mirror of
https://github.com/corda/corda.git
synced 2025-02-20 09:26:41 +00:00
CORDA-2028 - Fix use of required paramers/options on command line (#4040)
* Make required parameters work with --install-shell-extensions and make errors look a bit more errorey * Make blobinspector required parameter work the way it used to * Fix compilation Error
This commit is contained in:
parent
5d84640d1f
commit
9c8a1cd14a
@ -34,8 +34,8 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
class BlobInspector : CordaCliWrapper("blob-inspector", "Convert AMQP serialised binary blobs to text") {
|
||||
@Parameters(index = "*..0", paramLabel = "SOURCE", description = ["URL or file path to the blob"], converter = [SourceConverter::class])
|
||||
var source: MutableList<URL> = mutableListOf()
|
||||
@Parameters(index = "0", paramLabel = "SOURCE", description = ["URL or file path to the blob"], converter = [SourceConverter::class])
|
||||
var source: URL? = null
|
||||
|
||||
@Option(names = ["--format"], paramLabel = "type", description = ["Output format. Possible values: [YAML, JSON]"])
|
||||
private var formatType: OutputFormatType = OutputFormatType.YAML
|
||||
@ -61,8 +61,7 @@ class BlobInspector : CordaCliWrapper("blob-inspector", "Convert AMQP serialised
|
||||
}
|
||||
|
||||
fun run(out: PrintStream): Int {
|
||||
require(source.count() == 1) { "You must specify URL or file path to the blob" }
|
||||
val inputBytes = source.first().readBytes()
|
||||
val inputBytes = source!!.readBytes()
|
||||
val bytes = parseToBinaryRelaxed(inputFormatType, inputBytes)
|
||||
?: throw IllegalArgumentException("Error: this input does not appear to be encoded in Corda's AMQP extended format, sorry.")
|
||||
|
||||
|
@ -53,7 +53,7 @@ class BlobInspectorTest {
|
||||
}
|
||||
|
||||
private fun run(resourceName: String): String {
|
||||
blobInspector.source = mutableListOf(javaClass.getResource(resourceName))
|
||||
blobInspector.source = javaClass.getResource(resourceName)
|
||||
val writer = StringWriter()
|
||||
blobInspector.run(PrintStream(WriterOutputStream(writer, UTF_8)))
|
||||
val output = writer.toString()
|
||||
|
@ -21,8 +21,6 @@ import java.util.concurrent.Callable
|
||||
interface Validated {
|
||||
companion object {
|
||||
val logger = contextLogger()
|
||||
const val RED = "\u001B[31m"
|
||||
const val RESET = "\u001B[0m"
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,8 +34,8 @@ interface Validated {
|
||||
fun validate() {
|
||||
val errors = validator()
|
||||
if (errors.isNotEmpty()) {
|
||||
logger.error(RED + "Exceptions when parsing command line arguments:")
|
||||
logger.error(errors.joinToString("\n") + RESET)
|
||||
logger.error(ShellConstants.RED + "Exceptions when parsing command line arguments:")
|
||||
logger.error(errors.joinToString("\n") + ShellConstants.RESET)
|
||||
CommandLine(this).usage(System.err)
|
||||
exitProcess(ExitCodes.FAILURE)
|
||||
}
|
||||
@ -55,6 +53,11 @@ object CordaSystemUtils {
|
||||
fun getOsName(): String = System.getProperty(OS_NAME)
|
||||
}
|
||||
|
||||
object ShellConstants {
|
||||
const val RED = "\u001B[31m"
|
||||
const val RESET = "\u001B[0m"
|
||||
}
|
||||
|
||||
fun CordaCliWrapper.start(args: Array<String>) {
|
||||
this.args = args
|
||||
|
||||
@ -66,27 +69,47 @@ fun CordaCliWrapper.start(args: Array<String>) {
|
||||
cmd.registerConverter(Path::class.java) { Paths.get(it).toAbsolutePath().normalize() }
|
||||
cmd.commandSpec.name(alias)
|
||||
cmd.commandSpec.usageMessage().description(description)
|
||||
cmd.commandSpec.parser().collectErrors(true)
|
||||
try {
|
||||
val defaultAnsiMode = if (CordaSystemUtils.isOsWindows()) { Help.Ansi.ON } else { Help.Ansi.AUTO }
|
||||
val results = cmd.parseWithHandlers(RunLast().useOut(System.out).useAnsi(defaultAnsiMode),
|
||||
DefaultExceptionHandler<List<Any>>().useErr(System.err).useAnsi(defaultAnsiMode),
|
||||
*args)
|
||||
// If an error code has been returned, use this and exit
|
||||
results?.firstOrNull()?.let {
|
||||
if (it is Int) {
|
||||
exitProcess(it)
|
||||
} else {
|
||||
val defaultAnsiMode = if (CordaSystemUtils.isOsWindows()) {
|
||||
Help.Ansi.ON
|
||||
} else {
|
||||
Help.Ansi.AUTO
|
||||
}
|
||||
|
||||
val results = cmd.parse(*args)
|
||||
val app = cmd.getCommand<CordaCliWrapper>()
|
||||
if (cmd.isUsageHelpRequested) {
|
||||
cmd.usage(System.out, defaultAnsiMode)
|
||||
exitProcess(ExitCodes.SUCCESS)
|
||||
}
|
||||
if (cmd.isVersionHelpRequested) {
|
||||
cmd.printVersionHelp(System.out, defaultAnsiMode)
|
||||
exitProcess(ExitCodes.SUCCESS)
|
||||
}
|
||||
if (app.installShellExtensionsParser.installShellExtensions) {
|
||||
System.out.println("Install shell extensions: ${app.installShellExtensionsParser.installShellExtensions}")
|
||||
// ignore any parsing errors and run the program
|
||||
exitProcess(app.call())
|
||||
}
|
||||
val allErrors = results.flatMap { it.parseResult?.errors() ?: emptyList() }
|
||||
if (allErrors.any()) {
|
||||
val parameterExceptions = allErrors.asSequence().filter { it is ParameterException }
|
||||
if (parameterExceptions.any()) {
|
||||
System.err.println("${ShellConstants.RED}${parameterExceptions.map{ it.message }.joinToString()}${ShellConstants.RESET}")
|
||||
parameterExceptions.filter { it is UnmatchedArgumentException}.forEach { (it as UnmatchedArgumentException).printSuggestions(System.out) }
|
||||
usage(cmd, System.out, defaultAnsiMode)
|
||||
exitProcess(ExitCodes.FAILURE)
|
||||
}
|
||||
throw allErrors.first()
|
||||
}
|
||||
// If no results returned, picocli ran something without invoking the main program, e.g. --help or --version, so exit successfully
|
||||
exitProcess(ExitCodes.SUCCESS)
|
||||
} catch (e: ExecutionException) {
|
||||
exitProcess(app.call())
|
||||
} catch (e: Exception) {
|
||||
val throwable = e.cause ?: e
|
||||
if (this.verbose) {
|
||||
throwable.printStackTrace()
|
||||
} else {
|
||||
System.err.println("*ERROR*: ${throwable.rootMessage ?: "Use --verbose for more details"}")
|
||||
System.err.println("${ShellConstants.RED}${throwable.rootMessage ?: "Use --verbose for more details"}${ShellConstants.RESET}")
|
||||
}
|
||||
exitProcess(ExitCodes.FAILURE)
|
||||
}
|
||||
@ -126,7 +149,7 @@ abstract class CordaCliWrapper(val alias: String, val description: String) : Cal
|
||||
var loggingLevel: Level = Level.INFO
|
||||
|
||||
@Mixin
|
||||
private lateinit var installShellExtensionsParser: InstallShellExtensionsParser
|
||||
lateinit var installShellExtensionsParser: InstallShellExtensionsParser
|
||||
|
||||
// This needs to be called before loggers (See: NodeStartup.kt:51 logger called by lazy, initLogging happens before).
|
||||
// Node's logging is more rich. In corda configurations two properties, defaultLoggingLevel and consoleLogLevel, are usually used.
|
||||
|
Loading…
x
Reference in New Issue
Block a user