mirror of
https://github.com/x-motemen/ghq.git
synced 2026-09-10 07:26:27 -04:00
googlecode and hg support
This commit is contained in:
parent
f6300cfdd0
commit
f7bf6ed8d7
13
commands.go
13
commands.go
|
|
@ -44,9 +44,9 @@ func CommandGet(c *cli.Context) {
|
|||
}
|
||||
|
||||
func getRemoteRepository(remote RemoteRepository, doUpdate bool) {
|
||||
remoteURL := remote.RepositoryURL()
|
||||
remoteURL := remote.URL()
|
||||
pathParts := append(
|
||||
[]string{remoteURL.Host}, strings.Split(remote.RepositoryURL().Path, "/")...,
|
||||
[]string{remoteURL.Host}, strings.Split(remoteURL.Path, "/")...,
|
||||
)
|
||||
local := LocalRepositoryFromPathParts(pathParts)
|
||||
|
||||
|
|
@ -63,14 +63,13 @@ func getRemoteRepository(remote RemoteRepository, doUpdate bool) {
|
|||
}
|
||||
|
||||
if newPath {
|
||||
utils.Log("clone", fmt.Sprintf("%s -> %s", remote.RepositoryURL(), path))
|
||||
utils.Log("clone", fmt.Sprintf("%s -> %s", remoteURL, path))
|
||||
|
||||
remote.VCS().Clone(remote.RepositoryURL(), path)
|
||||
remote.VCS().Clone(remoteURL, path)
|
||||
} else {
|
||||
if doUpdate {
|
||||
utils.Log("update", path)
|
||||
|
||||
remote.VCS().Update(path)
|
||||
local.VCS().Update(path)
|
||||
} else {
|
||||
utils.Log("exists", path)
|
||||
}
|
||||
|
|
@ -197,7 +196,7 @@ func CommandPocket(c *cli.Context) {
|
|||
utils.Log("authorized", authorized.Username)
|
||||
|
||||
accessToken = authorized.AccessToken
|
||||
Git("config", "ghq.pocket.token", authorized.AccessToken)
|
||||
utils.Run("git", "config", "ghq.pocket.token", authorized.AccessToken)
|
||||
}
|
||||
|
||||
utils.Log("pocket", "Retrieving github.com entries")
|
||||
|
|
|
|||
18
git.go
18
git.go
|
|
@ -1,30 +1,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/motemen/ghq/utils"
|
||||
)
|
||||
|
||||
func Git(command ...string) error {
|
||||
utils.Log("git", strings.Join(command, " "))
|
||||
|
||||
cmd := exec.Command("git", command...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("git: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GitConfig(key string) (string, error) {
|
||||
cmd := exec.Command("git", "config", "--path", "--null", "--get", key)
|
||||
cmd.Stderr = os.Stderr
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ func (repo *LocalRepository) NonHostPath() string {
|
|||
return strings.Join(repo.PathParts[1:], "/")
|
||||
}
|
||||
|
||||
// Checks if any subpath of the local repository equals the query.
|
||||
func (repo *LocalRepository) Matches(pathQuery string) bool {
|
||||
for _, p := range repo.Subpaths() {
|
||||
if p == pathQuery {
|
||||
|
|
@ -63,6 +64,26 @@ func (repo *LocalRepository) Matches(pathQuery string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// TODO return err
|
||||
func (repo *LocalRepository) VCS() *VCSBackend {
|
||||
var (
|
||||
fi os.FileInfo
|
||||
err error
|
||||
)
|
||||
|
||||
fi, err = os.Stat(filepath.Join(repo.FullPath, ".git"))
|
||||
if err == nil && fi.IsDir() {
|
||||
return GitBackend
|
||||
}
|
||||
|
||||
fi, err = os.Stat(filepath.Join(repo.FullPath, ".hg"))
|
||||
if err == nil && fi.IsDir() {
|
||||
return MercurialBackend
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func walkLocalRepositories(callback func(*LocalRepository)) {
|
||||
filepath.Walk(localRepositoriesRoot(), func(path string, fileInfo os.FileInfo, err error) error {
|
||||
repo, err := LocalRepositoryFromFullPath(path)
|
||||
|
|
|
|||
2
main.go
2
main.go
|
|
@ -55,7 +55,7 @@ func main() {
|
|||
|
||||
func mustBeOkay(err error) {
|
||||
if err != nil {
|
||||
_, file, line, _ := runtime.Caller(0)
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
utils.Log("error", fmt.Sprintf("at %s line %d: %s", file, line, err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,32 +3,38 @@ package main
|
|||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/motemen/ghq/utils"
|
||||
)
|
||||
|
||||
// Represents a remote repository.
|
||||
type RemoteRepository interface {
|
||||
RepositoryURL() *url.URL
|
||||
// The repository URL.
|
||||
URL() *url.URL
|
||||
// Checks if the URL is valid.
|
||||
IsValid() bool
|
||||
// The VCS backend that hosts the repository.
|
||||
VCS() *VCSBackend
|
||||
}
|
||||
|
||||
// Represents a GitHub repository. Impliments RemoteRepository.
|
||||
type GitHubRepository struct {
|
||||
*url.URL
|
||||
url *url.URL
|
||||
}
|
||||
|
||||
func (repo *GitHubRepository) RepositoryURL() *url.URL {
|
||||
return repo.URL
|
||||
func (repo *GitHubRepository) URL() *url.URL {
|
||||
return repo.url
|
||||
}
|
||||
|
||||
func (repo *GitHubRepository) IsValid() bool {
|
||||
if strings.HasPrefix(repo.Path, "/blog/") {
|
||||
if strings.HasPrefix(repo.url.Path, "/blog/") {
|
||||
return false
|
||||
}
|
||||
|
||||
// must be /{user}/{project}
|
||||
if len(strings.Split(repo.Path, "/")) != 3 {
|
||||
if len(strings.Split(repo.url.Path, "/")) != 3 {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -39,29 +45,28 @@ func (repo *GitHubRepository) VCS() *VCSBackend {
|
|||
return GitBackend
|
||||
}
|
||||
|
||||
type VCSBackend struct {
|
||||
Clone func(*url.URL, string) error
|
||||
Update func(string) error
|
||||
type GoogleCodeRepository struct {
|
||||
url *url.URL
|
||||
}
|
||||
|
||||
var GitBackend = &VCSBackend{
|
||||
Clone: func(remote *url.URL, local string) error {
|
||||
dir, _ := filepath.Split(local)
|
||||
err := os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (repo *GoogleCodeRepository) URL() *url.URL {
|
||||
return repo.url
|
||||
}
|
||||
|
||||
return Git("clone", remote.String(), local)
|
||||
},
|
||||
Update: func(local string) error {
|
||||
err := os.Chdir(local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var validGoogleCodePathPattern = regexp.MustCompile(`^/p/[^/]+/?$`)
|
||||
|
||||
return Git("remote", "update")
|
||||
},
|
||||
func (repo *GoogleCodeRepository) IsValid() bool {
|
||||
return validGoogleCodePathPattern.MatchString(repo.url.Path)
|
||||
}
|
||||
|
||||
func (repo *GoogleCodeRepository) VCS() *VCSBackend {
|
||||
if utils.RunSilently("hg", "identify", repo.url.String()) == nil {
|
||||
return MercurialBackend
|
||||
} else if utils.RunSilently("git", "ls-remote", repo.url.String()) == nil {
|
||||
return GitBackend
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewRemoteRepository(url *url.URL) (RemoteRepository, error) {
|
||||
|
|
@ -69,5 +74,9 @@ func NewRemoteRepository(url *url.URL) (RemoteRepository, error) {
|
|||
return &GitHubRepository{url}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("Unsupported domain")
|
||||
if url.Host == "code.google.com" {
|
||||
return &GoogleCodeRepository{url}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("Unsupported host")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
func Log(prefix string, message string) {
|
||||
if prefix == "git" || prefix == "skip" {
|
||||
if prefix == "git" || prefix == "hg" || prefix == "skip" {
|
||||
ct.ChangeColor(ct.White, false, ct.None, false)
|
||||
} else if prefix == "open" || prefix == "exists" {
|
||||
ct.ChangeColor(ct.Yellow, false, ct.None, false)
|
||||
|
|
|
|||
45
utils/run.go
Normal file
45
utils/run.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Run(command string, args ...string) error {
|
||||
cmd := exec.Command(command, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return RunCommand(cmd)
|
||||
}
|
||||
|
||||
func RunSilently(command string, args ...string) error {
|
||||
cmd := exec.Command(command, args...)
|
||||
cmd.Stdout = ioutil.Discard
|
||||
cmd.Stderr = ioutil.Discard
|
||||
|
||||
return RunCommand(cmd)
|
||||
}
|
||||
|
||||
func RunCommand(cmd *exec.Cmd) error {
|
||||
Log(cmd.Args[0], strings.Join(cmd.Args[1:], " "))
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return &RunError{cmd, err}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type RunError struct {
|
||||
Command *exec.Cmd
|
||||
ExecError error
|
||||
}
|
||||
|
||||
func (e *RunError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Command.Path, e.ExecError)
|
||||
}
|
||||
57
vcs.go
Normal file
57
vcs.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/motemen/ghq/utils"
|
||||
)
|
||||
|
||||
// Represents a VCS backend.
|
||||
type VCSBackend struct {
|
||||
// Clones a remote repository to local path.
|
||||
Clone func(*url.URL, string) error
|
||||
// Updates a cloned local repository.
|
||||
Update func(string) error
|
||||
}
|
||||
|
||||
var GitBackend = &VCSBackend{
|
||||
Clone: func(remote *url.URL, local string) error {
|
||||
dir, _ := filepath.Split(local)
|
||||
err := os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utils.Run("git", "clone", remote.String(), local)
|
||||
},
|
||||
Update: func(local string) error {
|
||||
err := os.Chdir(local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utils.Run("git", "remote", "update")
|
||||
},
|
||||
}
|
||||
|
||||
var MercurialBackend = &VCSBackend{
|
||||
Clone: func(remote *url.URL, local string) error {
|
||||
dir, _ := filepath.Split(local)
|
||||
err := os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utils.Run("hg", "clone", remote.String(), local)
|
||||
},
|
||||
Update: func(local string) error {
|
||||
err := os.Chdir(local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utils.Run("hg", "pull")
|
||||
},
|
||||
}
|
||||
Loading…
Reference in a new issue