@@ -13,9 +13,44 @@ import (
13
13
"strings"
14
14
)
15
15
16
+ // WriteCloserError wraps an io.WriteCloser with an additional CloseWithError function
17
+ type WriteCloserError interface {
18
+ io.WriteCloser
19
+ CloseWithError (err error ) error
20
+ }
21
+
22
+ // CatFileBatchCheck opens git cat-file --batch-check in the provided repo and returns a stdin pipe, a stdout reader and cancel function
23
+ func CatFileBatchCheck (repoPath string ) (WriteCloserError , * bufio.Reader , func ()) {
24
+ batchStdinReader , batchStdinWriter := io .Pipe ()
25
+ batchStdoutReader , batchStdoutWriter := io .Pipe ()
26
+ cancel := func () {
27
+ _ = batchStdinReader .Close ()
28
+ _ = batchStdinWriter .Close ()
29
+ _ = batchStdoutReader .Close ()
30
+ _ = batchStdoutWriter .Close ()
31
+ }
32
+
33
+ go func () {
34
+ stderr := strings.Builder {}
35
+ err := NewCommand ("cat-file" , "--batch-check" ).RunInDirFullPipeline (repoPath , batchStdoutWriter , & stderr , batchStdinReader )
36
+ if err != nil {
37
+ _ = batchStdoutWriter .CloseWithError (ConcatenateError (err , (& stderr ).String ()))
38
+ _ = batchStdinReader .CloseWithError (ConcatenateError (err , (& stderr ).String ()))
39
+ } else {
40
+ _ = batchStdoutWriter .Close ()
41
+ _ = batchStdinReader .Close ()
42
+ }
43
+ }()
44
+
45
+ // For simplicities sake we'll us a buffered reader to read from the cat-file --batch
46
+ batchReader := bufio .NewReader (batchStdoutReader )
47
+
48
+ return batchStdinWriter , batchReader , cancel
49
+ }
50
+
16
51
// CatFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function
17
- func CatFileBatch (repoPath string ) (* io. PipeWriter , * bufio.Reader , func ()) {
18
- // Next feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
52
+ func CatFileBatch (repoPath string ) (WriteCloserError , * bufio.Reader , func ()) {
53
+ // We often want to feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
19
54
// so let's create a batch stdin and stdout
20
55
batchStdinReader , batchStdinWriter := io .Pipe ()
21
56
batchStdoutReader , batchStdoutWriter := io .Pipe ()
@@ -47,26 +82,28 @@ func CatFileBatch(repoPath string) (*io.PipeWriter, *bufio.Reader, func()) {
47
82
// ReadBatchLine reads the header line from cat-file --batch
48
83
// We expect:
49
84
// <sha> SP <type> SP <size> LF
85
+ // sha is a 40byte not 20byte here
50
86
func ReadBatchLine (rd * bufio.Reader ) (sha []byte , typ string , size int64 , err error ) {
51
87
sha , err = rd .ReadBytes (' ' )
52
88
if err != nil {
53
89
return
54
90
}
55
91
sha = sha [:len (sha )- 1 ]
56
92
57
- typ , err = rd .ReadString (' ' )
93
+ typ , err = rd .ReadString ('\n ' )
58
94
if err != nil {
59
95
return
60
96
}
61
- typ = typ [:len (typ )- 1 ]
62
97
63
- var sizeStr string
64
- sizeStr , err = rd . ReadString ( '\n' )
65
- if err != nil {
98
+ idx := strings . Index ( typ , " " )
99
+ if idx < 0 {
100
+ err = ErrNotExist { ID : string ( sha )}
66
101
return
67
102
}
103
+ sizeStr := typ [idx + 1 : len (typ )- 1 ]
104
+ typ = typ [:idx ]
68
105
69
- size , err = strconv .ParseInt (sizeStr [: len ( sizeStr ) - 1 ] , 10 , 64 )
106
+ size , err = strconv .ParseInt (sizeStr , 10 , 64 )
70
107
return
71
108
}
72
109
@@ -128,7 +165,7 @@ headerLoop:
128
165
}
129
166
130
167
// Discard the rest of the commit
131
- discard := size - n
168
+ discard := size - n + 1
132
169
for discard > math .MaxInt32 {
133
170
_ , err := rd .Discard (math .MaxInt32 )
134
171
if err != nil {
0 commit comments