DEV Community

Cover image for Are you still coding go cli handling by hand?

Posted on

Are you still coding go cli handling by hand?

Are you still coding your go cli handling by hand? Time to stop and rethink better ways to do it now.

Take a look at this go command line handling file:

The help text "path to serve files from" shows up three times:

$ grep -1 'path to serve' OpenSesame_cliDef.go
        Port string // listening port
        Path string // path to serve files from
        Help bool   // show usage help
        flag.StringVar(&Opts.Path, "path", "./",
                "path to serve files from")
        flag.BoolVar(&Opts.Help, "help", false,

const usageSummary = "  -port\tlistening port (OPENSESAME_PORT)\n  -path\tpath to serve files from (OPENSESAME_PATH)\n  -help\tshow usage help (OPENSESAME_HELP)\n\nDetails:\n\n"
Enter fullscreen mode Exit fullscreen mode

If coding by hand, most probably the first occurrence will be omitted. But that's kind of pity, as the help text is helpful in explaining what exactly the Path string variable is for:

        Path string // path to serve files from
Enter fullscreen mode Exit fullscreen mode

Also, if coding by hand, the second and third occurrences will very easily get out of sync if not be taken care of all the time.

All these violate the DRY (Don't Repeat Yourself) principle. How to avoid it? The answer is this file:

from which we can see that the help text "path to serve files from" is defined only once but get automatically put into three different proper places.


This is the go cli handling code auto generation we are talking about. Look at the above two files, which one is more easier to maintain? With cli handling code auto generation feature out there, don't code it manually next time when you do cli handling again.

What if you already have a manually written cli handling code? Well, converting it to automatically generated is not that hard at all. Here are just two simple steps,

  • introduce config.go, which ports the existing cli handling from existing code into auto-generated config.go file.

  • implemented -d, -c, & -help, which adds more business logic handling for the newly added command line flags/parameters.

Very simple, no sweat at all. All thanks to the auto-generated config.go file.


OK, now comes to the question, how is the config.go file auto-generated? Let me answer it with another example, that starts everything from the beginning, with all the following explanation borrowed from here

This section will work through every steps how the program is created.

  1. Initialize an empty project. The _proj.yaml file will later be used to
  2. Initialize project wireframe using the standard Go flag package, by
    1. Edit the _cli.yaml cli arguments definition file
    2. Then do go generate (enabled like this), or directly invoke the script
    3. Finally do go build
  3. Provide the initial OpenSesame functionality
  4. Update OpenSesame code to make use of the auto-generated cli wireframe
  5. The auto-generated cli wireframe code are not set in stones, they can later be further amended, just like the real-world cases. For e.g.

This finished a full Initialize -> Make use -> More changes to cli definitions cycle.


Make sure to check out the rest of the above quoted wiki, Go command line flag handling code auto generation, from which you can see that using the same .yaml driven file, not only the go standard flag command line handling code can be automatically generated, but viper and cobra as well, and all the way to the full-featured cli code that can set the argument values at three different levels:

So the priority of setting the Host value is, from lowest priority to the highest:

  1. self-config file
  2. environment variable
  3. command line

Three different levels.

Top comments (0)