A CheckSum Utility
24 25 -@Command(description = "Prints the checksum (MD5 by default) of a file to STDOUT.", + @Command(description = "Prints the checksum (SHA-1 by default) of a file to STDOUT.", name = "checksum", mixinStandardHelpOptions = true, version = "checksum 3.0") class CheckSum implements Callable<Void> { @@ -1720,7 +1719,7 @@A CheckSum Utility
private File file; @Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...") - private String algorithm = "MD5"; + private String algorithm = "SHA-1"; public static void main(String[] args) { // CheckSum implements Callable, so parsing, error handling and handling user @@ -1759,7 +1758,7 @@A CheckSum Utility
-The
+<file>
positional parameter does not have a default, so this a mandatory parameter. The--algorithm
option does have a default:"MD5"
, so it is optional.The
<file>
positional parameter does not have a default, so this a mandatory parameter. The--algorithm
option does have a default:"SHA-1"
, so it is optional.@@ -2632,7 +2555,7 @@Note that our program does not have any logic to validate the user input. The validation was done automatically by picocli as part of the
@@ -1770,14 +1769,14 @@CommandLine.call(Callable, String[])
invocation in ourmain
method. Later we will show some alternatives that give more control to the application.A CheckSum Utility
@@ -2541,8 +2464,8 @@Comparing ourCheckSum
utility againstmd5sum
andsha1sum
-$ java picocli.example.CheckSum picocli-3.9.5.jar +$ java picocli.example.CheckSum --algorithm=MD5 picocli-3.9.5.jar 509e3e2602854d5b88e2e7baa476a7fe $ md5sum picocli-3.9.5.jar 509e3e2602854d5b88e2e7baa476a7fe *picocli-3.9.5.jar -$ java picocli.example.CheckSum --algorithm=SHA1 picocli-3.9.5.jar +$ java picocli.example.CheckSum picocli-3.9.5.jar f659a2feef0e8f7f8458aaf7d36c4d92f65320c8 $ sha1sum picocli-3.9.5.jar @@ -1808,7 +1807,7 @@A CheckSum Utility
$ java picocli.example.CheckSum --help Usage: checksum [-hV] [-a=<algorithm>] <file> -Prints the checksum (MD5 by default) of a file to STDOUT. +Prints the checksum (SHA-1 by default) of a file to STDOUT. <file> The file whose checksum to calculate. -a, --algorithm=<algorithm> MD5, SHA-1, SHA-256, ... @@ -2738,7 +2737,7 @@+private String algorithm = "SHA-1";Completion Candidates
} @Option(names = {"-a", "--algorithm"}, completionCandidates = AlgoList.class, description = "${COMPLETION-CANDIDATES}, ...") -private String algorithm = "MD5";@@ -2817,7 +2816,7 @@diff --git a/docs/announcing-picocli-1.0.html b/docs/announcing-picocli-1.0.html index 6330fea13..22d56aafa 100644 --- a/docs/announcing-picocli-1.0.html +++ b/docs/announcing-picocli-1.0.html @@ -4,26 +4,24 @@ - +Groovy Scripts
@Option(names = ["-a", "--algorithm"], description = [ "MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512, or", " any other MessageDigest algorithm. See [1] for more details."]) -@Field private String algorithm = "MD5" +@Field private String algorithm = "SHA-1" files.each { println ""+MessageDigest.getInstance(algorithm).digest(it.bytes).encodeHex()+"\t"+it @@ -3086,8 +3085,8 @@Conclusion
Announcing picocli 1.0 - a mighty tiny command line interface - - - - - + + +picocli - a mighty tiny command line interface
-version 4.6.2, -2021-11-05 +version 4.6.3, +2022-02-09@@ -2485,7 +2408,7 @@Features@@ -2270,14 +2193,14 @@import java.util.concurrent.Callable; @Command(name = "checksum", mixinStandardHelpOptions = true, version = "checksum 4.0", - description = "Prints the checksum (MD5 by default) of a file to STDOUT.") + description = "Prints the checksum (SHA-256 by default) of a file to STDOUT.") class CheckSum implements Callable<Integer> { @Parameters(index = "0", description = "The file whose checksum to calculate.") private File file; @Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...") - private String algorithm = "MD5"; + private String algorithm = "SHA-256"; @Override public Integer call() throws Exception { // your business logic goes here... @@ -2299,7 +2222,7 @@
Groovy-@Grab('info.picocli:picocli-groovy:4.6.2') +
@Grab('info.picocli:picocli-groovy:4.6.3') import picocli.CommandLine import static picocli.CommandLine.* @@ -2307,14 +2230,14 @@
import java.util.concurrent.Callable @Command(name = 'checksum', mixinStandardHelpOptions = true, version = 'checksum 4.0', - description = 'Prints the checksum (MD5 by default) of a file to STDOUT.') + description = 'Prints the checksum (SHA-256 by default) of a file to STDOUT.') class Checksum implements Callable<Integer> { @Parameters(index = '0', description = 'The file whose checksum to calculate.') File file @Option(names = ['-a', '--algorithm'], description = 'MD5, SHA-1, SHA-256, ...') - String algorithm = 'MD5' + String algorithm = 'SHA-256' Integer call() throws Exception { println MessageDigest.getInstance(algorithm).digest(file.bytes).encodeHex().toString() @@ -2330,20 +2253,20 @@
Groovy script-@@ -2364,14 +2287,14 @@@Grab('info.picocli:picocli-groovy:4.6.2') +
@Grab('info.picocli:picocli-groovy:4.6.3') import static picocli.CommandLine.* import groovy.transform.Field import java.security.MessageDigest @Command(name = 'checksum', mixinStandardHelpOptions = true, version = 'checksum 4.0', - description = 'Prints the checksum (MD5 by default) of a file to STDOUT.') + description = 'Prints the checksum (SHA-256 by default) of a file to STDOUT.') @picocli.groovy.PicocliScript @Parameters(index = '0', description = 'The file whose checksum to calculate.') @Field File file @Option(names = ['-a', '--algorithm'], description = 'MD5, SHA-1, SHA-256, ...') -@Field String algorithm = 'MD5' +@Field String algorithm = 'SHA-256' println MessageDigest.getInstance(algorithm).digest(file.bytes).encodeHex().toString()
import kotlin.system.exitProcess @Command(name = "checksum", mixinStandardHelpOptions = true, version = ["checksum 4.0"], - description = ["Prints the checksum (MD5 by default) of a file to STDOUT."]) + description = ["Prints the checksum (SHA-256 by default) of a file to STDOUT."]) class Checksum : Callable<Int> { @Parameters(index = "0", description = ["The file whose checksum to calculate."]) lateinit var file: File @Option(names = ["-a", "--algorithm"], description = ["MD5, SHA-1, SHA-256, ..."]) - var algorithm = "MD5" + var algorithm = "SHA-256" override fun call(): Int { val fileContents = Files.readAllBytes(file.toPath()) @@ -2397,14 +2320,14 @@
import java.util.concurrent.Callable @Command(name = "checksum", mixinStandardHelpOptions = true, version = Array("checksum 4.0"), - description = Array("Prints the checksum (MD5 by default) of a file to STDOUT.")) + description = Array("Prints the checksum (SHA-256 by default) of a file to STDOUT.")) class Checksum extends Callable[Int] { @Parameters(index = "0", description = Array("The file whose checksum to calculate.")) private var file: File = null @Option(names = Array("-a", "--algorithm"), description = Array("MD5, SHA-1, SHA-256, ...")) - private var algorithm = "MD5" + private var algorithm = "SHA-256" def call(): Int = { val fileContents = Files.readAllBytes(file.toPath) @@ -2475,7 +2398,7 @@
Gradle
dependencies { - implementation 'info.picocli:picocli:4.6.2' + implementation 'info.picocli:picocli:4.6.3' }
<dependency> <groupId>info.picocli</groupId> <artifactId>picocli</artifactId> - <version>4.6.2</version> + <version>4.6.3</version> </dependency>
Usi
Gradledependencies { - implementation 'info.picocli:picocli:4.6.2' - annotationProcessor 'info.picocli:picocli-codegen:4.6.2' + implementation 'info.picocli:picocli:4.6.3' + annotationProcessor 'info.picocli:picocli-codegen:4.6.3' } @@ -2564,7 +2487,7 @@
Usi <path> <groupId>info.picocli</groupId> <artifactId>picocli-codegen</artifactId> - <version>4.6.2</version> + <version>4.6.3</version> </path> </annotationProcessorPaths> <compilerArgs> @@ -2589,7 +2512,7 @@
apply plugin: 'kotlin-kapt' // required dependencies { // ... - kapt 'info.picocli:picocli-codegen:4.6.2' + kapt 'info.picocli:picocli-codegen:4.6.3' }
-+java -cp "picocli-4.6.2.jar:checksum.jar" CheckSum --algorithm SHA-1 hello.txt
java -cp "picocli-4.6.3.jar:checksum.jar" CheckSum --algorithm SHA-1 hello.txt
@@ -6316,7 +6239,7 @@static class Outer { @Option(names = "-x", defaultValue = "XX") String x = "XX"; - @ArgGroup(exclusive = "true") + @ArgGroup(exclusive = true) Inner inner; // no initial value } @@ -6350,7 +6273,7 @@
class Outer { @Option(names = "-x", defaultValue = "XX") var x = "XX"; - @ArgGroup(exclusive = "true") + @ArgGroup(exclusive = true) lateinit var inner: Inner // no initial value } @@ -8182,14 +8105,14 @@
-
11.9. Option Names or Subcommands as Option Values
---Since picocli 4.4, the parser will no longer assign values that match a subcommand name or an option name to options that take a parameter, unless the value is in quotes. - For example:
--+Java-+-11.9. Option Names or Subcommands as Option Values
+++Since picocli 4.4, the parser will no longer assign values that match a subcommand name or an option name to options that take a parameter, unless the value is in quotes. +For example:
++-Java+--class App { @Option(names = "-x") String x; @Option(names = "-y") String y; @@ -8200,11 +8123,11 @@
System.out.printf("x='%s', y='%s'%n", app.x, app.y); } }
-+Kotlin-+++-Kotlin+--class App { @Option(names = ["-x"]) var x: String? = null @Option(names = ["-y"]) var y: String? = null @@ -8215,35 +8138,35 @@
CommandLine(app).setTrimQuotes(true).parseArgs(*args) println("x='${app.x}', y='${app.y}'") }
--In previous versions of picocli, the above command would accept input
--x -y
, and the value-y
would be assigned to thex
String field. - As of picocli 4.4, the above input will be rejected with an error message indicating that the-x
option requires a parameter.--If it is necessary to accept values that match option names, such values need to be quoted. - For example:
------java App -x="-y"
--This will print the following output:
------x='-y', y='null'
--Another idea is to replace or augment picocli’s parser by doing custom parameter processing for such options. For example:
--+Java-++++In previous versions of picocli, the above command would accept input
+-x -y
, and the value-y
would be assigned to thex
String field. +As of picocli 4.4, the above input will be rejected with an error message indicating that the-x
option requires a parameter.++If it is necessary to accept values that match option names, such values need to be quoted. +For example:
++++++java App -x="-y"
++This will print the following output:
++++++x='-y', y='null'
++Another idea is to replace or augment picocli’s parser by doing custom parameter processing for such options. For example:
++-Java+--class App implements Runnable { @Option(names = "-x", parameterConsumer = App.CustomConsumer.class) String x; @@ -8274,11 +8197,11 @@
new CommandLine(new App()).execute(args); } }
-+Kotlin-+++-Kotlin+--class App : Runnable { @Option(names = ["-x"], parameterConsumer = CustomConsumer::class) var x: String? = null @@ -8312,23 +8235,22 @@
} } }
--The above code assigns whatever command line argument that follows the
--x
option to that option, - and allows input like the following:-+++++The above code assigns whatever command line argument that follows the
+-x
option to that option, +and allows input like the following:+--java App -x=mySubcommand java App -x mySubcommand java App -x=-y java App -x -y -y=123
- +++11.10. Toggle Boolean Flags
When a flag option is specified on the command line picocli will set its value to the opposite of its default value.
@@ -14493,7 +14415,7 @@
-+java -cp "picocli-4.6.2.jar;myapp.jar" org.myorg.GreetingApp Sarah Lea
java -cp "picocli-4.6.3.jar;myapp.jar" org.myorg.GreetingApp Sarah Lea
@@ -14510,7 +14432,7 @@
-+java -cp "picocli-4.6.2.jar;myapp.jar" org.myorg.GreetingApp --locale=es Sarah Lea
java -cp "picocli-4.6.3.jar;myapp.jar" org.myorg.GreetingApp --locale=es Sarah Lea
@@ -14959,6 +14881,60 @@}
++
++ ++ + ++ +++Applications that reuse a single
+CommandLine
instance for multipleparseArgs
orexecute
invocations should be aware of the following:++Annotated setter method options that explicitly set
+defaultValue = Option.NULL_VALUE
will get a call with anull
parameter when the command line did not include that option.++If the setter method annotation does not explicitly set
+defaultValue = Option.NULL_VALUE
, then this method will not be called when the command line did not include that option. This means that the value will retain the value of the previousparseArgs
orexecute
invocation, which may not be desirable. (This only happens for applications that reuse a singleCommandLine
instance for multipleparseArgs
orexecute
invocations.)++Java++++class App { + String x; + String y; + + // reset to null when option not specified + @Option(names = "-x", defaultValue = Option.NULL) + void setX(String x) { this.x = x; } + + // retains value of previous parseArgs invocation when option not specified + @Option(names = "-y") + void setY(String y) { this.y = y; } +}
++Kotlin++++class App { + var x + var y + + // reset to null when option not specified + @Option(names = ["-x"], defaultValue = Option.NULL) + fun setX(x: String) { this.x = x } + + // retains value of previous parseArgs invocation when option not specified + @Option(names = ["-y"]) + fun setY(y: String) { this.y = y } +}
@@ -16080,7 +16056,7 @@@@ -16088,7 +16064,7 @@
<dependency> <groupId>info.picocli</groupId> <artifactId>picocli-spring-boot-starter</artifactId> - <version>4.6.2</version> + <version>4.6.3</version> </dependency>
Gradle (Groovy)
@@ -16096,7 +16072,7 @@dependencies { - implementation 'info.picocli:picocli-spring-boot-starter:4.6.2' + implementation 'info.picocli:picocli-spring-boot-starter:4.6.3' }
Gradle (Kotlin)
@@ -16506,7 +16482,7 @@dependencies { - implementation("info.picocli:picocli-spring-boot-starter:4.6.2") + implementation("info.picocli:picocli-spring-boot-starter:4.6.3") }
22.3. Micronaut Example
-+
The Micronaut microservices framework provides built-in support for picocli with its
@@ -17706,7 +17682,7 @@PicocliRunner
class.
-+java -cp "picocli-4.6.2.jar;myapp.jar" org.myorg.MyMainClass --option=value arg0 arg1
java -cp "picocli-4.6.3.jar;myapp.jar" org.myorg.MyMainClass --option=value arg0 arg1
-+alias mycommand='java -cp "/path/to/picocli-4.6.2.jar:/path/to/myapp.jar" org.myorg.MainClass'
alias mycommand='java -cp "/path/to/picocli-4.6.3.jar:/path/to/myapp.jar" org.myorg.MainClass'
When upgrading scripts from picocli versions older than 4.0, just changing the version number is not enough! -Scripts should use @@ -18166,7 +18142,7 @@@Grab('info.picocli:picocli-groovy:4.6.2')
. The old artifact id@Grab('info.picocli:picocli:4.6.2')
will not work, +Scripts should use@Grab('info.picocli:picocli-groovy:4.6.3')
. The old artifact id@Grab('info.picocli:picocli:4.6.3')
will not work, because the@picocli.groovy.PicocliScript
annotation class and supporting classes have been moved into a separate module,picocli-groovy
.
-@@ -18357,14 +18333,14 @@@Grab('info.picocli:picocli-groovy:4.6.2') +
@Grab('info.picocli:picocli-groovy:4.6.3') @GrabExclude('org.codehaus.groovy:groovy-all') // work around GROOVY-7613 ...
37.1. Build too
Gradle-+implementation 'info.picocli:picocli:4.6.2'
implementation 'info.picocli:picocli:4.6.3'
@@ -18374,46 +18350,46 @@Gradle (Kotlin)dependencies { - implementation("info.picocli:picocli:4.6.2") + implementation("info.picocli:picocli:4.6.3") }
37.1. Build too
<dependency> <groupId>info.picocli</groupId> <artifactId>picocli</artifactId> - <version>4.6.2</version> + <version>4.6.3</version> </dependency>
Scala SBT-+libraryDependencies += "info.picocli" % "picocli" % "4.6.2"
libraryDependencies += "info.picocli" % "picocli" % "4.6.3"
Ivy-+<dependency org="info.picocli" name="picocli" rev="4.6.2" />
<dependency org="info.picocli" name="picocli" rev="4.6.3" />
Grape@Grapes( - @Grab(group='info.picocli', module='picocli', version='4.6.2') + @Grab(group='info.picocli', module='picocli', version='4.6.3') )
Leiningen-+[info.picocli/picocli "4.6.2"]
[info.picocli/picocli "4.6.3"]
Buildr-+'info.picocli:picocli:jar:4.6.2'
'info.picocli:picocli:jar:4.6.3'
@@ -18421,7 +18397,7 @@JBang-+//DEPS info.picocli:picocli:4.6.2
//DEPS info.picocli:picocli:4.6.3
37.1. Build too
37.2. Source
@@ -18430,8 +18406,8 @@By using picocli in source form, you can avoid having an external dependency on picocli. -Picocli has only one source file: CommandLine.java. +Picocli has only one source file: CommandLine.java. This facilitates including picocli in your project: simply copy and paste the code of this file into a file called
CommandLine.java
, add it to your project, and enjoy!37.2. Source
@@ -18469,4 +18445,4 @@37.2. Source
handleTocOnResize(); -