diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2021-12-07 21:59:36 +1100 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2021-12-29 09:14:39 +1100 |
commit | d913c041098438bf07b8d1e3bbb6cef2195b671a (patch) | |
tree | 73461d15185832c4947ed7df876372aaa3f0474c | |
parent | 9ef65574db3f0fd30b3782a8582212619edf4650 (diff) |
WIP
48 files changed, 433 insertions, 489 deletions
diff --git a/pkg/app/app.go b/pkg/app/app.go index f24af6e58..d4e3e15f7 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -146,7 +146,7 @@ func NewApp(config config.AppConfigurer, filterPath string) (*App, error) { } func (app *App) validateGitVersion() error { - output, err := app.OSCommand.RunCommandWithOutput("git --version") + output, err := app.OSCommand.RunWithOutput(app.OSCommand.NewCmdObj("git --version")) // if we get an error anywhere here we'll show the same status minVersionError := errors.New(app.Tr.MinGitVersionError) if err != nil { @@ -231,7 +231,7 @@ func (app *App) setupRepo() (bool, error) { os.Exit(1) } - if err := app.OSCommand.RunCommand("git init"); err != nil { + if err := app.OSCommand.Run(app.OSCommand.NewCmdObj("git init")); err != nil { return false, err } } diff --git a/pkg/commands/branches.go b/pkg/commands/branches.go index 3f6820c09..cc513a974 100644 --- a/pkg/commands/branches.go +++ b/pkg/commands/branches.go @@ -11,19 +11,19 @@ import ( // NewBranch create new branch func (c *GitCommand) NewBranch(name string, base string) error { - return c.RunCommand("git checkout -b %s %s", c.OSCommand.Quote(name), c.OSCommand.Quote(base)) + return c.Run(c.NewCmdObj(fmt.Sprintf("git checkout -b %s %s", c.OSCommand.Quote(name), c.OSCommand.Quote(base)))) } // CurrentBranchName get the current branch name and displayname. // the first returned string is the name and the second is the displayname // e.g. name is 123asdf and displayname is '(HEAD detached at 123asdf)' func (c *GitCommand) CurrentBranchName() (string, string, error) { - branchName, err := c.RunCommandWithOutput("git symbolic-ref --short HEAD") + branchName, err := c.RunWithOutput(c.NewCmdObj("git symbolic-ref --short HEAD")) if err == nil && branchName != "HEAD\n" { trimmedBranchName := strings.TrimSpace(branchName) return trimmedBranchName, trimmedBranchName, nil } - output, err := c.RunCommandWithOutput("git branch --contains") + output, err := c.RunWithOutput(c.NewCmdObj("git branch --contains")) if err != nil { return "", "", err } @@ -47,7 +47,7 @@ func (c *GitCommand) DeleteBranch(branch string, force bool) error { command = "git branch -D" } - return c.OSCommand.RunCommand("%s %s", command, c.OSCommand.Quote(branch)) + return c.OSCommand.Run(c.OSCommand.NewCmdObj(fmt.Sprintf("%s %s", command, c.OSCommand.Quote(branch)))) } // Checkout checks out a branch (or commit), with --force if you set the force arg to true @@ -61,36 +61,42 @@ func (c *GitCommand) Checkout(branch string, options CheckoutOptions) error { if options.Force { forceArg = " --force" } - return c.OSCommand.RunCommandWithOptions(fmt.Sprintf("git checkout%s %s", forceArg, c.OSCommand.Quote(branch)), oscommands.RunCommandOptions{EnvVars: options.EnvVars}) + + cmdObj := c.NewCmdObj(fmt.Sprintf("git checkout%s %s", forceArg, c.OSCommand.Quote(branch))). + // prevents git from prompting us for input which would freeze the program + // TODO: see if this is actually needed here + AddEnvVars("GIT_TERMINAL_PROMPT=0"). + AddEnvVars(options.EnvVars...) + + return c.OSCommand.Run(cmdObj) } // GetBranchGraph gets the color-formatted graph of the log for the given branch // Currently it limits the result to 100 commits, but when we get async stuff // working we can do lazy loading func (c *GitCommand) GetBranchGraph(branchName string) (string, error) { - cmdStr := c.GetBranchGraphCmdStr(branchName) - return c.OSCommand.RunCommandWithOutput(cmdStr) + return c.OSCommand.RunWithOutput(c.GetBranchGraphCmdObj(branchName)) } func (c *GitCommand) GetUpstreamForBranch(branchName string) (string, error) { - output, err := c.RunCommandWithOutput("git rev-parse --abbrev-ref --symbolic-full-name %s@{u}", c.OSCommand.Quote(branchName)) + output, err := c.RunWithOutput(c.NewCmdObj(fmt.Sprintf("git rev-parse --abbrev-ref --symbolic-full-name %s@{u}", c.OSCommand.Quote(branchName)))) return strings.TrimSpace(output), err } -func (c *GitCommand) GetBranchGraphCmdStr(branchName string) string { +func (c *GitCommand) GetBranchGraphCmdObj(branchName string) oscommands.ICmdObj { branchLogCmdTemplate := c.Config.GetUserConfig().Git.BranchLogCmd templateValues := map[string]string{ "branchName": c.OSCommand.Quote(branchName), } - return utils.ResolvePlaceholderString(branchLogCmdTemplate, templateValues) + return c.NewCmdObj(utils.ResolvePlaceholderString(branchLogCmdTemplate, templateValues)) } func (c *GitCommand) SetUpstreamBranch(upstream string) error { - return c.RunCommand("git branch -u %s", c.OSCommand.Quote(upstream)) + return c.Run(c.NewCmdObj("git branch -u " + c.OSCommand.Quote(upstream))) } func (c *GitCommand) SetBranchUpstream(remoteName string, remoteBranchName string, branchName string) error { - return c.RunCommand("git branch --set-upstream-to=%s/%s %s", c.OSCommand.Quote(remoteName), c.OSCommand.Quote(remoteBranchName), c.OSCommand.Quote(branchName)) + return c.Run(c.NewCmdObj(fmt.Sprintf("git branch --set-upstream-to=%s/%s %s", c.OSCommand.Quote(remoteName), c.OSCommand.Quote(remoteBranchName), c.OSCommand.Quote(branchName)))) } func (c *GitCommand) GetCurrentBranchUpstreamDifferenceCount() (string, string) { @@ -105,11 +111,11 @@ func (c *GitCommand) GetBranchUpstreamDifferenceCount(branchName string) (string // current branch func (c *GitCommand) GetCommitDifferences(from, to string) (string, string) { command := "git rev-list %s..%s --count" - pushableCount, err := c.OSCommand.RunCommandWithOutput(command, to, from) + pushableCount, err := c.RunWithOutput(c.NewCmdObj(fmt.Sprintf(command, to, from))) if err != nil { return "?", "?" } - pullableCount, err := c.OSCommand.RunCommandWithOutput(command, from, to) + pullableCount, err := c.RunWithOutput(c.NewCmdObj(fmt.Sprintf(command, from, to))) if err != nil { return "?", "?" } @@ -129,33 +135,33 @@ func (c *GitCommand) Merge(branchName string, opts MergeOpts) error { command = fmt.Sprintf("%s --ff-only", command) } - return c.OSCommand.RunCommand(command) + return c.OSCommand.Run(c.OSCommand.NewCmdObj(command)) } // AbortMerge abort merge func (c *GitCommand) AbortMerge() error { - return c.RunCommand("git merge --abort") + return c.Run(c.NewCmdObj("git merge --abort")) } func (c *GitCommand) IsHeadDetached() bool { - err := c.RunCommand("git symbolic-ref -q HEAD") + err := c.Run(c.NewCmdObj("git symbolic-ref -q HEAD")) return err != nil } // ResetHardHead runs `git reset --hard` func (c *GitCommand) ResetHard(ref string) error { - return c.RunCommand("git reset --hard " + c.OSCommand.Quote(ref)) + return c.Run(c.NewCmdObj("git reset --hard " + c.OSCommand.Quote(ref))) } // ResetSoft runs `git reset --soft HEAD` func (c *GitCommand) ResetSoft(ref string) error { - return c.RunCommand("git reset --soft " + c.OSCommand.Quote(ref)) + return c.Run(c.NewCmdObj("git reset --soft " + c.OSCommand.Quote(ref))) } func (c *GitCommand) ResetMixed(ref string) error { - return c.RunCommand("git reset --mixed " + c.OSCommand.Quote(ref)) + return c.Run(c.NewCmdObj("git reset --mixed " + c.OSCommand.Quote(ref))) } func (c *GitCommand) RenameBranch(oldName string, newName string) error { - return c.RunCommand("git branch --move %s %s", c.OSCommand.Quote(oldName), c.OSCommand.Quote(newName)) + return c.Run(c.NewCmdObj(fmt.Sprintf("git branch --move %s %s", c.OSCommand.Quote(oldName), c.OSCommand.Quote(newName)))) } diff --git a/pkg/commands/branches_test.go b/pkg/commands/branches_test.go index 85c477523..ee050e5be 100644 --- a/pkg/commands/branches_test.go +++ b/pkg/commands/branches_test.go @@ -210,7 +210,7 @@ func TestGitCommandGetAllBranchGraph(t *testing.T) { return secureexec.Command("echo") } cmdStr := gitCmd.Config.GetUserConfig().Git.AllBranchesLogCmd - _, err := gitCmd.OSCommand.RunCommandWithOutput(cmdStr) + _, err := gitCmd.OSCommand.RunWithOutput(gitCmd.NewCmdObj(cmdStr)) assert.NoError(t, err) } diff --git a/pkg/commands/commits.go b/pkg/commands/commits.go index 56b8533ac..269eef073 100644 --- a/pkg/commands/commits.go +++ b/pkg/commands/commits.go @@ -10,15 +10,21 @@ import ( // RenameCommit renames the topmost commit with the given name func (c *GitCommand) RenameCommit(name string) error { - return c.RunCommand("git commit --allow-empty --amend --only -m %s", c.OSCommand.Quote(name)) + return c.Run(c.NewCmdObj("git commit --allow-empty --amend --only -m " + c.OSCommand.Quote(name))) } // ResetToCommit reset to commit -func (c *GitCommand) ResetToCommit(sha string, strength string, options oscommands.RunCommandOptions) error { - return c.OSCommand.RunCommandWithOptions(fmt.Sprintf("git reset --%s %s", strength, sha), options) +func (c *GitCommand) ResetToCommit(sha string, strength string, envVars []string) error { + cmdObj := c.NewCmdObj(fmt.Sprintf("git reset --%s %s", strength, sha)). + // prevents git from prompting us for input which would freeze the program + // TODO: see if this is actually needed here + AddEnvVars("GIT_TERMINAL_PROMPT=0"). + AddEnvVars(envVars...) + + return c.OSCommand.Run(cmdObj) } -func (c *GitCommand) CommitCmdStr(message string, flags string) string { +func (c *GitCommand) CommitCmdObj(message string, flags string) oscommands.ICmdObj { splitMessage := strings.Split(message, "\n") lineArgs := "" for _, line := range splitMessage { @@ -30,52 +36,53 @@ func (c *GitCommand) CommitCmdStr(message string, flags string) string { flagsStr = fmt.Sprintf(" %s", flags) } - return fmt.Sprintf("git commit%s%s", flagsStr, lineArgs) + return c.NewCmdObj(fmt.Sprintf("git commit%s%s", flagsStr, lineArgs)) } // Get the subject of the HEAD commit func (c *GitCommand) GetHeadCommitMessage() (string, error) { - cmdStr := "git log -1 --pretty=%s" - message, err := c.OSCommand.RunCommandWithOutput(cmdStr) + message, err := c.RunWithOutput(c.NewCmdObj("git log -1 --pretty=%s")) return strings.TrimSpace(message), err } func (c *GitCommand) GetCommitMessage(commitSha string) (string, error) { cmdStr := "git rev-list --format=%B --max-count=1 " + commitSha - messageWithHeader, err := c.OSCommand.RunCommandWithOutput(cmdStr) + messageWithHeader, err := c.RunWithOutput(c.NewCmdObj(cmdStr)) message := strings.Join(strings.SplitAfter(messageWithHeader, "\n")[1:], "\n") return strings.TrimSpace(message), err } func (c *GitCommand) GetCommitMessageFirstLine(sha string) (string, error) { - return c.RunCommandWithOutput("git show --no-patch --pretty=format:%%s %s", sha) + return c.RunWithOutput(c.NewCmdObj(fmt.Sprintf("git show --no-patch --pretty=format:%%s %s", sha))) } // AmendHead amends HEAD with whatever is staged in your working tree func (c *GitCommand) AmendHead() error { - return c.OSCommand.RunCommand(c.AmendHeadCmdStr()) + return c.OSCommand.Run(c.AmendHeadCmdObj()) } -func (c *GitCommand) AmendHeadCmdStr() string { - return "git commit --amend --no-edit --allow-empty" +func (c *GitCommand) AmendHeadCmdObj() oscommands.ICmdObj { + return c.NewCmdObj("git commit --amend --no-edit --allow-empty") } -func (c *GitCommand) ShowCmdStr(sha string, filterPath string) string { +func (c *GitCommand) ShowCmdObj(sha string, filterPath string) oscommands.ICmdObj { contextSize := c.Config.GetUserConfig().Git.DiffContextSize filterPathArg := "" if filterPath != "" { filterPathArg = fmt.Sprintf(" -- %s", c.OSCommand.Quote(filterPath)) } - return fmt.Sprintf("git show --submodule --color=%s --unified=%d --no-renames --stat -p %s %s", c.colorArg(), contextSize, sha, filterPathArg) + + cmdStr := fmt.Sprintf("git show --submodule --color=%s --unified=%d --no-renames --stat -p %s %s", c.colorArg(), contextSize, sha, filterPathArg) + return c.NewCmdObj(cmdStr) } // Revert reverts the selected commit by sha func (c *GitCommand) Revert(sha string) error { - return c.RunCommand("git revert %s", sha) + return c.Run(c.NewCmdObj(fmt.Sprintf("git revert %s", sha))) } func (c *GitCommand) RevertMerge(sha string, parentNumber int) error { - return c.RunCommand("git revert %s -m %d", sha, parentNumber) + return c.Run(c.NewCmdObj(fmt.Sprintf("git revert %s -m %d", sha, parentNumber))) } // CherryPickCommits begins an interactive rebase with the given shas being cherry picked onto HEAD @@ -90,10 +97,10 @@ func (c *GitCommand) CherryPickCommits(commits []*models.Commit) error { return err } - return c.OSCommand.RunPreparedCommand(cmd) + return c.OSCommand.Run(cmd) } // CreateFixupCommit creates a commit that fixes up a previous commit func (c *GitCommand) CreateFixupCommit(sha string) error { - return c.RunCommand("git commit --fixup=%s", sha) + return c.Run(c.NewCmdObj(fmt.Sprintf("git commit --fixup=%s", sha))) } diff --git a/pkg/commands/commits_test.go b/pkg/commands/commits_test.go index f6dd1f71b..04a5c01d7 100644 --- a/pkg/commands/commits_test.go +++ b/pkg/commands/commits_test.go @@ -4,7 +4,6 @@ import ( "os/exec" "testing" - "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/secureexec" "github.com/jesseduffield/lazygit/pkg/test" "github.com/stretchr/testify/assert" @@ -33,11 +32,11 @@ func TestGitCommandResetToCommit(t *testing.T) { return secureexec.Command("echo") } - assert.NoError(t, gitCmd.ResetToCommit("78976bc", "hard", oscommands.RunCommandOptions{})) + assert.NoError(t, gitCmd.ResetToCommit("78976bc", "hard", []string{})) } -// TestGitCommandCommitStr is a function. -func TestGitCommandCommitStr(t *testing.T) { +// TestGitCommandCommitObj is a function. +func TestGitCommandCommitObj(t *testing.T) { gitCmd := NewDummyGitCommand() type scenario struct { @@ -70,7 +69,7 @@ func TestGitCommandCommitStr(t *testing.T) { for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { - cmdStr := gitCmd.CommitCmdStr(s.message, s.flags) + cmdStr := gitCmd.CommitCmdObj(s.message, s.flags).ToString() assert.Equal(t, s.expected, cmdStr) }) } @@ -111,8 +110,8 @@ func TestGitCommandCreateFixupCommit(t *testing.T) { } } -// TestGitCommandShowCmdStr is a function. -func TestGitCommandShowCmdStr(t *testing.T) { +// TestGitCommandShowCmdObj is a function. +func TestGitCommandShowCmdObj(t *testing.T) { type scenario struct { testName string filterPath string @@ -146,7 +145,7 @@ func TestGitCommandShowCmdStr(t *testing.T) { for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { gitCmd.Config.GetUserConfig().Git.DiffContextSize = s.contextSize - cmdStr := gitCmd.ShowCmdStr("1234567890", s.filterPath) + cmdStr := gitCmd.ShowCmdObj("1234567890", s.filterPath).ToString() assert.Equal(t, s.expected, cmdStr) }) } diff --git a/pkg/commands/files.go b/pkg/commands/files.go index 8eb154c30..289337b70 100644 --- a/pkg/commands/files.go +++ b/pkg/commands/files.go @@ -10,6 +10,7 @@ import ( "github.com/go-errors/errors" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -23,27 +24,27 @@ func (c *GitCommand) CatFile(fileName string) (string, error) { return string(buf), nil } -func (c *GitCommand) OpenMergeToolCmd() string { - return "git mergetool" +func (c *GitCommand) OpenMergeToolCmdObj() oscommands.ICmdObj { + return c.NewCmdObj("git mergetool") } func (c *GitCommand) OpenMergeTool() error { - return c.OSCommand.RunCommand("git mergetool") + return c.Run(c.OpenMergeToolCmdObj()) } // StageFile stages a file func (c *GitCommand) StageFile(fileName string) error { - return c.RunCommand("git add -- %s", c.OSCommand.Quote(fileName)) + return c.Run(c.NewCmdObj("git add -- " + c.OSCommand.Quote(fileName))) } // StageAll stages all files func (c *GitCommand) StageAll() error { - return c.RunCommand("git add -A") + return c.Run(c.NewCmdObj("git add -A")) } // UnstageAll unstages all files func (c *GitCommand) UnstageAll() error { - return c.RunCommand("git reset") + return c.Run(c.NewCmdObj("git reset")) } // UnStageFile unstages a file @@ -56,7 +57,8 @@ func (c *GitCommand) UnStageFile(fileNames []string, reset bool) error { } for _, name := range fileNames { - if err := c.OSCommand.RunCommand(command, c.OSCommand.Quote(name)); err != nil { + cmdObj := c.NewCmdObj(fmt.Sprintf(command, c.OSCommand.Quote(name))) + if err := c.Run(cmdObj); err != nil { return err } } @@ -120,22 +122,22 @@ func (c *GitCommand) DiscardAllFileChanges(file *models.File) error { quotedFileName := c.OSCommand.Quote(file.Name) if file.ShortStatus == "AA" { - if err := c.RunCommand("git checkout --ours -- %s", quotedFileName); err != nil { + if err := c.Run(c.NewCmdObj("git checkout --ours -- " + quotedFileName)); err != nil { return err } - if err := c.RunCommand("git add -- %s", quotedFileName); err != nil { + if err := c.Run(c.NewCmdObj("git add -- " + quotedFileName)); err != nil { return err } return nil } if file.ShortStatus == "DU" { - return c.RunCommand("git rm -- %s", quotedFileName) + return c.Run(c.NewCmdObj("git rm -- " + quotedFileName)) } // if the file isn't tracked, we assume you want to delete it if file.HasStagedChanges || file.HasMergeConflicts { - if err := c.RunCommand("git reset -- %s", quotedFileName); err != nil { + if err := c.Run(c.NewCmdObj("git reset -- " + quotedFileName)); err != nil { return err } } @@ -161,7 +163,7 @@ func (c *GitCommand) DiscardUnstagedDirChanges(node *filetree.FileNode) error { } quotedPath := c.OSCommand.Quote(node.GetPath()) - if err := c.RunCommand("git checkout -- %s", quotedPath); err != nil { + if err := c.Run(c.NewCmdObj("git checkout -- " + quotedPath)); err != nil { return err } @@ -186,7 +188,7 @@ func (c *GitCommand) RemoveUntrackedDirFiles(node *filetree.FileNode) error { // DiscardUnstagedFileChanges directly func (c *GitCommand) DiscardUnstagedFileChanges(file *models.File) error { quotedFileName := c.OSCommand.Quote(file.Name) - return c.RunCommand("git checkout -- %s", quotedFileName) + return c.Run(c.NewCmdObj("git checkout -- " + quotedFileName)) } // Ignore adds a file to the gitignore for the repo @@ -197,11 +199,11 @@ func (c *GitCommand) Ignore(filename string) error { // WorktreeFileDiff returns the diff of a file func (c *GitCommand) WorktreeFileDiff(file *models.File, plain bool, cached bool, ignoreWhitespace bool) string { // for now we assume an error means the file was deleted - s, _ := c.OSCommand.RunCommandWithOutput(c.WorktreeFileDiffCmdStr(file, plain, cached, ignoreWhitespace)) + s, _ := c.OSCommand.RunWithOutput(c.WorktreeFileDiffCmdObj(file, plain, cached, ignoreWhitespace)) return s } -func (c *GitCommand) WorktreeFileDiffCmdStr(node models.IFile, plain bool, cached bool, ignoreWhitespace bool) string { +func (c *GitCommand) WorktreeFileDiffCmdObj(node models.IFile, plain bool, cached bool, ignoreWhitespace bool) oscommands.ICmdObj { cachedArg := "" trackedArg := "--" colorArg := c.colorArg() @@ -221,7 +223,9 @@ func (c *GitCommand) WorktreeFileDiffCmdStr(node models.IFile, plain bool, cache ignoreWhitespaceArg = "--ignore-all-space" } - return fmt.Sprintf("git diff --submodule --no-ext-diff --unified=%d --color=%s %s %s %s %s", contextSize, colorArg, ignoreWhitespaceArg, cachedArg, trackedArg, quotedPath) + cmdStr := fmt.Sprintf("git diff --submodule --no-ext-diff --unified=%d --color=%s %s %s %s %s", contextSize, colorArg, ignoreWhitespaceArg, cachedArg, trackedArg, quotedPath) + + return c.NewCmdObj(cmdStr) } func (c *GitCommand) ApplyPatch(patch string, flags ...string) error { @@ -236,17 +240,17 @@ func (c *GitCommand) ApplyPatch(patch string, flags ...string) error { flagStr += " --" + flag } - return c.RunCommand("git apply %s %s", flagStr, c.OSCommand.Quote(filepath)) + return c.Run(c.NewCmdObj(fmt.Sprintf("git apply %s %s", flagStr, c.OSCommand.Quote(filepath)))) } // ShowFileDiff get the diff of specified from and to. Typically this will be used for a single commit so it'll be 123abc^..123abc // but when we're in diff mode it could be any 'from' to any 'to'. The reverse flag is also here thanks to diff mode. func (c *GitCommand) ShowFileDiff(from string, to string, reverse bool, fileName string, plain bool) (string, error) { - cmdStr := c.ShowFileDiffCmdStr(from, to, reverse, fileName, plain) - return c.OSCommand.RunCommandWithOutput(cmdStr) + cmdObj := c.ShowFileDiffCmdObj(from, to, reverse, fileName, plain) + return c.RunWithOutput(cmdObj) } -func (c *GitCommand) ShowFileDiffCmdStr(from string, to string, reverse bool, fileName string, plain bool) string { +func (c *GitCommand) ShowFileDiffCmdObj(from string, to string, reverse bool, fileName string, plain bool) oscommands.ICmdObj { colorArg := c.colorArg() contextSize := c.Config.GetUserConfig().Git.DiffContextSize if plain { @@ -258,12 +262,12 @@ func (c *GitCommand) ShowFileDiffCmdStr(from string, to string, reverse bool, fi reverseFlag = " -R " } - ret |