// printHelp dispatches into individual defined commands to find their help, as // needed func printHelp(stream *os.File) { if _, help, err := cli.NewCmd("help"); err == nil { help.RunCli() } else { fmt.Fprintln(os.Stderr, "help command not defined") } }
func main() { var exitcode int // defer os.Exit first since it would cancel any previous defers. defer func() { os.Exit(exitcode) }() // Handle any panic not caught at command-level. defer func() { if r := recover(); r != nil { // Dump the stack with information about what command was being run. cli.PanicStack = make([]byte, 1<<20) // 1 MB runtime.Stack(cli.PanicStack, true) header := "Panic within CLI\n\n" // Extend to make room for header. cli.PanicStack = append(cli.PanicStack, make([]byte, len(header))...) copy(cli.PanicStack[len(header):], cli.PanicStack) copy(cli.PanicStack[:len(header)], header) reportPanic() } }() handleSignals() // Special handling of flags to avoid calling flag.Parse() here. Commands // use flag.Flagsets and we don't want to interfere. if len(os.Args) == 1 { printHelp(os.Stderr) exitcode = 1 return } else if len(os.Args) == 2 { switch os.Args[1] { case "-v", "--v", "-version", "--version": if _, ver, err := cli.NewCmd("version"); err == nil { ver.RunCli() } else { fmt.Fprintln(os.Stderr, "version command not defined") } return case "-h", "--h", "-help", "--help": printHelp(os.Stdout) exitcode = 0 return } } // Find the command cmdDef, cmd, err := cli.NewCmd(os.Args[1:]...) if err != nil { exitcode = 1 // Print help and error if command was found but args were incorrect. // e.g. any validation errors returned are surfaced here. if cmdDef != nil { cmdDef.PrintHelp(os.Stderr) // Hide any 'help requested' errors from bubbling up, but still show // usage errors. if err.Error() == "flag: help requested" { return } } fmt.Fprintf(os.Stderr, terminal.Colorize(terminal.ColorError, "Error (usage): %s\n"), err) exitcode = 1 return } // Catch any other '--version' flags. While instances of "apc --version", etc // will be caught above in our len(os.Args) case, we want to take example input // like "apc app --version" just in case. if cli.ShowVersion { if _, ver, err := cli.NewCmd("version"); err == nil { ver.RunCli() } else { fmt.Fprintln(os.Stderr, "version command not defined") } return } conn, err := grpc.Dial(determineKurmaHostPort()) if err != nil { fmt.Fprintf(os.Stderr, terminal.Colorize(terminal.ColorError, ERROR_PREFIX+"%s\n"), err.Error()) exitcode = 1 return } defer conn.Close() cmd.Client = pb.NewKurmaClient(conn) exitcode = runCommand(cmd) }