Getting started with CLI's using Golang.

Getting started with CLI's using Golang.

Build your own Simple CLI using Golang and Cobra-CLI :)

Introduction

In this blog we are going to get started with CLI using Golang and Cobra CLI. We are just going to make a simple Quiz game CLI and get friendly with the Cobra-CLI library.

Why Cobra-CLI?

Cobra is both a library for creating powerful modern CLI applications and a program to generate applications and CLI applications in Go. Cobra powers most of the popular Go applications including CoreOS, Delve, Docker, Dropbox, Git Lfs, Hugo, Kubernetes, and many more. With integrated command help, autocomplete and documentation.

Prerequisites

To continue with tutorial, firstly you need to have Golang and Cobra-CLI installed.

Installation

  • Golang

  • For installing Cobra-CLI you can go to Cobra or run go install github.com/spf13/cobra-cli@latest in the terminal.

Initializing the Project

After completing the Installation part to get started make a folder for eg. go_quiz , run the given command

go mod init github.com/Siddheshk02/go_quiz

In place of Siddheshk02 use the name in which your project directories are. Now the structure will look like this

mod init.png

Cobra-cli init

This command initializes the CLI and make a main.go file along with cmd folder containing root.go

cli.png

The main.go file will contain this code

package main

import "github.com/Siddheshk02/go_quiz/cmd"

func main() {
    cmd.Execute()
}

This means the main cli commands implementation will be in cmd which is called through main.go.

Make the following changes in the root.go file.

package cmd

import (
    "os"

    "github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
    Use:   "go_quiz",
    Short: "A Simple Quiz game CLI",
    Long: `A Simple Quiz game CLI using Golang.`,

}

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

func init() {
    rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

In root.go, function Execute gets called from main.go and it executes the rootCmd. Use is used to define the command to be used and Short and Long contains the information or description for the Command in short and long format respectively.

Now run go run main.go or go build . and .\go_quiz or go_quiz.

C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz> go run main.go
A Simple Quiz game CLI using Golang.
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz> go build .
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz> .\go_quiz
A Simple Quiz game CLI using Golang.
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz>go_quiz -h       
A Simple Quiz game CLI using Golang.

Usage:
  go_quiz [flags]
  go_quiz [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  help        Help about any command
  start       Starting a new Quiz

Flags:
  -h, --help     help for go_quiz
  -t, --toggle   Help message for toggle

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

Now let's make a csv file data.csv in the go_quiz directory, to store the questions and answers for the quiz.

Store the following values in the file.

5+5,10
7+3,10
1-1,0
8+3,11
1+2,3
8-6,2
3-1,2
1+4,5
5-1,4
2+3,5
3+3,6
7-4,3
5+2,7
9-2,7
4+8,12
1+8,9

Lets make a new command which will be used to start a Quiz.

for adding a new command run this code Cobra-cli add start, here start is the new command made.

This will create a new file start.go in the cmd folder.

start_new.png

Make the following changes in the start.go file

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

var startCmd = &cobra.Command{
    Use:   "start",
    Short: "Starting a new Quiz",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("start called")
    },
}

func init() {
    rootCmd.AddCommand(startCmd)
}

let's try running our new command. Run go build . in the terminal and then run go_quiz start

C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz>go_quiz start    
start called

you can also try running go_quiz start -h.

Now, for the main implementation of the Quiz game, we will make a folder pkg in the project directory i.e. go_quiz and a file quiz.go in the pkg folder.

pkg.png

In the quiz.go make a functionQuiz that returns a string res

func Quiz() (res string) {

    return res
}

This function will be called in the start.go as :

Run: func(cmd *cobra.Command, args []string) {
        res := pkg.Quiz
},

Now, let's code in the Quiz function in quiz.go

Firstly, we need to open and read the data.csv file to get the questions and there answers.

package pkg

import (
    "encoding/csv"
    "errors"
    "fmt"
    "io"
    "log"
    "os"
    "strconv"
)

func Quiz() (res int, err error) {
    res = 0

    f, err := os.Open("C:/Users/Admin/Go/src/github.com/Siddheshk02/go_quiz/data.csv")
    if err != nil {
        log.Fatal(err)
    }

    defer f.Close()

    csvReader := csv.NewReader(f)
    var ans int
    for {
        rec, err := csvReader.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        fmt.Print(rec[0] + " : ")

        c, _ := strconv.Atoi(rec[1])

        fmt.Scanf("%d\n", &ans)

        if ans == c {
            res = res + 1
            fmt.Println("correct")
            continue

        } else {
            err = errors.New("Incorrect Response!!")

            break
        }

    }
    return res, err
}

Here, we are taking the questions and answers in rec which is a string array, so for each iteration in the loop the rec array takes question in rec[0] and answer in rec[1].

Then for comparing the user input ans with the original answer i.e. rec[1], we first convert rec[1] into integer type as ans is in integer whereas rec is string.

A res variable is created to store the result count, which is returned along with err error after completing the quiz or after giving an Incorrect response.

So, the start.go will look like the following code after all changes:

Run: func(cmd *cobra.Command, args []string) {
        res, err := pkg.Quiz()
        if err != nil {
            fmt.Println(err)
            fmt.Printf("Your Score is %d", res)
        } else {
            if res == 16 {
                fmt.Println("Congrats!, you got all questions Correct")
            }
            fmt.Printf("Your Score is %d", res)
        }
    },

Now, run go build . and then go_quiz start to test the CLI.

C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz>go_quiz start 
5+5 :

Enter the answers after getting the question :)

If all the given responses are correct

.
.
.
1+8 : 9
correct
Congrats!, you got all questions Correct
Your Score is 16

And if any of the response is Incorrect :(

.
.
7+3 : 10
correct
1-1 : 0
correct
8+3 : 1 
Your Score is 3

The complete code is saved on GitHub

Conclusion

In this tutorial we learnt how to create a command-line application with Go and Cobra. In the next upcoming tutorial , we will learn how to add flags, commands, etc. and build more such amazing stuff.

If you enjoyed this article and you'd like more, consider following Siddhesh on Twitter to get the latest updates.

Congratulations, you did great. Keep learning and keep coding :)