Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 12 из 25 ~18 мин +50 XP

Справка: кастомизация help и usage

Cobra help кастомизация сводится к трём точкам входа: шаблон SetHelpTemplate, шаблон SetUsageTemplate и функция SetHelpFunc, а содержимое страницы складывают поля Long и Example. Разберём, чем help отличается от usage, как собрать страницу справки под свою утилиту и как переопределить вывод для одной подкоманды, не трогая остальные.

Содержание урока · 11 разделов

Пользователь, открывший вашу утилиту впервые, делает одно и то же: печатает --help и за десять секунд решает, разбираться дальше или закрыть терминал. За эти десять секунд отвечает не код команды, а страница справки, и у Cobra она собрана из двух слоёв. Первый слой — содержимое: поля Short, Long и Example, которые вы заполняете у каждой команды. Второй — форма: два Go-шаблона, HelpTemplate и UsageTemplate, раскладывающие это содержимое по экрану. Пока утилита маленькая, дефолтная страница выглядит прилично, и трогать её не нужно. Но как только справка перестаёт вмещать нужное — пример с флагами, секция про переменные окружения, особый формат для одной команды — начинается кастомизация. Пройдём оба слоя по порядку: сначала поля, из которых складывается текст страницы, затем шаблоны, задающие ей форму, и в конце — функция SetHelpFunc, заменяющая рендеринг целиком.

Две страницы: help и usage#

У каждой команды в Cobra две страницы, и это разные тексты. Usage — выжимка: строка использования UseLine, алиасы, список доступных подкоманд, локальные и глобальные флаги. Help — то, что печатается по флагу --help и по команде help: сначала абзац Long, затем Example, а в конце — usage-страница целиком. Из этого устройства следует главное правило кастомизации: содержимое пишем в поля, а не в шаблоны — Long и Example попадают на страницу сами, шаблоны нужны, когда не устраивает раскладка. Usage чаще всего видит расстроенный пользователь: при ошибке разбора флагов Cobra печатает сообщение и следом usage-страницу, и простыня флагов в этот момент скорее мешает найти саму ошибку — как её убрать, разбирается в уроке про ошибки и коды выхода. Отрендеренную usage можно получить и из кода: метод UsageString() возвращает её строкой, чем пользуются и кастомные шаблоны, и тесты.

Long и Example: содержимое страницы

GO
var serveCmd = &cobra.Command{
        Use:   "serve [каталог]",
        Short: "Запустить сервер заметок",
        Long: `Запускает HTTP-сервер, который раздаёт заметки из каталога.
Порт и каталог переопределяются флагами; конфиг
читается из текущего каталога.`,
        Example: `  notes serve                       # текущий каталог
  notes serve ~/notes --port 9000
  notes serve --open                # сразу открыть браузер`,
        RunE: func(cmd *cobra.Command, args []string) error {
                return startServer(cmd, args)
        },
}

Long — абзац для страницы help: не дублируйте Short дословно, здесь место для деталей, которых не видно в списке команд. Example — многострочная строка с реальными вызовами; отступ в два пробела задаёт выравнивание, как в справках kubectl и gh. Оба поля дефолтный шаблон печатает сам — пока они заполнены, в шаблоны лезть не нужно.

Проверка: пустой Long

У serveCmd не заполнено поле Long, Short задан. Что напечатает notes serve --help?

Кастомизация help: шаблон SetHelpTemplate#

Шаблон help — обычный text/template из стандартной библиотеки: в двойных фигурных скобках доступны поля команды, и на них можно собрать что угодно. Минимальная осмысленная замена дефолту — SetHelpTemplate с телом из описания и usage: {{.Long}}, пустая строка, {{.UsageString}}. В шаблоне доступны .Long, .Short, .Example, .CommandPath, .UseLine, .Runnable, флаги через .LocalFlags и .InheritedFlags, а из функций — rpad, gt, eq и trimTrailingWhitespaces, которыми пользуется и дефолтный шаблон. Важная деталь механики: шаблон ищется не только на самой команде. Не нашли у подкоманды — Cobra поднимается по дереву и берёт шаблон ближайшего предка, у которого он задан; установили на корне — получили для всего дерева сразу. И следите за концом шаблона: печатается ровно то, что в нём написано, включая финальный перенос строки, — без него справка прилипнет к следующему приглашению терминала.

SetHelpTemplate с секцией примеров

GO
func init() {
        rootCmd.SetHelpTemplate(`{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}

{{end}}{{if .HasExample}}Примеры:
{{.Example}}

{{end}}{{.UsageString}}`)
}

Шаблон начинается как дефолтный — or .Long .Short с обрезкой хвостовых пробелов, — затем идёт своя секция «Примеры:», печатающаяся только при заполненном Example, и в конце UsageString со списком команд и флагов. Пустые строки между секциями набраны руками: шаблон ничего не добавляет сам, поэтому переводы строк — часть вашего контракта с пользователем.

Шаблон, который печатает один Long

Прочитайте код и выберите, что он выведет:

rootCmd.SetHelpTemplate("{{.Long}}")

// notes serve --help
// Long и Example у serveCmd заполнены

Usage-шаблон: SetUsageTemplate и секции#

Usage-шаблон устроен плотнее: дефолт собирает строку использования, алиасы, примеры, доступные команды, флаги, глобальные флаги и дополнительные темы помощи — каждая секция через своё условие {{if}}. Кастомизация здесь обычно точечная: русифицировать заголовок Available Commands, спрятать секцию Additional help topics, добавить в конец строку со ссылкой на документацию. Механика наследования та же, что у help-шаблона: SetUsageTemplate на корне действует на всё дерево, а отдельная команда со своим шаблоном переопределяет только себя. Совсем заменить рендеринг функцией можно методом SetUsageFunc — она принимает func(*cobra.Command) error и пригодится, когда странице нужно то, чего шаблоном не выразить, например вывод через внешнюю программу. На практике функций хватает одному проценту утилит: сначала пробуйте шаблон, и только упершись в его пределы — SetUsageFunc.

Свой usage-шаблон по-русски

GO
rootCmd.SetUsageTemplate(`Usage:{{if .Runnable}}
  {{.UseLine}}{{end}}

Доступные команды:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}

Флаги:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}
`)

Упрощённый usage: строка использования, команды с русским заголовком и локальные флаги. Range по .Commands с проверкой IsAvailableCommand оставляет видимыми только настоящие команды плюс help, rpad выравнивает имена по общей ширине. За основу берите полный дефолтный шаблон из исходников своей версии Cobra — он длиннее и включает глобальные флаги и темы помощи.

SetHelpFunc: справка под полный контроль#

Когда шаблонов мало, остаётся функция. SetHelpFunc принимает func(*cobra.Command, []string) и полностью забирает рендеринг: Cobra больше ничего не печатает, всё на вас — хоть JSON для скриптов, хоть вывод через пейджер вроде less, хоть запрос к внешней программе. Аргументы — сама команда и хвост, который пользователь дописал после слова help: вызов notes help serve принесёт в функцию serve. Внутри принято печатать через cmd.OutOrStdout(): при обычном запуске это stdout, а в тестах вывод перехватывается буфером — им же мы будем ловить справку в уроке про тестирование. Наследование работает и здесь: HelpFunc ищется по дереву вверх, и функция корня отрисует справку всем подкомандам, у которых своей нет. Скажу честно, как о рабочем опыте: в девяти проектах из десяти хватает Long, Example и одного шаблона, а SetHelpFunc остаётся лазейкой на особые случаи — держите её в голове, но не открывайте без причины.

SetHelpFunc: своя функция справки

GO
rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
        out := cmd.OutOrStdout()
        if cmd.Long != "" {
                fmt.Fprintln(out, cmd.Long)
        } else {
                fmt.Fprintln(out, cmd.Short)
        }
        if cmd.Example != "" {
                fmt.Fprintf(out, "
Примеры:
%s
", cmd.Example)
        }
        fmt.Fprint(out, cmd.UsageString())
})

Функция повторяет дефолтную логику в миниатюре: описание с подстановкой Short, свои «Примеры», usage в конце. Вся печать через OutOrStdout — справка уважает перенаправление и тестовые буферы. Обратите внимание: функция получает указатель на конкретную команду, поэтому никакой хардкод «описания корня» внутри недопустим — читайте cmd.

Проверка: чья функция справки

Справку рендерит функция, заданная через rootCmd.SetHelpFunc. У serveCmd собственной help-функции нет. Что произойдёт при notes serve --help?

Флаг --help у каждой подкоманды#

Флаг -h/--help не объявляется руками: Cobra добавляет его каждой команде сама, через InitDefaultHelpFlag, в момент выполнения. Поэтому notes serve --help показывает справку именно serve: её Long, её Example, её флаги, а флаги корня попадают в отдельную секцию Global Flags. Help-команда тоже строится автоматически, и notes help serve приводит к той же странице, что и notes serve --help, — разница только в привычке. Для --help не выполняется ни Run, ни хуки из следующего урока: проверка флага случается раньше, поэтому справка открывается мгновенно даже у тяжёлых команд, и звать её из скриптов безопасно. Если понадобится своё поведение помощи, команду help можно подменить через SetHelpCommand — но это экзотика, и в девяти случаях из десяти штатного флага достаточно.

Чек-лист справки перед релизом#

  1. Long есть у каждой команды с флагами; Short описывает команду одним предложением и не повторяет Long дословно.
  2. Example показывает два-три реальных вызова, начиная с самого частого сценария.
  3. --help проверен на трёх уровнях: корень, подкоманда, вложенная подкоманда; отдельно — вызов notes help serve.
  4. Перенаправление вывода не ломает справку: она уходит через OutOrStdout, а не печатается мимо stdout.
  5. Правка шаблона не тронула автодополнение и команду help — они живут отдельно от шаблонов.

help и usage рядом#

helpusage
Когда печатаетсяпо --help/-h и команде helpпосле ошибки флагов и внизу help-страницы
СоставLong или Short, Example, usage целикомUseLine, алиасы, команды, флаги
КастомизацияSetHelpTemplate и SetHelpFuncSetUsageTemplate и SetUsageFunc
Наследованиеу ближайшего предка с шаблоном или функциейто же самое
Доступ из кодаcmd.Help() печатает страницуcmd.UsageString() возвращает строкой

Соберите шаблон и описание

Впишите название шаблонного метода и поле длинного описания.

rootCmd.SetTemplate("{{.Long}}\n\n{{.UsageString}}") var serveCmd = &cobra.Command{ Use: "serve", Short: "Запустить сервер заметок", : "Длинное описание сервера с деталями конфига", }

Соберите SetHelpFunc из шести строк

Расставьте: переменная корня, начало функции, печать описания, печать usage, закрытие функции, регистрация.

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Карточки: шаблоны и функции справки

Термин

HelpTemplate

нажмите, чтобы перевернуть
Определение

Шаблон страницы --help: дефолт печатает or .Long .Short, затем Example и UsageString. Задаётся SetHelpTemplate и наследуется от ближайшего предка.

1 / 6

Что дальше#

Страница справки собрана, и в следующем уроке про хуки PreRun и PostRun мы переходим к тому, что происходит вокруг выполнения команды: цепочка PersistentPreRunE → PreRunE → RunE → PostRunE и знаменитая ловушка наследования PersistentPreRun. Справка — идеальный кандидат на тест: в уроке про тестирование команд вывод --help ловится буфером и сравнивается с ожидаемым, так что правки шаблона перестанут быть слепыми. Обзор всех тем курса — на странице Cobra. И напоминание про среду, уже знакомое по другим урокам курса: шаблоны исполняются только живой утилитой, поэтому соберите проект локально, вызовите --help для корня и пары подкоманд и прочитайте результат своими глазами раньше, чем это сделают пользователи.

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Вывод

Запустите код, чтобы увидеть вывод.

Коротко: что запомнить

  • Справка состоит из двух слоёв: содержимое в полях Long и Example, форма — в шаблонах HelpTemplate и UsageTemplate.
  • Help печатается по --help и команде help; usage показывается после ошибок флагов и внизу help-страницы.
  • Пустой Long подменяется Short — заполняйте Long хотя бы у команд с флагами.
  • SetHelpTemplate на корне действует на всё дерево: шаблон ищется у ближайшего предка с заданным значением.
  • UsageString() возвращает usage строкой — удобно для своих шаблонов и тестов.
  • SetHelpFunc заменяет рендеринг целиком; вся печать — через cmd.OutOrStdout().
  • После правки шаблона проверяйте --help локально: ошибка шаблона вылезает только в рантайме.

Домашнее задание

Заполните Long и Example для трёх команд своей утилиты, затем замените заголовок Available Commands на «Доступные команды» через SetUsageTemplate. Добавьте секцию «Примеры:» в SetHelpTemplate так, чтобы она печаталась только при непустом Example. Соберите проект, откройте --help для корня и двух подкоманд и проверьте, что ни одна секция не потерялась.

Личные заметкиПусто
Хранятся только в вашем браузере (Cobra · Справка: кастомизация help и usage)

Вопросы и ответы по уроку

Как изменить заголовок Available Commands в Cobra?

Задайте свой SetUsageTemplate на корне: скопируйте дефолтный шаблон из исходников Cobra вашей версии и замените текст заголовка внутри range по .Commands. Дефолтный шаблон меняется между версиями, поэтому правьте копию, а не пересобирайте с нуля.

Чем SetHelpFunc отличается от SetHelpTemplate?

Шаблон — это text/template, который Cobra исполняет за вас; функция — полный контроль: она вызывается вместо любого рендеринга и печатает что угодно, включая пейджер или JSON. Для большинства утилит хватает шаблона, функция нужна для особых форматов вывода.

Почему --help подкоманды показывает Short вместо длинного описания?

Поле Long у этой подкоманды пустое: дефолтный шаблон берёт or .Long .Short. Заполните Long — и страница подкоманды получит полноценное описание, не трогая Short в списке команд родителя.

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Сравните с альтернативами

Практический вопрос после первых уроков: а почему именно эта библиотека? Мы разобрали конкурентов по одним критериям, с кодом одной задачи рядом и персональным подбором под ваши приоритеты.

Следующая ступень учебного пути

Bubble Tea25 уроков~10 чпрактика25 уроков уже доступны

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