Linux Format

Go: Viper and Cobra

Mihalis Tsoukalos explains how to develop fully-functional command line utilities with complete options using Viper and Cobra.

- our Expert Mihalis Tsoukalos is the author of Go Systems Programmin­g and Mastering Go. You can reach him at www. mtsoukalos.eu and @mactsouk.

Mihalis Tsoukalos explains how to develop fully functional command line utilities with complete options using Viper, Cobra and Go. Just dandy.

Viper and Cobra are two Go packages that enable you to create powerful command line tools such as docker and kubectl. Among other things, in this tutorial you’ll learn how to tell Viper to read JSON and YAML configurat­ion files and how to create command line utilities with commands and subcommand­s using Cobra. You’ll need to download both Go packages before using them for the first time because they’re not (yet) part of the Standard Go Library, which is the subject of the first section.

Snakes on a terminal

You can download Viper as well as another handy Go package related to Viper named pflag by executing the following commands:

$ go get github.com/spf13/viper

$ go get github.com/spf13/pflag

Similarly, before using Cobra for the first time you should execute the following commands in order to obtain all the required files:

$ go get github.com/spf13/cobra/cobra

$ go get -u github.com/spf13/cobra/cobra

Along with the installati­on of the Cobra Go package, you’ll also get a command line tool named cobra that simplifies the use of the Cobra Go package. The cobra CLI will be used in this tutorial for creating new Cobra applicatio­ns and for adding new commands to existing Cobra applicatio­ns, because it’s a great time saver. To make sure that everything is working as expected execute the following Go program, which is named

usevc.go and imports the two packages without actually doing something with them:

package main

import (

“fmt” _ “github.com/spf13/cobra” _ “github.com/spf13/viper” )

func main() { fmt.println(“everything is OK!”) }

The underscore character in front of the two packages tells Go that it’s fine not to use these two packages in your program (Go will complain otherwise). If both Cobra and Viper are successful­ly installed, usevc.go will generate the “Everything is OK!” message. Otherwise you’ll see an error message and the program won’t get executed.

If you don’t want to have many packages installed on your Linux machine, there’s always the choice of using a Docker image to do your job. Although you’ll need to learn how to use Docker and work with Docker images, you’ll see many benefits in the long run from that choice, especially if you’re using multiple Linux machines with various Linux distros for developmen­t.

Bitten by the Viper

In this section we’re going to learn how to convert an existing Go program that uses the flag package into using Viper. This is an easy process that shows that the developers of Viper are good people! For that purpose you’ll need Viper as well as the pflag package that you downloaded in the previous section.

We’ll start with a Go program that uses the flag package named usingflag.go and convert it into a new program that uses Viper and is called usingviper.go. The good thing is that you now know how to use both Viper and pflag for working with command line arguments. The usingflag.go command line utility supports a single command line option named i.

The screenshot (left) shows the Go code of both usingflag.go and usingviper.go whereas the screenshot (right) shows the kind of output that usingviper.go generates including the way Viper handles erroneous input. The first screenshot also reveals that converting a program which uses the flag package into a program that uses Viper is a straightfo­rward process as long as you know what you’re doing. Finally, Viper enables you to easily get and set the values of UNIX environmen­t variables. This is illustrate­d in the next Go code, which is included in envviper.go: func main() { VIPER.BINDENV(“GOMAXPROCS”) val := VIPER.GET(“GOMAXPROCS”) fmt.println(val) VIPER.SET(“GOMAXPROCS”, 10) val = VIPER.GET(“GOMAXPROCS”) fmt.println(val) }

So, you’ll need to call viper.bindenv() to start working with an environmen­t variable, viper.get() to

get the current value of it – or <nil> in case the environmen­t variable is unset – and viper.set() to set the value of an environmen­t variable. Executing envviper.go will generate the following output:

$ go run envviper.go

<nil>

10

However, as you’ll see in the sections that follow, Viper can perform many more advanced tasks.

On the JSON

Let’s find out how to obtain the configurat­ion of a Go applicatio­n from plain text configurat­ion files. In this case it will be a text file written in the JSON format. The Go code for the command line utility is saved in jsonviper.go. The core functional­ity of jsonviper.go is implemente­d in the following Go code:

viper.setconfigt­ype(“json”) viper.setconfigf­ile(”./myconfig.json”) fmt.printf(“using config: %s\n”, viper.configfile­used()) viper.readinconf­ig()

So, viper.setconfigt­ype() defines the expected format of the configurat­ion file, viper.setconfigf­ile() sets the path of the configurat­ion file and viper. Readinconf­ig() reads and parses that file. If you forget to call viper.readinconf­ig() then your program won’t work as expected.

Note that the path of the JSON file is hard-coded into jsonviper.go for reasons of simplicity – the next section will show you how to overcome that restrictio­n in many ways. Finally, viper.configfile­used() prints the path of the used configurat­ion file. This isn’t necessary in this case because the path and the name of the configurat­ion file are hard-coded, but can be handy in other situations.

The contents of the JSON configurat­ion file, which is saved as myconfig.json, can be seen in the screenshot on page 94. It also shows the output of the jsonviper.go utility for various types of input including erroneous ones. Please note that you’re responsibl­e for making sure that the configurat­ion file you want to use is there – Viper won’t check it for you.

Hearing YAML

YAML is a popular file format for text files and so it comes as no surprise that Viper also supports YAML configurat­ion files. This time the filename of the YAML configurat­ion file will be given as a command line argument to the utility.

Additional­ly, this time the viper.addconfigp­ath() function will add three search paths, which are places where Viper will look for configurat­ion files. The Go code for the command line utility is saved in yamlviper.go. The core functional­ity of yamlviper.go is implemente­d with the following Go code:

var configfile *string = flag.string(“c”, “myconfig”, “Setting the configurat­ion file”) flag.parse()

_, err := os.stat(*configfile) if err == nil { fmt.println(“using User Specified Configurat­ion file!”) viper.setconfigf­ile(*configfile) } else { viper.setconfign­ame(*configfile) ... }

 ??  ?? Here’s the Go code of usingflag.go and usingviper.go that use the flag and Viper packages, respective­ly, to support command line flags.
Here’s the Go code of usingflag.go and usingviper.go that use the flag and Viper packages, respective­ly, to support command line flags.
 ??  ??
 ??  ?? Here’s usingviper. go in action. If you forget to provide a value to the defined flag or if you give an invalid value, the utility will print an error message.
Here’s usingviper. go in action. If you forget to provide a value to the defined flag or if you give an invalid value, the utility will print an error message.

Newspapers in English

Newspapers from Australia