diff --git a/commands.go b/commands.go index 06d8b7ee..4d9c92c2 100644 --- a/commands.go +++ b/commands.go @@ -3,6 +3,7 @@ package main import ( "bufio" "fmt" + "io" "os" "os/exec" "runtime" @@ -322,7 +323,45 @@ func doImport(c *cli.Context) { isShallow = c.Bool("shallow") ) - scanner := bufio.NewScanner(os.Stdin) + var ( + in io.Reader + finalize func() error + ) + + if len(c.Args()) == 0 { + // `ghq import` reads URLs from stdin + in = os.Stdin + finalize = func() error { return nil } + } else { + // Handle `ghq import starred motemen` case + // with `git config --global ghq.import.starred "!github-list-starred"` + subCommand := c.Args().First() + command, err := GitConfigSingle("ghq.import." + subCommand) + if err == nil && command == "" { + err = fmt.Errorf("ghq.import.%s configuration not found", subCommand) + } + utils.DieIf(err) + + // execute `sh -c 'COMMAND "$@"' -- ARG...` + // TODO: Windows + command = strings.TrimLeft(command, "!") + shellCommand := append([]string{"sh", "-c", command + ` "$@"`, "--"}, c.Args().Tail()...) + + utils.Log("run", strings.Join(append([]string{command}, c.Args().Tail()...), " ")) + + cmd := exec.Command(shellCommand[0], shellCommand[1:]...) + cmd.Stderr = os.Stderr + + in, err = cmd.StdoutPipe() + utils.DieIf(err) + + err = cmd.Start() + utils.DieIf(err) + + finalize = cmd.Wait + } + + scanner := bufio.NewScanner(in) for scanner.Scan() { line := scanner.Text() url, err := NewURL(line) @@ -353,6 +392,8 @@ func doImport(c *cli.Context) { utils.Log("error", fmt.Sprintf("While reading input: %s", err)) os.Exit(1) } + + utils.DieIf(finalize()) } func doRoot(c *cli.Context) { diff --git a/ghq.txt b/ghq.txt index 33d09463..55f00cba 100644 --- a/ghq.txt +++ b/ghq.txt @@ -11,7 +11,7 @@ ghq - Manage remote repository clones $ ghq get https://github.com/motemen/ghq # Runs `git clone https://github.com/motemen/ghq ~/.ghq/github.com/motemen/ghq` -You can also list local repositories (+ghq list+), jump into local repositories (+ghq look+), and bulk cloning repositories from several web services (+ghq import+). +You can also list local repositories (+ghq list+), jump into local repositories (+ghq look+), and bulk get repositories by list of URLs (+ghq import+). == SYNOPSIS @@ -19,7 +19,8 @@ You can also list local repositories (+ghq list+), jump into local repositories 'ghq' get [-u] [-p] ( | / | ) 'ghq' list [-p] [-e] [] 'ghq' look ( | ) -'ghq' import < FILE +'ghq' import [-u] [-p] < FILE +'ghq' import [...] == COMMANDS @@ -48,7 +49,12 @@ look:: Look into a locally cloned repository with the shell. import:: - Reads repository URLs from stdin and performs 'get' for each of them. + If no extra arguments given, reads repository URLs from stdin line by line + and performs 'get' for each of them. + + If given a subcommand name e.g. 'ghq import [...]', + ghq looks up a configuration 'ghq.import.' for a command, invokes + it, and uses its output as URLs list. See below for 'ghq.import.' + in CONFIGURATION section. == CONFIGURATION @@ -69,7 +75,7 @@ ghq..vcs:: Accepted values are "git", "github" (an alias for "git"), "mercurial", "hg" (an alias for "mercurial"). + To get this configuration variable effective, you will need Git 1.8.5 or higher. + - For example in .gitconfig: + + For example in .gitconfig: .... [ghq "https://git.example.com/repos/"] @@ -77,6 +83,20 @@ vcs = git .... +ghq.import.:: + When 'import' is called with extra arguments e.g. 'ghq import [...]', + first of them is treated as a subcommand name and this configuration value + will be used for a command. The command is invoked with rest arguments + and expected to print remote repository URLs line by line. + + For example with https://github.com/motemen/github-list-starred[github-list-starred]: + +.... +# Invoke as `ghq import starred motemen` +[ghq "import"] +starred = github-list-starred +.... + + ghq.ghe.host:: The hostname of your GitHub Enterprise installation. A repository that has a hostname set with this key will be regarded as same one as one on GitHub.