How to Create a CLI in Go?

How to Create a CLI in Go?

In our day-to-day work, we are used to using nifty tools in the command line. We are surrounded by CLI (Docker, Kubectl, Terraform, AWS, etc.). We will see in this tutorial, that in just a few minutes, it is possible to create a CLI with Go language and the Cobra library. Are you ready?

Get up and Go with this quick and effective tutorial.

Why Go?

How to Create a CLI in Go

_**Go**pher friend_

Go, created in 2009, and used in production by thousands of companies around the world (including Uber, Lyft, Slack, Pinterest ... and of course Google), is becoming the preferred language of the Cloud. It is easy to install, provides libraries and tools, and is fast to compile and not very greedy in memory.

With its ecosystem riddled with tools and CLIs, it would be wrong not to put Go in our toolbox. If you have not started Go yet, you can start by doing the interactive "tour de go" tutorial: https://tour.golang.org.

As you will see in this article, writing a CLI with GO is a breeze!

You may also like: Golang Tutorial: Learn Golang by Examples.

Prerequisites:

Go!

The first step is, if you have not already done so, to install Go on your machine. For this, you can follow the installation procedure on the official website or go through GVM. GVM is a very practical version for Go, which allows you to update your version of Go by specifying which version you want.

Installation:

For bash:

bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

For zsh:

zsh < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

Usage:

$ gvm 

Usage: gvm [command]

Description:

  GVM is the Go Version Manager

Commands:

  version    - print the gvm version number

  get        - gets the latest code (for debugging)

  use        - select a go version to use (--default to set permanently)

  diff       - view changes to Go root

  help       - display this usage text

  implode    - completely remove gvm

  install    - install go versions

  uninstall  - uninstall go versions

  cross      - install go cross compilers

  linkthis   - link this directory into GOPATH

  list       - list installed go versions

  listall    - list available versions

  alias      - manage go version aliases

  pkgset     - manage go packages sets

  pkgenv     - edit the environment for a package set

The GVM command that will interest us especially is the command gvm install, it is used like this:

$ gvm install [version] [options]

Go installation:

$ gvm install go1.12.9 -B
$ gvm use go1.12.9 --default

In your .zshrc or .bashrc file, set your $GOROOT and $GOPATH environment variables. Here is an example :

[[ -s"$HOME/.gvm/scripts/gvm" ]] && source"$HOME/.gvm/scripts/gvm"

export GOPATH=$HOME/go

export GOBIN=$GOPATH/bin

export PATH=${PATH}:$GOBIN

That's it, Go is installed, its version manager also, it's time to get to the heart of the matter and create our first CLI.

Cobra

How to Create a CLI in Go

Cobra is both a library for creating powerful modern CLI applications and a program for generating applications and batch files.

Using Cobra is easy. First, use the go get command to download the latest version. This command will install the cobra generator executable with the library and its dependencies:

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

The cobra binary is now in the bin/ directory of your $GOPATH, which is itself in your PATH, so it can be used directly.

We will start by generating our first application with the command cobra init followed by the package and the name of your app. The command will generate the application with the correct file structure and imports.

$ cd $GOPATH/src 

$ cobra init github.com/scraly/hello-world

Using config file: /home/scraly/.cobra.yaml

Your Cobra application is ready at

/home/scraly/git/src/github.com/scraly/hello-world

Give it a try by going there and running `go run main.go`.

Add commands to it by running `cobra add [cmdname]`.

Your application is initialized, a main.go file and a cmd/ package has been created:

$ cd github.com/scraly/hello-world

$ tree
.
├── cmd
│   └── root.go
├── LICENSE
└── main.go

1 directory, 3 files

At the execution of our CLI we want to display:

  • a short description
  • a long description
  • using our app

To do this, simply modify the cmd/root.go file:

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
   Use:   "hello-world",
   Short: "A brief description of your application",
   Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
   // Uncomment the following line if your bare application
   // has an action associated with it:
   // Run: func(cmd *cobra.Command, args []string) { },
}

Now, we want to add a start command in our small application. For that, we will use the add command of the cobra CLI:

$ cobra add start

Using config file: /home/scraly/.cobra.yaml

start created at /home/scraly/git/src/github.com/scraly/hello-world/cmd/start.go

/!\ Warning: Note that the command names must be in camelCase format.

Once you have executed these three commands, you get an application structure similar to this one:

$ tree
.
├── cmd
│   ├── root.go
│   └── start.go
├── LICENSE
└── main.go

At this point, you can run go run main.go to run your application:

$ go run main.go 

A longer description that spans multiple lines and likely contains

examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.

This application is a tool to generate the needed files

to quickly create a Cobra application.

Usage:

  hello-world [command]

Available Commands:

  help        Help about any command

  start       A brief description of your command

Flags:

      --config string   config file (default is $HOME/.hello-world.yaml)

  -h, --help            help for hello-world

  -t, --toggle          Help message for toggle

Use "hello-world [command] --help" for more information about a command.

Then, run main.go to run the start command:

$ go run main.go start

start called

If we had created another command, for example, cobra add config, we could also test the command by typing go run config.go.

We will now modify the cmd/start.go file, with our own code, so that our application displays the message we want for the start command:

var startCmd = &cobra.Command{

        Use:   "start",

        Short: "This command will show you a hello world message",

        Long: `Welcome in start command, this cmd will display to you a hello world message.`,

        Run: func(cmd *cobra.Command, args []string) {

                fmt.Println("Hello world, start have been called!")

        },

}

We can test the help of our start command right now:

$ go run main.go start -h

Welcome in start command, this cmd will display to you a hello world message.

Usage:

  hello-world start [flags]

Flags:

  -h, --help   help for start

Global Flags:

      --config string   config file (default is $HOME/.hello-world.yaml)

Then, run the start command to see the updated message:

$ go run main.go start

Hello world, start have been called!

We can also display the help message from our start command:

$ go run main.go start -h

Welcome in start command, this cmd will display to you a hello world message.

Usage:

  hello-world start [flags]

Flags:

  -h, --help   help for start

Global Flags:

      --config string   config file (default is $HOME/.hello-world.yaml)

Your application is ready, you just have to build/install it in your $GOPATH then use it:

$ go install

$ hello-world start
Hello world, start have been called!

Want to go further?

We will add a say command and a hello subcommand to make our little program say: "hello, world!"

Let's add our say command:

$ cobra add say
say created at /Users/uidn3817/go/src/github.com/scraly/hello-world/cmd/say.go

Let's edit this file to warn the user that the say command is not used alone. Just replace the Run method with this one:

    RunE: func(cmd *cobra.Command, args []string) error {

        return errors.New("Provide item to the say command")

    },

Next, we add hello sub command:

$ cobra add hello -p 'sayCmd'

hello created at /Users/uidn3817/go/src/github.com/scraly/hello-world/cmd/hello.go

Let's modify the hello.go file that has just been generated, so that the CLI can display "hello, world!"

    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("hello world !")
    },

Now, we need to install the app again in our machine:

$ go install

And we test again:

$ hello-world say

Error: Provide item to the say command

Usage:

  hello-world say [flags]

  hello-world say [command]

Available Commands:

  hello       A brief description of your command

Flags:

  -h, --help   help for say

Global Flags:

      --config string   config file (default is $HOME/.hello-world.yaml)

Use "hello-world say [command] --help" for more information about a command.

Provide item to the say command

And now we can just test again our app with the say command and hello sub command:

$ hello-world say hello

hello world !

And that's it, you coded your CLI in Go in a few minutes; it's a good start! :-)

If you liked this article, I'll write several articles to go further with your first CLI and your first application in Go!

go

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

What's new in the go 1.15

Go announced Go 1.15 version on 11 Aug 2020. Highlighted updates and features include Substantial improvements to the Go linker, Improved allocation for small objects at high core counts, X.509 CommonName deprecation, GOPROXY supports skipping proxies that return errors, New embedded tzdata package, Several Core Library improvements and more.

Tiny Go: Small Is Going Big

Ron Evans talks about TinyGo - a compiler for Go, written in Go itself, that uses LLVM to achieve very small, fast, and concurrent binaries that can also target devices where Go could never go before.

Secure HTTPS servers in Go

In this article, we are going to look at some of the basic APIs of the http package to create and initialize HTTPS servers in Go

Go Go Release!

TLDR; Just Want A Go Release Tool? I’m neither a lover nor a hater when it comes to Go and its ecosystem. Generally things Go are a bit rudimentary but very open and accessible. You may have to do some work yourself, but you’ll be able to get results.