Changes
5 changed files (+178/-70)
-
-
@@ -12,9 +12,9 @@ dirs:templates: ./templates static: ./static meta: title: git good description: i think it's a skill issue title: icy does git description: come get your free software server: name: git.icyphox.sh host: 127.0.0.1 host: 0.0.0.0 port: 5555
-
-
-
@@ -38,7 +38,7 @@ };docker = pkgs.dockerTools.buildLayeredImage { name = "sini:5000/legit"; tag = "latest"; contents = [ files legit ]; contents = [ files legit pkgs.git ]; config = { Entrypoint = [ "${legit}/bin/legit" ]; ExposedPorts = { "5555/tcp" = { }; };
-
-
git/service/service.go (new)
-
@@ -0,0 +1,121 @@package service import ( "bytes" "fmt" "io" "log" "net/http" "os/exec" "strings" "syscall" ) // Mostly from charmbracelet/soft-serve and sosedoff/gitkit. type ServiceCommand struct { Dir string Stdin io.Reader Stdout http.ResponseWriter } func (c *ServiceCommand) InfoRefs() error { cmd := exec.Command("git", []string{ "upload-pack", "--stateless-rpc", "--advertise-refs", ".", }...) cmd.Dir = c.Dir cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} stdoutPipe, _ := cmd.StdoutPipe() cmd.Stderr = cmd.Stdout if err := cmd.Start(); err != nil { log.Printf("git: failed to start git-upload-pack (info/refs): %s", err) return err } if err := packLine(c.Stdout, "# service=git-upload-pack\n"); err != nil { log.Printf("git: failed to write pack line: %s", err) return err } if err := packFlush(c.Stdout); err != nil { log.Printf("git: failed to flush pack: %s", err) return err } buf := bytes.Buffer{} if _, err := io.Copy(&buf, stdoutPipe); err != nil { log.Printf("git: failed to copy stdout to tmp buffer: %s", err) return err } if err := cmd.Wait(); err != nil { out := strings.Builder{} _, _ = io.Copy(&out, &buf) log.Printf("git: failed to run git-upload-pack; err: %s; output: %s", err, out.String()) return err } if _, err := io.Copy(c.Stdout, &buf); err != nil { log.Printf("git: failed to copy stdout: %s", err) } return nil } func (c *ServiceCommand) UploadPack() error { cmd := exec.Command("git", []string{ "-c", "uploadpack.allowFilter=true", "upload-pack", "--stateless-rpc", ".", }...) cmd.Dir = c.Dir cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} stdoutPipe, _ := cmd.StdoutPipe() cmd.Stderr = cmd.Stdout defer stdoutPipe.Close() stdinPipe, err := cmd.StdinPipe() if err != nil { return err } defer stdinPipe.Close() if err := cmd.Start(); err != nil { log.Printf("git: failed to start git-upload-pack: %s", err) return err } if _, err := io.Copy(stdinPipe, c.Stdin); err != nil { log.Printf("git: failed to copy stdin: %s", err) return err } stdinPipe.Close() if _, err := io.Copy(newWriteFlusher(c.Stdout), stdoutPipe); err != nil { log.Printf("git: failed to copy stdout: %s", err) return err } if err := cmd.Wait(); err != nil { log.Printf("git: failed to wait for git-upload-pack: %s", err) return err } return nil } func packLine(w io.Writer, s string) error { _, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s) return err } func packFlush(w io.Writer) error { _, err := fmt.Fprint(w, "0000") return err }
-
-
-
@@ -0,0 +1,25 @@package service import ( "io" "net/http" ) func newWriteFlusher(w http.ResponseWriter) io.Writer { return writeFlusher{w.(interface { io.Writer http.Flusher })} } type writeFlusher struct { wf interface { io.Writer http.Flusher } } func (w writeFlusher) Write(p []byte) (int, error) { defer w.wf.Flush() return w.wf.Write(p) }
-
-
-
@@ -1,16 +1,13 @@package routes import ( "errors" "compress/gzip" "io" "log" "net/http" "path/filepath" "github.com/go-git/go-billy/v5/osfs" "github.com/go-git/go-git/v5/plumbing/format/pktline" "github.com/go-git/go-git/v5/plumbing/protocol/packp" "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport/server" "git.icyphox.sh/legit/git/service" ) func (d *deps) InfoRefs(w http.ResponseWriter, r *http.Request) {
-
@@ -20,41 +17,16 @@repo := filepath.Join(d.c.Repo.ScanPath, name) w.Header().Set("content-type", "application/x-git-upload-pack-advertisement") w.WriteHeader(http.StatusOK) ep, err := transport.NewEndpoint("/") if err != nil { http.Error(w, err.Error(), 500) log.Printf("git: %s", err) return cmd := service.ServiceCommand{ Dir: repo, Stdout: w, } billyfs := osfs.New(repo) loader := server.NewFilesystemLoader(billyfs) srv := server.NewServer(loader) session, err := srv.NewUploadPackSession(ep, nil) if err != nil { if err := cmd.InfoRefs(); err != nil { http.Error(w, err.Error(), 500) log.Printf("git: %s", err) return } ar, err := session.AdvertisedReferencesContext(r.Context()) if errors.Is(err, transport.ErrRepositoryNotFound) { http.Error(w, err.Error(), 404) return } else if err != nil { http.Error(w, err.Error(), 500) return } ar.Prefix = [][]byte{ []byte("# service=git-upload-pack"), pktline.Flush, } if err = ar.Encode(w); err != nil { http.Error(w, err.Error(), 500) log.Printf("git: %s", err) log.Printf("git: failed to execute git-upload-pack (info/refs) %s", err) return } }
-
@@ -66,42 +38,32 @@repo := filepath.Join(d.c.Repo.ScanPath, name) w.Header().Set("content-type", "application/x-git-upload-pack-result") upr := packp.NewUploadPackRequest() err := upr.Decode(r.Body) if err != nil { http.Error(w, err.Error(), 400) log.Printf("git: %s", err) return } w.Header().Set("Connection", "Keep-Alive") w.Header().Set("Transfer-Encoding", "chunked") w.WriteHeader(http.StatusOK) ep, err := transport.NewEndpoint("/") if err != nil { http.Error(w, err.Error(), 500) log.Printf("git: %s", err) return cmd := service.ServiceCommand{ Dir: repo, Stdout: w, } billyfs := osfs.New(repo) loader := server.NewFilesystemLoader(billyfs) svr := server.NewServer(loader) session, err := svr.NewUploadPackSession(ep, nil) if err != nil { http.Error(w, err.Error(), 500) log.Printf("git: %s", err) return } var reader io.ReadCloser reader = r.Body res, err := session.UploadPack(r.Context(), upr) if err != nil { http.Error(w, err.Error(), 500) log.Printf("git: %s", err) return if r.Header.Get("Content-Encoding") == "gzip" { reader, err := gzip.NewReader(r.Body) if err != nil { http.Error(w, err.Error(), 500) log.Printf("git: failed to create gzip reader: %s", err) return } defer reader.Close() } if err = res.Encode(w); err != nil { cmd.Stdin = reader if err := cmd.UploadPack(); err != nil { http.Error(w, err.Error(), 500) log.Printf("git: %s", err) log.Printf("git: failed to execute git-upload-pack %s", err) return } }
-