diff --git a/GUIDE.md b/GUIDE.md index e0d64d8..96cf200 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -1,7 +1,9 @@ -# acmd guides +# Guide for acmd ## Flag + Example with command like that `./dummy server ./openapi.yml -port=8080` from [dummy](https://github.com/go-dummy/dummy/blob/main/cmd/dummy/main.go) + ```go func run() error { cmds := []acmd.Command{ @@ -36,3 +38,48 @@ func run() error { return r.Run() } ``` + +## Flags propagation + +There is no special methods, config fields to propagate flags to subcommands. However it's not hard to make this, because every command can access predefined flags, which are shared across handlers. + +```go +type commonFlags struct { + IsVerbose bool +} + +// NOTE: should be added before flag.FlagSet method Parse(). +func withCommonFlags(fs *flag.FlagSet) *commonFlags { + c := &commonFlags{} + fs.BoolVar(&c.IsVerbose, "verbose", false, "should app be verbose") + return c +} + +func cmdFoo(ctx context.Context, args []string) error { + fs := flag.NewFlagSet("foo", flag.ContinueOnError) + // NOTE: here add flags for cmdBar as always + + // add common flags, make sure it's before Parse but after all defined flags + common := withCommonFlags(fs) + if err := fs.Parse(args); err != nil { + return err + } + // use commonFlags fields or any other flags that you have defined + return nil +} + +func cmdBar(ctx context.Context, args []string) error { + fs := flag.NewFlagSet("bar", flag.ContinueOnError) + // NOTE: here add flags for cmdFoo as always + + // add common flags, make sure it's before Parse but after all defined flags + common := withCommonFlags(fs) + if err := fs.Parse(args); err != nil { + return err + } + // use commonFlags fields or any other flags that you have defined + return nil +} +``` + +Also see `ExamplePropagateFlags` test. diff --git a/example_test.go b/example_test.go index f83c736..0917277 100644 --- a/example_test.go +++ b/example_test.go @@ -1,6 +1,7 @@ package acmd_test import ( + "bytes" "context" "flag" "fmt" @@ -256,3 +257,67 @@ func ExampleNestedCommands() { // Output: qux } + +func ExamplePropagateFlags() { + testOut := os.Stdout + testArgs := []string{"someapp", "foo", "-dir=test-dir", "--verbose"} + buf := &bytes.Buffer{} + + cmds := []acmd.Command{ + { + Name: "foo", Do: func(ctx context.Context, args []string) error { + fs := flag.NewFlagSet("foo", flag.ContinueOnError) + isRecursive := fs.Bool("r", false, "should file list be recursive") + common := withCommonFlags(fs) + if err := fs.Parse(args); err != nil { + return err + } + if common.IsVerbose { + fmt.Fprintf(buf, "TODO: dir %q, is recursive = %v\n", common.Dir, *isRecursive) + } + return nil + }, + }, + { + Name: "bar", Do: func(ctx context.Context, args []string) error { + fs := flag.NewFlagSet("bar", flag.ContinueOnError) + common := withCommonFlags(fs) + if err := fs.Parse(args); err != nil { + return err + } + if common.IsVerbose { + fmt.Fprintf(buf, "TODO: dir %q\n", common.Dir) + } + return nil + }, + }, + } + + r := acmd.RunnerOf(cmds, acmd.Config{ + AppName: "acmd-example", + AppDescription: "Example of acmd package", + Version: "the best v0.x.y", + Output: testOut, + Args: testArgs, + }) + + if err := r.Run(); err != nil { + panic(err) + } + fmt.Println(buf.String()) + + // Output: TODO: dir "test-dir", is recursive = false +} + +type commonFlags struct { + IsVerbose bool + Dir string +} + +// NOTE: should be added before flag.FlagSet method Parse(). +func withCommonFlags(fs *flag.FlagSet) *commonFlags { + c := &commonFlags{} + fs.BoolVar(&c.IsVerbose, "verbose", false, "should app be verbose") + fs.StringVar(&c.Dir, "dir", ".", "directory to process") + return c +}