Skip to content

Commit 9da4642

Browse files
zeripathbrechtvllunny
authored
Fix blame view missing lines (#22826) (#22929)
Backport #22826 Creating a new buffered reader for every part of the blame can miss lines, as it will read and buffer bytes that the next buffered reader will not get. --------- Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Brecht Van Lommel <brecht@blender.org> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
1 parent 1d191f9 commit 9da4642

File tree

2 files changed

+22
-24
lines changed

2 files changed

+22
-24
lines changed

modules/git/blame.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ type BlamePart struct {
2424

2525
// BlameReader returns part of file blame one by one
2626
type BlameReader struct {
27-
cmd *exec.Cmd
28-
output io.ReadCloser
29-
reader *bufio.Reader
30-
lastSha *string
31-
cancel context.CancelFunc // Cancels the context that this reader runs in
32-
finished process.FinishedFunc // Tells the process manager we're finished and it can remove the associated process from the process table
27+
cmd *exec.Cmd
28+
reader io.ReadCloser
29+
lastSha *string
30+
cancel context.CancelFunc // Cancels the context that this reader runs in
31+
finished process.FinishedFunc // Tells the process manager we're finished and it can remove the associated process from the process table
32+
bufferedReader *bufio.Reader
3333
}
3434

3535
var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
@@ -38,8 +38,6 @@ var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
3838
func (r *BlameReader) NextPart() (*BlamePart, error) {
3939
var blamePart *BlamePart
4040

41-
reader := r.reader
42-
4341
if r.lastSha != nil {
4442
blamePart = &BlamePart{*r.lastSha, make([]string, 0)}
4543
}
@@ -49,7 +47,7 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
4947
var err error
5048

5149
for err != io.EOF {
52-
line, isPrefix, err = reader.ReadLine()
50+
line, isPrefix, err = r.bufferedReader.ReadLine()
5351
if err != nil && err != io.EOF {
5452
return blamePart, err
5553
}
@@ -71,7 +69,7 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
7169
r.lastSha = &sha1
7270
// need to munch to end of line...
7371
for isPrefix {
74-
_, isPrefix, err = reader.ReadLine()
72+
_, isPrefix, err = r.bufferedReader.ReadLine()
7573
if err != nil && err != io.EOF {
7674
return blamePart, err
7775
}
@@ -86,7 +84,7 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
8684

8785
// need to munch to end of line...
8886
for isPrefix {
89-
_, isPrefix, err = reader.ReadLine()
87+
_, isPrefix, err = r.bufferedReader.ReadLine()
9088
if err != nil && err != io.EOF {
9189
return blamePart, err
9290
}
@@ -102,9 +100,9 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
102100
func (r *BlameReader) Close() error {
103101
defer r.finished() // Only remove the process from the process table when the underlying command is closed
104102
r.cancel() // However, first cancel our own context early
103+
r.bufferedReader = nil
105104

106-
_ = r.output.Close()
107-
105+
_ = r.reader.Close()
108106
if err := r.cmd.Wait(); err != nil {
109107
return fmt.Errorf("Wait: %w", err)
110108
}
@@ -126,25 +124,27 @@ func createBlameReader(ctx context.Context, dir string, command ...string) (*Bla
126124
cmd.Stderr = os.Stderr
127125
process.SetSysProcAttribute(cmd)
128126

129-
stdout, err := cmd.StdoutPipe()
127+
reader, stdout, err := os.Pipe()
130128
if err != nil {
131129
defer finished()
132130
return nil, fmt.Errorf("StdoutPipe: %w", err)
133131
}
132+
cmd.Stdout = stdout
134133

135134
if err = cmd.Start(); err != nil {
136135
defer finished()
137136
_ = stdout.Close()
138137
return nil, fmt.Errorf("Start: %w", err)
139138
}
139+
_ = stdout.Close()
140140

141-
reader := bufio.NewReader(stdout)
141+
bufferedReader := bufio.NewReader(reader)
142142

143143
return &BlameReader{
144-
cmd: cmd,
145-
output: stdout,
146-
reader: reader,
147-
cancel: cancel,
148-
finished: finished,
144+
cmd: cmd,
145+
reader: reader,
146+
cancel: cancel,
147+
finished: finished,
148+
bufferedReader: bufferedReader,
149149
}, nil
150150
}

modules/git/blame_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ summary Add code of delete user
6565
previous be0ba9ea88aff8a658d0495d36accf944b74888d gogs.go
6666
filename gogs.go
6767
// license that can be found in the LICENSE file.
68-
68+
` + `
6969
e2aa991e10ffd924a828ec149951f2f20eecead2 6 6 2
7070
author Lunny Xiao
7171
author-mail <xiaolunwen@gmail.com>
@@ -112,9 +112,7 @@ func TestReadingBlameOutput(t *testing.T) {
112112
},
113113
{
114114
"ce21ed6c3490cdfad797319cbb1145e2330a8fef",
115-
[]string{
116-
"// Copyright 2016 The Gitea Authors. All rights reserved.",
117-
},
115+
[]string{"// Copyright 2016 The Gitea Authors. All rights reserved."},
118116
},
119117
{
120118
"4b92a6c2df28054ad766bc262f308db9f6066596",

0 commit comments

Comments
 (0)