mirror of
https://github.com/apple/pkl.git
synced 2026-03-28 20:01:55 +01:00
Command flag behavior improvements (#1432)
* Forbid overlap of built-in and command-defined flag names * Allow interleaving built-in and command-defined flags on the command line * List abbreviated flag names first, matching the behavior of built-in flags
This commit is contained in:
@@ -45,6 +45,8 @@ class CliCommandRunner
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
private val options: CliBaseOptions,
|
||||
private val reservedFlagNames: Set<String>,
|
||||
private val reservedFlagShortNames: Set<String>,
|
||||
private val args: List<String>,
|
||||
private val outputStream: OutputStream = System.out,
|
||||
private val errStream: OutputStream = System.err,
|
||||
@@ -65,7 +67,11 @@ constructor(
|
||||
private fun evalCmd(builder: EvaluatorBuilder) {
|
||||
val evaluator = builder.build()
|
||||
evaluator.use {
|
||||
evaluator.evaluateCommand(uri(normalizedSourceModule)) { spec ->
|
||||
evaluator.evaluateCommand(
|
||||
uri(normalizedSourceModule),
|
||||
reservedFlagNames,
|
||||
reservedFlagShortNames,
|
||||
) { spec ->
|
||||
try {
|
||||
val root = SynthesizedRunCommand(spec, this, options.sourceModules.first().toString())
|
||||
root.installCommonOptions(includeVersion = false)
|
||||
@@ -233,7 +239,7 @@ constructor(
|
||||
.mapNotNull {
|
||||
val opt = it as? OptionWithValues<*, *, *> ?: return@mapNotNull null
|
||||
return@mapNotNull if (it.names.contains("--help")) null
|
||||
else it.names.first().trimStart('-') to opt.value
|
||||
else it.names.last().trimStart('-') to opt.value
|
||||
}
|
||||
.toMap() +
|
||||
registeredArguments()
|
||||
|
||||
@@ -16,11 +16,16 @@
|
||||
package org.pkl.cli.commands
|
||||
|
||||
import com.github.ajalt.clikt.completion.CompletionCandidates
|
||||
import com.github.ajalt.clikt.core.MissingArgument
|
||||
import com.github.ajalt.clikt.core.PrintHelpMessage
|
||||
import com.github.ajalt.clikt.core.context
|
||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||
import com.github.ajalt.clikt.parameters.arguments.convert
|
||||
import com.github.ajalt.clikt.parameters.arguments.multiple
|
||||
import com.github.ajalt.clikt.parameters.arguments.optional
|
||||
import com.github.ajalt.clikt.parameters.groups.provideDelegate
|
||||
import com.github.ajalt.clikt.parameters.options.flag
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
import java.net.URI
|
||||
import org.pkl.cli.CliCommandRunner
|
||||
import org.pkl.commons.cli.commands.BaseCommand
|
||||
@@ -32,19 +37,46 @@ class RunCommand : BaseCommand(name = "run", helpLink = helpLink) {
|
||||
override val treatUnknownOptionsAsArgs = true
|
||||
|
||||
init {
|
||||
context { allowInterspersedArgs = false }
|
||||
context {
|
||||
// override clikt's built-in help behavior
|
||||
// the built-in --help is eager so any --help/-h would force printing of pkl run's help
|
||||
// which is not desired when a command module (or any of its subcommands) are present
|
||||
// since that would mean command-defined help is gated behind a non-obvious `-- --help`
|
||||
helpOptionNames = emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
val module: URI by
|
||||
argument(name = "module", completionCandidates = CompletionCandidates.Path).convert {
|
||||
BaseOptions.parseModuleName(it)
|
||||
}
|
||||
private val showHelp by option("-h", "--help", help = "Show this message and exit").flag()
|
||||
|
||||
val module: URI? by
|
||||
argument(name = "module", completionCandidates = CompletionCandidates.Path)
|
||||
.convert { BaseOptions.parseModuleName(it) }
|
||||
.optional()
|
||||
|
||||
val args: List<String> by argument(name = "args").multiple()
|
||||
|
||||
private val projectOptions by ProjectOptions()
|
||||
|
||||
override fun run() {
|
||||
CliCommandRunner(baseOptions.baseOptions(listOf(module), projectOptions), args).run()
|
||||
// if no module is specified but --help is show help, otherwise error becuase module is missing
|
||||
if (module == null)
|
||||
if (showHelp) throw PrintHelpMessage(currentContext)
|
||||
else throw MissingArgument(registeredArguments().find { it.name == "module" }!!)
|
||||
|
||||
val reservedFlagNames = mutableSetOf("help")
|
||||
val reservedFlagShortNames = mutableSetOf("h")
|
||||
registeredOptions().forEach { opt ->
|
||||
(opt.names + opt.secondaryNames).forEach {
|
||||
if (it.startsWith("--")) reservedFlagNames.add(it.trimStart('-'))
|
||||
else reservedFlagShortNames.add(it.trimStart('-'))
|
||||
}
|
||||
}
|
||||
CliCommandRunner(
|
||||
baseOptions.baseOptions(listOf(module!!), projectOptions),
|
||||
reservedFlagNames,
|
||||
reservedFlagShortNames,
|
||||
if (showHelp) args + listOf("--help") else args,
|
||||
)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,15 @@ class CliCommandRunnerTest {
|
||||
|
||||
private fun runToStdout(options: CliBaseOptions, args: List<String>): String {
|
||||
val outWriter = ByteArrayOutputStream()
|
||||
CliCommandRunner(options, args, outWriter, ByteArrayOutputStream()).run()
|
||||
CliCommandRunner(
|
||||
options,
|
||||
setOf("root-dir"),
|
||||
emptySet(),
|
||||
args,
|
||||
outWriter,
|
||||
ByteArrayOutputStream(),
|
||||
)
|
||||
.run()
|
||||
return outWriter.toString(StandardCharsets.UTF_8)
|
||||
}
|
||||
|
||||
@@ -1071,9 +1079,9 @@ class CliCommandRunnerTest {
|
||||
int16: Int16
|
||||
@CountedFlag { shortName = "d" }
|
||||
int32: Int32
|
||||
@CountedFlag { shortName = "e" }
|
||||
@CountedFlag { shortName = "x" }
|
||||
uint: UInt
|
||||
@CountedFlag { shortName = "f" }
|
||||
@CountedFlag { shortName = "y" }
|
||||
uint8: UInt8
|
||||
@CountedFlag { shortName = "g" }
|
||||
uint16: UInt16
|
||||
@@ -1087,7 +1095,7 @@ class CliCommandRunnerTest {
|
||||
val output =
|
||||
runToStdout(
|
||||
CliBaseOptions(sourceModules = listOf(moduleUri)),
|
||||
listOf("-abbcccddddeeeeeffffffgggggggiiiiiiii"),
|
||||
listOf("-abbcccddddxxxxxyyyyyygggggggiiiiiiii"),
|
||||
)
|
||||
assertThat(output)
|
||||
.isEqualTo(
|
||||
|
||||
Reference in New Issue
Block a user