This repository has been archived by the owner on Oct 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
run.go
119 lines (98 loc) · 2.63 KB
/
run.go
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package cli
import (
"os"
"strings"
"github.com/spf13/pflag"
)
type aliasMap map[Command][]string
func appendParent(parent string, add string) string {
return parent + add + " "
}
// splitArgs tries to split the args between the parent command's flags/args, and the subcommand's
// flags/args. If a subcommand is found, the parent args, subcommand args, and the subcommand will
// be returned. If a subcommand isn't found, the args will be returned as is, the subcommand args
// will be empty, and the subcommand will be nil.
func splitArgs(subCmds []Command, args []string, aliases aliasMap) (cmdArgs, subArgs []string, subCmd Command) {
for i, arg := range args {
if strings.HasPrefix(arg, "-") {
continue
}
for _, subCommand := range subCmds {
spec := subCommand.Spec()
if spec.HasAliases() {
for _, alias := range spec.Aliases {
if arg == alias {
return args[:i], args[i+1:], subCommand
}
}
}
if spec.Name == arg {
return args[:i], args[i+1:], subCommand
}
}
}
return args, []string{}, nil
}
// Run sets up flags, helps, and executes the command with the provided
// arguments.
//
// parents is the list of parent commands.
// E.g the parent for `sail run hello` would be `sail run`.
//
// Use RunRoot if this package is managing the entire CLI.
func Run(cmd Command, args []string, parent string) {
name := parent + cmd.Spec().Name
fl := pflag.NewFlagSet(name, pflag.ContinueOnError)
// Ensure pflag library doesn't print usage for us automatically,
// we'll override this below.
fl.Usage = func() {}
if fc, ok := cmd.(FlaggedCommand); ok {
fc.RegisterFlags(fl)
}
if cmd.Spec().RawArgs {
// Use `--` to return immediately when parsing the flags.
args = append([]string{"--"}, args...)
}
var (
cmdArgs, subArgs []string
subCmd Command
)
pc, isParentCmd := cmd.(ParentCommand)
if isParentCmd {
aliases := make(aliasMap)
subCmds := pc.Subcommands()
for _, sc := range subCmds {
spec := sc.Spec()
if spec.HasAliases() {
aliases[sc] = spec.Aliases
}
}
cmdArgs, subArgs, subCmd = splitArgs(subCmds, args, aliases)
if subCmd != nil {
args = cmdArgs
}
}
err := fl.Parse(args)
// Reassign the usage now that we've parsed the args
// so that we can render it manually.
fl.Usage = func() {
renderHelp(os.Stderr, name, cmd, fl)
}
if err != nil {
fl.Usage()
os.Exit(2)
}
// Route to subcommand.
if isParentCmd && subCmd != nil {
Run(
subCmd, subArgs,
appendParent(parent, cmd.Spec().Name),
)
return
}
cmd.Run(fl)
}
// RunRoot calls Run with the process's arguments.
func RunRoot(cmd Command) {
Run(cmd, os.Args[1:], "")
}