В този урок обсъждаме как да кодираме помощно съобщение с помощта на пакета 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), за да активираме съответно режима с цифри или букви. Ако едно от тях е вярно, друго е невярно.

Опцията — 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 и letters.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 и letters.go.

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

Cobra генерира част от следния код. Декларирахме променливи countFlagNumbersи rangeFlagNumbers за съхраняване на стойности съответно от
--countи --rangeфлагове. Освен това инициализирахме необходимите флагове (--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

› Добавяне на флагове Version и Verbose

В root.go актуализираме използването на нашата програма, добавяме флаговете --version и
_52.

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)
    }
}

Флагът--verbose е постоянен и глобален. Което означава, че можете да кажете на програмата да ви покаже подробности за изпълнението на програмата с всяка команда и зададен флаг.

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 флаг, ще получите само списък с числа. Както беше обсъдено по-рано, можете да използвате colon:, за да разделите тези числа. Например:

$ 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 години на английски и руски език. Завършила е специалност „Информационна сигурност“ в Новосибирския държавен технически университет и специализира информационна сигурност на автоматизирани системи. Можете да я последвате в Twitter и да видите другите й писмени работи на publications.enthusiastic.io.