Статьи

Groovy 2.5 Обновление CliBuilder (часть 2)

Класс CliBuilder для быстрой и лаконичной сборки приложений командной строки был обновлен в Apache Groovy 2.5.

Это вторая статья из двух частей, в которой рассказывается, что нового. В случае, если вы пропустили это, часть 1 здесь.

В этой статье показаны некоторые расширенные функции базовых библиотек из CliBuilder.

CliBuilder

Краткий groovy.util.CliBuilder части 1 : класс groovy.util.CliBuilder устарел. Вместо этого теперь есть две реализации CliBuilder в разных модулях, одна с Apache Commons CLI в качестве базовой библиотеки синтаксического анализатора, и новая, основанная на анализаторе picocli.

Рекомендуется, чтобы приложения явно импортировали либо groovy.cli.picocli.CliBuilder либо groovy.cli.commons.CliBuilder . Класс groovy.util.CliBuilder устарел и делегируется версии CLI Commons для обратной совместимости.

Новые функции, скорее всего, будут добавлены только в версию picocli, и groovy.util.CliBuilder может быть удален в будущей версии Groovy. Версия Commons CLI предназначена для приложений, которые полагаются на внутреннюю часть реализации Commons CLI в CliBuilder и не могут легко перейти на версию picocli.

Далее, давайте взглянем на некоторые расширенные функции, предлагаемые этими базовыми библиотеками синтаксического анализа командной строки.

Apache Commons CLI Особенности

Иногда вы можете захотеть использовать расширенные функции базовой библиотеки синтаксического анализа. Например, у вас может быть приложение командной строки с взаимоисключающими параметрами. В приведенном ниже коде показано, как этого добиться с помощью API-интерфейса Apache Commons CLI OptionGroup :

01
02
03
04
05
06
07
08
09
10
11
12
import groovy.cli.commons.CliBuilder
import org.apache.commons.cli.*
 
def cli = new CliBuilder()
def optionGroup = new OptionGroup()
optionGroup.with {
  addOption cli.option('s', [longOpt: 'silent'], 's option')
  addOption cli.option('v', [longOpt: 'verbose'], 'v option')
}
cli.options.addOptionGroup optionGroup
 
assert !cli.parse('--silent --verbose'.split()) (1)
  1. Синтаксический анализ этого ввода завершится неудачно, так как были указаны две взаимоисключающие опции.

Picocli CliBuilder Особенности

Сильно типизированные списки

Список CliBuilder

Параметры с несколькими значениями часто используют массив или список для захвата значений. Массивы могут быть строго типизированы, то есть содержать элементы, отличные от String. Версия CliBuilder для Picocli позволяет делать то же самое со списками. auxiliaryType указывает тип, в который элементы должны быть преобразованы. Например:

1
2
3
4
5
6
7
import groovy.cli.picocli.CliBuilder
 
def cli = new CliBuilder()
cli.T(type: List, auxiliaryTypes: Long, 'typed list')  (1)
 
def options = cli.parse('-T 1 -T 2 -T 3'.split())      (2)
assert options.Ts == [ 1L, 2L, 3L ]                    (3)
  1. Определите параметр, который может иметь несколько целочисленных значений.
  2. Пример командной строки.
  3. Значения параметра представлены в виде List<Integer> .

Сильно типизированные карты

Версия CliBuilder для picocli предлагает встроенную поддержку параметров карты. Это так же просто, как указать карту в качестве типа параметра. По умолчанию ключи и значения хранятся в виде строк на карте, но можно использовать auxiliaryType тип, чтобы указать типы, в которые должны быть преобразованы ключи и значения.

01
02
03
04
05
06
07
08
09
10
11
import groovy.cli.picocli.CliBuilder
 
def cli = new CliBuilder()
cli.D(args: 2,   valueSeparator: '=', 'Commons CLI style map')                 (1)
cli.X(type: Map, 'picocli style map support')                                  (2)
cli.Z(type: Map, auxiliaryTypes: [TimeUnit, Integer].toArray(), 'typed map')   (3)
 
def options = cli.parse('-Da=b -Dc=d -Xx=y -Xi=j -ZDAYS=2 -ZHOURS=23'.split()) (4)
assert options.Ds == ['a', 'b', 'c', 'd']                                      (5)
assert options.Xs == [ 'x':'y', 'i':'j' ]                                      (6)
assert options.Zs == [ (DAYS as TimeUnit):2, (HOURS as TimeUnit):23 ]          (7)
  1. CLI Commons имеет параметры, подобные карте, указав, что каждый параметр должен иметь два параметра с некоторым разделителем.
  2. Версия CliBuilder для picocli имеет встроенную поддержку параметров карты.
  3. Тип ключа и тип значения могут быть указаны для строго типизированных карт.
  4. Пример командной строки.
  5. Опция стиля CLI Commons дает список объектов [ключ, значение, ключ, значение,…].
  6. Опция стиля picocli дает результат в виде Map<String, String> .
  7. Если указаны auxiliaryTypes типы, ключи и значения карты преобразуются в указанные типы, получая Map<TimeUnit, Integer> .

Справка по использованию с подробным резюме

CliBuilder всегда поддерживал свойство use для отображения справки по использованию команды:

1
2
// the old way
new CliBuilder(usage: 'myapp [options]').usage()

Вышеприведенная программа печатает:

1
Usage: myapp [options]

Это все еще работает, но у версии picocli есть лучшая альтернатива со свойством name . Если вы укажете name вместо usage , picocli покажет все параметры в кратком резюме с квадратными скобками [ и ] для необязательных элементов и многоточие …​ элементов, которые могут повторяться один или несколько раз. Например:

1
2
3
4
5
def cli = new CliBuilder(name: 'myapp') // detailed synopsis
cli.a('option a description')
cli.b('option b description')
cli.c(type: List, 'option c description')
cli.usage()

Вышеприведенная программа печатает:

1
2
3
4
5
Usage: myapp [-ab] [-c=PARAM]...
the new way
  -a           option a description
  -b           option b description
  -c= PARAM    option c description

Используйте любые названия опций

Изображение предоставлено: (c) PsychoShadow — www.bigstockphoto.com

Ранее, если у опции было несколько имен с одним дефисом, у вас не было выбора, кроме как объявить опцию несколько раз:

1
2
3
4
// before: split -cp, -classpath into two options
def cli = new CliBuilder(usage: 'groovyConsole [options] [filename]')
cli.classpath('Where to find the class files')
cli.cp(longOpt: 'classpath', 'Aliases for '-classpath')

Версия CliBuilder для picocli поддерживает свойство names которое может иметь любое количество имен параметров, которые могут принимать любой префикс. Например:

1
2
3
// after: an option can have many names with any prefix
def cli = new CliBuilder(usage: 'groovyConsole [options] [filename]')
cli._(names: ['-cp', '-classpath', '--classpath'], 'Where to find the class files')

Мелкозернистое Справочное сообщение об использовании

Picocli предлагает детальный контроль над форматом сообщения справки об использовании, и эта функциональность предоставляется через свойство usageMessage CliBuilder.

Сообщение об использовании имеет несколько разделов: заголовок, краткий обзор, описание, параметры, параметры и, наконец, нижний колонтитул. Каждый раздел имеет заголовок, который предшествует первой строке его раздела. Например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
import groovy.cli.picocli.CliBuilder
 
def cli = new CliBuilder()
cli.name = "groovy clidemo"
cli.usageMessage.with {                (1)
    headerHeading("Header heading:%n") (2)
    header("header 1", "header 2")     (3)
    synopsisHeading("%nUSAGE: ")
    descriptionHeading("%nDescription heading:%n")
    description("description 1", "description 2")
    optionListHeading("%nOPTIONS:%n")
    footerHeading("%nFooter heading:%n")
    footer("footer 1", "footer 2")
}
cli.a(longOpt: 'aaa', 'a-arg')         (4)
cli.b(longOpt: 'bbb', 'b-arg')
cli.usage()
  1. Используйте usageMessage CliessMuageMessage для настройки сообщения справки об использовании.
  2. Заголовки могут содержать спецификаторы формата строки, такие как символ новой строки %n .
  3. Разделы многострочные: каждая строка будет отображаться на отдельной строке.
  4. Определите некоторые варианты.

Это печатает следующий вывод:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
Header heading:
header 1
header 2
 
USAGE: groovy clidemo [-ab]
 
Description heading:
description 1
description 2
 
OPTIONS:
  -a, --aaa    a-arg
  -b, --bbb    b-arg
 
Footer heading:
footer 1
footer 2

Справка по использованию с цветами ANSI

Из коробки имя команды, имена опций и метки параметров в сообщении помощи по использованию отображаются со стилями и цветами ANSI . Цветовая схема для этих элементов может быть настроена с помощью системных свойств.

Кроме этого, вы можете использовать цвета и стили в описаниях и других разделах справочного сообщения об использовании, используя простую запись разметки . Пример ниже демонстрирует:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def cli = new groovy.cli.picocli.CliBuilder(name: 'myapp')
cli.usageMessage.with {
    headerHeading("@|bold,red,underline Header heading|@:%n")
    header($/@|bold,green \
  ___ _ _ ___      _ _    _
 / __| (_) _ )_  _(_) |__| |___ _ _
| (__| | | _ \ || | | / _` / -_) '_|
 \___|_|_|___/\_,_|_|_\__,_\___|_|
|@/$)
    synopsisHeading("@|bold,underline Usage|@: ")
    descriptionHeading("%n@|bold,underline Description heading|@:%n")
    description("Description 1", "Description 2")      // after the synopsis
    optionListHeading("%n@|bold,underline Options heading|@:%n")
    footerHeading("%n@|bold,underline Footer heading|@:%n")
    footer($/@|bold,blue \
   ___                         ___   ___
  / __|_ _ ___  _____ ___  _  |_  ) | __|
 | (_ | '_/ _ \/ _ \ V / || |  / / _|__ \
  \___|_| \___/\___/\_/ \_, | /___(_)___/
                        |__/             |@/$)
}
cli.a('option a description')
cli.b('option b description')
cli.c(type: List, 'option c description')
cli.usage()

Код выше дает следующий вывод:

CliBuilder

(Благодарим http://patorjk.com/software/taag/ за искусство ASCII.)

Новое свойство errorWriter

ошибка

Когда пользователь предоставил неверный ввод, версия CliBuilder для picocli записывает сообщение об ошибке и сообщение помощи по использованию в новое свойство errorWriter (по умолчанию установлено значение System.err ). Когда пользователь запрашивает помощь, а приложение вызывает CliBuilder.usage() , сообщение об использовании использования CliBuilder.usage() по умолчанию System.out ).

Предыдущие версии CliBuilder использовали свойство writer как для неверного ввода, так и для запрашиваемой пользователем справки.

Почему это изменение? Это помогает авторам приложений командной строки следовать стандартной практике и отделять выходные данные диагностики от выходных данных программы. Если выходные данные программы Groovy передаются по конвейеру в другую программу, отправка сообщений об ошибках в STDERR предотвращает непреднамеренную попытку исходящей программы проанализировать выходные данные ошибок. С другой стороны, когда пользователи запрашивают помощь с --help или --version , вывод должен быть отправлен в STDOUT, потому что пользователь может захотеть передать вывод в утилиту, такую ​​как less или grep .

Для обратной совместимости установка свойства writer в другое значение также установит errorWriter в то же значение. (Вы все равно можете установить errorWriter на другое значение, если errorWriter .)

Вывод

Groovy 2.5 CliBuilder предлагает множество новых интересных функций. Попробуйте и дайте нам знать, что вы думаете!

Это вторая часть статьи из двух частей. Если вы пропустили это, вот часть 1 .

Для получения дополнительной информации посетите сайт Groovy и проект GitHub, а также сайт picocli и проект GitHub picocli . Пожалуйста, отметьте проекты, если вам нравится то, что вы видите!

Смотреть оригинальную статью здесь: Groovy 2.5 CliBuilder Renewal (часть 2)

Мнения, высказанные участниками Java Code Geeks, являются их собственными.