Парсинг флагов и аргументов в языке Go

27 ноября 2019

В этой небольшой заметке мы поговорим о том, как парсить флаги и аргументы командной строки в языке Go. Казалось бы, в стандартной библиотеке есть пакет flag — берешь и используешь. Но он плох тем, что заставляет пользователя указывать флаги в стиле -config, вместо всем привычных -c и --config. То есть, когда два знака минус используются для полного имени флага, и один знак для короткого. Кроме того, pflag не помогает обрабатывать сложные команды вроде тех, что использует утилита kubectlget nodes, describe pods, и так далее.

Поэтому вместо стандартного flag многие используют spf13/pflag:

package main

import (
    log "github.com/sirupsen/logrus"
    "github.com/spf13/pflag"
)

func main() {
    var showHelp bool
    var configPath string
    pflag.StringVarP(&configPath, "config", "c", "",
        "Config file path")
    pflag.BoolVarP(&showHelp,"help", "h", false,
        "Show help message")
    pflag.Parse()
    if showHelp {
        pflag.Usage()
        return
    }

    log.Infof("configPath == %s", configPath)
}

Библиотека предельно проста в использовании, поэтому не будем подробно на ней останавливаться. Стоит только отметить, что в ней нет понятия «обязательного аргумента». Дело в том, что библиотека работает с флагами, а все флаги по определению опциональны. Зато в spf13/pflag есть проверка множества разных форматов. Например, можно убедиться, что пользователь указал правильный IP-адрес, и всякое в таком духе.

Аргументы часто парсятся с помощью spf13/cobra. Cobra позиционируется как фреймворк для написания CLI с интерфейсом в стиле kubectl get pods. Пример использования:

package main

import (
    log "github.com/sirupsen/logrus"
    "github.com/spf13/cobra"
)

func main() {
    var configPath string

    rootCmd := cobra.Command{
        Use: "rest-service-example",
        Version: "v1.0",
        Run: func(cmd *cobra.Command, args []string) {
            log.Infof("configPath == %s", configPath)
        },
    }

    rootCmd.Flags().StringVarP(&configPath, "config", "c", "",
                               "Config file path")
    err := rootCmd.MarkFlagRequired("config")
    if err != nil {
        panic("rootCmd.MarkFlagRequired() failed")
    }

    err = rootCmd.Execute()
    if err != nil {
        // Required arguments are missing, etc
        return
    }
}

Заметьте, что флаг --config теперь стал обязательным.

Больше примеров вы найдете в документации. Например, из нее вы узнаете, как сделать поддержку нескольких команд в одной утилите и построить из этих команд иерархию. А еще, что cobra имеет безумный функционал типа генерации автокомплишена для Bash и Zsh.

Интересно, что kubectl реально написан с использованием данных библиотек.

А чем вы парсите флаги и аргументы в Go?

Дополнение: Парсинг конфигов в Go с помощью Viper

Метки: .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.