Skip to content

Commit

Permalink
Common flags example (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
cristaloleg authored Jan 30, 2022
1 parent e51f45c commit 096b533
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
49 changes: 48 additions & 1 deletion GUIDE.md
Original file line number Diff line number Diff line change
@@ -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{
Expand Down Expand Up @@ -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.
65 changes: 65 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package acmd_test

import (
"bytes"
"context"
"flag"
"fmt"
Expand Down Expand Up @@ -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
}

0 comments on commit 096b533

Please sign in to comment.