github.com/bigcommerce/nomad@v0.9.3-bc/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "os" 8 "sort" 9 "strings" 10 "text/tabwriter" 11 12 "github.com/hashicorp/nomad/command" 13 "github.com/hashicorp/nomad/drivers/docker/docklog" 14 "github.com/hashicorp/nomad/version" 15 "github.com/mattn/go-colorable" 16 "github.com/mitchellh/cli" 17 "github.com/sean-/seed" 18 "golang.org/x/crypto/ssh/terminal" 19 ) 20 21 var ( 22 // Hidden hides the commands from both help and autocomplete. Commands that 23 // users should not be running should be placed here, versus hiding 24 // subcommands from the main help, which should be filtered out of the 25 // commands above. 26 hidden = []string{ 27 "alloc-status", 28 "check", 29 "client-config", 30 "eval-status", 31 "executor", 32 "keygen", 33 "keyring", 34 "logmon", 35 "node-drain", 36 "node-status", 37 "server-force-leave", 38 "server-join", 39 "server-members", 40 "syslog", 41 docklog.PluginName, 42 } 43 44 // aliases is the list of aliases we want users to be aware of. We hide 45 // these form the help output but autocomplete them. 46 aliases = []string{ 47 "fs", 48 "init", 49 "inspect", 50 "logs", 51 "plan", 52 "validate", 53 } 54 55 // Common commands are grouped separately to call them out to operators. 56 commonCommands = []string{ 57 "run", 58 "stop", 59 "status", 60 "alloc", 61 "job", 62 "node", 63 "agent", 64 } 65 ) 66 67 func init() { 68 seed.Init() 69 } 70 71 func main() { 72 os.Exit(Run(os.Args[1:])) 73 } 74 75 func Run(args []string) int { 76 return RunCustom(args) 77 } 78 79 func RunCustom(args []string) int { 80 // Parse flags into env vars for global use 81 args = setupEnv(args) 82 83 // Create the meta object 84 metaPtr := new(command.Meta) 85 86 // Don't use color if disabled 87 color := true 88 if os.Getenv(command.EnvNomadCLINoColor) != "" { 89 color = false 90 } 91 92 isTerminal := terminal.IsTerminal(int(os.Stdout.Fd())) 93 metaPtr.Ui = &cli.BasicUi{ 94 Reader: os.Stdin, 95 Writer: colorable.NewColorableStdout(), 96 ErrorWriter: colorable.NewColorableStderr(), 97 } 98 99 // The Nomad agent never outputs color 100 agentUi := &cli.BasicUi{ 101 Reader: os.Stdin, 102 Writer: os.Stdout, 103 ErrorWriter: os.Stderr, 104 } 105 106 // Only use colored UI if stdout is a tty, and not disabled 107 if isTerminal && color { 108 metaPtr.Ui = &cli.ColoredUi{ 109 ErrorColor: cli.UiColorRed, 110 WarnColor: cli.UiColorYellow, 111 InfoColor: cli.UiColorGreen, 112 Ui: metaPtr.Ui, 113 } 114 } 115 116 commands := command.Commands(metaPtr, agentUi) 117 cli := &cli.CLI{ 118 Name: "nomad", 119 Version: version.GetVersion().FullVersionNumber(true), 120 Args: args, 121 Commands: commands, 122 HiddenCommands: hidden, 123 Autocomplete: true, 124 AutocompleteNoDefaultFlags: true, 125 HelpFunc: groupedHelpFunc( 126 cli.BasicHelpFunc("nomad"), 127 ), 128 HelpWriter: os.Stdout, 129 } 130 131 exitCode, err := cli.Run() 132 if err != nil { 133 fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error()) 134 return 1 135 } 136 137 return exitCode 138 } 139 140 func groupedHelpFunc(f cli.HelpFunc) cli.HelpFunc { 141 return func(commands map[string]cli.CommandFactory) string { 142 var b bytes.Buffer 143 tw := tabwriter.NewWriter(&b, 0, 2, 6, ' ', 0) 144 145 fmt.Fprintf(tw, "Usage: nomad [-version] [-help] [-autocomplete-(un)install] <command> [args]\n\n") 146 fmt.Fprintf(tw, "Common commands:\n") 147 for _, v := range commonCommands { 148 printCommand(tw, v, commands[v]) 149 } 150 151 // Filter out common commands and aliased commands from the other 152 // commands output 153 otherCommands := make([]string, 0, len(commands)) 154 for k := range commands { 155 found := false 156 for _, v := range commonCommands { 157 if k == v { 158 found = true 159 break 160 } 161 } 162 163 for _, v := range aliases { 164 if k == v { 165 found = true 166 break 167 } 168 } 169 170 if !found { 171 otherCommands = append(otherCommands, k) 172 } 173 } 174 sort.Strings(otherCommands) 175 176 fmt.Fprintf(tw, "\n") 177 fmt.Fprintf(tw, "Other commands:\n") 178 for _, v := range otherCommands { 179 printCommand(tw, v, commands[v]) 180 } 181 182 tw.Flush() 183 184 return strings.TrimSpace(b.String()) 185 } 186 } 187 188 func printCommand(w io.Writer, name string, cmdFn cli.CommandFactory) { 189 cmd, err := cmdFn() 190 if err != nil { 191 panic(fmt.Sprintf("failed to load %q command: %s", name, err)) 192 } 193 fmt.Fprintf(w, " %s\t%s\n", name, cmd.Synopsis()) 194 } 195 196 // setupEnv parses args and may replace them and sets some env vars to known 197 // values based on format options 198 func setupEnv(args []string) []string { 199 noColor := false 200 for _, arg := range args { 201 // Check if color is set 202 if arg == "-no-color" || arg == "--no-color" { 203 noColor = true 204 } 205 } 206 207 // Put back into the env for later 208 if noColor { 209 os.Setenv(command.EnvNomadCLINoColor, "true") 210 } 211 212 return args 213 }