зеркало из https://github.com/mislav/hub.git
164 строки
3.0 KiB
Go
164 строки
3.0 KiB
Go
package commands
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/github/hub/cmd"
|
|
"github.com/github/hub/git"
|
|
"github.com/github/hub/ui"
|
|
"github.com/kballard/go-shellquote"
|
|
)
|
|
|
|
type Runner struct {
|
|
commands map[string]*Command
|
|
}
|
|
|
|
func NewRunner() *Runner {
|
|
return &Runner{
|
|
commands: make(map[string]*Command),
|
|
}
|
|
}
|
|
|
|
func (r *Runner) All() map[string]*Command {
|
|
return r.commands
|
|
}
|
|
|
|
func (r *Runner) Use(command *Command, aliases ...string) {
|
|
r.commands[command.Name()] = command
|
|
if len(aliases) > 0 {
|
|
r.commands[aliases[0]] = command
|
|
}
|
|
}
|
|
|
|
func (r *Runner) Lookup(name string) *Command {
|
|
return r.commands[name]
|
|
}
|
|
|
|
func (r *Runner) Execute(cliArgs []string) error {
|
|
args := NewArgs(cliArgs[1:])
|
|
args.ProgramPath = cliArgs[0]
|
|
forceFail := false
|
|
|
|
if args.Command == "" && len(args.GlobalFlags) == 0 {
|
|
args.Command = "help"
|
|
forceFail = true
|
|
}
|
|
|
|
cmdName := args.Command
|
|
if strings.Contains(cmdName, "=") {
|
|
cmdName = strings.SplitN(cmdName, "=", 2)[0]
|
|
}
|
|
|
|
git.GlobalFlags = args.GlobalFlags // preserve git global flags
|
|
if !isBuiltInHubCommand(cmdName) {
|
|
expandAlias(args)
|
|
cmdName = args.Command
|
|
}
|
|
|
|
cmd := r.Lookup(cmdName)
|
|
if cmd != nil && cmd.Runnable() {
|
|
err := callRunnableCommand(cmd, args)
|
|
if err == nil && forceFail {
|
|
err = fmt.Errorf("")
|
|
}
|
|
return err
|
|
}
|
|
|
|
gitArgs := []string{}
|
|
if args.Command != "" {
|
|
gitArgs = append(gitArgs, args.Command)
|
|
}
|
|
gitArgs = append(gitArgs, args.Params...)
|
|
|
|
return git.Run(gitArgs...)
|
|
}
|
|
|
|
func callRunnableCommand(cmd *Command, args *Args) error {
|
|
err := cmd.Call(args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cmds := args.Commands()
|
|
if args.Noop {
|
|
printCommands(cmds)
|
|
} else if err = executeCommands(cmds, len(args.Callbacks) == 0); err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, fn := range args.Callbacks {
|
|
if err = fn(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func printCommands(cmds []*cmd.Cmd) {
|
|
for _, c := range cmds {
|
|
ui.Println(c)
|
|
}
|
|
}
|
|
|
|
func executeCommands(cmds []*cmd.Cmd, execFinal bool) error {
|
|
for i, c := range cmds {
|
|
var err error
|
|
// Run with `Exec` for the last command in chain
|
|
if execFinal && i == len(cmds)-1 {
|
|
err = c.Run()
|
|
} else {
|
|
err = c.Spawn()
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func expandAlias(args *Args) {
|
|
cmd := args.Command
|
|
if cmd == "" {
|
|
return
|
|
}
|
|
expandedCmd, err := git.Alias(cmd)
|
|
|
|
if err == nil && expandedCmd != "" && !git.IsBuiltInGitCommand(cmd) {
|
|
words, e := splitAliasCmd(expandedCmd)
|
|
if e == nil {
|
|
args.Command = words[0]
|
|
args.PrependParams(words[1:]...)
|
|
}
|
|
}
|
|
}
|
|
|
|
func isBuiltInHubCommand(command string) bool {
|
|
for hubCommand := range CmdRunner.All() {
|
|
if hubCommand == command {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
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
|
|
}
|