Aprenda a criar aplicações CLI em Go com a biblioteca Cobra, desde a configuração inicial até a adição de subcomandos e flags.
Tempo de Leitura: 10 minutos
Uma Interface de Linha de Comando (CLI) é uma forma de interação entre o usuário e o sistema, onde comandos de texto são digitados diretamente em um terminal ou console para executar tarefas. Ao contrário das interfaces gráficas (GUI), onde o usuário interage com o sistema por meio de janelas, botões e ícones, uma CLI baseia-se inteiramente em texto e requer a execução de instruções específicas por meio de comandos.
O que é uma Interface de Linha de Comando (CLI)?
Neste artigo, exploraremos o conceito de CLI, exemplos de programas que utilizam essa abordagem, e como desenvolver uma aplicação de comandos CLI em Go usando o Cobra CLI. Além disso, veremos como essa biblioteca pode simplificar a criação de ferramentas robustas, escaláveis e eficientes.
Ao final, você terá uma compreensão profunda das vantagens no uso de CLI e dos passos práticos para implementá-las.
Uma Interface de Linha de Comando (CLI) é uma forma de interação entre o usuário e o sistema, onde comandos de texto são digitados diretamente em um terminal ou console para executar tarefas. Ao contrário das interfaces gráficas (GUI), onde o usuário interage com o sistema por meio de janelas, botões e ícones, uma CLI baseia-se inteiramente em texto e requer a execução de instruções específicas por meio de comandos.
Vantagens de uma CLI
- Eficiência: Para tarefas repetitivas ou complexas, a CLI pode ser mais rápida e eficiente em comparação a interfaces gráficas.
- Automação: Ferramentas de CLI podem ser facilmente integradas em scripts e sistemas de automação.
- Controle: Proporciona um nível maior de controle e personalização das operações.
- Flexibilidade: CLI permite que o usuário combine múltiplos comandos, use pipes e redirecione a saída de um comando para a entrada de outro.
Exemplos de programas CLI populares
Muitos programas amplamente utilizados baseiam-se em interfaces de linha de comando. Aqui estão alguns exemplos:
- Git: Ferramenta de controle de versão amplamente utilizada por desenvolvedores para versionamento de código. Sua interface CLI é a forma mais comum de interação com repositórios Git.
- AWS CLI: A Amazon Web Services oferece uma CLI para gerenciar seus serviços em nuvem. Isso permite que os usuários executem tarefas complexas, como provisionamento de servidores, diretamente de um terminal.
- Docker CLI: Ferramenta usada para gerenciar contêineres de software. Desenvolvedores podem usar a CLI para criar, executar e gerenciar containers Docker com comandos simples.
- Kubernetes CLI (kubectl): Usado para gerenciar clusters Kubernetes, facilitando o controle e automação de cargas de trabalho em contêineres.
Criando uma Biblioteca Compartilhada em Go
Go, também conhecido como Golang, é uma linguagem de programação desenvolvida pelo Google, conhecida por sua simplicidade e eficiência. Ela possui suporte nativo para a criação de bibliotecas compartilhadas. Neste guia, vamos criar uma biblioteca compartilhada simples em Go e demonstrar como utilizá-la em outras linguagens.
Pronto para expandir suas habilidades em Go? Aprenda a criar bibliotecas compartilhadas e integrá-las com outras linguagens. Confira este guia completo sobre Go e comece agora! Leia mais aqui.
1. Criar o código Go
Primeiramente, vamos criar um projeto Go. Usarei o VSCode, mas você pode utilizar o editor de sua preferência. Suponhamos que queremos criar uma aplicação para chamar funções via linhas de comando (prompt de comando, Powershell, bash). Crie uma pasta chamada go-cli:
Para isso, iremos criar o arquivo go mod do projeto. Vou seguir a normalização da nomenclatura usando o caminho do repositório Git. Por exemplo:
go mod init github.com/Thiagohalves85/go-cli
Esse comando irá gerar um arquivo go.mod com as informações do pacote. Com o nosso gerenciador de pacotes criados, vamos criar o arquivo main.go, que conterá a lógica da nossa aplicação.
Como estamos utilizando módulos no Go, vamos criar uma pasta chamada function com o arquivo function.go dentro do projeto. Esse arquivo conterá as funções que serão chamadas no nosso main.go.
O projeto ficará assim:
2. Estruturar funções
No arquivo function, vamos incluir as funções Somar, Subtrair, Multiplicar, Dividir, StringUppercase e ReverseString.
package function
import (
"strings"
)
func Somar(valor1, valor2 int) (resposta int) {
resposta = valor1 + valor2
return
}
func Subtrair(valor1, valor2 int) (resposta int) {
resposta = valor1 - valor2
return
}
func Multiplicar(valor1, valor2 int) (resposta int) {
resposta = valor1 * valor2
return
}
func Dividir(valor1, valor2 float64) (resposta float64) {
resposta = valor1 / valor2
return
}
func StringUppercase(campo string) string {
return strings.ToUpper(campo)
}
func ReverseString(campo string) string {
runes := []rune(campo)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
3. Configurar main.go
No arquivo main.go iremos importar o módulo de function fazer as chamadas dos métodos e ver os retornos:
package main
import (
"fmt"
f "github.com/Thiagohalves85/go-cli/function"
)
func main() {
//Retorno da soma
soma := f.Somar(10, 5)
fmt.Printf("A Soma de 10 e 5 é: %d\n", soma)
//Retorno da subtração
subtrai := f.Subtrair(10, 5)
fmt.Printf("A Subtração de 10 e 5 é: %d\n", subtrai)
//Retorno da multiplicação
multiplica := f.Multiplicar(10, 5)
fmt.Printf("A Multiplicação de 10 e 5 é: %d\n", multiplica)
//Retorno da divisão
divide := f.Dividir(10, 5)
fmt.Printf("A Divisão de 10 e 5 é: %g\n", divide)
//Retorno do texto maiusculo
textoMaiuculo := f.StringUppercase("texto retornado com as letras maiusculas!")
fmt.Println(textoMaiuculo)
//Retorno do texto reverso
textoReverso := f.ReverseString("esse texto vai ser reverso")
fmt.Println(textoReverso)
}
Explicação do código:
- Pacote main: Importa módulo da function
- Dentro da func main() estão sendo chamados os métodos que serão mostrados na tela quando fizer o comando go run main.go. Ficará assim:
4. Melhorando o código para passar os valores no prompt de comando
Até então os valores foram passados dentro do código sem a possibilidade de conseguir mudar, mas não é isso que queremos, então vamos alterar o código na main para que possamos imputar os valores pelo prompt de comando.
Usaremos a função fmt.Scanln() que ao executar o código espera que retornemos valores:
import (
fmt"
f "github.com/Thiagohalves85/go-cli/function"
)
func main() {
var nsoma1 int
var nsoma2 int
// Fazer a pergunta dos números para a soma
fmt.Println("digite o primeiro número da soma")
fmt.Scanln(&nsoma1)
fmt.Println("digite o segundo número da soma")
fmt.Scanln(&nsoma2)
//Retorno da soma
soma := f.Somar(nsoma1, nsoma2)
fmt.Printf("A Soma de %d e %d é: %d\n", nsoma1, nsoma2, soma)
var nsubtrai1 int
var nsubtrai2 int
// Fazer a pergunta dos números para a subtração
fmt.Println("digite o primeiro número da subtração")
fmt.Scanln(&nsubtrai1)
fmt.Println("digite o segundo número da subtração")
fmt.Scanln(&nsubtrai2)
//Retorno da subtração
subtrai := f.Subtrair(nsubtrai1, nsubtrai2)
fmt.Printf("A Subtração de %d e %d é: %d\n", nsubtrai1, nsubtrai2, subtrai)
var nmultiplica1 int
var nmultiplica2 int
// Fazer a pergunta dos números para a multiplicação
fmt.Println("digite o primeiro número da multiplicação")
fmt.Scanln(&nmultiplica1)
fmt.Println("digite o segundo número da multiplicação")
fmt.Scanln(&nmultiplica2)
//Retorno da multiplicação
multiplica := f.Multiplicar(nmultiplica1, nmultiplica2)
fmt.Printf("A Multiplicação de %d e %d é: %d\n", nmultiplica1, nmultiplica2, multiplica)
var ndivide1 float64
var ndivide2 float64
// Fazer a pergunta dos números para a divisão
fmt.Println("digite o primeiro número da divisão")
fmt.Scanln(&ndivide1)
fmt.Println("digite o segundo número da divisão")
fmt.Scanln(&ndivide2)
//Retorno da divisão
divide := f.Dividir(ndivide1, ndivide2)
fmt.Printf("A Divisão de %g e %g é: %g\n", ndivide1, ndivide2, divide)
var texto string
// Fazer a pergunta para inserir o texto
fmt.Println("digite um texto!")
fmt.Scanln(&texto)
//Retorno do texto maiusculo
textoMaiuculo := f.StringUppercase(texto)
fmt.Printf("O texto em maiusculo: %s", textoMaiuculo)
//Retorno do texto reverso
textoReverso := f.ReverseString(texto)
fmt.Printf("O texto ao contrário: %s", textoReverso)
}
O retorno será assim:
Agora conseguimos inserir informações para a aplicação de forma mais dinâmica, mas ter que ficar esperando até colocar um valor não é uma forma muito satisfatória, ainda mais se quisermos automatizar a aplicação.
Então vamos refatorar o nosso código para que possamos passar as informações via prompt de comando de forma mais simples e direta. E para isso iremos usar a biblioteca Cobra CLI.
Utilizando a biblioteca em outras linguagens
O que é Cobra CLI?
O Cobra CLI é uma biblioteca desenvolvida em Go que facilita a criação de aplicações de linha de comando. Cobra foi criada para ser robusta, modular e extensível, permitindo que desenvolvedores criem aplicações CLI completas com comandos, flags e subcomandos. Além disso, Cobra é amplamente utilizada na comunidade Go, sendo a escolha padrão para muitos projetos de código aberto, como o Kubernetes e o Helm.
Por que utilizar o Cobra CLI?
Algumas das principais razões para utilizar o Cobra incluem:
- Estrutura clara: Cobra fornece uma estrutura organizada para lidar com comandos e subcomandos.
- Facilidade de uso: Cobra abstrai a complexidade de lidar diretamente com os argumentos da linha de comando e oferece uma maneira fácil de definir comandos e opções.
- Suporte para subcomandos: Com Cobra, é possível criar aplicações com múltiplos níveis de subcomandos, o que é ideal para ferramentas complexas como git, que possuem muitos comandos (git commit, git push, etc.).
Funcionalidades principais do Cobra
- Comandos: Um comando é a unidade de ação da CLI. Cada comando pode ter flags (opções) associadas.
- Flags: Flags são opções que podem ser passadas para um comando para modificar seu comportamento.
- Argumentos: São os parâmetros passados para um comando.
- Autocompletar: Cobra permite habilitar o autocompletar de comandos no terminal, facilitando a usabilidade.
Refatorando a aplicação usando CLI com Cobra em Go
Agora, vamos começar. Primeiro, precisamos instalar o Cobra. Execute o seguinte comando para instalar o Cobra CLI:
go get -u github.com/spf13/cobra@latest
1. Estrutura do projeto
Agora, foi adicionada uma nova pasta, cmd, que contém os arquivos que definem cada comando da aplicação, com os arquivos root.go e subcommand.go.
2. Criando o comando raiz (root command)
Vamos começar criando o comando raiz da nossa aplicação. O comando raiz é o comando principal que a aplicação executa. Ele será responsável por iniciar a aplicação e exibir a ajuda.
No comando rootCmd, temos algumas configurações básicas:
- Use: Nome do comando que será utilizado no terminal.
- Short: Descrição curta do comando.
- Long: Descrição longa que aparecerá no comando de ajuda.
- Run: A função que será executada quando o comando for invocado.
Agora, vamos chamar nosso root no arquivo main.go:
package main
import (
"github.com/Thiagohalves85/go-cli/cmd"
)
func main() {
cmd.Execute()
}
Aqui, estamos chamando a função Execute definida no root.go, que inicializa nossa aplicação CLI.
3. Adicionando um subcomando
Agora, vamos adicionar um subcomando à nossa aplicação. Um subcomando é um comando adicional que é invocado a partir do comando raiz. Por exemplo, no Git, temos subcomandos como git commit, git push, etc.
Vamos alterar o arquivo cmd/subcommand.go:
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var helloCmd = &cobra.Command{
Use: "hello",
Short: "Diz olá para o usuário",
Long: "Este comando exibe uma mensagem de saudação para o usuário.",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Olá, seja bem-vindo à aplicação CLI!")
},
}
func init() {
rootCmd.AddCommand(helloCmd)
}
Aqui, criamos um novo comando chamado hello, que, quando executado, exibirá uma mensagem de saudação.
4. Adicionando flags
As flags são uma maneira de modificar o comportamento dos comandos. Vamos adicionar uma flag ao comando hello para permitir que o usuário personalize a saudação com o nome dele.
Modifique o arquivo cmd/subcommand.go para incluir uma flag:
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var nome string
var helloCmd = &cobra.Command{
Use: "hello",
Short: "Diz olá para o usuário",
Long: "Este comando exibe uma mensagem de saudação para o usuário.",
Run: func(cmd *cobra.Command, args []string) {
if nome != "" {
fmt.Printf("Olá, %s! Seja bem-vindo à aplicação CLI!\n", nome)
} else {
fmt.Println("Olá, seja bem-vindo à aplicação CLI!")
}
},
}
func init() {
rootCmd.AddCommand(helloCmd)
helloCmd.Flags().StringVarP(&nome, "nome", "n", "", "Seu nome")
}
Aqui, adicionamos uma flag chamada nome com o atalho -n. Quando o comando hello for executado com essa flag, ele exibirá uma saudação personalizada.
5. Testando a aplicação
Para testar a aplicação, execute o seguinte comando no terminal:
-
go run main.go hello
Isso deve resultar na mensagem:
-
Olá, seja bem-vindo à aplicação CLI!
Se você adicionar a flag -n, por exemplo:
-
go run main.go hello -n João
A saída será:
-
Olá, João! Seja bem-vindo à aplicação CLI!
6. Alterando a aplicação para incluir os métodos
Agora, vamos incluir os métodos do arquivo function.go para incluir a CLI nelas.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
f "github.com/Thiagohalves85/go-cli/function"
)
var nome, texto string
var valor1, valor2 int
var valor3, valor4 float64
// Chamada comando hello
var helloCmd = &cobra.Command{
Use: "hello",
Short: "Diz olá para o usuário",
Long: "Este comando exibe uma mensagem de saudação para o usuário.",
Run: func(cmd *cobra.Command, args []string) {
if nome != "" {
fmt.Printf("Olá, %s! Seja bem-vindo à aplicação CLI!\n", nome)
} else {
fmt.Println("Olá, seja bem-vindo à aplicação CLI!")
}
},
}
// Chamada comando somar
var somarCmd = &cobra.Command{
Use: "somar",
Short: "Chama a função de Somar",
Long: "Este comando retorna a soma de valor1 e valor2.",
Run: func(cmd *cobra.Command, args []string) {
if valor1 == 0 || valor2 == 0 {
fmt.Println("Os dois valores devem ser maiores que zero (0)")
} else {
resposta := f.Somar(valor1, valor2)
fmt.Printf("A Soma de %d e %d é: %d\n", valor1, valor2, resposta)
}
},
}
// Chamada comando subtrair
var subtrairCmd = &cobra.Command{
Use: "subtrair",
Short: "Chama a função de Subtrair",
Long: "Este comando retorna a subtração de valor1 e valor2.",
Run: func(cmd *cobra.Command, args []string) {
if valor1 == 0 || valor2 == 0 {
fmt.Println("Os dois valores devem ser maiores que zero (0)")
} else {
resposta := f.Subtrair(valor1, valor2)
fmt.Printf("A Subtração de %d e %d é: %d\n", valor1, valor2, resposta)
}
},
}
// Chamada comando multiplicar
var multiplicarCmd = &cobra.Command{
Use: "multiplicar",
Short: "Chama a função de Multiplicar",
Long: "Este comando retorna a multiplicação de valor1 e valor2.",
Run: func(cmd *cobra.Command, args []string) {
if valor1 == 0 || valor2 == 0 {
fmt.Println("Os dois valores devem ser maiores que zero (0)")
} else {
resposta := f.Multiplicar(valor1, valor2)
fmt.Printf("A Multiplicação de %d e %d é: %d\n", valor1, valor2, resposta)
}
},
}
// Chamada comando dividir
var dividirCmd = &cobra.Command{
Use: "dividir",
Short: "Chama a função de Dividir",
Long: "Este comando retorna a multiplicação de valor1 e valor2.",
Run: func(cmd *cobra.Command, args []string) {
if valor3 == 0 || valor4 == 0 {
fmt.Println("Os dois valores devem ser maiores que zero (0)")
} else {
resposta := f.Dividir(valor3, valor4)
fmt.Printf("A Divisão de %g e %g é: %g\n", valor3, valor4, resposta)
}
},
}
// Chamada comando strUppercase
var strUpperCmd = &cobra.Command{
Use: "strUppercase",
Short: "Chama a função de StringUppercase",
Long: "Este comando retorna a frase com letras MAIÚSCULAS.",
Run: func(cmd *cobra.Command, args []string) {
if texto == "" {
fmt.Println("O texto não pode estar vazio!")
} else {
retorno := f.StringUppercase(texto)
fmt.Printf("O texto em maiusculo: %s", retorno)
}
},
}
func init() {
//Adiciona os comandos para o root
rootCmd.AddCommand(helloCmd)
rootCmd.AddCommand(somarCmd)
rootCmd.AddCommand(subtrairCmd)
rootCmd.AddCommand(multiplicarCmd)
rootCmd.AddCommand(dividirCmd)
rootCmd.AddCommand(strUpperCmd)
// falg para o comando hello
helloCmd.Flags().StringVarP(&nome, "nome", "n", "", "Seu nome")
// flags para o comando somar
somarCmd.Flags().IntVarP(&valor1, "valor1", "a", 0, "Valor 1")
somarCmd.Flags().IntVarP(&valor2, "valor2", "b", 0, "Valor 2")
// falgs para o comando subtrair
subtrairCmd.Flags().IntVarP(&valor1, "valor1", "a", 0, "Valor 1")
subtrairCmd.Flags().IntVarP(&valor2, "valor2", "b", 0, "Valor 2")
// falgs para o comando multiplicar
multiplicarCmd.Flags().IntVarP(&valor1, "valor1", "a", 0, "Valor 1")
multiplicarCmd.Flags().IntVarP(&valor2, "valor2", "b", 0, "Valor 2")
// falgs para o comando dividir
dividirCmd.Flags().Float64VarP(&valor3, "valor1", "a", 0, "Valor 1")
dividirCmd.Flags().Float64VarP(&valor4, "valor2", "b", 0, "Valor 2")
// falg para o comando strUppercase
strUpperCmd.Flags().StringVarP(&texto, "texto", "t", "", "Texto")
}
Explicação:
- No arquivo subcommand.go importamos as funções da function;
- Criamos uma propriedade de comando para cada função (somarCmd, subtrairCmd, multiplicarCmd, dividirCmd e strUpperCmd)
- Na função init() adicionamos cada propriedade de comando na rootcmd e criamos as flags para cada comando;
7. Testando a aplicação com as alterações
Para testar a aplicação, execute o seguinte comando no terminal e deverá retornar da seguinte maneira:
8. Adicionando nas variáveis de ambiente
Para finalizar, vamos incluir nossa aplicação nas variáveis de ambiente para ser executada diretamente no prompt de comando.
1 - Gerar o executável:
-
go build -o gocli.exe main.go
2 - Pegue o executável e salve C:\go-cli
3 - No Windows vá em crie uma pasta
- Propriedades do Sistema -> Variáveis de Ambiente -> Variáveis do sistema -> Path -> Novo… -> C:\go-cli\
4 - No Linux edite o arquivo .bashrc ou .bash_profile (dependendo do seu shell) e adicione a seguinte linha:
- export PATH=$PATH:/<caminho para o diretório>/go-cli
5- Agora execute os comandos direto no prompt de comando
Conclusão
Desenvolver uma aplicação em Go é uma forma eficiente e estruturada de criar ferramentas robustas e versáteis. Neste artigo, exploramos o conceito de CLI, vimos exemplos de ferramentas populares que utilizam essa abordagem e criamos uma aplicação simples com o Cobra CLI.
A biblioteca Cobra permite expandir suas aplicações CLI de maneira fácil e modular, adicionando comandos e opções que tornam a interação dos usuários mais intuitiva e flexível. Com a prática e exploração, você pode criar ferramentas poderosas que automatizam tarefas e otimizam a eficiência do seu fluxo de trabalho.
Se tiver dúvidas ou quiser compartilhar experiências sobre o desenvolvimento de aplicações em Go, visite o fórum da Casa do Desenvolvedor e participe da nossa comunidade!