github.com/pengwynn/gh@v1.0.1-0.20140118055701-14327ca3942e/commands/runner.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "github.com/jingweno/gh/cmd" 6 "github.com/jingweno/gh/git" 7 "github.com/jingweno/gh/utils" 8 "github.com/kballard/go-shellquote" 9 flag "github.com/ogier/pflag" 10 "os" 11 "os/exec" 12 "strings" 13 "syscall" 14 ) 15 16 type ExecError struct { 17 Err error 18 ExitCode int 19 } 20 21 func (execError *ExecError) Error() string { 22 return execError.Err.Error() 23 } 24 25 func newExecError(err error) ExecError { 26 exitCode := 0 27 if err != nil { 28 exitCode = 1 29 if exitError, ok := err.(*exec.ExitError); ok { 30 if status, ok := exitError.Sys().(syscall.WaitStatus); ok { 31 exitCode = status.ExitStatus() 32 } 33 } 34 } 35 36 return ExecError{Err: err, ExitCode: exitCode} 37 } 38 39 type Runner struct { 40 commands map[string]*Command 41 } 42 43 func NewRunner() *Runner { 44 return &Runner{commands: make(map[string]*Command)} 45 } 46 47 func (r *Runner) All() map[string]*Command { 48 return r.commands 49 } 50 51 func (r *Runner) Use(command *Command) { 52 r.commands[command.Name()] = command 53 } 54 55 func (r *Runner) Lookup(name string) *Command { 56 return r.commands[name] 57 } 58 59 func (r *Runner) Execute() ExecError { 60 args := NewArgs(os.Args[1:]) 61 62 if args.Command == "" { 63 printUsage() 64 return newExecError(nil) 65 } 66 67 updater := NewUpdater() 68 err := updater.PromptForUpdate() 69 utils.Check(err) 70 71 expandAlias(args) 72 slurpGlobalFlags(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 slurpGlobalFlags(args *Args) { 103 for i, p := range args.Params { 104 if p == "--noop" { 105 args.Noop = true 106 args.RemoveParam(i) 107 } 108 } 109 } 110 111 func printCommands(cmds []*cmd.Cmd) { 112 for _, c := range cmds { 113 fmt.Println(c) 114 } 115 } 116 117 func executeCommands(cmds []*cmd.Cmd) error { 118 for _, c := range cmds { 119 err := c.Exec() 120 if err != nil { 121 return err 122 } 123 } 124 125 return nil 126 } 127 128 func expandAlias(args *Args) { 129 cmd := args.Command 130 expandedCmd, err := git.Alias(cmd) 131 if err == nil && expandedCmd != "" { 132 words, e := splitAliasCmd(expandedCmd) 133 if e == nil { 134 args.Command = words[0] 135 args.PrependParams(words[1:]...) 136 } 137 } 138 } 139 140 func splitAliasCmd(cmd string) ([]string, error) { 141 if cmd == "" { 142 return nil, fmt.Errorf("alias can't be empty") 143 } 144 145 if strings.HasPrefix(cmd, "!") { 146 return nil, fmt.Errorf("alias starting with ! can't be split") 147 } 148 149 words, err := shellquote.Split(cmd) 150 if err != nil { 151 return nil, err 152 } 153 154 return words, nil 155 }