summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Crute <mike@crute.us>2018-03-27 03:59:24 +0000
committerMike Crute <mike@crute.us>2018-03-27 03:59:24 +0000
commit6d9f2cb2dd4bdd9b7c8e3806a5082240e7e87673 (patch)
treed41182b6245c4ef7356a533382d8cf694ae0edb3
downloadgithub_mirror-6d9f2cb2dd4bdd9b7c8e3806a5082240e7e87673.tar.bz2
github_mirror-6d9f2cb2dd4bdd9b7c8e3806a5082240e7e87673.tar.xz
github_mirror-6d9f2cb2dd4bdd9b7c8e3806a5082240e7e87673.zip
Initial import
-rw-r--r--main.go190
1 files changed, 190 insertions, 0 deletions
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..5c962d3
--- /dev/null
+++ b/main.go
@@ -0,0 +1,190 @@
1package main
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "github.com/google/go-github/github"
8 "golang.org/x/crypto/ssh"
9 "golang.org/x/oauth2"
10 "io/ioutil"
11 "log"
12 "strings"
13)
14
15const (
16 ACCESS_TOKEN = ""
17 KEY_PASSWORD = ""
18 KEY_PATH = ""
19 SSH_USERNAME = ""
20 SSH_HOST = ""
21 REPO_PREFIX = "mcrute/github-mirror/"
22 GITHUB_USERNAME = "mcrute"
23)
24
25func GetGitoliteRepos(c *ssh.Client, prefix string) (map[string]string, error) {
26 repos := make(map[string]string)
27
28 session, err := c.NewSession()
29 if err != nil {
30 return nil, err
31 }
32 defer session.Close()
33
34 output, err := session.Output(fmt.Sprintf("info -json %s", prefix))
35 if err != nil {
36 return nil, err
37 }
38
39 var d map[string]interface{}
40 if err = json.Unmarshal(output, &d); err != nil {
41 return nil, err
42 }
43
44 for k, _ := range d["repos"].(map[string]interface{}) {
45 name := strings.TrimPrefix(k, REPO_PREFIX)
46 if name == ".*" {
47 continue
48 }
49 repos[name] = k
50 }
51
52 return repos, nil
53}
54
55func SyncGitoliteRepo(c *ssh.Client, name string) error {
56 session, err := c.NewSession()
57 if err != nil {
58 return err
59 }
60 defer session.Close()
61
62 if err = session.Run(fmt.Sprintf("sync-mirror %s", name)); err != nil {
63 return err
64 }
65
66 return nil
67}
68
69func CreateGitoliteMirror(c *ssh.Client, name, remote string) error {
70 session, err := c.NewSession()
71 if err != nil {
72 return err
73 }
74 defer session.Close()
75
76 if err = session.Run(fmt.Sprintf("create-mirror %s %s", remote, name)); err != nil {
77 return err
78 }
79
80 return nil
81}
82
83func SSHConnect(key, password, username, host string) (*ssh.Client, error) {
84 pem_bytes, err := ioutil.ReadFile(key)
85 if err != nil {
86 return nil, err
87 }
88
89 signer, err := ssh.ParsePrivateKeyWithPassphrase(pem_bytes, []byte(password))
90 if err != nil {
91 return nil, err
92 }
93
94 client_config := &ssh.ClientConfig{
95 User: username,
96 Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
97 HostKeyCallback: ssh.InsecureIgnoreHostKey(),
98 }
99
100 ssh_client, err := ssh.Dial("tcp", host, client_config)
101 if err != nil {
102 return nil, err
103 }
104
105 return ssh_client, nil
106}
107
108func NewGithubClient(token string) *github.Client {
109 ctx := context.Background()
110 ts := oauth2.StaticTokenSource(
111 &oauth2.Token{AccessToken: token},
112 )
113 tc := oauth2.NewClient(ctx, ts)
114 return github.NewClient(tc)
115}
116
117type GitHubRepo struct {
118 Name string
119 FullName string
120 IsFork bool
121 CloneURL string
122}
123
124func ListGithubRepos(c *github.Client, username string) ([]GitHubRepo, error) {
125 ctx := context.Background()
126 gh_repos := make([]GitHubRepo, 0)
127 opts := &github.RepositoryListOptions{}
128
129 for {
130 repos, resp, err := c.Repositories.List(ctx, username, opts)
131 if err != nil {
132 return nil, err
133 }
134
135 for _, r := range repos {
136 gh_repos = append(gh_repos, GitHubRepo{
137 Name: strings.TrimPrefix(*r.FullName, fmt.Sprintf("%s/", username)),
138 FullName: *r.FullName,
139 IsFork: *r.Fork,
140 CloneURL: *r.CloneURL,
141 })
142 }
143
144 if resp.NextPage == 0 {
145 break
146 }
147
148 opts.Page = resp.NextPage
149 }
150
151 return gh_repos, nil
152}
153
154func main() {
155 gh_client := NewGithubClient(ACCESS_TOKEN)
156
157 ssh_client, err := SSHConnect(KEY_PATH, KEY_PASSWORD, SSH_USERNAME, SSH_HOST)
158 if err != nil {
159 log.Fatal(err)
160 }
161
162 server_repos, err := GetGitoliteRepos(ssh_client, REPO_PREFIX)
163 if err != nil {
164 log.Fatal(err)
165 }
166
167 gh_repos, err := ListGithubRepos(gh_client, GITHUB_USERNAME)
168 if err != nil {
169 log.Fatal(err)
170 }
171
172 for _, r := range gh_repos {
173 gitolite_name, have := server_repos[r.Name]
174 if have {
175 err = SyncGitoliteRepo(ssh_client, gitolite_name)
176 if err != nil {
177 log.Fatal("Failed to sync: %s", r.Name)
178 } else {
179 log.Printf("Synced: %s", r.Name)
180 }
181 } else if !have && !r.IsFork {
182 err = CreateGitoliteMirror(ssh_client, fmt.Sprintf("%s%s", REPO_PREFIX, r.Name), r.CloneURL)
183 if err != nil {
184 log.Fatal("Failed to mirror: %s", r.Name)
185 } else {
186 log.Printf("Mirrored: %s", r.Name)
187 }
188 }
189 }
190}