diff --git a/appview/pages/templates/repo/index.html b/appview/pages/templates/repo/index.html index ac47a90..b6da3e5 100644 --- a/appview/pages/templates/repo/index.html +++ b/appview/pages/templates/repo/index.html @@ -41,18 +41,22 @@ {{ range .Files }} {{ if not .IsFile }}
- -
- {{ .Name }}/ -
-
+
+ +
+ {{ .Name }} +
+
+ + +
{{ end }} {{ end }} @@ -60,18 +64,22 @@ {{ range .Files }} {{ if .IsFile }}
- -
- {{ .Name }} -
-
+
+ +
+ {{ .Name }} +
+
+ + +
{{ end }} {{ end }} diff --git a/appview/pages/templates/repo/tree.html b/appview/pages/templates/repo/tree.html index 5441ab2..1a709a7 100644 --- a/appview/pages/templates/repo/tree.html +++ b/appview/pages/templates/repo/tree.html @@ -13,24 +13,32 @@ {{ range .Files }} {{ if not .IsFile }}
- -
- {{ .Name }}/ + - +
{{ end }} {{ end }} {{ range .Files }} {{ if .IsFile }} -
- -
- {{ .Name }} -
-
+
+ +
+ +
+ {{ .Name }} +
+
+ +
+
{{ end }} {{ end }}
diff --git a/appview/state/state.go b/appview/state/state.go index 89141bc..79fedf7 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -519,9 +519,15 @@ func (s *State) AddRepo(w http.ResponseWriter, r *http.Request) { s.pages.Notice(w, "repo", "Failed to create repository on knot server.") return } - if resp.StatusCode != http.StatusNoContent { - s.pages.Notice(w, "repo", fmt.Sprintf("Server returned unexpected status: %d", resp.StatusCode)) + + switch resp.StatusCode { + case http.StatusConflict: + s.pages.Notice(w, "repo", "A repository with that name already exists.") return + case http.StatusInternalServerError: + s.pages.Notice(w, "repo", "Failed to create repository on knot. Try again later.") + case http.StatusNoContent: + // continue } // add to local db diff --git a/input.css b/input.css index cf59353..12529b5 100644 --- a/input.css +++ b/input.css @@ -21,7 +21,7 @@ @apply bg-opacity-30; } a { - @apply underline text-black hover:text-gray-800 visited:text-gray-600; + @apply underline text-black hover:text-gray-800; } @layer base { diff --git a/knotserver/git/git.go b/knotserver/git/git.go index 0e870b0..53fad88 100644 --- a/knotserver/git/git.go +++ b/knotserver/git/git.go @@ -2,11 +2,14 @@ package git import ( "archive/tar" + "bytes" "fmt" "io" "io/fs" + "os/exec" "path" "sort" + "strings" "sync" "time" @@ -35,8 +38,9 @@ var ( ) type GitRepo struct { - r *git.Repository - h plumbing.Hash + path string + r *git.Repository + h plumbing.Hash } type TagList struct { @@ -102,7 +106,7 @@ func (self *TagList) Less(i, j int) bool { func Open(path string, ref string) (*GitRepo, error) { var err error - g := GitRepo{} + g := GitRepo{path: path} g.r, err = git.PlainOpen(path) if err != nil { return nil, fmt.Errorf("opening %s: %w", path, err) @@ -295,33 +299,38 @@ func (g *GitRepo) WriteTar(w io.Writer, prefix string) error { return nil } -func (g *GitRepo) LastCommitTime(filePath string) (*object.Commit, error) { +func (g *GitRepo) LastCommitForPath(path string) (*object.Commit, error) { cacheMu.RLock() - if commit, exists := commitCache.Get(filePath); exists { + if commit, found := commitCache.Get(path); found { cacheMu.RUnlock() return commit.(*object.Commit), nil } cacheMu.RUnlock() - commitIter, err := g.r.Log(&git.LogOptions{ - From: g.h, - PathFilter: func(s string) bool { - return s == filePath - }, - Order: git.LogOrderCommitterTime, - }) + cmd := exec.Command("git", "-C", g.path, "log", "-1", "--format=%H", "--", path) - if err != nil { - return nil, fmt.Errorf("failed to get commit log for %s: %w", filePath, err) + var out bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &out + + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("failed to get commit hash: %w", err) } - commit, err := commitIter.Next() + commitHash := strings.TrimSpace(out.String()) + if commitHash == "" { + return nil, fmt.Errorf("no commits found for path: %s", path) + } + + hash := plumbing.NewHash(commitHash) + + commit, err := g.r.CommitObject(hash) if err != nil { - return nil, fmt.Errorf("no commit found for %s", filePath) + return nil, err } cacheMu.Lock() - commitCache.Set(filePath, commit, 1) + commitCache.Set(path, commit, 1) cacheMu.Unlock() return commit, nil diff --git a/knotserver/git/tree.go b/knotserver/git/tree.go index f47355b..3783adf 100644 --- a/knotserver/git/tree.go +++ b/knotserver/git/tree.go @@ -20,7 +20,7 @@ func (g *GitRepo) FileTree(path string) ([]types.NiceTree, error) { } if path == "" { - files = g.makeNiceTree(tree) + files = g.makeNiceTree(tree, "") } else { o, err := tree.FindEntry(path) if err != nil { @@ -33,22 +33,29 @@ func (g *GitRepo) FileTree(path string) ([]types.NiceTree, error) { return nil, err } - files = g.makeNiceTree(subtree) + files = g.makeNiceTree(subtree, path) } } return files, nil } -func (g *GitRepo) makeNiceTree(t *object.Tree) []types.NiceTree { +func (g *GitRepo) makeNiceTree(t *object.Tree, parent string) []types.NiceTree { nts := []types.NiceTree{} for _, e := range t.Entries { mode, _ := e.Mode.ToOSFileMode() sz, _ := t.Size(e.Name) - lastCommit, err := g.LastCommitTime(e.Name) + var fpath string + if parent != "" { + fpath = fmt.Sprintf("%s/%s", parent, e.Name) + } else { + fpath = e.Name + } + lastCommit, err := g.LastCommitForPath(fpath) if err != nil { + fmt.Println("error getting last commit time:", err) continue } diff --git a/knotserver/routes.go b/knotserver/routes.go index 94f9226..73507d0 100644 --- a/knotserver/routes.go +++ b/knotserver/routes.go @@ -17,6 +17,7 @@ import ( securejoin "github.com/cyphar/filepath-securejoin" "github.com/gliderlabs/ssh" "github.com/go-chi/chi/v5" + gogit "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" "github.com/russross/blackfriday/v2" @@ -504,8 +505,13 @@ func (h *Handle) NewRepo(w http.ResponseWriter, r *http.Request) { err := git.InitBare(repoPath) if err != nil { l.Error("initializing bare repo", "error", err.Error()) - writeError(w, err.Error(), http.StatusInternalServerError) - return + if errors.Is(err, gogit.ErrRepositoryAlreadyExists) { + writeError(w, "That repo already exists!", http.StatusConflict) + return + } else { + writeError(w, err.Error(), http.StatusInternalServerError) + return + } } // add perms for this user to access the repo