Creating CLI Utilities in Go with the Cobra Library

Cobra turn regular Go code into a CLI tool. Cobra allows you to create command line interfaces.

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 initwhich 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.gowhich 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 addwhich 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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *