/
mirrored_repositories.go
118 lines (96 loc) · 3.67 KB
/
mirrored_repositories.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
package git
import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
)
// DefaultMaster is a default name for master branch.
const DefaultMaster = "master"
// ErrorNotMirrored is an error returned by Get if given repository does not exist.
var ErrorNotMirrored = errors.New("mirror not found")
// MirroredRepositories is a type that is intended for maintaining local Git repository mirrors
// located under the mirrorPath directory.
type MirroredRepositories struct {
cmd Command
mirrorPath string
}
// NewMirroredRepositories creates and initializes an instance of MirroredRepositories reading and creating
// repositories under path directory.
func NewMirroredRepositories(path string, gitCommand Command) *MirroredRepositories {
return &MirroredRepositories{
cmd: gitCommand,
mirrorPath: path,
}
}
// All recursively searches and returns a list of repositories under mirrorPath. Unlike Get, All returns
// only basic information about Git repository, such as its name and the name of master branch.
func (service *MirroredRepositories) All() ([]*Repository, error) {
return service.findGitRepos("")
}
// Get searches for a git repository in <mirrorPath>/<fullName> and returns the name of its name, master branch
// and lastest commit. If specified directory does not exist or not a git repository ErrorNotMirrored is returned.
func (service *MirroredRepositories) Get(fullName string) (*Repository, error) {
if !service.cmd.IsRepository(service.resolveMirrorPath(fullName)) {
return nil, ErrorNotMirrored
}
repo := service.repositoryFromDir(fullName)
repo.LatestMasterCommit = service.commitFromDir(fullName)
return repo, nil
}
// Create creates a local mirror of remote repository from gitURL by calling "git --mirror <gitURL> <fullName>".
func (service *MirroredRepositories) Create(fullName, gitURL string) error {
fullPath := service.resolveMirrorPath(fullName)
if _, err := os.Stat(fullPath); err == nil {
log.Printf("[WARN] %s already exists, removing", fullPath)
if err := os.RemoveAll(fullPath); err != nil {
return fmt.Errorf("failed to remove an existing file/directory %s: %s", fullPath, err)
}
}
return service.cmd.CloneMirror(gitURL, fullPath)
}
// Update downloads latest changes from remote repository into a local mirror discarding any changes that were pushed
// to mirror only. Update calls "git remote update" in <mirrorPath>/<fullName>.
func (service *MirroredRepositories) Update(fullName string) error {
return service.cmd.UpdateRemote(service.resolveMirrorPath(fullName))
}
func (service *MirroredRepositories) findGitRepos(path string) ([]*Repository, error) {
if service.cmd.IsRepository(service.resolveMirrorPath(path)) {
return []*Repository{service.repositoryFromDir(path)}, nil
}
entries, err := ioutil.ReadDir(filepath.Join(service.mirrorPath, path))
if err != nil {
return nil, err
}
var repos []*Repository
for _, entry := range entries {
if !entry.IsDir() {
continue
}
r, err := service.findGitRepos(filepath.Join(path, entry.Name()))
if err != nil {
return nil, err
}
repos = append(repos, r...)
}
return repos, nil
}
func (service *MirroredRepositories) repositoryFromDir(path string) *Repository {
return &Repository{
FullName: path,
Master: service.cmd.CurrentBranch(service.resolveMirrorPath(path)),
LatestMasterCommit: service.commitFromDir(path),
}
}
func (service *MirroredRepositories) commitFromDir(path string) *Commit {
commit, err := service.cmd.LastCommit(service.resolveMirrorPath(path))
if err != nil {
return nil
}
return &commit
}
func (service *MirroredRepositories) resolveMirrorPath(path string) string {
return filepath.Join(service.mirrorPath, path)
}