Updated kotlinx.cli to version 0.3.1
This commit is contained in:
committed by
Stanislav Erokhin
parent
2d30796483
commit
cb642bca69
+59
-32
@@ -143,12 +143,12 @@ open class ArgParser(
|
|||||||
/**
|
/**
|
||||||
* Used prefix form for full option form.
|
* Used prefix form for full option form.
|
||||||
*/
|
*/
|
||||||
private val optionFullFormPrefix = if (prefixStyle == OptionPrefixStyle.JVM) "-" else "--"
|
protected val optionFullFormPrefix = if (prefixStyle == OptionPrefixStyle.JVM) "-" else "--"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used prefix form for short option form.
|
* Used prefix form for short option form.
|
||||||
*/
|
*/
|
||||||
private val optionShortFromPrefix = "-"
|
protected val optionShortFromPrefix = "-"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name with all commands that should be executed.
|
* Name with all commands that should be executed.
|
||||||
@@ -160,6 +160,21 @@ open class ArgParser(
|
|||||||
*/
|
*/
|
||||||
protected var treatAsOption = true
|
protected var treatAsOption = true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arguments which should be parsed with subcommands.
|
||||||
|
*/
|
||||||
|
private val subcommandsArguments = mutableListOf<String>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options which should be parsed with subcommands.
|
||||||
|
*/
|
||||||
|
private val subcommandsOptions = mutableListOf<String>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subcommand used in commmand line arguments.
|
||||||
|
*/
|
||||||
|
private var usedSubcommand: Subcommand? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The way an option/argument has got its value.
|
* The way an option/argument has got its value.
|
||||||
*/
|
*/
|
||||||
@@ -229,7 +244,7 @@ open class ArgParser(
|
|||||||
if (prefixStyle == OptionPrefixStyle.GNU && shortName != null)
|
if (prefixStyle == OptionPrefixStyle.GNU && shortName != null)
|
||||||
require(shortName.length == 1) {
|
require(shortName.length == 1) {
|
||||||
"""
|
"""
|
||||||
GNU standart for options allow to use short form whuch consists of one character.
|
GNU standart for options allow to use short form which consists of one character.
|
||||||
For more information, please, see https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
|
For more information, please, see https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
@@ -359,7 +374,9 @@ open class ArgParser(
|
|||||||
*/
|
*/
|
||||||
private fun treatAsArgument(arg: String, argumentsQueue: ArgumentsQueue) {
|
private fun treatAsArgument(arg: String, argumentsQueue: ArgumentsQueue) {
|
||||||
if (!saveAsArg(arg, argumentsQueue)) {
|
if (!saveAsArg(arg, argumentsQueue)) {
|
||||||
printError("Too many arguments! Couldn't process argument $arg!")
|
usedSubcommand?.let {
|
||||||
|
(if (treatAsOption) subcommandsOptions else subcommandsArguments).add(arg)
|
||||||
|
} ?: printError("Too many arguments! Couldn't process argument $arg!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,9 +433,12 @@ open class ArgParser(
|
|||||||
*
|
*
|
||||||
* @param argValue argument value with all information about option.
|
* @param argValue argument value with all information about option.
|
||||||
*/
|
*/
|
||||||
private fun saveOptionWithoutParameter(argValue: ParsingValue<*, *>) {
|
internal fun saveOptionWithoutParameter(argValue: ParsingValue<*, *>) {
|
||||||
// Boolean flags.
|
// Boolean flags.
|
||||||
if (argValue.descriptor.fullName == "help") {
|
if (argValue.descriptor.fullName == "help") {
|
||||||
|
usedSubcommand?.let {
|
||||||
|
it.parse(listOf("${it.optionFullFormPrefix}${argValue.descriptor.fullName}"))
|
||||||
|
}
|
||||||
println(makeUsage())
|
println(makeUsage())
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
@@ -569,43 +589,42 @@ open class ArgParser(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val argumentsQueue = ArgumentsQueue(arguments.map { it.value.descriptor as ArgDescriptor<*, *> })
|
val argumentsQueue = ArgumentsQueue(arguments.map { it.value.descriptor as ArgDescriptor<*, *> })
|
||||||
|
usedSubcommand = null
|
||||||
|
subcommandsOptions.clear()
|
||||||
|
subcommandsArguments.clear()
|
||||||
|
|
||||||
val argIterator = args.listIterator()
|
val argIterator = args.listIterator()
|
||||||
try {
|
try {
|
||||||
while (argIterator.hasNext()) {
|
while (argIterator.hasNext()) {
|
||||||
val arg = argIterator.next()
|
val arg = argIterator.next()
|
||||||
// Check for subcommands.
|
// Check for subcommands.
|
||||||
@OptIn(ExperimentalCli::class)
|
if (arg !in subcommands) {
|
||||||
subcommands.forEach { (name, subcommand) ->
|
// Parse arguments from command line.
|
||||||
if (arg == name) {
|
if (treatAsOption && arg.startsWith('-')) {
|
||||||
// Use parser for this subcommand.
|
// Candidate in being option.
|
||||||
subcommand.parse(args.slice(argIterator.nextIndex() until args.size))
|
// Option is found.
|
||||||
subcommand.execute()
|
if (!(recognizeAndSaveOptionShortForm(arg, argIterator) ||
|
||||||
parsingState = ArgParserResult(name)
|
recognizeAndSaveOptionFullForm(arg, argIterator))
|
||||||
|
) {
|
||||||
return parsingState!!
|
// State is changed so next options are arguments.
|
||||||
}
|
if (!treatAsOption) {
|
||||||
}
|
// Argument is found.
|
||||||
// Parse arguments from command line.
|
treatAsArgument(argIterator.next(), argumentsQueue)
|
||||||
if (treatAsOption && arg.startsWith('-')) {
|
} else {
|
||||||
// Candidate in being option.
|
usedSubcommand?.let { subcommandsOptions.add(arg) } ?: run {
|
||||||
// Option is found.
|
// Try save as argument.
|
||||||
if (!(recognizeAndSaveOptionShortForm(arg, argIterator) ||
|
if (!saveAsArg(arg, argumentsQueue)) {
|
||||||
recognizeAndSaveOptionFullForm(arg, argIterator))) {
|
printError("Unknown option $arg")
|
||||||
// State is changed so next options are arguments.
|
}
|
||||||
if (!treatAsOption) {
|
}
|
||||||
// Argument is found.
|
|
||||||
treatAsArgument(argIterator.next(), argumentsQueue)
|
|
||||||
} else {
|
|
||||||
// Try save as argument.
|
|
||||||
if (!saveAsArg(arg, argumentsQueue)) {
|
|
||||||
printError("Unknown option $arg")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Argument is found.
|
||||||
|
treatAsArgument(arg, argumentsQueue)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Argument is found.
|
usedSubcommand = subcommands[arg]
|
||||||
treatAsArgument(arg, argumentsQueue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Postprocess results of parsing.
|
// Postprocess results of parsing.
|
||||||
@@ -618,6 +637,14 @@ open class ArgParser(
|
|||||||
printError("Value for ${value.descriptor.textDescription} should be always provided in command line.")
|
printError("Value for ${value.descriptor.textDescription} should be always provided in command line.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Parse arguments for subcommand.
|
||||||
|
usedSubcommand?.let {
|
||||||
|
it.parse(subcommandsOptions + listOfNotNull("--".takeUnless { treatAsOption }) + subcommandsArguments)
|
||||||
|
it.execute()
|
||||||
|
parsingState = ArgParserResult(it.name)
|
||||||
|
|
||||||
|
return parsingState!!
|
||||||
|
}
|
||||||
} catch (exception: ParsingException) {
|
} catch (exception: ParsingException) {
|
||||||
printError(exception.message!!)
|
printError(exception.message!!)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,16 +70,45 @@ abstract class ArgType<T : Any>(val hasParameter: kotlin.Boolean) {
|
|||||||
?: throw ParsingException("Option $name is expected to be double number. $value is provided.")
|
?: throw ParsingException("Option $name is expected to be double number. $value is provided.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Helper for arguments that have limited set of possible values represented as enumeration constants.
|
||||||
|
*/
|
||||||
|
inline fun <reified T: Enum<T>> Choice(
|
||||||
|
noinline toVariant: (kotlin.String) -> T = {
|
||||||
|
enumValues<T>().find { e -> e.toString().equals(it, ignoreCase = true) } ?:
|
||||||
|
throw IllegalArgumentException("No enum constant $it")
|
||||||
|
},
|
||||||
|
noinline toString: (T) -> kotlin.String = { it.toString().toLowerCase() }): Choice<T> {
|
||||||
|
return Choice(enumValues<T>().toList(), toVariant, toString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type for arguments that have limited set of possible values.
|
* Type for arguments that have limited set of possible values.
|
||||||
*/
|
*/
|
||||||
class Choice(val values: List<kotlin.String>) : ArgType<kotlin.String>(true) {
|
class Choice<T: Any>(choices: List<T>,
|
||||||
override val description: kotlin.String
|
val toVariant: (kotlin.String) -> T,
|
||||||
get() = "{ Value should be one of $values }"
|
val variantToString: (T) -> kotlin.String = { it.toString() }): ArgType<T>(true) {
|
||||||
|
private val choicesMap: Map<kotlin.String, T> = choices.associateBy { variantToString(it) }
|
||||||
|
|
||||||
override fun convert(value: kotlin.String, name: kotlin.String): kotlin.String =
|
init {
|
||||||
if (value in values) value
|
require(choicesMap.size == choices.size) {
|
||||||
else throw ParsingException("Option $name is expected to be one of $values. $value is provided.")
|
"Command line representations of enum choices are not distinct"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val description: kotlin.String
|
||||||
|
get() {
|
||||||
|
return "{ Value should be one of ${choicesMap.keys} }"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun convert(value: kotlin.String, name: kotlin.String) =
|
||||||
|
try {
|
||||||
|
toVariant(value)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw ParsingException("Option $name is expected to be one of ${choicesMap.keys}. $value is provided.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -159,7 +159,7 @@ class MultipleArgument<T : Any, DefaultRequired: DefaultRequiredType> internal c
|
|||||||
fun <T : Any, TResult, DefaultRequired: DefaultRequiredType>
|
fun <T : Any, TResult, DefaultRequired: DefaultRequiredType>
|
||||||
AbstractSingleArgument<T, TResult, DefaultRequired>.multiple(number: Int): MultipleArgument<T, DefaultRequired> {
|
AbstractSingleArgument<T, TResult, DefaultRequired>.multiple(number: Int): MultipleArgument<T, DefaultRequired> {
|
||||||
require(number >= 2) { "multiple() modifier with value less than 2 is unavailable. It's already set to 1." }
|
require(number >= 2) { "multiple() modifier with value less than 2 is unavailable. It's already set to 1." }
|
||||||
val newArgument = with(delegate.cast<ParsingValue<T, T>>().descriptor as ArgDescriptor) {
|
val newArgument = with((delegate.cast<ParsingValue<T, T>>()).descriptor as ArgDescriptor) {
|
||||||
MultipleArgument<T, DefaultRequired>(ArgDescriptor(type, fullName, number, description, listOfNotNull(defaultValue),
|
MultipleArgument<T, DefaultRequired>(ArgDescriptor(type, fullName, number, description, listOfNotNull(defaultValue),
|
||||||
required, deprecatedWarning), owner)
|
required, deprecatedWarning), owner)
|
||||||
}
|
}
|
||||||
@@ -172,7 +172,7 @@ fun <T : Any, TResult, DefaultRequired: DefaultRequiredType>
|
|||||||
*/
|
*/
|
||||||
fun <T : Any, TResult, DefaultRequired: DefaultRequiredType> AbstractSingleArgument<T, TResult, DefaultRequired>.vararg():
|
fun <T : Any, TResult, DefaultRequired: DefaultRequiredType> AbstractSingleArgument<T, TResult, DefaultRequired>.vararg():
|
||||||
MultipleArgument<T, DefaultRequired> {
|
MultipleArgument<T, DefaultRequired> {
|
||||||
val newArgument = with(delegate.cast<ParsingValue<T, T>>().descriptor as ArgDescriptor) {
|
val newArgument = with((delegate.cast<ParsingValue<T, T>>()).descriptor as ArgDescriptor) {
|
||||||
MultipleArgument<T, DefaultRequired>(ArgDescriptor(type, fullName, null, description, listOfNotNull(defaultValue),
|
MultipleArgument<T, DefaultRequired>(ArgDescriptor(type, fullName, null, description, listOfNotNull(defaultValue),
|
||||||
required, deprecatedWarning), owner)
|
required, deprecatedWarning), owner)
|
||||||
}
|
}
|
||||||
@@ -189,7 +189,7 @@ fun <T : Any, TResult, DefaultRequired: DefaultRequiredType> AbstractSingleArgum
|
|||||||
* @param value the default value.
|
* @param value the default value.
|
||||||
*/
|
*/
|
||||||
fun <T: Any> SingleNullableArgument<T>.default(value: T): SingleArgument<T, DefaultRequiredType.Default> {
|
fun <T: Any> SingleNullableArgument<T>.default(value: T): SingleArgument<T, DefaultRequiredType.Default> {
|
||||||
val newArgument = with(delegate.cast<ParsingValue<T, T>>().descriptor as ArgDescriptor) {
|
val newArgument = with((delegate.cast<ParsingValue<T, T>>()).descriptor as ArgDescriptor) {
|
||||||
SingleArgument<T, DefaultRequiredType.Default>(ArgDescriptor(type, fullName, number, description, value,
|
SingleArgument<T, DefaultRequiredType.Default>(ArgDescriptor(type, fullName, number, description, value,
|
||||||
false, deprecatedWarning), owner)
|
false, deprecatedWarning), owner)
|
||||||
}
|
}
|
||||||
@@ -208,7 +208,7 @@ fun <T: Any> SingleNullableArgument<T>.default(value: T): SingleArgument<T, Defa
|
|||||||
fun <T: Any> MultipleArgument<T, DefaultRequiredType.None>.default(value: Collection<T>):
|
fun <T: Any> MultipleArgument<T, DefaultRequiredType.None>.default(value: Collection<T>):
|
||||||
MultipleArgument<T, DefaultRequiredType.Default> {
|
MultipleArgument<T, DefaultRequiredType.Default> {
|
||||||
require (value.isNotEmpty()) { "Default value for argument can't be empty collection." }
|
require (value.isNotEmpty()) { "Default value for argument can't be empty collection." }
|
||||||
val newArgument = with(delegate.cast<ParsingValue<T, List<T>>>().descriptor as ArgDescriptor) {
|
val newArgument = with((delegate.cast<ParsingValue<T, List<T>>>()).descriptor as ArgDescriptor) {
|
||||||
MultipleArgument<T, DefaultRequiredType.Default>(ArgDescriptor(type, fullName, number, description, value.toList(),
|
MultipleArgument<T, DefaultRequiredType.Default>(ArgDescriptor(type, fullName, number, description, value.toList(),
|
||||||
required, deprecatedWarning), owner)
|
required, deprecatedWarning), owner)
|
||||||
}
|
}
|
||||||
@@ -224,7 +224,7 @@ fun <T: Any> MultipleArgument<T, DefaultRequiredType.None>.default(value: Collec
|
|||||||
* Note that only trailing arguments can be optional, i.e. no required arguments can follow optional ones.
|
* Note that only trailing arguments can be optional, i.e. no required arguments can follow optional ones.
|
||||||
*/
|
*/
|
||||||
fun <T: Any> SingleArgument<T, DefaultRequiredType.Required>.optional(): SingleNullableArgument<T> {
|
fun <T: Any> SingleArgument<T, DefaultRequiredType.Required>.optional(): SingleNullableArgument<T> {
|
||||||
val newArgument = with(delegate.cast<ParsingValue<T, T>>().descriptor as ArgDescriptor) {
|
val newArgument = with((delegate.cast<ParsingValue<T, T>>()).descriptor as ArgDescriptor) {
|
||||||
SingleNullableArgument(ArgDescriptor(type, fullName, number, description, defaultValue,
|
SingleNullableArgument(ArgDescriptor(type, fullName, number, description, defaultValue,
|
||||||
false, deprecatedWarning), owner)
|
false, deprecatedWarning), owner)
|
||||||
}
|
}
|
||||||
@@ -240,7 +240,7 @@ fun <T: Any> SingleArgument<T, DefaultRequiredType.Required>.optional(): SingleN
|
|||||||
* Note that only trailing arguments can be optional: no required arguments can follow the optional ones.
|
* Note that only trailing arguments can be optional: no required arguments can follow the optional ones.
|
||||||
*/
|
*/
|
||||||
fun <T: Any> MultipleArgument<T, DefaultRequiredType.Required>.optional(): MultipleArgument<T, DefaultRequiredType.None> {
|
fun <T: Any> MultipleArgument<T, DefaultRequiredType.Required>.optional(): MultipleArgument<T, DefaultRequiredType.None> {
|
||||||
val newArgument = with(delegate.cast<ParsingValue<T, List<T>>>().descriptor as ArgDescriptor) {
|
val newArgument = with((delegate.cast<ParsingValue<T, List<T>>>()).descriptor as ArgDescriptor) {
|
||||||
MultipleArgument<T, DefaultRequiredType.None>(ArgDescriptor(type, fullName, number, description,
|
MultipleArgument<T, DefaultRequiredType.None>(ArgDescriptor(type, fullName, number, description,
|
||||||
defaultValue?.toList() ?: listOf(), false, deprecatedWarning), owner)
|
defaultValue?.toList() ?: listOf(), false, deprecatedWarning), owner)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ import kotlin.annotation.AnnotationTarget.*
|
|||||||
* annotating that usage with the [UseExperimental] annotation, e.g. `@UseExperimental(ExperimentalCli::class)`,
|
* annotating that usage with the [UseExperimental] annotation, e.g. `@UseExperimental(ExperimentalCli::class)`,
|
||||||
* or by using the compiler argument `-Xuse-experimental=kotlinx.cli.ExperimentalCli`.
|
* or by using the compiler argument `-Xuse-experimental=kotlinx.cli.ExperimentalCli`.
|
||||||
*/
|
*/
|
||||||
@RequiresOptIn("This API is experimental. It may be changed in the future without notice.", level = RequiresOptIn.Level.WARNING)
|
@RequiresOptIn("This API is experimental. It may be changed in the future without notice.", RequiresOptIn.Level.WARNING)
|
||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
@Target(
|
@Target(
|
||||||
CLASS,
|
CLASS,
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class MultipleOption<T : Any, OptionType : MultipleOptionType, DefaultType: Defa
|
|||||||
*/
|
*/
|
||||||
fun <T : Any, TResult, DefaultType: DefaultRequiredType> AbstractSingleOption<T, TResult, DefaultType>.multiple():
|
fun <T : Any, TResult, DefaultType: DefaultRequiredType> AbstractSingleOption<T, TResult, DefaultType>.multiple():
|
||||||
MultipleOption<T, MultipleOptionType.Repeated, DefaultType> {
|
MultipleOption<T, MultipleOptionType.Repeated, DefaultType> {
|
||||||
val newOption = with(delegate.cast<ParsingValue<T, T>>().descriptor as OptionDescriptor) {
|
val newOption = with((delegate.cast<ParsingValue<T, T>>()).descriptor as OptionDescriptor) {
|
||||||
MultipleOption<T, MultipleOptionType.Repeated, DefaultType>(
|
MultipleOption<T, MultipleOptionType.Repeated, DefaultType>(
|
||||||
OptionDescriptor(
|
OptionDescriptor(
|
||||||
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
||||||
@@ -122,7 +122,7 @@ fun <T : Any, TResult, DefaultType: DefaultRequiredType> AbstractSingleOption<T,
|
|||||||
*/
|
*/
|
||||||
fun <T : Any, DefaultType: DefaultRequiredType> MultipleOption<T, MultipleOptionType.Delimited, DefaultType>.multiple():
|
fun <T : Any, DefaultType: DefaultRequiredType> MultipleOption<T, MultipleOptionType.Delimited, DefaultType>.multiple():
|
||||||
MultipleOption<T, MultipleOptionType.RepeatedDelimited, DefaultRequiredType> {
|
MultipleOption<T, MultipleOptionType.RepeatedDelimited, DefaultRequiredType> {
|
||||||
val newOption = with(delegate.cast<ParsingValue<T, List<T>>>().descriptor as OptionDescriptor) {
|
val newOption = with((delegate.cast<ParsingValue<T, List<T>>>()).descriptor as OptionDescriptor) {
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
error("Try to use modifier multiple() twice on option ${fullName ?: ""}")
|
error("Try to use modifier multiple() twice on option ${fullName ?: ""}")
|
||||||
}
|
}
|
||||||
@@ -145,7 +145,7 @@ fun <T : Any, DefaultType: DefaultRequiredType> MultipleOption<T, MultipleOption
|
|||||||
* @param value the default value.
|
* @param value the default value.
|
||||||
*/
|
*/
|
||||||
fun <T : Any> SingleNullableOption<T>.default(value: T): SingleOption<T, DefaultRequiredType.Default> {
|
fun <T : Any> SingleNullableOption<T>.default(value: T): SingleOption<T, DefaultRequiredType.Default> {
|
||||||
val newOption = with(delegate.cast<ParsingValue<T, T>>().descriptor as OptionDescriptor) {
|
val newOption = with((delegate.cast<ParsingValue<T, T>>()).descriptor as OptionDescriptor) {
|
||||||
SingleOption<T, DefaultRequiredType.Default>(
|
SingleOption<T, DefaultRequiredType.Default>(
|
||||||
OptionDescriptor(
|
OptionDescriptor(
|
||||||
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
||||||
@@ -167,7 +167,7 @@ fun <T : Any> SingleNullableOption<T>.default(value: T): SingleOption<T, Default
|
|||||||
fun <T : Any, OptionType : MultipleOptionType>
|
fun <T : Any, OptionType : MultipleOptionType>
|
||||||
MultipleOption<T, OptionType, DefaultRequiredType.None>.default(value: Collection<T>):
|
MultipleOption<T, OptionType, DefaultRequiredType.None>.default(value: Collection<T>):
|
||||||
MultipleOption<T, OptionType, DefaultRequiredType.Default> {
|
MultipleOption<T, OptionType, DefaultRequiredType.Default> {
|
||||||
val newOption = with(delegate.cast<ParsingValue<T, List<T>>>().descriptor as OptionDescriptor) {
|
val newOption = with((delegate.cast<ParsingValue<T, List<T>>>()).descriptor as OptionDescriptor) {
|
||||||
require(value.isNotEmpty()) { "Default value for option can't be empty collection." }
|
require(value.isNotEmpty()) { "Default value for option can't be empty collection." }
|
||||||
MultipleOption<T, OptionType, DefaultRequiredType.Default>(
|
MultipleOption<T, OptionType, DefaultRequiredType.Default>(
|
||||||
OptionDescriptor(
|
OptionDescriptor(
|
||||||
@@ -185,7 +185,7 @@ fun <T : Any, OptionType : MultipleOptionType>
|
|||||||
* Requires the option to be always provided in command line.
|
* Requires the option to be always provided in command line.
|
||||||
*/
|
*/
|
||||||
fun <T : Any> SingleNullableOption<T>.required(): SingleOption<T, DefaultRequiredType.Required> {
|
fun <T : Any> SingleNullableOption<T>.required(): SingleOption<T, DefaultRequiredType.Required> {
|
||||||
val newOption = with(delegate.cast<ParsingValue<T, T>>().descriptor as OptionDescriptor) {
|
val newOption = with((delegate.cast<ParsingValue<T, T>>()).descriptor as OptionDescriptor) {
|
||||||
SingleOption<T, DefaultRequiredType.Required>(
|
SingleOption<T, DefaultRequiredType.Required>(
|
||||||
OptionDescriptor(
|
OptionDescriptor(
|
||||||
optionFullFormPrefix, optionShortFromPrefix, type, fullName,
|
optionFullFormPrefix, optionShortFromPrefix, type, fullName,
|
||||||
@@ -204,7 +204,7 @@ fun <T : Any> SingleNullableOption<T>.required(): SingleOption<T, DefaultRequire
|
|||||||
fun <T : Any, OptionType : MultipleOptionType>
|
fun <T : Any, OptionType : MultipleOptionType>
|
||||||
MultipleOption<T, OptionType, DefaultRequiredType.None>.required():
|
MultipleOption<T, OptionType, DefaultRequiredType.None>.required():
|
||||||
MultipleOption<T, OptionType, DefaultRequiredType.Required> {
|
MultipleOption<T, OptionType, DefaultRequiredType.Required> {
|
||||||
val newOption = with(delegate.cast<ParsingValue<T, List<T>>>().descriptor as OptionDescriptor) {
|
val newOption = with((delegate.cast<ParsingValue<T, List<T>>>()).descriptor as OptionDescriptor) {
|
||||||
MultipleOption<T, OptionType, DefaultRequiredType.Required>(
|
MultipleOption<T, OptionType, DefaultRequiredType.Required>(
|
||||||
OptionDescriptor(
|
OptionDescriptor(
|
||||||
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
||||||
@@ -228,7 +228,7 @@ fun <T : Any, OptionType : MultipleOptionType>
|
|||||||
fun <T : Any, DefaultRequired: DefaultRequiredType> AbstractSingleOption<T, *, DefaultRequired>.delimiter(
|
fun <T : Any, DefaultRequired: DefaultRequiredType> AbstractSingleOption<T, *, DefaultRequired>.delimiter(
|
||||||
delimiterValue: String):
|
delimiterValue: String):
|
||||||
MultipleOption<T, MultipleOptionType.Delimited, DefaultRequired> {
|
MultipleOption<T, MultipleOptionType.Delimited, DefaultRequired> {
|
||||||
val newOption = with(delegate.cast<ParsingValue<T, T>>().descriptor as OptionDescriptor) {
|
val newOption = with((delegate.cast<ParsingValue<T, T>>()).descriptor as OptionDescriptor) {
|
||||||
MultipleOption<T, MultipleOptionType.Delimited, DefaultRequired>(
|
MultipleOption<T, MultipleOptionType.Delimited, DefaultRequired>(
|
||||||
OptionDescriptor(
|
OptionDescriptor(
|
||||||
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
||||||
@@ -252,7 +252,7 @@ fun <T : Any, DefaultRequired: DefaultRequiredType> AbstractSingleOption<T, *, D
|
|||||||
fun <T : Any, DefaultRequired: DefaultRequiredType> MultipleOption<T, MultipleOptionType.Repeated, DefaultRequired>.delimiter(
|
fun <T : Any, DefaultRequired: DefaultRequiredType> MultipleOption<T, MultipleOptionType.Repeated, DefaultRequired>.delimiter(
|
||||||
delimiterValue: String):
|
delimiterValue: String):
|
||||||
MultipleOption<T, MultipleOptionType.RepeatedDelimited, DefaultRequired> {
|
MultipleOption<T, MultipleOptionType.RepeatedDelimited, DefaultRequired> {
|
||||||
val newOption = with(delegate.cast<ParsingValue<T, List<T>>>().descriptor as OptionDescriptor) {
|
val newOption = with((delegate.cast<ParsingValue<T, List<T>>>()).descriptor as OptionDescriptor) {
|
||||||
MultipleOption<T, MultipleOptionType.RepeatedDelimited, DefaultRequired>(
|
MultipleOption<T, MultipleOptionType.RepeatedDelimited, DefaultRequired>(
|
||||||
OptionDescriptor(
|
OptionDescriptor(
|
||||||
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
* that can be found in the LICENSE file.
|
* that can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("UNUSED_VARIABLE")
|
||||||
|
|
||||||
package kotlinx.cli
|
package kotlinx.cli
|
||||||
|
|
||||||
import kotlinx.cli.ArgParser
|
import kotlinx.cli.ArgParser
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package kotlinx.cli
|
||||||
|
|
||||||
|
enum class DataSourceEnum {
|
||||||
|
LOCAL,
|
||||||
|
STAGING,
|
||||||
|
PRODUCTION;
|
||||||
|
|
||||||
|
override fun toString(): String = name.toLowerCase()
|
||||||
|
}
|
||||||
@@ -3,10 +3,10 @@
|
|||||||
* that can be found in the LICENSE file.
|
* that can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("UNUSED_VARIABLE")
|
||||||
|
|
||||||
package kotlinx.cli
|
package kotlinx.cli
|
||||||
|
|
||||||
import kotlinx.cli.ArgParser
|
|
||||||
import kotlinx.cli.ArgType
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
class ErrorTests {
|
class ErrorTests {
|
||||||
@@ -42,15 +42,31 @@ class ErrorTests {
|
|||||||
assertTrue("Option number is expected to be integer number. out.txt is provided." in exception.message!!)
|
assertTrue("Option number is expected to be integer number. out.txt is provided." in exception.message!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class RenderEnum {
|
||||||
|
TEXT,
|
||||||
|
HTML;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testWrongChoice() {
|
fun testWrongChoice() {
|
||||||
val argParser = ArgParser("testParser")
|
val argParser = ArgParser("testParser")
|
||||||
val useShortForm by argParser.option(ArgType.Boolean, "short", "s", "Show short version of report").default(false)
|
val useShortForm by argParser.option(ArgType.Boolean, "short", "s", "Show short version of report").default(false)
|
||||||
val renders by argParser.option(ArgType.Choice(listOf("text", "html")),
|
val renders by argParser.option(ArgType.Choice<RenderEnum>(),
|
||||||
"renders", "r", "Renders for showing information").multiple().default(listOf("text"))
|
"renders", "r", "Renders for showing information").multiple().default(listOf(RenderEnum.TEXT))
|
||||||
val exception = assertFailsWith<IllegalStateException> {
|
val exception = assertFailsWith<IllegalStateException> {
|
||||||
argParser.parse(arrayOf("-r", "xml"))
|
argParser.parse(arrayOf("-r", "xml"))
|
||||||
}
|
}
|
||||||
assertTrue("Option renders is expected to be one of [text, html]. xml is provided." in exception.message!!)
|
assertTrue("Option renders is expected to be one of [text, html]. xml is provided." in exception.message!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWrongEnumChoice() {
|
||||||
|
val argParser = ArgParser("testParser")
|
||||||
|
val sources by argParser.option(ArgType.Choice<DataSourceEnum>(),
|
||||||
|
"sources", "s", "Data sources").multiple().default(listOf(DataSourceEnum.PRODUCTION))
|
||||||
|
val exception = assertFailsWith<IllegalStateException> {
|
||||||
|
argParser.parse(arrayOf("-s", "debug"))
|
||||||
|
}
|
||||||
|
assertTrue("Option sources is expected to be one of [local, staging, production]. debug is provided." in exception.message!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,20 @@
|
|||||||
* that can be found in the LICENSE file.
|
* that can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
@file:OptIn(ExperimentalCli::class)
|
@file:OptIn(ExperimentalCli::class)
|
||||||
|
@file:Suppress("UNUSED_VARIABLE")
|
||||||
|
|
||||||
package kotlinx.cli
|
package kotlinx.cli
|
||||||
|
|
||||||
import kotlinx.cli.ArgParser
|
|
||||||
import kotlinx.cli.ArgType
|
|
||||||
import kotlinx.cli.ExperimentalCli
|
|
||||||
import kotlinx.cli.Subcommand
|
|
||||||
import kotlin.math.exp
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
class HelpTests {
|
class HelpTests {
|
||||||
|
enum class Renders {
|
||||||
|
TEXT,
|
||||||
|
HTML,
|
||||||
|
TEAMCITY,
|
||||||
|
STATISTICS,
|
||||||
|
METRICS
|
||||||
|
}
|
||||||
@Test
|
@Test
|
||||||
fun testHelpMessage() {
|
fun testHelpMessage() {
|
||||||
val argParser = ArgParser("test")
|
val argParser = ArgParser("test")
|
||||||
@@ -23,8 +27,10 @@ class HelpTests {
|
|||||||
val epsValue by argParser.option(ArgType.Double, "eps", "e", "Meaningful performance changes").default(1.0)
|
val epsValue by argParser.option(ArgType.Double, "eps", "e", "Meaningful performance changes").default(1.0)
|
||||||
val useShortForm by argParser.option(ArgType.Boolean, "short", "s",
|
val useShortForm by argParser.option(ArgType.Boolean, "short", "s",
|
||||||
"Show short version of report").default(false)
|
"Show short version of report").default(false)
|
||||||
val renders by argParser.option(ArgType.Choice(listOf("text", "html", "teamcity", "statistics", "metrics")),
|
val renders by argParser.option(ArgType.Choice(listOf("text", "html", "teamcity", "statistics", "metrics"), { it }),
|
||||||
shortName = "r", description = "Renders for showing information").multiple().default(listOf("text"))
|
shortName = "r", description = "Renders for showing information").multiple().default(listOf("text"))
|
||||||
|
val sources by argParser.option(ArgType.Choice<DataSourceEnum>(),
|
||||||
|
"sources", "ds", "Data sources").multiple().default(listOf(DataSourceEnum.PRODUCTION))
|
||||||
val user by argParser.option(ArgType.String, shortName = "u", description = "User access information for authorization")
|
val user by argParser.option(ArgType.String, shortName = "u", description = "User access information for authorization")
|
||||||
argParser.parse(arrayOf("main.txt"))
|
argParser.parse(arrayOf("main.txt"))
|
||||||
val helpOutput = argParser.makeUsage().trimIndent()
|
val helpOutput = argParser.makeUsage().trimIndent()
|
||||||
@@ -40,33 +46,47 @@ Options:
|
|||||||
--eps, -e [$epsDefault] -> Meaningful performance changes { Double }
|
--eps, -e [$epsDefault] -> Meaningful performance changes { Double }
|
||||||
--short, -s [false] -> Show short version of report
|
--short, -s [false] -> Show short version of report
|
||||||
--renders, -r [text] -> Renders for showing information { Value should be one of [text, html, teamcity, statistics, metrics] }
|
--renders, -r [text] -> Renders for showing information { Value should be one of [text, html, teamcity, statistics, metrics] }
|
||||||
|
--sources, -ds [production] -> Data sources { Value should be one of [local, staging, production] }
|
||||||
--user, -u -> User access information for authorization { String }
|
--user, -u -> User access information for authorization { String }
|
||||||
--help, -h -> Usage info
|
--help, -h -> Usage info
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
assertEquals(expectedOutput, helpOutput)
|
assertEquals(expectedOutput, helpOutput)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class MetricType {
|
||||||
|
SAMPLES,
|
||||||
|
GEOMEAN;
|
||||||
|
|
||||||
|
override fun toString() = name.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testHelpForSubcommands() {
|
fun testHelpForSubcommands() {
|
||||||
class Summary: Subcommand("summary", "Get summary information") {
|
class Summary: Subcommand("summary", "Get summary information") {
|
||||||
val exec by option(ArgType.Choice(listOf("samples", "geomean")),
|
val exec by option(ArgType.Choice<MetricType>(),
|
||||||
description = "Execution time way of calculation").default("geomean")
|
description = "Execution time way of calculation").default(MetricType.GEOMEAN)
|
||||||
val execSamples by option(ArgType.String, "exec-samples",
|
val execSamples by option(ArgType.String, "exec-samples",
|
||||||
description = "Samples used for execution time metric (value 'all' allows use all samples)").delimiter(",")
|
description = "Samples used for execution time metric (value 'all' allows use all samples)").delimiter(",")
|
||||||
val execNormalize by option(ArgType.String, "exec-normalize",
|
val execNormalize by option(ArgType.String, "exec-normalize",
|
||||||
description = "File with golden results which should be used for normalization")
|
description = "File with golden results which should be used for normalization")
|
||||||
val compile by option(ArgType.Choice(listOf("samples", "geomean")),
|
val compile by option(ArgType.Choice<MetricType>(),
|
||||||
description = "Compile time way of calculation").default("geomean")
|
description = "Compile time way of calculation").default(MetricType.GEOMEAN)
|
||||||
val compileSamples by option(ArgType.String, "compile-samples",
|
val compileSamples by option(ArgType.String, "compile-samples",
|
||||||
description = "Samples used for compile time metric (value 'all' allows use all samples)").delimiter(",")
|
description = "Samples used for compile time metric (value 'all' allows use all samples)").delimiter(",")
|
||||||
val compileNormalize by option(ArgType.String, "compile-normalize",
|
val compileNormalize by option(ArgType.String, "compile-normalize",
|
||||||
description = "File with golden results which should be used for normalization")
|
description = "File with golden results which should be used for normalization")
|
||||||
val codesize by option(ArgType.Choice(listOf("samples", "geomean")),
|
val codesize by option(ArgType.Choice<MetricType>(),
|
||||||
description = "Code size way of calculation").default("geomean")
|
description = "Code size way of calculation").default(MetricType.GEOMEAN)
|
||||||
val codesizeSamples by option(ArgType.String, "codesize-samples",
|
val codesizeSamples by option(ArgType.String, "codesize-samples",
|
||||||
description = "Samples used for code size metric (value 'all' allows use all samples)").delimiter(",")
|
description = "Samples used for code size metric (value 'all' allows use all samples)").delimiter(",")
|
||||||
val codesizeNormalize by option(ArgType.String, "codesize-normalize",
|
val codesizeNormalize by option(ArgType.String, "codesize-normalize",
|
||||||
description = "File with golden results which should be used for normalization")
|
description = "File with golden results which should be used for normalization")
|
||||||
|
val source by option(ArgType.Choice<DataSourceEnum>(),
|
||||||
|
description = "Data source").default(DataSourceEnum.PRODUCTION)
|
||||||
|
val sourceSamples by option(ArgType.String, "source-samples",
|
||||||
|
description = "Samples used for code size metric (value 'all' allows use all samples)").delimiter(",")
|
||||||
|
val sourceNormalize by option(ArgType.String, "source-normalize",
|
||||||
|
description = "File with golden results which should be used for normalization")
|
||||||
val user by option(ArgType.String, shortName = "u", description = "User access information for authorization")
|
val user by option(ArgType.String, shortName = "u", description = "User access information for authorization")
|
||||||
val mainReport by argument(ArgType.String, description = "Main report for analysis")
|
val mainReport by argument(ArgType.String, description = "Main report for analysis")
|
||||||
|
|
||||||
@@ -94,6 +114,9 @@ Options:
|
|||||||
--codesize [geomean] -> Code size way of calculation { Value should be one of [samples, geomean] }
|
--codesize [geomean] -> Code size way of calculation { Value should be one of [samples, geomean] }
|
||||||
--codesize-samples -> Samples used for code size metric (value 'all' allows use all samples) { String }
|
--codesize-samples -> Samples used for code size metric (value 'all' allows use all samples) { String }
|
||||||
--codesize-normalize -> File with golden results which should be used for normalization { String }
|
--codesize-normalize -> File with golden results which should be used for normalization { String }
|
||||||
|
--source [production] -> Data source { Value should be one of [local, staging, production] }
|
||||||
|
--source-samples -> Samples used for code size metric (value 'all' allows use all samples) { String }
|
||||||
|
--source-normalize -> File with golden results which should be used for normalization { String }
|
||||||
--user, -u -> User access information for authorization { String }
|
--user, -u -> User access information for authorization { String }
|
||||||
--help, -h -> Usage info
|
--help, -h -> Usage info
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
* that can be found in the LICENSE file.
|
* that can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("UNUSED_VARIABLE")
|
||||||
|
|
||||||
package kotlinx.cli
|
package kotlinx.cli
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
@@ -38,6 +40,13 @@ class OptionsTests {
|
|||||||
assertEquals("input.txt", input)
|
assertEquals("input.txt", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class Renders {
|
||||||
|
TEXT,
|
||||||
|
HTML,
|
||||||
|
XML,
|
||||||
|
JSON
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGNUPrefix() {
|
fun testGNUPrefix() {
|
||||||
val argParser = ArgParser("testParser", prefixStyle = ArgParser.OptionPrefixStyle.GNU)
|
val argParser = ArgParser("testParser", prefixStyle = ArgParser.OptionPrefixStyle.GNU)
|
||||||
@@ -74,26 +83,37 @@ class OptionsTests {
|
|||||||
fun testMultipleOptions() {
|
fun testMultipleOptions() {
|
||||||
val argParser = ArgParser("testParser")
|
val argParser = ArgParser("testParser")
|
||||||
val useShortForm by argParser.option(ArgType.Boolean, "short", "s", "Show short version of report").default(false)
|
val useShortForm by argParser.option(ArgType.Boolean, "short", "s", "Show short version of report").default(false)
|
||||||
val renders by argParser.option(ArgType.Choice(listOf("text", "html", "xml", "json")),
|
val renders by argParser.option(ArgType.Choice<Renders>(),
|
||||||
"renders", "r", "Renders for showing information").multiple().default(listOf("text"))
|
"renders", "r", "Renders for showing information").multiple().default(listOf(Renders.TEXT))
|
||||||
argParser.parse(arrayOf("-s", "-r", "text", "-r", "json"))
|
val sources by argParser.option(ArgType.Choice<DataSourceEnum>(),
|
||||||
|
"sources", "ds", "Data sources").multiple().default(listOf(DataSourceEnum.PRODUCTION))
|
||||||
|
argParser.parse(arrayOf("-s", "-r", "text", "-r", "json", "-ds", "local", "-ds", "production"))
|
||||||
assertEquals(true, useShortForm)
|
assertEquals(true, useShortForm)
|
||||||
|
|
||||||
assertEquals(2, renders.size)
|
assertEquals(2, renders.size)
|
||||||
val (firstRender, secondRender) = renders
|
val (firstRender, secondRender) = renders
|
||||||
assertEquals("text", firstRender)
|
assertEquals(Renders.TEXT, firstRender)
|
||||||
assertEquals("json", secondRender)
|
assertEquals(Renders.JSON, secondRender)
|
||||||
|
|
||||||
|
assertEquals(2, sources.size)
|
||||||
|
val (firstSource, secondSource) = sources
|
||||||
|
assertEquals(DataSourceEnum.LOCAL, firstSource)
|
||||||
|
assertEquals(DataSourceEnum.PRODUCTION, secondSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDefaultOptions() {
|
fun testDefaultOptions() {
|
||||||
val argParser = ArgParser("testParser")
|
val argParser = ArgParser("testParser")
|
||||||
val useShortForm by argParser.option(ArgType.Boolean, "short", "s", "Show short version of report").default(false)
|
val useShortForm by argParser.option(ArgType.Boolean, "short", "s", "Show short version of report").default(false)
|
||||||
val renders by argParser.option(ArgType.Choice(listOf("text", "html", "xml", "json")),
|
val renders by argParser.option(ArgType.Choice<Renders>(),
|
||||||
"renders", "r", "Renders for showing information").multiple().default(listOf("text"))
|
"renders", "r", "Renders for showing information").multiple().default(listOf(Renders.TEXT))
|
||||||
|
val sources by argParser.option(ArgType.Choice<DataSourceEnum>(),
|
||||||
|
"sources", "ds", "Data sources").multiple().default(listOf(DataSourceEnum.PRODUCTION))
|
||||||
val output by argParser.option(ArgType.String, "output", "o", "Output file")
|
val output by argParser.option(ArgType.String, "output", "o", "Output file")
|
||||||
argParser.parse(arrayOf("-o", "out.txt"))
|
argParser.parse(arrayOf("-o", "out.txt"))
|
||||||
assertEquals(false, useShortForm)
|
assertEquals(false, useShortForm)
|
||||||
assertEquals("text", renders[0])
|
assertEquals(Renders.TEXT, renders[0])
|
||||||
|
assertEquals(DataSourceEnum.PRODUCTION, sources[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -101,20 +121,26 @@ class OptionsTests {
|
|||||||
val argParser = ArgParser("testParser")
|
val argParser = ArgParser("testParser")
|
||||||
val useShortFormOption = argParser.option(ArgType.Boolean, "short", "s", "Show short version of report").default(false)
|
val useShortFormOption = argParser.option(ArgType.Boolean, "short", "s", "Show short version of report").default(false)
|
||||||
var useShortForm by useShortFormOption
|
var useShortForm by useShortFormOption
|
||||||
val rendersOption = argParser.option(ArgType.Choice(listOf("text", "html", "xml", "json")),
|
val rendersOption = argParser.option(ArgType.Choice<Renders>(),
|
||||||
"renders", "r", "Renders for showing information").multiple().default(listOf("text"))
|
"renders", "r", "Renders for showing information").multiple().default(listOf(Renders.TEXT))
|
||||||
var renders by rendersOption
|
var renders by rendersOption
|
||||||
|
val sourcesOption = argParser.option(ArgType.Choice<DataSourceEnum>(),
|
||||||
|
"sources", "ds", "Data sources").multiple().default(listOf(DataSourceEnum.PRODUCTION))
|
||||||
|
var sources by sourcesOption
|
||||||
val outputOption = argParser.option(ArgType.String, "output", "o", "Output file")
|
val outputOption = argParser.option(ArgType.String, "output", "o", "Output file")
|
||||||
var output by outputOption
|
var output by outputOption
|
||||||
argParser.parse(arrayOf("-o", "out.txt"))
|
argParser.parse(arrayOf("-o", "out.txt"))
|
||||||
output = null
|
output = null
|
||||||
useShortForm = true
|
useShortForm = true
|
||||||
renders = listOf()
|
renders = listOf()
|
||||||
|
sources = listOf()
|
||||||
assertEquals(true, useShortForm)
|
assertEquals(true, useShortForm)
|
||||||
assertEquals(null, output)
|
assertEquals(null, output)
|
||||||
assertEquals(0, renders.size)
|
assertEquals(0, renders.size)
|
||||||
|
assertEquals(0, sources.size)
|
||||||
assertEquals(ArgParser.ValueOrigin.REDEFINED, outputOption.valueOrigin)
|
assertEquals(ArgParser.ValueOrigin.REDEFINED, outputOption.valueOrigin)
|
||||||
assertEquals(ArgParser.ValueOrigin.REDEFINED, useShortFormOption.valueOrigin)
|
assertEquals(ArgParser.ValueOrigin.REDEFINED, useShortFormOption.valueOrigin)
|
||||||
assertEquals(ArgParser.ValueOrigin.REDEFINED, rendersOption.valueOrigin)
|
assertEquals(ArgParser.ValueOrigin.REDEFINED, rendersOption.valueOrigin)
|
||||||
|
assertEquals(ArgParser.ValueOrigin.REDEFINED, sourcesOption.valueOrigin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class SubcommandsTests {
|
|||||||
}
|
}
|
||||||
val action = Summary()
|
val action = Summary()
|
||||||
argParser.subcommands(action)
|
argParser.subcommands(action)
|
||||||
argParser.parse(arrayOf("-o", "out.txt", "summary", "-i", "2", "3", "5"))
|
argParser.parse(arrayOf("summary", "-o", "out.txt", "-i", "2", "3", "5"))
|
||||||
assertEquals("out.txt", output)
|
assertEquals("out.txt", output)
|
||||||
assertEquals(-10, action.result)
|
assertEquals(-10, action.result)
|
||||||
}
|
}
|
||||||
@@ -100,4 +100,37 @@ class SubcommandsTests {
|
|||||||
argParser.parse(arrayOf("calc", "-i", "summary", "2", "3", "5"))
|
argParser.parse(arrayOf("calc", "-i", "summary", "2", "3", "5"))
|
||||||
assertEquals(-10, action.result)
|
assertEquals(-10, action.result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCommonDefaultInSubcommand() {
|
||||||
|
val parser = ArgParser("testParser")
|
||||||
|
val output by parser.option(ArgType.String, "output", "o", "Output file")
|
||||||
|
.default("any_file")
|
||||||
|
class Summary: Subcommand("summary", "Calculate summary") {
|
||||||
|
val invert by option(ArgType.Boolean, "invert", "i", "Invert results").default(false)
|
||||||
|
val addendums by argument(ArgType.Int, "addendums", description = "Addendums").vararg()
|
||||||
|
var result: Int = 0
|
||||||
|
|
||||||
|
override fun execute() {
|
||||||
|
result = addendums.sum()
|
||||||
|
result = if (invert) -1 * result else result
|
||||||
|
println("result is: $result and will output to $output")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Multiply: Subcommand("mul", "Multiply") {
|
||||||
|
val numbers by argument(ArgType.Int, description = "Addendums").vararg()
|
||||||
|
var result: Int = 0
|
||||||
|
|
||||||
|
override fun execute() {
|
||||||
|
result = numbers.reduce{ acc, it -> acc * it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val summary = Summary()
|
||||||
|
val multiple = Multiply()
|
||||||
|
parser.subcommands(summary, multiple)
|
||||||
|
|
||||||
|
parser.parse(arrayOf("summary", "1", "2", "4"))
|
||||||
|
assertEquals("any_file", output)
|
||||||
|
assertEquals(7, summary.result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user