all repos — legit @ fba146ac6867b13c40802c4d7a21a8a32571473c

web frontend for git

git/service/service.go (view raw)

  1package service
  2
  3import (
  4	"bytes"
  5	"fmt"
  6	"io"
  7	"log"
  8	"net/http"
  9	"os/exec"
 10	"strings"
 11	"syscall"
 12)
 13
 14// Mostly from charmbracelet/soft-serve and sosedoff/gitkit.
 15
 16type ServiceCommand struct {
 17	Dir    string
 18	Stdin  io.Reader
 19	Stdout http.ResponseWriter
 20}
 21
 22func (c *ServiceCommand) InfoRefs() error {
 23	cmd := exec.Command("git", []string{
 24		"upload-pack",
 25		"--stateless-rpc",
 26		"--advertise-refs",
 27		".",
 28	}...)
 29
 30	cmd.Dir = c.Dir
 31	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
 32	stdoutPipe, _ := cmd.StdoutPipe()
 33	cmd.Stderr = cmd.Stdout
 34
 35	if err := cmd.Start(); err != nil {
 36		log.Printf("git: failed to start git-upload-pack (info/refs): %s", err)
 37		return err
 38	}
 39
 40	if err := packLine(c.Stdout, "# service=git-upload-pack\n"); err != nil {
 41		log.Printf("git: failed to write pack line: %s", err)
 42		return err
 43	}
 44
 45	if err := packFlush(c.Stdout); err != nil {
 46		log.Printf("git: failed to flush pack: %s", err)
 47		return err
 48	}
 49
 50	buf := bytes.Buffer{}
 51	if _, err := io.Copy(&buf, stdoutPipe); err != nil {
 52		log.Printf("git: failed to copy stdout to tmp buffer: %s", err)
 53		return err
 54	}
 55
 56	if err := cmd.Wait(); err != nil {
 57		out := strings.Builder{}
 58		_, _ = io.Copy(&out, &buf)
 59		log.Printf("git: failed to run git-upload-pack; err: %s; output: %s", err, out.String())
 60		return err
 61	}
 62
 63	if _, err := io.Copy(c.Stdout, &buf); err != nil {
 64		log.Printf("git: failed to copy stdout: %s", err)
 65	}
 66
 67	return nil
 68}
 69
 70func (c *ServiceCommand) UploadPack() error {
 71	cmd := exec.Command("git", []string{
 72		"-c", "uploadpack.allowFilter=true",
 73		"upload-pack",
 74		"--stateless-rpc",
 75		".",
 76	}...)
 77	cmd.Dir = c.Dir
 78	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
 79
 80	stdoutPipe, _ := cmd.StdoutPipe()
 81	cmd.Stderr = cmd.Stdout
 82	defer stdoutPipe.Close()
 83
 84	stdinPipe, err := cmd.StdinPipe()
 85	if err != nil {
 86		return err
 87	}
 88	defer stdinPipe.Close()
 89
 90	if err := cmd.Start(); err != nil {
 91		log.Printf("git: failed to start git-upload-pack: %s", err)
 92		return err
 93	}
 94
 95	if _, err := io.Copy(stdinPipe, c.Stdin); err != nil {
 96		log.Printf("git: failed to copy stdin: %s", err)
 97		return err
 98	}
 99	stdinPipe.Close()
100
101	if _, err := io.Copy(newWriteFlusher(c.Stdout), stdoutPipe); err != nil {
102		log.Printf("git: failed to copy stdout: %s", err)
103		return err
104	}
105	if err := cmd.Wait(); err != nil {
106		log.Printf("git: failed to wait for git-upload-pack: %s", err)
107		return err
108	}
109
110	return nil
111}
112
113func packLine(w io.Writer, s string) error {
114	_, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s)
115	return err
116}
117
118func packFlush(w io.Writer) error {
119	_, err := fmt.Fprint(w, "0000")
120	return err
121}