Go: Viper and Co­bra

Mi­halis Tsouka­los ex­plains how to de­velop fully-func­tional com­mand line util­i­ties with com­plete op­tions us­ing Viper and Co­bra.

Linux Format - - CONTENTS - our Ex­pert Mi­halis Tsouka­los is the au­thor of Go Sys­tems Pro­gram­ming and Mas­ter­ing Go. You can reach him at www. mt­souka­los.eu and @mact­souk.

Mi­halis Tsouka­los ex­plains how to de­velop fully func­tional com­mand line util­i­ties with com­plete op­tions us­ing Viper, Co­bra and Go. Just dandy.

Viper and Co­bra are two Go pack­ages that en­able you to cre­ate pow­er­ful com­mand line tools such as docker and kubectl. Among other things, in this tu­to­rial you’ll learn how to tell Viper to read JSON and YAML con­fig­u­ra­tion files and how to cre­ate com­mand line util­i­ties with com­mands and sub­com­mands us­ing Co­bra. You’ll need to down­load both Go pack­ages be­fore us­ing them for the first time be­cause they’re not (yet) part of the Stan­dard Go Li­brary, which is the sub­ject of the first sec­tion.

Snakes on a ter­mi­nal

You can down­load Viper as well as an­other handy Go pack­age re­lated to Viper named pflag by ex­e­cut­ing the fol­low­ing com­mands:

$ go get github.com/spf13/viper

$ go get github.com/spf13/pflag

Sim­i­larly, be­fore us­ing Co­bra for the first time you should ex­e­cute the fol­low­ing com­mands in or­der to ob­tain all the re­quired files:

$ go get github.com/spf13/co­bra/co­bra

$ go get -u github.com/spf13/co­bra/co­bra

Along with the in­stal­la­tion of the Co­bra Go pack­age, you’ll also get a com­mand line tool named co­bra that sim­pli­fies the use of the Co­bra Go pack­age. The co­bra CLI will be used in this tu­to­rial for cre­at­ing new Co­bra ap­pli­ca­tions and for adding new com­mands to ex­ist­ing Co­bra ap­pli­ca­tions, be­cause it’s a great time saver. To make sure that ev­ery­thing is work­ing as ex­pected ex­e­cute the fol­low­ing Go pro­gram, which is named

usevc.go and im­ports the two pack­ages with­out ac­tu­ally do­ing some­thing with them:

pack­age main

im­port (

“fmt” _ “github.com/spf13/co­bra” _ “github.com/spf13/viper” )

func main() { fmt.println(“ev­ery­thing is OK!”) }

The un­der­score char­ac­ter in front of the two pack­ages tells Go that it’s fine not to use these two pack­ages in your pro­gram (Go will com­plain oth­er­wise). If both Co­bra and Viper are suc­cess­fully in­stalled, usevc.go will gen­er­ate the “Ev­ery­thing is OK!” mes­sage. Oth­er­wise you’ll see an er­ror mes­sage and the pro­gram won’t get ex­e­cuted.

If you don’t want to have many pack­ages in­stalled on your Linux ma­chine, there’s al­ways the choice of us­ing a Docker im­age to do your job. Al­though you’ll need to learn how to use Docker and work with Docker images, you’ll see many ben­e­fits in the long run from that choice, espe­cially if you’re us­ing mul­ti­ple Linux ma­chines with var­i­ous Linux dis­tros for de­vel­op­ment.

Bit­ten by the Viper

In this sec­tion we’re go­ing to learn how to con­vert an ex­ist­ing Go pro­gram that uses the flag pack­age into us­ing Viper. This is an easy process that shows that the developers of Viper are good peo­ple! For that pur­pose you’ll need Viper as well as the pflag pack­age that you down­loaded in the pre­vi­ous sec­tion.

We’ll start with a Go pro­gram that uses the flag pack­age named us­ingflag.go and con­vert it into a new pro­gram that uses Viper and is called us­ingviper.go. The good thing is that you now know how to use both Viper and pflag for work­ing with com­mand line ar­gu­ments. The us­ingflag.go com­mand line util­ity sup­ports a sin­gle com­mand line op­tion named i.

The screen­shot (left) shows the Go code of both us­ingflag.go and us­ingviper.go whereas the screen­shot (right) shows the kind of out­put that us­ingviper.go gen­er­ates in­clud­ing the way Viper han­dles er­ro­neous in­put. The first screen­shot also re­veals that con­vert­ing a pro­gram which uses the flag pack­age into a pro­gram that uses Viper is a straight­for­ward process as long as you know what you’re do­ing. Fi­nally, Viper en­ables you to eas­ily get and set the val­ues of UNIX en­vi­ron­ment vari­ables. This is il­lus­trated in the next Go code, which is in­cluded 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 work­ing with an en­vi­ron­ment vari­able, viper.get() to

get the cur­rent value of it – or <nil> in case the en­vi­ron­ment vari­able is un­set – and viper.set() to set the value of an en­vi­ron­ment vari­able. Ex­e­cut­ing envviper.go will gen­er­ate the fol­low­ing out­put:

$ go run envviper.go

<nil>

10

How­ever, as you’ll see in the sec­tions that fol­low, Viper can per­form many more ad­vanced tasks.

On the JSON

Let’s find out how to ob­tain the con­fig­u­ra­tion of a Go ap­pli­ca­tion from plain text con­fig­u­ra­tion files. In this case it will be a text file writ­ten in the JSON for­mat. The Go code for the com­mand line util­ity is saved in json­viper.go. The core func­tion­al­ity of json­viper.go is im­ple­mented in the fol­low­ing Go code:

viper.set­con­fig­type(“json”) viper.set­con­fig­file(”./my­con­fig.json”) fmt.printf(“us­ing con­fig: %s\n”, viper.con­fig­fileused()) viper.read­in­con­fig()

So, viper.set­con­fig­type() de­fines the ex­pected for­mat of the con­fig­u­ra­tion file, viper.set­con­fig­file() sets the path of the con­fig­u­ra­tion file and viper. Read­in­con­fig() reads and parses that file. If you for­get to call viper.read­in­con­fig() then your pro­gram won’t work as ex­pected.

Note that the path of the JSON file is hard-coded into json­viper.go for rea­sons of sim­plic­ity – the next sec­tion will show you how to over­come that re­stric­tion in many ways. Fi­nally, viper.con­fig­fileused() prints the path of the used con­fig­u­ra­tion file. This isn’t nec­es­sary in this case be­cause the path and the name of the con­fig­u­ra­tion file are hard-coded, but can be handy in other sit­u­a­tions.

The con­tents of the JSON con­fig­u­ra­tion file, which is saved as my­con­fig.json, can be seen in the screen­shot on page 94. It also shows the out­put of the json­viper.go util­ity for var­i­ous types of in­put in­clud­ing er­ro­neous ones. Please note that you’re re­spon­si­ble for mak­ing sure that the con­fig­u­ra­tion file you want to use is there – Viper won’t check it for you.

Hear­ing YAML

YAML is a pop­u­lar file for­mat for text files and so it comes as no sur­prise that Viper also sup­ports YAML con­fig­u­ra­tion files. This time the file­name of the YAML con­fig­u­ra­tion file will be given as a com­mand line ar­gu­ment to the util­ity.

Ad­di­tion­ally, this time the viper.ad­d­con­fig­path() func­tion will add three search paths, which are places where Viper will look for con­fig­u­ra­tion files. The Go code for the com­mand line util­ity is saved in yam­lviper.go. The core func­tion­al­ity of yam­lviper.go is im­ple­mented with the fol­low­ing Go code:

var con­fig­file *string = flag.string(“c”, “my­con­fig”, “Set­ting the con­fig­u­ra­tion file”) flag.parse()

_, err := os.stat(*con­fig­file) if err == nil { fmt.println(“us­ing User Spec­i­fied Con­fig­u­ra­tion file!”) viper.set­con­fig­file(*con­fig­file) } else { viper.set­con­fig­name(*con­fig­file) ... }

Here’s the Go code of us­ingflag.go and us­ingviper.go that use the flag and Viper pack­ages, re­spec­tively, to sup­port com­mand line flags.

Here’s us­ingviper. go in ac­tion. If you for­get to pro­vide a value to the de­fined flag or if you give an in­valid value, the util­ity will print an er­ror mes­sage.

Newspapers in English

Newspapers from Australia

© PressReader. All rights reserved.