Creating CLI Utilities in Go with the Cobra Library
Let's start from the very beginning – installation and configuration of the project.
Installation
The first thing you need to do is install the Cobra library itself:
go get github.com/spf13/cobra/cobra
Next, you need to initialize a new project. There is a commandcobra init
which will create all the files and directory structure for the project. Go to the directory where the project will be located and execute:
cobra init --pkg-name ваше_имя_проекта
The command will prepare the basic structure of the CLI application by creating a directory cmd
and in it is the initial file root.go
which will be the entry point to the application.
Now you're ready to get started!
Creating the Basic CLI Structure
At the root of a Go CLI project, the main file that serves as the entry point is root.go
. This file is located in the directory cmd/
and contains the definition of the application's root command. Sample Contents root.go
:
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "[your-cli-app-name]",
Short: "A brief description of your CLI application",
Long: `A longer description that explains your CLI application in detail,
including available commands and their usage.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Welcome to [your-cli-app-name]! Use --help for usage.")
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func main() {
Execute()
}
The code defines the basic structure and command that is executed by default when users run your application without any subcommands.
Use
: how the command is called from the command line.Short
: a short description of the command, shown in the help.Long
: a more detailed description that is also displayed in the help.Run
: a function that is executed when the command is called.
Function Execute()
is called in main.go
and is responsible for executing the root command.
To extend the functionality of the CLI application, you can add new commands using the command cobra add <commandName>
. This will create a new file in the directory cmd/
containing the code template for the new command. For example, adding the command add
will create a file add.go
with the following contents:
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var addCmd = &cobra.Command{
Use: "add",
Short: "Add numbers",
Long: `Adds two numbers and prints the result.`,
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Adding numbers...")
// логика добавления номеров
},
}
func init() {
rootCmd.AddCommand(addCmd)
}
The code defines a new command add
which requires two arguments and executes the function defined in Run
.
To manage configurations, the CLI application can be used Viper. IN root.go
you can initialize Viper in a function initConfig
:
func initConfig() {
viper.AddConfigPath("path/to/your/config")
viper.SetConfigName("config")
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can't read config:", err)
os.Exit(1)
}
}
The code downloads the configuration file and makes it available in the application.
Flags and Subcommands
Flags in Cobra come in two forms: local and persistent. Local flags apply only to the command they are attached to, while persistent flags are also inherited by all subcommands of that command.
Example of adding a local flag:
import (
"fmt"
"github.com/spf13/cobra"
)
var cmd = &cobra.Command{
Use: "example",
Run: func(cmd *cobra.Command, args []string) {
// логика
},
}
func init() {
cmd.Flags().StringP("flagname", "f", "default", "Description of the flag")
}
Flag flagname
available only to the team example
.
Example of adding a permanent flag:
func init() {
cmd.PersistentFlags().StringP("persistflag", "p", "default", "Description of persistent flag")
}
Permanent flag persistflag
will be available both for the team it is attached to and for all its subteams.
Subcommands allow you to build multi-level CLI structures, where each command can have its own subcommands.
Example:
var rootCmd = &cobra.Command{Use: "app"}
var subCmd = &cobra.Command{
Use: "sub",
Short: "This is a subcommand",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Subcommand executed")
},
}
func init() {
rootCmd.AddCommand(subCmd)
}
In this case sub
is a subcommand for app
. You can add as many subcommands as you like, creating complex command hierarchies.
Example of using Cobra
Let's create a task management utility, similar to a simplified version todo
applications. We will not implement the logic of work, so as not to complicate the reading, we will consider only what concerns Cobraю
First, we create the basis of the application. We define the root command and the basic structure:
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var rootCmd = &cobra.Command{
Use: "tasker",
Short: "Tasker is a CLI for managing your tasks",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application.`,
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func main() {
Execute()
}
Add subcommands for creating, viewing and deleting tasks:
func init() {
rootCmd.AddCommand(addCmd)
rootCmd.AddCommand(listCmd)
rootCmd.AddCommand(deleteCmd)
}
var addCmd = &cobra.Command{
Use: "add [task]",
Short: "Add a new task",
Run: func(cmd *cobra.Command, args []string) {
// логика добавления задачи
fmt.Println("Added task:", args[0])
},
}
var listCmd = &cobra.Command{
Use: "list",
Short: "List all tasks",
Run: func(cmd *cobra.Command, args []string) {
// логика отображения всех задач
fmt.Println("Listing all tasks")
},
}
var deleteCmd = &cobra.Command{
Use: "delete [id]",
Short: "Delete a task by its ID",
Run: func(cmd *cobra.Command, args []string) {
// логика удаления задачи
fmt.Println("Deleted task with ID:", args[0])
},
}
Let's add flags to refine actions, for example, to filter the task list:
func init() {
listCmd.Flags().BoolP("completed", "c", false, "Show only completed tasks")
}
Using Viper:
func initConfig() {
viper.AddConfigPath(".")
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
func init() {
cobra.OnInitialize(initConfig)
}
You can find more information about Cobra find out here.
OTUS experts tell more about programming languages in practical online courses. With a full catalog of courses You can read it at the link.