diff options
Diffstat (limited to 'modules/git/repo_attribute.go')
-rw-r--r-- | modules/git/repo_attribute.go | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go index 90eb783fe8..e7c6c1a47f 100644 --- a/modules/git/repo_attribute.go +++ b/modules/git/repo_attribute.go @@ -9,6 +9,8 @@ import ( "fmt" "io" "os" + "path/filepath" + "time" "code.gitea.io/gitea/modules/log" ) @@ -102,7 +104,7 @@ type CheckAttributeReader struct { stdinReader io.ReadCloser stdinWriter *os.File - stdOut attributeWriter + stdOut *nulSeparatedAttributeWriter cmd *Command env []string ctx context.Context @@ -152,7 +154,6 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error { return nil } -// Run run cmd func (c *CheckAttributeReader) Run() error { defer func() { _ = c.stdinReader.Close() @@ -176,7 +177,7 @@ func (c *CheckAttributeReader) Run() error { func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err error) { defer func() { if err != nil && err != c.ctx.Err() { - log.Error("Unexpected error when checking path %s in %s. Error: %v", path, c.Repo.Path, err) + log.Error("Unexpected error when checking path %s in %s, error: %v", path, filepath.Base(c.Repo.Path), err) } }() @@ -191,9 +192,31 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err return nil, err } + reportTimeout := func() error { + stdOutClosed := false + select { + case <-c.stdOut.closed: + stdOutClosed = true + default: + } + debugMsg := fmt.Sprintf("check path %q in repo %q", path, filepath.Base(c.Repo.Path)) + debugMsg += fmt.Sprintf(", stdOut: tmp=%q, pos=%d, closed=%v", string(c.stdOut.tmp), c.stdOut.pos, stdOutClosed) + if c.cmd.cmd != nil { + debugMsg += fmt.Sprintf(", process state: %q", c.cmd.cmd.ProcessState.String()) + } + _ = c.Close() + return fmt.Errorf("CheckPath timeout: %s", debugMsg) + } + rs = make(map[string]string) for range c.Attributes { select { + case <-time.After(5 * time.Second): + // There is a strange "hang" problem in gitdiff.GetDiff -> CheckPath + // So add a timeout here to mitigate the problem, and output more logs for debug purpose + // In real world, if CheckPath runs long than seconds, it blocks the end user's operation, + // and at the moment the CheckPath result is not so important, so we can just ignore it. + return nil, reportTimeout() case attr, ok := <-c.stdOut.ReadAttribute(): if !ok { return nil, c.ctx.Err() @@ -206,18 +229,12 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err return rs, nil } -// Close close pip after use func (c *CheckAttributeReader) Close() error { c.cancel() err := c.stdinWriter.Close() return err } -type attributeWriter interface { - io.WriteCloser - ReadAttribute() <-chan attributeTriple -} - type attributeTriple struct { Filename string Attribute string @@ -263,7 +280,7 @@ func (wr *nulSeparatedAttributeWriter) Write(p []byte) (n int, err error) { } } wr.tmp = append(wr.tmp, p...) - return len(p), nil + return l, nil } func (wr *nulSeparatedAttributeWriter) ReadAttribute() <-chan attributeTriple { @@ -281,7 +298,7 @@ func (wr *nulSeparatedAttributeWriter) Close() error { return nil } -// Create a check attribute reader for the current repository and provided commit ID +// CheckAttributeReader creates a check attribute reader for the current repository and provided commit ID func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeReader, context.CancelFunc) { indexFilename, worktree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID) if err != nil { @@ -303,21 +320,21 @@ func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeRe } ctx, cancel := context.WithCancel(repo.Ctx) if err := checker.Init(ctx); err != nil { - log.Error("Unable to open checker for %s. Error: %v", commitID, err) + log.Error("Unable to open attribute checker for commit %s, error: %v", commitID, err) } else { go func() { err := checker.Run() - if err != nil && err != ctx.Err() { - log.Error("Unable to open checker for %s. Error: %v", commitID, err) + if err != nil && !IsErrCanceledOrKilled(err) { + log.Error("Attribute checker for commit %s exits with error: %v", commitID, err) } cancel() }() } - deferable := func() { + deferrable := func() { _ = checker.Close() cancel() deleteTemporaryFile() } - return checker, deferable + return checker, deferrable } |