В этом руководстве мы обсудим, как написать справочное сообщение с помощью пакета Cobra.

›Кратко о Cobra

Cobra - мощный пакет командной строки для Golang. Полный список проектов, использующих Cobra, находится здесь.

> Прежде чем вы начнете

Установите Cobra на свой компьютер:

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

Тем не менее, вам не нужно создавать файлы нашего приложения. Есть генератор, с помощью которого очень легко создать рабочий каталог.

Для установки генератора используйте эту команду:

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

Прежде чем мы начнем писать код, давайте рассмотрим справочное сообщение, которое мы собираемся создать с помощью пакета Cobra.

›Написание справочного сообщения

Справочное сообщение (или сообщение об использовании, или документ) - это то, что видят пользователи, когда

  • вызвать программу,
  • введите флаг, например --hили -h,
  • введите недопустимые аргументы.

Это сообщение включает в себя название программы, ее использование и параметры. Если вы используете командную строку, вы уже знакомы со справочными сообщениями или сообщениями об использовании. В Linux обычно можно набрать program --help, чтобы получить список допустимых аргументов программы.

В этом руководстве мы пишем справочное сообщение для программы, которая выводит:

  • список случайных чисел указанного количества и диапазона, или
  • список случайных букв определенного количества и языка.

Это наше сообщение об использовании:

Давайте проанализируем команду, числа из предыдущего сообщения:

randx numbers --count <count> [--range <range>...]

  • randx - название программы,
  • numbers - команда,
  • --count - вариант команды,
  • <count> - значение опции - количество,
  • [--range <range>…] - необязательный параметр, для которого требуется значение или несколько значений,
  • [--verbose] - необязательный флаг.

У нас есть две команды, numbers и letters (bool), для включения режима цифр или букв соответственно. Если один из них true, другой - false.

Параметр — count (int) требуется для команд numbers иletters. Программа выводит список цифр или букв указанного количества.

$ randx numbers --count 1

$ randx letters --count 1

Чтобы объявить необязательный аргумент --range ([] строка), мы используем квадратные скобки. Три точки в квадратных скобках означают, что вы можете передать в командную строку несколько аргументов. Например,

--range 1,10 --range 1,11 or
--range 1-10 --range 1-11 or
--range 1:10 --range 1:11

Эта опция устанавливает диапазон случайных чисел. Если есть два аргумента, программа выводит два списка с указанными диапазонами.

Необязательный аргумент --lang (строка), также заключен в квадратные скобки . Параметр принимает язык. Поэтому программа выводит буквы указанного языка.

Программа должна возвращать справочное сообщение, если необходимая опция не установлена ​​и / или аргументы недействительны. Оба параметра --range и --lang можно не указывать.

Кроме того, у нас есть три варианта (или просто флаги) без операндов в сообщении об использовании:

  • -h / --help - вывести сообщение об использовании,
  • --verbose - выводить подробную информацию о том, что делает программа; флаг используется для информирования пользователя о том, что программа на самом деле делает, включая ошибки при выполнении требуемого действия. Это может быть полезно для устранения неполадок.
  • --version - выведите версию используемой программы.

›Создание структуры проекта

  1. Создайте и перейдите в каталог:
mkdir -p ~/go/src/github.com/your_username/app && 
cd ~/go/src/github.com/your_username/app

2. Создайте структуру проекта с помощью cobra init:

cobra init --pkg-name ~/go/src/github.com/your_username/app

После этого у нас будет следующая структура проекта:

— — cmd
— — — root.go
— — LICENSE
— — main.go

Файл root.go содержит rootCmdcommand, который инициализирует все команды и флаги (или параметры).

›Создание команд

Чтобы добавить новую команду, просто используйте cobra add commandName в каталоге проекта. Для нашего справочного сообщения нам нужно создать две команды numbers и letters:

$ cobra add numbers
$ cobra add letters

После этого пакет cobra создает два файла, а именно numbers.go и letter.go в каталоге cmd. Теперь у нас есть следующая структура проекта:

 — — cmd
 — — — root.go
 — — — numbers.go
 — — — letters.go
 — — LICENSE
 — — main.go

›Как выглядит main.go

В файле main.go мы выполняем наши команды с cmd.Execute(). Полный код выглядит так:

package main
import “github.com/your_user_name/app/cmd”
func main() {
    cmd.Execute()
}

Здесь нет необходимости добавлять дополнительный код. Давайте создадим подкоманды и параметры в файлах numbers.go и letter.go.

›Команда чисел

Cobra сгенерировала часть следующего кода. Мы объявили переменные countFlagNumbers и rangeFlagNumbers для хранения значений из
--count и --rangeflags соответственно. Кроме того, мы инициализировали необходимые флаги (--count и --range) в функции init().

// beginning of numbers.go
package cmd
import (
    "fmt"
    "github.com/spf13/cobra" 
)
var (
    countFlagNumbers int
    rangeFlagNumbers []string
)
var numbersCmd = &cobra.Command{
    Use:   "numbers",
    Short: "Returns random numbers",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("numbers mode")
        fmt.Println("--count:", countFlagNumbers)
        fmt.Println("--range:", rangeFlagNumbers)
        fmt.Println("--verbose:", verbose)
    },
}
// here is init()

Мы вызываем метод arootCmd.AddCommand() для инициализации команды numbers.

//beginning of init()
func init() {
    rootCmd.AddCommand(numbersCmd)
...

Объявление каждого флага имеет следующий шаблон:

commandName.Flags().TypeOfValuesP(
    where to store, long flag name,
    short flag name, default value,
    explanation,
)

Объявить флаг --count:

...
    numbersCmd.Flags().IntVarP(
        &countFlag, "count", "c", 0,
        "A count of random numbers",
    )
...  

И сделайте этот флаг обязательным:

... 
    numbersCmd.MarkFlagRequired("count")
...

Когда мы делаем флаг обязательным, это означает, что пользователь не может выполнить программу без установленного флага. Произойдет ошибка.

Объявите флаг --range:

...
    numbersCmd.Flags().StringSliceVarP(
        &rangeFlag, "range", "r", []string{"1:100"}, 
        "Range of numbers. Optional",
    )
}
// end of init()
// end of numbers.go

›Письма команды

Так же, как и в numbers.go, был сгенерирован некоторый из следующего кода. Здесь мы объявили переменные countFlagLetters и langFlagLetters для хранения полученных значений от флагов --count и --lang соответственно.

// beginning of letters.go
package cmd
import (
    “fmt”
    “github.com/spf13/cobra”
)
var (
    countFlagLetters int
    langFlagLetters  string
)

Команда lettersCmd имеет ту же структуру, что и numbersCmd. Все флаги инициализируются так же, как в файле numbers.go.

var lettersCmd = &cobra.Command{
    Use:   "letters",
    Short: "Returns random letters",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("letters mode")
        fmt.Println("--count:", countFlagLetters)
        fmt.Println("--lang:", langFlagLetters)
        fmt.Println("--verbose:", verbose)
    },
}
func init() {
    rootCmd.AddCommand(lettersCmd)
    lettersCmd.Flags().IntVarP(
        &Count, "count", "c", 0,
        "A count of random letters",
    )
    lettersCmd.MarkFlagRequired("count")
    
    lettersCmd.Flags().StringVarP(
        &Lang, "lang", "l", "en", 
        "A language. Optional",
     )
}
// end of letters.go

›Добавление флагов версии и подробного вывода

В root.go мы обновляем использование нашей программы, добавляем --version и
--verboseflags.

package cmd
import (
    "fmt"
    "os"
    "github.com/spf13/cobra"
)

Объявите подробную переменную. Имеет тип bool.

var (
    verbose bool
)

Чтобы показать версию нашей программы, добавьте параметр Version и укажите текущую версию в кавычках.

var rootCmd = &cobra.Command{
    Use:     "randx",
    Version: "1.0.1",
    Short:   "Returns random numbers or letters.",
}
func Execute() {
    if err := rootCmd.Execute(); 
    err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

The--verboseflag является постоянным и глобальным. Это означает, что вы можете указать программе, чтобы она показывала вам подробности выполнения программы с любой установленной командой и флагом.

func init() {
    rootCmd.PersistentFlags().BoolVarP(
        &verbose, "verbose", "v", false,
        "Verbose output",
    )
}

> Использование

В этом разделе вы можете найти несколько примеров использования Cobra в командной строке.

›› Буквенный режим

$ go run main.go letters --count 9 
$ go run main.go letters -c 9
letters mode
--count: 9
--lang: en // this is a default value
--verbose: false
$ go run main.go letters --count 9 --lang en 
$ go run main.go letters -c 9 -l en
letters mode
--count: 9
--lang: en
--verbose: false

›› Режим чисел

$ go run main.go numbers --count 9 
$ go run main.go numbers -c 9 
numbers mode
--count: 9
--range: [1:100] // this is a default value
--verbose: false
$ go run main.go numbers --count 10 --range 9,10 
$ go run main.go numbers -c 10 -r 9,10
numbers mode
--count: 10
--range: [9 10]
--verbose: false
$ go run main.go numbers --count 10 --range 9,10 --range 0,15
numbers: true
--count: 10
--range: [9 10 0 15]
--verbose: false

Несколько комментариев по поводу разделителей. Если вы используете запятую в качестве разделителя во флаге
--range, вы получите только список чисел. Как обсуждалось ранее, вы можете использовать двоеточие: для разделения этих чисел. Например:

$ go run main.go numbers --count 10 --range 9:10 --range 10:11
numbers mode
--count: 10
--range: [9:10 10:11]
--verbose: false

>> Подробный

$ go run main.go numbers --count 18 --range 9,19 --verbose 
$ go run main.go numbers -c 18 -r 9,19 --verbose
numbers mode
--count: 18
--range: [9 19]
--verbose: true

›Об авторе

Джейн - программист на Go и технический писатель в области разработки программного обеспечения. В течение 5 лет она писала технические материалы на английском и русском языках. Она закончила Новосибирский государственный технический университет по специальности Информационная безопасность по специальности Информационная безопасность автоматизированных систем. Вы можете подписаться на нее в Твиттере и увидеть другие ее письменные работы на publishing.enthusiastic.io.