@@ -10,11 +10,7 @@ import (
10
10
"fmt"
11
11
"io"
12
12
"os"
13
- "os/exec"
14
13
"regexp"
15
-
16
- "code.gitea.io/gitea/modules/process"
17
- "code.gitea.io/gitea/modules/setting"
18
14
)
19
15
20
16
// BlamePart represents block of blame - continuous lines with one sha
@@ -25,12 +21,11 @@ type BlamePart struct {
25
21
26
22
// BlameReader returns part of file blame one by one
27
23
type BlameReader struct {
28
- cmd * exec.Cmd
29
- output io.ReadCloser
30
- reader * bufio.Reader
31
- lastSha * string
32
- cancel context.CancelFunc // Cancels the context that this reader runs in
33
- finished process.FinishedFunc // Tells the process manager we're finished and it can remove the associated process from the process table
24
+ cmd * CommandProxy
25
+ output io.WriteCloser
26
+ reader io.ReadCloser
27
+ done chan error
28
+ lastSha * string
34
29
}
35
30
36
31
var shaLineRegex = regexp .MustCompile ("^([a-z0-9]{40})" )
@@ -39,7 +34,7 @@ var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
39
34
func (r * BlameReader ) NextPart () (* BlamePart , error ) {
40
35
var blamePart * BlamePart
41
36
42
- reader := r .reader
37
+ reader := bufio . NewReader ( r .reader )
43
38
44
39
if r .lastSha != nil {
45
40
blamePart = & BlamePart {* r .lastSha , make ([]string , 0 )}
@@ -101,51 +96,40 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
101
96
102
97
// Close BlameReader - don't run NextPart after invoking that
103
98
func (r * BlameReader ) Close () error {
104
- defer r .finished () // Only remove the process from the process table when the underlying command is closed
105
- r .cancel () // However, first cancel our own context early
106
-
99
+ err := <- r .done
100
+ _ = r .reader .Close ()
107
101
_ = r .output .Close ()
108
102
109
- if err := r .cmd .Wait (); err != nil {
110
- return fmt .Errorf ("Wait: %v" , err )
111
- }
112
-
113
- return nil
103
+ return err
114
104
}
115
105
116
106
// CreateBlameReader creates reader for given repository, commit and file
117
107
func CreateBlameReader (ctx context.Context , repoPath , commitID , file string ) (* BlameReader , error ) {
118
- return createBlameReader (ctx , repoPath , setting . Git . Path , "blame" , commitID , "--porcelain" , "--" , file )
119
- }
108
+ cmd := NewCommandContextNoGlobals (ctx , "blame" , commitID , "--porcelain" , "--" , file )
109
+ cmd . SetDescription ( fmt . Sprintf ( "GetBlame [repo_path: %s]" , repoPath ))
120
110
121
- func createBlameReader (ctx context.Context , dir string , command ... string ) (* BlameReader , error ) {
122
- // Here we use the provided context - this should be tied to the request performing the blame so that it does not hang around.
123
- ctx , cancel , finished := process .GetManager ().AddContext (ctx , fmt .Sprintf ("GetBlame [repo_path: %s]" , dir ))
124
-
125
- cmd := exec .CommandContext (ctx , command [0 ], command [1 :]... )
126
- cmd .Dir = dir
127
- cmd .Stderr = os .Stderr
128
- process .SetSysProcAttribute (cmd )
129
-
130
- stdout , err := cmd .StdoutPipe ()
111
+ reader , stdout , err := os .Pipe ()
131
112
if err != nil {
132
- defer finished ()
133
- return nil , fmt .Errorf ("StdoutPipe: %v" , err )
113
+ return nil , err
134
114
}
135
115
136
- if err = cmd .Start (); err != nil {
137
- defer finished ()
138
- _ = stdout .Close ()
139
- return nil , fmt .Errorf ("Start: %v" , err )
140
- }
116
+ done := make (chan error , 1 )
141
117
142
- reader := bufio .NewReader (stdout )
118
+ go func (cmd * CommandProxy , dir string , stdout io.WriteCloser , done chan error ) {
119
+ if err := cmd .Run (& RunOpts {
120
+ Dir : dir ,
121
+ Stdout : stdout ,
122
+ Stderr : os .Stderr ,
123
+ }); err == nil {
124
+ stdout .Close ()
125
+ }
126
+ done <- err
127
+ }(cmd , repoPath , stdout , done )
143
128
144
129
return & BlameReader {
145
- cmd : cmd ,
146
- output : stdout ,
147
- reader : reader ,
148
- cancel : cancel ,
149
- finished : finished ,
130
+ cmd : cmd ,
131
+ output : stdout ,
132
+ reader : reader ,
133
+ done : done ,
150
134
}, nil
151
135
}
0 commit comments