Repository navigation
Expand file tree
/
Copy pathchanges_git.go
More file actions
97 lines (93 loc) · 2.31 KB
/
Copy pathchanges_git.go
File metadata and controls
97 lines (93 loc) · 2.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package history
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"os/exec"
"strings"
)
// WalkChangesGit produces the same Change stream as Repo.WalkChanges by
// shelling out to the git binary. It is also a benchmark baseline for the
// in-process walker.
func WalkChangesGit(repo string, merges bool, visit func(Change) error) error {
mergeMode := "off"
if merges {
mergeMode = "first-parent"
}
cmd := exec.Command("git", "-C", repo, "log", "--all", "--date-order",
"--root", "--no-abbrev", "--raw", "--no-renames", "-z",
"--diff-merges="+mergeMode, "--format=%x01%H%x00%aI%x00%P%x00%s")
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
return err
}
err = readGitChanges(stdout, visit)
if err != nil {
_ = cmd.Process.Kill()
}
waitErr := cmd.Wait()
if err != nil {
return fmt.Errorf("read history: %w", err)
}
return waitErr
}
func readGitChanges(input io.Reader, visit func(Change) error) error {
r := bufio.NewReaderSize(input, readerBufferSize)
field := func() (string, error) {
s, err := r.ReadString(0)
return strings.TrimSuffix(s, "\x00"), err
}
var c Change
for {
token, err := field()
if err == io.EOF && strings.TrimSpace(token) == "" {
return nil
}
if err != nil {
return err
}
token = strings.TrimLeft(token, "\n")
if strings.HasPrefix(token, "\x01") {
c.Commit = token[1:]
if c.Date, err = field(); err != nil {
return err
}
parents, err := field()
if err != nil {
return err
}
c.Merge = strings.Contains(parents, " ")
if c.Subject, err = field(); err != nil {
return err
}
continue
}
if !strings.HasPrefix(token, ":") {
continue
}
fields := strings.Fields(token[1:])
if len(fields) != 5 || c.Commit == "" {
return fmt.Errorf("invalid raw change %q", token)
}
c.OldMode, c.NewMode = fields[0], fields[1]
c.OldOID, c.NewOID = fields[2], fields[3]
if c.Path, err = field(); err != nil {
return err
}
if err := visit(c); err != nil {
return err
}
}
}
// ShallowGit reports whether the repository is a shallow clone by shelling
// out to git rev-parse.
func ShallowGit(repo string) (bool, error) {
out, err := exec.Command("git", "-C", repo, "rev-parse", "--is-shallow-repository").Output()
return bytes.HasPrefix(out, []byte("true")), err
}