Skip to content

Commit 61f35cb

Browse files
committed
Refactor interface for ApplyPatch
1 parent a3e34b6 commit 61f35cb

File tree

9 files changed

+157
-136
lines changed

9 files changed

+157
-136
lines changed

pkg/commands/git.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ func NewGitCommandAux(
117117
workingTreeCommands := git_commands.NewWorkingTreeCommands(gitCommon, submoduleCommands, fileLoader)
118118
rebaseCommands := git_commands.NewRebaseCommands(gitCommon, commitCommands, workingTreeCommands)
119119
stashCommands := git_commands.NewStashCommands(gitCommon, fileLoader, workingTreeCommands)
120-
// TODO: have patch builder take workingTreeCommands in its entirety
121-
patchBuilder := patch.NewPatchBuilder(cmn.Log, workingTreeCommands.ApplyPatch,
120+
patchBuilder := patch.NewPatchBuilder(cmn.Log,
122121
func(from string, to string, reverse bool, filename string, plain bool) (string, error) {
123122
// TODO: make patch builder take Gui.IgnoreWhitespaceInDiffView into
124123
// account. For now we just pass false.

pkg/commands/git_commands/patch.go

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package git_commands
22

33
import (
44
"fmt"
5+
"path/filepath"
6+
"time"
57

68
"github.com/fsmiamoto/git-todo-parser/todo"
79
"github.com/go-errors/errors"
810
"github.com/jesseduffield/lazygit/pkg/app/daemon"
911
"github.com/jesseduffield/lazygit/pkg/commands/models"
1012
"github.com/jesseduffield/lazygit/pkg/commands/patch"
1113
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
14+
"github.com/jesseduffield/lazygit/pkg/utils"
1215
)
1316

1417
type PatchCommands struct {
@@ -39,14 +42,61 @@ func NewPatchCommands(
3942
}
4043
}
4144

45+
type ApplyPatchOpts struct {
46+
ThreeWay bool
47+
Cached bool
48+
Index bool
49+
Reverse bool
50+
}
51+
52+
func (self *PatchCommands) ApplyCustomPatch(reverse bool) error {
53+
patch := self.PatchBuilder.PatchToApply(reverse)
54+
55+
return self.ApplyPatch(patch, ApplyPatchOpts{
56+
Index: true,
57+
ThreeWay: true,
58+
Reverse: reverse,
59+
})
60+
}
61+
62+
func (self *PatchCommands) ApplyPatch(patch string, opts ApplyPatchOpts) error {
63+
filepath, err := self.SaveTemporaryPatch(patch)
64+
if err != nil {
65+
return err
66+
}
67+
68+
return self.applyPatchFile(filepath, opts)
69+
}
70+
71+
func (self *PatchCommands) applyPatchFile(filepath string, opts ApplyPatchOpts) error {
72+
cmdStr := NewGitCmd("apply").
73+
ArgIf(opts.ThreeWay, "--3way").
74+
ArgIf(opts.Cached, "--cached").
75+
ArgIf(opts.Index, "--index").
76+
ArgIf(opts.Reverse, "--reverse").
77+
Arg(self.cmd.Quote(filepath)).
78+
ToString()
79+
80+
return self.cmd.New(cmdStr).Run()
81+
}
82+
83+
func (self *PatchCommands) SaveTemporaryPatch(patch string) (string, error) {
84+
filepath := filepath.Join(self.os.GetTempDir(), utils.GetCurrentRepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".patch")
85+
self.Log.Infof("saving temporary patch to %s", filepath)
86+
if err := self.os.CreateFileWithContent(filepath, patch); err != nil {
87+
return "", err
88+
}
89+
return filepath, nil
90+
}
91+
4292
// DeletePatchesFromCommit applies a patch in reverse for a commit
4393
func (self *PatchCommands) DeletePatchesFromCommit(commits []*models.Commit, commitIndex int) error {
4494
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIndex); err != nil {
4595
return err
4696
}
4797

4898
// apply each patch in reverse
49-
if err := self.PatchBuilder.ApplyPatches(true); err != nil {
99+
if err := self.ApplyCustomPatch(true); err != nil {
50100
_ = self.rebase.AbortRebase()
51101
return err
52102
}
@@ -72,7 +122,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
72122
}
73123

74124
// apply each patch forward
75-
if err := self.PatchBuilder.ApplyPatches(false); err != nil {
125+
if err := self.ApplyCustomPatch(false); err != nil {
76126
// Don't abort the rebase here; this might cause conflicts, so give
77127
// the user a chance to resolve them
78128
return err
@@ -121,7 +171,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
121171
}
122172

123173
// apply each patch in reverse
124-
if err := self.PatchBuilder.ApplyPatches(true); err != nil {
174+
if err := self.ApplyCustomPatch(true); err != nil {
125175
_ = self.rebase.AbortRebase()
126176
return err
127177
}
@@ -144,7 +194,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
144194
self.rebase.onSuccessfulContinue = func() error {
145195
// now we should be up to the destination, so let's apply forward these patches to that.
146196
// ideally we would ensure we're on the right commit but I'm not sure if that check is necessary
147-
if err := self.rebase.workingTree.ApplyPatch(patch, "index", "3way"); err != nil {
197+
if err := self.ApplyPatch(patch, ApplyPatchOpts{Index: true, ThreeWay: true}); err != nil {
148198
// Don't abort the rebase here; this might cause conflicts, so give
149199
// the user a chance to resolve them
150200
return err
@@ -177,7 +227,7 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
177227
return err
178228
}
179229

180-
if err := self.PatchBuilder.ApplyPatches(true); err != nil {
230+
if err := self.ApplyCustomPatch(true); err != nil {
181231
if self.status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
182232
_ = self.rebase.AbortRebase()
183233
}
@@ -201,7 +251,7 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
201251

202252
self.rebase.onSuccessfulContinue = func() error {
203253
// add patches to index
204-
if err := self.rebase.workingTree.ApplyPatch(patch, "index", "3way"); err != nil {
254+
if err := self.ApplyPatch(patch, ApplyPatchOpts{Index: true, ThreeWay: true}); err != nil {
205255
if self.status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
206256
_ = self.rebase.AbortRebase()
207257
}
@@ -226,7 +276,7 @@ func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, comm
226276
return err
227277
}
228278

229-
if err := self.PatchBuilder.ApplyPatches(true); err != nil {
279+
if err := self.ApplyCustomPatch(true); err != nil {
230280
_ = self.rebase.AbortRebase()
231281
return err
232282
}
@@ -242,7 +292,7 @@ func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, comm
242292
return err
243293
}
244294

245-
if err := self.rebase.workingTree.ApplyPatch(patch, "index", "3way"); err != nil {
295+
if err := self.ApplyPatch(patch, ApplyPatchOpts{Index: true, ThreeWay: true}); err != nil {
246296
_ = self.rebase.AbortRebase()
247297
return err
248298
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package git_commands
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"regexp"
7+
"testing"
8+
9+
"github.com/go-errors/errors"
10+
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestWorkingTreeApplyPatch(t *testing.T) {
15+
type scenario struct {
16+
testName string
17+
runner *oscommands.FakeCmdObjRunner
18+
test func(error)
19+
}
20+
21+
expectFn := func(regexStr string, errToReturn error) func(cmdObj oscommands.ICmdObj) (string, error) {
22+
return func(cmdObj oscommands.ICmdObj) (string, error) {
23+
re := regexp.MustCompile(regexStr)
24+
cmdStr := cmdObj.ToString()
25+
matches := re.FindStringSubmatch(cmdStr)
26+
assert.Equal(t, 2, len(matches), fmt.Sprintf("unexpected command: %s", cmdStr))
27+
28+
filename := matches[1]
29+
30+
content, err := os.ReadFile(filename)
31+
assert.NoError(t, err)
32+
33+
assert.Equal(t, "test", string(content))
34+
35+
return "", errToReturn
36+
}
37+
}
38+
39+
scenarios := []scenario{
40+
{
41+
testName: "valid case",
42+
runner: oscommands.NewFakeRunner(t).
43+
ExpectFunc(expectFn(`git apply --cached "(.*)"`, nil)),
44+
test: func(err error) {
45+
assert.NoError(t, err)
46+
},
47+
},
48+
{
49+
testName: "command returns error",
50+
runner: oscommands.NewFakeRunner(t).
51+
ExpectFunc(expectFn(`git apply --cached "(.*)"`, errors.New("error"))),
52+
test: func(err error) {
53+
assert.Error(t, err)
54+
},
55+
},
56+
}
57+
58+
for _, s := range scenarios {
59+
s := s
60+
t.Run(s.testName, func(t *testing.T) {
61+
instance := buildPatchCommands(commonDeps{runner: s.runner})
62+
s.test(instance.ApplyPatch("test", ApplyPatchOpts{Cached: true}))
63+
s.runner.CheckForMissingCalls()
64+
})
65+
}
66+
}

pkg/commands/git_commands/working_tree.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@ package git_commands
33
import (
44
"fmt"
55
"os"
6-
"path/filepath"
76
"strings"
8-
"time"
97

108
"github.com/go-errors/errors"
119
"github.com/jesseduffield/generics/slices"
1210
"github.com/jesseduffield/lazygit/pkg/commands/models"
1311
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
14-
"github.com/jesseduffield/lazygit/pkg/utils"
1512
)
1613

1714
type WorkingTreeCommands struct {
@@ -268,33 +265,6 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain
268265
return self.cmd.New(cmdStr).DontLog()
269266
}
270267

271-
func (self *WorkingTreeCommands) ApplyPatch(patch string, flags ...string) error {
272-
filepath, err := self.SaveTemporaryPatch(patch)
273-
if err != nil {
274-
return err
275-
}
276-
277-
return self.ApplyPatchFile(filepath, flags...)
278-
}
279-
280-
func (self *WorkingTreeCommands) ApplyPatchFile(filepath string, flags ...string) error {
281-
flagStr := ""
282-
for _, flag := range flags {
283-
flagStr += " --" + flag
284-
}
285-
286-
return self.cmd.New(fmt.Sprintf("git apply%s %s", flagStr, self.cmd.Quote(filepath))).Run()
287-
}
288-
289-
func (self *WorkingTreeCommands) SaveTemporaryPatch(patch string) (string, error) {
290-
filepath := filepath.Join(self.os.GetTempDir(), utils.GetCurrentRepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".patch")
291-
self.Log.Infof("saving temporary patch to %s", filepath)
292-
if err := self.os.CreateFileWithContent(filepath, patch); err != nil {
293-
return "", err
294-
}
295-
return filepath, nil
296-
}
297-
298268
// ShowFileDiff get the diff of specified from and to. Typically this will be used for a single commit so it'll be 123abc^..123abc
299269
// but when we're in diff mode it could be any 'from' to any 'to'. The reverse flag is also here thanks to diff mode.
300270
func (self *WorkingTreeCommands) ShowFileDiff(from string, to string, reverse bool, fileName string, plain bool,

pkg/commands/git_commands/working_tree_test.go

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package git_commands
22

33
import (
44
"fmt"
5-
"os"
6-
"regexp"
75
"testing"
86

97
"github.com/go-errors/errors"
@@ -430,60 +428,6 @@ func TestWorkingTreeCheckoutFile(t *testing.T) {
430428
}
431429
}
432430

433-
func TestWorkingTreeApplyPatch(t *testing.T) {
434-
type scenario struct {
435-
testName string
436-
runner *oscommands.FakeCmdObjRunner
437-
test func(error)
438-
}
439-
440-
expectFn := func(regexStr string, errToReturn error) func(cmdObj oscommands.ICmdObj) (string, error) {
441-
return func(cmdObj oscommands.ICmdObj) (string, error) {
442-
re := regexp.MustCompile(regexStr)
443-
cmdStr := cmdObj.ToString()
444-
matches := re.FindStringSubmatch(cmdStr)
445-
assert.Equal(t, 2, len(matches), fmt.Sprintf("unexpected command: %s", cmdStr))
446-
447-
filename := matches[1]
448-
449-
content, err := os.ReadFile(filename)
450-
assert.NoError(t, err)
451-
452-
assert.Equal(t, "test", string(content))
453-
454-
return "", errToReturn
455-
}
456-
}
457-
458-
scenarios := []scenario{
459-
{
460-
testName: "valid case",
461-
runner: oscommands.NewFakeRunner(t).
462-
ExpectFunc(expectFn(`git apply --cached "(.*)"`, nil)),
463-
test: func(err error) {
464-
assert.NoError(t, err)
465-
},
466-
},
467-
{
468-
testName: "command returns error",
469-
runner: oscommands.NewFakeRunner(t).
470-
ExpectFunc(expectFn(`git apply --cached "(.*)"`, errors.New("error"))),
471-
test: func(err error) {
472-
assert.Error(t, err)
473-
},
474-
},
475-
}
476-
477-
for _, s := range scenarios {
478-
s := s
479-
t.Run(s.testName, func(t *testing.T) {
480-
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner})
481-
s.test(instance.ApplyPatch("test", "cached"))
482-
s.runner.CheckForMissingCalls()
483-
})
484-
}
485-
}
486-
487431
func TestWorkingTreeDiscardUnstagedFileChanges(t *testing.T) {
488432
type scenario struct {
489433
testName string

0 commit comments

Comments
 (0)