Working with Cobra - Flags

This lesson wraps up the topic of working with Cobra as a library.

In this lesson, you will see how flags complement arguments on the command line, create the main.go file of our calculator demo application, and then take a little quiz.

Understanding flags

Commands and arguments are very powerful, but good command-line interfaces need flags too. Flags modify the way commands operate on their arguments.

There are two types of flags: persistent and non-persistent. Persistent flags are flags that are available to a command and all its sub-commands. In particular it is common to define persistent flags on the root command that will be available for all commands. For example, --verbose or --help are good examples for global flags that can apply to any command.

Local flags, on the other hand, apply only to the command they are attached to. Let’s add flags to our commands. We can do it in the init() function of each command.

Since our program deals with adding and subtracting integers, there’s the possibility of overflowing or under flowing. The calc package expects a Boolean variable for each command. If the check flag is true and the result overflows or underflows, it will panic. However if it’s false, it will just carry on and the result will be incorrect.

Here are the two function that check the operands before trying to add or subtract them:

const (
	maxUint=^uint(0)
	maxInt = int(maxUint >> 1)
	minInt = -maxInt - 1
)


func checkAdd(a, b int) {
	if a > 0 {
		if b > maxInt - a {
			panic("overflow!")
		}
	} else {
		if b < minInt - a {
			panic("underflow!")
		}
	}
}

func checkSub(a, b int) {
	if a > 0 {
		if b < minInt + a {
			panic("overflow!")
		}
	} else {
		if b < a - maxInt {
			panic("underflow!")
		}
	}
}

Here is the Add() function itself that calls the checkAdd() function if the check argument is true:

func Add(a, b int, check bool) int {
	if check {
		checkAdd(a, b)
	}

	return a + b
}

We may want a different behavior in different cases, so we can leave it to the user by defining a flag the user can specify when invoking our program.

Flags are defined on the command via the Flags() method for local flags and PersistentFlags() method for persistent flags.

Here is the definition for the Add command in its init() function:

var check bool

func init() {
	addCmd.Flags().BoolVar(
		&check,
		"check",
		false,
		"check controls if overflow/underflow check is performed")
	rootCmd.AddCommand(addCmd)
}

And, here is the definition for the Subtract command in its init() function:

var check bool

func init() {
	subtractCmd.Flags().BoolVar(
		&check,
		"check",
		false,
		"check controls if overflow/underflow check is performed")
	rootCmd.AddCommand(subtractCmd)
}

The default for the flags is false.

Note that flags are optional by default. If we want to require the user to specify a value for a flag (e.g. when there is no reasonable default), then we can mark it as required:

rootCmd.Flags().StringVar(&someFlag, "some-flag", "", "Some flag (required)")
rootCmd.MarkFlagRequired("some-flag")

Cobra automatically adds a global --version flag if the Version field is set on the root command. We can even customize the version’s display via the cmd.SetVersionTemplate(s string) function.

Alright. We created a root command and subcommands. The init() function of each subcommand configures flags and attaches them to the root command, but the root command itself is not invoked yet. This is the job of the main() in the main.go file. Let’s create it.

Creating the main.go file

The main.go file is the only file in the main package, and it contains the main() function, which is the entry point to the program. Its job is very simple: run the Execute() function defined in the cmd/root.go file.

package main

import "gigi/calc/cmd"

func main() {
	cmd.Execute()
}

This function simply runs the root command:

func Execute() {
	err := rootCmd.Execute()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

That’s all there is to it. Cobra takes care of everything else, including delegating work to the various subcommands, checking flags and arguments, and returning errors if necessary.

Run the following application with flags added.

Get hands-on with 1200+ tech skills courses.