Содержание урока · 12 разделов
- Что такое Cobra: go-библиотека CLI и её история
- Кто написан на Cobra
- Анатомия CLI: команда, подкоманда, флаг, аргумент
- Что общего у kubectl, Hugo и gh
- Cobra против пакета flag
- flag и Cobra: что приходится писать самому
- Когда Cobra не нужна
- Как устроен курс и что понадобится
- Что дальше
- Песочница урока
- Коротко: что запомнить
- Вопросы и ответы
Откройте терминал и наберите kubectl get pods -n prod --watch. За долю секунды kubectl разберёт эту строку: get — подкоманда, pods — её аргумент, -n и --watch — флаги, один со значением, другой без. Потом он напечатает справку, если вы ошиблись, дополнит имя подкоманды по Tab и молча проглотит любой порядок флагов. Ничего из этого не имеет отношения к Kubernetes — это работа CLI-фреймворка. Написать разбор строки руками на os.Args можно: срез строк, switch по первому элементу, вложенный switch внутри него. Но к третьей подкоманде в коде заводится собственный мини-парсер, к пятой — самодельная справка, а к седьмой вы ловите себя на том, что пишете kubectl в миниатюре вместо своей задачи. Cobra закрывает именно эту рутину — и сейчас разберём, как она устроена и зачем её вообще отделять от бизнес-логики.
Что такое Cobra: go-библиотека CLI и её история#
Cobra — CLI-фреймворк для Go: библиотека, которая берёт на себя разбор командной строки, дерево подкоманд, справку и автодополнение. Написал её Стив Франсия (Steve Francia, ник spf13) в 2013 году — тот же человек за год до этого создал генератор сайтов Hugo, а позже руководил developer relations в Docker и Google. Проект годами живёт в версии 1.x: API стабилен настолько, что примеры из туториалов пятилетней давности компилируются без правок. Код лежит в github.com/spf13/cobra, а рядом живёт Viper — библиотека конфигурации от того же автора; в реальных CLI они часто ходят парой, и в этом курсе мы до неё тоже дойдём. За эти годы Cobra стала стандартом де-факто: когда в Go-команде встаёт вопрос «как делать CLI», ответ по умолчанию — она же, и собеседования спрашивают ровно про это. У Cobra две ипостаси, которые новички часто путают: сама библиотека и генератор каркасов cobra-cli — отдельная утилита, которая по одной команде создаёт готовый проект. С генератором познакомимся во втором уроке, пока важен словарь.
Кто написан на Cobra#
- Kubernetes — kubectl целиком построен на Cobra: get, apply, describe и десятки других подкоманд
- GitHub CLI (gh) — pr, issue, repo: три уровня дерева команд на одном фреймворке
- Hugo — генератор статических сайтов, родной брат Cobra: автор у обоих один и тот же
- Docker CLI — клиент docker переехал на Cobra вместе с системой плагинов
- rclone, etcd, Twitch CLI — список проектов на сайте Cobra давно перевалил за сотню
Анатомия CLI: команда, подкоманда, флаг, аргумент#
Возьмём строку посложнее: gh pr create --title «Правки в API» --base main 42. Слева направо: gh — исполняемый файл, то, что нашлось в PATH; pr — подкоманда первого уровня; create — подкоманда второго уровня; 42 — позиционный аргумент, его смысл определяется только местом в строке; --title и --base — флаги со значениями, их порядок можно менять как угодно. Этот словарь — фундамент курса, проговорим его чётко. Команды задают глагол: что делать. Аргументы — объект: над чем делать. Флаги — настройки: как именно делать. Сильные консольные утилиты соблюдают это правило почти религиозно: в git commit -m «сообщение» команда — commit, флаг -m несёт текст. Если пользователь вашей утилиты должен угадывать, что значит третий параметр подряд, — это баг дизайна, а не сложность предметной области.
Минимальная программа на Cobra, которую будем разбирать
GOpackage main
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "hello",
Short: "Приветствие из первого урока",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Привет, CLI!")
},
}
func main() {
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}Вся программа — одна переменная rootCmd типа *cobra.Command. Поле Use задаёт имя команды, Short — однострочное описание для справки, Run — функцию, которая выполнится при запуске. Execute() читает os.Args, находит нужную команду и вызывает её Run; при ошибке возвращается error, и os.Exit(1) отдаёт скриптам код выхода, отличный от нуля.
Что общего у kubectl, Hugo и gh#
Сядьте за любой из этих инструментов — и первые минуты пройдёте без документации, потому что все они ведут себя одинаково. gh --help печатает список подкоманд с однострочными описаниями; gh pr --help разворачивает подробности уже про pr. hugo server --port 1313 понимает флаг и до, и после имени подкоманды. kubectl на опечатку отвечает подсказкой Did you mean this?. Это не копирование чужого стиля — это Cobra, у которой контракт пользователя встроен в библиотеку: справка генерируется на каждом уровне дерева, у флагов есть шорткаты (-n и --namespace — один и тот же флаг), шелл получает автодополнение через встроенную команду completion, версия печатается по --version. Пользователь вашей утилиты получит привычное поведение бесплатно, а вы выбросите из плана сорок разборов os.Args. Заодно унифицируется мелочь, которую никто не любит писать руками: --version у корня, поведение при пустом вызове, чтение конфига до первой команды. Каждый пункт по отдельности — полчаса работы и вечный спор «а как у нас принято?»; в Cobra они просто есть.
Cobra против пакета flag#
Стандартная библиотека Go умеет парсить флаги пакетом flag, и на одном уровне он хорош: определить flag.String, вызвать flag.Parse — готово. Ограничения всплывают сразу за этим уровнем. Дерева команд нет: подкоманды придётся перебирать вручную по os.Args и для каждой заводить свой FlagSet. Справка генерируется только списком флагов — ни однострочных описаний подкоманд, ни развёрнутых Long-текстов. Автодополнения и подсказок при опечатках нет вообще. Нюанс, о котором забывают: под капотом Cobra работает не flag, а pflag — его форк с POSIX-семантикой: формы --flag=value, объединение шорткатов -abc в один вызов, флаги до и после позиционных аргументов. flag с этим справляется хуже. Если у вас уже есть код на flag, миграция обычно начинается с замены flag.String на cmd.Flags().String — семантика почти совпадает, ломаться нечему. Мой вывод после утилит на обоих: flag — для скриптов и инструментов с одной командой, Cobra — как только нарисовалась вторая подкоманда. Это не религия, а точка окупаемости: дерево и справка в Cobra описываются декларативно, руками — итеративно и со скрипом.
flag и Cobra: что приходится писать самому#
| Задача | flag | Cobra |
|---|---|---|
| Дерево подкоманд | нет — только вручную по os.Args | AddCommand и готовая маршрутизация |
| Справка --help | список флагов по умолчанию | генерируется по Use, Short, Long, Example |
| Автодополнение bash/zsh | нет | встроенная команда completion |
| Подсказка при опечатке | нет | Did you mean this? из коробки |
| Хуки до и после команды | нет | PreRun, PostRun и их персистентные версии |
| Привязка конфигурации | нет | штатная связка с Viper |
Библиотека github.com/spf13/cobra попадает в go.mod каждого вашего проекта. cobra-cli — генератор каркасов: ставится один раз на машину и нужен только чтобы создать файлы проекта и добавить заготовки подкоманд. В коде приложений cobra-cli не упоминается.
Когда Cobra не нужна#
Честности ради: не каждая утилита заслуживает фреймворк. Если программа принимает пару флагов, у неё одна точка входа, а справка помещается в абзац README — берите flag или читайте os.Args напрямую: лишняя зависимость в go.mod не нужна. Мой водораздел такой: появилась вторая подкоманда или справка перестала влезать в одну строку — время Cobra. Вторая ситуация, где я обходился без неё, — утилиты внутри монорепозитория со своим запускачом и конфигом: там от CLI нужны только флаги, и flag хватает с запасом. Спорная часть: некоторые тянут Cobra и для однострочников ради красивой справки. Я так не делаю — сборка дольше, пользы ноль, — но если в команде есть готовый шаблон проекта, цена стремится к нулю, и тогда возражений нет.
Как устроен курс и что понадобится#
Курс практический: с третьего урока в голове держим один проект — CLI-менеджер задач, который к финалу обрастёт конфигами, цветным выводом и тестами. Одна оговорка про формат: браузерная песочница сайта исполняет чистый Go без файловой системы и os.Args, поэтому Cobra-код в уроках не запускается онлайн — примеры нужно гонять локально с установленным Go, а интерактивы в песочнице остаются разминкой на синтаксис. Если сам Go у вас пока на уровне «читал, но не писал», начните с базового курса: структуры, ошибки и пакеты понадобятся уже на второй неделе. И настройтесь на интерактивы в каждом уроке — тесты, пропуски и карточки засчитывают XP и заодно работают повторением: тезис, который не отложился, всплывёт в вопросе раньше, чем вы его забудете.
Проверка: анатомия командной строки
В вызове gh pr create --title «Правки» 42 что такое 42?
Проверка: flag или Cobra
Что из перечисленного умеет Cobra, но не умеет пакет flag?
Что напечатает программа без аргументов
Прочитайте код и выберите, что он выведет:
package main
import (
"fmt"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "hello",
Short: "Приветствие из первого урока",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Привет, CLI!")
},
}
func main() {
rootCmd.Execute()
}Восстановите минимальную Cobra-программу
Впишите имя пакета, путь импорта фреймворка, имя команды в Use и тип команды.
Соберите каркас из шести строк
Расставьте строки от объявления пакета до вызова Execute.
Строки
Ваша программа
Нажимайте на строки слева, чтобы собрать программу
Карточки: словарь CLI и Cobra
Что дальше#
Во втором уроке поставим Cobra и сгенерируем первый проект: cobra-cli init, структура main.go и cmd/root.go, первый запуск. Третий урок — дерево команд: rootCmd, AddCommand и справка, ради которой всё затевалось. Потом пойдут флаги — локальные и персистентные, они заслуживают отдельного урока, потому что в CLI их больше всего. Финал курса — CLI-менеджер задач, куда сложится всё пройденное. Пока подготовьте площадку: убедитесь, что go version отвечает, и освободите вечер — с четверти часа на второй урок уйдёт только на установку.
Песочница урока
Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.
Запустите код, чтобы увидеть вывод.
Коротко: что запомнить
- Cobra — CLI-фреймворк Go: дерево команд, справка, автодополнение и хуки в одной библиотеке.
- На Cobra написаны kubectl, Hugo, GitHub CLI и Docker CLI — у всех один пользовательский контракт.
- Словарь курса: команда — глагол, аргумент — объект, флаг — настройка.
- flag парсит флаги одной программы; Cobra добавляет дерево, справку, подсказки и completion, работая поверх pflag.
- Cobra и cobra-cli — разные вещи: библиотека в каждом проекте, генератор — один раз на машину.
- Для утилиты с парой флагов Cobra избыточна; моя точка входа — вторая подкоманда.
- Код курса запускается локально: песочница сайта Cobra не исполняет.
Домашнее задание
Вспомните три CLI, которыми пользуетесь каждый день: git, docker, kubectl — что угодно. Для каждого выпишите две подкоманды, один позиционный аргумент и два флага, один со значением, другой без. Затем откройте справку каждой утилиты через --help и проверьте, что подкоманды показаны с однострочными описаниями. Этот словарь пригодится в четвёртом уроке, где будем решать, аргумент перед нами или флаг.
Личные заметкиПусто
Вопросы и ответы по уроку
Что такое Cobra в Go простыми словами?
Библиотека, которая снимает с разработчика рутину консольной утилиты: разбор строки запуска, дерево подкоманд, справку --help, автодополнение и подсказки при опечатках. Вы описываете команды и пишете только их логику.
Чем Cobra лучше стандартного flag?
flag умеет парсить флаги одной программы. Cobra добавляет дерево подкоманд, многоуровневую справку, автодополнение для шеллов, хуки PreRun и PostRun, подсказки опечаток. Для утилиты с подкомандами разница огромна.
Нужно ли знать Go, чтобы пройти курс?
Да, на базовом уровне: функции, структуры, ошибки. Если это пока в стадии чтения, начните с курса «Go с нуля» — код Cobra-проектов опирается на структуры и методы с самых первых уроков.
Термины урока
Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.
Сравните с альтернативами
Практический вопрос после первых уроков: а почему именно эта библиотека? Мы разобрали конкурентов по одним критериям, с кодом одной задачи рядом и персональным подбором под ваши приоритеты.
Изучайте дальше
Следующая ступень учебного пути
Bubble Tea: TUI-приложения в терминале
Интерактивный курс Bubble Tea — TUI-фреймворка на Go: Elm-архитектура, bubbles, Lip Gloss, мышь и клавиатура. 25 уроков с примерами и итоговым приложением.
- Понимать Elm-архитектуру: Model, Update, View, Init
- Обрабатывать клавиатуру и мышь в терминале
- Писать асинхронные операции через tea.Cmd, Batch и Sequence
- Использовать bubbles: list, textinput, textarea, table, viewport, progress, spinner