// Returns local cloned repositories' root. // Uses the value of `git config ghq.root` or defaults to ~/.ghq. func localRepositoryRoots() []string { if len(_localRepositoryRoots) != 0 { return _localRepositoryRoots } var err error _localRepositoryRoots, err = GitConfigAll("ghq.root") utils.PanicIf(err) if len(_localRepositoryRoots) == 0 { homeDir, err := homedir.Dir() utils.PanicIf(err) _localRepositoryRoots = []string{filepath.Join(homeDir, ".ghq")} } for i, v := range _localRepositoryRoots { path := filepath.Clean(v) if _, err := os.Stat(path); err == nil { _localRepositoryRoots[i], err = filepath.EvalSymlinks(path) utils.PanicIf(err) } else { _localRepositoryRoots[i] = path } } return _localRepositoryRoots }
func doImportPocket(c *cli.Context) { if pocket.ConsumerKey == "" { utils.Log("error", "Built without consumer key set") return } accessToken, err := GitConfig("ghq.pocket.token") utils.PanicIf(err) if accessToken == "" { receiverURL, ch, err := pocket.StartAccessTokenReceiver() utils.PanicIf(err) utils.Log("pocket", "Waiting for Pocket authentication callback at "+receiverURL) utils.Log("pocket", "Obtaining request token") authRequest, err := pocket.ObtainRequestToken(receiverURL) utils.DieIf(err) url := pocket.GenerateAuthorizationURL(authRequest.Code, receiverURL) utils.Log("open", url) <-ch utils.Log("pocket", "Obtaining access token") authorized, err := pocket.ObtainAccessToken(authRequest.Code) utils.DieIf(err) utils.Log("authorized", authorized.Username) accessToken = authorized.AccessToken utils.Run("git", "config", "ghq.pocket.token", authorized.AccessToken) } utils.Log("pocket", "Retrieving github.com entries") res, err := pocket.RetrieveGitHubEntries(accessToken) utils.DieIf(err) for _, item := range res.List { url, err := url.Parse(item.ResolvedURL) if err != nil { utils.Log("error", fmt.Sprintf("Could not parse URL <%s>: %s", item.ResolvedURL, err)) continue } remote, err := NewRemoteRepository(url) if utils.ErrorIf(err) { continue } if remote.IsValid() == false { utils.Log("skip", fmt.Sprintf("Not a valid repository: %s", url)) continue } getRemoteRepository(remote, c.Bool("update")) } }
func getRemoteRepository(remote RemoteRepository, doUpdate bool) { remoteURL := remote.URL() local := LocalRepositoryFromURL(remoteURL) path := local.FullPath newPath := false _, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { newPath = true err = nil } utils.PanicIf(err) } if newPath { utils.Log("clone", fmt.Sprintf("%s -> %s", remoteURL, path)) remote.VCS().Clone(remoteURL, path) } else { if doUpdate { utils.Log("update", path) local.VCS().Update(path) } else { utils.Log("exists", path) } } }
// getRemoteRepository clones or updates a remote repository remote. // If doUpdate is true, updates the locally cloned repository. Otherwise does nothing. // If isShallow is true, does shallow cloning. (no effect if already cloned or the VCS is Mercurial) func getRemoteRepository(remote RemoteRepository, doUpdate bool, isShallow bool) { remoteURL := remote.URL() local := LocalRepositoryFromURL(remoteURL) path := local.FullPath newPath := false _, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { newPath = true err = nil } utils.PanicIf(err) } if newPath { utils.Log("clone", fmt.Sprintf("%s -> %s", remoteURL, path)) vcs := remote.VCS() if vcs == nil { utils.Log("error", fmt.Sprintf("Could not find version control system: %s", remoteURL)) os.Exit(1) } vcs.Clone(remoteURL, path, isShallow) } else { if doUpdate { utils.Log("update", path) local.VCS().Update(path) } else { utils.Log("exists", path) } } }
// Returns local cloned repositories' root. // Uses the value of `git config ghq.root` or defaults to ~/.ghq. func localRepositoryRoots() []string { if len(_localRepositoryRoots) != 0 { return _localRepositoryRoots } var err error _localRepositoryRoots, err = GitConfigAll("ghq.root") utils.PanicIf(err) if len(_localRepositoryRoots) == 0 { usr, err := user.Current() utils.PanicIf(err) _localRepositoryRoots = []string{path.Join(usr.HomeDir, ".ghq")} } return _localRepositoryRoots }
func doLook(c *cli.Context) { name := c.Args().First() if name == "" { cli.ShowCommandHelp(c, "look") os.Exit(1) } reposFound := []*LocalRepository{} walkLocalRepositories(func(repo *LocalRepository) { if repo.Matches(name) { reposFound = append(reposFound, repo) } }) switch len(reposFound) { case 0: utils.Log("error", "No repository found") os.Exit(1) case 1: if runtime.GOOS == "windows" { cmd := exec.Command(os.Getenv("COMSPEC")) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Dir = reposFound[0].FullPath err := cmd.Start() if err == nil { cmd.Wait() os.Exit(0) } } else { shell := os.Getenv("SHELL") if shell == "" { shell = "/bin/sh" } utils.Log("cd", reposFound[0].FullPath) err := os.Chdir(reposFound[0].FullPath) utils.PanicIf(err) syscall.Exec(shell, []string{shell}, syscall.Environ()) } default: utils.Log("error", "More than one repositories are found; Try more precise name") for _, repo := range reposFound { utils.Log("error", "- "+strings.Join(repo.PathParts, "/")) } } }
func doGet(c *cli.Context) { argURL := c.Args().Get(0) category := c.Args().Get(1) doUpdate := c.Bool("update") isShallow := c.Bool("shallow") if argURL == "" { cli.ShowCommandHelp(c, "get") os.Exit(1) } url, err := NewURL(argURL) utils.DieIf(err) isSSH := c.Bool("p") if isSSH { // Assume Git repository if `-p` is given. url, err = ConvertGitURLHTTPToSSH(url) utils.DieIf(err) } remote, err := NewRemoteRepository(url) utils.DieIf(err) if remote.IsValid() == false { utils.Log("error", fmt.Sprintf("Not a valid repository: %s", url)) os.Exit(1) } getRemoteRepository(remote, doUpdate, isShallow) if category != "" { localPath := LocalRepositoryFromURL(remote.URL()).FullPath categoryFile := path.Dir(localPath) + "/." + path.Base(localPath) if doUpdate { utils.Log("overwrite category", fmt.Sprintf("%s as %s", localPath, category)) ioutil.WriteFile(categoryFile, []byte(category+"\n"), 0644) } else { _, err := os.Stat(localPath) if err != nil { utils.PanicIf(err) } else { utils.Log("new category", fmt.Sprintf("%s as %s", localPath, category)) ioutil.WriteFile(categoryFile, []byte(category+"\n"), 0644) } } } }
func doLook(c *cli.Context) { name := c.Args().First() if name == "" { cli.ShowCommandHelp(c, "look") os.Exit(1) } reposFound := []*LocalRepository{} walkLocalRepositories(func(repo *LocalRepository) { if repo.Matches(name) { reposFound = append(reposFound, repo) } }) switch len(reposFound) { case 0: utils.Log("error", "No repository found") case 1: shell := os.Getenv("SHELL") if shell == "" { shell = "/bin/sh" } utils.Log("cd", reposFound[0].FullPath) err := os.Chdir(reposFound[0].FullPath) utils.PanicIf(err) syscall.Exec(shell, []string{shell}, syscall.Environ()) default: utils.Log("error", "More than one repositories are found; Try more precise name") for _, repo := range reposFound { utils.Log("error", "- "+strings.Join(repo.PathParts, "/")) } } }
func gitVersionOutputSatisfies(gitVersionOutput string, baseVersionParts []uint) bool { versionStrings := versionRx.FindStringSubmatch(gitVersionOutput) if versionStrings == nil { return false } for i, v := range baseVersionParts { thisV64, err := strconv.ParseUint(versionStrings[i+1], 10, 0) utils.PanicIf(err) thisV := uint(thisV64) if thisV > v { return true } else if v == thisV { continue } else { return false } } return true }
func doList(c *cli.Context) { query := c.Args().First() category := c.Args().First() isCategory := c.Bool("category") exact := c.Bool("exact") printFullPaths := c.Bool("full-path") printUniquePaths := c.Bool("unique") if isCategory { query = "" } var categoryFn = func(repo *LocalRepository) bool { if isCategory && category != "" { localPath := repo.FullPath categoryFile := path.Dir(localPath) + "/." + path.Base(localPath) fp, err := os.Open(categoryFile) if err != nil { return false } defer fp.Close() scanner := bufio.NewScanner(fp) var flg bool if scanner.Scan() { flg = category == scanner.Text() } else { flg = false } if err := scanner.Err(); err != nil { utils.PanicIf(err) } return flg } return true } var filterFn func(*LocalRepository) bool if query == "" { filterFn = func(repo *LocalRepository) bool { return true } } else if exact { filterFn = func(repo *LocalRepository) bool { return repo.Matches(query) } } else { filterFn = func(repo *LocalRepository) bool { return strings.Contains(repo.NonHostPath(), query) } } repos := []*LocalRepository{} walkLocalRepositories(func(repo *LocalRepository) { if (categoryFn(repo) && filterFn(repo)) == false { return } repos = append(repos, repo) }) if printUniquePaths { subpathCount := map[string]int{} // Count duplicated subpaths (ex. foo/dotfiles and bar/dotfiles) reposCount := map[string]int{} // Check duplicated repositories among roots // Primary first for _, repo := range repos { if reposCount[repo.RelPath] == 0 { for _, p := range repo.Subpaths() { subpathCount[p] = subpathCount[p] + 1 } } reposCount[repo.RelPath] = reposCount[repo.RelPath] + 1 } for _, repo := range repos { if reposCount[repo.RelPath] > 1 && repo.IsUnderPrimaryRoot() == false { continue } for _, p := range repo.Subpaths() { if subpathCount[p] == 1 { fmt.Println(p) break } } } } else { for _, repo := range repos { if printFullPaths { fmt.Println(repo.FullPath) } else { fmt.Println(repo.RelPath) } } } }
func doImportStarred(c *cli.Context) { user := c.Args().First() doUpdate := c.Bool("update") isSSH := c.Bool("p") isShallow := c.Bool("shallow") if user == "" { cli.ShowCommandHelp(c, "starred") os.Exit(1) } githubToken := os.Getenv("GHQ_GITHUB_TOKEN") if githubToken == "" { var err error githubToken, err = GitConfigSingle("ghq.github.token") utils.PanicIf(err) } var client *github.Client if githubToken != "" { oauthTransport := &oauth.Transport{ Token: &oauth.Token{AccessToken: githubToken}, } client = github.NewClient(oauthTransport.Client()) } else { client = github.NewClient(nil) } options := &github.ActivityListStarredOptions{Sort: "created"} for page := 1; ; page++ { options.Page = page repositories, res, err := client.Activity.ListStarred(user, options) utils.DieIf(err) utils.Log("page", fmt.Sprintf("%d/%d", page, res.LastPage)) for _, repo := range repositories { url, err := url.Parse(*repo.HTMLURL) if err != nil { utils.Log("error", fmt.Sprintf("Could not parse URL <%s>: %s", repo.HTMLURL, err)) continue } if isSSH { url, err = ConvertGitURLHTTPToSSH(url) if err != nil { utils.Log("error", fmt.Sprintf("Could not convert URL <%s>: %s", repo.HTMLURL, err)) continue } } remote, err := NewRemoteRepository(url) if utils.ErrorIf(err) { continue } if remote.IsValid() == false { utils.Log("skip", fmt.Sprintf("Not a valid repository: %s", url)) continue } getRemoteRepository(remote, doUpdate, isShallow) } if page >= res.LastPage { break } } }