Remove git.Command.Run and git.Command.RunInDir* (#19280)

Follows #19266, #8553, Close #18553, now there are only three `Run..(&RunOpts{})` functions.
 * before: `stdout, err := RunInDir(path)`
 * now: `stdout, _, err := RunStdString(&git.RunOpts{Dir:path})`
This commit is contained in:
2022-04-01 10:55:30 +08:00
committed by GitHub
parent 3a73645502
commit 124b072f0b
78 changed files with 594 additions and 672 deletions

View File

@ -309,7 +309,7 @@ func runHookPostReceive(c *cli.Context) error {
defer cancel()
// First of all run update-server-info no matter what
if _, err := git.NewCommand(ctx, "update-server-info").Run(); err != nil {
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
}

View File

@ -28,8 +28,8 @@ func TestAPIGitTags(t *testing.T) {
token := getTokenForLoggedInUser(t, session)
// Set up git config for the tagger
git.NewCommand(git.DefaultContext, "config", "user.name", user.Name).RunInDir(repo.RepoPath())
git.NewCommand(git.DefaultContext, "config", "user.email", user.Email).RunInDir(repo.RepoPath())
_ = git.NewCommand(git.DefaultContext, "config", "user.name", user.Name).Run(&git.RunOpts{Dir: repo.RepoPath()})
_ = git.NewCommand(git.DefaultContext, "config", "user.email", user.Email).Run(&git.RunOpts{Dir: repo.RepoPath()})
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
defer gitRepo.Close()

View File

@ -134,7 +134,7 @@ func doGitInitTestRepository(dstPath string) func(*testing.T) {
// Init repository in dstPath
assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false))
// forcibly set default branch to master
_, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0o644))
assert.NoError(t, git.AddChanges(dstPath, true))
@ -153,49 +153,49 @@ func doGitInitTestRepository(dstPath string) func(*testing.T) {
func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "remote", "add", remoteName, u.String()).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, "remote", "add", remoteName, u.String()).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPushTestRepository(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"push", "-u"}, args...)...).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"push", "-u"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPushTestRepositoryFail(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"push"}, args...)...).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"push"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.Error(t, err)
}
}
func doGitCreateBranch(dstPath, branch string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "checkout", "-b", branch).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, "checkout", "-b", branch).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "checkout"), args...)...).RunInDir(dstPath)
_, _, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "checkout"), args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitMerge(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"merge"}, args...)...).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"merge"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPull(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "pull"), args...)...).RunInDir(dstPath)
_, _, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "pull"), args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}

View File

@ -160,9 +160,9 @@ func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS strin
return
}
prefix := "lfs-data-file-"
_, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").RunInDir(dstPath)
err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track", prefix+"*").RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track", prefix+"*").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
err = git.AddChanges(dstPath, false, ".gitattributes")
assert.NoError(t, err)
@ -292,20 +292,20 @@ func lockTest(t *testing.T, repoPath string) {
}
func lockFileTest(t *testing.T, filename, repoPath string) {
_, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunInDir(repoPath)
_, _, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock", filename).RunInDir(repoPath)
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock", filename).RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunInDir(repoPath)
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock", filename).RunInDir(repoPath)
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock", filename).RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
}
func doCommitAndPush(t *testing.T, size int, repoPath, prefix string) string {
name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two", prefix)
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunInDir(repoPath) // Push
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunStdString(&git.RunOpts{Dir: repoPath}) // Push
assert.NoError(t, err)
return name
}
@ -671,7 +671,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
})
t.Run("Push", func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).RunInDir(dstPath)
err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}
@ -692,7 +692,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
assert.Contains(t, "Testing commit 1", prMsg.Body)
assert.Equal(t, commit, prMsg.Head.Sha)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}
@ -745,7 +745,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
})
t.Run("Push2", func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).RunInDir(dstPath)
err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}
@ -757,7 +757,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
assert.Equal(t, false, prMsg.HasMerged)
assert.Equal(t, commit, prMsg.Head.Sha)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}

View File

@ -269,25 +269,24 @@ func TestCantMergeUnrelated(t *testing.T) {
}).(*repo_model.Repository)
path := repo_model.RepoPath(user1.Name, repo1.Name)
_, err := git.NewCommand(git.DefaultContext, "read-tree", "--empty").RunInDir(path)
err := git.NewCommand(git.DefaultContext, "read-tree", "--empty").Run(&git.RunOpts{Dir: path})
assert.NoError(t, err)
stdin := bytes.NewBufferString("Unrelated File")
var stdout strings.Builder
err = git.NewCommand(git.DefaultContext, "hash-object", "-w", "--stdin").RunWithContext(&git.RunContext{
Timeout: -1,
Dir: path,
Stdin: stdin,
Stdout: &stdout,
err = git.NewCommand(git.DefaultContext, "hash-object", "-w", "--stdin").Run(&git.RunOpts{
Dir: path,
Stdin: stdin,
Stdout: &stdout,
})
assert.NoError(t, err)
sha := strings.TrimSpace(stdout.String())
_, err = git.NewCommand(git.DefaultContext, "update-index", "--add", "--replace", "--cacheinfo", "100644", sha, "somewher-over-the-rainbow").RunInDir(path)
_, _, err = git.NewCommand(git.DefaultContext, "update-index", "--add", "--replace", "--cacheinfo", "100644", sha, "somewher-over-the-rainbow").RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err)
treeSha, err := git.NewCommand(git.DefaultContext, "write-tree").RunInDir(path)
treeSha, _, err := git.NewCommand(git.DefaultContext, "write-tree").RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err)
treeSha = strings.TrimSpace(treeSha)
@ -308,17 +307,16 @@ func TestCantMergeUnrelated(t *testing.T) {
stdout.Reset()
err = git.NewCommand(git.DefaultContext, "commit-tree", treeSha).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: path,
Stdin: messageBytes,
Stdout: &stdout,
Run(&git.RunOpts{
Env: env,
Dir: path,
Stdin: messageBytes,
Stdout: &stdout,
})
assert.NoError(t, err)
commitSha := strings.TrimSpace(stdout.String())
_, err = git.NewCommand(git.DefaultContext, "branch", "unrelated", commitSha).RunInDir(path)
_, _, err = git.NewCommand(git.DefaultContext, "branch", "unrelated", commitSha).RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err)
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")

View File

@ -66,10 +66,10 @@ func TestCreateNewTagProtected(t *testing.T) {
doGitClone(dstPath, u)(t)
_, err = git.NewCommand(git.DefaultContext, "tag", "v-2").RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "tag", "v-2").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunStdString(&git.RunOpts{Dir: dstPath})
assert.Error(t, err)
assert.Contains(t, err.Error(), "Tag v-2 is protected")
})

View File

@ -83,17 +83,17 @@ func fixMergeBase(x *xorm.Engine) error {
if !pr.HasMerged {
var err error
pr.MergeBase, err = git.NewCommand(git.DefaultContext, "merge-base", "--", pr.BaseBranch, gitRefName).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, "merge-base", "--", pr.BaseBranch, gitRefName).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
var err2 error
pr.MergeBase, err2 = git.NewCommand(git.DefaultContext, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath)
pr.MergeBase, _, err2 = git.NewCommand(git.DefaultContext, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath})
if err2 != nil {
log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2)
continue
}
}
} else {
parentsString, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue
@ -106,7 +106,7 @@ func fixMergeBase(x *xorm.Engine) error {
args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, gitRefName)
pr.MergeBase, err = git.NewCommand(git.DefaultContext, args...).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, args...).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue

View File

@ -80,7 +80,7 @@ func refixMergeBase(x *xorm.Engine) error {
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
parentsString, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue
@ -94,7 +94,7 @@ func refixMergeBase(x *xorm.Engine) error {
args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, gitRefName)
pr.MergeBase, err = git.NewCommand(git.DefaultContext, args...).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, args...).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue

View File

@ -44,17 +44,17 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
if !pr.HasMerged {
var err error
pr.MergeBase, err = git.NewCommand(ctx, "merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(ctx, "merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
var err2 error
pr.MergeBase, err2 = git.NewCommand(ctx, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath)
pr.MergeBase, _, err2 = git.NewCommand(ctx, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath})
if err2 != nil {
logger.Warn("Unable to get merge base for PR ID %d, #%d onto %s in %s/%s. Error: %v & %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err, err2)
return nil
}
}
} else {
parentsString, err := git.NewCommand(ctx, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
parentsString, _, err := git.NewCommand(ctx, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
logger.Warn("Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
return nil
@ -67,7 +67,7 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, pr.GetGitRefName())
pr.MergeBase, err = git.NewCommand(ctx, args...).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(ctx, args...).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
logger.Warn("Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
return nil

View File

@ -95,11 +95,11 @@ func checkEnablePushOptions(ctx context.Context, logger log.Logger, autofix bool
defer r.Close()
if autofix {
_, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions", "true").RunInDir(r.Path)
_, _, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions", "true").RunStdString(&git.RunOpts{Dir: r.Path})
return err
}
value, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions").RunInDir(r.Path)
value, _, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions").RunStdString(&git.RunOpts{Dir: r.Path})
if err != nil {
return err
}

View File

@ -34,10 +34,9 @@ func EnsureValidGitRepository(ctx context.Context, repoPath string) error {
stderr := strings.Builder{}
err := NewCommand(ctx, "rev-parse").
SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stderr: &stderr,
Run(&RunOpts{
Dir: repoPath,
Stderr: &stderr,
})
if err != nil {
return ConcatenateError(err, (&stderr).String())
@ -65,12 +64,11 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
stderr := strings.Builder{}
err := NewCommand(ctx, "cat-file", "--batch-check").
SetDescription(fmt.Sprintf("%s cat-file --batch-check [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdin: batchStdinReader,
Stdout: batchStdoutWriter,
Stderr: &stderr,
Run(&RunOpts{
Dir: repoPath,
Stdin: batchStdinReader,
Stdout: batchStdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
@ -110,12 +108,11 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
stderr := strings.Builder{}
err := NewCommand(ctx, "cat-file", "--batch").
SetDescription(fmt.Sprintf("%s cat-file --batch [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdin: batchStdinReader,
Stdout: batchStdoutWriter,
Stderr: &stderr,
Run(&RunOpts{
Dir: repoPath,
Stdin: batchStdinReader,
Stdout: batchStdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))

View File

@ -94,8 +94,8 @@ func (c *Command) AddArguments(args ...string) *Command {
return c
}
// RunContext represents parameters to run the command
type RunContext struct {
// RunOpts represents parameters to run the command
type RunOpts struct {
Env []string
Timeout time.Duration
Dir string
@ -104,16 +104,19 @@ type RunContext struct {
PipelineFunc func(context.Context, context.CancelFunc) error
}
// RunWithContext run the command with context
func (c *Command) RunWithContext(rc *RunContext) error {
if rc.Timeout <= 0 {
rc.Timeout = defaultCommandExecutionTimeout
// Run runs the command with the RunOpts
func (c *Command) Run(opts *RunOpts) error {
if opts == nil {
opts = &RunOpts{}
}
if opts.Timeout <= 0 {
opts.Timeout = defaultCommandExecutionTimeout
}
if len(rc.Dir) == 0 {
if len(opts.Dir) == 0 {
log.Debug("%s", c)
} else {
log.Debug("%s: %v", rc.Dir, c)
log.Debug("%s: %v", opts.Dir, c)
}
desc := c.desc
@ -132,17 +135,17 @@ func (c *Command) RunWithContext(rc *RunContext) error {
args[urlArgIndex] = util.SanitizeCredentialURLs(args[urlArgIndex])
}
}
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), rc.Dir)
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir)
}
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc)
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
defer finished()
cmd := exec.CommandContext(ctx, c.name, c.args...)
if rc.Env == nil {
if opts.Env == nil {
cmd.Env = os.Environ()
} else {
cmd.Env = rc.Env
cmd.Env = opts.Env
}
cmd.Env = append(
@ -154,16 +157,16 @@ func (c *Command) RunWithContext(rc *RunContext) error {
"GIT_NO_REPLACE_OBJECTS=1",
)
cmd.Dir = rc.Dir
cmd.Stdout = rc.Stdout
cmd.Stderr = rc.Stderr
cmd.Stdin = rc.Stdin
cmd.Dir = opts.Dir
cmd.Stdout = opts.Stdout
cmd.Stderr = opts.Stderr
cmd.Stdin = opts.Stdin
if err := cmd.Start(); err != nil {
return err
}
if rc.PipelineFunc != nil {
err := rc.PipelineFunc(ctx, cancel)
if opts.PipelineFunc != nil {
err := opts.PipelineFunc(ctx, cancel)
if err != nil {
cancel()
_ = cmd.Wait()
@ -178,18 +181,18 @@ func (c *Command) RunWithContext(rc *RunContext) error {
return ctx.Err()
}
type RunError interface {
type RunStdError interface {
error
Stderr() string
}
type runError struct {
type runStdError struct {
err error
stderr string
errMsg string
}
func (r *runError) Error() string {
func (r *runStdError) Error() string {
// the stderr must be in the returned error text, some code only checks `strings.Contains(err.Error(), "git error")`
if r.errMsg == "" {
r.errMsg = ConcatenateError(r.err, r.stderr).Error()
@ -197,11 +200,11 @@ func (r *runError) Error() string {
return r.errMsg
}
func (r *runError) Unwrap() error {
func (r *runStdError) Unwrap() error {
return r.err
}
func (r *runError) Stderr() string {
func (r *runStdError) Stderr() string {
return r.stderr
}
@ -209,64 +212,40 @@ func bytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b)) // that's what Golang's strings.Builder.String() does (go/src/strings/builder.go)
}
// RunWithContextString run the command with context and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
func (c *Command) RunWithContextString(rc *RunContext) (stdout, stderr string, runErr RunError) {
stdoutBytes, stderrBytes, err := c.RunWithContextBytes(rc)
// RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
stdoutBytes, stderrBytes, err := c.RunStdBytes(opts)
stdout = bytesToString(stdoutBytes)
stderr = bytesToString(stderrBytes)
if err != nil {
return stdout, stderr, &runError{err: err, stderr: stderr}
return stdout, stderr, &runStdError{err: err, stderr: stderr}
}
// even if there is no err, there could still be some stderr output, so we just return stdout/stderr as they are
return stdout, stderr, nil
}
// RunWithContextBytes run the command with context and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
func (c *Command) RunWithContextBytes(rc *RunContext) (stdout, stderr []byte, runErr RunError) {
if rc.Stdout != nil || rc.Stderr != nil {
// RunStdBytes runs the command with options and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
if opts == nil {
opts = &RunOpts{}
}
if opts.Stdout != nil || opts.Stderr != nil {
// we must panic here, otherwise there would be bugs if developers set Stdin/Stderr by mistake, and it would be very difficult to debug
panic("stdout and stderr field must be nil when using RunWithContextBytes")
panic("stdout and stderr field must be nil when using RunStdBytes")
}
stdoutBuf := &bytes.Buffer{}
stderrBuf := &bytes.Buffer{}
rc.Stdout = stdoutBuf
rc.Stderr = stderrBuf
err := c.RunWithContext(rc)
opts.Stdout = stdoutBuf
opts.Stderr = stderrBuf
err := c.Run(opts)
stderr = stderrBuf.Bytes()
if err != nil {
return nil, stderr, &runError{err: err, stderr: string(stderr)}
return nil, stderr, &runStdError{err: err, stderr: bytesToString(stderr)}
}
// even if there is no err, there could still be some stderr output
return stdoutBuf.Bytes(), stderr, nil
}
// RunInDirBytes executes the command in given directory
// and returns stdout in []byte and error (combined with stderr).
func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
stdout, _, err := c.RunWithContextBytes(&RunContext{Dir: dir})
return stdout, err
}
// RunInDir executes the command in given directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) RunInDir(dir string) (string, error) {
return c.RunInDirWithEnv(dir, nil)
}
// RunInDirWithEnv executes the command in given directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) RunInDirWithEnv(dir string, env []string) (string, error) {
stdout, _, err := c.RunWithContextString(&RunContext{Env: env, Dir: dir})
return stdout, err
}
// Run executes the command in default working directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) Run() (string, error) {
stdout, _, err := c.RunWithContextString(&RunContext{})
return stdout, err
}
// AllowLFSFiltersArgs return globalCommandArgs with lfs filter, it should only be used for tests
func AllowLFSFiltersArgs() []string {
// Now here we should explicitly allow lfs filters to run

View File

@ -19,7 +19,7 @@ func TestRunWithContextNoTimeout(t *testing.T) {
// 'git --version' does not block so it must be finished before the timeout triggered.
cmd := NewCommand(context.Background(), "--version")
for i := 0; i < maxLoops; i++ {
if err := cmd.RunWithContext(&RunContext{}); err != nil {
if err := cmd.Run(&RunOpts{}); err != nil {
t.Fatal(err)
}
}
@ -31,7 +31,7 @@ func TestRunWithContextTimeout(t *testing.T) {
// 'git hash-object --stdin' blocks on stdin so we can have the timeout triggered.
cmd := NewCommand(context.Background(), "hash-object", "--stdin")
for i := 0; i < maxLoops; i++ {
if err := cmd.RunWithContext(&RunContext{Timeout: 1 * time.Millisecond}); err != nil {
if err := cmd.Run(&RunOpts{Timeout: 1 * time.Millisecond}); err != nil {
if err != context.DeadlineExceeded {
t.Fatalf("Testing %d/%d: %v", i, maxLoops, err)
}

View File

@ -13,13 +13,13 @@ import (
func TestRunWithContextStd(t *testing.T) {
cmd := NewCommand(context.Background(), "--version")
stdout, stderr, err := cmd.RunWithContextString(&RunContext{})
stdout, stderr, err := cmd.RunStdString(&RunOpts{})
assert.NoError(t, err)
assert.Empty(t, stderr)
assert.Contains(t, stdout, "git version")
cmd = NewCommand(context.Background(), "--no-such-arg")
stdout, stderr, err = cmd.RunWithContextString(&RunContext{})
stdout, stderr, err = cmd.RunStdString(&RunOpts{})
if assert.Error(t, err) {
assert.Equal(t, stderr, err.Stderr())
assert.Contains(t, err.Stderr(), "unknown option:")

View File

@ -94,7 +94,7 @@ func AddChangesWithArgs(repoPath string, globalArgs []string, all bool, files ..
cmd.AddArguments("--all")
}
cmd.AddArguments("--")
_, err := cmd.AddArguments(files...).RunInDir(repoPath)
_, _, err := cmd.AddArguments(files...).RunStdString(&RunOpts{Dir: repoPath})
return err
}
@ -130,7 +130,7 @@ func CommitChangesWithArgs(repoPath string, args []string, opts CommitChangesOpt
}
cmd.AddArguments("-m", opts.Message)
_, err := cmd.RunInDir(repoPath)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
// No stderr but exit status 1 means nothing to commit.
if err != nil && err.Error() == "exit status 1" {
return nil
@ -151,7 +151,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
cmd.AddArguments(files...)
}
stdout, err := cmd.RunInDir(repoPath)
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return 0, err
}
@ -168,7 +168,7 @@ func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath [
cmd.AddArguments(relpath...)
}
stdout, err := cmd.RunInDir(repoPath)
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return 0, err
}
@ -206,7 +206,7 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
}
if err := CheckGitVersionAtLeast("1.8"); err == nil {
_, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunInDir(c.repo.Path)
_, _, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunStdString(&RunOpts{Dir: c.repo.Path})
if err == nil {
return true, nil
}
@ -219,7 +219,7 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
return false, err
}
result, err := NewCommand(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunInDir(c.repo.Path)
result, _, err := NewCommand(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil {
return false, err
}
@ -381,7 +381,7 @@ func (c *Commit) GetBranchName() (string, error) {
}
args = append(args, "--name-only", "--no-undefined", c.ID.String())
data, err := NewCommand(c.repo.Ctx, args...).RunInDir(c.repo.Path)
data, _, err := NewCommand(c.repo.Ctx, args...).RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil {
// handle special case where git can not describe commit
if strings.Contains(err.Error(), "cannot describe") {
@ -407,7 +407,7 @@ func (c *Commit) LoadBranchName() (err error) {
// GetTagName gets the current tag name for given commit
func (c *Commit) GetTagName() (string, error) {
data, err := NewCommand(c.repo.Ctx, "describe", "--exact-match", "--tags", "--always", c.ID.String()).RunInDir(c.repo.Path)
data, _, err := NewCommand(c.repo.Ctx, "describe", "--exact-match", "--tags", "--always", c.ID.String()).RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil {
// handle special case where there is no tag for this commit
if strings.Contains(err.Error(), "no tag exactly matches") {
@ -486,11 +486,10 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
stderr := new(bytes.Buffer)
args := []string{"log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1", commitID}
err := NewCommand(ctx, args...).RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdout: w,
Stderr: stderr,
err := NewCommand(ctx, args...).Run(&RunOpts{
Dir: repoPath,
Stdout: w,
Stderr: stderr,
})
w.Close() // Close writer to exit parsing goroutine
if err != nil {
@ -503,7 +502,7 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, error) {
commitID, err := NewCommand(ctx, "rev-parse", shortID).RunInDir(repoPath)
commitID, _, err := NewCommand(ctx, "rev-parse", shortID).RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
if strings.Contains(err.Error(), "exit status 128") {
return "", ErrNotExist{shortID, ""}

View File

@ -36,11 +36,10 @@ func GetRawDiff(ctx context.Context, repoPath, commitID string, diffType RawDiff
func GetReverseRawDiff(ctx context.Context, repoPath, commitID string, writer io.Writer) error {
stderr := new(bytes.Buffer)
cmd := NewCommand(ctx, "show", "--pretty=format:revert %H%n", "-R", commitID)
if err := cmd.RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdout: writer,
Stderr: stderr,
if err := cmd.Run(&RunOpts{
Dir: repoPath,
Stdout: writer,
Stderr: stderr,
}); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr)
}
@ -97,11 +96,10 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
stderr := new(bytes.Buffer)
cmd := NewCommand(repo.Ctx, args...)
if err = cmd.RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: writer,
Stderr: stderr,
if err = cmd.Run(&RunOpts{
Dir: repo.Path,
Stdout: writer,
Stderr: stderr,
}); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr)
}
@ -301,11 +299,10 @@ func GetAffectedFiles(repo *Repository, oldCommitID, newCommitID string, env []s
// Run `git diff --name-only` to get the names of the changed files
err = NewCommand(repo.Ctx, "diff", "--name-only", oldCommitID, newCommitID).
RunWithContext(&RunContext{
Env: env,
Timeout: -1,
Dir: repo.Path,
Stdout: stdoutWriter,
Run(&RunOpts{
Env: env,
Dir: repo.Path,
Stdout: stdoutWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
// Close the writer end of the pipe to begin processing
_ = stdoutWriter.Close()

View File

@ -54,9 +54,9 @@ func LoadGitVersion() error {
return nil
}
stdout, err := NewCommand(context.Background(), "version").Run()
if err != nil {
return err
stdout, _, runErr := NewCommand(context.Background(), "version").RunStdString(nil)
if runErr != nil {
return runErr
}
fields := strings.Fields(stdout)
@ -74,6 +74,7 @@ func LoadGitVersion() error {
versionString = fields[2]
}
var err error
gitVersion, err = version.NewVersion(versionString)
return err
}
@ -297,5 +298,5 @@ func checkAndRemoveConfig(key, value string) error {
// Fsck verifies the connectivity and validity of the objects in the database
func Fsck(ctx context.Context, repoPath string, timeout time.Duration, args ...string) error {
return NewCommand(ctx, "fsck").AddArguments(args...).RunWithContext(&RunContext{Timeout: timeout, Dir: repoPath})
return NewCommand(ctx, "fsck").AddArguments(args...).Run(&RunOpts{Timeout: timeout, Dir: repoPath})
}

View File

@ -55,11 +55,10 @@ func LogNameStatusRepo(ctx context.Context, repository, head, treepath string, p
go func() {
stderr := strings.Builder{}
err := NewCommand(ctx, args...).RunWithContext(&RunContext{
Timeout: -1,
Dir: repository,
Stdout: stdoutWriter,
Stderr: &stderr,
err := NewCommand(ctx, args...).Run(&RunOpts{
Dir: repository,
Stdout: stdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))

View File

@ -27,12 +27,11 @@ func CatFileBatchCheck(ctx context.Context, shasToCheckReader *io.PipeReader, ca
stderr := new(bytes.Buffer)
var errbuf strings.Builder
cmd := git.NewCommand(ctx, "cat-file", "--batch-check")
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdin: shasToCheckReader,
Stdout: catFileCheckWriter,
Stderr: stderr,
if err := cmd.Run(&git.RunOpts{
Dir: tmpBasePath,
Stdin: shasToCheckReader,
Stdout: catFileCheckWriter,
Stderr: stderr,
}); err != nil {
_ = catFileCheckWriter.CloseWithError(fmt.Errorf("git cat-file --batch-check [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
}
@ -46,11 +45,10 @@ func CatFileBatchCheckAllObjects(ctx context.Context, catFileCheckWriter *io.Pip
stderr := new(bytes.Buffer)
var errbuf strings.Builder
cmd := git.NewCommand(ctx, "cat-file", "--batch-check", "--batch-all-objects")
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: catFileCheckWriter,
Stderr: stderr,
if err := cmd.Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: catFileCheckWriter,
Stderr: stderr,
}); err != nil {
log.Error("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String())
err = fmt.Errorf("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String())
@ -67,12 +65,11 @@ func CatFileBatch(ctx context.Context, shasToBatchReader *io.PipeReader, catFile
stderr := new(bytes.Buffer)
var errbuf strings.Builder
if err := git.NewCommand(ctx, "cat-file", "--batch").RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: catFileBatchWriter,
Stdin: shasToBatchReader,
Stderr: stderr,
if err := git.NewCommand(ctx, "cat-file", "--batch").Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: catFileBatchWriter,
Stdin: shasToBatchReader,
Stderr: stderr,
}); err != nil {
_ = shasToBatchReader.CloseWithError(fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
}

View File

@ -53,11 +53,10 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
go func() {
stderr := strings.Builder{}
err := git.NewCommand(repo.Ctx, "rev-list", "--all").RunWithContext(&git.RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: revListWriter,
Stderr: &stderr,
err := git.NewCommand(repo.Ctx, "rev-list", "--all").Run(&git.RunOpts{
Dir: repo.Path,
Stdout: revListWriter,
Stderr: &stderr,
})
if err != nil {
_ = revListWriter.CloseWithError(git.ConcatenateError(err, (&stderr).String()))

View File

@ -23,12 +23,11 @@ func NameRevStdin(ctx context.Context, shasToNameReader *io.PipeReader, nameRevS
stderr := new(bytes.Buffer)
var errbuf strings.Builder
if err := git.NewCommand(ctx, "name-rev", "--stdin", "--name-only", "--always").RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: nameRevStdinWriter,
Stdin: shasToNameReader,
Stderr: stderr,
if err := git.NewCommand(ctx, "name-rev", "--stdin", "--name-only", "--always").Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: nameRevStdinWriter,
Stdin: shasToNameReader,
Stderr: stderr,
}); err != nil {
_ = shasToNameReader.CloseWithError(fmt.Errorf("git name-rev [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
}

View File

@ -25,11 +25,10 @@ func RevListAllObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sy
stderr := new(bytes.Buffer)
var errbuf strings.Builder
cmd := git.NewCommand(ctx, "rev-list", "--objects", "--all")
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: basePath,
Stdout: revListWriter,
Stderr: stderr,
if err := cmd.Run(&git.RunOpts{
Dir: basePath,
Stdout: revListWriter,
Stderr: stderr,
}); err != nil {
log.Error("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String())
err = fmt.Errorf("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String())
@ -45,11 +44,10 @@ func RevListObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.
stderr := new(bytes.Buffer)
var errbuf strings.Builder
cmd := git.NewCommand(ctx, "rev-list", "--objects", headSHA, "--not", baseSHA)
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: revListWriter,
Stderr: stderr,
if err := cmd.Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: revListWriter,
Stderr: stderr,
}); err != nil {
log.Error("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())
errChan <- fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())

View File

@ -22,7 +22,7 @@ func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.UR
cmd = NewCommand(ctx, "config", "--get", "remote."+remoteName+".url")
}
result, err := cmd.RunInDir(repoPath)
result, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return nil, err
}

View File

@ -59,7 +59,7 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) ([]*Commit, erro
// IsRepoURLAccessible checks if given repository URL is accessible.
func IsRepoURLAccessible(ctx context.Context, url string) bool {
_, err := NewCommand(ctx, "ls-remote", "-q", "-h", url, "HEAD").Run()
_, _, err := NewCommand(ctx, "ls-remote", "-q", "-h", url, "HEAD").RunStdString(nil)
return err == nil
}
@ -74,7 +74,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
if bare {
cmd.AddArguments("--bare")
}
_, err = cmd.RunInDir(repoPath)
_, _, err = cmd.RunStdString(&RunOpts{Dir: repoPath})
return err
}
@ -82,11 +82,10 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
func (repo *Repository) IsEmpty() (bool, error) {
var errbuf, output strings.Builder
if err := NewCommand(repo.Ctx, "show-ref", "--head", "^HEAD$").
RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: &output,
Stderr: &errbuf,
Run(&RunOpts{
Dir: repo.Path,
Stdout: &output,
Stderr: &errbuf,
}); err != nil {
if err.Error() == "exit status 1" && errbuf.String() == "" {
return true, nil
@ -174,7 +173,7 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
}
stderr := new(bytes.Buffer)
if err = cmd.RunWithContext(&RunContext{
if err = cmd.Run(&RunOpts{
Timeout: opts.Timeout,
Env: envs,
Stdout: io.Discard,
@ -219,7 +218,7 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
opts.Timeout = -1
}
err := cmd.RunWithContext(&RunContext{
err := cmd.Run(&RunOpts{
Env: opts.Env,
Timeout: opts.Timeout,
Dir: repoPath,
@ -261,7 +260,7 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
// GetLatestCommitTime returns time for latest commit in repository (across all branches)
func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error) {
cmd := NewCommand(ctx, "for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)")
stdout, err := cmd.RunInDir(repoPath)
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return time.Time{}, err
}
@ -278,7 +277,7 @@ type DivergeObject struct {
func checkDivergence(ctx context.Context, repoPath, baseBranch, targetBranch string) (int, error) {
branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch)
cmd := NewCommand(ctx, "rev-list", "--count", branches)
stdout, err := cmd.RunInDir(repoPath)
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return -1, err
}
@ -315,23 +314,23 @@ func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.
defer os.RemoveAll(tmp)
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
_, err = NewCommand(ctx, "init", "--bare").RunInDirWithEnv(tmp, env)
_, _, err = NewCommand(ctx, "init", "--bare").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}
_, err = NewCommand(ctx, "reset", "--soft", commit).RunInDirWithEnv(tmp, env)
_, _, err = NewCommand(ctx, "reset", "--soft", commit).RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}
_, err = NewCommand(ctx, "branch", "-m", "bundle").RunInDirWithEnv(tmp, env)
_, _, err = NewCommand(ctx, "branch", "-m", "bundle").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}
tmpFile := filepath.Join(tmp, "bundle")
_, err = NewCommand(ctx, "bundle", "create", tmpFile, "bundle", "HEAD").RunInDirWithEnv(tmp, env)
_, _, err = NewCommand(ctx, "bundle", "create", tmpFile, "bundle", "HEAD").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

View File

@ -57,11 +57,10 @@ func (repo *Repository) CreateArchive(ctx context.Context, format ArchiveType, t
)
var stderr strings.Builder
err := NewCommand(ctx, args...).RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: target,
Stderr: &stderr,
err := NewCommand(ctx, args...).Run(&RunOpts{
Dir: repo.Path,
Stdout: target,
Stderr: &stderr,
})
if err != nil {
return ConcatenateError(err, stderr.String())

View File

@ -76,12 +76,11 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[
cmd := NewCommand(repo.Ctx, cmdArgs...)
if err := cmd.RunWithContext(&RunContext{
Env: env,
Timeout: -1,
Dir: repo.Path,
Stdout: stdOut,
Stderr: stdErr,
if err := cmd.Run(&RunOpts{
Env: env,
Dir: repo.Path,
Stdout: stdOut,
Stderr: stdErr,
}); err != nil {
return nil, fmt.Errorf("failed to run check-attr: %v\n%s\n%s", err, stdOut.String(), stdErr.String())
}
@ -189,13 +188,12 @@ func (c *CheckAttributeReader) Run() error {
_ = c.stdOut.Close()
}()
stdErr := new(bytes.Buffer)
err := c.cmd.RunWithContext(&RunContext{
Env: c.env,
Timeout: -1,
Dir: c.Repo.Path,
Stdin: c.stdinReader,
Stdout: c.stdOut,
Stderr: stdErr,
err := c.cmd.Run(&RunOpts{
Env: c.env,
Dir: c.Repo.Path,
Stdin: c.stdinReader,
Stdout: c.stdOut,
Stderr: stdErr,
PipelineFunc: func(_ context.Context, _ context.CancelFunc) error {
select {
case <-c.running:

View File

@ -8,12 +8,13 @@ import "fmt"
// FileBlame return the Blame object of file
func (repo *Repository) FileBlame(revision, path, file string) ([]byte, error) {
return NewCommand(repo.Ctx, "blame", "--root", "--", file).RunInDirBytes(path)
stdout, _, err := NewCommand(repo.Ctx, "blame", "--root", "--", file).RunStdBytes(&RunOpts{Dir: path})
return stdout, err
}
// LineBlame returns the latest commit at the given line
func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) {
res, err := NewCommand(repo.Ctx, "blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunInDir(path)
res, _, err := NewCommand(repo.Ctx, "blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunStdString(&RunOpts{Dir: path})
if err != nil {
return nil, err
}

View File

@ -24,7 +24,7 @@ const PullRequestPrefix = "refs/for/"
// IsReferenceExist returns true if given reference exists in the repository.
func IsReferenceExist(ctx context.Context, repoPath, name string) bool {
_, err := NewCommand(ctx, "show-ref", "--verify", "--", name).RunInDir(repoPath)
_, _, err := NewCommand(ctx, "show-ref", "--verify", "--", name).RunStdString(&RunOpts{Dir: repoPath})
return err == nil
}
@ -46,7 +46,7 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
if repo == nil {
return nil, fmt.Errorf("nil repo")
}
stdout, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -65,13 +65,14 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
// SetDefaultBranch sets default branch of repository.
func (repo *Repository) SetDefaultBranch(name string) error {
_, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD", BranchPrefix+name).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD", BranchPrefix+name).RunStdString(&RunOpts{Dir: repo.Path})
return err
}
// GetDefaultBranch gets default branch of repository.
func (repo *Repository) GetDefaultBranch() (string, error) {
return NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path})
return stdout, err
}
// GetBranch returns a branch by it's name
@ -133,7 +134,7 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
}
cmd.AddArguments("--", name)
_, err := cmd.RunInDir(repo.Path)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err
}
@ -143,7 +144,7 @@ func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
cmd := NewCommand(repo.Ctx, "branch")
cmd.AddArguments("--", branch, oldbranchOrCommit)
_, err := cmd.RunInDir(repo.Path)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err
}
@ -156,13 +157,13 @@ func (repo *Repository) AddRemote(name, url string, fetch bool) error {
}
cmd.AddArguments(name, url)
_, err := cmd.RunInDir(repo.Path)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err
}
// RemoveRemote removes a remote from repository.
func (repo *Repository) RemoveRemote(name string) error {
_, err := NewCommand(repo.Ctx, "remote", "rm", name).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "remote", "rm", name).RunStdString(&RunOpts{Dir: repo.Path})
return err
}
@ -173,6 +174,6 @@ func (branch *Branch) GetCommit() (*Commit, error) {
// RenameBranch rename a branch
func (repo *Repository) RenameBranch(from, to string) error {
_, err := NewCommand(repo.Ctx, "branch", "-m", from, to).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "branch", "-m", from, to).RunStdString(&RunOpts{Dir: repo.Path})
return err
}

View File

@ -112,11 +112,10 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
if arg != "" {
args = append(args, arg)
}
err := NewCommand(ctx, args...).RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdout: stdoutWriter,
Stderr: stderrBuilder,
err := NewCommand(ctx, args...).Run(&RunOpts{
Dir: repoPath,
Stdout: stdoutWriter,
Stderr: stderrBuilder,
})
if err != nil {
if stderrBuilder.Len() == 0 {

View File

@ -58,12 +58,12 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
relpath = `\` + relpath
}
stdout, err := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, id.String(), "--", relpath).RunInDir(repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, id.String(), "--", relpath).RunStdString(&RunOpts{Dir: repo.Path})
if runErr != nil {
return nil, runErr
}
id, err = NewIDFromString(stdout)
id, err := NewIDFromString(stdout)
if err != nil {
return nil, err
}
@ -73,9 +73,9 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
// GetCommitByPath returns the last commit of relative path.
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, "--", relpath).RunStdBytes(&RunOpts{Dir: repo.Path})
if runErr != nil {
return nil, runErr
}
commits, err := repo.parsePrettyFormatLogToList(stdout)
@ -86,8 +86,8 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
}
func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) ([]*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize),
"--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunInDirBytes(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize),
"--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -139,7 +139,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
// search for commits matching given constraints and keywords in commit msg
cmd.AddArguments(args...)
stdout, err := cmd.RunInDirBytes(repo.Path)
stdout, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -161,7 +161,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
hashCmd.AddArguments(v)
// search with given constraints for commit matching sha hash of v
hashMatching, err := hashCmd.RunInDirBytes(repo.Path)
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil || bytes.Contains(stdout, hashMatching) {
continue
}
@ -175,7 +175,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
}
func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", id1, id2).RunInDirBytes(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", id1, id2).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -185,7 +185,7 @@ func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
// You must ensure that id1 and id2 are valid commit ids.
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", "-z", id1, id2, "--", filename).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return false, err
}
@ -211,11 +211,10 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
err := NewCommand(repo.Ctx, "log", revision, "--follow",
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page),
prettyLogFormat, "--", file).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: &stderr,
Run(&RunOpts{
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
@ -244,8 +243,8 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
// CommitsByFileAndRangeNoFollow return the commits according revision file and the page
func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, page int) ([]*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", revision, "--skip="+strconv.Itoa((page-1)*50),
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "log", revision, "--skip="+strconv.Itoa((page-1)*50),
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -254,11 +253,11 @@ func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, pag
// FilesCountBetween return the number of files changed between two commits
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", startCommitID+"..."+endCommitID).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil && strings.Contains(err.Error(), "no merge base") {
// git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated.
// previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that...
stdout, err = NewCommand(repo.Ctx, "diff", "--name-only", startCommitID, endCommitID).RunInDir(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "diff", "--name-only", startCommitID, endCommitID).RunStdString(&RunOpts{Dir: repo.Path})
}
if err != nil {
return 0, err
@ -272,13 +271,13 @@ func (repo *Repository) CommitsBetween(last, before *Commit) ([]*Commit, error)
var stdout []byte
var err error
if before == nil {
stdout, err = NewCommand(repo.Ctx, "rev-list", last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
} else {
stdout, err = NewCommand(repo.Ctx, "rev-list", before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", before.ID.String()+".."+last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil && strings.Contains(err.Error(), "no merge base") {
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
// previously it would return the results of git rev-list before last so let's try that...
stdout, err = NewCommand(repo.Ctx, "rev-list", before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", before.ID.String(), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
}
}
if err != nil {
@ -292,13 +291,13 @@ func (repo *Repository) CommitsBetweenLimit(last, before *Commit, limit, skip in
var stdout []byte
var err error
if before == nil {
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
} else {
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil && strings.Contains(err.Error(), "no merge base") {
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
// previously it would return the results of git rev-list --max-count n before last so let's try that...
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
}
}
if err != nil {
@ -344,9 +343,9 @@ func (repo *Repository) commitsBefore(id SHA1, limit int) ([]*Commit, error) {
cmd.AddArguments(prettyLogFormat, id.String())
}
stdout, err := cmd.RunInDirBytes(repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if runErr != nil {
return nil, runErr
}
formattedLog, err := repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
@ -381,7 +380,7 @@ func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) ([]*Commit, erro
func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) {
if CheckGitVersionAtLeast("2.7.0") == nil {
stdout, err := NewCommand(repo.Ctx, "for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -390,7 +389,7 @@ func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error)
return branches, nil
}
stdout, err := NewCommand(repo.Ctx, "branch", "--contains", commit.ID.String()).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "branch", "--contains", commit.ID.String()).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -429,7 +428,7 @@ func (repo *Repository) GetCommitsFromIDs(commitIDs []string) []*Commit {
// IsCommitInBranch check if the commit is on the branch
func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err error) {
stdout, err := NewCommand(repo.Ctx, "branch", "--contains", commitID, branch).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "branch", "--contains", commitID, branch).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return false, err
}

Some files were not shown because too many files have changed in this diff Show More