Skip to content

Go R1 Day 45

progress๐Ÿ”—

  • Worked through merging flags and the "run" approach from Mat Ryer.
  • Used ff for parsing.

The resulting logic seems correct with main being very simple with:

package main
import(
    "io"
    "flag"
    "os"
    "github.com/peterbourgon/ff/v3"
    "github.com/peterbourgon/ff/v3/ffcli"
    "github.com/peterbourgon/ff/v3/fftoml"
)
const (
 // exitFail is the exit code if the program
 // fails.
 exitFail           = 1
)

// main configuration from Matt Ryer with minimal logic, passing to run, to allow easier CLI tests
func main() {
 if err := run(os.Args, os.Stdout); err != nil {
  fmt.Fprintf(os.Stderr, "%s\n", err)
  os.Exit(exitFail)
 }
}

The run function then handles the actual parsing:

func run(args []string, stdout io.Writer) error {
 if len(args) == 0 {
  return errors.New("no arguments")
 }
  flags := flag.NewFlagSet(args[0], flag.ExitOnError)
 flag.BoolVar(&debug, "debug", false, "sets log level to debug")

if err := ff.Parse(flags, args,
  ff.WithEnvVarNoPrefix(),
  ff.WithConfigFileFlag("config"),
  ff.WithConfigFileParser(fftoml.Parser),
 ); err != nil {
  return err
 }
 if debug {
  logLevel = "debug"
 }
  // proceed with initialization of logger and other tools
  return nil

I like this approach, as the examples by Mat show how you can end up testing the inputs and variations on flags as well. The example from his blog post showed how easy it became with:

err := run([]string{"program", "-v", "-debug=true", "-another=2"})