Monorepo for Tangled
tangled.org
1package git
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "os/exec"
8 "strings"
9 "syscall"
10)
11
12const (
13 fieldSeparator = "\x1f" // ASCII Unit Separator
14 recordSeparator = "\x1e" // ASCII Record Separator
15)
16
17func (g *GitRepo) runGitCmd(command string, extraArgs ...string) ([]byte, error) {
18 var args []string
19 args = append(args, command)
20 args = append(args, extraArgs...)
21
22 cmd := exec.Command("git", args...)
23
24 if g.sandbox != nil {
25 var wrapErr error
26 cmd, wrapErr = g.sandbox.Wrap(g.path, cmd)
27 if wrapErr != nil {
28 return nil, fmt.Errorf("sandbox wrap: %w", wrapErr)
29 }
30 } else {
31 cmd.Dir = g.path
32 }
33
34 if cmd.SysProcAttr == nil {
35 cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
36 }
37
38 out, err := cmd.Output()
39 if err != nil {
40 if exitErr, ok := err.(*exec.ExitError); ok {
41 return nil, fmt.Errorf("%w, stderr: %s", err, string(exitErr.Stderr))
42 }
43 return nil, err
44 }
45
46 return out, nil
47}
48
49func (g *GitRepo) revList(extraArgs ...string) ([]byte, error) {
50 return g.runGitCmd("rev-list", extraArgs...)
51}
52
53func (g *GitRepo) forEachRef(extraArgs ...string) ([]byte, error) {
54 return g.runGitCmd("for-each-ref", extraArgs...)
55}
56
57func (g *GitRepo) revParse(extraArgs ...string) ([]byte, error) {
58 return g.runGitCmd("rev-parse", extraArgs...)
59}
60
61func (g *GitRepo) mergeBase(extraArgs ...string) ([]byte, error) {
62 return g.runGitCmd("merge-base", extraArgs...)
63}
64
65func (g *GitRepo) WriteArchive(w io.Writer, format string, prefix string) error {
66 args := []string{"archive", "--format=" + format}
67 if prefix != "" {
68 args = append(args, "--prefix="+strings.TrimRight(prefix, "/")+"/")
69 }
70 args = append(args, g.h.String())
71
72 cmd := exec.Command("git", args...)
73 cmd.Dir = g.path
74 cmd.Stdout = w
75 stderr := new(bytes.Buffer)
76 cmd.Stderr = stderr
77
78 if err := cmd.Run(); err != nil {
79 return fmt.Errorf("%w, stderr: %s", err, stderr.String())
80 }
81
82 return nil
83}