this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cmd/cue: refactor our use of cobra

Our API in cmd/cue/cmd was somewhat confused;
the New function was only meant to create the root command,
but it also returned an error as it had to do more work upfront.
In particular, it tried to interpret arguments and flags to support:

1) `cue mycmd` being a shortcut to `cue cmd mycmd`

2) `cue help cmd` and `cue help cmd mycmd` loading custom command info

This code was messy and has caused bugs in the past,
such as `cue help` loading the current package unnecessarily (#2161),
or TestHelp being chatty since New could print usage text
before cobra.Command.SetOutput could be called (#1694).

Instead, make New do very little work, and offload the two cases above:

1) Allow the root command to take arbitrary arguments,
meaning that its RunE func is used as a fallback when the first
argument does not match any built-in sub-command like `fix`.
Said RunE func is simply forwarded to `cue cmd`,
which is taught how to load `*_tool.cue` files just like New used to,
to then run the specified command.

2) Add our own custom "help" command, a version of cobra's default
which knows how to load `*_tool.cue` files and add all of their
custom commands when using `cue help cmd [args]`.

For consistency with "help" now being our own command and not cobra's,
make the "-h" or "--help" flag our own, and hide it from the usage text.

We also slightly improve the output from `cue foo` and `cue cmd foo`
when "foo" is not a known built-in nor custom command,
which can be seen from the changes in testdata.

While here, update the version of cobra as well.

Finally, add copious amounts of documentation to the tricky bits,
because it took some digging to figure out how to make it work well.

Note that a bit more cleanup can be done in the other subcommands,
but this CL focuses on "cmd" and "help" as they were the biggest ones.

Also note that we don't change the API for New and Command.Run,
although New always returns a nil error and args are only used by Run,
because it feels like unnecessary churn to break the API right now.
Plus, this refactor is already large enough as it is.

Fixes #1694.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: Iabe6e5724e2da9afbab8897fa22b49883e195733
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/552733
Unity-Result: CUEcueckoo <cueckoo@cuelang.org>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Reviewed-by: Roger Peppe <rogpeppe@gmail.com>

+182 -226
+38 -10
cmd/cue/cmd/cmd.go
··· 16 16 17 17 import ( 18 18 "fmt" 19 - "os" 20 19 21 20 "github.com/spf13/cobra" 21 + "github.com/spf13/pflag" 22 22 ) 23 23 24 24 // TODO: generate long description from documentation. ··· 133 133 Run "cue help commands" for more details on tasks and commands. 134 134 `, 135 135 RunE: mkRunE(c, func(cmd *Command, args []string) error { 136 - w := cmd.Stderr() 136 + // The behavior when there's no known subcommand is different 137 + // depending on whether we ran via `cue cmd` or the `cue` shortcut. 138 + isRootCmd := cmd.Command == cmd.root 139 + 140 + // TODO(mvdan): test running `cue` and `cue cmd` via testscript as well 137 141 if len(args) == 0 { 142 + // `cue` should print the top-level help like `cue -h`, 143 + // but `cue cmd` should explain that a custom command is required. 144 + if isRootCmd { 145 + return pflag.ErrHelp 146 + } 147 + w := cmd.OutOrStderr() 138 148 fmt.Fprintln(w, "cmd must be run as one of its subcommands") 139 - } else { 140 - const msg = `cmd must be run as one of its subcommands: unknown subcommand %q 141 - Ensure commands are defined in a "_tool.cue" file. 142 - ` 143 - fmt.Fprintf(w, msg, args[0]) 149 + fmt.Fprintln(w, "Run 'cue help cmd' for known subcommands.") 150 + return ErrPrintedError 144 151 } 145 - fmt.Fprintln(w, "Run 'cue help cmd' for known subcommands.") 146 - os.Exit(1) // TODO: get rid of this 147 - return nil 152 + tools, err := buildTools(cmd, args[1:]) 153 + if err != nil && !isRootCmd { 154 + // `cue cmd` fails immediately if there is no CUE package, 155 + // but `cue` does not in order to always show a useful error in `cue typo`. 156 + return err 157 + } 158 + sub, err := customCommand(cmd, commandSection, args[0], tools) 159 + if err != nil { 160 + w := cmd.OutOrStderr() 161 + cmdline := "cue" 162 + if !isRootCmd { 163 + cmdline += " cmd" 164 + } 165 + fmt.Fprintf(w, "unknown '%s' subcommand: %q\n\n", cmdline, args[0]) 166 + fmt.Fprintln(w, `Ensure custom commands are defined in a "_tool.cue" file.`) 167 + fmt.Fprintln(w, "Run 'cue help cmd' to list available custom commands.") 168 + if isRootCmd { 169 + fmt.Fprintln(w, "Run 'cue help' to see the built-in 'cue' commands.") 170 + } 171 + return ErrPrintedError 172 + } 173 + // Presumably the *cobra.Command argument should be cmd.Command, 174 + // as that is the one which will have the right settings applied. 175 + return sub.RunE(cmd.Command, args[1:]) 148 176 }), 149 177 } 150 178
-1
cmd/cue/cmd/common.go
··· 773 773 } 774 774 775 775 func buildTools(cmd *Command, args []string) (*cue.Instance, error) { 776 - 777 776 cfg := &load.Config{ 778 777 Tools: true, 779 778 }
+23 -5
cmd/cue/cmd/custom.go
··· 39 39 "cuelang.org/go/tools/flow" 40 40 ) 41 41 42 - const ( 43 - commandSection = "command" 44 - ) 42 + const commandSection = "command" 45 43 46 44 func lookupString(obj cue.Value, key, def string) string { 47 45 str, err := obj.Lookup(key).String() ··· 60 58 return 61 59 } 62 60 63 - func addCustom(c *Command, parent *cobra.Command, typ, name string, tools *cue.Instance) (*cobra.Command, error) { 61 + // addCustomCommands iterates over all commands defined under field typ 62 + // and adds them as cobra subcommands to cmd. 63 + // The func is only used in `cue help cmd`, which doesn't show errors. 64 + func addCustomCommands(c *Command, cmd *cobra.Command, typ string, tools *cue.Instance) { 65 + commands := tools.Lookup(typ) 66 + if !commands.Exists() { 67 + return 68 + } 69 + fields, err := commands.Fields() 70 + if err != nil { 71 + return 72 + } 73 + for fields.Next() { 74 + sub, err := customCommand(c, commandSection, fields.Label(), tools) 75 + if err == nil { 76 + cmd.AddCommand(sub) 77 + } 78 + } 79 + } 80 + 81 + // customCommand creates a cobra.Command out of a CUE command definition. 82 + func customCommand(c *Command, typ, name string, tools *cue.Instance) (*cobra.Command, error) { 64 83 if tools == nil { 65 84 return nil, errors.New("no commands defined") 66 85 } ··· 116 135 return doTasks(cmd, typ, name, tools) 117 136 }), 118 137 } 119 - parent.AddCommand(sub) 120 138 121 139 // TODO: implement var/flag handling. 122 140 return sub, nil
+45
cmd/cue/cmd/help.go
··· 25 25 // The user can then scroll up to get a more in-depth explanation. But is 26 26 // this how users use it? 27 27 28 + // newHelpCmd is largely borrowed from cobra, 29 + // but knows how to load custom commands in `cue help cmd`. 30 + func newHelpCmd(c *Command) *cobra.Command { 31 + cmd := &cobra.Command{ 32 + Use: "help [command]", 33 + Short: "Help about any command", 34 + Long: `Help provides help for any command in the application. 35 + Simply type ` + c.Name() + ` help [path to command] for full details.`, 36 + Run: func(_ *cobra.Command, args []string) { 37 + cmd, _, e := c.Root().Find(args) 38 + if len(args) > 0 && args[0] == "cmd" { 39 + // args is one of: 40 + // 41 + // ["cmd"] 42 + // ["cmd", "mycmd"] 43 + // ["cmd", "mycmd", "./mypkg"] 44 + // 45 + // We want to skip the first two arguments in pkgArgs. 46 + pkgArgs := args[1:] 47 + if len(pkgArgs) > 0 { 48 + pkgArgs = pkgArgs[1:] 49 + } 50 + 51 + tools, err := buildTools(c, pkgArgs) 52 + if err == nil { 53 + addCustomCommands(c, cmd, commandSection, tools) 54 + // For the sake of `cue help cmd mycmd`, find the command again. 55 + cmd, _, e = c.Root().Find(args) 56 + } 57 + } 58 + if cmd == nil || e != nil { 59 + c.Printf("Unknown help topic %#q\n", args) 60 + cobra.CheckErr(c.Root().Usage()) 61 + } else { 62 + cobra.CheckErr(cmd.Help()) 63 + } 64 + }, 65 + } 66 + return cmd 67 + } 68 + 69 + // TODO(mvdan): having the help topics as top-level commands means that `cue topic` 70 + // is taken and works as well as `cue help topic`, which is unnecessary. 71 + // Consider removing support for the short form at some point. 72 + 28 73 func newHelpTopics(c *Command) []*cobra.Command { 29 74 return []*cobra.Command{ 30 75 inputsHelp,
+35 -163
cmd/cue/cmd/root.go
··· 18 18 "context" 19 19 "io" 20 20 "os" 21 - "strings" 22 21 23 22 "github.com/spf13/cobra" 24 - "github.com/spf13/pflag" 25 23 26 24 "cuelang.org/go/cue" 27 25 "cuelang.org/go/cue/cuecontext" 28 26 "cuelang.org/go/cue/errors" 29 - "cuelang.org/go/cue/token" 30 27 "cuelang.org/go/internal/core/adt" 31 28 "cuelang.org/go/internal/encoding" 32 29 "cuelang.org/go/internal/filetypes" ··· 71 68 statsEnc := statsEncoder(c) 72 69 73 70 err := f(c, args) 74 - if err != nil { 75 - exitOnErr(c, err, true) 76 - } 77 71 78 72 if statsEnc != nil { 79 73 statsEnc.Encode(c.ctx.Encode(adt.TotalStats())) ··· 83 77 } 84 78 } 85 79 86 - // newRootCmd creates the base command when called without any subcommands 87 - func newRootCmd() *Command { 80 + // TODO(mvdan): remove this error return at some point. 81 + // The API could also be made clearer if we want to keep cmd public, 82 + // such as not leaking *cobra.Command via embedding. 83 + 84 + // New creates the top-level command. 85 + // The returned error is always nil, and is a historical artifact. 86 + func New(args []string) (*Command, error) { 88 87 cmd := &cobra.Command{ 89 88 Use: "cue", 90 89 Short: "cue emits configuration files to user-defined commands.", ··· 106 105 run 'cue help cmd' or go to cuelang.org/pkg/cmd. 107 106 108 107 For more information on writing CUE configuration files see cuelang.org.`, 109 - // Uncomment the following line if your bare application 110 - // has an action associated with it: 111 - // Run: func(cmd *cobra.Command, args []string) { }, 112 108 113 - SilenceUsage: true, 109 + // ArbitraryArgs allows us to forward the top-level RunE to cmdCmd.RunE, 110 + // which supports `cue mycmd` as a short-cut for `cue cmd mycmd`. 111 + // Without ArbitraryArgs, cobra fails with "unknown command" errors. 112 + Args: cobra.ArbitraryArgs, 113 + 114 + // We print errors ourselves in Main, which allows for ErrPrintedError. 115 + // Similarly, we don't want to print the entire help text on any error. 116 + // We can explicitly trigger help on certain errors via pflag.ErrHelp. 117 + SilenceErrors: true, 118 + SilenceUsage: true, 119 + 120 + // We currently support top-level custom commands like `cue mycmd` as an alias 121 + // for `cue cmd mycmd`, so any sub-command suggestions might be confusing. 122 + DisableSuggestions: true, 114 123 } 115 124 116 125 c := &Command{ ··· 148 157 cmd.AddCommand(sub) 149 158 } 150 159 151 - return c 160 + // Cobra's --help flag shows up in help text by default, which is unnecessary. 161 + cmd.InitDefaultHelpFlag() 162 + cmd.Flag("help").Hidden = true 163 + 164 + // "help" is treated as a special command by cobra. 165 + cmd.SetHelpCommand(newHelpCmd(c)) 166 + 167 + // For `cue mycmd` to be a shortcut for `cue cmd mycmd`. 168 + cmd.RunE = cmdCmd.RunE 169 + 170 + cmd.SetArgs(args) 171 + return c, nil 152 172 } 153 173 154 174 // MainTest is like Main, runs the cue tool and returns the code for passing to os.Exit. ··· 163 183 // Main runs the cue tool and returns the code for passing to os.Exit. 164 184 func Main() int { 165 185 cwd, _ := os.Getwd() 166 - err := mainErr(context.Background(), os.Args[1:]) 167 - if err != nil { 186 + cmd, _ := New(os.Args[1:]) 187 + if err := cmd.Run(context.Background()); err != nil { 168 188 if err != ErrPrintedError { 169 189 errors.Print(os.Stderr, err, &errors.Config{ 170 190 Cwd: cwd, ··· 176 196 return 0 177 197 } 178 198 179 - func mainErr(ctx context.Context, args []string) error { 180 - cmd, err := New(args) 181 - if err != nil { 182 - return err 183 - } 184 - return cmd.Run(ctx) 185 - } 186 - 187 199 type Command struct { 188 200 // The currently active command. 189 201 *cobra.Command ··· 262 274 panic(e) 263 275 } 264 276 // We use panic to escape, instead of os.Exit 265 - } 266 - 267 - func New(args []string) (cmd *Command, err error) { 268 - defer recoverError(&err) 269 - 270 - cmd = newRootCmd() 271 - rootCmd := cmd.root 272 - if len(args) == 0 { 273 - return cmd, nil 274 - } 275 - rootCmd.SetArgs(args) 276 - 277 - var sub = map[string]*subSpec{ 278 - "cmd": {commandSection, cmd.cmd}, 279 - // "serve": {"server", nil}, 280 - // "fix": {"fix", nil}, 281 - } 282 - 283 - if args[0] == "help" { 284 - if len(args) >= 2 && sub[args[1]] != nil { 285 - // addSubcommands adds helpful information to each of the help docs, 286 - // for example `cue help cmd` shows the available commands by loading 287 - // `*_tools.cue` files. 288 - // 289 - // Ignore errors, since this is a help command and the extra content 290 - // is an extra that shouldn't prevent help text from being shown. 291 - // 292 - // TODO: `cue cmd -h` does not trigger this, and maybe it should for 293 - // consistency with `cue help cmd`. 294 - _ = addSubcommands(cmd, sub, args[1:], true) 295 - } 296 - return cmd, nil 297 - } 298 - 299 - if _, ok := sub[args[0]]; ok { 300 - return cmd, addSubcommands(cmd, sub, args, false) 301 - } 302 - 303 - // TODO: clean this up once we either use Cobra properly or when we remove 304 - // it. 305 - err = cmd.cmd.ParseFlags(args) 306 - if err != nil { 307 - if errors.Is(err, pflag.ErrHelp) { 308 - return cmd, nil 309 - } 310 - return nil, err 311 - } 312 - 313 - args = cmd.cmd.Flags().Args() 314 - rootCmd.SetArgs(args) 315 - 316 - if c, _, err := rootCmd.Find(args); err == nil && c != nil { 317 - return cmd, nil 318 - } 319 - 320 - if !isCommandName(args[0]) { 321 - return cmd, nil // Forces unknown command message from Cobra. 322 - } 323 - 324 - tools, err := buildTools(cmd, args[1:]) 325 - if err != nil { 326 - return cmd, err 327 - } 328 - _, err = addCustom(cmd, rootCmd, commandSection, args[0], tools) 329 - if err != nil { 330 - err = errors.Newf(token.NoPos, 331 - `%s %q is not defined 332 - Ensure commands are defined in a "_tool.cue" file. 333 - Run 'cue help' to show available commands.`, 334 - commandSection, args[0], 335 - ) 336 - return cmd, err 337 - } 338 - return cmd, nil 339 - } 340 - 341 - type subSpec struct { 342 - name string 343 - cmd *cobra.Command 344 - } 345 - 346 - func addSubcommands(cmd *Command, sub map[string]*subSpec, args []string, isHelp bool) error { 347 - if len(args) > 0 { 348 - if _, ok := sub[args[0]]; ok { 349 - oldargs := []string{args[0]} 350 - args = args[1:] 351 - 352 - // Check for 'cue cmd --help|-h' 353 - // it is behaving differently for this one command, cobra does not seem to pick it up 354 - // See issue #340 355 - if len(args) == 1 && (args[0] == "--help" || args[0] == "-h") { 356 - return cmd.Usage() 357 - } 358 - 359 - if !isHelp { 360 - err := cmd.cmd.ParseFlags(args) 361 - if err != nil { 362 - return err 363 - } 364 - args = cmd.cmd.Flags().Args() 365 - cmd.root.SetArgs(append(oldargs, args...)) 366 - } 367 - } 368 - } 369 - 370 - if len(args) > 0 { 371 - if !isCommandName(args[0]) { 372 - return nil // Forces unknown command message from Cobra. 373 - } 374 - args = args[1:] 375 - } 376 - 377 - tools, err := buildTools(cmd, args) 378 - if err != nil { 379 - return err 380 - } 381 - 382 - // TODO: for now we only allow one instance. Eventually, we can allow 383 - // more if they all belong to the same package and we merge them 384 - // before computing commands. 385 - for _, spec := range sub { 386 - commands := tools.Lookup(spec.name) 387 - if !commands.Exists() { 388 - return nil 389 - } 390 - i, err := commands.Fields() 391 - if err != nil { 392 - return errors.Newf(token.NoPos, "could not create command definitions: %v", err) 393 - } 394 - for i.Next() { 395 - _, _ = addCustom(cmd, spec.cmd, spec.name, i.Label(), tools) 396 - } 397 - } 398 - return nil 399 - } 400 - 401 - func isCommandName(s string) bool { 402 - return !strings.Contains(s, `/\`) && 403 - !strings.HasPrefix(s, ".") && 404 - !strings.HasSuffix(s, ".cue") 405 277 } 406 278 407 279 type panicError struct {
+20 -17
cmd/cue/cmd/root_test.go
··· 14 14 15 15 package cmd 16 16 17 - import "testing" 17 + import ( 18 + "context" 19 + "io" 20 + "testing" 21 + ) 18 22 19 23 func TestHelp(t *testing.T) { 20 - cmd, err := New([]string{"help"}) 21 - if err != nil || cmd == nil { 24 + // TODO(mvdan): consider rewriting in testscript, capturing stdout/stderr 25 + run := func(args ...string) error { 26 + cmd, _ := New(args) 27 + cmd.SetOutput(io.Discard) 28 + ctx := context.Background() 29 + return cmd.Run(ctx) 30 + } 31 + if err := run("help"); err != nil { 22 32 t.Error("help command failed unexpectedly") 23 33 } 24 34 25 - cmd, err = New([]string{"--help"}) 26 - if err != nil || cmd == nil { 35 + if err := run("--help"); err != nil { 27 36 t.Error("help command failed unexpectedly") 28 37 } 29 38 30 - cmd, err = New([]string{"-h"}) 31 - if err != nil || cmd == nil { 39 + if err := run("-h"); err != nil { 32 40 t.Error("help command failed unexpectedly") 33 41 } 34 42 35 - cmd, err = New([]string{"help", "cmd"}) 36 - if err != nil || cmd == nil { 43 + if err := run("help", "cmd"); err != nil { 37 44 t.Error("help command failed unexpectedly") 38 45 } 39 46 40 - cmd, err = New([]string{"cmd", "--help"}) 41 - if err != nil || cmd == nil { 47 + if err := run("cmd", "--help"); err != nil { 42 48 t.Error("help command failed unexpectedly") 43 49 } 44 50 45 - cmd, err = New([]string{"cmd", "-h"}) 46 - if err != nil || cmd == nil { 51 + if err := run("cmd", "-h"); err != nil { 47 52 t.Error("help command failed unexpectedly") 48 53 } 49 54 50 - cmd, err = New([]string{"help", "eval"}) 51 - if err != nil || cmd == nil { 55 + if err := run("help", "eval"); err != nil { 52 56 t.Error("help command failed unexpectedly") 53 57 } 54 58 55 - cmd, err = New([]string{"eval", "--help"}) 56 - if err != nil || cmd == nil { 59 + if err := run("eval", "--help"); err != nil { 57 60 t.Error("help command failed unexpectedly") 58 61 } 59 62 }
+2 -6
cmd/cue/cmd/script_test.go
··· 163 163 args, err := shlex.Split(cmd) 164 164 check(err) 165 165 166 - c, err := New(args[1:]) 167 - check(err) 166 + c, _ := New(args[1:]) 168 167 b := &bytes.Buffer{} 169 168 c.SetOutput(b) 170 169 err = c.Run(context.Background()) ··· 219 218 // Like MainTest, but sets stdin to a pipe, 220 219 // to emulate stdin reads like a terminal. 221 220 inTest = true 222 - cmd, err := New(os.Args[1:]) 223 - if err != nil { 224 - return err 225 - } 221 + cmd, _ := New(os.Args[1:]) 226 222 pr, pw, err := os.Pipe() 227 223 if err != nil { 228 224 return err
+4 -3
cmd/cue/cmd/testdata/script/cmd_notool.txtar
··· 3 3 cmp stderr cmd_baddisplay.out 4 4 5 5 -- cmd_baddisplay.out -- 6 - cmd must be run as one of its subcommands: unknown subcommand "notool" 7 - Ensure commands are defined in a "_tool.cue" file. 8 - Run 'cue help cmd' for known subcommands. 6 + unknown 'cue cmd' subcommand: "notool" 7 + 8 + Ensure custom commands are defined in a "_tool.cue" file. 9 + Run 'cue help cmd' to list available custom commands. 9 10 -- task.cue -- 10 11 package home 11 12 message: "Hello world!"
+5 -3
cmd/cue/cmd/testdata/script/cmd_notool2.txtar
··· 3 3 cmp stderr cmd_baddisplay.out 4 4 5 5 -- cmd_baddisplay.out -- 6 - command "notool" is not defined 7 - Ensure commands are defined in a "_tool.cue" file. 8 - Run 'cue help' to show available commands. 6 + unknown 'cue' subcommand: "notool" 7 + 8 + Ensure custom commands are defined in a "_tool.cue" file. 9 + Run 'cue help cmd' to list available custom commands. 10 + Run 'cue help' to see the built-in 'cue' commands. 9 11 -- task.cue -- 10 12 package home 11 13 message: "Hello world!"
+1 -1
cmd/cue/cmd/testdata/script/help.txtar
··· 30 30 For more information on writing CUE configuration files see cuelang.org. 31 31 32 32 Usage: 33 + cue [flags] 33 34 cue [command] 34 35 35 36 Available Commands: ··· 50 51 51 52 Flags: 52 53 -E, --all-errors print all available errors 53 - -h, --help help for cue 54 54 -i, --ignore proceed in the presence of errors 55 55 -s, --simplify simplify output 56 56 --strict report errors for lossy mappings
-1
cmd/cue/cmd/testdata/script/help_cmd.txtar
··· 138 138 hello say hello to someone 139 139 140 140 Flags: 141 - -h, --help help for cmd 142 141 -t, --inject stringArray set the value of a tagged field 143 142 -T, --inject-vars inject system variables in tags (default true) 144 143
-3
cmd/cue/cmd/testdata/script/help_hello.txtar
··· 25 25 Usage: 26 26 cue cmd hello [flags] 27 27 28 - Flags: 29 - -h, --help help for hello 30 - 31 28 Global Flags: 32 29 -E, --all-errors print all available errors 33 30 -i, --ignore proceed in the presence of errors
+2 -5
doc/tutorial/kubernetes/tut_test.go
··· 371 371 } 372 372 cfg.Stdout = buf 373 373 } 374 - cmd, err := cmd.New(args) 375 - if err != nil { 376 - t.Fatal(err) 377 - } 374 + cmd, _ := cmd.New(args) 378 375 if cfg.Stdout != nil { 379 376 cmd.SetOutput(cfg.Stdout) 380 377 } else { ··· 383 380 if cfg.Stdin != nil { 384 381 cmd.SetInput(cfg.Stdin) 385 382 } 386 - if err = cmd.Run(context.Background()); err != nil { 383 + if err := cmd.Run(context.Background()); err != nil { 387 384 if cfg.Stdout == nil { 388 385 logf(t, "Output:\n%s", buf.String()) 389 386 }
+2 -2
go.mod
··· 13 13 github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de 14 14 github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 15 15 github.com/rogpeppe/go-internal v1.10.0 16 - github.com/spf13/cobra v1.4.0 16 + github.com/spf13/cobra v1.7.0 17 17 github.com/spf13/pflag v1.0.5 18 18 github.com/stretchr/testify v1.2.2 19 19 golang.org/x/mod v0.9.0 ··· 25 25 26 26 require ( 27 27 github.com/davecgh/go-spew v1.1.1 // indirect 28 - github.com/inconshreveable/mousetrap v1.0.0 // indirect 28 + github.com/inconshreveable/mousetrap v1.1.0 // indirect 29 29 github.com/kr/text v0.1.0 // indirect 30 30 github.com/lib/pq v1.0.0 // indirect 31 31 github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+5 -6
go.sum
··· 1 1 github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= 2 2 github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= 3 - github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 3 + github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 4 4 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 5 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 6 github.com/emicklei/proto v1.10.0 h1:pDGyFRVV5RvV+nkBK9iy3q67FBy9Xa7vwrOTE+g5aGw= ··· 11 11 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= 12 12 github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= 13 13 github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 14 - github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 15 - github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 14 + github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 15 + github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 16 16 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 17 17 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 18 18 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= ··· 36 36 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 37 37 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= 38 38 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 39 - github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= 40 - github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= 39 + github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= 40 + github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= 41 41 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 42 42 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 43 43 github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= ··· 56 56 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 57 57 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 58 58 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 59 - gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 60 59 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 61 60 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=