rin
Публичный Open-source lightweight git hosting.
http.go · 85 строк · 2.1 KB
Raw
1 package git
2
3 import (
4 "bytes"
5 "context"
6 "errors"
7 "fmt"
8 "io"
9 "os"
10 "os/exec"
11 "strings"
12 "time"
13 )
14
15 var ErrUnsupportedService = errors.New("unsupported git service")
16
17 func subcommandForService(service string) (string, error) {
18 switch service {
19 case "git-upload-pack":
20 return "upload-pack", nil
21 case "git-receive-pack":
22 return "receive-pack", nil
23 default:
24 return "", ErrUnsupportedService
25 }
26 }
27
28 func pktLine(payload string) string {
29 return fmt.Sprintf("%04x%s", len(payload)+4, payload)
30 }
31
32 func AdvertiseRefs(ctx context.Context, repoPath, service string, out io.Writer) error {
33 subcmd, err := subcommandForService(service)
34 if err != nil {
35 return err
36 }
37
38 cctx, cancel := context.WithTimeout(ctx, 30*time.Second)
39 defer cancel()
40
41 var stdout, stderr bytes.Buffer
42 cmd := exec.CommandContext(cctx, "git", subcmd, "--stateless-rpc", "--advertise-refs", repoPath)
43 cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0", "LC_ALL=C")
44 cmd.Stdout = &stdout
45 cmd.Stderr = &stderr
46
47 if err := cmd.Run(); err != nil {
48 return fmt.Errorf("git %s advertise-refs: %w (%s)", subcmd, err, strings.TrimSpace(stderr.String()))
49 }
50
51 header := pktLine(fmt.Sprintf("# service=%s\n", service)) + "0000"
52 if _, err := io.WriteString(out, header); err != nil {
53 return err
54 }
55 _, err = out.Write(stdout.Bytes())
56 return err
57 }
58
59 func ServiceRPC(ctx context.Context, repoPath, service string, in io.Reader, out io.Writer) error {
60 subcmd, err := subcommandForService(service)
61 if err != nil {
62 return err
63 }
64
65 cctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
66 defer cancel()
67
68 var stderr bytes.Buffer
69 cmd := exec.CommandContext(cctx, "git", subcmd, "--stateless-rpc", repoPath)
70 cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0", "LC_ALL=C")
71 cmd.Stdin = in
72 cmd.Stdout = out
73 cmd.Stderr = &stderr
74
75 if err := cmd.Run(); err != nil {
76 return fmt.Errorf("git %s stateless-rpc: %w (%s)", subcmd, err, strings.TrimSpace(stderr.String()))
77 }
78
79 if service == "git-receive-pack" {
80 _, _ = EnsureDefaultBranch(ctx, repoPath, "main")
81 _, _ = runGit(ctx, repoPath, 5*time.Second, "update-server-info")
82 }
83
84 return nil
85 }
86