From afbdb8b2aa8fe8d790a015f4dc861193d45e9294 Mon Sep 17 00:00:00 2001 From: tjh Date: Thu, 22 May 2025 20:32:02 +0000 Subject: [PATCH] knotserver: git/service: refactor execution of git service command --- knotserver/git/service/service.go | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------- 1 file(s) changed, 54 insertion(s)(+), 70 deletion(s)(-) diff --git a/knotserver/git/service/service.go b/knotserver/git/service/service.go --- a/knotserver/git/service/service.go +++ b/knotserver/git/service/service.go @@ -21,6 +21,57 @@ Stdin io.Reader Stdout http.ResponseWriter } +func (c *ServiceCommand) RunService(cmd *exec.Cmd) error { + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + cmd.Dir = c.Dir + cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_PROTOCOL=%s", c.GitProtocol)) + + var stderr bytes.Buffer + cmd.Stderr = &stderr + + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + return fmt.Errorf("failed to create stdout pipe: %w", err) + } + + stdinPipe, err := cmd.StdinPipe() + if err != nil { + return fmt.Errorf("failed to create stdin pipe: %w", err) + } + + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to start '%s': %w", cmd.String(), err) + } + + var wg sync.WaitGroup + + if c.Stdin != nil { + wg.Add(1) + go func() { + defer wg.Done() + defer stdinPipe.Close() + io.Copy(stdinPipe, c.Stdin) + }() + } + + if c.Stdout != nil { + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(newWriteFlusher(c.Stdout), stdoutPipe) + stdoutPipe.Close() + }() + } + + wg.Wait() + + if err := cmd.Wait(); err != nil { + return fmt.Errorf("'%s' failed: %w, stderr: %s", cmd.String(), err, stderr.String()) + } + + return nil +} + func (c *ServiceCommand) InfoRefs() error { cmd := exec.Command("git", []string{ "upload-pack", @@ -28,16 +79,6 @@ "--stateless-rpc", "--http-backend-info-refs", ".", }...) - cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_PROTOCOL=%s", c.GitProtocol)) - 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 !strings.Contains(c.GitProtocol, "version=2") { if err := packLine(c.Stdout, "# service=git-upload-pack\n"); err != nil { @@ -51,29 +92,10 @@ 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 + return c.RunService(cmd) } func (c *ServiceCommand) UploadPack() error { - var stderr bytes.Buffer - cmd := exec.Command("git", []string{ "-c", "uploadpack.allowFilter=true", "upload-pack", @@ -81,49 +103,11 @@ "--stateless-rpc", ".", }...) - cmd.Dir = c.Dir cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_PROTOCOL=%s", c.GitProtocol)) - - stdoutPipe, err := cmd.StdoutPipe() - if err != nil { - return fmt.Errorf("failed to create stdout pipe: %w", err) - } - - cmd.Stderr = &stderr - - stdinPipe, err := cmd.StdinPipe() - if err != nil { - return fmt.Errorf("failed to create stdin pipe: %w", err) - } - - if err := cmd.Start(); err != nil { - return fmt.Errorf("failed to start git-upload-pack: %w", err) - } - - var wg sync.WaitGroup + cmd.Dir = c.Dir - wg.Add(1) - go func() { - defer wg.Done() - defer stdinPipe.Close() - io.Copy(stdinPipe, c.Stdin) - }() - - wg.Add(1) - go func() { - defer wg.Done() - io.Copy(newWriteFlusher(c.Stdout), stdoutPipe) - stdoutPipe.Close() - }() - - wg.Wait() - - if err := cmd.Wait(); err != nil { - return fmt.Errorf("git-upload-pack failed: %w, stderr: %s", err, stderr.String()) - } - - return nil + return c.RunService(cmd) } func packLine(w io.Writer, s string) error { -- tangled.sh