Pull to refresh

Работа с commons-cli 1.2

Reading time5 min
Views21K
В процессе работы на одним проектом, возникла необходимость разработать консольное приложение для удаленного доступа к системе. За подобное взялся впервые в таких масштабах, раньше все было на окошках или если консоль, то точно известно число, тип и порядок передаваемых параметров. А здесь возникла необходимость в большом количестве команд, каждая со своими параметрами, или вовсе без них, соответственно для обеспечения гибкости возникла потребность в парсере, переданных параметров.

Дабы не изобретать велосипед, решил взять готовую библиотеку. Выбор остановил на commons-cli, для нее удалось найти пару примеров и использование ее казалось не очень уж сложны.

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

Итак, начнем. В основе Commons-cli лежит понятие опции. Чтобы сразу внести ясность, попробуем определиться с терминологией. Рассмотрим такую строчку:

Text.exe –l login ––password 123456

Происходит вызов программы test.exe с использованием опции l, которая в качестве аргумента принимает строку «login» и с использованием опции password, с аргументом в виде строки «123456». Нетрудно догадаться, что программа требует аутентификации, опция l отвечает за логин, а опция password само собой за пароль. Для простоты можно пару «опция, аргумент» рассматривать классичским способом «параметр=значение».

Кстати, форма записи со знаком «=» вполне допустима при использовании commons-cli.

Опции могут быть без аргументов вовсе или аргументов может быть больше одного. Если имя опции состоит из 1 буквы, то ей предшествует «-» (назовем это, по простому «тире»). Если имя опции состоит из 2 и более букв то необходимо удваивать «тире», как с опцией password.

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

Option option = new Option("l", "login", true, "Login"); 


Коснтруктор в данном случае принимает 4 параметра: короткую форму опции (однобуквенная опция), длинную форму опции, флаг обозночающий наличие параметров и текстовое пояснение данной опции. Мы могли указать только однобуквнное предствления опции или только расширенное представлении опции, в каждом из этих случае конструктор принимал бы 3 параметра, но не указывать ни многобуквенной ни однобуквенной опции нельзя, необходимо указать хотя бы одну. Затем необходимо определить, как данная опция будет работать с аругментами. Примерно так:

option.setArgs(1); // число аргументов в опции
option.setOptionalArg(false);// являются ли аргументы необязательными для ввода, по умолчанию аргументы обязательны для ввода, так что эту строчку можно было опутить
option.setArgName("login ");//имя аргумета, именно так аргумент будет отображатся в справка по использованию командной строки.


Вроде бы из комментариев к коду все должно быть понятно. Если нам необходима опция без аргументов (опция-флаг), то ставим setArgs(0). После создания опции необходимо добавить ее в объект Options.

Options posixOptions = new Options();
posixOptions.addOption(option);


Теперь необходимо создать парсер командной строки и снабдить его необходимой информацией для работы:

CommandLineParser cmdLinePosixParser = new PosixParser();// создаем Posix парсер
CommandLine commandLine = cmdLinePosixParser.parse(posixOptions, commandLineArguments);// парсим командную строку


Для начала создаем парсер, полновесных парсера в commons-cli 2 – Posix парсер и GNU парсер. Скажу честно, в их различия не вникал, но по беглому осмотру мне приглянулся Posix-парсер (регламентируется Posix стандартом, соотвественно будет работать на всех система поддерживающих этот стандарт).Затем запускаем парсер, в качестве параметров метод parse принимает коллекцию опций в виде объекта Options, и собственно строку с параметрами которые были переданны вашей программе при запуске (само собой что стандартный массив args[] перед использованием необходимо объекденить в одну строку разделяя элементы пробелами). Разультат разбора будет возвращен в объект commandLine.

Теперь необходимо выполнить полученные команды, делается это вот так:

if (commandLine.hasOption(“l”)) { // проверяем, передавали ли нам команду l, сравнение будет идти с первым представлением опции, в нашем случаее это было однобуквенное представление l
	String[] arguments = commandLine.getOptionValues(“l”);// если такая опция есть, то получаем переданные ей аргументы
	System.out.println("We try to Login with: " + arguments[0]);// выводим переданный логин
	… // работаем дальше
}


Как видно, работа с commons-cli довольно просто. К тому же данная библеотека возьмет на себя заботы по выводу справки по использованию программы, не полностью, но многое облегчит:

public static void printHelp(
	final Options options,
	final int printedRowWidth,
	final String header,
	final String footer,
	final int spacesBeforeOption,
	final int spacesBeforeOptionDescription,
	final boolean displayUsage,
	final OutputStream out)
	{
		final String commandLineSyntax = "java test.jar";//подсказка по запуску самой программы
		final PrintWriter writer = new PrintWriter(out);// куда печатаем help
		final HelpFormatter helpFormatter = new HelpFormatter();// создаем объект для вывода help`а
		helpFormatter.printHelp(
		writer,
		printedRowWidth,
		commandLineSyntax,
		header,
		options,
		spacesBeforeOption,
		spacesBeforeOptionDescription,
		footer,
		displayUsage);//формирование справки
		writer.flush(); // вывод
	}

Чтобы все стало ясно, приведу пример вызова данного метода:

printHelp(
	posixOptions, // опции по которым составляем help
	80, // ширина строки вывода
	"Options", // строка предшествующая выводу
	"-- HELP --", // строка следующая за выводом
	3, // число пробелов перед выводом опции 
	5, // число пробелов перед выводом опцисания опции
	true, // выводить ли в строке usage список команд
	System.out // куда производить вывод
);


Пожалуй здесь все понятно, кроме термина «строка usage». Приведу пример пример, из которого станет ясно как использовать данный параметр. При значении true вывод будет примерно такой:

usage: java test.jar [-l ] [-h]

При значении false, вывод будет таким:

usage: java test.jar

Думаю разница понятна.

Последнее — это группы опций. Например, есть две опции -a и -b, они являются взаимоисключающими, то есть одновременно не могут быть указаны. Для такого случая и создаются группы опций:

OptionGroup optionGroup = new OptionGroup();
optionGroup.addOption(new Option("a", true, "A option");
optionGroup.addOption(new Option("b", true, "B option");
posixOptions.addOptionGroup(optionGroup);

Тоже все довольно просто.

В общем бибилиотека оставила неплохие впечатления по использованию, но очень быстро ее стало не хватать. Текущая версия бибилиотеки 1.2, при этом идет развитие абсолютно новой версии 2.0 – собственно, по описанию api версии 2.0 можно сказать, что эта версия должна удовлетворить большинство потребностей предъявляемых к библиотекам cli.

Плюсы commons-cli:
  • простота использования
  • группы опций
  • длинные и короткие нотации опций (-l, --login)
  • возможность парсить опции следующего вида -ab, когда есть две опции -a, -b

Минусы (из собственных потребностей, а так их конечно больше):
  • нет возможности создавать подкоманды (как в git есть команды branch, status и т.д. со своими опциями)
  • не очень удобная работа с аргументами опции, если их больше 1

В итоге, для простенькой cli — отличное решение, что-то более серьезное искать альтернативы или ждать версию 2.0.

Ссылки в статье:


UPD. По подсказке nord_ua исправил ссылку на Posix стандарт командной строки.
Исправил опечатки и добавил ссылку на commons-cli. Спасибо nik_lazarev и FractalizeR.
Tags:
Hubs:
+30
Comments19

Articles

Change theme settings