Criando Command Line Interface (CLI) com Cobra

Go é uma linguagem muito versátil, o que nos possibilita criar vários tipos de programas. Dentre os tipos, um dos que nos ajuda muito no dia a dia são os do tipo Command Line Interface ou só CLI, como normalmente chamamos.

Hoje vamos ver como utilizar um package open source chamado Cobra para nos ajudar nessa tarefa. Vamos utiliza-lo por ele ser usado por grandes implementações de CLI como por exemplo Kubernetes, Hugo e GitHub CLI.

Primeira coisa que vamos fazer é instalar o package.

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

Agora vamos criar um arquivo hello.go, onde vamos criar um comando para retornar um “Olá + parâmetro passado”.

Nesse arquivo vamos criar uma função que retorna uma struct do tipo *cobra.Command.

package main

import (
    "github.com/spf13/cobra"
)

func Hello() *cobra.Command {

}

Essa struct cobra.Command é onde vamos ter toda a definição do nosso comando. Como nosso comando será bem simples, vamos definir os seguintes atributos dessa struct.

  • Use: Exemplo de utilização do comando
  • Short: Pequena descrição do que o comando faz
  • Args: Número de argumentos esperado
  • Run: Função com o código do comando

Tendo explicado o que é cada um dos atributos, vamos criar essa struct dentro da nossa função Hello.

package main

import (
    "fmt"
    "github.com/spf13/cobra"
)

func Hello() *cobra.Command {
    return &cobra.Command{
        Use:   "hello [name]",
        Short: "retorna Olá + name passado",
        Args:  cobra.ExactArgs(1),
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Olá %s\n", args[0])
        },
    }
}

Implementado nosso comando, vamos criar um arquivo main.go e adicionar a função main do nosso programa.

package main

import "github.com/spf13/cobra"

func main() {
    rootCmd := &cobra.Command{}
    rootCmd.AddCommand(Hello())

    rootCmd.Execute()
}

Dentro da função main, nós criamos um comando vazio para servir de root de todos os comandos.

Logo em seguida, adicionamos nossa função e depois executamos a função Execute da struct que criamos como root.

Agora vamos buildar nosso programa com o seguinte comando.

$ go build -o agl

Assim que o build finalizar, você deve ter um binário chamado agl. Para garantir que deu tudo certo e nosso comando foi adicionado, vamos executar o seguinte:

$ ./agl --help

O retorno deve ser algo semelhante a isso:

Usage:
   [command]

Available Commands:
  completion  generate the autocompletion script for the specified shell
  hello       retorna Olá + name passado
  help        Help about any command

Flags:
  -h, --help   help for this command

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

Como podemos ver, nosso comando hello está ali logo abaixo de completion. Agora faça um ./agl hello --help e veja a mágica acontecer.

retorna Olá + name passado

Usage:
   hello [name] [flags]

Flags:
  -h, --help   help for hello

Como podemos ver o package cobra nos ajuda em muitos detalhes para que tenhamos um CLI bonito e bem estruturado.

Agora, vamos finalmente testar nosso comando fazendo um ./agl hello Mundo.

Bacana não?!

Antes de finalizar esse post, vamos fazer uma pequena mudança em nosso código para, ao invés de argumento, a gente passar o valor que queremos concatenar com “Olá” usando uma flag.

func Hello() *cobra.Command {
    var name string

    cmd := &cobra.Command{
        Use:   "hello [name]",
        Short: "retorna Olá + name passado",
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Printf("Olá %s\n", name)
        },
    }

    cmd.Flags().StringVarP(&name, "name", "n", "Mundo", "flag para concatenar com Olá")

    return cmd
}

Como podemos ver, as mudanças foram bem simples.

  1. Adicionamos uma nova variável no inicio que será usada dentro da função do comando;
  2. Atribuímos a struct a uma variável chamada cmd;
  3. Removemos o atributo Args da definição da struct;
  4. Passamos o ponteiro da variável name na função StringVarP seguida do nome da flag, nome curto da flag, valor default, pequena descrição sobre o que a flag faz.

Feito isso, vamos fazer o go build -o agl novamente e depois testar nossa mudança.

$ ./agl hello
retorno: Olá Mundo

$ ./agl hello --name Gopher
retorno: Olá Gopher

Deixem suas dúvidas nos comentários.

Até a próxima!


Subscreva

Fique por dentro de tudo o que acontece no mundo Go.

Deixe uma resposta