forked from tangled.org/core
this repo has no description

knotserver: git/service: refactor execution of git service command

authored by tjh.dev and committed by Tangled afbdb8b2 6ec3a3d5

Changed files
+54 -70
knotserver
git
service
+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 {