github.com/chasestarr/deis@v1.13.5-0.20170519182049-1d9e59fbdbfc/client/deis.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "strings" 8 "syscall" 9 10 "github.com/deis/deis/client/parser" 11 docopt "github.com/docopt/docopt-go" 12 ) 13 14 const extensionPrefix = "deis-" 15 16 // main exits with the return value of Command(os.Args[1:]), deferring all logic to 17 // a func we can test. 18 func main() { 19 os.Exit(Command(os.Args[1:])) 20 } 21 22 // Command routes deis commands to their proper parser. 23 func Command(argv []string) int { 24 usage := ` 25 The Deis command-line client issues API calls to a Deis controller. 26 27 Usage: deis <command> [<args>...] 28 29 Option flags:: 30 31 -h --help display help information 32 -v --version display client version 33 34 Auth commands:: 35 36 register register a new user with a controller 37 login login to a controller 38 logout logout from the current controller 39 40 Subcommands, use 'deis help [subcommand]' to learn more:: 41 42 apps manage applications used to provide services 43 ps manage processes inside an app container 44 config manage environment variables that define app config 45 domains manage and assign domain names to your applications 46 builds manage builds created using 'git push' 47 limits manage resource limits for your application 48 tags manage tags for application containers 49 releases manage releases of an application 50 certs manage SSL endpoints for an app 51 52 keys manage ssh keys used for 'git push' deployments 53 perms manage permissions for applications 54 git manage git for applications 55 users manage users 56 version display client version 57 58 Shortcut commands, use 'deis shortcuts' to see all:: 59 60 create create a new application 61 scale scale processes by type (web=2, worker=1) 62 info view information about the current app 63 open open a URL to the app in a browser 64 logs view aggregated log info for the app 65 run run a command in an ephemeral app container 66 destroy destroy an application 67 pull imports an image and deploys as a new release 68 69 Use 'git push deis master' to deploy to an application. 70 ` 71 // Reorganize some command line flags and commands. 72 command, argv := parseArgs(argv) 73 // Give docopt an optional final false arg so it doesn't call os.Exit(). 74 _, err := docopt.Parse(usage, []string{command}, false, "", true, false) 75 76 if err != nil { 77 fmt.Fprintln(os.Stderr, err) 78 return 1 79 } 80 81 if len(argv) == 0 { 82 fmt.Fprintln(os.Stderr, "Usage: deis <command> [<args>...]") 83 return 1 84 } 85 86 // Dispatch the command, passing the argv through so subcommands can 87 // re-parse it according to their usage strings. 88 switch command { 89 case "auth": 90 err = parser.Auth(argv) 91 case "ps": 92 err = parser.Ps(argv) 93 case "apps": 94 err = parser.Apps(argv) 95 case "config": 96 err = parser.Config(argv) 97 case "domains": 98 err = parser.Domains(argv) 99 case "builds": 100 err = parser.Builds(argv) 101 case "limits": 102 err = parser.Limits(argv) 103 case "tags": 104 err = parser.Tags(argv) 105 case "releases": 106 err = parser.Releases(argv) 107 case "certs": 108 err = parser.Certs(argv) 109 case "keys": 110 err = parser.Keys(argv) 111 case "perms": 112 err = parser.Perms(argv) 113 case "git": 114 err = parser.Git(argv) 115 case "users": 116 err = parser.Users(argv) 117 case "version": 118 err = parser.Version(argv) 119 case "help": 120 fmt.Print(usage) 121 return 0 122 default: 123 env := os.Environ() 124 125 binary, err := exec.LookPath(extensionPrefix + command) 126 if err != nil { 127 parser.PrintUsage() 128 return 1 129 } 130 131 cmdArgv := prepareCmdArgs(command, argv) 132 133 err = syscall.Exec(binary, cmdArgv, env) 134 if err != nil { 135 parser.PrintUsage() 136 return 1 137 } 138 } 139 if err != nil { 140 fmt.Fprintf(os.Stderr, "Error: %v\n", err) 141 return 1 142 } 143 return 0 144 } 145 146 // parseArgs returns the provided args with "--help" as the last arg if need be, 147 // expands shortcuts and formats commands to be properly routed. 148 func parseArgs(argv []string) (string, []string) { 149 if len(argv) == 1 { 150 if argv[0] == "--help" || argv[0] == "-h" { 151 // rearrange "deis --help" as "deis help" 152 argv[0] = "help" 153 } else if argv[0] == "--version" || argv[0] == "-v" { 154 // rearrange "deis --version" as "deis version" 155 argv[0] = "version" 156 } 157 } 158 159 if len(argv) >= 2 { 160 // Rearrange "deis help <command>" to "deis <command> --help". 161 if argv[0] == "help" || argv[0] == "--help" || argv[0] == "-h" { 162 argv = append(argv[1:], "--help") 163 } 164 } 165 166 if len(argv) > 0 { 167 argv[0] = replaceShortcut(argv[0]) 168 169 index := strings.Index(argv[0], ":") 170 171 if index != -1 { 172 command := argv[0] 173 return command[:index], argv 174 } 175 176 return argv[0], argv 177 } 178 179 return "", argv 180 } 181 182 // split original command and pass its first element in arguments 183 func prepareCmdArgs(command string, argv []string) []string { 184 cmdArgv := []string{extensionPrefix + command} 185 cmdSplit := strings.Split(argv[0], command+":") 186 187 if len(cmdSplit) > 1 { 188 cmdArgv = append(cmdArgv, cmdSplit[1]) 189 } 190 191 return append(cmdArgv, argv[1:]...) 192 } 193 194 func replaceShortcut(command string) string { 195 shortcuts := map[string]string{ 196 "create": "apps:create", 197 "destroy": "apps:destroy", 198 "info": "apps:info", 199 "login": "auth:login", 200 "logout": "auth:logout", 201 "logs": "apps:logs", 202 "open": "apps:open", 203 "passwd": "auth:passwd", 204 "pull": "builds:create", 205 "register": "auth:register", 206 "rollback": "releases:rollback", 207 "run": "apps:run", 208 "scale": "ps:scale", 209 "sharing": "perms:list", 210 "sharing:list": "perms:list", 211 "sharing:add": "perms:create", 212 "sharing:remove": "perms:delete", 213 "whoami": "auth:whoami", 214 } 215 216 expandedCommand := shortcuts[command] 217 if expandedCommand == "" { 218 return command 219 } 220 221 return expandedCommand 222 }