aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2021-02-18 20:59:50 +0100
committerMartin Polden <mpolden@mpolden.no>2021-02-18 21:06:29 +0100
commit2ca5d50afea2ea87efd6260c7c9942dc0004860d (patch)
tree3f06278bd25731808739f8e74812471826561437
parentb185c4c04ab8174a4165812985f1000f92f375a1 (diff)
all: Remove go-github dependency
-rw-r--r--LICENSE2
-rw-r--r--README.md2
-rw-r--r--git.go69
-rw-r--r--git/git.go48
-rw-r--r--git/git_test.go13
-rw-r--r--github/github.go44
-rw-r--r--github/github_test.go38
-rw-r--r--go.mod4
-rw-r--r--go.sum13
-rw-r--r--main.go57
10 files changed, 98 insertions, 192 deletions
diff --git a/LICENSE b/LICENSE
index c0a096f..e3800fe 100644
--- a/LICENSE
+++ b/LICENSE
@@ -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
diff --git a/README.md b/README.md
index a05db1f..444ea27 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/git.go b/git.go
new file mode 100644
index 0000000..44708b2
--- /dev/null
+++ b/git.go
@@ -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")
- }
-}
diff --git a/go.mod b/go.mod
index ed4e822..886ca41 100644
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
deleted file mode 100644
index 283cb5f..0000000
--- a/go.sum
+++ /dev/null
@@ -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=
diff --git a/main.go b/main.go
index 0927767..e0c22a0 100644
--- a/main.go
+++ b/main.go
@@ -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)
}