diff --git a/cli/internal/error.go b/cli/internal/error.go new file mode 100644 index 00000000..ca1a24bf --- /dev/null +++ b/cli/internal/error.go @@ -0,0 +1,64 @@ +package internal + +import ( + "fmt" + "runtime" + + "github.com/charmbracelet/log" +) + +func Error(msg string) HelpError { + caller := "" + if Debug { + _, file, line, _ := runtime.Caller(1) + caller = log.ShortCallerFormatter(file, line, "") + + } + return HelpError{err: msg, caller: caller} +} + +func Errorf(format string, a ...any) HelpError { + caller := "" + if Debug { + _, file, line, _ := runtime.Caller(1) + caller = log.ShortCallerFormatter(file, line, "") + + } + return HelpError{err: fmt.Sprintf(format, a...), caller: caller} +} + +type HelpError struct { + err string + caller string + help string +} + +func (e HelpError) Help(help string) HelpError { + e.help = help + return e +} + +func (e HelpError) Helpf(format string, a ...any) HelpError { + e.help = fmt.Sprintf(format, a...) + return e +} + +func (e HelpError) Error() string { + return e.format() +} + +func (e HelpError) format() string { + msg := "" + if e.caller != "" { + msg += fmt.Sprintf("<%s> ", e.caller) + } + + msg += e.err + if e.help == "" { + return msg + } + + return fmt.Sprintf(`%s + +Help: %s `, msg, e.help) +} diff --git a/cli/run.go b/cli/run.go index 104b3bf2..5c09a602 100644 --- a/cli/run.go +++ b/cli/run.go @@ -66,6 +66,8 @@ func Run(version, commit string) { } rootCmd.CompletionOptions.DisableDefaultCmd = true + // This prevents displaying usage for errors returned from RunE + rootCmd.SilenceUsage = true manCommand := &cobra.Command{ Use: "man [flags]", diff --git a/cli/server/add.go b/cli/server/add.go index 2a99b650..75c846fa 100644 --- a/cli/server/add.go +++ b/cli/server/add.go @@ -1,6 +1,8 @@ package server import ( + "errors" + "fmt" "os" "path/filepath" @@ -41,19 +43,20 @@ developer machine. The domain is then set to "default".`, ValidArgsFunction: func( cmd *cobra.Command, args []string, - toComplete string) ([]string, cobra.ShellCompDirective) { + toComplete string, + ) ([]string, cobra.ShellCompDirective) { if !local { return autocomplete.ServerNameComplete() } return nil, cobra.ShellCompDirectiveDefault }, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if len(args) > 0 && local { - log.Fatal("cannot use [server] and --local together") + return errors.New("cannot use [server] and --local together") } if len(args) == 0 && !local { - log.Fatal("missing argument or --local/-l flag") + return errors.New("missing argument or --local/-l flag") } name := "default" @@ -69,14 +72,14 @@ developer machine. The domain is then set to "default".`, if local { created, err := createServerDir(name) if err != nil { - log.Fatal(err) + return err } log.Debugf("attempting to create client for %s", name) if _, err := client.New(name, timeout); err != nil { cleanUp(name) - log.Fatal(err) + return err } if created { @@ -85,18 +88,18 @@ developer machine. The domain is then set to "default".`, log.Warn("local server already exists") } - return + return nil } _, err := createServerDir(name) if err != nil { - log.Fatal(err) + return err } created, err := newContext(name) if err != nil { cleanUp(name) - log.Fatalf("unable to create local context: %s", err) + return fmt.Errorf("unable to create local context: %s", err) } log.Debugf("attempting to create client for %s", name) @@ -104,7 +107,7 @@ developer machine. The domain is then set to "default".`, if _, err := client.New(name, timeout); err != nil { cleanUp(name) log.Debugf("ssh %s error: %s", name, sshPkg.Fatal(name, err)) - log.Fatalf("can't ssh to %s, make sure \"ssh %s\" works", name, name) + return internal.Errorf("can't ssh to %s", name).Helpf("make sure \"ssh %s\" works", name) } if created { @@ -114,10 +117,11 @@ developer machine. The domain is then set to "default".`, log.Warnf("unable to resolve IPv4 for %s", name) } - return + return nil } log.Warnf("%s already exists", name) + return nil }, } @@ -189,9 +193,7 @@ func createServerDir(name string) (bool, error) { return true, nil } -var ( - local bool -) +var local bool func init() { ServerAddCommand.Flags().BoolVarP(