bidet

commit c362fc5ff73740244ceaacba31cdae3e6098ac04

tree

parent:
cba0e159e0fcd8f08f13af5673509418e8fe9e67

nmyk <nick@nmyk.io>

2026-04-21T19:17:51-04:00

fixes git clone bug

info/refs and upload-pack did not work with --directory specified

diff --git a/internal/core/repo.go b/internal/core/repo.go
index 5a947efa56094282502ac9e815ebe5b4724d9c0f..6607f5443a42ab968757502d3203fe0f9d49492b 100644
--- a/internal/core/repo.go
+++ b/internal/core/repo.go
@@ -5,7 +5,6 @@ 	"bytes"
 	"errors"
 	"fmt"
 	"io"
-	"os"
 	"path"
 	"strings"
 
@@ -17,49 +16,9 @@ 	"github.com/go-git/go-git/v6/plumbing/object"
 	"github.com/go-git/go-git/v6/utils/binary"
 )
 
-const dotGit = ".git"
-
-func List(dir string) ([]*Repo, error) {
-	entries, err := os.ReadDir(dir)
-	if err != nil {
-		return nil, err
-	}
-	var repos []*Repo
-	for _, e := range entries {
-		if e.Name() == dotGit {
-			continue
-		}
-		repo, err := Open(strings.TrimSuffix(e.Name(), dotGit))
-		if err == nil {
-			if _, err = repo.Worktree(); errors.Is(err, git.ErrIsBareRepository) {
-				repos = append(repos, repo)
-			}
-		}
-	}
-	if len(repos) == 0 {
-		return nil, errors.New("No repos found in " + dir)
-	}
-	return repos, nil
-}
-
 type Repo struct {
 	*git.Repository
 	Name string
-}
-
-func Open(repoName string) (*Repo, error) {
-	if _, err := os.Stat(repoName + dotGit); os.IsNotExist(err) {
-		return nil, err
-	}
-	repo, err := git.PlainOpen(repoName + dotGit)
-	if err != nil {
-		return nil, err
-	}
-	return &Repo{repo, repoName}, nil
-}
-
-func (repo *Repo) Path() string {
-	return repo.Name + dotGit
 }
 
 func (repo *Repo) Load(entry *object.TreeEntry) (string, error) {
diff --git a/internal/handlers/directory.go b/internal/handlers/directory.go
new file mode 100644
index 0000000000000000000000000000000000000000..6043457d4d2bdd4bf1971b67e21ea5ac65e93637
--- /dev/null
+++ b/internal/handlers/directory.go
@@ -0,0 +1,51 @@
+package handlers
+
+import (
+	"errors"
+	"os"
+	"path"
+	"strings"
+
+	"github.com/go-git/go-git/v6"
+	"nmyk.io/bidet/internal/core"
+)
+
+const dotGit = ".git"
+
+func (s Server) List() ([]*core.Repo, error) {
+	entries, err := os.ReadDir(s.Dir)
+	if err != nil {
+		return nil, err
+	}
+	var repos []*core.Repo
+	for _, e := range entries {
+		if e.Name() == dotGit {
+			continue
+		}
+		repo, err := s.Open(strings.TrimSuffix(e.Name(), dotGit))
+		if err == nil {
+			if _, err = repo.Worktree(); errors.Is(err, git.ErrIsBareRepository) {
+				repos = append(repos, repo)
+			}
+		}
+	}
+	if len(repos) == 0 {
+		return nil, errors.New("No repos found in " + s.Dir)
+	}
+	return repos, nil
+}
+
+func (s Server) repoPath(repoName string) string {
+	return path.Join(s.Dir, repoName) + dotGit
+}
+
+func (s Server) Open(repoName string) (*core.Repo, error) {
+	if _, err := os.Stat(s.repoPath(repoName)); os.IsNotExist(err) {
+		return nil, err
+	}
+	repo, err := git.PlainOpen(s.repoPath(repoName))
+	if err != nil {
+		return nil, err
+	}
+	return &core.Repo{Repository: repo, Name: repoName}, nil
+}
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index 5b6180c9f368e86454f109a4aa8d81e90228ad97..85ba4192e852a173598c5bdf8165902149dcc049 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -131,7 +131,7 @@ 	Updated time.Time
 }
 
 func (s Server) ListRepos(w http.ResponseWriter, _ *http.Request) {
-	repos, err := core.List(s.Dir)
+	repos, err := s.List()
 	if err != nil {
 		s.error(w, err)
 		return
@@ -184,13 +184,9 @@ 	Branches []BranchMeta
 	Tags     []TagMeta
 }
 
-func (s Server) open(name string) (*core.Repo, error) {
-	return core.Open(path.Join(s.Dir, name))
-}
-
 func (s Server) Refs(w http.ResponseWriter, r *http.Request) {
 	repoName := r.PathValue("name")
-	repo, err := s.open(repoName)
+	repo, err := s.Open(repoName)
 	if err != nil {
 		s.error(w, err)
 		return
@@ -300,7 +296,7 @@ }
 
 func (s Server) Commits(w http.ResponseWriter, r *http.Request) {
 	repoName := r.PathValue("name")
-	repo, err := s.open(repoName)
+	repo, err := s.Open(repoName)
 	if err != nil {
 		s.error(w, err)
 		return
@@ -343,7 +339,7 @@ 	ctx, cancel := context.WithCancel(r.Context())
 	defer cancel()
 
 	cmd := exec.CommandContext(ctx, "git", args...)
-	cmd.Dir = path.Join(s.Dir, repo.Path())
+	cmd.Dir = s.repoPath(repoName)
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
 		s.error(w, err)
@@ -454,7 +450,7 @@ }
 
 func (s Server) Commit(w http.ResponseWriter, r *http.Request) {
 	repoName := r.PathValue("name")
-	repo, err := s.open(repoName)
+	repo, err := s.Open(repoName)
 	if err != nil {
 		s.error(w, err)
 		return
@@ -511,7 +507,7 @@ }
 
 func (s Server) Blob(w http.ResponseWriter, r *http.Request) {
 	repoName := r.PathValue("name")
-	repo, err := s.open(repoName)
+	repo, err := s.Open(repoName)
 	if err != nil {
 		s.error(w, err)
 		return
@@ -568,7 +564,7 @@ }
 
 func (s Server) Tree(w http.ResponseWriter, r *http.Request) {
 	repoName := r.PathValue("name")
-	repo, err := s.open(repoName)
+	repo, err := s.Open(repoName)
 	if err != nil {
 		s.error(w, err)
 		return
@@ -679,8 +675,14 @@ 	}
 }
 
 func (s Server) InfoRefs(w http.ResponseWriter, r *http.Request) {
-	repoName := r.PathValue("name")
-	repo, err := git.PlainOpen(repoName)
+	repoDir := r.PathValue("name")
+	// repoDir already ends in .git
+	repoLocation, cut := strings.CutSuffix(s.repoPath(repoDir), dotGit)
+	if !cut {
+		http.NotFound(w, r)
+		return
+	}
+	repo, err := git.PlainOpen(repoLocation)
 	if err != nil {
 		s.error(w, err)
 		return
@@ -697,7 +699,13 @@ 	}
 }
 
 func (s Server) UploadPack(w http.ResponseWriter, r *http.Request) {
-	repoName := r.PathValue("name")
+	repoDir := r.PathValue("name")
+	// repoDir already ends in .git
+	repoLocation, cut := strings.CutSuffix(s.repoPath(repoDir), dotGit)
+	if !cut {
+		http.NotFound(w, r)
+		return
+	}
 	var bodyReader io.ReadCloser
 	switch strings.ToLower(r.Header.Get("Content-Encoding")) {
 	case "gzip":
@@ -714,7 +722,7 @@ 	}
 	w.Header().Add("Content-Type", fmt.Sprintf("application/x-%s-result", r.PathValue("path")))
 	w.Header().Add("Cache-Control", "no-cache")
 	w.WriteHeader(http.StatusOK)
-	if err := core.UploadPack(repoName, bodyReader, w); err != nil {
+	if err := core.UploadPack(repoLocation, bodyReader, w); err != nil {
 		s.error(w, err)
 		return
 	}
@@ -722,7 +730,7 @@ }
 
 func (s Server) RepoTree(w http.ResponseWriter, r *http.Request) {
 	repoName := r.PathValue("name")
-	repo, err := s.open(repoName)
+	repo, err := s.Open(repoName)
 	if err != nil {
 		s.error(w, err)
 		return