-
Notifications
You must be signed in to change notification settings - Fork 25
/
git_patches.go
83 lines (72 loc) · 2.16 KB
/
git_patches.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package vcs
import (
"bytes"
"fmt"
"os/exec"
git "github.com/libgit2/git2go/v33"
)
// ApplyPatchesToIndex patches parsed and applied sequentially and the index is written afterwards.
// If there is an error with any of the patches, the function returns before writing the index.
// Returns a treeID or an error. The treeID can be passed to CommitIndexTree.
func (repo *repository) ApplyPatchesToIndex(patches [][]byte) (*git.Oid, error) {
defer getMeterFunc("ApplyPatchesToIndex")()
opts, err := git.DefaultApplyOptions()
if err != nil {
return nil, err
}
for _, p := range patches {
diff, err := git.DiffFromBuffer(p, repo.r)
if err != nil {
return nil, fmt.Errorf("failed to parse change: %w", err)
}
err = repo.r.ApplyDiff(diff, git.ApplyLocationIndex, opts)
if err != nil {
_ = diff.Free()
return nil, fmt.Errorf("failed to apply change: %w", err)
}
_ = diff.Free()
}
index, err := repo.r.Index()
if err != nil {
return nil, fmt.Errorf("failed to access vcs index: %w", err)
}
defer index.Free()
oid, err := index.WriteTree()
if err != nil {
return nil, fmt.Errorf("write tree failed: %w", err)
}
return oid, nil
}
func (repo *repository) ApplyPatchesToWorkdir(patches [][]byte) error {
defer getMeterFunc("ApplyPatchesToWorkdir")()
for _, patch := range patches {
cmd := exec.Command("git", "apply", "-")
cmd.Dir = repo.path
cmd.Stdin = bytes.NewReader(patch)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("unexpected error: '%s' %w", string(out), err)
}
}
return nil
}
func (r *repository) CanApplyPatch(patch []byte) (bool, error) {
defer getMeterFunc("CanApplyPatch")()
cmd := exec.Command("git", "apply", "--check", "-")
cmd.Dir = r.path
cmd.Stdin = bytes.NewReader(patch)
out, err := cmd.CombinedOutput()
if err != nil {
if bytes.HasPrefix(out, []byte("error: patch failed: ")) {
return false, nil
}
if bytes.HasSuffix(out, []byte(": already exists in working directory\n")) {
return false, nil
}
if bytes.HasSuffix(out, []byte(": No such file or directory\n")) {
return false, nil
}
return false, fmt.Errorf("unexpected error: '%s' %w", string(out), err)
}
return true, nil
}