diff options
author | Martin Polden <mpolden@mpolden.no> | 2021-02-18 20:59:50 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2021-02-18 21:06:29 +0100 |
commit | 2ca5d50afea2ea87efd6260c7c9942dc0004860d (patch) | |
tree | 3f06278bd25731808739f8e74812471826561437 | |
parent | b185c4c04ab8174a4165812985f1000f92f375a1 (diff) |
all: Remove go-github dependency
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | git.go | 69 | ||||
-rw-r--r-- | git/git.go | 48 | ||||
-rw-r--r-- | git/git_test.go | 13 | ||||
-rw-r--r-- | github/github.go | 44 | ||||
-rw-r--r-- | github/github_test.go | 38 | ||||
-rw-r--r-- | go.mod | 4 | ||||
-rw-r--r-- | go.sum | 13 | ||||
-rw-r--r-- | main.go | 57 |
10 files changed, 98 insertions, 192 deletions
@@ -1,4 +1,4 @@ -Copyright (c) 2014-2019, Martin Polden +Copyright (c) 2014-2021, Martin Polden All rights reserved. Redistribution and use in source and binary forms, with or without @@ -45,7 +45,7 @@ Usage of ghm: Number of repositories to mirror concurrently (default 1) -n Print commands that would be run and exit -p string - Protocol to use for mirroring [ssh|https|git] (default "ssh") + Protocol to use for mirroring [git|https|ssh] (default "ssh") -q Only print errors -s Skip forked repositories @@ -0,0 +1,69 @@ +package main + +import ( + "encoding/json" + "log" + "net/http" + "os" + "os/exec" + "path/filepath" +) + +type git struct { + path string + inheritIO bool +} + +type repository struct { + Name string `json:"name"` + SSHURL string `json:"ssh_url"` + GitURL string `json:"git_url"` + CloneURL string `json:"clone_url"` + Fork bool `json:"fork"` + Archived bool `json:"archived"` +} + +func listRepositories(user string) ([]repository, error) { + res, err := http.Get("https://api.github.com/users/" + user + "/repos") + if err != nil { + return nil, err + } + defer res.Body.Close() + dec := json.NewDecoder(res.Body) + var repos []repository + if err := dec.Decode(&repos); err != nil { + return nil, err + } + return repos, nil +} + +func gitCommand(inheritIO bool) (*git, error) { + p, err := exec.LookPath("git") + if err != nil { + return nil, err + } + return &git{path: p, inheritIO: inheritIO}, nil +} + +func repositoryPath(parentDir, repoName string) string { + return filepath.Join(parentDir, repoName+".git") +} + +func (g *git) command(args ...string) *exec.Cmd { + cmd := exec.Command(g.path, args...) + if g.inheritIO { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + } + return cmd +} + +func (g *git) sync(url, path string) *exec.Cmd { + _, err := os.Stat(path) + if os.IsNotExist(err) { + return g.command("clone", "--mirror", url, path) + } else if err != nil { + log.Fatal(err) + } + return g.command("-C", path, "fetch", "--prune") +} diff --git a/git/git.go b/git/git.go deleted file mode 100644 index 2ddbe81..0000000 --- a/git/git.go +++ /dev/null @@ -1,48 +0,0 @@ -package git - -import ( - "os" - "os/exec" - "path/filepath" -) - -type Git struct { - path string - inheritIO bool -} - -func New(inheritIO bool) (*Git, error) { - p, err := exec.LookPath("git") - if err != nil { - return nil, err - } - return &Git{path: p, inheritIO: inheritIO}, nil -} - -func LocalDir(parentDir, repoName string) string { - return filepath.Join(parentDir, repoName+".git") -} - -func (g *Git) command(args ...string) *exec.Cmd { - cmd := exec.Command(g.path, args...) - if g.inheritIO { - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - } - return cmd -} - -func (g *Git) Mirror(repoURL, localDir string) *exec.Cmd { - return g.command("clone", "--mirror", repoURL, localDir) -} - -func (g *Git) Update(localDir string) *exec.Cmd { - return g.command("-C", localDir, "fetch", "--prune") -} - -func (g *Git) Sync(repoURL, localDir string) *exec.Cmd { - if _, err := os.Stat(localDir); os.IsNotExist(err) { - return g.Mirror(repoURL, localDir) - } - return g.Update(localDir) -} diff --git a/git/git_test.go b/git/git_test.go deleted file mode 100644 index 7100659..0000000 --- a/git/git_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package git - -import "testing" - -func TestLocalDir(t *testing.T) { - parentDir := "/foo/bar" - repoName := "baz" - - got := LocalDir(parentDir, repoName) - if want := "/foo/bar/baz.git"; got != want { - t.Errorf("got %s, want %s", got, want) - } -} diff --git a/github/github.go b/github/github.go deleted file mode 100644 index 0dea270..0000000 --- a/github/github.go +++ /dev/null @@ -1,44 +0,0 @@ -package github - -import ( - "context" - "fmt" - - "github.com/google/go-github/v28/github" -) - -type Client struct { - *github.Client -} - -func New() *Client { - return &Client{github.NewClient(nil)} -} - -func (c *Client) ListAllRepositories(username string) ([]*github.Repository, error) { - opt := &github.RepositoryListOptions{Type: "owner", ListOptions: github.ListOptions{PerPage: 100}} - var repos []*github.Repository - ctx := context.Background() - for done := false; !done; { - rs, response, err := c.Repositories.List(ctx, username, opt) - if err != nil { - return nil, err - } - repos = append(repos, rs...) - opt.ListOptions.Page = response.NextPage - done = response.NextPage == 0 - } - return repos, nil -} - -func CloneURL(protocol string, r *github.Repository) (string, error) { - switch protocol { - case "https": - return *r.CloneURL, nil - case "git": - return *r.GitURL, nil - case "ssh": - return *r.SSHURL, nil - } - return "", fmt.Errorf("unknown protocol: %s", protocol) -} diff --git a/github/github_test.go b/github/github_test.go deleted file mode 100644 index 3c4705f..0000000 --- a/github/github_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package github - -import ( - "testing" - - "github.com/google/go-github/v28/github" -) - -func TestCloneURL(t *testing.T) { - httpsURL := "https://github.com/octocat/Hello-World.git" - gitURL := "git://github.com/octocat/Hello-World.git" - sshURL := "git@github.com:octocat/Hello-World.git" - r := github.Repository{ - CloneURL: &httpsURL, - GitURL: &gitURL, - SSHURL: &sshURL, - } - var tests = []struct { - in string - out string - }{ - {"https", httpsURL}, - {"git", gitURL}, - {"ssh", sshURL}, - } - for _, tt := range tests { - got, err := CloneURL(tt.in, &r) - if err != nil { - t.Fatal(err) - } - if got != tt.out { - t.Errorf("got %s for %s, want %s", got, tt.in, tt.out) - } - } - if _, err := CloneURL("", &r); err == nil { - t.Error("want error") - } -} @@ -1,5 +1,3 @@ module github.com/mpolden/ghm -go 1.13 - -require github.com/google/go-github/v28 v28.1.1 +go 1.15 @@ -1,13 +0,0 @@ -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo= -github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -8,11 +8,6 @@ import ( "os/exec" "strings" "sync" - - "github.com/google/go-github/v28/github" - - "github.com/mpolden/ghm/git" - gh "github.com/mpolden/ghm/github" ) type syncer struct { @@ -40,27 +35,32 @@ func (s *syncer) run(cmd *exec.Cmd) error { return nil } -func (s *syncer) sync(g *git.Git, r *github.Repository) error { - repoURL, err := gh.CloneURL(s.protocol, r) - if err != nil { - return err +func (s *syncer) sync(g *git, r repository) error { + var url string + switch s.protocol { + case "ssh": + url = r.SSHURL + case "git": + url = r.GitURL + default: + url = r.CloneURL } - localDir := git.LocalDir(s.localPath, *r.Name) - syncCmd := g.Sync(repoURL, localDir) + localDir := repositoryPath(s.localPath, r.Name) + syncCmd := g.sync(url, localDir) return s.run(syncCmd) } -func (s *syncer) syncAll(g *git.Git, repos []*github.Repository) { +func (s *syncer) syncAll(g *git, repos []repository) { sem := make(chan bool, s.concurrency) for _, r := range repos { - if s.skipFork && *r.Fork { + if s.skipFork && r.Fork { continue } - if s.skipArchived && *r.Archived { + if s.skipArchived && r.Archived { continue } sem <- true - go func(r *github.Repository) { + go func(r repository) { defer func() { <-sem }() if err := s.sync(g, r); err != nil { log.Fatal(err) @@ -76,7 +76,6 @@ func (s *syncer) syncAll(g *git.Git, repos []*github.Repository) { func main() { log.SetPrefix("ghm: ") log.SetFlags(log.Lshortfile) - flag.Usage = func() { out := flag.CommandLine.Output() fmt.Fprintf(out, "Usage of %s:\n", os.Args[0]) @@ -86,34 +85,26 @@ func main() { } quiet := flag.Bool("q", false, "Only print errors") dryrun := flag.Bool("n", false, "Print commands that would be run and exit") - protocol := flag.String("p", "ssh", "Protocol to use for mirroring [ssh|https|git]") + protocol := flag.String("p", "ssh", "Protocol to use for mirroring [git|https|ssh]") skipFork := flag.Bool("s", false, "Skip forked repositories") skipArchived := flag.Bool("a", false, "Skip archived repositories") concurrency := flag.Int("c", 1, "Number of repositories to mirror concurrently") flag.Parse() - - if *concurrency < 1 { - log.Fatal("concurrency level must be positive") - } - args := flag.Args() if len(args) < 2 { flag.Usage() + return } - username := args[0] - path := args[1] - - gh := gh.New() - repos, err := gh.ListAllRepositories(username) - if err != nil { - log.Fatal(err) + if *concurrency < 1 { + log.Fatal("invalid concurrency level") } - g, err := git.New(!*quiet) + g, err := gitCommand(!*quiet) if err != nil { log.Fatal(err) } - + githubUser := args[0] + path := args[1] syncer := syncer{ dryrun: *dryrun, protocol: *protocol, @@ -122,5 +113,9 @@ func main() { concurrency: *concurrency, localPath: path, } + repos, err := listRepositories(githubUser) + if err != nil { + log.Fatal(err) + } syncer.syncAll(g, repos) } |