all repos

mugit @ bdfa44c8e002cda7b7110caad47e522ed9aeab53

🐮 git server that your cow will love

mugit/internal/git/external.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
git: improve ergonomics of method that is only used 4 times, 2 months ago
1
package git
2
3
import (
4
	"cmp"
5
	"context"
6
	"fmt"
7
	"io"
8
	"os/exec"
9
	"strings"
10
	"syscall"
11
)
12
13
var gitEnv = []string{
14
	"GIT_CONFIG_GLOBAL=/dev/null",
15
	"GIT_CONFIG_SYSTEM=/dev/null",
16
}
17
18
type cmdOpts struct {
19
	Cmd         []string
20
	GitProtocol string
21
	Stdin       io.Reader
22
	Stdout      io.Writer
23
	Stderr      io.Writer
24
}
25
26
func (g *Repo) gitCmd(ctx context.Context, opts cmdOpts) error {
27
	opts.Cmd = append(opts.Cmd, ".")
28
	cmd := exec.CommandContext(ctx, "git", opts.Cmd...)
29
	cmd.Dir = g.path
30
	cmd.Env = append(gitEnv, fmt.Sprintf("GIT_PROTOCOL=%s", opts.GitProtocol))
31
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
32
	cmd.Stdin = cmp.Or[io.Reader](opts.Stdin, strings.NewReader(""))
33
	cmd.Stdout = cmp.Or(opts.Stdout, io.Discard)
34
	cmd.Stderr = cmp.Or(opts.Stderr, io.Discard)
35
	return cmd.Run()
36
}
37
38
func (g *Repo) streamingGitLog(ctx context.Context, extraArgs ...string) (io.ReadCloser, error) {
39
	args := []string{"log", g.h.String()}
40
	args = append(args, extraArgs...)
41
42
	cmd := exec.CommandContext(ctx, "git", args...)
43
	cmd.Dir = g.path
44
45
	stdout, err := cmd.StdoutPipe()
46
	if err != nil {
47
		return nil, err
48
	}
49
50
	if err := cmd.Start(); err != nil {
51
		return nil, err
52
	}
53
54
	return &processReader{
55
		Reader: stdout,
56
		cmd:    cmd,
57
		stdout: stdout,
58
	}, nil
59
}
60
61
// processReader wraps a reader and ensures the associated process is cleaned up
62
type processReader struct {
63
	io.Reader
64
	cmd    *exec.Cmd
65
	stdout io.ReadCloser
66
}
67
68
func (pr *processReader) Close() error {
69
	if err := pr.stdout.Close(); err != nil {
70
		return err
71
	}
72
	return pr.cmd.Wait()
73
}