diff --git a/go.mod b/go.mod index d5b4252..01c55d5 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module up2GitX go 1.14 require ( + github.com/bitly/go-simplejson v0.5.0 github.com/go-git/go-git/v5 v5.1.0 github.com/gookit/color v1.2.5 github.com/gookit/gcli/v2 v2.2.1 diff --git a/go.sum b/go.sum index 0a0f476..87c230a 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/platform/gitee.go b/platform/gitee.go index d40bbd6..2e392a4 100644 --- a/platform/gitee.go +++ b/platform/gitee.go @@ -52,7 +52,12 @@ func GiteeCommand() *gcli.Command { /tmp/repos/git-work-repo1 /Zoker/workspace/git-work-repo2 /other/path/to/git-bare-repo3 - ...`} + ... + + Using Source: {$binName} {$cmd} github:zoker + Support import from Github source, replace {zoker} with your expected Github path + Alert: Only Github source and public project supported, other platform like Gitlab, Bitbucket will be added later +`} // bind args with names gitee.AddArg("repoSource", "Tell me which repo dir or list your want to sync, is required", false) @@ -68,7 +73,7 @@ func syncGitee(c *gcli.Command, args []string) error { } // check repodir and print projects to ensure - repos := share.ReadyToAuth(args[0]) + repos := share.ReadyToAuth(args[0], c.Name) if repos == nil { return nil } diff --git a/share/tools.go b/share/tools.go index 2088a6b..d06d109 100644 --- a/share/tools.go +++ b/share/tools.go @@ -10,6 +10,7 @@ import ( "net/url" "os" "path/filepath" + "regexp" "strings" "sync" "time" @@ -19,6 +20,7 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "gopkg.in/src-d/go-git.v4/plumbing/transport/http" + "github.com/bitly/go-simplejson" ) type RepoLocal struct { @@ -34,7 +36,7 @@ const ( func InvalidAlert(platform string) { fmt.Printf("Tell me which repos source your want to sync, Usage: ") - color.Yellow.Printf("up2 %s /Users/Zoker/repos/ or up2 %s /Users/Zoker/repo.txt\n", platform, platform) + color.Yellow.Printf("up2 %s /Users/Zoker/repos/ or up2 %s /Users/Zoker/repo.txt or up2 %s github:kesin\n", platform, platform, platform) fmt.Printf("See 'up2 %s -h' for more details\n", platform) } @@ -111,13 +113,12 @@ func isGitRepo(repoPath string) (isGit bool) { } } -func printRepos(repos []string) { +func printRepos(repos []RepoLocal) { color.Yellow.Println(len(repos), "repositories detected, please check below: ", "\n") alertFlag := false - reposLocal := getRepoLocal(repos) - for i, repo := range reposLocal { + for i, repo := range repos { i = i + 1 p := fmt.Sprintf("%d. %s", i, repo.path) fmt.Printf(p) @@ -153,6 +154,38 @@ func getRepoLocal(repos []string) (reposLocal []RepoLocal) { return reposLocal } +func getRepoApi(repoDir string) (reposLocal []RepoLocal, repos []string) { + orgPath := repoDir[7:] + platform := repoDir[:6] + apiUrl := fmt.Sprintf("https://api.github.com/search/repositories?q=org:%s", orgPath) + result, err := GetByte(apiUrl) + if err != nil { + color.Red.Printf("Request error: %s \n", err.Error()) + return nil, nil + } + jsonRes, _ := simplejson.NewJson([]byte(result)) + count, _ := jsonRes.Get("total_count").Float64() + if count == 0 { + color.Yellow.Printf("No repositories found in https://github.com/%s\nPlease check if path is validate\n", orgPath) + return nil, nil + } else { // TODO optimize code with local repo and struct repos + repoArray, _ := jsonRes.Get("items").Array() + for _, ra := range repoArray { + item := ra.(map[string]interface{}) + outOf1G := false + size, _ := item["size"].(json.Number).Int64() + if size > 1024*1024 { + outOf1G = true + } + sizeMB := float32(size) / 1024.0 + repoPath := fmt.Sprintf("https://%s.com/%s/%s", platform, orgPath, item["name"].(string)) + reposLocal = append(reposLocal, RepoLocal{path: repoPath, sizeM: sizeMB, alert: outOf1G}) + repos = append(repos, repoPath) + } + return reposLocal, repos + } +} + func getRepoItemWorker(paths <- chan string, wp *sync.WaitGroup, reposLocal *[]RepoLocal, mutex *sync.Mutex) { for path := range paths { size, outAlert, _ := repoSize(path) @@ -180,13 +213,34 @@ func repoSize(path string) (float32, bool, error) { return sizeMB, outOf1G, err } -func ReadyToAuth(repoDir string) []string { +func ReadyToAuth(repoDir string, platform string) []string { + if platform == "gitee" { + reg, err := regexp.Compile(`^github:.+`) + if err == nil && reg.MatchString(repoDir) { + reposLocal, repos := getRepoApi(repoDir) + if repos != nil { + printRepos(reposLocal) + if len(repos) > 1000 { + color.Warn.Println("\nWarning: Gitee only support 1000 projects for each user, some of projects will not sync as expect") + } + inPut, _ := interact.ReadLine("\nCheck if this repositories are what you expected, ready to the next step? (y/n) ") + if inPut == "y" { + return repos + } else { + ExitMessage() + } + } + } + return nil + } + if FileExists(repoDir) { repos, _ := GetGitDir(repoDir) if len(repos) == 0 { color.Red.Printf("No git repositories detected in %s \n", repoDir) } else { - printRepos(repos) + reposLocal := getRepoLocal(repos) + printRepos(reposLocal) inPut, _ := interact.ReadLine("\nCheck if this repositories are what you expected, ready to the next step? (y/n) ") if inPut == "y" { return repos @@ -204,6 +258,18 @@ func ExitMessage() { color.Yellow.Println("Bye, see you next time!") } +func GetByte(url string) ([]byte, error) { + response, err := NetHttp.Get(url) + if err != nil { + color.Red.Printf("Request failed, Error: %s \n", err.Error()) + return nil, err + } + defer response.Body.Close() + + body, _ := ioutil.ReadAll(response.Body) + return body, nil +} + func Get(url string) (map[string]interface{}, error) { response, err := NetHttp.Get(url) if err != nil {