WIP
This commit is contained in:
@@ -6,7 +6,6 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
|
||||
@@ -42,6 +41,8 @@ type GitCommand struct {
|
||||
// Coincidentally at the moment it's the same view that OnRunCommand logs to
|
||||
// but that need not always be the case.
|
||||
GetCmdWriter func() io.Writer
|
||||
|
||||
Cmd oscommands.ICmdObjBuilder
|
||||
}
|
||||
|
||||
// NewGitCommand it runs git commands
|
||||
@@ -68,6 +69,8 @@ func NewGitCommand(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd)
|
||||
|
||||
gitCommand := &GitCommand{
|
||||
Common: cmn,
|
||||
OSCommand: osCommand,
|
||||
@@ -76,6 +79,7 @@ func NewGitCommand(
|
||||
PushToCurrent: pushToCurrent,
|
||||
GitConfig: gitConfig,
|
||||
GetCmdWriter: func() io.Writer { return ioutil.Discard },
|
||||
Cmd: cmd,
|
||||
}
|
||||
|
||||
gitCommand.PatchManager = patch.NewPatchManager(gitCommand.Log, gitCommand.ApplyPatch, gitCommand.ShowFileDiff)
|
||||
@@ -219,46 +223,19 @@ func VerifyInGitRepo(osCommand *oscommands.OSCommand) error {
|
||||
}
|
||||
|
||||
func (c *GitCommand) Run(cmdObj oscommands.ICmdObj) error {
|
||||
_, err := c.RunWithOutput(cmdObj)
|
||||
return err
|
||||
return cmdObj.Run()
|
||||
}
|
||||
|
||||
func (c *GitCommand) RunWithOutput(cmdObj oscommands.ICmdObj) (string, error) {
|
||||
// TODO: have this retry logic in other places we run the command
|
||||
waitTime := 50 * time.Millisecond
|
||||
retryCount := 5
|
||||
attempt := 0
|
||||
|
||||
for {
|
||||
output, err := c.OSCommand.RunWithOutput(cmdObj)
|
||||
if err != nil {
|
||||
// if we have an error based on the index lock, we should wait a bit and then retry
|
||||
if strings.Contains(output, ".git/index.lock") {
|
||||
c.Log.Error(output)
|
||||
c.Log.Info("index.lock prevented command from running. Retrying command after a small wait")
|
||||
attempt++
|
||||
time.Sleep(waitTime)
|
||||
if attempt < retryCount {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return output, err
|
||||
}
|
||||
return cmdObj.RunWithOutput()
|
||||
}
|
||||
|
||||
func (c *GitCommand) RunLineOutputCmd(cmdObj oscommands.ICmdObj, onLine func(line string) (bool, error)) error {
|
||||
return c.OSCommand.RunLineOutputCmd(cmdObj, onLine)
|
||||
return cmdObj.RunLineOutputCmd(onLine)
|
||||
}
|
||||
|
||||
func (c *GitCommand) NewCmdObj(cmdStr string) oscommands.ICmdObj {
|
||||
return c.OSCommand.NewCmdObj(cmdStr).AddEnvVars("GIT_OPTIONAL_LOCKS=0")
|
||||
}
|
||||
|
||||
func (c *GitCommand) NewCmdObjWithLog(cmdStr string) oscommands.ICmdObj {
|
||||
cmdObj := c.NewCmdObj(cmdStr)
|
||||
c.OSCommand.LogCmdObj(cmdObj)
|
||||
return cmdObj
|
||||
return c.Cmd.New(cmdStr)
|
||||
}
|
||||
|
||||
func (c *GitCommand) Quote(str string) string {
|
||||
|
||||
47
pkg/commands/git_cmd_obj_builder.go
Normal file
47
pkg/commands/git_cmd_obj_builder.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// all we're doing here is wrapping the default command object builder with
|
||||
// some git-specific stuff: e.g. adding a git-specific env var
|
||||
|
||||
type gitCmdObjBuilder struct {
|
||||
innerBuilder *oscommands.CmdObjBuilder
|
||||
}
|
||||
|
||||
var _ oscommands.ICmdObjBuilder = &gitCmdObjBuilder{}
|
||||
|
||||
func NewGitCmdObjBuilder(log *logrus.Entry, innerBuilder *oscommands.CmdObjBuilder) *gitCmdObjBuilder {
|
||||
// the price of having a convenient interface where we can say .New(...).Run() is that our builder now depends on our runner, so when we want to wrap the default builder/runner in new functionality we need to jump through some hoops. We could avoid the use of a decorator function here by just exporting the runner field on the default builder but that would be misleading because we don't want anybody using that to run commands (i.e. we want there to be a single API used across the codebase)
|
||||
updatedBuilder := innerBuilder.CloneWithNewRunner(func(runner oscommands.ICmdObjRunner) oscommands.ICmdObjRunner {
|
||||
return &gitCmdObjRunner{
|
||||
log: log,
|
||||
innerRunner: runner,
|
||||
}
|
||||
})
|
||||
|
||||
return &gitCmdObjBuilder{
|
||||
innerBuilder: updatedBuilder,
|
||||
}
|
||||
}
|
||||
|
||||
var defaultEnvVar = "GIT_OPTIONAL_LOCKS=0"
|
||||
|
||||
func (self *gitCmdObjBuilder) New(cmdStr string) oscommands.ICmdObj {
|
||||
return self.innerBuilder.New(cmdStr).AddEnvVars(defaultEnvVar)
|
||||
}
|
||||
|
||||
func (self *gitCmdObjBuilder) NewFromArgs(args []string) oscommands.ICmdObj {
|
||||
return self.innerBuilder.NewFromArgs(args).AddEnvVars(defaultEnvVar)
|
||||
}
|
||||
|
||||
func (self *gitCmdObjBuilder) NewShell(cmdStr string) oscommands.ICmdObj {
|
||||
return self.innerBuilder.NewShell(cmdStr).AddEnvVars(defaultEnvVar)
|
||||
}
|
||||
|
||||
func (self *gitCmdObjBuilder) Quote(str string) string {
|
||||
return self.innerBuilder.Quote(str)
|
||||
}
|
||||
49
pkg/commands/git_cmd_obj_runner.go
Normal file
49
pkg/commands/git_cmd_obj_runner.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// here we're wrapping the default command runner in some git-specific stuff e.g. retry logic if we get an error due to the presence of .git/index.lock
|
||||
|
||||
type gitCmdObjRunner struct {
|
||||
log *logrus.Entry
|
||||
innerRunner oscommands.ICmdObjRunner
|
||||
}
|
||||
|
||||
func (self *gitCmdObjRunner) Run(cmdObj oscommands.ICmdObj) error {
|
||||
_, err := self.RunWithOutput(cmdObj)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *gitCmdObjRunner) RunWithOutput(cmdObj oscommands.ICmdObj) (string, error) {
|
||||
// TODO: have this retry logic in other places we run the command
|
||||
waitTime := 50 * time.Millisecond
|
||||
retryCount := 5
|
||||
attempt := 0
|
||||
|
||||
for {
|
||||
output, err := self.innerRunner.RunWithOutput(cmdObj)
|
||||
if err != nil {
|
||||
// if we have an error based on the index lock, we should wait a bit and then retry
|
||||
if strings.Contains(output, ".git/index.lock") {
|
||||
self.log.Error(output)
|
||||
self.log.Info("index.lock prevented command from running. Retrying command after a small wait")
|
||||
attempt++
|
||||
time.Sleep(waitTime)
|
||||
if attempt < retryCount {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return output, err
|
||||
}
|
||||
}
|
||||
|
||||
func (self *gitCmdObjRunner) RunLineOutputCmd(cmdObj oscommands.ICmdObj, onLine func(line string) (bool, error)) error {
|
||||
return self.innerRunner.RunLineOutputCmd(cmdObj, onLine)
|
||||
}
|
||||
@@ -17,7 +17,7 @@ type ICmdObj interface {
|
||||
RunLineOutputCmd(onLine func(line string) (bool, error)) error
|
||||
|
||||
// logs command
|
||||
Log()
|
||||
Log() ICmdObj
|
||||
}
|
||||
|
||||
type CmdObj struct {
|
||||
@@ -46,8 +46,10 @@ func (self *CmdObj) GetEnvVars() []string {
|
||||
return self.cmd.Env
|
||||
}
|
||||
|
||||
func (self *CmdObj) Log() {
|
||||
func (self *CmdObj) Log() ICmdObj {
|
||||
self.logCommand(self)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *CmdObj) Run() error {
|
||||
|
||||
72
pkg/commands/oscommands/cmd_obj_builder.go
Normal file
72
pkg/commands/oscommands/cmd_obj_builder.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package oscommands
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/mgutz/str"
|
||||
)
|
||||
|
||||
type ICmdObjBuilder interface {
|
||||
// New returns a new command object based on the string provided
|
||||
New(cmdStr string) ICmdObj
|
||||
// NewShell takes a string like `git commit` and returns an executable shell command for it e.g. `sh -c 'git commit'`
|
||||
NewShell(commandStr string) ICmdObj
|
||||
// NewFromArgs takes a slice of strings like []string{"git", "commit"} and returns a new command object. This can be useful when you don't want to worry about whitespace and quoting and stuff.
|
||||
NewFromArgs(args []string) ICmdObj
|
||||
// Quote wraps a string in quotes with any necessary escaping applied. The reason for bundling this up with the other methods in this interface is that we basically always need to make use of this when creating new command objects.
|
||||
Quote(str string) string
|
||||
}
|
||||
|
||||
// poor man's version of explicitly saying that struct X implements interface Y
|
||||
var _ ICmdObjBuilder = &CmdObjBuilder{}
|
||||
|
||||
type CmdObjBuilder struct {
|
||||
runner ICmdObjRunner
|
||||
logCmdObj func(ICmdObj)
|
||||
// TODO: see if you can just remove this entirely and use secureexec.Command,
|
||||
// now that we're mocking out the runner itself.
|
||||
command func(string, ...string) *exec.Cmd
|
||||
platform *Platform
|
||||
}
|
||||
|
||||
func (self *CmdObjBuilder) New(cmdStr string) ICmdObj {
|
||||
args := str.ToArgv(cmdStr)
|
||||
cmd := self.command(args[0], args[1:]...)
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
return &CmdObj{
|
||||
cmdStr: cmdStr,
|
||||
cmd: cmd,
|
||||
runner: self.runner,
|
||||
logCommand: self.logCmdObj,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *CmdObjBuilder) NewFromArgs(args []string) ICmdObj {
|
||||
cmd := self.command(args[0], args[1:]...)
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
return &CmdObj{
|
||||
cmdStr: strings.Join(args, " "),
|
||||
cmd: cmd,
|
||||
runner: self.runner,
|
||||
logCommand: self.logCmdObj,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *CmdObjBuilder) NewShell(commandStr string) ICmdObj {
|
||||
return self.NewFromArgs([]string{self.platform.Shell, self.platform.ShellArg, commandStr})
|
||||
}
|
||||
|
||||
func (self *CmdObjBuilder) CloneWithNewRunner(decorate func(ICmdObjRunner) ICmdObjRunner) *CmdObjBuilder {
|
||||
decoratedRunner := decorate(self.runner)
|
||||
|
||||
return &CmdObjBuilder{
|
||||
runner: decoratedRunner,
|
||||
logCmdObj: self.logCmdObj,
|
||||
command: self.command,
|
||||
platform: self.platform,
|
||||
}
|
||||
}
|
||||
79
pkg/commands/oscommands/cmd_obj_runner.go
Normal file
79
pkg/commands/oscommands/cmd_obj_runner.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package oscommands
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ICmdObjRunner interface {
|
||||
Run(cmdObj ICmdObj) error
|
||||
RunWithOutput(cmdObj ICmdObj) (string, error)
|
||||
RunLineOutputCmd(cmdObj ICmdObj, onLine func(line string) (bool, error)) error
|
||||
}
|
||||
|
||||
type RunExpectation func(ICmdObj) (string, error)
|
||||
|
||||
type RealRunner struct {
|
||||
log *logrus.Entry
|
||||
logCmdObj func(ICmdObj)
|
||||
}
|
||||
|
||||
func (self *RealRunner) Run(cmdObj ICmdObj) error {
|
||||
_, err := self.RunWithOutput(cmdObj)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *RealRunner) RunWithOutput(cmdObj ICmdObj) (string, error) {
|
||||
self.logCmdObj(cmdObj)
|
||||
output, err := sanitisedCommandOutput(cmdObj.GetCmd().CombinedOutput())
|
||||
if err != nil {
|
||||
self.log.WithField("command", cmdObj.ToString()).Error(output)
|
||||
}
|
||||
return output, err
|
||||
}
|
||||
|
||||
func (self *RealRunner) RunLineOutputCmd(cmdObj ICmdObj, onLine func(line string) (bool, error)) error {
|
||||
cmd := cmdObj.GetCmd()
|
||||
stdoutPipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(stdoutPipe)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
stop, err := onLine(line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if stop {
|
||||
_ = cmd.Process.Kill()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
_ = cmd.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitisedCommandOutput(output []byte, err error) (string, error) {
|
||||
outputString := string(output)
|
||||
if err != nil {
|
||||
// errors like 'exit status 1' are not very useful so we'll create an error
|
||||
// from the combined output
|
||||
if outputString == "" {
|
||||
return "", utils.WrapError(err)
|
||||
}
|
||||
return outputString, errors.New(outputString)
|
||||
}
|
||||
return outputString, nil
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package oscommands
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -16,7 +15,6 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/common"
|
||||
"github.com/jesseduffield/lazygit/pkg/secureexec"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/mgutz/str"
|
||||
)
|
||||
|
||||
// Platform stores the os state
|
||||
@@ -55,9 +53,7 @@ type OSCommand struct {
|
||||
|
||||
removeFile func(string) error
|
||||
|
||||
Cmd ICmdObjBuilder
|
||||
|
||||
ICmdObjRunner
|
||||
Cmd *CmdObjBuilder
|
||||
}
|
||||
|
||||
// TODO: make these fields private
|
||||
@@ -92,15 +88,20 @@ func NewCmdLogEntry(cmdStr string, span string, commandLine bool) CmdLogEntry {
|
||||
|
||||
// NewOSCommand os command runner
|
||||
func NewOSCommand(common *common.Common) *OSCommand {
|
||||
command := secureexec.Command
|
||||
platform := getPlatform()
|
||||
|
||||
c := &OSCommand{
|
||||
Common: common,
|
||||
Platform: getPlatform(),
|
||||
Command: secureexec.Command,
|
||||
Platform: platform,
|
||||
Command: command,
|
||||
Getenv: os.Getenv,
|
||||
removeFile: os.RemoveAll,
|
||||
}
|
||||
|
||||
c.ICmdObjRunner = &RealRunner{c: c}
|
||||
runner := &RealRunner{log: common.Log, logCmdObj: c.LogCmdObj}
|
||||
c.Cmd = &CmdObjBuilder{runner: runner, command: command, logCmdObj: c.LogCmdObj, platform: platform}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -181,8 +182,12 @@ func (c *OSCommand) OpenLink(link string) error {
|
||||
|
||||
// Quote wraps a message in platform-specific quotation marks
|
||||
func (c *OSCommand) Quote(message string) string {
|
||||
return c.Cmd.Quote(message)
|
||||
}
|
||||
|
||||
func (self *CmdObjBuilder) Quote(message string) string {
|
||||
var quote string
|
||||
if c.Platform.OS == "windows" {
|
||||
if self.platform.OS == "windows" {
|
||||
quote = `\"`
|
||||
message = strings.NewReplacer(
|
||||
`"`, `"'"'"`,
|
||||
@@ -365,137 +370,16 @@ func (c *OSCommand) RemoveFile(path string) error {
|
||||
return c.removeFile(path)
|
||||
}
|
||||
|
||||
// builders
|
||||
|
||||
type ICmdObjBuilder interface {
|
||||
// returns a new command object based on the string provided
|
||||
New(cmdStr string) ICmdObj
|
||||
NewShell(commandStr string) ICmdObj
|
||||
NewFromArgs(args []string) ICmdObj
|
||||
Quote(str string) string
|
||||
}
|
||||
|
||||
func (c *OSCommand) NewCmdObj(cmdStr string) ICmdObj {
|
||||
args := str.ToArgv(cmdStr)
|
||||
cmd := c.Command(args[0], args[1:]...)
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
return &CmdObj{
|
||||
cmdStr: cmdStr,
|
||||
cmd: cmd,
|
||||
runner: c.ICmdObjRunner,
|
||||
logCommand: c.LogCmdObj,
|
||||
}
|
||||
return c.Cmd.New(cmdStr)
|
||||
}
|
||||
|
||||
func (c *OSCommand) NewCmdObjFromArgs(args []string) ICmdObj {
|
||||
cmd := c.Command(args[0], args[1:]...)
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
return &CmdObj{
|
||||
cmdStr: strings.Join(args, " "),
|
||||
cmd: cmd,
|
||||
runner: c.ICmdObjRunner,
|
||||
logCommand: c.LogCmdObj,
|
||||
}
|
||||
return c.Cmd.NewFromArgs(args)
|
||||
}
|
||||
|
||||
// NewShellCmdObj takes a string like `git commit` and returns an executable shell command for it
|
||||
func (c *OSCommand) NewShellCmdObj(commandStr string) ICmdObj {
|
||||
quotedCommand := ""
|
||||
// Windows does not seem to like quotes around the command
|
||||
if c.Platform.OS == "windows" {
|
||||
quotedCommand = strings.NewReplacer(
|
||||
"^", "^^",
|
||||
"&", "^&",
|
||||
"|", "^|",
|
||||
"<", "^<",
|
||||
">", "^>",
|
||||
"%", "^%",
|
||||
).Replace(commandStr)
|
||||
} else {
|
||||
quotedCommand = c.Quote(commandStr)
|
||||
}
|
||||
|
||||
shellCommand := fmt.Sprintf("%s %s %s", c.Platform.Shell, c.Platform.ShellArg, quotedCommand)
|
||||
return c.NewCmdObj(shellCommand)
|
||||
}
|
||||
|
||||
// TODO: pick one of NewShellCmdObj2 and ShellCommandFromString to use. I'm not sure
|
||||
// which one actually is better, but I suspect it's NewShellCmdObj2
|
||||
func (c *OSCommand) NewShellCmdObj2(command string) ICmdObj {
|
||||
return c.NewCmdObjFromArgs([]string{c.Platform.Shell, c.Platform.ShellArg, command})
|
||||
}
|
||||
|
||||
// runners
|
||||
|
||||
type ICmdObjRunner interface {
|
||||
Run(cmdObj ICmdObj) error
|
||||
RunWithOutput(cmdObj ICmdObj) (string, error)
|
||||
RunLineOutputCmd(cmdObj ICmdObj, onLine func(line string) (bool, error)) error
|
||||
}
|
||||
|
||||
type RunExpectation func(ICmdObj) (string, error)
|
||||
|
||||
type RealRunner struct {
|
||||
c *OSCommand
|
||||
}
|
||||
|
||||
func (self *RealRunner) Run(cmdObj ICmdObj) error {
|
||||
_, err := self.RunWithOutput(cmdObj)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *RealRunner) RunWithOutput(cmdObj ICmdObj) (string, error) {
|
||||
self.c.LogCmdObj(cmdObj)
|
||||
output, err := sanitisedCommandOutput(cmdObj.GetCmd().CombinedOutput())
|
||||
if err != nil {
|
||||
self.c.Log.WithField("command", cmdObj.ToString()).Error(output)
|
||||
}
|
||||
return output, err
|
||||
}
|
||||
|
||||
func (self *RealRunner) RunLineOutputCmd(cmdObj ICmdObj, onLine func(line string) (bool, error)) error {
|
||||
cmd := cmdObj.GetCmd()
|
||||
stdoutPipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(stdoutPipe)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
stop, err := onLine(line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if stop {
|
||||
_ = cmd.Process.Kill()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
_ = cmd.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitisedCommandOutput(output []byte, err error) (string, error) {
|
||||
outputString := string(output)
|
||||
if err != nil {
|
||||
// errors like 'exit status 1' are not very useful so we'll create an error
|
||||
// from the combined output
|
||||
if outputString == "" {
|
||||
return "", utils.WrapError(err)
|
||||
}
|
||||
return outputString, errors.New(outputString)
|
||||
}
|
||||
return outputString, nil
|
||||
return c.Cmd.NewShell(commandStr)
|
||||
}
|
||||
|
||||
func GetTempDir() string {
|
||||
|
||||
@@ -111,14 +111,15 @@ func (c *GitCommand) SubmoduleDelete(submodule *models.SubmoduleConfig) error {
|
||||
}
|
||||
|
||||
func (c *GitCommand) SubmoduleAdd(name string, path string, url string) error {
|
||||
return c.OSCommand.Run(
|
||||
c.OSCommand.NewCmdObj(
|
||||
return c.Cmd.
|
||||
New(
|
||||
fmt.Sprintf(
|
||||
"git submodule add --force --name %s -- %s %s ",
|
||||
c.OSCommand.Quote(name),
|
||||
c.OSCommand.Quote(url),
|
||||
c.OSCommand.Quote(path),
|
||||
)))
|
||||
)).
|
||||
Run()
|
||||
}
|
||||
|
||||
func (c *GitCommand) SubmoduleUpdateUrl(name string, path string, newUrl string) error {
|
||||
|
||||
@@ -244,7 +244,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand
|
||||
}
|
||||
|
||||
if customCommand.Subprocess {
|
||||
return gui.runSubprocessWithSuspenseAndRefresh(gui.OSCommand.NewShellCmdObj2(cmdStr))
|
||||
return gui.runSubprocessWithSuspenseAndRefresh(gui.OSCommand.Cmd.NewShell(cmdStr))
|
||||
}
|
||||
|
||||
loadingText := customCommand.LoadingText
|
||||
|
||||
@@ -465,7 +465,7 @@ func (gui *Gui) handleCommitEditorPress() error {
|
||||
cmdStr := "git " + strings.Join(args, " ")
|
||||
|
||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
||||
gui.GitCommand.WithSpan(gui.Tr.Spans.Commit).NewCmdObjWithLog(cmdStr),
|
||||
gui.GitCommand.WithSpan(gui.Tr.Spans.Commit).NewCmdObj(cmdStr).Log(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -923,7 +923,7 @@ func (gui *Gui) handleCustomCommand() error {
|
||||
|
||||
gui.OnRunCommand(oscommands.NewCmdLogEntry(command, gui.Tr.Spans.CustomCommand, true))
|
||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
||||
gui.OSCommand.NewShellCmdObj2(command),
|
||||
gui.OSCommand.NewShellCmdObj(command),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -32,7 +32,7 @@ func (gui *Gui) gitFlowFinishBranch(gitFlowConfig string, branchName string) err
|
||||
}
|
||||
|
||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
||||
gui.GitCommand.WithSpan(gui.Tr.Spans.GitFlowFinish).NewCmdObjWithLog("git flow " + branchType + " finish " + suffix),
|
||||
gui.GitCommand.WithSpan(gui.Tr.Spans.GitFlowFinish).NewCmdObj("git flow " + branchType + " finish " + suffix).Log(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func (gui *Gui) handleCreateGitFlowMenu() error {
|
||||
title: title,
|
||||
handleConfirm: func(name string) error {
|
||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
||||
gui.GitCommand.WithSpan(gui.Tr.Spans.GitFlowStart).NewCmdObjWithLog("git flow " + branchType + " start " + name),
|
||||
gui.GitCommand.WithSpan(gui.Tr.Spans.GitFlowStart).NewCmdObj("git flow " + branchType + " start " + name).Log(),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user