-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathgit.go
147 lines (130 loc) · 3.52 KB
/
git.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package cvebaser
import (
"errors"
"fmt"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/object"
)
func (r *Repo) initGitRepo(clone, pull bool) error {
var err error
// Check dir exists
exists, err := DirExists(r.DirPath)
if err != nil {
return fmt.Errorf("error checking dir exists: %v", err)
}
// If new repo flag is set, clone fresh repo from github and return early
if clone {
if exists {
return fmt.Errorf("repo already exists: %s", r.DirPath)
}
_, err = git.PlainClone(r.DirPath, false, &git.CloneOptions{
URL: "https://github.com/cvebase/cvebase.com",
// Progress: os.Stdout,
})
if err != nil {
if err == git.ErrRepositoryAlreadyExists {
return errors.New("git repository already exists")
}
return fmt.Errorf("error cloning cvebase.com git repo: %v", err)
}
return nil
}
if !exists {
return fmt.Errorf("repo does not exist: %s", r.DirPath)
}
// Open git repo at given path
gitRepo, err := git.PlainOpen(r.DirPath)
if err != nil {
return fmt.Errorf("error loading git repo: %v", err)
}
// If pull flag is set, git pull to match remote origin
if pull {
w, err := gitRepo.Worktree()
if err != nil {
return err
}
err = w.Pull(&git.PullOptions{RemoteName: "origin"})
if err != nil && err != git.NoErrAlreadyUpToDate {
return err
}
}
return err
}
func (r *Repo) CheckFilenamesFromCommit(h string) ([]string, error) {
gitRepo, err := git.PlainOpen(r.DirPath)
if err != nil {
return nil, fmt.Errorf("error loading git repo: %v", err)
}
ref, err := gitRepo.Head()
if err != nil {
return nil, err
}
cIter, err := gitRepo.Log(&git.LogOptions{From: ref.Hash()})
if err != nil {
return nil, err
}
var files []string
// loop through each commit
err = cIter.ForEach(func(c *object.Commit) error {
if c.NumParents() == 0 {
return nil
}
// collect files if commit hash matches
if h == c.Hash.String() {
files, err = getFilesModified(c)
if err != nil {
return err
}
// Exit commitIter after matching commit hash
cIter.Close()
}
return nil
})
if err != nil {
return nil, err
}
// Dedupe values
files = UniqStrings(files)
return files, nil
}
// getFilesModified returns a slice of files modified in the given commit.
// Git DiffTree compares the content and mode of the blobs found via two tree objects.
// https://github.com/go-git/go-git/blob/218a744b6995a89f5c322aa58e79138d65392ea6/plumbing/object/difftree.go
func getFilesModified(commit *object.Commit) ([]string, error) {
var files []string
ct, err := commit.Tree() // current commit tree
if err != nil {
return nil, fmt.Errorf("error getting current tree from commit: %v", err)
}
prev, err := commit.Parent(0)
// Exit if first commit and no parent
if prev == nil {
return nil, errors.New("first commit and no parent")
}
if err != nil {
return nil, fmt.Errorf("error getting parent of commit: %v", err)
}
pt, err := prev.Tree() // previous commit tree
if err != nil {
return nil, fmt.Errorf("error getting tree from previous commit: %v", err)
}
changes, err := object.DiffTree(pt, ct)
if err != nil {
return nil, fmt.Errorf("error DiffTree on previous and current commit trees: %v", err)
}
patch, err := changes.Patch()
if err != nil {
return nil, fmt.Errorf("error getting patch changes: %v", err)
}
diffs := patch.FilePatches()
for _, d := range diffs {
_, to := d.Files()
// Skip non-existing file; `to` is nil when file is deleted
if to == nil {
continue
}
file := to.Path()
files = append(files, file)
}
return files, nil
}