forked from stormcat24/protodep
/
git.go
155 lines (127 loc) · 4.01 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
148
149
150
151
152
153
154
155
package repository
import (
"fmt"
"os"
"path/filepath"
"github.com/mittwald/protodep/dependency"
"github.com/mittwald/protodep/helper"
"github.com/mittwald/protodep/logger"
"github.com/pkg/errors"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
)
type GitRepository interface {
Open() (*OpenedRepository, error)
ProtoRootDir() string
}
type GitHubRepository struct {
protodepDir string
dep dependency.ProtoDepDependency
authProvider helper.AuthProvider
}
type OpenedRepository struct {
Repository *git.Repository
Dep dependency.ProtoDepDependency
Hash string
}
func NewGitRepository(protodepDir string, dep dependency.ProtoDepDependency, authProvider helper.AuthProvider) GitRepository {
return &GitHubRepository{
protodepDir: protodepDir,
dep: dep,
authProvider: authProvider,
}
}
func (r *GitHubRepository) fetchRepository(repopath string) (*git.Repository, error) {
reponame := r.dep.Repository()
var rep *git.Repository
if stat, err := os.Stat(repopath); err == nil && stat.IsDir() {
spinner := logger.InfoWithSpinner("Getting in existing dir %s ", logger.CensorHttpsPassword(reponame))
rep, err = git.PlainOpen(repopath)
if err != nil {
return nil, errors.Wrap(err, "open repository is failed")
}
spinner.Stop()
fetchOpts := &git.FetchOptions{
Auth: r.authProvider.AuthMethod(),
}
if err := rep.Fetch(fetchOpts); err != nil {
if err != git.NoErrAlreadyUpToDate {
return nil, errors.Wrap(err, "fetch repository is failed")
}
}
spinner.Finish()
} else {
spinner := logger.InfoWithSpinner("Getting new Repo %s ", logger.CensorHttpsPassword(reponame))
rep, err = git.PlainClone(repopath, false, &git.CloneOptions{
Auth: r.authProvider.AuthMethod(),
URL: r.authProvider.GetRepositoryURL(reponame),
})
if err != nil {
return nil, errors.Wrap(err, "clone repository is failed")
}
spinner.Finish()
}
return rep, nil
}
func (r *GitHubRepository) getCommitHashFromBranch(rep *git.Repository, branch string, wt *git.Worktree) (*git.Repository, error) {
revision := r.dep.Revision
if revision == "" {
target, err := rep.Storer.Reference(plumbing.ReferenceName(fmt.Sprintf("refs/remotes/origin/%s", branch)))
if err != nil {
return nil, errors.Wrapf(err, "change branch to %s is failed", branch)
}
if err := wt.Checkout(&git.CheckoutOptions{Hash: target.Hash()}); err != nil {
return nil, errors.Wrapf(err, "checkout to %s is failed", revision)
}
head := plumbing.NewHashReference(plumbing.HEAD, target.Hash())
if err := rep.Storer.SetReference(head); err != nil {
return nil, errors.Wrapf(err, "set head to %s is failed", branch)
}
} else {
hash := plumbing.NewHash(revision)
if err := wt.Checkout(&git.CheckoutOptions{Hash: hash}); err != nil {
return nil, errors.Wrapf(err, "checkout to %s is failed", revision)
}
head := plumbing.NewHashReference(plumbing.HEAD, hash)
if err := rep.Storer.SetReference(head); err != nil {
return nil, errors.Wrapf(err, "set head to %s is failed", revision)
}
}
return rep, nil
}
func (r *GitHubRepository) Open() (*OpenedRepository, error) {
branch := "master"
if r.dep.Branch != "" {
branch = r.dep.Branch
}
reponame := r.dep.Repository()
repopath := filepath.Join(r.protodepDir, logger.CensorHttpsPassword(reponame))
rep, err := r.fetchRepository(repopath)
if err != nil {
return nil, err
}
wt, err := rep.Worktree()
if err != nil {
return nil, errors.Wrap(err, "get worktree is failed")
}
rep, err = r.getCommitHashFromBranch(rep, branch, wt)
if err != nil {
return nil, err
}
committer, err := rep.Log(&git.LogOptions{All: true})
if err != nil {
return nil, errors.Wrap(err, "get commit is failed")
}
current, err := committer.Next()
if err != nil {
return nil, errors.Wrap(err, "get commit current is failed")
}
return &OpenedRepository{
Repository: rep,
Dep: r.dep,
Hash: current.Hash.String(),
}, nil
}
func (r *GitHubRepository) ProtoRootDir() string {
return filepath.Join(r.protodepDir, r.dep.Target)
}