Integrating Cobra and Viper

In this lesson, you will see the synergy between Cobra and Viper in action using our demo calculator application.

We'll cover the following

Integrating Cobra and Viper

To make things interesting, we will add two integers that will cause an overflow and see how playing with the configuration and command-line flags influences the result.

First, we will add a configuration file called config.toml with a key called check set to false:

check = false

The main function will use Viper to read this configuration file:

package main

import (
	"log"

	"github.com/spf13/viper"

	"gigi/calc/cmd"
)

func main() {
	viper.SetConfigFile("config.toml")
	err := viper.ReadInConfig()
	if err != nil {
		log.Fatal(err)
	}

	cmd.Execute()
}

We’re ready for some experiments. Let’s pick two large numbers that will cause an overflow. Note that the Go int type is not well defined, so on your machine the maximal integer might be different. However, an int is always at least 32-bit. On my machine, it is 64-bit, so the max signed int value is 9223372036854775807.

Let’s see what happens if we try to add 1 to it.

$ go run main.go add 9223372036854775807 1
-9223372036854775808

Uh, oh. That’s what an unchecked overflow looks like. When we add 1 to the max integer we get the min integer. This may be confusing, but it makes sense if you know that Go represents numbers in the two’s-complement system.

If we had added the max integer to itself, we get -2:

$ go run main.go add 9223372036854775807 9223372036854775807
-2

Now, that you have seen what happens with uncheck calculation, we should put a stop to it!

We can use the --check command-line argument for that. It works just fine and panics.

$ go run main.go add --check 9223372036854775807 1
panic: overflow!

goroutine 1 [running]:
gigi/calc/pkg/calc.checkAdd(...)
	/Users/gigi.sayfan/git/cobra-lib-demo/pkg/calc/calc.go:12
gigi/calc/pkg/calc.Add(...)
	/Users/gigi.sayfan/git/cobra-lib-demo/pkg/calc/calc.go:35
gigi/calc/cmd.glob..func1(0x18a31c0, 0xc00011b9b0, 0x2, 0x3)
	/Users/gigi.sayfan/git/cobra-lib-demo/cmd/add.go:32 +0x1d1
github.com/spf13/cobra.(*Command).execute(0x18a31c0, 0xc00011b950, 0x3, 0x3, 0x18a31c0, 0xc00011b950)
	/Users/gigi.sayfan/go/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:846 +0x29d
github.com/spf13/cobra.(*Command).ExecuteC(0x18a2c80, 0x14f0027, 0xc00011b7d0, 0xc00019c000)
	/Users/gigi.sayfan/go/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:950 +0x349
github.com/spf13/cobra.(*Command).Execute(...)
	/Users/gigi.sayfan/go/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:887
gigi/calc/cmd.Execute()
	/Users/gigi.sayfan/git/cobra-lib-demo/cmd/root.go:23 +0x31
main.main()
	/Users/gigi.sayfan/git/cobra-lib-demo/main.go:18 +0xa2

Let’s make sure it doesn’t panic when the numbers don’t cause an overflow:

$ go run main.go add --check 7 8
15

Okay. Looks like we’re good here. However, remembering to typing --check every time is labor-intensive and error-prone, so it’s better to just set it once in our configuration file:

check = true

Now, if we try to add two large numbers without the --check command-line argument it will still panic:

$ go run main.go add 9223372036854775807 1
panic: overflow!

goroutine 1 [running]:
gigi/calc/pkg/calc.checkAdd(...)
	/Users/gigi.sayfan/git/cobra-lib-demo/pkg/calc/calc.go:12
gigi/calc/pkg/calc.Add(...)
	/Users/gigi.sayfan/git/cobra-lib-demo/pkg/calc/calc.go:35
gigi/calc/cmd.glob..func1(0x18a31c0, 0xc00000e8a0, 0x2, 0x2)
	/Users/gigi.sayfan/git/cobra-lib-demo/cmd/add.go:32 +0x1d1
github.com/spf13/cobra.(*Command).execute(0x18a31c0, 0xc00000e860, 0x2, 0x2, 0x18a31c0, 0xc00000e860)
	/Users/gigi.sayfan/go/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:846 +0x29d
github.com/spf13/cobra.(*Command).ExecuteC(0x18a2c80, 0x14f0027, 0xc00009f7d0, 0xc000186000)
	/Users/gigi.sayfan/go/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:950 +0x349
github.com/spf13/cobra.(*Command).Execute(...)
	/Users/gigi.sayfan/go/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:887
gigi/calc/cmd.Execute()
	/Users/gigi.sayfan/git/cobra-lib-demo/cmd/root.go:23 +0x31
main.main()
	/Users/gigi.sayfan/git/cobra-lib-demo/main.go:18 +0xa2

This is cool, but we can still override the configuration file by explicitly specifying --check=false on the command-line:

$ go run main.go add --check=false 9223372036854775807 1
-9223372036854775808

Yeah, we just demonstrated how Viper allows our program to benefit from a configuration so we don’t have to provide common arguments every time on the command-line. However, if we want a different behavior every now and then, we don’t have to modify our configuration file, and we can override it with a command-line argument.

Get hands-on with 1200+ tech skills courses.