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