+54
-70
knotserver/git/service/service.go
+54
-70
knotserver/git/service/service.go
···
21
21
Stdout http.ResponseWriter
22
22
}
23
23
24
+
func (c *ServiceCommand) RunService(cmd *exec.Cmd) error {
25
+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
26
+
cmd.Dir = c.Dir
27
+
cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_PROTOCOL=%s", c.GitProtocol))
28
+
29
+
var stderr bytes.Buffer
30
+
cmd.Stderr = &stderr
31
+
32
+
stdoutPipe, err := cmd.StdoutPipe()
33
+
if err != nil {
34
+
return fmt.Errorf("failed to create stdout pipe: %w", err)
35
+
}
36
+
37
+
stdinPipe, err := cmd.StdinPipe()
38
+
if err != nil {
39
+
return fmt.Errorf("failed to create stdin pipe: %w", err)
40
+
}
41
+
42
+
if err := cmd.Start(); err != nil {
43
+
return fmt.Errorf("failed to start '%s': %w", cmd.String(), err)
44
+
}
45
+
46
+
var wg sync.WaitGroup
47
+
48
+
if c.Stdin != nil {
49
+
wg.Add(1)
50
+
go func() {
51
+
defer wg.Done()
52
+
defer stdinPipe.Close()
53
+
io.Copy(stdinPipe, c.Stdin)
54
+
}()
55
+
}
56
+
57
+
if c.Stdout != nil {
58
+
wg.Add(1)
59
+
go func() {
60
+
defer wg.Done()
61
+
io.Copy(newWriteFlusher(c.Stdout), stdoutPipe)
62
+
stdoutPipe.Close()
63
+
}()
64
+
}
65
+
66
+
wg.Wait()
67
+
68
+
if err := cmd.Wait(); err != nil {
69
+
return fmt.Errorf("'%s' failed: %w, stderr: %s", cmd.String(), err, stderr.String())
70
+
}
71
+
72
+
return nil
73
+
}
74
+
24
75
func (c *ServiceCommand) InfoRefs() error {
25
76
cmd := exec.Command("git", []string{
26
77
"upload-pack",
···
28
79
"--http-backend-info-refs",
29
80
".",
30
81
}...)
31
-
cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_PROTOCOL=%s", c.GitProtocol))
32
-
cmd.Dir = c.Dir
33
-
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
34
-
stdoutPipe, _ := cmd.StdoutPipe()
35
-
cmd.Stderr = cmd.Stdout
36
-
37
-
if err := cmd.Start(); err != nil {
38
-
log.Printf("git: failed to start git-upload-pack (info/refs): %s", err)
39
-
return err
40
-
}
41
82
42
83
if !strings.Contains(c.GitProtocol, "version=2") {
43
84
if err := packLine(c.Stdout, "# service=git-upload-pack\n"); err != nil {
···
51
92
}
52
93
}
53
94
54
-
buf := bytes.Buffer{}
55
-
if _, err := io.Copy(&buf, stdoutPipe); err != nil {
56
-
log.Printf("git: failed to copy stdout to tmp buffer: %s", err)
57
-
return err
58
-
}
59
-
60
-
if err := cmd.Wait(); err != nil {
61
-
out := strings.Builder{}
62
-
_, _ = io.Copy(&out, &buf)
63
-
log.Printf("git: failed to run git-upload-pack; err: %s; output: %s", err, out.String())
64
-
return err
65
-
}
66
-
67
-
if _, err := io.Copy(c.Stdout, &buf); err != nil {
68
-
log.Printf("git: failed to copy stdout: %s", err)
69
-
}
70
-
71
-
return nil
95
+
return c.RunService(cmd)
72
96
}
73
97
74
98
func (c *ServiceCommand) UploadPack() error {
75
-
var stderr bytes.Buffer
76
-
77
99
cmd := exec.Command("git", []string{
78
100
"-c", "uploadpack.allowFilter=true",
79
101
"upload-pack",
···
81
103
".",
82
104
}...)
83
105
84
-
cmd.Dir = c.Dir
85
106
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
86
107
cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_PROTOCOL=%s", c.GitProtocol))
87
-
88
-
stdoutPipe, err := cmd.StdoutPipe()
89
-
if err != nil {
90
-
return fmt.Errorf("failed to create stdout pipe: %w", err)
91
-
}
92
-
93
-
cmd.Stderr = &stderr
94
-
95
-
stdinPipe, err := cmd.StdinPipe()
96
-
if err != nil {
97
-
return fmt.Errorf("failed to create stdin pipe: %w", err)
98
-
}
99
-
100
-
if err := cmd.Start(); err != nil {
101
-
return fmt.Errorf("failed to start git-upload-pack: %w", err)
102
-
}
103
-
104
-
var wg sync.WaitGroup
108
+
cmd.Dir = c.Dir
105
109
106
-
wg.Add(1)
107
-
go func() {
108
-
defer wg.Done()
109
-
defer stdinPipe.Close()
110
-
io.Copy(stdinPipe, c.Stdin)
111
-
}()
112
-
113
-
wg.Add(1)
114
-
go func() {
115
-
defer wg.Done()
116
-
io.Copy(newWriteFlusher(c.Stdout), stdoutPipe)
117
-
stdoutPipe.Close()
118
-
}()
119
-
120
-
wg.Wait()
121
-
122
-
if err := cmd.Wait(); err != nil {
123
-
return fmt.Errorf("git-upload-pack failed: %w, stderr: %s", err, stderr.String())
124
-
}
125
-
126
-
return nil
110
+
return c.RunService(cmd)
127
111
}
128
112
129
113
func packLine(w io.Writer, s string) error {