diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2023-01-03 16:17:13 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-03 16:17:13 +0800 |
commit | efa708501be70201f048c2936addfd1bcf570d31 (patch) | |
tree | 5759a3f000602ebc4bb20120dc969e7a0c1acb61 /modules/git/blame.go | |
parent | c59e1537a8bb57af0ca19c0adfe8ab613c567193 (diff) | |
download | gitea-efa708501be70201f048c2936addfd1bcf570d31.tar.gz gitea-efa708501be70201f048c2936addfd1bcf570d31.zip |
Use git command instead of exec.Cmd in blame (#22098)
extract from #18147
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Diffstat (limited to 'modules/git/blame.go')
-rw-r--r-- | modules/git/blame.go | 76 |
1 files changed, 31 insertions, 45 deletions
diff --git a/modules/git/blame.go b/modules/git/blame.go index fea75b4818..3b6e4c95db 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -9,10 +9,7 @@ import ( "fmt" "io" "os" - "os/exec" "regexp" - - "code.gitea.io/gitea/modules/process" ) // BlamePart represents block of blame - continuous lines with one sha @@ -23,12 +20,11 @@ type BlamePart struct { // BlameReader returns part of file blame one by one type BlameReader struct { - cmd *exec.Cmd - output io.ReadCloser - reader *bufio.Reader - lastSha *string - cancel context.CancelFunc // Cancels the context that this reader runs in - finished process.FinishedFunc // Tells the process manager we're finished and it can remove the associated process from the process table + cmd *Command + output io.WriteCloser + reader io.ReadCloser + done chan error + lastSha *string } var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})") @@ -37,7 +33,7 @@ var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})") func (r *BlameReader) NextPart() (*BlamePart, error) { var blamePart *BlamePart - reader := r.reader + reader := bufio.NewReader(r.reader) if r.lastSha != nil { blamePart = &BlamePart{*r.lastSha, make([]string, 0)} @@ -99,51 +95,41 @@ func (r *BlameReader) NextPart() (*BlamePart, error) { // Close BlameReader - don't run NextPart after invoking that func (r *BlameReader) Close() error { - defer r.finished() // Only remove the process from the process table when the underlying command is closed - r.cancel() // However, first cancel our own context early - + err := <-r.done + _ = r.reader.Close() _ = r.output.Close() - - if err := r.cmd.Wait(); err != nil { - return fmt.Errorf("Wait: %w", err) - } - - return nil + return err } // CreateBlameReader creates reader for given repository, commit and file func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) { - return createBlameReader(ctx, repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file) -} - -func createBlameReader(ctx context.Context, dir string, command ...string) (*BlameReader, error) { - // Here we use the provided context - this should be tied to the request performing the blame so that it does not hang around. - ctx, cancel, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("GetBlame [repo_path: %s]", dir)) - - cmd := exec.CommandContext(ctx, command[0], command[1:]...) - cmd.Dir = dir - cmd.Stderr = os.Stderr - process.SetSysProcAttribute(cmd) - - stdout, err := cmd.StdoutPipe() + cmd := NewCommandContextNoGlobals(ctx, "blame", "--porcelain"). + AddDynamicArguments(commitID). + AddDashesAndList(file). + SetDescription(fmt.Sprintf("GetBlame [repo_path: %s]", repoPath)) + reader, stdout, err := os.Pipe() if err != nil { - defer finished() - return nil, fmt.Errorf("StdoutPipe: %w", err) + return nil, err } - if err = cmd.Start(); err != nil { - defer finished() - _ = stdout.Close() - return nil, fmt.Errorf("Start: %w", err) - } + done := make(chan error, 1) - reader := bufio.NewReader(stdout) + go func(cmd *Command, dir string, stdout io.WriteCloser, done chan error) { + if err := cmd.Run(&RunOpts{ + UseContextTimeout: true, + Dir: dir, + Stdout: stdout, + Stderr: os.Stderr, + }); err == nil { + stdout.Close() + } + done <- err + }(cmd, repoPath, stdout, done) return &BlameReader{ - cmd: cmd, - output: stdout, - reader: reader, - cancel: cancel, - finished: finished, + cmd: cmd, + output: stdout, + reader: reader, + done: done, }, nil } |