github.com/trevoraustin/hub@v2.2.0-preview1.0.20141105230840-96d8bfc654cc+incompatible/commands/runner.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "strings" 8 "syscall" 9 10 "github.com/github/hub/cmd" 11 "github.com/github/hub/git" 12 "github.com/github/hub/utils" 13 "github.com/kballard/go-shellquote" 14 flag "github.com/ogier/pflag" 15 ) 16 17 type ExecError struct { 18 Err error 19 ExitCode int 20 } 21 22 func (execError *ExecError) Error() string { 23 return execError.Err.Error() 24 } 25 26 func newExecError(err error) ExecError { 27 exitCode := 0 28 if err != nil { 29 exitCode = 1 30 if exitError, ok := err.(*exec.ExitError); ok { 31 if status, ok := exitError.Sys().(syscall.WaitStatus); ok { 32 exitCode = status.ExitStatus() 33 } 34 } 35 } 36 37 return ExecError{Err: err, ExitCode: exitCode} 38 } 39 40 type Runner struct { 41 commands map[string]*Command 42 } 43 44 func NewRunner() *Runner { 45 return &Runner{commands: make(map[string]*Command)} 46 } 47 48 func (r *Runner) All() map[string]*Command { 49 return r.commands 50 } 51 52 func (r *Runner) Use(command *Command) { 53 r.commands[command.Name()] = command 54 } 55 56 func (r *Runner) Lookup(name string) *Command { 57 return r.commands[name] 58 } 59 60 func (r *Runner) Execute() ExecError { 61 args := NewArgs(os.Args[1:]) 62 63 if args.Command == "" { 64 printUsage() 65 return newExecError(nil) 66 } 67 68 updater := NewUpdater() 69 err := updater.PromptForUpdate() 70 utils.Check(err) 71 72 expandAlias(args) 73 74 cmd := r.Lookup(args.Command) 75 if cmd != nil && cmd.Runnable() { 76 return r.Call(cmd, args) 77 } 78 79 err = git.Spawn(args.Command, args.Params...) 80 return newExecError(err) 81 } 82 83 func (r *Runner) Call(cmd *Command, args *Args) ExecError { 84 err := cmd.Call(args) 85 if err != nil { 86 if err == flag.ErrHelp { 87 err = nil 88 } 89 return newExecError(err) 90 } 91 92 cmds := args.Commands() 93 if args.Noop { 94 printCommands(cmds) 95 } else { 96 err = executeCommands(cmds) 97 } 98 99 return newExecError(err) 100 } 101 102 func printCommands(cmds []*cmd.Cmd) { 103 for _, c := range cmds { 104 fmt.Println(c) 105 } 106 } 107 108 func executeCommands(cmds []*cmd.Cmd) error { 109 for _, c := range cmds { 110 err := c.Exec() 111 if err != nil { 112 return err 113 } 114 } 115 116 return nil 117 } 118 119 func expandAlias(args *Args) { 120 cmd := args.Command 121 expandedCmd, err := git.Alias(cmd) 122 if err == nil && expandedCmd != "" { 123 words, e := splitAliasCmd(expandedCmd) 124 if e == nil { 125 args.Command = words[0] 126 args.PrependParams(words[1:]...) 127 } 128 } 129 } 130 131 func splitAliasCmd(cmd string) ([]string, error) { 132 if cmd == "" { 133 return nil, fmt.Errorf("alias can't be empty") 134 } 135 136 if strings.HasPrefix(cmd, "!") { 137 return nil, fmt.Errorf("alias starting with ! can't be split") 138 } 139 140 words, err := shellquote.Split(cmd) 141 if err != nil { 142 return nil, err 143 } 144 145 return words, nil 146 }