2013-06-29 01:21:48 +04:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
2013-06-29 02:15:41 +04:00
|
|
|
"fmt"
|
2014-02-21 21:08:34 +04:00
|
|
|
"strings"
|
|
|
|
|
2014-02-10 20:22:36 +04:00
|
|
|
"github.com/github/hub/cmd"
|
|
|
|
"github.com/github/hub/git"
|
2015-02-10 11:26:45 +03:00
|
|
|
"github.com/github/hub/ui"
|
2016-01-20 06:37:48 +03:00
|
|
|
"github.com/kballard/go-shellquote"
|
2013-06-29 01:21:48 +04:00
|
|
|
)
|
|
|
|
|
|
|
|
type Runner struct {
|
2013-12-30 02:18:14 +04:00
|
|
|
commands map[string]*Command
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRunner() *Runner {
|
2014-12-22 19:34:57 +03:00
|
|
|
return &Runner{
|
|
|
|
commands: make(map[string]*Command),
|
|
|
|
}
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Runner) All() map[string]*Command {
|
|
|
|
return r.commands
|
|
|
|
}
|
|
|
|
|
2015-07-08 21:33:58 +03:00
|
|
|
func (r *Runner) Use(command *Command, aliases ...string) {
|
2013-12-30 02:18:14 +04:00
|
|
|
r.commands[command.Name()] = command
|
2015-07-08 21:33:58 +03:00
|
|
|
if len(aliases) > 0 {
|
|
|
|
r.commands[aliases[0]] = command
|
|
|
|
}
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Runner) Lookup(name string) *Command {
|
|
|
|
return r.commands[name]
|
2013-06-29 01:21:48 +04:00
|
|
|
}
|
|
|
|
|
2019-01-16 06:19:49 +03:00
|
|
|
func (r *Runner) Execute(cliArgs []string) error {
|
|
|
|
args := NewArgs(cliArgs[1:])
|
|
|
|
args.ProgramPath = cliArgs[0]
|
2016-09-11 00:49:58 +03:00
|
|
|
forceFail := false
|
2013-12-30 02:18:14 +04:00
|
|
|
|
2017-06-26 19:36:20 +03:00
|
|
|
if args.Command == "" && len(args.GlobalFlags) == 0 {
|
2016-09-11 00:49:58 +03:00
|
|
|
args.Command = "help"
|
|
|
|
forceFail = true
|
2013-06-29 01:21:48 +04:00
|
|
|
}
|
|
|
|
|
2018-07-07 13:27:46 +03:00
|
|
|
cmdName := args.Command
|
|
|
|
if strings.Contains(cmdName, "=") {
|
|
|
|
cmdName = strings.SplitN(cmdName, "=", 2)[0]
|
|
|
|
}
|
|
|
|
|
2015-01-13 10:07:21 +03:00
|
|
|
git.GlobalFlags = args.GlobalFlags // preserve git global flags
|
2018-07-07 13:27:46 +03:00
|
|
|
if !isBuiltInHubCommand(cmdName) {
|
2016-11-05 09:53:36 +03:00
|
|
|
expandAlias(args)
|
2018-07-07 14:35:00 +03:00
|
|
|
cmdName = args.Command
|
2016-11-05 09:53:36 +03:00
|
|
|
}
|
2013-06-29 02:15:41 +04:00
|
|
|
|
2018-07-07 13:27:46 +03:00
|
|
|
cmd := r.Lookup(cmdName)
|
2013-12-30 02:18:14 +04:00
|
|
|
if cmd != nil && cmd.Runnable() {
|
2019-01-16 06:19:49 +03:00
|
|
|
err := callRunnableCommand(cmd, args)
|
|
|
|
if err == nil && forceFail {
|
|
|
|
err = fmt.Errorf("")
|
2016-09-11 00:49:58 +03:00
|
|
|
}
|
2019-01-16 06:19:49 +03:00
|
|
|
return err
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
2013-06-29 01:21:48 +04:00
|
|
|
|
2019-03-29 01:55:24 +03:00
|
|
|
gitArgs := []string{}
|
|
|
|
if args.Command != "" {
|
|
|
|
gitArgs = append(gitArgs, args.Command)
|
|
|
|
}
|
2016-09-12 07:29:53 +03:00
|
|
|
gitArgs = append(gitArgs, args.Params...)
|
|
|
|
|
2019-01-16 06:19:49 +03:00
|
|
|
return git.Run(gitArgs...)
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
2013-06-29 01:31:04 +04:00
|
|
|
|
2019-01-16 06:19:49 +03:00
|
|
|
func callRunnableCommand(cmd *Command, args *Args) error {
|
2013-12-30 02:18:14 +04:00
|
|
|
err := cmd.Call(args)
|
2013-12-30 07:20:41 +04:00
|
|
|
if err != nil {
|
2019-01-16 06:19:49 +03:00
|
|
|
return err
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
cmds := args.Commands()
|
|
|
|
if args.Noop {
|
|
|
|
printCommands(cmds)
|
2019-01-16 06:19:49 +03:00
|
|
|
} else if err = executeCommands(cmds, len(args.Callbacks) == 0); err != nil {
|
|
|
|
return err
|
2016-09-11 00:49:58 +03:00
|
|
|
}
|
|
|
|
|
2019-01-16 06:19:49 +03:00
|
|
|
for _, fn := range args.Callbacks {
|
|
|
|
if err = fn(); err != nil {
|
|
|
|
return err
|
2016-09-11 00:49:58 +03:00
|
|
|
}
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
|
|
|
|
2019-01-16 06:19:49 +03:00
|
|
|
return nil
|
2013-06-29 01:21:48 +04:00
|
|
|
}
|
2013-06-29 02:15:41 +04:00
|
|
|
|
2013-07-05 22:10:24 +04:00
|
|
|
func printCommands(cmds []*cmd.Cmd) {
|
|
|
|
for _, c := range cmds {
|
2015-02-10 11:26:45 +03:00
|
|
|
ui.Println(c)
|
2013-07-05 22:10:24 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-11 00:49:58 +03:00
|
|
|
func executeCommands(cmds []*cmd.Cmd, execFinal bool) error {
|
2014-11-30 23:14:18 +03:00
|
|
|
for i, c := range cmds {
|
|
|
|
var err error
|
|
|
|
// Run with `Exec` for the last command in chain
|
2016-09-11 00:49:58 +03:00
|
|
|
if execFinal && i == len(cmds)-1 {
|
2014-11-30 23:14:18 +03:00
|
|
|
err = c.Run()
|
|
|
|
} else {
|
|
|
|
err = c.Spawn()
|
|
|
|
}
|
|
|
|
|
2013-07-05 22:10:24 +04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-06-29 02:15:41 +04:00
|
|
|
func expandAlias(args *Args) {
|
2013-07-02 22:28:50 +04:00
|
|
|
cmd := args.Command
|
2019-08-04 00:28:42 +03:00
|
|
|
if cmd == "" {
|
|
|
|
return
|
|
|
|
}
|
2013-12-04 19:08:52 +04:00
|
|
|
expandedCmd, err := git.Alias(cmd)
|
2016-11-05 09:53:36 +03:00
|
|
|
|
|
|
|
if err == nil && expandedCmd != "" && !git.IsBuiltInGitCommand(cmd) {
|
2013-12-29 07:07:48 +04:00
|
|
|
words, e := splitAliasCmd(expandedCmd)
|
|
|
|
if e == nil {
|
2013-08-16 18:16:59 +04:00
|
|
|
args.Command = words[0]
|
|
|
|
args.PrependParams(words[1:]...)
|
|
|
|
}
|
2013-06-29 02:15:41 +04:00
|
|
|
}
|
|
|
|
}
|
2013-12-29 07:07:48 +04:00
|
|
|
|
2016-11-05 09:53:36 +03:00
|
|
|
func isBuiltInHubCommand(command string) bool {
|
2019-07-23 10:28:32 +03:00
|
|
|
for hubCommand := range CmdRunner.All() {
|
2016-11-05 09:53:36 +03:00
|
|
|
if hubCommand == command {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2013-12-29 07:07:48 +04:00
|
|
|
func splitAliasCmd(cmd string) ([]string, error) {
|
|
|
|
if cmd == "" {
|
|
|
|
return nil, fmt.Errorf("alias can't be empty")
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasPrefix(cmd, "!") {
|
|
|
|
return nil, fmt.Errorf("alias starting with ! can't be split")
|
|
|
|
}
|
|
|
|
|
|
|
|
words, err := shellquote.Split(cmd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return words, nil
|
|
|
|
}
|