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
|
package testgit
import (
"fmt"
"io"
"os/exec"
"strings"
"sync"
"testing"
)
// packObjectsReadCloser wraps a pipe reader and process wait fn.
type packObjectsReadCloser struct {
reader io.ReadCloser
wait func() error
once sync.Once
}
// Read proxies reads to the wrapped reader.
func (reader *packObjectsReadCloser) Read(dst []byte) (int, error) {
return reader.reader.Read(dst)
}
// Close closes the stream and waits for the underlying process.
func (reader *packObjectsReadCloser) Close() error {
var out error
reader.once.Do(func() {
errClose := reader.reader.Close()
errWait := reader.wait()
if errClose != nil {
out = errClose
return
}
out = errWait
})
return out
}
// PackObjectsReader streams `git pack-objects --stdout --revs` output.
func (testRepo *TestRepo) PackObjectsReader(tb testing.TB, revs []string, thin bool) io.ReadCloser {
tb.Helper()
args := []string{"pack-objects", "--stdout", "--revs"}
if thin {
args = append(args, "--thin")
}
//nolint:noctx
cmd := exec.Command("git", args...) //#nosec G204
cmd.Dir = testRepo.dir
cmd.Env = testRepo.env
cmd.Stdin = strings.NewReader(strings.Join(revs, "\n") + "\n")
pr, pw := io.Pipe()
cmd.Stdout = pw
stderr := &strings.Builder{}
cmd.Stderr = stderr
waitDone := make(chan error, 1)
go func() {
err := cmd.Start()
if err != nil {
_ = pw.CloseWithError(fmt.Errorf("git %v start failed: %w", args, err))
waitDone <- nil
return
}
err = cmd.Wait()
if err != nil {
_ = pw.CloseWithError(fmt.Errorf("git %v failed: %w\n%s", args, err, stderr.String()))
} else {
_ = pw.Close()
}
waitDone <- nil
}()
return &packObjectsReadCloser{
reader: pr,
wait: func() error {
<-waitDone
return nil
},
}
}
|