В инструменте командной строки Cobra, как использовать одну и ту же переменную для разных флагов? - PullRequest
0 голосов
/ 28 февраля 2020

Этот пример приложения Cobra, https://github.com/kurtpeek/myCobraApp, содержит каркас приложения Cobra с использованием генератора Cobra со следующими командами:

cobra add serve
cobra add config

Структура каталога

.
├── LICENSE
├── cmd
│   ├── config.go
│   ├── root.go
│   └── serve.go
├── go.mod
├── go.sum
└── main.go

В config.go строковая переменная deviceUUID определена и привязана к флагу для этой команды со значением по умолчанию "configDeviceUUID":

var deviceUUID string

func init() {
    rootCmd.AddCommand(configCmd)

    // Cobra supports local flags which will only run when this command
    // is called directly, e.g.:
    configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")
    fmt.Println("deviceUUID after config init:", deviceUUID)
}

Аналогично, в serve.go deviceUUID переменная привязана к локальному флагу:

func init() {
    rootCmd.AddCommand(serveCmd)

    serveCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "serveDeviceUUID", "Device UUID")
    fmt.Println("deviceUUID after serve init:", deviceUUID)
}

Проблема в том, что если я запускаю команду config без указания флага deviceUUID в командной строке, он выбирает значение по умолчанию из команды serve:

> go run main.go config
deviceUUID after config init: configDeviceUUID
deviceUUID after serve init: serveDeviceUUID
deviceUUID: serveDeviceUUID
config called

Кажется, что происходит то, что функции init() в каждом файле выполняются в алфавитном порядке, и последняя из них устанавливает значение флага по умолчанию .

Как мне избежать этого поведения? Я бы хотел, чтобы значение по умолчанию, установленное в config.go, всегда применялось к команде config. (Конечно, я мог бы объявить отдельные переменные, такие как configDeviceUUID и serveDeviceUUID, но мне это кажется немного беспорядочным).

1 Ответ

1 голос
/ 28 февраля 2020

Я не знаю, почему вы считаете, что грязный . У вас есть одна переменная, и вы устанавливаете ее в нескольких init функциях, поэтому параметр last остается тем, который остается установленным: ваше объяснение происходящего является правильным. Понятно, что на самом деле это две разные переменные, просто одна из них будет использоваться .

(Предполагается, что есть другие команды, которые делают другие вещи, возможно, нет Будет использоваться этих глобальных переменных. Если бы Go был языком c с естественной более динамичностью, в котором все определяется во время выполнения, или если вы использовали более динамически c Настройка во время выполнения, вы не могли бы создать ни одного из них, но это не Go: Go полон переменных stati c typing и stati c, созданных во время соединения.)

Если вы действительно хотите использовать только одну глобальную переменную, тем не менее, очевидное решение состоит в том, чтобы выбрать какое-то значение часового, чтобы оно означало , а не установить , и сделать это значение по умолчанию, которое устанавливает Cobra. Затем, если переменная содержит значение «не установлено» при запуске команды, вы знаете, что пользователь не предоставил значение.

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

if deviceUUID == "" {
    deviceUUID = defaultDeviceUUID
}

и все готово.

Это может быть приятно или, по крайней мере, более удобно для вас, если код кобры сохранен значения инициализатора по умолчанию где-то private , когда вы сделали:

configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")

, а затем скопировали эти приватные, сохраненные значения по умолчанию в (одну) глобальную переменную , когда команда верхнего уровня решила, что подкоманду config следует использовать вместо того, чтобы не сохранять ее где-то в частном порядке и копировать ее в (единственную) глобальную переменную в в то время функция configCmd.Flags().StringVar() называется , но на самом деле это не так. Итак:

configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "", "Device UUID")

плюс приведенных выше тестов с пустыми строками может быть достаточно. Обратите внимание, что каждый init все еще перезаписывает глобальную переменную (одну, общую и, возможно, даже никогда не используемую) каждый раз, но все они устанавливают ее из начального значения пустой строки в новое значение пустой строки , оставив его без изменений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...