github.com/inteleradmedicalsystems/go-codecommit@v0.1.0/pkg/codecommit/git.go (about) 1 package codecommit 2 3 import ( 4 "os" 5 "path/filepath" 6 "strings" 7 "time" 8 9 log "github.com/sirupsen/logrus" 10 "gopkg.in/src-d/go-git.v4" 11 "gopkg.in/src-d/go-git.v4/plumbing" 12 "gopkg.in/src-d/go-git.v4/plumbing/object" 13 "gopkg.in/src-d/go-git.v4/plumbing/transport" 14 ) 15 16 //RepoWrapper wraps basic go-git comands 17 type RepoWrapper struct { 18 } 19 20 //Clone a Git repo, return true if the repo is up to date or was from an empty clone. 21 func (r *RepoWrapper) Clone(cloneURL string, destDir string) (*git.Repository, bool, error) { 22 log.Debugf("Cloning Git repo %s, dest %s", cloneURL, destDir) 23 24 cloneOpts := &git.CloneOptions{ 25 URL: cloneURL, 26 } 27 28 repo, err := git.PlainClone(destDir, false, cloneOpts) 29 if err != nil { 30 switch err { 31 case transport.ErrEmptyRemoteRepository: 32 return repo, true, nil 33 case git.NoErrAlreadyUpToDate: 34 return repo, true, nil 35 default: 36 return nil, false, err 37 } 38 } 39 return repo, false, nil 40 } 41 42 //Pull a Git repo from path 43 func (r *RepoWrapper) Pull(path string) error { 44 repo, err := r.repo(path) 45 if err != nil { 46 return err 47 } 48 return r.PullR(repo) 49 } 50 51 //PullR a Git repo. 52 func (r *RepoWrapper) PullR(repo *git.Repository) error { 53 w, err := repo.Worktree() 54 if err != nil { 55 return err 56 } 57 err = w.Pull(&git.PullOptions{RemoteName: "origin"}) 58 switch err { 59 case transport.ErrEmptyRemoteRepository: 60 log.Warnf("Warning: %s", err) 61 return nil 62 case git.NoErrAlreadyUpToDate: 63 return nil 64 default: 65 return err 66 } 67 } 68 69 //Push a Git repo from path 70 func (r *RepoWrapper) Push(path string) error { 71 repo, err := r.repo(path) 72 if err != nil { 73 return err 74 } 75 return r.PushR(repo) 76 } 77 78 //PushR a Git repo. 79 func (r *RepoWrapper) PushR(repo *git.Repository) error { 80 err := repo.Push(&git.PushOptions{}) 81 switch err { 82 case git.NoErrAlreadyUpToDate: 83 log.Warnf("Warning: %s", err) 84 return nil 85 default: 86 return err 87 } 88 } 89 90 //Commit to a Git repo 91 func (r *RepoWrapper) Commit(w *git.Worktree, name, email, message string, force bool) (*plumbing.Hash, error) { 92 status, err := w.Status() 93 if err != nil { 94 return nil, err 95 } 96 97 if !status.IsClean() || force { 98 log.Info(status.String()) 99 commit, err := w.Commit(message, &git.CommitOptions{ 100 Author: &object.Signature{ 101 Name: name, 102 Email: email, 103 When: time.Now(), 104 }, 105 }) 106 if err != nil { 107 return nil, err 108 } 109 log.Infof("Committed %s", commit) 110 return &commit, nil 111 } 112 log.Infof("no changes to commit") 113 return nil, nil 114 } 115 116 //GetDestPath returns 117 //get the dest from either last element of args or 118 //the basename of the url (with the .git suffix stripped). 119 func (r *RepoWrapper) GetDestPath(path string) string { 120 return strings.Replace(filepath.Base(path), ".git", "", -1) 121 } 122 123 func (r *RepoWrapper) manifestMap(destPrefix string, repo *git.Repository) (map[string]*object.File, error) { 124 m := make(map[string]*object.File) 125 ref, err := repo.Head() 126 if err != nil { 127 if err != plumbing.ErrReferenceNotFound { 128 return m, err 129 } 130 } else { 131 c, err := repo.CommitObject(ref.Hash()) 132 if err != nil { 133 return m, err 134 } 135 fIter, err := c.Files() 136 if err != nil { 137 return m, err 138 } 139 err = fIter.ForEach(func(f *object.File) error { 140 log.Debugf("repoFile:%s", f.Name) 141 if strings.HasPrefix(f.Name, destPrefix) { 142 m[f.Name] = f 143 } 144 return nil 145 }) 146 if err != nil { 147 return m, err 148 } 149 } 150 return m, nil 151 } 152 153 func (r *RepoWrapper) addRemove(destPrefix string, boundary string, repo *git.Repository, fm map[string]os.FileInfo) (*git.Worktree, error) { 154 w, err := repo.Worktree() 155 if err != nil { 156 return nil, err 157 } 158 159 mm, err := r.manifestMap(destPrefix, repo) 160 if err != nil { 161 return nil, err 162 } 163 log.Debugf("%v", mm) 164 165 for fn := range mm { 166 target := fn[len(destPrefix)+1:] 167 _, ok := fm[target] 168 log.Debugf("Target %v, fn %v, destPrefix %v, boundary %v", target, fn, destPrefix, boundary) 169 if !ok && strings.HasPrefix(target, boundary) { 170 log.Infof("Removing %v", fn) 171 w.Remove(fn) 172 } 173 } 174 175 for fn, f := range fm { 176 if f.Mode().IsRegular() { 177 target := filepath.Join(destPrefix, fn) 178 _, ok := mm[target] 179 if !ok { 180 // Only log file addition for files that are not in the Git cache. 181 log.Infof("Adding %v", target) 182 } 183 // Always call Add() 184 w.Add(target) 185 } 186 } 187 return w, nil 188 } 189 190 func (r *RepoWrapper) repo(path string) (*git.Repository, error) { 191 return git.PlainOpen(path) 192 }