9
9
"fmt"
10
10
"io"
11
11
"os"
12
+ "path/filepath"
13
+ "time"
12
14
13
15
"code.gitea.io/gitea/modules/log"
14
16
)
@@ -102,7 +104,7 @@ type CheckAttributeReader struct {
102
104
103
105
stdinReader io.ReadCloser
104
106
stdinWriter * os.File
105
- stdOut attributeWriter
107
+ stdOut * nulSeparatedAttributeWriter
106
108
cmd * Command
107
109
env []string
108
110
ctx context.Context
@@ -152,7 +154,6 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error {
152
154
return nil
153
155
}
154
156
155
- // Run run cmd
156
157
func (c * CheckAttributeReader ) Run () error {
157
158
defer func () {
158
159
_ = c .stdinReader .Close ()
@@ -176,7 +177,7 @@ func (c *CheckAttributeReader) Run() error {
176
177
func (c * CheckAttributeReader ) CheckPath (path string ) (rs map [string ]string , err error ) {
177
178
defer func () {
178
179
if err != nil && err != c .ctx .Err () {
179
- log .Error ("Unexpected error when checking path %s in %s. Error : %v" , path , c .Repo .Path , err )
180
+ log .Error ("Unexpected error when checking path %s in %s, error : %v" , path , filepath . Base ( c .Repo .Path ) , err )
180
181
}
181
182
}()
182
183
@@ -191,9 +192,31 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
191
192
return nil , err
192
193
}
193
194
195
+ reportTimeout := func () error {
196
+ stdOutClosed := false
197
+ select {
198
+ case <- c .stdOut .closed :
199
+ stdOutClosed = true
200
+ default :
201
+ }
202
+ debugMsg := fmt .Sprintf ("check path %q in repo %q" , path , filepath .Base (c .Repo .Path ))
203
+ debugMsg += fmt .Sprintf (", stdOut: tmp=%q, pos=%d, closed=%v" , string (c .stdOut .tmp ), c .stdOut .pos , stdOutClosed )
204
+ if c .cmd .cmd != nil {
205
+ debugMsg += fmt .Sprintf (", process state: %q" , c .cmd .cmd .ProcessState .String ())
206
+ }
207
+ _ = c .Close ()
208
+ return fmt .Errorf ("CheckPath timeout: %s" , debugMsg )
209
+ }
210
+
194
211
rs = make (map [string ]string )
195
212
for range c .Attributes {
196
213
select {
214
+ case <- time .After (5 * time .Second ):
215
+ // There is a strange "hang" problem in gitdiff.GetDiff -> CheckPath
216
+ // So add a timeout here to mitigate the problem, and output more logs for debug purpose
217
+ // In real world, if CheckPath runs long than seconds, it blocks the end user's operation,
218
+ // and at the moment the CheckPath result is not so important, so we can just ignore it.
219
+ return nil , reportTimeout ()
197
220
case attr , ok := <- c .stdOut .ReadAttribute ():
198
221
if ! ok {
199
222
return nil , c .ctx .Err ()
@@ -206,18 +229,12 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
206
229
return rs , nil
207
230
}
208
231
209
- // Close close pip after use
210
232
func (c * CheckAttributeReader ) Close () error {
211
233
c .cancel ()
212
234
err := c .stdinWriter .Close ()
213
235
return err
214
236
}
215
237
216
- type attributeWriter interface {
217
- io.WriteCloser
218
- ReadAttribute () <- chan attributeTriple
219
- }
220
-
221
238
type attributeTriple struct {
222
239
Filename string
223
240
Attribute string
@@ -281,7 +298,7 @@ func (wr *nulSeparatedAttributeWriter) Close() error {
281
298
return nil
282
299
}
283
300
284
- // Create a check attribute reader for the current repository and provided commit ID
301
+ // CheckAttributeReader creates a check attribute reader for the current repository and provided commit ID
285
302
func (repo * Repository ) CheckAttributeReader (commitID string ) (* CheckAttributeReader , context.CancelFunc ) {
286
303
indexFilename , worktree , deleteTemporaryFile , err := repo .ReadTreeToTemporaryIndex (commitID )
287
304
if err != nil {
@@ -303,21 +320,21 @@ func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeRe
303
320
}
304
321
ctx , cancel := context .WithCancel (repo .Ctx )
305
322
if err := checker .Init (ctx ); err != nil {
306
- log .Error ("Unable to open checker for %s. Error : %v" , commitID , err )
323
+ log .Error ("Unable to open attribute checker for commit %s, error : %v" , commitID , err )
307
324
} else {
308
325
go func () {
309
326
err := checker .Run ()
310
- if err != nil && err != ctx . Err ( ) {
311
- log .Error ("Unable to open checker for %s. Error : %v" , commitID , err )
327
+ if err != nil && ! IsErrCanceledOrKilled ( err ) {
328
+ log .Error ("Attribute checker for commit %s exits with error : %v" , commitID , err )
312
329
}
313
330
cancel ()
314
331
}()
315
332
}
316
- deferable := func () {
333
+ deferrable := func () {
317
334
_ = checker .Close ()
318
335
cancel ()
319
336
deleteTemporaryFile ()
320
337
}
321
338
322
- return checker , deferable
339
+ return checker , deferrable
323
340
}
0 commit comments