1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
package cli
import (
"context"
"errors"
"io"
"os"
"github.com/spf13/pflag"
"tsne.dev/hopper/internal/log"
)
// Run executes the CLI and returns the process exit code.
//
// Note: Help paths will call exit directly.
func Run(ctx context.Context, args []string) int {
main := newMainCommand()
err := runCommand(ctx, main, args)
if err != nil {
var exit exitError
if errors.As(err, &exit) {
return exit.code
}
var ev errorVerboser
if errors.As(err, &ev) {
log.Error("%s\n %s", err.Error(), ev.ErrorVerbose())
} else {
log.Error(err.Error())
}
return 1
}
return 0
}
type command interface {
Usage() string
Run(ctx context.Context, args []string) error
}
func parseFlags(cmd command, flags *pflag.FlagSet, args []string) {
err := flags.Parse(args)
if err != nil {
if errors.Is(err, pflag.ErrHelp) {
log.Print(cmd.Usage())
os.Exit(0)
} else {
log.Error("%s\n\n%s", err.Error(), cmd.Usage())
os.Exit(2)
}
}
}
func runCommand(ctx context.Context, cmd command, args []string) error {
err := cmd.Run(ctx, args)
if err != nil {
var usageErr usageError
if errors.As(err, &usageErr) {
log.Error("%s\n\n%s", usageErr.msg, cmd.Usage())
os.Exit(2)
}
return err
}
return nil
}
func newFlagset(name string) *pflag.FlagSet {
fs := pflag.NewFlagSet(name, pflag.ContinueOnError)
fs.SetOutput(io.Discard)
fs.Usage = func() {}
return fs
}
|