mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-15 11:56:37 +02:00
start adding support for logging of commands
This commit is contained in:
parent
e145090046
commit
bb918b579a
@ -2,7 +2,6 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
@ -53,11 +52,6 @@ func (c *GitCommand) AmendHead() error {
|
|||||||
return c.OSCommand.RunCommand(c.AmendHeadCmdStr())
|
return c.OSCommand.RunCommand(c.AmendHeadCmdStr())
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareCommitAmendHeadSubProcess prepares a subprocess for `git commit --amend --allow-empty`
|
|
||||||
func (c *GitCommand) PrepareCommitAmendHeadSubProcess() *exec.Cmd {
|
|
||||||
return c.OSCommand.ShellCommandFromString(c.AmendHeadCmdStr())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *GitCommand) AmendHeadCmdStr() string {
|
func (c *GitCommand) AmendHeadCmdStr() string {
|
||||||
return "git commit --amend --no-edit --allow-empty"
|
return "git commit --amend --no-edit --allow-empty"
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,5 @@ func NewDummyGitCommandWithOSCommand(osCommand *oscommands.OSCommand) *GitComman
|
|||||||
Tr: i18n.NewTranslationSet(utils.NewDummyLog()),
|
Tr: i18n.NewTranslationSet(utils.NewDummyLog()),
|
||||||
Config: config.NewDummyAppConfig(),
|
Config: config.NewDummyAppConfig(),
|
||||||
getGitConfigValue: func(string) (string, error) { return "", nil },
|
getGitConfigValue: func(string) (string, error) { return "", nil },
|
||||||
removeFile: func(string) error { return nil },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,14 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||||
"github.com/jesseduffield/lazygit/pkg/secureexec"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/test"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CatFile obtains the content of a file
|
// CatFile obtains the content of a file
|
||||||
@ -145,7 +139,7 @@ func (c *GitCommand) DiscardAllFileChanges(file *models.File) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if file.Added {
|
if file.Added {
|
||||||
return c.removeFile(file.Name)
|
return c.OSCommand.RemoveFile(file.Name)
|
||||||
}
|
}
|
||||||
return c.DiscardUnstagedFileChanges(file)
|
return c.DiscardUnstagedFileChanges(file)
|
||||||
}
|
}
|
||||||
@ -346,381 +340,3 @@ func (c *GitCommand) EditFileCmdStr(filename string) (string, error) {
|
|||||||
|
|
||||||
return fmt.Sprintf("%s %s", editor, c.OSCommand.Quote(filename)), nil
|
return fmt.Sprintf("%s %s", editor, c.OSCommand.Quote(filename)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGitCommandApplyPatch(t *testing.T) {
|
|
||||||
type scenario struct {
|
|
||||||
testName string
|
|
||||||
command func(string, ...string) *exec.Cmd
|
|
||||||
test func(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
scenarios := []scenario{
|
|
||||||
{
|
|
||||||
"valid case",
|
|
||||||
func(cmd string, args ...string) *exec.Cmd {
|
|
||||||
assert.Equal(t, "git", cmd)
|
|
||||||
assert.EqualValues(t, []string{"apply", "--cached"}, args[0:2])
|
|
||||||
filename := args[2]
|
|
||||||
content, err := ioutil.ReadFile(filename)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, "test", string(content))
|
|
||||||
|
|
||||||
return secureexec.Command("echo", "done")
|
|
||||||
},
|
|
||||||
func(err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command returns error",
|
|
||||||
func(cmd string, args ...string) *exec.Cmd {
|
|
||||||
assert.Equal(t, "git", cmd)
|
|
||||||
assert.EqualValues(t, []string{"apply", "--cached"}, args[0:2])
|
|
||||||
filename := args[2]
|
|
||||||
// TODO: Ideally we want to mock out OSCommand here so that we're not
|
|
||||||
// double handling testing it's CreateTempFile functionality,
|
|
||||||
// but it is going to take a bit of work to make a proper mock for it
|
|
||||||
// so I'm leaving it for another PR
|
|
||||||
content, err := ioutil.ReadFile(filename)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, "test", string(content))
|
|
||||||
|
|
||||||
return secureexec.Command("test")
|
|
||||||
},
|
|
||||||
func(err error) {
|
|
||||||
assert.Error(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range scenarios {
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
|
||||||
gitCmd := NewDummyGitCommand()
|
|
||||||
gitCmd.OSCommand.Command = s.command
|
|
||||||
s.test(gitCmd.ApplyPatch("test", "cached"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestGitCommandDiscardOldFileChanges is a function.
|
|
||||||
func TestGitCommandDiscardOldFileChanges(t *testing.T) {
|
|
||||||
type scenario struct {
|
|
||||||
testName string
|
|
||||||
getGitConfigValue func(string) (string, error)
|
|
||||||
commits []*models.Commit
|
|
||||||
commitIndex int
|
|
||||||
fileName string
|
|
||||||
command func(string, ...string) *exec.Cmd
|
|
||||||
test func(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
scenarios := []scenario{
|
|
||||||
{
|
|
||||||
"returns error when index outside of range of commits",
|
|
||||||
func(string) (string, error) {
|
|
||||||
return "", nil
|
|
||||||
},
|
|
||||||
[]*models.Commit{},
|
|
||||||
0,
|
|
||||||
"test999.txt",
|
|
||||||
nil,
|
|
||||||
func(err error) {
|
|
||||||
assert.Error(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"returns error when using gpg",
|
|
||||||
func(string) (string, error) {
|
|
||||||
return "true", nil
|
|
||||||
},
|
|
||||||
[]*models.Commit{{Name: "commit", Sha: "123456"}},
|
|
||||||
0,
|
|
||||||
"test999.txt",
|
|
||||||
nil,
|
|
||||||
func(err error) {
|
|
||||||
assert.Error(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checks out file if it already existed",
|
|
||||||
func(string) (string, error) {
|
|
||||||
return "", nil
|
|
||||||
},
|
|
||||||
[]*models.Commit{
|
|
||||||
{Name: "commit", Sha: "123456"},
|
|
||||||
{Name: "commit2", Sha: "abcdef"},
|
|
||||||
},
|
|
||||||
0,
|
|
||||||
"test999.txt",
|
|
||||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
|
||||||
{
|
|
||||||
Expect: "git rebase --interactive --autostash --keep-empty abcdef",
|
|
||||||
Replace: "echo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Expect: "git cat-file -e HEAD^:test999.txt",
|
|
||||||
Replace: "echo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Expect: "git checkout HEAD^ test999.txt",
|
|
||||||
Replace: "echo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Expect: "git commit --amend --no-edit --allow-empty",
|
|
||||||
Replace: "echo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Expect: "git rebase --continue",
|
|
||||||
Replace: "echo",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
func(err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// test for when the file was created within the commit requires a refactor to support proper mocks
|
|
||||||
// currently we'd need to mock out the os.Remove function and that's gonna introduce tech debt
|
|
||||||
}
|
|
||||||
|
|
||||||
gitCmd := NewDummyGitCommand()
|
|
||||||
|
|
||||||
for _, s := range scenarios {
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
|
||||||
gitCmd.OSCommand.Command = s.command
|
|
||||||
gitCmd.getGitConfigValue = s.getGitConfigValue
|
|
||||||
s.test(gitCmd.DiscardOldFileChanges(s.commits, s.commitIndex, s.fileName))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestGitCommandDiscardUnstagedFileChanges is a function.
|
|
||||||
func TestGitCommandDiscardUnstagedFileChanges(t *testing.T) {
|
|
||||||
type scenario struct {
|
|
||||||
testName string
|
|
||||||
file *models.File
|
|
||||||
command func(string, ...string) *exec.Cmd
|
|
||||||
test func(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
scenarios := []scenario{
|
|
||||||
{
|
|
||||||
"valid case",
|
|
||||||
&models.File{Name: "test.txt"},
|
|
||||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
|
||||||
{
|
|
||||||
Expect: `git checkout -- "test.txt"`,
|
|
||||||
Replace: "echo",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
func(err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
gitCmd := NewDummyGitCommand()
|
|
||||||
|
|
||||||
for _, s := range scenarios {
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
|
||||||
gitCmd.OSCommand.Command = s.command
|
|
||||||
s.test(gitCmd.DiscardUnstagedFileChanges(s.file))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestGitCommandDiscardAnyUnstagedFileChanges is a function.
|
|
||||||
func TestGitCommandDiscardAnyUnstagedFileChanges(t *testing.T) {
|
|
||||||
type scenario struct {
|
|
||||||
testName string
|
|
||||||
command func(string, ...string) *exec.Cmd
|
|
||||||
test func(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
scenarios := []scenario{
|
|
||||||
{
|
|
||||||
"valid case",
|
|
||||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
|
||||||
{
|
|
||||||
Expect: `git checkout -- .`,
|
|
||||||
Replace: "echo",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
func(err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
gitCmd := NewDummyGitCommand()
|
|
||||||
|
|
||||||
for _, s := range scenarios {
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
|
||||||
gitCmd.OSCommand.Command = s.command
|
|
||||||
s.test(gitCmd.DiscardAnyUnstagedFileChanges())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestGitCommandRemoveUntrackedFiles is a function.
|
|
||||||
func TestGitCommandRemoveUntrackedFiles(t *testing.T) {
|
|
||||||
type scenario struct {
|
|
||||||
testName string
|
|
||||||
command func(string, ...string) *exec.Cmd
|
|
||||||
test func(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
scenarios := []scenario{
|
|
||||||
{
|
|
||||||
"valid case",
|
|
||||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
|
||||||
{
|
|
||||||
Expect: `git clean -fd`,
|
|
||||||
Replace: "echo",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
func(err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
gitCmd := NewDummyGitCommand()
|
|
||||||
|
|
||||||
for _, s := range scenarios {
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
|
||||||
gitCmd.OSCommand.Command = s.command
|
|
||||||
s.test(gitCmd.RemoveUntrackedFiles())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestEditFileCmdStr is a function.
|
|
||||||
func TestEditFileCmdStr(t *testing.T) {
|
|
||||||
type scenario struct {
|
|
||||||
filename string
|
|
||||||
command func(string, ...string) *exec.Cmd
|
|
||||||
getenv func(string) string
|
|
||||||
getGitConfigValue func(string) (string, error)
|
|
||||||
test func(string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
scenarios := []scenario{
|
|
||||||
{
|
|
||||||
"test",
|
|
||||||
func(name string, arg ...string) *exec.Cmd {
|
|
||||||
return secureexec.Command("exit", "1")
|
|
||||||
},
|
|
||||||
func(env string) string {
|
|
||||||
return ""
|
|
||||||
},
|
|
||||||
func(cf string) (string, error) {
|
|
||||||
return "", nil
|
|
||||||
},
|
|
||||||
func(cmdStr string, err error) {
|
|
||||||
assert.EqualError(t, err, "No editor defined in $GIT_EDITOR, $VISUAL, $EDITOR, or git config")
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"test",
|
|
||||||
func(name string, arg ...string) *exec.Cmd {
|
|
||||||
assert.Equal(t, "which", name)
|
|
||||||
return secureexec.Command("exit", "1")
|
|
||||||
},
|
|
||||||
func(env string) string {
|
|
||||||
return ""
|
|
||||||
},
|
|
||||||
func(cf string) (string, error) {
|
|
||||||
return "nano", nil
|
|
||||||
},
|
|
||||||
func(cmdStr string, err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "nano \"test\"", cmdStr)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"test",
|
|
||||||
func(name string, arg ...string) *exec.Cmd {
|
|
||||||
assert.Equal(t, "which", name)
|
|
||||||
return secureexec.Command("exit", "1")
|
|
||||||
},
|
|
||||||
func(env string) string {
|
|
||||||
if env == "VISUAL" {
|
|
||||||
return "nano"
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
},
|
|
||||||
func(cf string) (string, error) {
|
|
||||||
return "", nil
|
|
||||||
},
|
|
||||||
func(cmdStr string, err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"test",
|
|
||||||
func(name string, arg ...string) *exec.Cmd {
|
|
||||||
assert.Equal(t, "which", name)
|
|
||||||
return secureexec.Command("exit", "1")
|
|
||||||
},
|
|
||||||
func(env string) string {
|
|
||||||
if env == "EDITOR" {
|
|
||||||
return "emacs"
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
},
|
|
||||||
func(cf string) (string, error) {
|
|
||||||
return "", nil
|
|
||||||
},
|
|
||||||
func(cmdStr string, err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "emacs \"test\"", cmdStr)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"test",
|
|
||||||
func(name string, arg ...string) *exec.Cmd {
|
|
||||||
assert.Equal(t, "which", name)
|
|
||||||
return secureexec.Command("echo")
|
|
||||||
},
|
|
||||||
func(env string) string {
|
|
||||||
return ""
|
|
||||||
},
|
|
||||||
func(cf string) (string, error) {
|
|
||||||
return "", nil
|
|
||||||
},
|
|
||||||
func(cmdStr string, err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "vi \"test\"", cmdStr)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file/with space",
|
|
||||||
func(name string, args ...string) *exec.Cmd {
|
|
||||||
assert.Equal(t, "which", name)
|
|
||||||
return secureexec.Command("echo")
|
|
||||||
},
|
|
||||||
func(env string) string {
|
|
||||||
return ""
|
|
||||||
},
|
|
||||||
func(cf string) (string, error) {
|
|
||||||
return "", nil
|
|
||||||
},
|
|
||||||
func(cmdStr string, err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "vi \"file/with space\"", cmdStr)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range scenarios {
|
|
||||||
gitCmd := NewDummyGitCommand()
|
|
||||||
gitCmd.OSCommand.Command = s.command
|
|
||||||
gitCmd.OSCommand.Getenv = s.getenv
|
|
||||||
gitCmd.getGitConfigValue = s.getGitConfigValue
|
|
||||||
s.test(gitCmd.EditFileCmdStr(s.filename))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -2,6 +2,7 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
@ -323,7 +324,7 @@ func TestGitCommandDiscardAllFileChanges(t *testing.T) {
|
|||||||
var cmdsCalled *[][]string
|
var cmdsCalled *[][]string
|
||||||
gitCmd := NewDummyGitCommand()
|
gitCmd := NewDummyGitCommand()
|
||||||
gitCmd.OSCommand.Command, cmdsCalled = s.command()
|
gitCmd.OSCommand.Command, cmdsCalled = s.command()
|
||||||
gitCmd.removeFile = s.removeFile
|
gitCmd.OSCommand.SetRemoveFile(s.removeFile)
|
||||||
s.test(cmdsCalled, gitCmd.DiscardAllFileChanges(s.file))
|
s.test(cmdsCalled, gitCmd.DiscardAllFileChanges(s.file))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -465,3 +466,381 @@ func TestGitCommandCheckoutFile(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGitCommandApplyPatch(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"valid case",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.Equal(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"apply", "--cached"}, args[0:2])
|
||||||
|
filename := args[2]
|
||||||
|
content, err := ioutil.ReadFile(filename)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "test", string(content))
|
||||||
|
|
||||||
|
return secureexec.Command("echo", "done")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command returns error",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.Equal(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"apply", "--cached"}, args[0:2])
|
||||||
|
filename := args[2]
|
||||||
|
// TODO: Ideally we want to mock out OSCommand here so that we're not
|
||||||
|
// double handling testing it's CreateTempFile functionality,
|
||||||
|
// but it is going to take a bit of work to make a proper mock for it
|
||||||
|
// so I'm leaving it for another PR
|
||||||
|
content, err := ioutil.ReadFile(filename)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "test", string(content))
|
||||||
|
|
||||||
|
return secureexec.Command("test")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.Error(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd := NewDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.Command = s.command
|
||||||
|
s.test(gitCmd.ApplyPatch("test", "cached"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGitCommandDiscardOldFileChanges is a function.
|
||||||
|
func TestGitCommandDiscardOldFileChanges(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
getGitConfigValue func(string) (string, error)
|
||||||
|
commits []*models.Commit
|
||||||
|
commitIndex int
|
||||||
|
fileName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"returns error when index outside of range of commits",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
[]*models.Commit{},
|
||||||
|
0,
|
||||||
|
"test999.txt",
|
||||||
|
nil,
|
||||||
|
func(err error) {
|
||||||
|
assert.Error(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"returns error when using gpg",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "true", nil
|
||||||
|
},
|
||||||
|
[]*models.Commit{{Name: "commit", Sha: "123456"}},
|
||||||
|
0,
|
||||||
|
"test999.txt",
|
||||||
|
nil,
|
||||||
|
func(err error) {
|
||||||
|
assert.Error(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"checks out file if it already existed",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
[]*models.Commit{
|
||||||
|
{Name: "commit", Sha: "123456"},
|
||||||
|
{Name: "commit2", Sha: "abcdef"},
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
"test999.txt",
|
||||||
|
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||||
|
{
|
||||||
|
Expect: "git rebase --interactive --autostash --keep-empty abcdef",
|
||||||
|
Replace: "echo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Expect: "git cat-file -e HEAD^:test999.txt",
|
||||||
|
Replace: "echo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Expect: "git checkout HEAD^ test999.txt",
|
||||||
|
Replace: "echo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Expect: "git commit --amend --no-edit --allow-empty",
|
||||||
|
Replace: "echo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Expect: "git rebase --continue",
|
||||||
|
Replace: "echo",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// test for when the file was created within the commit requires a refactor to support proper mocks
|
||||||
|
// currently we'd need to mock out the os.Remove function and that's gonna introduce tech debt
|
||||||
|
}
|
||||||
|
|
||||||
|
gitCmd := NewDummyGitCommand()
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd.OSCommand.Command = s.command
|
||||||
|
gitCmd.getGitConfigValue = s.getGitConfigValue
|
||||||
|
s.test(gitCmd.DiscardOldFileChanges(s.commits, s.commitIndex, s.fileName))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGitCommandDiscardUnstagedFileChanges is a function.
|
||||||
|
func TestGitCommandDiscardUnstagedFileChanges(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
file *models.File
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"valid case",
|
||||||
|
&models.File{Name: "test.txt"},
|
||||||
|
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||||
|
{
|
||||||
|
Expect: `git checkout -- "test.txt"`,
|
||||||
|
Replace: "echo",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
gitCmd := NewDummyGitCommand()
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd.OSCommand.Command = s.command
|
||||||
|
s.test(gitCmd.DiscardUnstagedFileChanges(s.file))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGitCommandDiscardAnyUnstagedFileChanges is a function.
|
||||||
|
func TestGitCommandDiscardAnyUnstagedFileChanges(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"valid case",
|
||||||
|
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||||
|
{
|
||||||
|
Expect: `git checkout -- .`,
|
||||||
|
Replace: "echo",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
gitCmd := NewDummyGitCommand()
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd.OSCommand.Command = s.command
|
||||||
|
s.test(gitCmd.DiscardAnyUnstagedFileChanges())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGitCommandRemoveUntrackedFiles is a function.
|
||||||
|
func TestGitCommandRemoveUntrackedFiles(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"valid case",
|
||||||
|
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||||
|
{
|
||||||
|
Expect: `git clean -fd`,
|
||||||
|
Replace: "echo",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
gitCmd := NewDummyGitCommand()
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd.OSCommand.Command = s.command
|
||||||
|
s.test(gitCmd.RemoveUntrackedFiles())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestEditFileCmdStr is a function.
|
||||||
|
func TestEditFileCmdStr(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
filename string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
getenv func(string) string
|
||||||
|
getGitConfigValue func(string) (string, error)
|
||||||
|
test func(string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"test",
|
||||||
|
func(name string, arg ...string) *exec.Cmd {
|
||||||
|
return secureexec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(env string) string {
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
func(cf string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(cmdStr string, err error) {
|
||||||
|
assert.EqualError(t, err, "No editor defined in $GIT_EDITOR, $VISUAL, $EDITOR, or git config")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test",
|
||||||
|
func(name string, arg ...string) *exec.Cmd {
|
||||||
|
assert.Equal(t, "which", name)
|
||||||
|
return secureexec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(env string) string {
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
func(cf string) (string, error) {
|
||||||
|
return "nano", nil
|
||||||
|
},
|
||||||
|
func(cmdStr string, err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "nano \"test\"", cmdStr)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test",
|
||||||
|
func(name string, arg ...string) *exec.Cmd {
|
||||||
|
assert.Equal(t, "which", name)
|
||||||
|
return secureexec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(env string) string {
|
||||||
|
if env == "VISUAL" {
|
||||||
|
return "nano"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
func(cf string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(cmdStr string, err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test",
|
||||||
|
func(name string, arg ...string) *exec.Cmd {
|
||||||
|
assert.Equal(t, "which", name)
|
||||||
|
return secureexec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(env string) string {
|
||||||
|
if env == "EDITOR" {
|
||||||
|
return "emacs"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
func(cf string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(cmdStr string, err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "emacs \"test\"", cmdStr)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test",
|
||||||
|
func(name string, arg ...string) *exec.Cmd {
|
||||||
|
assert.Equal(t, "which", name)
|
||||||
|
return secureexec.Command("echo")
|
||||||
|
},
|
||||||
|
func(env string) string {
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
func(cf string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(cmdStr string, err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "vi \"test\"", cmdStr)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file/with space",
|
||||||
|
func(name string, args ...string) *exec.Cmd {
|
||||||
|
assert.Equal(t, "which", name)
|
||||||
|
return secureexec.Command("echo")
|
||||||
|
},
|
||||||
|
func(env string) string {
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
func(cf string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(cmdStr string, err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "vi \"file/with space\"", cmdStr)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
gitCmd := NewDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.Command = s.command
|
||||||
|
gitCmd.OSCommand.Getenv = s.getenv
|
||||||
|
gitCmd.getGitConfigValue = s.getGitConfigValue
|
||||||
|
s.test(gitCmd.EditFileCmdStr(s.filename))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -33,7 +33,6 @@ type GitCommand struct {
|
|||||||
Tr *i18n.TranslationSet
|
Tr *i18n.TranslationSet
|
||||||
Config config.AppConfigurer
|
Config config.AppConfigurer
|
||||||
getGitConfigValue func(string) (string, error)
|
getGitConfigValue func(string) (string, error)
|
||||||
removeFile func(string) error
|
|
||||||
DotGitDir string
|
DotGitDir string
|
||||||
onSuccessfulContinue func() error
|
onSuccessfulContinue func() error
|
||||||
PatchManager *patch.PatchManager
|
PatchManager *patch.PatchManager
|
||||||
@ -75,7 +74,6 @@ func NewGitCommand(log *logrus.Entry, osCommand *oscommands.OSCommand, tr *i18n.
|
|||||||
Repo: repo,
|
Repo: repo,
|
||||||
Config: config,
|
Config: config,
|
||||||
getGitConfigValue: getGitConfigValue,
|
getGitConfigValue: getGitConfigValue,
|
||||||
removeFile: os.RemoveAll,
|
|
||||||
DotGitDir: dotGitDir,
|
DotGitDir: dotGitDir,
|
||||||
PushToCurrent: pushToCurrent,
|
PushToCurrent: pushToCurrent,
|
||||||
}
|
}
|
||||||
@ -85,6 +83,14 @@ func NewGitCommand(log *logrus.Entry, osCommand *oscommands.OSCommand, tr *i18n.
|
|||||||
return gitCommand, nil
|
return gitCommand, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) WithSpan(span string) *GitCommand {
|
||||||
|
newGitCommand := &GitCommand{}
|
||||||
|
*newGitCommand = *c
|
||||||
|
newGitCommand.OSCommand = c.OSCommand.WithSpan(span)
|
||||||
|
newGitCommand.PatchManager.ApplyPatch = newGitCommand.ApplyPatch
|
||||||
|
return newGitCommand
|
||||||
|
}
|
||||||
|
|
||||||
func navigateToRepoRootDirectory(stat func(string) (os.FileInfo, error), chdir func(string) error) error {
|
func navigateToRepoRootDirectory(stat func(string) (os.FileInfo, error), chdir func(string) error) error {
|
||||||
gitDir := env.GetGitDirEnv()
|
gitDir := env.GetGitDirEnv()
|
||||||
if gitDir != "" {
|
if gitDir != "" {
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
// NOTE: If the return data is empty it won't written anything to stdin
|
// NOTE: If the return data is empty it won't written anything to stdin
|
||||||
func RunCommandWithOutputLiveWrapper(c *OSCommand, command string, output func(string) string) error {
|
func RunCommandWithOutputLiveWrapper(c *OSCommand, command string, output func(string) string) error {
|
||||||
c.Log.WithField("command", command).Info("RunCommand")
|
c.Log.WithField("command", command).Info("RunCommand")
|
||||||
|
c.LogCommand(command, true)
|
||||||
cmd := c.ExecutableFromString(command)
|
cmd := c.ExecutableFromString(command)
|
||||||
cmd.Env = append(cmd.Env, "LANG=en_US.UTF-8", "LC_ALL=en_US.UTF-8")
|
cmd.Env = append(cmd.Env, "LANG=en_US.UTF-8", "LC_ALL=en_US.UTF-8")
|
||||||
|
|
||||||
|
@ -40,7 +40,44 @@ type OSCommand struct {
|
|||||||
Command func(string, ...string) *exec.Cmd
|
Command func(string, ...string) *exec.Cmd
|
||||||
BeforeExecuteCmd func(*exec.Cmd)
|
BeforeExecuteCmd func(*exec.Cmd)
|
||||||
Getenv func(string) string
|
Getenv func(string) string
|
||||||
onRunCommand func(string)
|
|
||||||
|
// callback to run before running a command, i.e. for the purposes of logging
|
||||||
|
onRunCommand func(CmdLogEntry)
|
||||||
|
|
||||||
|
// something like 'Staging File': allows us to group cmd logs under a single title
|
||||||
|
CmdLogSpan string
|
||||||
|
|
||||||
|
removeFile func(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make these fields private
|
||||||
|
type CmdLogEntry struct {
|
||||||
|
// e.g. 'git commit -m "haha"'
|
||||||
|
cmdStr string
|
||||||
|
// Span is something like 'Staging File'. Multiple commands can be grouped under the same
|
||||||
|
// span
|
||||||
|
span string
|
||||||
|
|
||||||
|
// sometimes our command is direct like 'git commit', and sometimes it's a
|
||||||
|
// command to remove a file but through Go's standard library rather than the
|
||||||
|
// command line
|
||||||
|
commandLine bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e CmdLogEntry) GetCmdStr() string {
|
||||||
|
return e.cmdStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e CmdLogEntry) GetSpan() string {
|
||||||
|
return e.span
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e CmdLogEntry) GetCommandLine() bool {
|
||||||
|
return e.commandLine
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCmdLogEntry(cmdStr string, span string, commandLine bool) CmdLogEntry {
|
||||||
|
return CmdLogEntry{cmdStr: cmdStr, span: span, commandLine: commandLine}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOSCommand os command runner
|
// NewOSCommand os command runner
|
||||||
@ -52,10 +89,30 @@ func NewOSCommand(log *logrus.Entry, config config.AppConfigurer) *OSCommand {
|
|||||||
Command: secureexec.Command,
|
Command: secureexec.Command,
|
||||||
BeforeExecuteCmd: func(*exec.Cmd) {},
|
BeforeExecuteCmd: func(*exec.Cmd) {},
|
||||||
Getenv: os.Getenv,
|
Getenv: os.Getenv,
|
||||||
|
removeFile: os.RemoveAll,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OSCommand) SetOnRunCommand(f func(string)) {
|
func (c *OSCommand) WithSpan(span string) *OSCommand {
|
||||||
|
newOSCommand := &OSCommand{}
|
||||||
|
*newOSCommand = *c
|
||||||
|
newOSCommand.CmdLogSpan = span
|
||||||
|
return newOSCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OSCommand) LogExecCmd(cmd *exec.Cmd) {
|
||||||
|
c.LogCommand(strings.Join(cmd.Args, " "), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OSCommand) LogCommand(cmdStr string, commandLine bool) {
|
||||||
|
c.Log.WithField("command", cmdStr).Info("RunCommand")
|
||||||
|
|
||||||
|
if c.onRunCommand != nil && c.CmdLogSpan != "" {
|
||||||
|
c.onRunCommand(NewCmdLogEntry(cmdStr, c.CmdLogSpan, commandLine))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OSCommand) SetOnRunCommand(f func(CmdLogEntry)) {
|
||||||
c.onRunCommand = f
|
c.onRunCommand = f
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +122,11 @@ func (c *OSCommand) SetCommand(cmd func(string, ...string) *exec.Cmd) {
|
|||||||
c.Command = cmd
|
c.Command = cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To be used for testing only
|
||||||
|
func (c *OSCommand) SetRemoveFile(f func(string) error) {
|
||||||
|
c.removeFile = f
|
||||||
|
}
|
||||||
|
|
||||||
func (c *OSCommand) SetBeforeExecuteCmd(cmd func(*exec.Cmd)) {
|
func (c *OSCommand) SetBeforeExecuteCmd(cmd func(*exec.Cmd)) {
|
||||||
c.BeforeExecuteCmd = cmd
|
c.BeforeExecuteCmd = cmd
|
||||||
}
|
}
|
||||||
@ -74,10 +136,7 @@ type RunCommandOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *OSCommand) RunCommandWithOutputWithOptions(command string, options RunCommandOptions) (string, error) {
|
func (c *OSCommand) RunCommandWithOutputWithOptions(command string, options RunCommandOptions) (string, error) {
|
||||||
c.Log.WithField("command", command).Info("RunCommand")
|
c.LogCommand(command, true)
|
||||||
if c.onRunCommand != nil {
|
|
||||||
c.onRunCommand(command)
|
|
||||||
}
|
|
||||||
cmd := c.ExecutableFromString(command)
|
cmd := c.ExecutableFromString(command)
|
||||||
|
|
||||||
cmd.Env = append(cmd.Env, "GIT_TERMINAL_PROMPT=0") // prevents git from prompting us for input which would freeze the program
|
cmd.Env = append(cmd.Env, "GIT_TERMINAL_PROMPT=0") // prevents git from prompting us for input which would freeze the program
|
||||||
@ -102,11 +161,8 @@ func (c *OSCommand) RunCommandWithOutput(formatString string, formatArgs ...inte
|
|||||||
if formatArgs != nil {
|
if formatArgs != nil {
|
||||||
command = fmt.Sprintf(formatString, formatArgs...)
|
command = fmt.Sprintf(formatString, formatArgs...)
|
||||||
}
|
}
|
||||||
c.Log.WithField("command", command).Info("RunCommand")
|
|
||||||
if c.onRunCommand != nil {
|
|
||||||
c.onRunCommand(command)
|
|
||||||
}
|
|
||||||
cmd := c.ExecutableFromString(command)
|
cmd := c.ExecutableFromString(command)
|
||||||
|
c.LogExecCmd(cmd)
|
||||||
output, err := sanitisedCommandOutput(cmd.CombinedOutput())
|
output, err := sanitisedCommandOutput(cmd.CombinedOutput())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Log.WithField("command", command).Error(output)
|
c.Log.WithField("command", command).Error(output)
|
||||||
@ -114,20 +170,9 @@ func (c *OSCommand) RunCommandWithOutput(formatString string, formatArgs ...inte
|
|||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OSCommand) CatFile(filename string) (string, error) {
|
|
||||||
arr := append(c.Platform.CatCmd, filename)
|
|
||||||
cmdStr := strings.Join(arr, " ")
|
|
||||||
c.Log.WithField("command", cmdStr).Info("Cat")
|
|
||||||
cmd := c.Command(arr[0], arr[1:]...)
|
|
||||||
output, err := sanitisedCommandOutput(cmd.CombinedOutput())
|
|
||||||
if err != nil {
|
|
||||||
c.Log.WithField("command", cmdStr).Error(output)
|
|
||||||
}
|
|
||||||
return output, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunExecutableWithOutput runs an executable file and returns its output
|
// RunExecutableWithOutput runs an executable file and returns its output
|
||||||
func (c *OSCommand) RunExecutableWithOutput(cmd *exec.Cmd) (string, error) {
|
func (c *OSCommand) RunExecutableWithOutput(cmd *exec.Cmd) (string, error) {
|
||||||
|
c.LogExecCmd(cmd)
|
||||||
c.BeforeExecuteCmd(cmd)
|
c.BeforeExecuteCmd(cmd)
|
||||||
return sanitisedCommandOutput(cmd.CombinedOutput())
|
return sanitisedCommandOutput(cmd.CombinedOutput())
|
||||||
}
|
}
|
||||||
@ -165,6 +210,18 @@ func (c *OSCommand) RunCommandWithOutputLive(command string, output func(string)
|
|||||||
return RunCommandWithOutputLiveWrapper(c, command, output)
|
return RunCommandWithOutputLiveWrapper(c, command, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *OSCommand) CatFile(filename string) (string, error) {
|
||||||
|
arr := append(c.Platform.CatCmd, filename)
|
||||||
|
cmdStr := strings.Join(arr, " ")
|
||||||
|
c.Log.WithField("command", cmdStr).Info("Cat")
|
||||||
|
cmd := c.Command(arr[0], arr[1:]...)
|
||||||
|
output, err := sanitisedCommandOutput(cmd.CombinedOutput())
|
||||||
|
if err != nil {
|
||||||
|
c.Log.WithField("command", cmdStr).Error(output)
|
||||||
|
}
|
||||||
|
return output, err
|
||||||
|
}
|
||||||
|
|
||||||
// DetectUnamePass detect a username / password / passphrase question in a command
|
// DetectUnamePass detect a username / password / passphrase question in a command
|
||||||
// promptUserForCredential is a function that gets executed when this function detect you need to fillin a password or passphrase
|
// promptUserForCredential is a function that gets executed when this function detect you need to fillin a password or passphrase
|
||||||
// The promptUserForCredential argument will be "username", "password" or "passphrase" and expects the user's password/passphrase or username back
|
// The promptUserForCredential argument will be "username", "password" or "passphrase" and expects the user's password/passphrase or username back
|
||||||
@ -201,9 +258,9 @@ func (c *OSCommand) RunCommand(formatString string, formatArgs ...interface{}) e
|
|||||||
// RunShellCommand runs shell commands i.e. 'sh -c <command>'. Good for when you
|
// RunShellCommand runs shell commands i.e. 'sh -c <command>'. Good for when you
|
||||||
// need access to the shell
|
// need access to the shell
|
||||||
func (c *OSCommand) RunShellCommand(command string) error {
|
func (c *OSCommand) RunShellCommand(command string) error {
|
||||||
c.Log.WithField("command", command).Info("RunShellCommand")
|
|
||||||
|
|
||||||
cmd := c.Command(c.Platform.Shell, c.Platform.ShellArg, command)
|
cmd := c.Command(c.Platform.Shell, c.Platform.ShellArg, command)
|
||||||
|
c.LogExecCmd(cmd)
|
||||||
|
|
||||||
_, err := sanitisedCommandOutput(cmd.CombinedOutput())
|
_, err := sanitisedCommandOutput(cmd.CombinedOutput())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
@ -236,6 +293,7 @@ func sanitisedCommandOutput(output []byte, err error) (string, error) {
|
|||||||
|
|
||||||
// OpenFile opens a file with the given
|
// OpenFile opens a file with the given
|
||||||
func (c *OSCommand) OpenFile(filename string) error {
|
func (c *OSCommand) OpenFile(filename string) error {
|
||||||
|
c.LogCommand(fmt.Sprintf("Opening file '%s'", filename), false)
|
||||||
commandTemplate := c.Config.GetUserConfig().OS.OpenCommand
|
commandTemplate := c.Config.GetUserConfig().OS.OpenCommand
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"filename": c.Quote(filename),
|
"filename": c.Quote(filename),
|
||||||
@ -248,6 +306,7 @@ func (c *OSCommand) OpenFile(filename string) error {
|
|||||||
|
|
||||||
// OpenLink opens a file with the given
|
// OpenLink opens a file with the given
|
||||||
func (c *OSCommand) OpenLink(link string) error {
|
func (c *OSCommand) OpenLink(link string) error {
|
||||||
|
c.LogCommand(fmt.Sprintf("Opening link '%s'", link), false)
|
||||||
commandTemplate := c.Config.GetUserConfig().OS.OpenLinkCommand
|
commandTemplate := c.Config.GetUserConfig().OS.OpenLinkCommand
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"link": c.Quote(link),
|
"link": c.Quote(link),
|
||||||
@ -265,6 +324,7 @@ func (c *OSCommand) PrepareSubProcess(cmdName string, commandArgs ...string) *ex
|
|||||||
if cmd != nil {
|
if cmd != nil {
|
||||||
cmd.Env = append(os.Environ(), "GIT_OPTIONAL_LOCKS=0")
|
cmd.Env = append(os.Environ(), "GIT_OPTIONAL_LOCKS=0")
|
||||||
}
|
}
|
||||||
|
c.LogExecCmd(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,6 +350,7 @@ func (c *OSCommand) Quote(message string) string {
|
|||||||
|
|
||||||
// AppendLineToFile adds a new line in file
|
// AppendLineToFile adds a new line in file
|
||||||
func (c *OSCommand) AppendLineToFile(filename, line string) error {
|
func (c *OSCommand) AppendLineToFile(filename, line string) error {
|
||||||
|
c.LogCommand(fmt.Sprintf("Appending '%s' to file '%s'", line, filename), false)
|
||||||
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return utils.WrapError(err)
|
return utils.WrapError(err)
|
||||||
@ -310,6 +371,7 @@ func (c *OSCommand) CreateTempFile(filename, content string) (string, error) {
|
|||||||
c.Log.Error(err)
|
c.Log.Error(err)
|
||||||
return "", utils.WrapError(err)
|
return "", utils.WrapError(err)
|
||||||
}
|
}
|
||||||
|
c.LogCommand(fmt.Sprintf("Creating temp file '%s'", tmpfile.Name()), false)
|
||||||
|
|
||||||
if _, err := tmpfile.WriteString(content); err != nil {
|
if _, err := tmpfile.WriteString(content); err != nil {
|
||||||
c.Log.Error(err)
|
c.Log.Error(err)
|
||||||
@ -325,6 +387,7 @@ func (c *OSCommand) CreateTempFile(filename, content string) (string, error) {
|
|||||||
|
|
||||||
// CreateFileWithContent creates a file with the given content
|
// CreateFileWithContent creates a file with the given content
|
||||||
func (c *OSCommand) CreateFileWithContent(path string, content string) error {
|
func (c *OSCommand) CreateFileWithContent(path string, content string) error {
|
||||||
|
c.LogCommand(fmt.Sprintf("Creating file '%s'", path), false)
|
||||||
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
||||||
c.Log.Error(err)
|
c.Log.Error(err)
|
||||||
return err
|
return err
|
||||||
@ -340,6 +403,7 @@ func (c *OSCommand) CreateFileWithContent(path string, content string) error {
|
|||||||
|
|
||||||
// Remove removes a file or directory at the specified path
|
// Remove removes a file or directory at the specified path
|
||||||
func (c *OSCommand) Remove(filename string) error {
|
func (c *OSCommand) Remove(filename string) error {
|
||||||
|
c.LogCommand(fmt.Sprintf("Removing '%s'", filename), false)
|
||||||
err := os.RemoveAll(filename)
|
err := os.RemoveAll(filename)
|
||||||
return utils.WrapError(err)
|
return utils.WrapError(err)
|
||||||
}
|
}
|
||||||
@ -360,6 +424,7 @@ func (c *OSCommand) FileExists(path string) (bool, error) {
|
|||||||
// before running it
|
// before running it
|
||||||
func (c *OSCommand) RunPreparedCommand(cmd *exec.Cmd) error {
|
func (c *OSCommand) RunPreparedCommand(cmd *exec.Cmd) error {
|
||||||
c.BeforeExecuteCmd(cmd)
|
c.BeforeExecuteCmd(cmd)
|
||||||
|
c.LogExecCmd(cmd)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
outString := string(out)
|
outString := string(out)
|
||||||
c.Log.Info(outString)
|
c.Log.Info(outString)
|
||||||
@ -383,12 +448,16 @@ func (c *OSCommand) GetLazygitPath() string {
|
|||||||
|
|
||||||
// PipeCommands runs a heap of commands and pipes their inputs/outputs together like A | B | C
|
// PipeCommands runs a heap of commands and pipes their inputs/outputs together like A | B | C
|
||||||
func (c *OSCommand) PipeCommands(commandStrings ...string) error {
|
func (c *OSCommand) PipeCommands(commandStrings ...string) error {
|
||||||
|
|
||||||
cmds := make([]*exec.Cmd, len(commandStrings))
|
cmds := make([]*exec.Cmd, len(commandStrings))
|
||||||
|
logCmdStr := ""
|
||||||
for i, str := range commandStrings {
|
for i, str := range commandStrings {
|
||||||
|
if i > 0 {
|
||||||
|
logCmdStr += " | "
|
||||||
|
}
|
||||||
|
logCmdStr += str
|
||||||
cmds[i] = c.ExecutableFromString(str)
|
cmds[i] = c.ExecutableFromString(str)
|
||||||
}
|
}
|
||||||
|
c.LogCommand(logCmdStr, true)
|
||||||
|
|
||||||
for i := 0; i < len(cmds)-1; i++ {
|
for i := 0; i < len(cmds)-1; i++ {
|
||||||
stdout, err := cmds[i].StdoutPipe()
|
stdout, err := cmds[i].StdoutPipe()
|
||||||
@ -479,5 +548,12 @@ func RunLineOutputCmd(cmd *exec.Cmd, onLine func(line string) (bool, error)) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *OSCommand) CopyToClipboard(str string) error {
|
func (c *OSCommand) CopyToClipboard(str string) error {
|
||||||
|
c.LogCommand(fmt.Sprintf("Copying '%s' to clipboard", utils.TruncateWithEllipsis(str, 40)), false)
|
||||||
return clipboard.WriteAll(str)
|
return clipboard.WriteAll(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *OSCommand) RemoveFile(path string) error {
|
||||||
|
c.LogCommand(fmt.Sprintf("Deleting path '%s'", path), false)
|
||||||
|
|
||||||
|
return c.removeFile(path)
|
||||||
|
}
|
||||||
|
@ -137,7 +137,7 @@ func (c *GitCommand) MovePatchToSelectedCommit(commits []*models.Commit, sourceC
|
|||||||
return c.GenericMergeOrRebaseAction("rebase", "continue")
|
return c.GenericMergeOrRebaseAction("rebase", "continue")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GitCommand) PullPatchIntoIndex(commits []*models.Commit, commitIdx int, p *patch.PatchManager, stash bool) error {
|
func (c *GitCommand) MovePatchIntoIndex(commits []*models.Commit, commitIdx int, p *patch.PatchManager, stash bool) error {
|
||||||
if stash {
|
if stash {
|
||||||
if err := c.StashSave(c.Tr.StashPrefix + commits[commitIdx].Sha); err != nil {
|
if err := c.StashSave(c.Tr.StashPrefix + commits[commitIdx].Sha); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -21,7 +21,7 @@ func (c *GitCommand) ShowStashEntryCmdStr(index int) string {
|
|||||||
// StashSaveStagedChanges stashes only the currently staged changes. This takes a few steps
|
// StashSaveStagedChanges stashes only the currently staged changes. This takes a few steps
|
||||||
// shoutouts to Joe on https://stackoverflow.com/questions/14759748/stashing-only-staged-changes-in-git-is-it-possible
|
// shoutouts to Joe on https://stackoverflow.com/questions/14759748/stashing-only-staged-changes-in-git-is-it-possible
|
||||||
func (c *GitCommand) StashSaveStagedChanges(message string) error {
|
func (c *GitCommand) StashSaveStagedChanges(message string) error {
|
||||||
|
// wrap in 'writing', which uses a mutex
|
||||||
if err := c.RunCommand("git stash --keep-index"); err != nil {
|
if err := c.RunCommand("git stash --keep-index"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ func (gui *Gui) getWindowDimensions(informationStr string, appStatus string) map
|
|||||||
mainPanelsDirection = boxlayout.COLUMN
|
mainPanelsDirection = boxlayout.COLUMN
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdLogSize := 10
|
cmdLogSize := 40 // TODO: make configurable
|
||||||
|
|
||||||
root := &boxlayout.Box{
|
root := &boxlayout.Box{
|
||||||
Direction: boxlayout.ROW,
|
Direction: boxlayout.ROW,
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,7 +20,9 @@ func (gui *Gui) handleCommitConfirm() error {
|
|||||||
flags = "--no-verify"
|
flags = "--no-verify"
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.withGpgHandling(gui.GitCommand.CommitCmdStr(message, flags), gui.Tr.CommittingStatus, func() error {
|
cmdStr := gui.GitCommand.CommitCmdStr(message, flags)
|
||||||
|
gui.OnRunCommand(oscommands.NewCmdLogEntry(cmdStr, "Commit", true))
|
||||||
|
return gui.withGpgHandling(cmdStr, gui.Tr.CommittingStatus, func() error {
|
||||||
_ = gui.returnFromContext()
|
_ = gui.returnFromContext()
|
||||||
gui.clearEditorView(gui.Views.CommitMessage)
|
gui.clearEditorView(gui.Views.CommitMessage)
|
||||||
return nil
|
return nil
|
||||||
|
@ -12,7 +12,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
|
|||||||
{
|
{
|
||||||
displayString: gui.Tr.LcDiscardAllChanges,
|
displayString: gui.Tr.LcDiscardAllChanges,
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
if err := gui.GitCommand.DiscardAllDirChanges(node); err != nil {
|
if err := gui.GitCommand.WithSpan("Discard all changes in directory").DiscardAllDirChanges(node); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
|
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
|
||||||
@ -24,7 +24,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
|
|||||||
menuItems = append(menuItems, &menuItem{
|
menuItems = append(menuItems, &menuItem{
|
||||||
displayString: gui.Tr.LcDiscardUnstagedChanges,
|
displayString: gui.Tr.LcDiscardUnstagedChanges,
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
if err := gui.GitCommand.DiscardUnstagedDirChanges(node); err != nil {
|
if err := gui.GitCommand.WithSpan("Discard unstaged changes in directory").DiscardUnstagedDirChanges(node); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +52,8 @@ func (gui *Gui) handleCreateDiscardMenu() error {
|
|||||||
{
|
{
|
||||||
displayString: gui.Tr.LcDiscardAllChanges,
|
displayString: gui.Tr.LcDiscardAllChanges,
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
if err := gui.GitCommand.DiscardAllFileChanges(file); err != nil {
|
gui.Log.Warn("HA?")
|
||||||
|
if err := gui.GitCommand.WithSpan("Discard all changes in file").DiscardAllFileChanges(file); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
|
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
|
||||||
@ -64,7 +65,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
|
|||||||
menuItems = append(menuItems, &menuItem{
|
menuItems = append(menuItems, &menuItem{
|
||||||
displayString: gui.Tr.LcDiscardUnstagedChanges,
|
displayString: gui.Tr.LcDiscardUnstagedChanges,
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
if err := gui.GitCommand.DiscardUnstagedFileChanges(file); err != nil {
|
if err := gui.GitCommand.WithSpan("Discard all unstaged changes in file").DiscardUnstagedFileChanges(file); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
@ -218,11 +219,11 @@ func (gui *Gui) handleFilePress() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if file.HasUnstagedChanges {
|
if file.HasUnstagedChanges {
|
||||||
if err := gui.GitCommand.StageFile(file.Name); err != nil {
|
if err := gui.GitCommand.WithSpan("Stage file").StageFile(file.Name); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := gui.GitCommand.UnStageFile(file.Names(), file.Tracked); err != nil {
|
if err := gui.GitCommand.WithSpan("Unstage file").UnStageFile(file.Names(), file.Tracked); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,12 +235,12 @@ func (gui *Gui) handleFilePress() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.GetHasUnstagedChanges() {
|
if node.GetHasUnstagedChanges() {
|
||||||
if err := gui.GitCommand.StageFile(node.Path); err != nil {
|
if err := gui.GitCommand.WithSpan("Stage file").StageFile(node.Path); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// pretty sure it doesn't matter that we're always passing true here
|
// pretty sure it doesn't matter that we're always passing true here
|
||||||
if err := gui.GitCommand.UnStageFile([]string{node.Path}, true); err != nil {
|
if err := gui.GitCommand.WithSpan("Unstage file").UnStageFile([]string{node.Path}, true); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,9 +269,9 @@ func (gui *Gui) focusAndSelectFile() error {
|
|||||||
func (gui *Gui) handleStageAll() error {
|
func (gui *Gui) handleStageAll() error {
|
||||||
var err error
|
var err error
|
||||||
if gui.allFilesStaged() {
|
if gui.allFilesStaged() {
|
||||||
err = gui.GitCommand.UnstageAll()
|
err = gui.GitCommand.WithSpan("Unstage all files").UnstageAll()
|
||||||
} else {
|
} else {
|
||||||
err = gui.GitCommand.StageAll()
|
err = gui.GitCommand.WithSpan("Stage all files").StageAll()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = gui.surfaceError(err)
|
_ = gui.surfaceError(err)
|
||||||
@ -293,10 +294,12 @@ func (gui *Gui) handleIgnoreFile() error {
|
|||||||
return gui.createErrorPanel("Cannot ignore .gitignore")
|
return gui.createErrorPanel("Cannot ignore .gitignore")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gitCommand := gui.GitCommand.WithSpan("Ignore file")
|
||||||
|
|
||||||
unstageFiles := func() error {
|
unstageFiles := func() error {
|
||||||
return node.ForEachFile(func(file *models.File) error {
|
return node.ForEachFile(func(file *models.File) error {
|
||||||
if file.HasStagedChanges {
|
if file.HasStagedChanges {
|
||||||
if err := gui.GitCommand.UnStageFile(file.Names(), file.Tracked); err != nil {
|
if err := gitCommand.UnStageFile(file.Names(), file.Tracked); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,11 +318,11 @@ func (gui *Gui) handleIgnoreFile() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.GitCommand.RemoveTrackedFiles(node.GetPath()); err != nil {
|
if err := gitCommand.RemoveTrackedFiles(node.GetPath()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.GitCommand.Ignore(node.GetPath()); err != nil {
|
if err := gitCommand.Ignore(node.GetPath()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}})
|
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}})
|
||||||
@ -331,7 +334,7 @@ func (gui *Gui) handleIgnoreFile() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.GitCommand.Ignore(node.GetPath()); err != nil {
|
if err := gitCommand.Ignore(node.GetPath()); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,7 +367,7 @@ func (gui *Gui) commitPrefixConfigForRepo() *config.CommitPrefixConfig {
|
|||||||
func (gui *Gui) prepareFilesForCommit() error {
|
func (gui *Gui) prepareFilesForCommit() error {
|
||||||
noStagedFiles := len(gui.stagedFiles()) == 0
|
noStagedFiles := len(gui.stagedFiles()) == 0
|
||||||
if noStagedFiles && gui.Config.GetUserConfig().Gui.SkipNoStagedFilesWarning {
|
if noStagedFiles && gui.Config.GetUserConfig().Gui.SkipNoStagedFilesWarning {
|
||||||
err := gui.GitCommand.StageAll()
|
err := gui.GitCommand.WithSpan("Stage all files").StageAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -419,7 +422,7 @@ func (gui *Gui) promptToStageAllAndRetry(retry func() error) error {
|
|||||||
title: gui.Tr.NoFilesStagedTitle,
|
title: gui.Tr.NoFilesStagedTitle,
|
||||||
prompt: gui.Tr.NoFilesStagedPrompt,
|
prompt: gui.Tr.NoFilesStagedPrompt,
|
||||||
handleConfirm: func() error {
|
handleConfirm: func() error {
|
||||||
if err := gui.GitCommand.StageAll(); err != nil {
|
if err := gui.GitCommand.WithSpan("Stage all files").StageAll(); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
if err := gui.refreshFilesAndSubmodules(); err != nil {
|
if err := gui.refreshFilesAndSubmodules(); err != nil {
|
||||||
@ -448,7 +451,9 @@ func (gui *Gui) handleAmendCommitPress() error {
|
|||||||
title: strings.Title(gui.Tr.AmendLastCommit),
|
title: strings.Title(gui.Tr.AmendLastCommit),
|
||||||
prompt: gui.Tr.SureToAmend,
|
prompt: gui.Tr.SureToAmend,
|
||||||
handleConfirm: func() error {
|
handleConfirm: func() error {
|
||||||
return gui.withGpgHandling(gui.GitCommand.AmendHeadCmdStr(), gui.Tr.AmendingStatus, nil)
|
cmdStr := gui.GitCommand.AmendHeadCmdStr()
|
||||||
|
gui.OnRunCommand(oscommands.NewCmdLogEntry(cmdStr, "Amend commit", true))
|
||||||
|
return gui.withGpgHandling(cmdStr, gui.Tr.AmendingStatus, nil)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -465,7 +470,7 @@ func (gui *Gui) handleCommitEditorPress() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
return gui.runSubprocessWithSuspenseAndRefresh(
|
||||||
gui.OSCommand.PrepareSubProcess("git", "commit"),
|
gui.OSCommand.WithSpan("Commit").PrepareSubProcess("git", "commit"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +481,7 @@ func (gui *Gui) editFile(filename string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
return gui.runSubprocessWithSuspenseAndRefresh(
|
||||||
gui.OSCommand.PrepareShellSubProcess(cmdStr),
|
gui.OSCommand.WithSpan("Edit file").PrepareShellSubProcess(cmdStr),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,6 +659,7 @@ func (gui *Gui) pullFiles(opts PullFilesOptions) error {
|
|||||||
|
|
||||||
mode := gui.Config.GetUserConfig().Git.Pull.Mode
|
mode := gui.Config.GetUserConfig().Git.Pull.Mode
|
||||||
|
|
||||||
|
// TODO: this doesn't look like a good idea. Why the goroutine?
|
||||||
go utils.Safe(func() { _ = gui.pullWithMode(mode, opts) })
|
go utils.Safe(func() { _ = gui.pullWithMode(mode, opts) })
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -663,7 +669,9 @@ func (gui *Gui) pullWithMode(mode string, opts PullFilesOptions) error {
|
|||||||
gui.Mutexes.FetchMutex.Lock()
|
gui.Mutexes.FetchMutex.Lock()
|
||||||
defer gui.Mutexes.FetchMutex.Unlock()
|
defer gui.Mutexes.FetchMutex.Unlock()
|
||||||
|
|
||||||
err := gui.GitCommand.Fetch(
|
gitCommand := gui.GitCommand.WithSpan("Pull")
|
||||||
|
|
||||||
|
err := gitCommand.Fetch(
|
||||||
commands.FetchOptions{
|
commands.FetchOptions{
|
||||||
PromptUserForCredential: gui.promptUserForCredential,
|
PromptUserForCredential: gui.promptUserForCredential,
|
||||||
RemoteName: opts.RemoteName,
|
RemoteName: opts.RemoteName,
|
||||||
@ -677,13 +685,13 @@ func (gui *Gui) pullWithMode(mode string, opts PullFilesOptions) error {
|
|||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case "rebase":
|
case "rebase":
|
||||||
err := gui.GitCommand.RebaseBranch("FETCH_HEAD")
|
err := gitCommand.RebaseBranch("FETCH_HEAD")
|
||||||
return gui.handleGenericMergeCommandResult(err)
|
return gui.handleGenericMergeCommandResult(err)
|
||||||
case "merge":
|
case "merge":
|
||||||
err := gui.GitCommand.Merge("FETCH_HEAD", commands.MergeOpts{})
|
err := gitCommand.Merge("FETCH_HEAD", commands.MergeOpts{})
|
||||||
return gui.handleGenericMergeCommandResult(err)
|
return gui.handleGenericMergeCommandResult(err)
|
||||||
case "ff-only":
|
case "ff-only":
|
||||||
err := gui.GitCommand.Merge("FETCH_HEAD", commands.MergeOpts{FastForwardOnly: true})
|
err := gitCommand.Merge("FETCH_HEAD", commands.MergeOpts{FastForwardOnly: true})
|
||||||
return gui.handleGenericMergeCommandResult(err)
|
return gui.handleGenericMergeCommandResult(err)
|
||||||
default:
|
default:
|
||||||
return gui.createErrorPanel(fmt.Sprintf("git pull mode '%s' unrecognised", mode))
|
return gui.createErrorPanel(fmt.Sprintf("git pull mode '%s' unrecognised", mode))
|
||||||
@ -696,7 +704,7 @@ func (gui *Gui) pushWithForceFlag(force bool, upstream string, args string) erro
|
|||||||
}
|
}
|
||||||
go utils.Safe(func() {
|
go utils.Safe(func() {
|
||||||
branchName := gui.getCheckedOutBranch().Name
|
branchName := gui.getCheckedOutBranch().Name
|
||||||
err := gui.GitCommand.Push(branchName, force, upstream, args, gui.promptUserForCredential)
|
err := gui.GitCommand.WithSpan("Push").Push(branchName, force, upstream, args, gui.promptUserForCredential)
|
||||||
if err != nil && !force && strings.Contains(err.Error(), "Updates were rejected") {
|
if err != nil && !force && strings.Contains(err.Error(), "Updates were rejected") {
|
||||||
forcePushDisabled := gui.Config.GetUserConfig().Git.DisableForcePushing
|
forcePushDisabled := gui.Config.GetUserConfig().Git.DisableForcePushing
|
||||||
if forcePushDisabled {
|
if forcePushDisabled {
|
||||||
@ -785,7 +793,7 @@ func (gui *Gui) handleSwitchToMerge() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) openFile(filename string) error {
|
func (gui *Gui) openFile(filename string) error {
|
||||||
if err := gui.OSCommand.OpenFile(filename); err != nil {
|
if err := gui.OSCommand.WithSpan("Open file").OpenFile(filename); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -804,6 +812,7 @@ func (gui *Gui) handleCustomCommand() error {
|
|||||||
return gui.prompt(promptOpts{
|
return gui.prompt(promptOpts{
|
||||||
title: gui.Tr.CustomCommand,
|
title: gui.Tr.CustomCommand,
|
||||||
handleConfirm: func(command string) error {
|
handleConfirm: func(command string) error {
|
||||||
|
gui.OnRunCommand(oscommands.NewCmdLogEntry(command, "Custom command", true))
|
||||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
return gui.runSubprocessWithSuspenseAndRefresh(
|
||||||
gui.OSCommand.PrepareShellSubProcess(command),
|
gui.OSCommand.PrepareShellSubProcess(command),
|
||||||
)
|
)
|
||||||
@ -816,13 +825,13 @@ func (gui *Gui) handleCreateStashMenu() error {
|
|||||||
{
|
{
|
||||||
displayString: gui.Tr.LcStashAllChanges,
|
displayString: gui.Tr.LcStashAllChanges,
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
return gui.handleStashSave(gui.GitCommand.StashSave)
|
return gui.handleStashSave(gui.GitCommand.WithSpan("Stash all changes").StashSave)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayString: gui.Tr.LcStashStagedChanges,
|
displayString: gui.Tr.LcStashStagedChanges,
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
return gui.handleStashSave(gui.GitCommand.StashSaveStagedChanges)
|
return gui.handleStashSave(gui.GitCommand.WithSpan("Stash staged changes").StashSaveStagedChanges)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func (gui *Gui) handleCreateGitFlowMenu() error {
|
|||||||
title: title,
|
title: title,
|
||||||
handleConfirm: func(name string) error {
|
handleConfirm: func(name string) error {
|
||||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
return gui.runSubprocessWithSuspenseAndRefresh(
|
||||||
gui.OSCommand.PrepareSubProcess("git", "flow", branchType, "start", name),
|
gui.OSCommand.WithSpan("Git Flow").PrepareSubProcess("git", "flow", branchType, "start", name),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -111,7 +111,8 @@ type Gui struct {
|
|||||||
PauseBackgroundThreads bool
|
PauseBackgroundThreads bool
|
||||||
|
|
||||||
// Log of the commands that get run, to be displayed to the user.
|
// Log of the commands that get run, to be displayed to the user.
|
||||||
CmdLog []string
|
CmdLog []string
|
||||||
|
OnRunCommand func(entry oscommands.CmdLogEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
type listPanelState struct {
|
type listPanelState struct {
|
||||||
@ -470,15 +471,30 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *oscom
|
|||||||
|
|
||||||
gui.watchFilesForChanges()
|
gui.watchFilesForChanges()
|
||||||
|
|
||||||
oSCommand.SetOnRunCommand(func(cmdStr string) {
|
onRunCommand := func() func(entry oscommands.CmdLogEntry) {
|
||||||
gui.Log.Warn("HHMM")
|
currentSpan := ""
|
||||||
gui.CmdLog = append(gui.CmdLog, cmdStr)
|
|
||||||
if gui.Views.CmdLog != nil {
|
return func(entry oscommands.CmdLogEntry) {
|
||||||
fmt.Fprintln(gui.Views.CmdLog, cmdStr)
|
if gui.Views.CmdLog == nil {
|
||||||
gui.Log.Warn("HHMM")
|
return
|
||||||
gui.Log.Warn(cmdStr)
|
}
|
||||||
|
|
||||||
|
if entry.GetSpan() != currentSpan {
|
||||||
|
fmt.Fprintln(gui.Views.CmdLog, utils.ColoredString(entry.GetSpan(), color.FgYellow))
|
||||||
|
currentSpan = entry.GetSpan()
|
||||||
|
}
|
||||||
|
|
||||||
|
clrAttr := theme.DefaultTextColor
|
||||||
|
if !entry.GetCommandLine() {
|
||||||
|
clrAttr = color.FgMagenta
|
||||||
|
}
|
||||||
|
gui.CmdLog = append(gui.CmdLog, entry.GetCmdStr())
|
||||||
|
fmt.Fprintln(gui.Views.CmdLog, " "+utils.ColoredString(entry.GetCmdStr(), clrAttr))
|
||||||
}
|
}
|
||||||
})
|
}()
|
||||||
|
|
||||||
|
oSCommand.SetOnRunCommand(onRunCommand)
|
||||||
|
gui.OnRunCommand = onRunCommand
|
||||||
|
|
||||||
return gui, nil
|
return gui, nil
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,11 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error {
|
|||||||
onPress: gui.handleDeletePatchFromCommit,
|
onPress: gui.handleDeletePatchFromCommit,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayString: "pull patch out into index",
|
displayString: "move patch out into index",
|
||||||
onPress: gui.handlePullPatchIntoWorkingTree,
|
onPress: gui.handleMovePatchIntoWorkingTree,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayString: "pull patch into new commit",
|
displayString: "move patch into new commit",
|
||||||
onPress: gui.handlePullPatchIntoNewCommit,
|
onPress: gui.handlePullPatchIntoNewCommit,
|
||||||
},
|
},
|
||||||
}...)
|
}...)
|
||||||
@ -98,7 +98,7 @@ func (gui *Gui) handleDeletePatchFromCommit() error {
|
|||||||
|
|
||||||
return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error {
|
||||||
commitIndex := gui.getPatchCommitIndex()
|
commitIndex := gui.getPatchCommitIndex()
|
||||||
err := gui.GitCommand.DeletePatchesFromCommit(gui.State.Commits, commitIndex, gui.GitCommand.PatchManager)
|
err := gui.GitCommand.WithSpan("Remove patch from commit").DeletePatchesFromCommit(gui.State.Commits, commitIndex, gui.GitCommand.PatchManager)
|
||||||
return gui.handleGenericMergeCommandResult(err)
|
return gui.handleGenericMergeCommandResult(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -114,12 +114,12 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error {
|
|||||||
|
|
||||||
return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error {
|
||||||
commitIndex := gui.getPatchCommitIndex()
|
commitIndex := gui.getPatchCommitIndex()
|
||||||
err := gui.GitCommand.MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx, gui.GitCommand.PatchManager)
|
err := gui.GitCommand.WithSpan("Move patch to selected commit").MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx, gui.GitCommand.PatchManager)
|
||||||
return gui.handleGenericMergeCommandResult(err)
|
return gui.handleGenericMergeCommandResult(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handlePullPatchIntoWorkingTree() error {
|
func (gui *Gui) handleMovePatchIntoWorkingTree() error {
|
||||||
if ok, err := gui.validateNormalWorkingTreeState(); !ok {
|
if ok, err := gui.validateNormalWorkingTreeState(); !ok {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ func (gui *Gui) handlePullPatchIntoWorkingTree() error {
|
|||||||
pull := func(stash bool) error {
|
pull := func(stash bool) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error {
|
||||||
commitIndex := gui.getPatchCommitIndex()
|
commitIndex := gui.getPatchCommitIndex()
|
||||||
err := gui.GitCommand.PullPatchIntoIndex(gui.State.Commits, commitIndex, gui.GitCommand.PatchManager, stash)
|
err := gui.GitCommand.WithSpan("Move patch into index").MovePatchIntoIndex(gui.State.Commits, commitIndex, gui.GitCommand.PatchManager, stash)
|
||||||
return gui.handleGenericMergeCommandResult(err)
|
return gui.handleGenericMergeCommandResult(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ func (gui *Gui) handlePullPatchIntoNewCommit() error {
|
|||||||
|
|
||||||
return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error {
|
||||||
commitIndex := gui.getPatchCommitIndex()
|
commitIndex := gui.getPatchCommitIndex()
|
||||||
err := gui.GitCommand.PullPatchIntoNewCommit(gui.State.Commits, commitIndex, gui.GitCommand.PatchManager)
|
err := gui.GitCommand.WithSpan("Move patch into new commit").PullPatchIntoNewCommit(gui.State.Commits, commitIndex, gui.GitCommand.PatchManager)
|
||||||
return gui.handleGenericMergeCommandResult(err)
|
return gui.handleGenericMergeCommandResult(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -170,7 +170,11 @@ func (gui *Gui) handleApplyPatch(reverse bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.GitCommand.PatchManager.ApplyPatches(reverse); err != nil {
|
span := "Apply patch"
|
||||||
|
if reverse {
|
||||||
|
span = "Apply patch in reverse"
|
||||||
|
}
|
||||||
|
if err := gui.GitCommand.WithSpan(span).PatchManager.ApplyPatches(reverse); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
|
return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
|
||||||
|
@ -43,18 +43,20 @@ func (gui *Gui) genericMergeCommand(command string) error {
|
|||||||
return gui.createErrorPanel(gui.Tr.NotMergingOrRebasing)
|
return gui.createErrorPanel(gui.Tr.NotMergingOrRebasing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gitCommand := gui.GitCommand.WithSpan(fmt.Sprintf("Merge: %s", command))
|
||||||
|
|
||||||
commandType := strings.Replace(status, "ing", "e", 1)
|
commandType := strings.Replace(status, "ing", "e", 1)
|
||||||
// we should end up with a command like 'git merge --continue'
|
// we should end up with a command like 'git merge --continue'
|
||||||
|
|
||||||
// it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge
|
// it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge
|
||||||
if status == commands.REBASE_MODE_MERGING && command != "abort" && gui.Config.GetUserConfig().Git.Merging.ManualCommit {
|
if status == commands.REBASE_MODE_MERGING && command != "abort" && gui.Config.GetUserConfig().Git.Merging.ManualCommit {
|
||||||
sub := gui.OSCommand.PrepareSubProcess("git", commandType, fmt.Sprintf("--%s", command))
|
sub := gitCommand.OSCommand.PrepareSubProcess("git", commandType, fmt.Sprintf("--%s", command))
|
||||||
if sub != nil {
|
if sub != nil {
|
||||||
return gui.runSubprocessWithSuspenseAndRefresh(sub)
|
return gui.runSubprocessWithSuspenseAndRefresh(sub)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
result := gui.GitCommand.GenericMergeOrRebaseAction(commandType, command)
|
result := gitCommand.GenericMergeOrRebaseAction(commandType, command)
|
||||||
if err := gui.handleGenericMergeCommandResult(result); err != nil {
|
if err := gui.handleGenericMergeCommandResult(result); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ func (gui *Gui) applySelection(reverse bool, state *lBlPanelState) error {
|
|||||||
if !reverse || state.SecondaryFocused {
|
if !reverse || state.SecondaryFocused {
|
||||||
applyFlags = append(applyFlags, "cached")
|
applyFlags = append(applyFlags, "cached")
|
||||||
}
|
}
|
||||||
err := gui.GitCommand.ApplyPatch(patch, applyFlags...)
|
err := gui.GitCommand.WithSpan("Apply patch").ApplyPatch(patch, applyFlags...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ func (gui *Gui) stashDo(method string) error {
|
|||||||
|
|
||||||
return gui.createErrorPanel(errorMessage)
|
return gui.createErrorPanel(errorMessage)
|
||||||
}
|
}
|
||||||
if err := gui.GitCommand.StashDo(stashEntry.Index, method); err != nil {
|
if err := gui.GitCommand.WithSpan("Stash").StashDo(stashEntry.Index, method); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{STASH, FILES}})
|
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{STASH, FILES}})
|
||||||
|
@ -81,7 +81,7 @@ func (gui *Gui) removeSubmodule(submodule *models.SubmoduleConfig) error {
|
|||||||
title: gui.Tr.RemoveSubmodule,
|
title: gui.Tr.RemoveSubmodule,
|
||||||
prompt: fmt.Sprintf(gui.Tr.RemoveSubmodulePrompt, submodule.Name),
|
prompt: fmt.Sprintf(gui.Tr.RemoveSubmodulePrompt, submodule.Name),
|
||||||
handleConfirm: func() error {
|
handleConfirm: func() error {
|
||||||
if err := gui.GitCommand.SubmoduleDelete(submodule); err != nil {
|
if err := gui.GitCommand.WithSpan("Remove submodule").SubmoduleDelete(submodule); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,17 +107,19 @@ func (gui *Gui) fileForSubmodule(submodule *models.SubmoduleConfig) *models.File
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) resetSubmodule(submodule *models.SubmoduleConfig) error {
|
func (gui *Gui) resetSubmodule(submodule *models.SubmoduleConfig) error {
|
||||||
|
gitCommand := gui.GitCommand.WithSpan("Reset submodule")
|
||||||
|
|
||||||
file := gui.fileForSubmodule(submodule)
|
file := gui.fileForSubmodule(submodule)
|
||||||
if file != nil {
|
if file != nil {
|
||||||
if err := gui.GitCommand.UnStageFile(file.Names(), file.Tracked); err != nil {
|
if err := gitCommand.UnStageFile(file.Names(), file.Tracked); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.GitCommand.SubmoduleStash(submodule); err != nil {
|
if err := gitCommand.SubmoduleStash(submodule); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
if err := gui.GitCommand.SubmoduleReset(submodule); err != nil {
|
if err := gitCommand.SubmoduleReset(submodule); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +142,7 @@ func (gui *Gui) handleAddSubmodule() error {
|
|||||||
initialContent: submoduleName,
|
initialContent: submoduleName,
|
||||||
handleConfirm: func(submodulePath string) error {
|
handleConfirm: func(submodulePath string) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.LcAddingSubmoduleStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.LcAddingSubmoduleStatus, func() error {
|
||||||
err := gui.GitCommand.SubmoduleAdd(submoduleName, submodulePath, submoduleUrl)
|
err := gui.GitCommand.WithSpan("Add submodule").SubmoduleAdd(submoduleName, submodulePath, submoduleUrl)
|
||||||
gui.handleCredentialsPopup(err)
|
gui.handleCredentialsPopup(err)
|
||||||
|
|
||||||
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
|
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
|
||||||
@ -160,7 +162,7 @@ func (gui *Gui) handleEditSubmoduleUrl(submodule *models.SubmoduleConfig) error
|
|||||||
initialContent: submodule.Url,
|
initialContent: submodule.Url,
|
||||||
handleConfirm: func(newUrl string) error {
|
handleConfirm: func(newUrl string) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.LcUpdatingSubmoduleUrlStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.LcUpdatingSubmoduleUrlStatus, func() error {
|
||||||
err := gui.GitCommand.SubmoduleUpdateUrl(submodule.Name, submodule.Path, newUrl)
|
err := gui.GitCommand.WithSpan("Update submodule URL").SubmoduleUpdateUrl(submodule.Name, submodule.Path, newUrl)
|
||||||
gui.handleCredentialsPopup(err)
|
gui.handleCredentialsPopup(err)
|
||||||
|
|
||||||
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
|
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
|
||||||
@ -171,7 +173,7 @@ func (gui *Gui) handleEditSubmoduleUrl(submodule *models.SubmoduleConfig) error
|
|||||||
|
|
||||||
func (gui *Gui) handleSubmoduleInit(submodule *models.SubmoduleConfig) error {
|
func (gui *Gui) handleSubmoduleInit(submodule *models.SubmoduleConfig) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.LcInitializingSubmoduleStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.LcInitializingSubmoduleStatus, func() error {
|
||||||
err := gui.GitCommand.SubmoduleInit(submodule.Path)
|
err := gui.GitCommand.WithSpan("Initialise submodule").SubmoduleInit(submodule.Path)
|
||||||
gui.handleCredentialsPopup(err)
|
gui.handleCredentialsPopup(err)
|
||||||
|
|
||||||
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
|
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
|
||||||
@ -214,7 +216,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
|
|||||||
displayStrings: []string{gui.Tr.LcBulkInitSubmodules, utils.ColoredString(gui.GitCommand.SubmoduleBulkInitCmdStr(), color.FgGreen)},
|
displayStrings: []string{gui.Tr.LcBulkInitSubmodules, utils.ColoredString(gui.GitCommand.SubmoduleBulkInitCmdStr(), color.FgGreen)},
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error {
|
return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error {
|
||||||
if err := gui.OSCommand.RunCommand(gui.GitCommand.SubmoduleBulkInitCmdStr()); err != nil {
|
if err := gui.OSCommand.WithSpan("Bulk initialise submodules").RunCommand(gui.GitCommand.SubmoduleBulkInitCmdStr()); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +228,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
|
|||||||
displayStrings: []string{gui.Tr.LcBulkUpdateSubmodules, utils.ColoredString(gui.GitCommand.SubmoduleBulkUpdateCmdStr(), color.FgYellow)},
|
displayStrings: []string{gui.Tr.LcBulkUpdateSubmodules, utils.ColoredString(gui.GitCommand.SubmoduleBulkUpdateCmdStr(), color.FgYellow)},
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error {
|
return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error {
|
||||||
if err := gui.OSCommand.RunCommand(gui.GitCommand.SubmoduleBulkUpdateCmdStr()); err != nil {
|
if err := gui.OSCommand.WithSpan("Bulk update submodules").RunCommand(gui.GitCommand.SubmoduleBulkUpdateCmdStr()); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +240,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
|
|||||||
displayStrings: []string{gui.Tr.LcSubmoduleStashAndReset, utils.ColoredString(fmt.Sprintf("git stash in each submodule && %s", gui.GitCommand.SubmoduleForceBulkUpdateCmdStr()), color.FgRed)},
|
displayStrings: []string{gui.Tr.LcSubmoduleStashAndReset, utils.ColoredString(fmt.Sprintf("git stash in each submodule && %s", gui.GitCommand.SubmoduleForceBulkUpdateCmdStr()), color.FgRed)},
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error {
|
return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error {
|
||||||
if err := gui.GitCommand.ResetSubmodules(gui.State.Submodules); err != nil {
|
if err := gui.GitCommand.WithSpan("Bulk stash and reset submodules").ResetSubmodules(gui.State.Submodules); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +252,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
|
|||||||
displayStrings: []string{gui.Tr.LcBulkDeinitSubmodules, utils.ColoredString(gui.GitCommand.SubmoduleBulkDeinitCmdStr(), color.FgRed)},
|
displayStrings: []string{gui.Tr.LcBulkDeinitSubmodules, utils.ColoredString(gui.GitCommand.SubmoduleBulkDeinitCmdStr(), color.FgRed)},
|
||||||
onPress: func() error {
|
onPress: func() error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error {
|
return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error {
|
||||||
if err := gui.OSCommand.RunCommand(gui.GitCommand.SubmoduleBulkDeinitCmdStr()); err != nil {
|
if err := gui.OSCommand.WithSpan("Bulk deinitialise submodules").RunCommand(gui.GitCommand.SubmoduleBulkDeinitCmdStr()); err != nil {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +267,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
|
|||||||
|
|
||||||
func (gui *Gui) handleUpdateSubmodule(submodule *models.SubmoduleConfig) error {
|
func (gui *Gui) handleUpdateSubmodule(submodule *models.SubmoduleConfig) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.LcUpdatingSubmoduleStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.LcUpdatingSubmoduleStatus, func() error {
|
||||||
err := gui.GitCommand.SubmoduleUpdate(submodule.Path)
|
err := gui.GitCommand.WithSpan("Update submodule").SubmoduleUpdate(submodule.Path)
|
||||||
gui.handleCredentialsPopup(err)
|
gui.handleCredentialsPopup(err)
|
||||||
|
|
||||||
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
|
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user