summaryrefslogtreecommitdiffstats
path: root/args4j
diff options
context:
space:
mode:
authormikaelpeltier <mikaelpeltier@google.com>2015-03-13 16:55:40 +0100
committermikaelpeltier <mikaelpeltier@google.com>2015-03-13 16:55:40 +0100
commit7c94b56d46601db9ed95143dc6889cdca83399e2 (patch)
tree620d5a914f444c3c30c7c6c14b39d9cf0dc0f170 /args4j
parent8007ff78c3d693f7a17350fae567ae5e6e0f0fb2 (diff)
downloadtoolchain_jack-7c94b56d46601db9ed95143dc6889cdca83399e2.zip
toolchain_jack-7c94b56d46601db9ed95143dc6889cdca83399e2.tar.gz
toolchain_jack-7c94b56d46601db9ed95143dc6889cdca83399e2.tar.bz2
Update arg4j to version 2.0.30
Change-Id: Ia94c584414379011b92c7e1d5f1e143bd1d4dc75
Diffstat (limited to 'args4j')
-rw-r--r--args4j/.classpath12
-rw-r--r--args4j/.project17
-rw-r--r--args4j/.settings/org.eclipse.jdt.core.prefs12
-rw-r--r--args4j/LICENSE19
-rw-r--r--args4j/NOTICE25
-rw-r--r--args4j/README.android6
-rw-r--r--args4j/README.md38
-rw-r--r--args4j/args4j-maven-plugin-example/pom.xml2
-rw-r--r--args4j/args4j-maven-plugin/pom.xml2
-rw-r--r--args4j/args4j-maven-plugin/src/main/java/org/kohsuke/args4j/maven/Args4jUsageMojo.java8
-rw-r--r--args4j/args4j-tools/maven.xml10
-rw-r--r--args4j/args4j-tools/pom.xml11
-rw-r--r--args4j/args4j-tools/project.properties3
-rw-r--r--args4j/args4j-tools/project.xml64
-rw-r--r--args4j/args4j-tools/src/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory1
-rw-r--r--args4j/args4j-tools/src/META-INF/services/javax.annotation.processing.Processor1
-rw-r--r--args4j/args4j-tools/src/org/kohsuke/args4j/apt/AnnotationProcessorFactoryImpl.java154
-rw-r--r--args4j/args4j-tools/src/org/kohsuke/args4j/apt/AnnotationProcessorImpl.java169
-rw-r--r--args4j/args4j-tools/src/org/kohsuke/args4j/apt/Main.java18
-rw-r--r--args4j/args4j-tools/src/org/kohsuke/args4j/apt/TxtWriter.java4
-rw-r--r--args4j/args4j-tools/src/org/kohsuke/args4j/apt/XmlWriter.java4
-rw-r--r--args4j/args4j/examples/SampleMain.java3
-rw-r--r--args4j/args4j/maven.xml23
-rw-r--r--args4j/args4j/pom.xml4
-rw-r--r--args4j/args4j/project.properties1
-rw-r--r--args4j/args4j/project.xml41
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Argument.java9
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/CmdLineException.java34
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/CmdLineParser.java566
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Config.java1
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/ExampleMode.java22
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/IllegalAnnotationError.java4
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Localizable.java32
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/MapSetter.java71
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Messages.java21
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Messages.properties11
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Messages_de.properties (renamed from args4j/args4j/src/org/kohsuke/args4j/Messages_de_DE.properties)9
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Messages_en.properties3
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Messages_ru.properties (renamed from args4j/args4j/src/org/kohsuke/args4j/Messages_ru_RU.properties)0
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/NamedOptionDef.java40
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Option.java102
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/OptionDef.java23
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/OptionHandlerFilter.java60
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/OptionHandlerRegistry.java187
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/ParserProperties.java120
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/Utilities.java28
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/XmlParser.java22
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/package.html85
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/AnnotationImpl.java12
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/ArrayFieldSetter.java103
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/BooleanOptionHandler.java2
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/CharOptionHandler.java5
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/ConfigElement.java3
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/DelimitedOptionHandler.java48
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/EnumOptionHandler.java11
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/ExplicitBooleanOptionHandler.java4
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/FieldSetter.java30
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/FileOptionHandler.java9
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/InetAddressOptionHandler.java36
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/MacAddressOptionHandler.java77
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/MapOptionHandler.java85
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/Messages.java39
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/Messages.properties42
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/Messages_de.properties32
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/Messages_en.properties3
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/MethodSetter.java15
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/MultiFileOptionHandler.java18
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/MultiPathOptionHandler.java18
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/MultiValueFieldSetter.java14
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/OneArgumentOptionHandler.java2
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/OptionHandler.java54
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/OptionImpl.java27
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/Parameters.java8
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/PathOptionHandler.java34
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/PatternOptionHandler.java44
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/RestOfArgumentsHandler.java7
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/Setter.java48
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/Setters.java11
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/StopOptionHandler.java21
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/StringArrayOptionHandler.java79
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/StringOptionHandler.java2
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/SubCommand.java27
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/SubCommandHandler.java166
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/SubCommands.java18
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/URIOptionHandler.java6
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/URLOptionHandler.java6
-rw-r--r--args4j/args4j/src/org/kohsuke/args4j/spi/UuidOptionHandler.java38
-rw-r--r--args4j/args4j/test/ExampleTest.java54
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/Aliased.java2
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/AliasedTest.java3
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/Args4JTestBase.java29
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/ArgumentTest.java21
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/AtOption.java13
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/AtOptionTest.java90
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/CmdLineExceptionTest.java61
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/CustomExceptionTest.java4
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/DependencyOptions.java27
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/DependencyOptionsTest.java104
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanArgumentTest.java2
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanOptionTest.java2
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/ExternalConfiguredTest.java2
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/HelpOption.java12
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/HelpOptionTest.java44
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/HiddenOption.java6
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/HiddenOptionTest.java23
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/KeyValue.java12
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/KeyValueTest.java35
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/LongUsageTest.java20
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/MultivaluedTest.java45
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/OptionHandlerRegistryTest.java68
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/ParserPropertiesUnitTest.java46
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/SimpleString.java2
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/SimpleStringTest.java3
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/StringWithMetavar.java2
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/StringWithMetavarTest.java53
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/SubCommandTest.java50
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/spi/InetAddressOptionHandlerTest.java35
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/spi/MultiPathOptionHandlerTest.java114
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/spi/PathOptionHandlerTest.java51
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/spi/PatternOptionHandlerTest.java50
-rw-r--r--args4j/args4j/test/org/kohsuke/args4j/spi/StringArrayOptionHandlerTest.java75
-rw-r--r--args4j/pom.xml25
-rw-r--r--args4j/project.properties44
-rw-r--r--args4j/project.xml66
-rw-r--r--args4j/release.sh6
-rw-r--r--args4j/src/site/apt/apt.apt4
-rw-r--r--args4j/src/site/apt/implementOptionhandler.apt4
-rw-r--r--args4j/src/site/apt/index.apt14
-rw-r--r--args4j/src/site/apt/sample.apt40
129 files changed, 3549 insertions, 1120 deletions
diff --git a/args4j/.classpath b/args4j/.classpath
new file mode 100644
index 0000000..327c709
--- /dev/null
+++ b/args4j/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="args4j-tools/src"/>
+ <classpathentry kind="src" output="args4j/target/examples" path="args4j/examples"/>
+ <classpathentry kind="src" output="args4j/target/classes" path="args4j/src"/>
+ <classpathentry kind="src" output="args4j/target/test-classes" path="args4j/test"/>
+ <classpathentry kind="lib" path="args4j/lib/ant.jar"/>
+ <classpathentry kind="lib" path="C:/jdk/150_14/lib/tools.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/150_14"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/args4j/.project b/args4j/.project
new file mode 100644
index 0000000..95c7aa3
--- /dev/null
+++ b/args4j/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>args4j</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/args4j/.settings/org.eclipse.jdt.core.prefs b/args4j/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..8923d4d
--- /dev/null
+++ b/args4j/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Wed Jun 18 20:01:43 CEST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/args4j/LICENSE b/args4j/LICENSE
new file mode 100644
index 0000000..c49840b
--- /dev/null
+++ b/args4j/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Kohsuke Kawaguchi and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/args4j/NOTICE b/args4j/NOTICE
deleted file mode 100644
index c5f4684..0000000
--- a/args4j/NOTICE
+++ /dev/null
@@ -1,25 +0,0 @@
-Copyright (c) 2003, Kohsuke Kawaguchi
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-
-
diff --git a/args4j/README.android b/args4j/README.android
index 1184a5c..4a67e5b 100644
--- a/args4j/README.android
+++ b/args4j/README.android
@@ -1,7 +1,7 @@
URL: https://github.com/kohsuke/args4j
-Version: args4j-site-2.0.22
+Version: args4j-site-2.0.30
License: MIT
Description: "Command line option parser"
-Direct link: https://github.com/kohsuke/args4j/tree/args4j-site-2.0.22
-Latest commit 754994797019e326578859f1d12826d72c813d01
+Direct link: https://github.com/kohsuke/args4j/releases/tag/args4j-site-2.0.30
+
diff --git a/args4j/README.md b/args4j/README.md
new file mode 100644
index 0000000..07d5e51
--- /dev/null
+++ b/args4j/README.md
@@ -0,0 +1,38 @@
+args4j
+======
+args4j is a small Java class library that makes it easy to parse command line options/arguments in your CUI
+application. See more info at [http://args4j.kohsuke.org/]
+
+Why should I use it?
+--------------------
+
+See [the quick intro](http://weblogs.java.net/blog/kohsuke/archive/2005/05/parsing_command.html)
+
+- It makes command line parsing very easy by using annotations
+- Generate usage text very easily
+- Generate HTML/XML documentation listing all options
+- Full localization support
+- Designed to parse javac like options, as opposed to GNU-style (where ls -lR is considered to have two options l and
+ R).
+- Licensed under [the MIT license](http://www.opensource.org/licenses/mit-license.php).
+
+How can I use it?
+-----------------
+
+1. Check [the sample](https://github.com/kohsuke/args4j/blob/master/args4j/examples/SampleMain.java). This is how your
+ code will look like.
+2. [Download](http://maven.glassfish.org/content/groups/public/args4j/) the distribution or include the library from
+ sthe Maven Repository at java.net.
+3. Write your code.
+
+More Resources
+--------------
+
+1. [A small tutorial](http://args4j.kohsuke.org/sample.html) for the use of the Starter and Args4J
+2. [javadoc](http://args4j.kohsuke.org/args4j/apidocs/)
+3. [How to generate a documentation for your CLI](http://args4j.kohsuke.org/apt.html)
+4. [Extend args4j to handle other Java types](http://args4j.kohsuke.org/implementOptionhandler.html)
+5. [Kohsuke's Blog: Parsing command line options in JDK 5.0 style]
+ (http://weblogs.java.net/blog/kohsuke/archive/2005/05/parsing_command.html)
+6. [A comparison between Commons CLI and Args4j](http://hikage.developpez.com/java/articles/api/cli-vs-args4j/) in
+ French
diff --git a/args4j/args4j-maven-plugin-example/pom.xml b/args4j/args4j-maven-plugin-example/pom.xml
index d1f8a94..724c6a4 100644
--- a/args4j/args4j-maven-plugin-example/pom.xml
+++ b/args4j/args4j-maven-plugin-example/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>args4j</groupId>
<artifactId>args4j-site</artifactId>
- <version>2.0.22</version>
+ <version>2.0.30</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>args4j-maven-plugin-example</artifactId>
diff --git a/args4j/args4j-maven-plugin/pom.xml b/args4j/args4j-maven-plugin/pom.xml
index 251a190..7678b00 100644
--- a/args4j/args4j-maven-plugin/pom.xml
+++ b/args4j/args4j-maven-plugin/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>args4j</groupId>
<artifactId>args4j-site</artifactId>
- <version>2.0.22</version>
+ <version>2.0.30</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.kohsuke.args4j</groupId>
diff --git a/args4j/args4j-maven-plugin/src/main/java/org/kohsuke/args4j/maven/Args4jUsageMojo.java b/args4j/args4j-maven-plugin/src/main/java/org/kohsuke/args4j/maven/Args4jUsageMojo.java
index b1ba66c..f93ffbd 100644
--- a/args4j/args4j-maven-plugin/src/main/java/org/kohsuke/args4j/maven/Args4jUsageMojo.java
+++ b/args4j/args4j-maven-plugin/src/main/java/org/kohsuke/args4j/maven/Args4jUsageMojo.java
@@ -6,6 +6,7 @@ import org.apache.maven.plugin.MojoFailureException;
import org.kohsuke.args4j.apt.Main;
import java.io.*;
+import java.net.URLDecoder;
import java.util.List;
/**
@@ -15,7 +16,7 @@ public class Args4jUsageMojo extends AbstractMojo {
/**
* Mode. 'TXT' 'XML' or 'HTML'
- * @parameter expression="TXT"
+ * @parameter default-value="TXT"
* @required
*/
private String mode;
@@ -52,7 +53,10 @@ public class Args4jUsageMojo extends AbstractMojo {
throw new MojoExecutionException("Couldn't create the directory " + args4jBuildDir.getAbsolutePath());
}
try {
- jar = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
+ String path = Main.class.getProtectionDomain().getCodeSource().getLocation().getPath();
+ String enc = System.getProperty("file.encoding");
+ path = URLDecoder.decode(path, enc);
+ jar = new File(path);
} catch (Exception e) {
throw new MojoExecutionException("Couldn't find the jar of the arg4s tools");
}
diff --git a/args4j/args4j-tools/maven.xml b/args4j/args4j-tools/maven.xml
deleted file mode 100644
index 27b713f..0000000
--- a/args4j/args4j-tools/maven.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<project xmlns:j="jelly:core" xmlns:u="jelly:util">
-
- <postGoal name="dist:prepare-bin-filesystem">
- <!-- copy additional files into the distribution zip/tgz -->
- <deploy:copy-deps xmlns:deploy="deploy"
- todir="${maven.dist.bin.archive.dir}/${maven.final.name}"
- excludes="ant,tools"
- />
- </postGoal>
-</project>
diff --git a/args4j/args4j-tools/pom.xml b/args4j/args4j-tools/pom.xml
index dd25bf4..2abf867 100644
--- a/args4j/args4j-tools/pom.xml
+++ b/args4j/args4j-tools/pom.xml
@@ -4,13 +4,15 @@
<parent>
<groupId>args4j</groupId>
<artifactId>args4j-site</artifactId>
- <version>2.0.22</version>
+ <version>2.0.30</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>args4j-tools</artifactId>
<name>args4j-tools</name>
<description>development-time tool for generating additional artifacits</description>
+ <packaging>bundle</packaging>
+
<properties>
<mainClass>org.kohsuke.args4j.apt.Main</mainClass>
</properties>
@@ -34,7 +36,7 @@
<archive>
<manifest>
<addClasspath>true</addClasspath>
- <mainClass>${mainClass}}</mainClass>
+ <mainClass>${mainClass}</mainClass>
</manifest>
</archive>
</configuration>
@@ -65,11 +67,6 @@
</build>
<dependencies>
<dependency>
- <groupId>ant</groupId>
- <artifactId>ant</artifactId>
- <version>1.5</version>
- </dependency>
- <dependency>
<groupId>args4j</groupId>
<artifactId>args4j</artifactId>
<version>${project.version}</version>
diff --git a/args4j/args4j-tools/project.properties b/args4j/args4j-tools/project.properties
deleted file mode 100644
index cc15913..0000000
--- a/args4j/args4j-tools/project.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-maven.javanet.release.folder=/dist/tools
-maven.jar.manifest.classpath.add=true
-maven.jar.mainclass=org.kohsuke.args4j.apt.Main
diff --git a/args4j/args4j-tools/project.xml b/args4j/args4j-tools/project.xml
deleted file mode 100644
index 7510961..0000000
--- a/args4j/args4j-tools/project.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project>
- <extend>../project.xml</extend>
-
- <pomVersion>3</pomVersion>
- <name>args4j-tools</name>
- <artifactId>args4j-tools</artifactId>
- <description>development-time tool for generating additional artifacits</description>
- <shortDescription>development-time tool for generating additional artifacits</shortDescription>
-
- <dependencies>
- <dependency>
- <id>ant</id>
- <version>1.5</version>
- </dependency>
- <dependency>
- <id>args4j</id>
- <version>${pom.currentVersion}</version>
- <properties>
- <jar.manifest.classpath>true</jar.manifest.classpath>
- </properties>
- </dependency>
- <dependency>
- <groupId>jdk</groupId>
- <artifactId>tools</artifactId>
- <version>5.0</version>
- <jar>${java.home}/../lib/tools.jar</jar>
- <url>http://java.sun.com/j2se/5.0/download.html</url>
- <properties>
- <comment>Needed to run HttpUnit tests. This is the tools.jar from sun jdk. Jar in not in maven repository
- but is set to JAVA_HOME/../lib/tools.jar in project.properties</comment>
- </properties>
- </dependency>
- <!--dependency>
- <id></id>
- <version></version>
- </dependency-->
- </dependencies>
-
- <build>
- <nagEmailAddress>kk@kohsuke.org</nagEmailAddress>
-
- <sourceDirectory>src</sourceDirectory>
- <unitTestSourceDirectory>test</unitTestSourceDirectory>
-
- <!-- Resources that are packaged up inside the JAR file -->
- <resources>
- <resource>
- <directory>src</directory>
- <includes>
- <include>**/*.properties</include>
- <include>META-INF/services/*</include>
- </includes>
- </resource>
- </resources>
-
- <!-- Unit test classes -->
- <unitTest>
- <includes>
- <include>**/Test*.java</include>
- </includes>
- </unitTest>
- </build>
-</project>
diff --git a/args4j/args4j-tools/src/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory b/args4j/args4j-tools/src/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory
deleted file mode 100644
index 69cf068..0000000
--- a/args4j/args4j-tools/src/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.kohsuke.args4j.apt.AnnotationProcessorFactoryImpl \ No newline at end of file
diff --git a/args4j/args4j-tools/src/META-INF/services/javax.annotation.processing.Processor b/args4j/args4j-tools/src/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..e36bc64
--- /dev/null
+++ b/args4j/args4j-tools/src/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.kohsuke.args4j.apt.AnnotationProcessorImpl
diff --git a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/AnnotationProcessorFactoryImpl.java b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/AnnotationProcessorFactoryImpl.java
deleted file mode 100644
index d7148f8..0000000
--- a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/AnnotationProcessorFactoryImpl.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package org.kohsuke.args4j.apt;
-
-import com.sun.mirror.apt.AnnotationProcessor;
-import com.sun.mirror.apt.AnnotationProcessorEnvironment;
-import com.sun.mirror.apt.AnnotationProcessorFactory;
-import com.sun.mirror.declaration.AnnotationTypeDeclaration;
-import com.sun.mirror.declaration.ClassDeclaration;
-import com.sun.mirror.declaration.Declaration;
-import com.sun.mirror.declaration.FieldDeclaration;
-import com.sun.mirror.declaration.MethodDeclaration;
-import com.sun.mirror.declaration.TypeDeclaration;
-import com.sun.mirror.declaration.MemberDeclaration;
-import com.sun.mirror.type.ClassType;
-import com.sun.mirror.util.SimpleDeclarationVisitor;
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.Option;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.FileInputStream;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.Properties;
-
-/**
- * {@link AnnotationProcessorFactory} to be invoked by APT.
- *
- * This class receives options from the Main method through system properties (ouch!).
- *
- * @author Kohsuke Kawaguchi
- */
-public class AnnotationProcessorFactoryImpl implements AnnotationProcessorFactory {
-
- private File outDir;
- private String format;
- private Properties resource = null;
-
- public AnnotationProcessorFactoryImpl() {
- outDir = new File(System.getProperty("args4j.outdir"));
- format = System.getProperty("args4j.format");
-
- String res = System.getProperty("args4j.resource");
- if(res!=null && res.length()>0) {
- try {
- resource = new Properties();
- resource.load(new FileInputStream(res));
- } catch (IOException e) {
- throw new Error(e);
- }
- }
- }
-
- public Collection<String> supportedOptions() {
- return Collections.emptyList();
- }
-
- public Collection<String> supportedAnnotationTypes() {
- return Arrays.asList(Option.class.getName(),Argument.class.getName());
- }
-
- public AnnotationProcessor getProcessorFor(final Set<AnnotationTypeDeclaration> annotationTypeDeclarations, final AnnotationProcessorEnvironment env) {
- return new AnnotationProcessor() {
- public void process() {
- Collection<Declaration> params = env.getDeclarationsAnnotatedWith((AnnotationTypeDeclaration)env.getTypeDeclaration(Option.class.getName()));
-
- final Set<TypeDeclaration> optionBeans = new HashSet<TypeDeclaration>();
- for (Declaration d : params) {
- d.accept(new SimpleDeclarationVisitor() {
- public void visitFieldDeclaration(FieldDeclaration f) {
- TypeDeclaration dt = f.getDeclaringType();
- optionBeans.add(dt);
- }
-
- public void visitMethodDeclaration(MethodDeclaration m) {
- optionBeans.add(m.getDeclaringType());
- }
- });
- }
-
- for (TypeDeclaration t : optionBeans) {
- // make sure that they are on classes
- if(t instanceof ClassDeclaration) {
- ClassDeclaration cd = (ClassDeclaration)t;
- try {
- AnnotationVisitor writer = createAnnotationVisitor(cd);
- env.getMessager().printNotice("Processing "+cd.getQualifiedName());
- scan(cd, writer);
- } catch (IOException e) {
- env.getMessager().printError(e.getMessage());
- }
- } else {
- env.getMessager().printError(t.getPosition(),
- "args4j annotations need to be placed on a class");
- }
- }
- }
- };
- }
-
- private AnnotationVisitor createAnnotationVisitor(ClassDeclaration cd) throws IOException {
- FileWriter out = new FileWriter(new File(outDir,cd.getQualifiedName()+"."+format.toLowerCase()));
- AnnotationVisitor writer;
- if(format.equals("XML"))
- writer = new XmlWriter(out,cd);
- else if (format.equals("TXT"))
- writer = new TxtWriter(out, cd);
- else
- writer = new HtmlWriter(out);
- return new AnnotationVisitorReorderer(writer);
- }
-
- private void scan(ClassDeclaration decl, AnnotationVisitor visitor) {
- while(decl!=null) {
- for( FieldDeclaration f : decl.getFields() )
- scan(f, visitor);
-
- for (MethodDeclaration m : decl.getMethods())
- scan(m, visitor);
-
- ClassType sc = decl.getSuperclass();
- if(sc==null) break;
-
- decl = sc.getDeclaration();
- }
-
- visitor.done();
- }
-
- private void scan(MemberDeclaration f, AnnotationVisitor visitor) {
- Option o = f.getAnnotation(Option.class);
- if(o==null) return;
-
- String usage = getUsage(o);
- if(isOptionHidden(usage)) return;
-
- visitor.onOption(new OptionWithUsage(o, usage));
- }
-
- private boolean isOptionHidden(String usage) {
- return usage==null || usage.length()==0;
- }
-
- private String getUsage(Option o) {
- if(resource==null)
- return o.usage();
- else
- return resource.getProperty(o.usage());
- }
-
-}
diff --git a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/AnnotationProcessorImpl.java b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/AnnotationProcessorImpl.java
new file mode 100644
index 0000000..e7bedd8
--- /dev/null
+++ b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/AnnotationProcessorImpl.java
@@ -0,0 +1,169 @@
+package org.kohsuke.args4j.apt;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.SimpleElementVisitor6;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+import static javax.tools.Diagnostic.Kind.*;
+
+/**
+ * Annotation {@link Processor} to be invoked by javac.
+ *
+ * This class receives options from the Main method through system properties
+ * (ouch!).
+ *
+ * @author Kohsuke Kawaguchi
+ */
+@SuppressWarnings("Since15")
+public class AnnotationProcessorImpl extends AbstractProcessor {
+
+ private File outDir;
+ private String format;
+ private Properties resource = null;
+ private Types typeUtils;
+ private Messager messenger;
+
+ public AnnotationProcessorImpl() {
+ outDir = new File(System.getProperty("args4j.outdir"));
+ format = System.getProperty("args4j.format");
+
+ String res = System.getProperty("args4j.resource");
+ if(res!=null && res.length()>0) {
+ try {
+ resource = new Properties();
+ resource.load(new FileInputStream(res));
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ }
+ }
+
+ @Override
+ public synchronized void init(ProcessingEnvironment processingEnv) {
+ super.init(processingEnv);
+ typeUtils = processingEnv.getTypeUtils();
+ messenger = processingEnv.getMessager();
+ }
+
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return new HashSet<String>(Arrays.asList(
+ Option.class.getName(),
+ Argument.class.getName()));
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latest();
+ }
+
+ private AnnotationVisitor createAnnotationVisitor(TypeElement te)
+ throws IOException {
+ FileWriter out = new FileWriter(new File(outDir, te.getQualifiedName()
+ + "." + format.toLowerCase()));
+ AnnotationVisitor writer;
+ if(format.equals("XML"))
+ writer = new XmlWriter(out, te);
+ else if (format.equals("TXT"))
+ writer = new TxtWriter(out, te);
+ else
+ writer = new HtmlWriter(out);
+ return new AnnotationVisitorReorderer(writer);
+ }
+
+ private void scan(TypeElement decl, AnnotationVisitor visitor) {
+ while (decl != null) {
+ for (Element f : decl.getEnclosedElements()) {
+ scan(f, visitor);
+ }
+ decl = (TypeElement) typeUtils.asElement(decl.getSuperclass());
+ }
+
+ visitor.done();
+ }
+
+ private void scan(Element f, AnnotationVisitor visitor) {
+ Option o = f.getAnnotation(Option.class);
+ if(o==null) return;
+
+ String usage = getUsage(o);
+ if(isOptionHidden(usage)) return;
+
+ visitor.onOption(new OptionWithUsage(o, usage));
+ }
+
+ private boolean isOptionHidden(String usage) {
+ return usage==null || usage.length()==0;
+ }
+
+ private String getUsage(Option o) {
+ if(resource==null)
+ return o.usage();
+ else
+ return resource.getProperty(o.usage());
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+
+ Set<? extends Element> params = roundEnv.getElementsAnnotatedWith(Option.class);
+
+ final Set<TypeElement> optionBeans = new HashSet<TypeElement>();
+
+ for (Element d : params) {
+
+ d.accept(new SimpleElementVisitor6<Void, Void>() {
+ @Override
+ public Void visitVariable(VariableElement e, Void p) {
+ TypeElement dt = (TypeElement) e.getEnclosingElement();
+ optionBeans.add(dt);
+ return null;
+ }
+
+ public Void visitExecutable(ExecutableElement m, Void p) {
+ optionBeans.add((TypeElement) m.getEnclosingElement());
+ return null;
+ }
+ }, null);
+ }
+
+ for (TypeElement t : optionBeans) {
+ // make sure that they are on classes
+ if (t.getKind().isClass()) {
+ try {
+ AnnotationVisitor writer = createAnnotationVisitor(t);
+ messenger.printMessage(NOTE, "Processing " + t.getQualifiedName());
+ scan(t, writer);
+ } catch (IOException e) {
+ messenger.printMessage(ERROR, e.getMessage());
+ }
+ } else {
+ messenger.printMessage(ERROR, "args4j annotations need to be placed on a class", t);
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/Main.java b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/Main.java
index 3839447..91bd47a 100644
--- a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/Main.java
+++ b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/Main.java
@@ -13,8 +13,12 @@ import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
+
/**
* Entry point that invokes APT.
+ *
* @author Kohsuke Kawaguchi
*/
public class Main {
@@ -61,15 +65,13 @@ public class Main {
if(resourceName==null) resourceName = ""; // can't have null in properties
System.setProperty("args4j.resource",resourceName);
- aptArgs.add(0,"-nocompile");
+ aptArgs.add(0, "-proc:only");
+ aptArgs.add(1, "-processor");
+ aptArgs.add(2, AnnotationProcessorImpl.class.getName());
+
+ JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
- // locate tools.jar
- ClassLoader cl = loadToolsJar();
- Class<?> apt = cl.loadClass("com.sun.tools.apt.Main");
- Method main = getProcessMethod(apt);
- return (Integer)main.invoke(null,new Object[]{
- cl.loadClass("org.kohsuke.args4j.apt.AnnotationProcessorFactoryImpl").newInstance(),
- aptArgs.toArray(new String[0])});
+ return javac.run(System.in, System.out, System.err, aptArgs.toArray(new String[0]));
}
private void printUsage(CmdLineParser parser) {
diff --git a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/TxtWriter.java b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/TxtWriter.java
index fc73b5c..ca98d8b 100644
--- a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/TxtWriter.java
+++ b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/TxtWriter.java
@@ -1,6 +1,6 @@
package org.kohsuke.args4j.apt;
-import com.sun.mirror.declaration.ClassDeclaration;
+import javax.lang.model.element.TypeElement;
import org.kohsuke.args4j.Option;
import java.io.PrintWriter;
@@ -14,7 +14,7 @@ import java.io.Writer;
class TxtWriter implements AnnotationVisitor {
private final PrintWriter out;
- public TxtWriter(Writer out, ClassDeclaration d) {
+ public TxtWriter(Writer out, TypeElement d) {
this.out = new PrintWriter(out);
this.out.println("Usage: " + d.getQualifiedName());
}
diff --git a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/XmlWriter.java b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/XmlWriter.java
index 1fcc5e5..0b20f31 100644
--- a/args4j/args4j-tools/src/org/kohsuke/args4j/apt/XmlWriter.java
+++ b/args4j/args4j-tools/src/org/kohsuke/args4j/apt/XmlWriter.java
@@ -1,6 +1,6 @@
package org.kohsuke.args4j.apt;
-import com.sun.mirror.declaration.ClassDeclaration;
+import javax.lang.model.element.TypeElement;
import java.io.PrintWriter;
import java.io.Writer;
@@ -13,7 +13,7 @@ import java.io.Writer;
class XmlWriter implements AnnotationVisitor {
private final PrintWriter out;
- public XmlWriter(Writer out, ClassDeclaration d) {
+ public XmlWriter(Writer out, TypeElement d) {
this.out = new PrintWriter(out);
this.out.println("<usage class=\'"+d.getQualifiedName()+"\'>");
}
diff --git a/args4j/args4j/examples/SampleMain.java b/args4j/args4j/examples/SampleMain.java
index 7704cbf..2892bbd 100644
--- a/args4j/args4j/examples/SampleMain.java
+++ b/args4j/args4j/examples/SampleMain.java
@@ -28,6 +28,9 @@ public class SampleMain {
@Option(name="-str") // no usage
private String str = "(default value)";
+ @Option(name="-hidden-str2",hidden=true,usage="hidden option")
+ private String hiddenStr2 = "(default value)";
+
@Option(name="-n",usage="repeat <n> times\nusage can have new lines in it and also it can be verrrrrrrrrrrrrrrrrry long")
private int num = -1;
diff --git a/args4j/args4j/maven.xml b/args4j/args4j/maven.xml
deleted file mode 100644
index 462931f..0000000
--- a/args4j/args4j/maven.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<project xmlns:j="jelly:core" xmlns:u="jelly:util">
-
- <postGoal name="dist:prepare-bin-filesystem">
- <!-- copy additional files into the distribution zip/tgz -->
- <copy todir="${maven.dist.bin.archive.dir}/${maven.final.name}/examples">
- <fileset dir="${basedir}/examples"/>
- </copy>
- </postGoal>
-
- <postGoal name="test:compile">
- <echo>compile the examples</echo>
- <mkdir dir="${basedir}/target/examples"/>
- <javac srcdir="${basedir}/examples"
- destdir="${basedir}/target/examples"
- classpath="${basedir}/target/classes">
- </javac>
- <echo>Copy test resources</echo>
- <copy todir="target/test-classes">
- <fileset dir="test" excludes="**/*.java"/>
- </copy>
- </postGoal>
-
-</project> \ No newline at end of file
diff --git a/args4j/args4j/pom.xml b/args4j/args4j/pom.xml
index 6a10c62..83c7747 100644
--- a/args4j/args4j/pom.xml
+++ b/args4j/args4j/pom.xml
@@ -3,11 +3,13 @@
<parent>
<groupId>args4j</groupId>
<artifactId>args4j-site</artifactId>
- <version>2.0.22</version>
+ <version>2.0.30</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>args4j</artifactId>
<name>args4j</name>
+
+ <packaging>bundle</packaging>
<build>
<sourceDirectory>src</sourceDirectory>
diff --git a/args4j/args4j/project.properties b/args4j/args4j/project.properties
deleted file mode 100644
index 6536eea..0000000
--- a/args4j/args4j/project.properties
+++ /dev/null
@@ -1 +0,0 @@
-maven.javanet.release.folder=/dist/runtime
diff --git a/args4j/args4j/project.xml b/args4j/args4j/project.xml
deleted file mode 100644
index ef119ba..0000000
--- a/args4j/args4j/project.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project>
- <extend>../project.xml</extend>
-
- <pomVersion>3</pomVersion>
- <name>args4j</name>
- <artifactId>args4j</artifactId>
-
- <dependencies>
- <!-- needed for the test cases inside this Maven project -->
- <dependency>
- <id>junit</id>
- <version>3.8.1</version>
- </dependency>
- </dependencies>
-
- <build>
- <nagEmailAddress>kk@kohsuke.org</nagEmailAddress>
-
- <sourceDirectory>src</sourceDirectory>
- <unitTestSourceDirectory>test</unitTestSourceDirectory>
-
- <!-- Resources that are packaged up inside the JAR file -->
- <resources>
- <resource>
- <directory>src</directory>
- <includes>
- <include>**/*.properties</include>
- <include>META-INF/services/*</include>
- </includes>
- </resource>
- </resources>
-
- <!-- Unit test classes -->
- <unitTest>
- <includes>
- <include>**/*Test.java</include>
- </includes>
- </unitTest>
- </build>
-</project> \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Argument.java b/args4j/args4j/src/org/kohsuke/args4j/Argument.java
index 12e9175..145d840 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/Argument.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/Argument.java
@@ -39,6 +39,11 @@ public @interface Argument {
boolean required() default false;
/**
+ * See {@link Option#hidden()}.
+ */
+ boolean hidden() default false;
+
+ /**
* See {@link Option#handler()}.
*/
Class<? extends OptionHandler> handler() default OptionHandler.class;
@@ -48,7 +53,7 @@ public @interface Argument {
*
* <p>
* If you define multiple single value properties to bind to arguments,
- * they should have index=0, index=1, index=2, ... and so on.
+ * they should have {@code index=0, index=1, index=2}, ... and so on.
*
* <p>
* Multi value properties bound to arguments must be always the last entry.
@@ -56,7 +61,7 @@ public @interface Argument {
int index() default 0;
/**
- * See {@link Option#multiValued()}.
+ *
*/
boolean multiValued() default false;
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/CmdLineException.java b/args4j/args4j/src/org/kohsuke/args4j/CmdLineException.java
index 7151801..1cfd5f1 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/CmdLineException.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/CmdLineException.java
@@ -1,5 +1,6 @@
package org.kohsuke.args4j;
+import java.util.Locale;
import org.kohsuke.args4j.spi.OptionHandler;
/**
@@ -10,8 +11,14 @@ import org.kohsuke.args4j.spi.OptionHandler;
public class CmdLineException extends Exception {
private static final long serialVersionUID = -8574071211991372980L;
- private CmdLineParser parser;
-
+ private CmdLineParser parser = null;
+
+ /**
+ * The optional localized message.
+ * @see Throwable#getLocalizedMessage()
+ */
+ private String localizedMessage = null;
+
/**
* @deprecated
* Use {@link #CmdLineException(CmdLineParser, String)}
@@ -35,7 +42,17 @@ public class CmdLineException extends Exception {
public CmdLineException(Throwable cause) {
super(cause);
}
-
+
+ public CmdLineException(CmdLineParser parser, Localizable message, String... args) {
+ super(message.formatWithLocale(Locale.ENGLISH, (Object[])args));
+ this.localizedMessage = message.format((Object[])args);
+ this.parser = parser;
+ }
+
+ /**
+ * @deprecated
+ * Use {@link #CmdLineException(org.kohsuke.args4j.CmdLineParser, Localizable, java.lang.String...) }
+ */
public CmdLineException(CmdLineParser parser, String message) {
super(message);
this.parser = parser;
@@ -51,12 +68,21 @@ public class CmdLineException extends Exception {
this.parser = parser;
}
+ @Override
+ public String getLocalizedMessage() {
+ if (localizedMessage != null) {
+ return localizedMessage;
+ } else {
+ return getMessage();
+ }
+ }
+
/**
* Obtains the {@link CmdLineParser} that triggered an exception.
*
* <p>
* Unless you have legacy {@link OptionHandler} that doesn't pass in this information
- * when it throws an exception, this method should always return a non-null value. a
+ * when it throws an exception, this method should always return a non-null value.
*/
public CmdLineParser getParser() {
return parser;
diff --git a/args4j/args4j/src/org/kohsuke/args4j/CmdLineParser.java b/args4j/args4j/src/org/kohsuke/args4j/CmdLineParser.java
index 7829416..2fdb134 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/CmdLineParser.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/CmdLineParser.java
@@ -1,56 +1,37 @@
package org.kohsuke.args4j;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URI;
-import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
-import java.util.TreeMap;
-import java.util.Collection;
-import java.util.logging.Logger;
-
-import org.kohsuke.args4j.spi.BooleanOptionHandler;
-import org.kohsuke.args4j.spi.ByteOptionHandler;
-import org.kohsuke.args4j.spi.CharOptionHandler;
-import org.kohsuke.args4j.spi.DoubleOptionHandler;
-import org.kohsuke.args4j.spi.EnumOptionHandler;
-import org.kohsuke.args4j.spi.FileOptionHandler;
-import org.kohsuke.args4j.spi.FloatOptionHandler;
-import org.kohsuke.args4j.spi.IntOptionHandler;
-import org.kohsuke.args4j.spi.LongOptionHandler;
-import org.kohsuke.args4j.spi.MapOptionHandler;
+
import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.Parameters;
import org.kohsuke.args4j.spi.Setter;
-import org.kohsuke.args4j.spi.ShortOptionHandler;
-import org.kohsuke.args4j.spi.StringOptionHandler;
-import org.kohsuke.args4j.spi.URIOptionHandler;
-import org.kohsuke.args4j.spi.URLOptionHandler;
-
/**
* Command line argument owner.
*
* <p>
- * For a typical usage, see <a href="https://args4j.dev.java.net/source/browse/args4j/args4j/examples/SampleMain.java?view=markup">this example</a>.
+ * For typical usage, see <a href="https://args4j.dev.java.net/source/browse/args4j/args4j/examples/SampleMain.java?view=markup">this example</a>.
*
* @author
* Kohsuke Kawaguchi (kk@kohsuke.org)
*/
public class CmdLineParser {
+
/**
* Discovered {@link OptionHandler}s for options.
*/
@@ -65,11 +46,9 @@ public class CmdLineParser {
private OptionHandler currentOptionHandler = null;
/**
- * The length of a usage line.
- * If the usage message is longer than this value, the parser
- * wraps the line. Defaults to 80.
+ * settings for the parser
*/
- private int usageWidth = 80;
+ private ParserProperties parserProperties;
/**
* Creates a new command line owner that
@@ -78,13 +57,34 @@ public class CmdLineParser {
*
* @param bean
* instance of a class annotated by {@link Option} and {@link Argument}.
- * this object will receive values. If this is null, the processing will
+ * this object will receive values. If this is {@code null}, the processing will
* be skipped, which is useful if you'd like to feed metadata from other sources.
*
* @throws IllegalAnnotationError
* if the option bean class is using args4j annotations incorrectly.
*/
public CmdLineParser(Object bean) {
+ // for display purposes, we like the arguments in argument order, but the options in alphabetical order
+ this(bean, ParserProperties.defaults());
+ }
+
+ /**
+ * Creates a new command line owner that
+ * parses arguments/options and set them into
+ * the given object.
+ *
+ * @param bean
+ * instance of a class annotated by {@link Option} and {@link Argument}.
+ * this object will receive values. If this is {@code null}, the processing will
+ * be skipped, which is useful if you'd like to feed metadata from other sources.
+ *
+ * @param parserProperties various settings for this class
+ *
+ * @throws IllegalAnnotationError
+ * if the option bean class is using args4j annotations incorrectly.
+ */
+ public CmdLineParser(Object bean, ParserProperties parserProperties) {
+ this.parserProperties = parserProperties;
// A 'return' in the constructor just skips the rest of the implementation
// and returns the new object directly.
if (bean==null) return;
@@ -92,22 +92,42 @@ public class CmdLineParser {
// Parse the metadata and create the setters
new ClassParser().parse(bean,this);
- // for display purposes, we like the arguments in argument order, but the options in alphabetical order
- Collections.sort(options, new Comparator<OptionHandler>() {
- public int compare(OptionHandler o1, OptionHandler o2) {
- return o1.option.toString().compareTo(o2.option.toString());
- }
- });
+ if (parserProperties.getOptionSorter()!=null) {
+ Collections.sort(options, parserProperties.getOptionSorter());
+ }
+ }
+
+ public ParserProperties getProperties() {
+ return parserProperties;
+ }
+
+ /** This method is similar to {@code Objects.requireNonNull()}.
+ * But this one is available for JDK 1.6 which is the
+ * current target of args4j.
+ * I didn't want to break compatibility with JDK 1.6.
+ * @param obj the object to check for {@code null} value.
+ * @param name the object name. If {@code obj} is {@code null}, then
+ * an exception is constructed from this name.
+ */
+ private static void checkNonNull(Object obj, String name) {
+ if (obj == null) {
+ throw new NullPointerException(name+" is null");
+ }
}
/**
- * Programmatically defines an argument (instead of reading it from annotations like you normally do.)
+ * Programmatically defines an argument (instead of reading it from annotations as normal).
*
* @param setter the setter for the type
* @param a the Argument
+ * @throws NullPointerException if {@code setter} or {@code a} is {@code null}.
*/
public void addArgument(Setter setter, Argument a) {
- OptionHandler h = createOptionHandler(new OptionDef(a,setter.isMultiValued()),setter);
+ Utilities.checkNonNull(setter, "Setter");
+ Utilities.checkNonNull(a, "Argument");
+
+ OptionHandler h = OptionHandlerRegistry.getRegistry().createOptionHandler(this,
+ new OptionDef(a,setter.isMultiValued()),setter);
int index = a.index();
// make sure the argument will fit in the list
while (index >= arguments.size()) {
@@ -116,28 +136,46 @@ public class CmdLineParser {
if(arguments.get(index)!=null) {
throw new IllegalAnnotationError(Messages.MULTIPLE_USE_OF_ARGUMENT.format(index));
}
- arguments.set(index,h);
+ arguments.set(index, h);
}
/**
- * Programmatically defines an option (instead of reading it from annotations like you normally do.)
+ * Programmatically defines an option (instead of reading it from annotations as normal).
*
* @param setter the setter for the type
- * @param o the Option
+ * @param o the {@code Option}
+ * @throws NullPointerException if {@code setter} or {@code o} is {@code null}.
+ * @throws IllegalAnnotationError if the option name or one of the aliases is already taken.
*/
public void addOption(Setter setter, Option o) {
+ checkNonNull(setter, "Setter");
+ checkNonNull(o, "Option");
+
checkOptionNotInMap(o.name());
for (String alias : o.aliases()) {
checkOptionNotInMap(alias);
}
- options.add(createOptionHandler(new NamedOptionDef(o, setter.isMultiValued()), setter));
+ options.add(OptionHandlerRegistry.getRegistry().createOptionHandler(
+ this, new NamedOptionDef(o), setter));
}
-
+
+ /**
+ * Lists up all the defined arguments in the order.
+ */
public List<OptionHandler> getArguments() {
return arguments;
}
+ /**
+ * Lists up all the defined options.
+ */
+ public List<OptionHandler> getOptions() {
+ return options;
+ }
+
private void checkOptionNotInMap(String name) throws IllegalAnnotationError {
+ checkNonNull(name, "name");
+
if(findOptionByName(name)!=null) {
throw new IllegalAnnotationError(Messages.MULTIPLE_USE_OF_OPTION.format(name));
}
@@ -146,96 +184,89 @@ public class CmdLineParser {
/**
* Creates an {@link OptionHandler} that handles the given {@link Option} annotation
* and the {@link Setter} instance.
+ * @deprecated You should use {@link OptionHandlerRegistry#createOptionHandler(org.kohsuke.args4j.CmdLineParser, org.kohsuke.args4j.OptionDef, org.kohsuke.args4j.spi.Setter) } instead.
*/
- @SuppressWarnings("unchecked")
protected OptionHandler createOptionHandler(OptionDef o, Setter setter) {
-
- Constructor<? extends OptionHandler> handlerType;
- Class<? extends OptionHandler> h = o.handler();
-
- if(h==OptionHandler.class) {
- // infer the type
-
- // enum is the special case
- Class t = setter.getType();
- if(Enum.class.isAssignableFrom(t))
- return new EnumOptionHandler(this,o,setter,t);
-
- handlerType = handlerClasses.get(t);
- if(handlerType==null)
- throw new IllegalAnnotationError(Messages.UNKNOWN_HANDLER.format(t));
- } else {
- handlerType = getConstructor(h);
- }
-
- try {
- return handlerType.newInstance(this,o,setter);
- } catch (InstantiationException e) {
- throw new IllegalAnnotationError(e);
- } catch (IllegalAccessException e) {
- throw new IllegalAnnotationError(e);
- } catch (InvocationTargetException e) {
- throw new IllegalAnnotationError(e);
- }
+ checkNonNull(o, "OptionDef");
+ checkNonNull(setter, "Setter");
+ return OptionHandlerRegistry.getRegistry().createOptionHandler(this, o, setter);
}
/**
* Formats a command line example into a string.
*
- * See {@link #printExample(ExampleMode, ResourceBundle)} for more details.
+ * See {@link #printExample(OptionHandlerFilter, ResourceBundle)} for more details.
*
- * @param mode
- * must not be null.
+ * @param filter
+ * must not be {@code null}.
* @return
- * always non-null.
+ * always non-{@code null}.
+ */
+ public String printExample(OptionHandlerFilter filter) {
+ return printExample(filter,null);
+ }
+
+ /**
+ * @deprecated
+ * Use {@link #printExample(OptionHandlerFilter)}
*/
public String printExample(ExampleMode mode) {
- return printExample(mode,null);
+ return printExample(mode, null);
}
/**
* Formats a command line example into a string.
*
* <p>
- * This method produces a string like " -d &lt;dir> -v -b",
- * which is useful for printing a command line example, perhaps
- * as a part of the usage screen.
+ * This method produces a string like <code> -d &lt;dir&gt; -v -b</code>.
+ * This is useful for printing a command line example (perhaps
+ * as a part of the usage screen).
*
*
* @param mode
- * One of the {@link ExampleMode} constants. Must not be null.
- * This determines what option should be a part of the returned string.
+ * Determines which options will be a part of the returned string.
+ * Must not be {@code null}.
* @param rb
- * If non-null, meta variables (&lt;dir> in the above example)
+ * If non-{@code null}, meta variables (<code>&lt;dir&gt;</code> in the above example)
* is treated as a key to this resource bundle, and the associated
* value is printed. See {@link Option#metaVar()}. This is to support
* localization.
*
- * Passing <tt>null</tt> would print {@link Option#metaVar()} directly.
+ * Passing {@code null} would print {@link Option#metaVar()} directly.
* @return
- * always non-null. If there's no option, this method returns
- * just the empty string "". Otherwise, this method returns a
- * string that contains a space at the beginning (but not at the end.)
+ * always non-{@code null}. If there's no option, this method returns
+ * just the empty string {@code ""}. Otherwise, this method returns a
+ * string that contains a space at the beginning (but not at the end).
* This allows you to do something like:
- *
- * <pre>System.err.println("java -jar my.jar"+parser.printExample(REQUIRED)+" arg1 arg2");</pre>
+ * <code>System.err.println("java -jar my.jar"+parser.printExample(REQUIRED)+" arg1 arg2");</code>
+ * @throws NullPointerException if {@code mode} is {@code null}.
*/
- public String printExample(ExampleMode mode,ResourceBundle rb) {
+ public String printExample(OptionHandlerFilter mode, ResourceBundle rb) {
StringBuilder buf = new StringBuilder();
+ Utilities.checkNonNull(mode, "mode");
+
for (OptionHandler h : options) {
OptionDef option = h.option;
if(option.usage().length()==0) continue; // ignore
- if(!mode.print(option)) continue;
+ if(!mode.select(h)) continue;
buf.append(' ');
- buf.append(h.getNameAndMeta(rb));
+ buf.append(h.getNameAndMeta(rb, parserProperties));
}
return buf.toString();
}
/**
+ * @deprecated
+ * Use {@link #printExample(OptionHandlerFilter,ResourceBundle)}
+ */
+ public String printExample(ExampleMode mode, ResourceBundle rb) {
+ return printExample((OptionHandlerFilter) mode, rb);
+ }
+
+ /**
* Prints the list of options and their usages to the screen.
*
* <p>
@@ -247,13 +278,25 @@ public class CmdLineParser {
}
/**
- * Prints the list of options and their usages to the screen.
+ * Prints the list of all the non-hidden options and their usages to the screen.
+ *
+ * <p>
+ * Short for {@code printUsage(out,rb,OptionHandlerFilter.PUBLIC)}
+ */
+ public void printUsage(Writer out, ResourceBundle rb) {
+ printUsage(out, rb, OptionHandlerFilter.PUBLIC);
+ }
+
+ /**
+ * Prints the list of all the non-hidden options and their usages to the screen.
*
* @param rb
- * if this is non-null, {@link Option#usage()} is treated
+ * If non-{@code null}, {@link Option#usage()} is treated
* as a key to obtain the actual message from this resource bundle.
+ * @param filter
+ * Controls which options to be printed.
*/
- public void printUsage(Writer out, ResourceBundle rb) {
+ public void printUsage(Writer out, ResourceBundle rb, OptionHandlerFilter filter) {
PrintWriter w = new PrintWriter(out);
// determine the length of the option + metavar first
int len = 0;
@@ -268,41 +311,50 @@ public class CmdLineParser {
// then print
for (OptionHandler h : arguments) {
- printOption(w, h, len, rb);
+ printOption(w, h, len, rb, filter);
}
for (OptionHandler h : options) {
- printOption(w, h, len, rb);
+ printOption(w, h, len, rb, filter);
}
w.flush();
}
/**
- * Prints the usage information for a given option.
+ * Prints usage information for a given option.
+ *
+ * <p>
+ * Subtypes may override this method and determine which options get printed (or other things),
+ * based on {@link OptionHandler} (perhaps by using {@code handler.setter.asAnnotatedElement()}).
+ *
* @param out Writer to write into
- * @param handler handler where to receive the informations
+ * @param handler handler where to receive the information
* @param len Maximum length of metadata column
- * @param rb ResourceBundle for I18N
+ * @param rb {@code ResourceBundle} for I18N
+ * @see Setter#asAnnotatedElement()
*/
- private void printOption(PrintWriter out, OptionHandler handler, int len, ResourceBundle rb) {
+ protected void printOption(PrintWriter out, OptionHandler handler, int len, ResourceBundle rb, OptionHandlerFilter filter) {
// Hiding options without usage information
- if (handler.option.usage() == null || handler.option.usage().length() == 0) {
+ if (handler.option.usage() == null ||
+ handler.option.usage().length() == 0 ||
+ !filter.select(handler)) {
return;
}
// What is the width of the two data columns
- int widthMetadata = Math.min(len, (usageWidth - 4) / 2);
- int widthUsage = usageWidth - 4 - widthMetadata;
+ int totalUsageWidth = parserProperties.getUsageWidth();
+ int widthMetadata = Math.min(len, (totalUsageWidth - 4) / 2);
+ int widthUsage = totalUsageWidth - 4 - widthMetadata;
// Line wrapping
- List<String> namesAndMetas = wrapLines(handler.getNameAndMeta(rb), widthMetadata);
+ List<String> namesAndMetas = wrapLines(handler.getNameAndMeta(rb, parserProperties), widthMetadata);
List<String> usages = wrapLines(localize(handler.option.usage(),rb), widthUsage);
// Output
for(int i=0; i<Math.max(namesAndMetas.size(), usages.size()); i++) {
String nameAndMeta = (i >= namesAndMetas.size()) ? "" : namesAndMetas.get(i);
String usage = (i >= usages.size()) ? "" : usages.get(i);
- String format = (nameAndMeta.length() > 0)
+ String format = ((nameAndMeta.length() > 0) && (i == 0))
? " %1$-" + widthMetadata + "s : %2$-1s"
: " %1$-" + widthMetadata + "s %2$-1s";
String output = String.format(format, nameAndMeta, usage);
@@ -317,6 +369,7 @@ public class CmdLineParser {
/**
* Wraps a line so that the resulting parts are not longer than a given maximum length.
+ *
* @param line Line to wrap
* @param maxLength maximum length for the resulting parts
* @return list of all wrapped parts
@@ -329,7 +382,7 @@ public class CmdLineParser {
int lineLength;
String candidate = restOfLine.substring(0, maxLength);
int sp=candidate.lastIndexOf(' ');
- if(sp>maxLength*3/4) lineLength=sp;
+ if(sp>maxLength*3/5) lineLength=sp;
else lineLength=maxLength;
rv.add(restOfLine.substring(0, lineLength));
restOfLine = restOfLine.substring(lineLength).trim();
@@ -343,12 +396,12 @@ public class CmdLineParser {
if(h.option.usage().length()==0)
return 0;
- return h.getNameAndMeta(rb).length();
+ return h.getNameAndMeta(rb, parserProperties).length();
}
/**
* Essentially a pointer over a {@link String} array.
- * Can move forward, can look ahead.
+ * Can move forward; can look ahead.
*/
private class CmdLineImpl implements Parameters {
private final String[] args;
@@ -372,14 +425,27 @@ public class CmdLineParser {
}
public String getParameter(int idx) throws CmdLineException {
- if( pos+idx>=args.length )
- throw new CmdLineException(CmdLineParser.this, Messages.MISSING_OPERAND.format(getOptionName()));
+ if( pos+idx>=args.length || pos+idx<0 )
+ throw new CmdLineException(CmdLineParser.this, Messages.MISSING_OPERAND, getOptionName());
return args[pos+idx];
}
public int size() {
return args.length-pos;
}
+
+ /**
+ * Used when the current token is of the form "-option=value",
+ * to replace the current token by "value", as if this was given as two tokens "-option value"
+ */
+ void splitToken() {
+ if (pos < args.length && pos >= 0) {
+ int idx = args[pos].indexOf("=");
+ if (idx > 0) {
+ args[pos] = args[pos].substring(idx + 1);
+ }
+ }
+ }
}
private String getOptionName() {
@@ -387,7 +453,7 @@ public class CmdLineParser {
}
/**
- * Same as {@link #parseArgument(String[])}
+ * Same as {@link #parseArgument(String[])}
*/
public void parseArgument(Collection<String> args) throws CmdLineException {
parseArgument(args.toArray(new String[args.size()]));
@@ -402,9 +468,17 @@ public class CmdLineParser {
* @throws CmdLineException
* if there's any error parsing arguments, or if
* {@link Option#required() required} option was not given.
+ * @throws NullPointerException if {@code args} is {@code null}.
*/
public void parseArgument(final String... args) throws CmdLineException {
- CmdLineImpl cmdLine = new CmdLineImpl(args);
+
+ Utilities.checkNonNull(args, "args");
+
+ String expandedArgs[] = args;
+ if (parserProperties.getAtSyntax()) {
+ expandedArgs = expandAtFiles(args);
+ }
+ CmdLineImpl cmdLine = new CmdLineImpl(expandedArgs);
Set<OptionHandler> present = new HashSet<OptionHandler>();
int argIndex = 0;
@@ -412,25 +486,34 @@ public class CmdLineParser {
while( cmdLine.hasMore() ) {
String arg = cmdLine.getCurrentToken();
if( isOption(arg) ) {
- boolean isKeyValuePair = arg.indexOf('=')!=-1;
+ // '=' is for historical compatibility fallback
+ boolean isKeyValuePair = arg.contains(parserProperties.getOptionValueDelimiter()) || arg.indexOf('=')!=-1;
+
// parse this as an option.
currentOptionHandler = isKeyValuePair ? findOptionHandler(arg) : findOptionByName(arg);
if(currentOptionHandler==null) {
// TODO: insert dynamic handler processing
- throw new CmdLineException(this, Messages.UNDEFINED_OPTION.format(arg));
+ throw new CmdLineException(this, Messages.UNDEFINED_OPTION, arg);
}
// known option; skip its name
- cmdLine.proceed(1);
+ if (isKeyValuePair) {
+ cmdLine.splitToken();
+ } else {
+ cmdLine.proceed(1);
+ }
} else {
if (argIndex >= arguments.size()) {
Messages msg = arguments.size() == 0 ? Messages.NO_ARGUMENT_ALLOWED : Messages.TOO_MANY_ARGUMENTS;
- throw new CmdLineException(this, msg.format(arg));
+ throw new CmdLineException(this, msg, arg);
}
// known argument
currentOptionHandler = arguments.get(argIndex);
+ if (currentOptionHandler==null) // this is a programmer error. arg index should be continuous
+ throw new IllegalStateException("@Argument with index="+argIndex+" is undefined");
+
if (!currentOptionHandler.option.isMultiValued())
argIndex++;
}
@@ -439,36 +522,135 @@ public class CmdLineParser {
present.add(currentOptionHandler);
}
+ // check whether a help option is set
+ boolean helpSet = false;
+ for (OptionHandler handler : options) {
+ if(handler.option.help() && present.contains(handler)) {
+ helpSet = true;
+ }
+ }
+
+ if (!helpSet) {
+ checkRequiredOptionsAndArguments(present);
+ }
+ }
+
+ /**
+ * Expands every entry prefixed with the AT sign by
+ * reading the file. The AT sign is used to reference
+ * another file that contains command line options separated
+ * by line breaks.
+ * @param args the command line arguments to be preprocessed.
+ * @return args with the @ sequences replaced by the text files referenced
+ * by the @ sequences, split around the line breaks.
+ * @throws CmdLineException
+ */
+ private String[] expandAtFiles(String args[]) throws CmdLineException {
+ List<String> result = new ArrayList<String>();
+ for (String arg : args) {
+ if (arg.startsWith("@")) {
+ File file = new File(arg.substring(1));
+ if (!file.exists())
+ throw new CmdLineException(this,Messages.NO_SUCH_FILE,file.getPath());
+ try {
+ result.addAll(readAllLines(file));
+ } catch (IOException ex) {
+ throw new CmdLineException(this, "Failed to parse "+file,ex);
+ }
+ } else {
+ result.add(arg);
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ /**
+ * Reads all lines of a file with the platform encoding.
+ */
+ private static List<String> readAllLines(File f) throws IOException {
+ BufferedReader r = new BufferedReader(new FileReader(f));
+ try {
+ List<String> result = new ArrayList<String>();
+ String line;
+ while ((line = r.readLine()) != null) {
+ result.add(line);
+ }
+ return result;
+ } finally {
+ r.close();
+ }
+ }
+
+ private void checkRequiredOptionsAndArguments(Set<OptionHandler> present) throws CmdLineException {
// make sure that all mandatory options are present
- for (OptionHandler handler : options)
- if(handler.option.required() && !present.contains(handler))
- throw new CmdLineException(this, Messages.REQUIRED_OPTION_MISSING.format(handler.option.toString()));
+ for (OptionHandler handler : options) {
+ if(handler.option.required() && !present.contains(handler)) {
+ throw new CmdLineException(this, Messages.REQUIRED_OPTION_MISSING, handler.option.toString());
+ }
+ }
// make sure that all mandatory arguments are present
- for (OptionHandler handler : arguments)
- if(handler.option.required() && !present.contains(handler))
- throw new CmdLineException(this, Messages.REQUIRED_ARGUMENT_MISSING.format(handler.option.toString()));
+ for (OptionHandler handler : arguments) {
+ if(handler.option.required() && !present.contains(handler)) {
+ throw new CmdLineException(this, Messages.REQUIRED_ARGUMENT_MISSING, handler.option.toString());
+ }
+ }
+
+ //make sure that all requires arguments are present
+ for (OptionHandler handler : present) {
+ if (handler.option instanceof NamedOptionDef && !isHandlerHasHisOptions((NamedOptionDef)handler.option, present)) {
+ throw new CmdLineException(this, Messages.REQUIRES_OPTION_MISSING,
+ handler.option.toString(), Arrays.toString(((NamedOptionDef)handler.option).depends()));
+ }
+ }
+
+ //make sure that all forbids arguments are not present
+ for (OptionHandler handler : present) {
+ if (handler.option instanceof NamedOptionDef && !isHandlerAllowOtherOptions((NamedOptionDef) handler.option, present)) {
+ throw new CmdLineException(this, Messages.FORBIDDEN_OPTION_PRESENT,
+ handler.option.toString(), Arrays.toString(((NamedOptionDef) handler.option).forbids()));
+ }
+ }
}
- private OptionHandler findOptionHandler(String name) {
- OptionHandler handler = findOptionByName(name);
- if (handler==null) {
- // Have not found by its name, maybe its a property?
- // Search for parts of the name (=prefix) - most specific first
- for (int i=name.length(); i>1; i--) {
- String prefix = name.substring(0, i);
- Map<String,OptionHandler> possibleHandlers = filter(options, prefix);
- handler = possibleHandlers.get(prefix);
- if (handler!=null) return handler;
- }
- }
- return handler;
- }
+ /**
+ * @return {@code true} if all options required by {@code option} are present, {@code false} otherwise
+ */
+ private boolean isHandlerHasHisOptions(NamedOptionDef option, Set<OptionHandler> present) {
+ for (String depend : option.depends()) {
+ if (!present.contains(findOptionHandler(depend)))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return {@code true} if all options forbid by {@code option} are not present, {@code false} otherwise
+ */
+ private boolean isHandlerAllowOtherOptions(NamedOptionDef option, Set<OptionHandler> present) {
+ for (String forbid : option.forbids()) {
+ if (present.contains(findOptionHandler(forbid)))
+ return false;
+ }
+ return true;
+ }
+
+ private OptionHandler findOptionHandler(String name) {
+ // Look for key/value pair first.
+ int pos = name.indexOf(parserProperties.getOptionValueDelimiter());
+ if (pos < 0) {
+ pos = name.indexOf('='); // historical compatibility fallback
+ }
+ if (pos > 0) {
+ name = name.substring(0, pos);
+ }
+ return findOptionByName(name);
+ }
/**
- * Finds a registered OptionHandler by its name or its alias.
+ * Finds a registered {@code OptionHandler} by its name or its alias.
* @param name name
- * @return the OptionHandler or <tt>null</tt>
+ * @return the {@code OptionHandler} or {@code null}
*/
private OptionHandler findOptionByName(String name) {
for (OptionHandler h : options) {
@@ -485,33 +667,17 @@ public class CmdLineParser {
return null;
}
-
- private Map<String,OptionHandler> filter(List<OptionHandler> opt, String keyFilter) {
- Map<String,OptionHandler> rv = new TreeMap<String,OptionHandler>();
- for (OptionHandler h : opt) {
- if (opt.toString().startsWith(keyFilter)) rv.put(opt.toString(), h);
- }
- return rv;
- }
-
-
/**
- * Returns true if the given token is an option
- * (as opposed to an argument.)
+ * Returns {@code true} if the given token is an option
+ * (as opposed to an argument).
+ * @throws NullPointerException if {@code arg} is {@code null}.
*/
protected boolean isOption(String arg) {
+ Utilities.checkNonNull(arg, "arg");
+
return parsingOptions && arg.startsWith("-");
}
-
- /**
- * All {@link OptionHandler}s known to the {@link CmdLineParser}.
- *
- * Constructors of {@link OptionHandler}-derived class keyed by their supported types.
- */
- private static final Map<Class,Constructor<? extends OptionHandler>> handlerClasses =
- Collections.synchronizedMap(new HashMap<Class,Constructor<? extends OptionHandler>>());
-
/**
* Registers a user-defined {@link OptionHandler} class with args4j.
*
@@ -525,54 +691,35 @@ public class CmdLineParser {
* @param handlerClass
* This class must have the constructor that has the same signature as
* {@link OptionHandler#OptionHandler(CmdLineParser, OptionDef, Setter)}
+ * @throws NullPointerException if {@code valueType} or {@code handlerClass} is {@code null}.
+ * @throws IllegalArgumentException if {@code handlerClass} is not a subtype of {@code OptionHandler}.
+ * @deprecated You should use {@link OptionHandlerRegistry#registerHandler(java.lang.Class, java.lang.Class)} instead.
*/
public static void registerHandler( Class valueType, Class<? extends OptionHandler> handlerClass ) {
- if(valueType==null || handlerClass==null)
- throw new IllegalArgumentException();
- if(!OptionHandler.class.isAssignableFrom(handlerClass))
- throw new IllegalArgumentException(Messages.NO_OPTIONHANDLER.format());
-
- Constructor<? extends OptionHandler> c = getConstructor(handlerClass);
- handlerClasses.put(valueType,c);
- }
-
- private static Constructor<? extends OptionHandler> getConstructor(Class<? extends OptionHandler> handlerClass) {
- try {
- return handlerClass.getConstructor(CmdLineParser.class, OptionDef.class, Setter.class);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException(Messages.NO_CONSTRUCTOR_ON_HANDLER.format(handlerClass));
- }
- }
+ checkNonNull(valueType, "valueType");
+ checkNonNull(handlerClass, "handlerClass");
- static {
- registerHandler(Boolean.class,BooleanOptionHandler.class);
- registerHandler(boolean.class,BooleanOptionHandler.class);
- registerHandler(File.class,FileOptionHandler.class);
- registerHandler(URL.class, URLOptionHandler.class);
- registerHandler(URI.class, URIOptionHandler.class);
- registerHandler(Integer.class,IntOptionHandler.class);
- registerHandler(int.class,IntOptionHandler.class);
- registerHandler(Double.class, DoubleOptionHandler.class);
- registerHandler(double.class,DoubleOptionHandler.class);
- registerHandler(String.class,StringOptionHandler.class);
- registerHandler(Byte.class, ByteOptionHandler.class);
- registerHandler(byte.class, ByteOptionHandler.class);
- registerHandler(Character.class, CharOptionHandler.class);
- registerHandler(char.class, CharOptionHandler.class);
- registerHandler(Float.class, FloatOptionHandler.class);
- registerHandler(float.class, FloatOptionHandler.class);
- registerHandler(Long.class, LongOptionHandler.class);
- registerHandler(long.class, LongOptionHandler.class);
- registerHandler(Short.class, ShortOptionHandler.class);
- registerHandler(short.class, ShortOptionHandler.class);
- // enum is a special case
- registerHandler(Map.class,MapOptionHandler.class);
+ OptionHandlerRegistry.getRegistry().registerHandler(valueType, handlerClass);
}
+ /**
+ * Sets the width of the usage output.
+ * @param usageWidth the width of the usage output in columns.
+ * @throws IllegalArgumentException if {@code usageWidth} is negative
+ * @deprecated
+ * Use {@link ParserProperties#withUsageWidth(int)} instead.
+ */
public void setUsageWidth(int usageWidth) {
- this.usageWidth = usageWidth;
+ parserProperties.withUsageWidth(usageWidth);
}
+ /**
+ * Signals the parser that parsing the options has finished.
+ *
+ * <p>
+ * Everything seen after this call is treated as an argument
+ * as opposed to an option.
+ */
public void stopOptionParsing() {
parsingOptions = false;
}
@@ -583,19 +730,26 @@ public class CmdLineParser {
* <p>
* This is a convenience method for calling {@code printUsage(new OutputStreamWriter(out),null)}
* so that you can do {@code printUsage(System.err)}.
+ * @throws NullPointerException if {@code out} is {@code null}.
*/
public void printSingleLineUsage(OutputStream out) {
- printSingleLineUsage(new OutputStreamWriter(out),null);
+ checkNonNull(out, "OutputStream");
+
+ printSingleLineUsage(new OutputStreamWriter(out), null);
}
/**
* Prints a single-line usage to the screen.
*
* @param rb
- * if this is non-null, {@link Option#usage()} is treated
+ * if this is non-{@code null}, {@link Option#usage()} is treated
* as a key to obtain the actual message from this resource bundle.
+ * @throws NullPointerException if {@code w} is {@code null}.
*/
+ // TODO test this!
public void printSingleLineUsage(Writer w, ResourceBundle rb) {
+ Utilities.checkNonNull(w, "Writer");
+
PrintWriter pw = new PrintWriter(w);
for (OptionHandler h : arguments) {
printSingleLineOption(pw, h, rb);
@@ -610,13 +764,11 @@ public class CmdLineParser {
pw.print(' ');
if (!h.option.required())
pw.print('[');
- pw.print(h.getNameAndMeta(rb));
+ pw.print(h.getNameAndMeta(rb, parserProperties));
if (h.option.isMultiValued()) {
pw.print(" ...");
}
if (!h.option.required())
pw.print(']');
}
-
- private static final Logger LOGGER = Logger.getLogger(CmdLineParser.class.getName());
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Config.java b/args4j/args4j/src/org/kohsuke/args4j/Config.java
index 005f3d6..88402a2 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/Config.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/Config.java
@@ -1,7 +1,6 @@
package org.kohsuke.args4j;
import java.io.IOException;
-import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
diff --git a/args4j/args4j/src/org/kohsuke/args4j/ExampleMode.java b/args4j/args4j/src/org/kohsuke/args4j/ExampleMode.java
index c3a4b18..3f2edb5 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/ExampleMode.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/ExampleMode.java
@@ -1,33 +1,33 @@
package org.kohsuke.args4j;
+import org.kohsuke.args4j.spi.OptionHandler;
+
/**
* Used with {@link CmdLineParser#printExample(ExampleMode)}.
*
* @author Kohsuke Kawaguchi
+ *
+ * @deprecated use {@link OptionHandlerFilter}
*/
-public enum ExampleMode {
+public enum ExampleMode implements OptionHandlerFilter {
/**
* Print all defined options in the example.
*
* <p>
- * This would be useful only when you have small number of options.
+ * This would only be useful with small numbers of options.
*/
ALL() {
- @Override
- /*package*/ boolean print(OptionDef o) {
+ public boolean select(OptionHandler o) {
return true;
}
},
/**
- * Print all {@link Option#required() required} option.
+ * Print all {@linkplain Option#required() required} option.
*/
REQUIRED() {
- @Override
- /*package*/ boolean print(OptionDef o) {
- return o.required();
+ public boolean select(OptionHandler o) {
+ return o.option.required();
}
- };
-
- /*package*/ abstract boolean print(OptionDef o);
+ }
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/IllegalAnnotationError.java b/args4j/args4j/src/org/kohsuke/args4j/IllegalAnnotationError.java
index d7fab10..80cd937 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/IllegalAnnotationError.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/IllegalAnnotationError.java
@@ -5,8 +5,8 @@ package org.kohsuke.args4j;
*
* <p>
* This only happens when there's something wrong with the way you use
- * args4j in your code, not when the arguments supplied by the user is
- * wrong. Hence this class is an {@link Error}.
+ * args4j in your code--<em>not</em> when the user's arguments are wrong.
+ * Therefore, this class is an {@link Error}.
*
* @author Kohsuke Kawaguchi
*/
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Localizable.java b/args4j/args4j/src/org/kohsuke/args4j/Localizable.java
new file mode 100644
index 0000000..bb50fd9
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/Localizable.java
@@ -0,0 +1,32 @@
+package org.kohsuke.args4j;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+
+/**
+ * A message that can be formatted with arguments and locale.
+ * <p>
+ * The message is implicitly given by {@code this} object and can
+ * contain formatting similar to the {@link MessageFormat} class.
+ *
+ * @see Messages
+ * @see org.kohsuke.args4j.spi.Messages
+ * @author Stephan Fuhrmann
+ */
+public interface Localizable {
+
+ /**
+ * Format the implicitly given message by {@code this} object with the given locale.
+ * @param locale the locale to use for formatting .
+ * @param args the arguments to use for formatting. See {@link MessageFormat#format(java.lang.String, java.lang.Object...)}.
+ * @return the formatted string.
+ */
+ public String formatWithLocale( Locale locale, Object... args );
+
+ /**
+ * Format the implicitly given message by {@code this} object with the default locale.
+ * @param args the arguments to use for formatting. See {@link MessageFormat#format(java.lang.String, java.lang.Object...)}.
+ * @return the formatted string.
+ */
+ public String format( Object... args );
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/MapSetter.java b/args4j/args4j/src/org/kohsuke/args4j/MapSetter.java
deleted file mode 100644
index d465d73..0000000
--- a/args4j/args4j/src/org/kohsuke/args4j/MapSetter.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.kohsuke.args4j;
-
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.kohsuke.args4j.spi.Setter;
-
-/**
- * This setter adds a new entry to a Map.
- * The value which is passed is split into the Map-key and Map-value by a "=".
- * <p>
- * <tt>-map key=value</tt></p>
- */
-public class MapSetter implements Setter {
- private final Field f;
- private final Object bean;
-
-
- public MapSetter(Object bean, Field f) {
- super();
- this.f = f;
- this.bean = bean;
- }
-
- public Class getType() {
- return f.getType();
- }
-
- public boolean isMultiValued() {
- return false;
- }
-
- public void addValue(Object value) {
- if (String.valueOf(value).indexOf('=') == -1) {
- throw new RuntimeException(Messages.FORMAT_ERROR_FOR_MAP.format());
- }
-
- String[] parts = String.valueOf(value).split("=");
- String mapKey = parts[0];
- String mapValue = (parts.length > 1) ? parts[1] : null;
-
- if (mapKey == null || mapKey.length()==0) {
- throw new RuntimeException(Messages.MAP_HAS_NO_KEY.format());
- }
-
- try {
- addValue(mapKey, mapValue);
- } catch (IllegalAccessException _) {
- // try again
- f.setAccessible(true);
- try {
- addValue(mapKey, mapValue);
- } catch (IllegalAccessException e) {
- throw new IllegalAccessError(e.getMessage());
- }
- }
- }
-
- private void addValue(Object key, Object value) throws IllegalArgumentException, IllegalAccessException {
- Map map = (Map) f.get(bean);
- if (map == null) {
- // Field is null so set it to an empty Map
- map = new HashMap();
- // and reset the field on the bean not just the local reference
- f.set(bean, map);
- }
- map.put(key, value);
- }
-
-}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Messages.java b/args4j/args4j/src/org/kohsuke/args4j/Messages.java
index f65cd16..24112db 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/Messages.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/Messages.java
@@ -1,12 +1,13 @@
package org.kohsuke.args4j;
import java.text.MessageFormat;
+import java.util.Locale;
import java.util.ResourceBundle;
/**
* @author Kohsuke Kawaguchi
*/
-enum Messages {
+enum Messages implements Localizable {
MISSING_OPERAND,
UNDEFINED_OPTION,
NO_ARGUMENT_ALLOWED,
@@ -19,17 +20,17 @@ enum Messages {
UNKNOWN_HANDLER,
NO_OPTIONHANDLER,
NO_CONSTRUCTOR_ON_HANDLER,
- FORMAT_ERROR_FOR_MAP,
- MAP_HAS_NO_KEY
+ REQUIRES_OPTION_MISSING,
+ FORBIDDEN_OPTION_PRESENT,
+ NO_SUCH_FILE
;
- private static ResourceBundle rb;
-
+ public String formatWithLocale( Locale locale, Object... args ) {
+ ResourceBundle localized = ResourceBundle.getBundle(Messages.class.getName(), locale);
+ return MessageFormat.format(localized.getString(name()),args);
+ }
+
public String format( Object... args ) {
- synchronized(Messages.class) {
- if(rb==null)
- rb = ResourceBundle.getBundle(Messages.class.getName());
- return MessageFormat.format(rb.getString(name()),args);
- }
+ return formatWithLocale(Locale.getDefault(),args);
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Messages.properties b/args4j/args4j/src/org/kohsuke/args4j/Messages.properties
index e89cd6a..cbcd63a 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/Messages.properties
+++ b/args4j/args4j/src/org/kohsuke/args4j/Messages.properties
@@ -34,8 +34,11 @@ NO_OPTIONHANDLER = \
NO_CONSTRUCTOR_ON_HANDLER = \
{0} does not have the proper constructor
-FORMAT_ERROR_FOR_MAP = \
- An argument for setting a Map must contain a "="
+REQUIRES_OPTION_MISSING = \
+ option "{0}" requires the option(s) {1}
-MAP_HAS_NO_KEY = \
- A key must be set. \ No newline at end of file
+FORBIDDEN_OPTION_PRESENT = \
+ option "{0}" cannot be used with the option(s) {1}
+
+NO_SUCH_FILE = \
+ No such file: {0} \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Messages_de_DE.properties b/args4j/args4j/src/org/kohsuke/args4j/Messages_de.properties
index 0dcdc72..9bc34e7 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/Messages_de_DE.properties
+++ b/args4j/args4j/src/org/kohsuke/args4j/Messages_de.properties
@@ -34,7 +34,7 @@ MULTIPLE_USE_OF_OPTION = \
Die Option '{0}' ist mehr als einmal verwendet
UNKNOWN_HANDLER = \
- Es ist kein OptionHandler für '{0}' registriert
+ Es ist kein OptionHandler f\u00fcr '{0}' registriert
NO_OPTIONHANDLER = \
Ist keine OptionHandler Klasse
@@ -42,8 +42,5 @@ NO_OPTIONHANDLER = \
NO_CONSTRUCTOR_ON_HANDLER = \
{0} hat nicht den notwendigen Konstruktor
-FORMAT_ERROR_FOR_MAP = \
- Ein Argument für eine Map muss ein "=" enthalten
-
-MAP_HAS_NO_KEY = \
- A Schl\u00fcssel muss gesetzt sein \ No newline at end of file
+REQUIRES_OPTION_MISSING = \
+ Option "{0}" ben\u00f6tigt die Option(en) {1}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Messages_en.properties b/args4j/args4j/src/org/kohsuke/args4j/Messages_en.properties
new file mode 100644
index 0000000..78c56fb
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/Messages_en.properties
@@ -0,0 +1,3 @@
+# this file is intentionally empty to fall back to the default
+# which is the English locale
+
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Messages_ru_RU.properties b/args4j/args4j/src/org/kohsuke/args4j/Messages_ru.properties
index 1e6f8d0..1e6f8d0 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/Messages_ru_RU.properties
+++ b/args4j/args4j/src/org/kohsuke/args4j/Messages_ru.properties
diff --git a/args4j/args4j/src/org/kohsuke/args4j/NamedOptionDef.java b/args4j/args4j/src/org/kohsuke/args4j/NamedOptionDef.java
index 5ad895a..1ed2dd1 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/NamedOptionDef.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/NamedOptionDef.java
@@ -1,25 +1,55 @@
package org.kohsuke.args4j;
+import java.util.Arrays;
+
/**
- * Run-time copy of the Option or Argument annotation.
+ * Immutable run-time copy of {@link Option} annotation.
*/
public final class NamedOptionDef extends OptionDef {
private final String name;
private final String[] aliases;
+ private final String[] depends;
+ private final String[] forbids;
+ /**
+ * @deprecated
+ * multi-valuedness as option definition does not make sense. It's driven by the setter.
+ */
public NamedOptionDef(Option o, boolean forceMultiValued) {
- super(o.usage(),o.metaVar(),o.required(),o.handler(),o.multiValued() || forceMultiValued);
-
+ this(o);
+ }
+
+ public NamedOptionDef(Option o) {
+ super(o.usage(),o.metaVar(),o.required(),o.help(),o.hidden(),o.handler(),false);
+
this.name = o.name();
- this.aliases = o.aliases();
+ this.aliases = createZeroSizedArrayIfNull(o.aliases());
+ this.depends = createZeroSizedArrayIfNull(o.depends());
+ this.forbids = createZeroSizedArrayIfNull(o.forbids());
}
+ private static String[] createZeroSizedArrayIfNull(String in[]) {
+ if (in == null) {
+ return new String[0];
+ } else {
+ return in;
+ }
+ }
+
public String name() {
return name;
}
public String[] aliases() {
- return aliases;
+ return Arrays.copyOf(aliases, aliases.length);
+ }
+
+ public String[] depends() {
+ return Arrays.copyOf(depends, depends.length);
+ }
+
+ public String[] forbids() {
+ return Arrays.copyOf(forbids, forbids.length);
}
@Override
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Option.java b/args4j/args4j/src/org/kohsuke/args4j/Option.java
index 7ddf979..e870017 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/Option.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/Option.java
@@ -1,11 +1,11 @@
package org.kohsuke.args4j;
import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Setter;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
import java.lang.reflect.AccessibleObject;
import java.util.ResourceBundle;
@@ -19,7 +19,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*
* <p>
* This annotation can be placed on a field of type T or the method
- * of the form <tt>void <i>methodName</i>(T value)</tt>. Its access
+ * of the form <code>void <i><code>methodName</code></i>(T value)</code>. Its access
* modified can be anything, but if it's not public, your application
* needs to run in a security context that allows args4j to access
* the field/method (see {@link AccessibleObject#setAccessible(boolean)}.
@@ -30,25 +30,25 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*
* <h2>Boolean Switch</h2>
* <p>
- * When T is boolean , it represents
- * a boolean option that takes the form of "-OPT". When this option is set,
- * the property will be set to true.
+ * When <var>T</var> is {@code boolean} , it represents
+ * a {@code boolean} option that takes the form of <code>-OPT</code>. When this option is set,
+ * the property will be set to {@code true}.
*
* <h2>String Switch</h2>
* <p>
- * When T is {@link String}, it represents
+ * When <var>T</var> is {@link String}, it represents
* an option that takes one operand. The value of the operand is set
* to the property.
*
* <h2>Enum Switch</h2>
* <p>
- * When T is derived from {@link Enum}, it represents an option that takes
+ * When <var>T</var> is derived from {@link Enum}, it represents an option that takes
* an operand, which must be one of the enum constant. The comparion between
* the operand and the enum constant name is done in a case insensitive fashion.
* <p>
* For example, the following definition will represent command line options
- * like "-coin penny" or "-coin DIME" but things like "-coin" or "-coin abc" are
- * errors.
+ * like <code>-coin penny</code> or <code>-coin DIME</code>,
+ * but things like <code>-coin</code> or <code>-coin abc</code> are errors.
*
* <pre>
* enum Coin { PENNY,NICKEL,DIME,QUARTER }
@@ -61,7 +61,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*
* <h2>File Switch</h2>
* <p>
- * When T is a {@link File}, it represents an option that takes a file/directory
+ * When <var>T</var> is a {@link File}, it represents an option that takes a file/directory
* name as an operand.
*
* @author Kohsuke Kawaguchi
@@ -70,12 +70,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({FIELD,METHOD,PARAMETER})
public @interface Option {
/**
- * Name of the option, such as "-foo" or "-bar".
+ * Name of the option, such as <code>-foo</code> or <code>-bar</code>.
*/
String name();
/**
- * Aliases for the options, such as "--long-option-name".
+ * Aliases for the options, such as <code>--long-option-name</code>.
*/
String[] aliases() default { };
@@ -102,14 +102,16 @@ public @interface Option {
String usage() default "";
/**
- * When the option takes an operand, the usage screen will show something like this:
+ * When the option takes an operand, the usage screen will show something like this
+ *
* <pre>
* -x FOO : blah blah blah
* </pre>
- * You can replace the 'FOO' token by using this parameter.
+ *
+ * You can replace the <code>FOO</code> token by using this parameter.
*
* <p>
- * If left unspecifiied, this value is infered from the type of the option.
+ * If left unspecified, this value is infered from the type of the option.
*
* <p>
* Just like {@link #usage()}, normally, this value is printed as is.
@@ -132,6 +134,33 @@ public @interface Option {
* flag.
*/
boolean required() default false;
+
+ /**
+ * Specify that the option is a help option.
+ *
+ * <p>
+ * When flagging an option being the help option, required
+ * arguments or options that are missing in an actual command
+ * line don't cause an exception to be thrown.
+ * @see #required()
+ */
+ boolean help() default false;
+
+ /**
+ * Specify that the option is hidden from the usage, by default.
+ *
+ * <p>
+ * You can still have {@link CmdLineParser} show hidden options
+ * by using {@link OptionHandlerFilter#ALL}, which allows you to
+ * create an option that shows hidden options.
+ *
+ * <p>
+ * If you need more complicated filtering logic, define your own
+ * annotations and check them in {@link Setter#asAnnotatedElement()}.
+ *
+ * @see OptionHandlerFilter#PUBLIC
+ */
+ boolean hidden() default false;
/**
* Specify the {@link OptionHandler} that processes the command line arguments.
@@ -148,6 +177,7 @@ public @interface Option {
* defining a non-standard option parsing semantics.
*
* <h3>Example</h3>
+ *
* <pre>
* // this is a normal "-r" option
* &#64;Option(name="-r")
@@ -160,10 +190,46 @@ public @interface Option {
* </pre>
*/
Class<? extends OptionHandler> handler() default OptionHandler.class;
+
+ /**
+ * List of other options that this option depends on.
+ *
+ * <h3>Example</h3>
+ *
+ * <pre>
+ * &#64;Option(name="-a")
+ * int a;
+ * //-b is not required but if it's provided, then a becomes required
+ * &#64;Option(name="-b", depends={"-a"}
+ * int b;
+ * </pre>
+ *
+ * <p>
+ * At the end of {@link CmdLineParser#parseArgument(String...)},
+ * a {@link CmdLineException} will be thrown if options required by another one
+ * are not present.
+ * </p>
+ */
+ String[] depends() default { };
/**
- * Whether the option is multi-valued.
- * For mappings to List<...>, this defaults to true, otherwise false
+ * List of other options that this option is incompatible with..
+ *
+ * <h3>Example</h3>
+ *
+ * <pre>
+ * &#64;Option(name="-a")
+ * int a;
+ * // -h and -a cannot be specified together
+ * &#64;Option(name="-h", forbids={"-a"}
+ * boolean h;
+ * </pre>
+ *
+ * <p>
+ * At the end of {@link CmdLineParser#parseArgument(String...)},
+ * a {@link CmdLineException} will be thrown if forbidden option
+ * combinations are present.
+ * </p>
*/
- boolean multiValued() default false;
+ String[] forbids() default { };
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/OptionDef.java b/args4j/args4j/src/org/kohsuke/args4j/OptionDef.java
index 5601a41..703debd 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/OptionDef.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/OptionDef.java
@@ -12,18 +12,24 @@ public class OptionDef {
private final String usage;
private final String metaVar;
private final boolean required;
+ private final boolean help;
+ private final boolean hidden;
private final boolean multiValued;
private final Class<? extends OptionHandler> handler;
public OptionDef(Argument a, boolean forceMultiValued) {
- this(a.usage(), a.metaVar(), a.required(), a.handler(), a.multiValued() || forceMultiValued);
+ this(a.usage(), a.metaVar(), a.required(), false, a.hidden(), a.handler(), a.multiValued() || forceMultiValued);
}
protected OptionDef(String usage, String metaVar, boolean required,
- Class<? extends OptionHandler> handler, boolean multiValued) {
+ boolean help, boolean hidden,
+ Class<? extends OptionHandler> handler,
+ boolean multiValued) {
this.usage = usage;
this.metaVar = metaVar;
this.required = required;
+ this.help = help;
+ this.hidden = hidden;
this.handler = handler;
this.multiValued = multiValued;
}
@@ -39,6 +45,17 @@ public class OptionDef {
public boolean required() {
return required;
}
+
+ public boolean help() {
+ return help;
+ }
+
+ /**
+ * Value from {@link Option#hidden()} or {@link Argument#hidden()}
+ */
+ public boolean hidden() {
+ return hidden;
+ }
public Class<? extends OptionHandler> handler() {
return handler;
@@ -47,7 +64,7 @@ public class OptionDef {
public boolean isMultiValued() {
return multiValued;
}
-
+
public boolean isArgument() {
return true;
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/OptionHandlerFilter.java b/args4j/args4j/src/org/kohsuke/args4j/OptionHandlerFilter.java
new file mode 100644
index 0000000..f80540b
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/OptionHandlerFilter.java
@@ -0,0 +1,60 @@
+package org.kohsuke.args4j;
+
+import org.kohsuke.args4j.spi.OptionHandler;
+
+import java.io.Writer;
+import java.util.ResourceBundle;
+
+/**
+ * Selects {@link OptionHandler}.
+ *
+ * <p>
+ * For example, we use this to let the caller specify which
+ * options are printed, and which ones aren't.
+ *
+ * @author Kohsuke Kawaguchi
+ * @see CmdLineParser#printExample(OptionHandlerFilter)
+ * @see CmdLineParser#printUsage(Writer, ResourceBundle, OptionHandlerFilter)
+ */
+public interface OptionHandlerFilter {
+ /**
+ *
+ * @param o
+ * Never {@code null}. Internally options (like <code>-r</code>) and arguments (others)
+ * are treated uniformly as {@link OptionHandler}.
+ * See {@link OptionDef#isArgument()} to distinguish them.
+ * @return
+ * true to choose this option, false to ignore/discard/disregard it.
+ */
+ boolean select(OptionHandler o);
+
+ /**
+ * Print all defined options in the example.
+ */
+ OptionHandlerFilter ALL = new OptionHandlerFilter() {
+ public boolean select(OptionHandler o) {
+ return true;
+ }
+ };
+
+ /**
+ * Print all {@linkplain Option#hidden() non-hidden} options.
+ *
+ * <p>
+ * This would only be useful with a small number of options.
+ */
+ OptionHandlerFilter PUBLIC = new OptionHandlerFilter() {
+ public boolean select(OptionHandler o) {
+ return !o.option.hidden();
+ }
+ };
+
+ /**
+ * Print all {@linkplain Option#required() required} options.
+ */
+ OptionHandlerFilter REQUIRED = new OptionHandlerFilter() {
+ public boolean select(OptionHandler o) {
+ return o.option.required();
+ }
+ };
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/OptionHandlerRegistry.java b/args4j/args4j/src/org/kohsuke/args4j/OptionHandlerRegistry.java
new file mode 100644
index 0000000..45dda07
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/OptionHandlerRegistry.java
@@ -0,0 +1,187 @@
+package org.kohsuke.args4j;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+import org.kohsuke.args4j.spi.BooleanOptionHandler;
+import org.kohsuke.args4j.spi.ByteOptionHandler;
+import org.kohsuke.args4j.spi.CharOptionHandler;
+import org.kohsuke.args4j.spi.DoubleOptionHandler;
+import org.kohsuke.args4j.spi.EnumOptionHandler;
+import org.kohsuke.args4j.spi.FileOptionHandler;
+import org.kohsuke.args4j.spi.FloatOptionHandler;
+import org.kohsuke.args4j.spi.InetAddressOptionHandler;
+import org.kohsuke.args4j.spi.IntOptionHandler;
+import org.kohsuke.args4j.spi.LongOptionHandler;
+import org.kohsuke.args4j.spi.MapOptionHandler;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.PathOptionHandler;
+import org.kohsuke.args4j.spi.PatternOptionHandler;
+import org.kohsuke.args4j.spi.Setter;
+import org.kohsuke.args4j.spi.ShortOptionHandler;
+import org.kohsuke.args4j.spi.StringOptionHandler;
+import org.kohsuke.args4j.spi.URIOptionHandler;
+import org.kohsuke.args4j.spi.URLOptionHandler;
+
+/**
+ * Manages the registration of option handlers.
+ * This is good for registering custom handlers
+ * for specific parameter classes not yet implemented.
+ * The registry is a singleton that can be
+ * retrieved with the {@link #getRegistry()} call.
+ * @author Stephan Fuhrmann
+ */
+public class OptionHandlerRegistry {
+
+ /**
+ * The shared reference.
+ * @see #getRegistry()
+ */
+ private static OptionHandlerRegistry instance;
+
+ /**
+ * Gets the option handler registry singleton instance.
+ * @return a shared instance of the registry.
+ */
+ public synchronized static OptionHandlerRegistry getRegistry() {
+ if (instance == null) {
+ instance = new OptionHandlerRegistry();
+ }
+ return instance;
+ }
+
+ /**
+ * Constructs an option handler manager with the
+ * default handlers initialized.
+ */
+ private OptionHandlerRegistry() {
+ initHandlers();
+ }
+
+ /** Registers the default handlers. */
+ private void initHandlers() {
+ registerHandler(Boolean.class,BooleanOptionHandler.class);
+ registerHandler(boolean.class,BooleanOptionHandler.class);
+ registerHandler(File.class,FileOptionHandler.class);
+ registerHandler(URL.class, URLOptionHandler.class);
+ registerHandler(URI.class, URIOptionHandler.class);
+ registerHandler(Integer.class,IntOptionHandler.class);
+ registerHandler(int.class,IntOptionHandler.class);
+ registerHandler(Double.class, DoubleOptionHandler.class);
+ registerHandler(double.class,DoubleOptionHandler.class);
+ registerHandler(String.class,StringOptionHandler.class);
+ registerHandler(Byte.class, ByteOptionHandler.class);
+ registerHandler(byte.class, ByteOptionHandler.class);
+ registerHandler(Character.class, CharOptionHandler.class);
+ registerHandler(char.class, CharOptionHandler.class);
+ registerHandler(Float.class, FloatOptionHandler.class);
+ registerHandler(float.class, FloatOptionHandler.class);
+ registerHandler(Long.class, LongOptionHandler.class);
+ registerHandler(long.class, LongOptionHandler.class);
+ registerHandler(Short.class, ShortOptionHandler.class);
+ registerHandler(short.class, ShortOptionHandler.class);
+ registerHandler(InetAddress.class, InetAddressOptionHandler.class);
+ registerHandler(Pattern.class, PatternOptionHandler.class);
+ // enum is a special case
+ registerHandler(Map.class,MapOptionHandler.class);
+
+ try {
+ Class p = Class.forName("java.nio.file.Path");
+ registerHandler(p, PathOptionHandler.class);
+ } catch (ClassNotFoundException e) {
+ // running in Java6 or earlier
+ }
+ }
+
+ /** Finds the constructor for an option handler.
+ */
+ private static Constructor<? extends OptionHandler> getConstructor(Class<? extends OptionHandler> handlerClass) {
+ try {
+ return handlerClass.getConstructor(CmdLineParser.class, OptionDef.class, Setter.class);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException(Messages.NO_CONSTRUCTOR_ON_HANDLER.format(handlerClass));
+ }
+ }
+
+ /**
+ * Registers a user-defined {@link OptionHandler} class with args4j.
+ *
+ * <p>
+ * This method allows users to extend the behavior of args4j by writing
+ * their own {@link OptionHandler} implementation.
+ *
+ * @param valueType
+ * The specified handler is used when the field/method annotated by {@link Option}
+ * is of this type.
+ * @param handlerClass
+ * This class must have the constructor that has the same signature as
+ * {@link OptionHandler#OptionHandler(CmdLineParser, OptionDef, Setter)}
+ * @throws NullPointerException if {@code valueType} or {@code handlerClass} is {@code null}.
+ * @throws IllegalArgumentException if {@code handlerClass} is not a subtype of {@code OptionHandler}.
+ */
+ public void registerHandler( Class valueType, Class<? extends OptionHandler> handlerClass ) {
+ Utilities.checkNonNull(valueType, "valueType");
+ Utilities.checkNonNull(handlerClass, "handlerClass");
+
+ if(!OptionHandler.class.isAssignableFrom(handlerClass))
+ throw new IllegalArgumentException(Messages.NO_OPTIONHANDLER.format());
+
+ Constructor<? extends OptionHandler> c = getConstructor(handlerClass);
+ handlerClasses.put(valueType,c);
+ }
+
+ /**
+ * Creates an {@link OptionHandler} that handles the given {@link Option} annotation
+ * and the {@link Setter} instance.
+ */
+ @SuppressWarnings("unchecked")
+ protected OptionHandler createOptionHandler(CmdLineParser parser, OptionDef o, Setter setter) {
+ Utilities.checkNonNull(o, "CmdLineParser");
+ Utilities.checkNonNull(o, "OptionDef");
+ Utilities.checkNonNull(setter, "Sette");
+
+ Constructor<? extends OptionHandler> handlerType;
+ Class<? extends OptionHandler> h = o.handler();
+
+ if(h==OptionHandler.class) {
+ // infer the type
+
+ // enum is the special case
+ Class t = setter.getType();
+ if(Enum.class.isAssignableFrom(t))
+ return new EnumOptionHandler(parser,o,setter,t);
+
+ handlerType = handlerClasses.get(t);
+ if(handlerType==null)
+ throw new IllegalAnnotationError(Messages.UNKNOWN_HANDLER.format(t));
+ } else {
+ handlerType = getConstructor(h);
+ }
+
+ try {
+ return handlerType.newInstance(parser,o,setter);
+ } catch (InstantiationException e) {
+ throw new IllegalAnnotationError(e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalAnnotationError(e);
+ } catch (InvocationTargetException e) {
+ throw new IllegalAnnotationError(e);
+ }
+ }
+
+ /**
+ * All {@link OptionHandler}s known to the {@link CmdLineParser}.
+ *
+ * Constructors of {@link OptionHandler}-derived class keyed by their supported types.
+ */
+ private final Map<Class,Constructor<? extends OptionHandler>> handlerClasses =
+ Collections.synchronizedMap(new HashMap<Class,Constructor<? extends OptionHandler>>());
+
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/ParserProperties.java b/args4j/args4j/src/org/kohsuke/args4j/ParserProperties.java
new file mode 100644
index 0000000..fd36dfa
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/ParserProperties.java
@@ -0,0 +1,120 @@
+package org.kohsuke.args4j;
+
+import org.kohsuke.args4j.spi.OptionHandler;
+
+import java.util.Comparator;
+
+/**
+ * Set of properties that controls {@link CmdLineParser} behaviours.
+ *
+ * @see CmdLineParser#CmdLineParser(Object, ParserProperties)
+ */
+public class ParserProperties {
+
+ private static final int DEFAULT_USAGE_WIDTH = 80;
+
+ private int usageWidth = DEFAULT_USAGE_WIDTH;
+ private Comparator<OptionHandler> optionSorter = DEFAULT_COMPARATOR;
+ private String optionValueDelimiter=" ";
+ private boolean atSyntax = true;
+
+ private ParserProperties() {
+ }
+
+ /**
+ * Returns an instance of the default parser properties.
+ * This instance can be manipulated with the {@code withXXX()} methods
+ * in this class.
+ */
+ public static ParserProperties defaults() {
+ return new ParserProperties();
+ }
+
+ /**
+ * Toggles the parsing of @-prefixes in values.
+ * If a command line value starts with @, it is interpreted
+ * as being a file, loaded, and interpreted as if
+ * the file content would have been passed to the command line.
+ * @param atSyntax {@code true} if at sign is being parsed, {@code false}
+ * if it is to be ignored. Defaults to {@code true}.
+ * @see #getAtSyntax()
+ */
+ public ParserProperties withAtSyntax(boolean atSyntax) {
+ this.atSyntax = atSyntax;
+ return this;
+ }
+
+ /**
+ * Gets whether @-prefix-parsing is enabled.
+ * @see #withAtSyntax(boolean)
+ */
+ public boolean getAtSyntax() {
+ return atSyntax;
+ }
+
+ /**
+ * Sets the width of a usage line.
+ * If the usage message is longer than this value, the parser wraps the line.
+ *
+ * Defaults to {@code 80}.
+ *
+ * @param usageWidth the width of the usage output in columns.
+ * @throws IllegalArgumentException if {@code usageWidth} is negative
+ */
+ public ParserProperties withUsageWidth(int usageWidth) {
+ if (usageWidth < 0)
+ throw new IllegalArgumentException("Usage width is negative");
+ this.usageWidth = usageWidth;
+ return this;
+ }
+
+ /**
+ * @return the width of a usage line.
+ */
+ int getUsageWidth() {
+ return usageWidth;
+ }
+
+ /**
+ * Controls how options are sorted in the usage screen.
+ *
+ * @param sorter
+ * If non-{@code null}, options are sorted in the order induced by this comparator.
+ */
+ public ParserProperties withOptionSorter(Comparator<OptionHandler> sorter) {
+ this.optionSorter = sorter;
+ return this;
+ }
+
+ /**
+ * @return
+ * {@code null} if options are left unsorted and should be listed by their discovery order.
+ * Otherwise the returned comparator is used to sort options.
+ * The default value is a comparator that sorts options alphabetically.
+ */
+ Comparator<OptionHandler> getOptionSorter() {
+ return optionSorter;
+ }
+
+ /**
+ * Sets the string used to separate option name and its value (such as --foo=bar vs --foo bar)
+ *
+ * Default to whitespace. Note that the tokens separated in the argument array (such as '-foo','bar')
+ * is always recognized as a valid name/value separator.
+ *
+ */
+ public ParserProperties withOptionValueDelimiter(String v) {
+ this.optionValueDelimiter = v;
+ return this;
+ }
+
+ public String getOptionValueDelimiter() {
+ return this.optionValueDelimiter;
+ }
+
+ static final Comparator<OptionHandler> DEFAULT_COMPARATOR = new Comparator<OptionHandler>() {
+ public int compare(OptionHandler o1, OptionHandler o2) {
+ return o1.option.toString().compareTo(o2.option.toString());
+ }
+ };
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/Utilities.java b/args4j/args4j/src/org/kohsuke/args4j/Utilities.java
new file mode 100644
index 0000000..205ebcf
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/Utilities.java
@@ -0,0 +1,28 @@
+package org.kohsuke.args4j;
+
+/**
+ * Misc utility methods. Don't make this
+ * class visible to the outside world.
+ * When we switch to JDK 1.7, re-check the sense
+ * of this class.
+ */
+class Utilities {
+
+ private Utilities() {
+ // no instance
+ }
+
+ /** This method is similar to {@code Objects.requireNonNull()}.
+ * But this one is available for JDK 1.6 which is the
+ * current target of args4j.
+ * I didn't want to break compatibility with JDK 1.6.
+ * @param obj the object to check for {@code null} value.
+ * @param name the object name. If {@code obj} is {@code null}, then
+ * an exception is constructed from this name.
+ */
+ static void checkNonNull(Object obj, String name) {
+ if (obj == null) {
+ throw new NullPointerException(name+" is null");
+ }
+ }
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/XmlParser.java b/args4j/args4j/src/org/kohsuke/args4j/XmlParser.java
index 8f71c5d..abf07f1 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/XmlParser.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/XmlParser.java
@@ -13,23 +13,23 @@ import org.xml.sax.InputSource;
* Parses an XML-file specifying the 'annotations'.
* The XML must have the structure:
* <pre>
- * &lt;args>
- * &lt;option field="" method="" name="" usage="" metavar="" handler=""/>
- * &lt;argument field="" method="" usage="" metavar="" handler=""/>
- * &lt;/args>
+ * &lt;args&gt;
+ * &lt;option field="" method="" name="" usage="" metavar="" handler=""/&gt;
+ * &lt;argument field="" method="" usage="" metavar="" handler=""/&gt;
+ * &lt;/args&gt;
* </pre>
* Exactly one of the attributes 'field' or 'method' must be set.
* The 'handler' value specifies a full qualified class name.
*
* <h3>Example</h3>
* <pre>
- * &lt;args>
- * &lt;option field="recursive" name="-r" usage="recursively run something"/>
- * &lt;option field="out" name="-o" usage="output to this file" metavar="OUTPUT"/>
- * &lt;option method="setStr(String)" name="-str"/>
- * &lt;option field="data" name="-custom" handler="org.kohsuke.args4j.spi.BooleanOptionHandler" usage="boolean value for checking the custom handler"/>
- * &lt;argument field="arguments"/>
- * &lt;args>
+ * &lt;args&gt;
+ * &lt;option field="recursive" name="-r" usage="recursively run something"/&gt;
+ * &lt;option field="out" name="-o" usage="output to this file" metavar="OUTPUT"/&gt;
+ * &lt;option method="setStr(String)" name="-str"/&gt;
+ * &lt;option field="data" name="-custom" handler="org.kohsuke.args4j.spi.BooleanOptionHandler" usage="boolean value for checking the custom handler"/&gt;
+ * &lt;argument field="arguments"/&gt;
+ * &lt;args&gt;
* </pre>
*
* @author Jan Materne
diff --git a/args4j/args4j/src/org/kohsuke/args4j/package.html b/args4j/args4j/src/org/kohsuke/args4j/package.html
index bac7614..d641053 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/package.html
+++ b/args4j/args4j/src/org/kohsuke/args4j/package.html
@@ -1,33 +1,40 @@
-<html><body>
+<html>
+<body>
+
<p>Core classes of the Args4J command line parser.</p>
-<h1>What is Args4J</h1>
-<p>Args4J is a command line parser. As such a parser its job is to parse the String-array passed to the main() method
-and transfer the values to a java object, which includes type conversion. The entry point into this parsing is
-the CmdLineParser class with its parse() Method.</p>
-<p>Args4J must know the mapping between the flag from the command line and the target for the value.
-There are multiple ways for Args4J: <ul>
- <li>place an @Option or @Argument annotation at a setter or on a field</li>
- <li>provide a XML configuration file</li>
- <li>make all fields public available</li>
-</ul>
-depending on what you want, you have to do a configuration step before starting the parsing.</p>
+<h1>What is Args4J?</h1>
+
+ <p>
+ Args4J is a command line parser.
+ As such, its job is to parse the String-array passed to the <code>main()</code> method and
+ transfer the values to a Java object, which includes type conversion.
+ The entry point into this parsing is the <code>CmdLineParser</code> class,
+ with its <code>parse()</code> method.
+ </p>
+
+ <p>Args4J must know the mapping between the flag from the command line and the target for the value.
+ There are many ways to use Args4J:</p>
+
+ <ul>
+ <li>place an <code>@Option</code> or <code>@Argument</code> annotation at a setter or on a field</li>
+ <li>provide a XML configuration file</li>
+ <li>make all fields publicly available</li>
+ </ul>
+
+ <p>Depending on what you want, you may have perform a configuration step before parsing.</p>
+
<h1>Examples</h1>
-<p><tt>java Main -text newText</tt></p>
+<p><code>java Main -text newText</code></p>
+
+<p>The typical use involves writing a small bean class and providing the annotations.</p>
+<p>This feature is available since the first Args4J release:</p>
-<p>The standard use case is having a bean class and providing the annotations.
-This feature is available since the first Args4J release:
-<!-- TODO:
-Javadoc stops when reaching the at-sign. When I load the package.html directly into Firefox,
-all is fine. But when creating the javadoc it stops copying the content at that sign.
-(a) is a compromise here ...
-Does anyone know how to handle that?
--->
<pre>
public class Bean {
- (a)Option(name="-text")
+ {@literal @}Option(name="-text")
String text;
}
public class Main {
@@ -39,12 +46,14 @@ public class Main {
}
</pre>
-<p>An easy way for initializing fields and not touching the bean source code
-is using the FieldParser. The FieldParser scans all fields of the bean class
-(including inheritance) and makes them public available as options with
-a '-' prefix in the name.
-This feature is available since Args4J release 2.0.16:
-<pre>
+
+<p>An easy way to initialize fields without touching the bean source code is to use the <code>FieldParser</code>.</p>
+
+<p>The <code>FieldParser</code> scans all fields of bean class (including inheritance), and makes them publicly available as options with a <code>-</code> prefix in the name.</p>
+
+<p>This feature is available since Args4J release 2.0.16:</p>
+
+<code><pre>
public class Bean {
String text;
}
@@ -56,13 +65,14 @@ public class Main {
parser.parse(args);
}
}
-</pre>
+</pre></code>
-<p>While the FieldParser is easier to use, the XmlParser supports more features.
-That said it supports all features which are available via annotations: usage text, specifying handlers and more.
-You have to provide an XML InputSource or an URL to the XML file.
-This feature is available since Args4J release 2.0.16:
-<pre>
+<p>While the <code>FieldParser</code> is easier to use, the <code>XmlParser</code> supports more features.</p>
+<p>That said, it supports all features which are available via annotations: usage text, specifying handlers, and more. You have to provide an XML <code>InputSource</code> or a URL to the XML file.</p>
+
+<p>This feature is available since Args4J release 2.0.16:</p>
+
+<code><pre>
public class Bean {
String text;
}
@@ -77,8 +87,7 @@ public class Main {
&lt;args>
&lt;option field="text" name="-text" usage="Output text"/>
&lt;/args>
-</pre>
-</p>
-
+</pre></code>
-</body></html> \ No newline at end of file
+</body>
+</html> \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/AnnotationImpl.java b/args4j/args4j/src/org/kohsuke/args4j/spi/AnnotationImpl.java
index bd1a2ec..5af572b 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/AnnotationImpl.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/AnnotationImpl.java
@@ -1,6 +1,7 @@
package org.kohsuke.args4j.spi;
import java.lang.annotation.Annotation;
+import java.util.Arrays;
/**
@@ -26,12 +27,13 @@ public abstract class AnnotationImpl implements Annotation {
metaVar = ce.metavar != null ? ce.metavar : "";
multiValued = ce.multiValued;
required = ce.required;
+ hidden = ce.hidden;
usage = ce.usage != null ? ce.usage : "";
}
public String[] aliases;
public String[] aliases() {
- return aliases;
+ return Arrays.copyOf(aliases, aliases.length);
}
public Class<? extends OptionHandler> handler;
public Class<? extends OptionHandler> handler() {
@@ -49,6 +51,14 @@ public abstract class AnnotationImpl implements Annotation {
public boolean required() {
return required;
}
+ public boolean help;
+ public boolean help() {
+ return help;
+ }
+ public boolean hidden;
+ public boolean hidden() {
+ return hidden;
+ }
public String usage;
public String usage() {
return usage;
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/ArrayFieldSetter.java b/args4j/args4j/src/org/kohsuke/args4j/spi/ArrayFieldSetter.java
new file mode 100644
index 0000000..4951450
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/ArrayFieldSetter.java
@@ -0,0 +1,103 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.IllegalAnnotationError;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+
+/**
+ * {@link Setter} that allows multiple values to be stored into one array field.
+ *
+ * <p>
+ * Because of the {@link CmdLineParser} abstractions of allowing incremental parsing of options,
+ * this implementation creates a whole new array each time a new value is found.
+ *
+ * This is also why we don't support a setter method that takes list/array as arguments.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+final class ArrayFieldSetter implements Setter {
+ private final Object bean;
+ private final Field f;
+
+ private Object defaultArray;
+
+ public ArrayFieldSetter(Object bean, Field f) {
+ this.bean = bean;
+ this.f = f;
+
+ if(!f.getType().isArray())
+ throw new IllegalAnnotationError(Messages.ILLEGAL_FIELD_SIGNATURE.format(f.getType()));
+
+ trySetDefault(bean);
+ }
+
+ /** Remember default so we throw away the default when adding user values.
+ */
+ private void trySetDefault(Object bean1) throws IllegalAccessError {
+ try {
+ doSetDefault(bean1);
+ } catch (IllegalAccessException ex) {
+ try {
+ // try again
+ f.setAccessible(true);
+ doSetDefault(bean1);
+ }catch (IllegalAccessException ex1) {
+ throw new IllegalAccessError(ex1.getMessage());
+ }
+ }
+ }
+
+ private void doSetDefault(Object bean) throws IllegalAccessException {
+ this.defaultArray = f.get(bean);
+ }
+
+ public FieldSetter asFieldSetter() {
+ return new FieldSetter(bean,f);
+ }
+
+ public AnnotatedElement asAnnotatedElement() {
+ return f;
+ }
+
+ public boolean isMultiValued() {
+ return true;
+ }
+
+ public Class getType() {
+ return f.getType().getComponentType();
+ }
+
+ public void addValue(Object value) {
+ try {
+ doAddValue(bean, value);
+ } catch (IllegalAccessException ex) {
+ // try again
+ f.setAccessible(true);
+ try {
+ doAddValue(bean,value);
+ } catch (IllegalAccessException e) {
+ throw new IllegalAccessError(e.getMessage());
+ }
+ }
+ }
+
+ private void doAddValue(Object bean, Object value) throws IllegalAccessException {
+ Object ary = f.get(bean);
+ if (ary == null || ary == defaultArray) {
+ ary = Array.newInstance(getType(), 1);
+ Array.set(ary, 0, value);
+ } else {
+ int len = Array.getLength(ary);
+ Object newAry = Array.newInstance(ary.getClass().getComponentType(), len +1);
+ System.arraycopy(ary, 0, newAry, 0, len);
+ Array.set(newAry, len, value);
+ ary = newAry;
+ }
+
+ f.set(bean, ary);
+ }
+}
+
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/BooleanOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/BooleanOptionHandler.java
index 5382fed..344d6d7 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/BooleanOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/BooleanOptionHandler.java
@@ -26,7 +26,7 @@ public class BooleanOptionHandler extends OptionHandler<Boolean> {
String valueStr = params.getParameter(0).toLowerCase();
int index = ACCEPTABLE_VALUES.indexOf(valueStr);
if (index == -1) {
- throw new CmdLineException(owner, Messages.ILLEGAL_BOOLEAN.format(valueStr));
+ throw new CmdLineException(owner, Messages.ILLEGAL_BOOLEAN, valueStr);
}
setter.addValue(index < ACCEPTABLE_VALUES.size() / 2);
return 1;
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/CharOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/CharOptionHandler.java
index f2089d8..814688b 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/CharOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/CharOptionHandler.java
@@ -4,10 +4,9 @@ import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.OptionDef;
import org.kohsuke.args4j.CmdLineException;
-import java.text.MessageFormat;
/**
- * {@link Char}
+ * {@link Character}
* {@link OptionHandler}
* {@link OneArgumentOptionHandler}
* @author Jan Materne
@@ -22,7 +21,7 @@ public class CharOptionHandler extends OneArgumentOptionHandler<Character> {
@Override
protected Character parse(String argument) throws NumberFormatException, CmdLineException {
if (argument.length() != 1)
- throw new CmdLineException(owner, Messages.ILLEGAL_CHAR.format(argument));
+ throw new CmdLineException(owner, Messages.ILLEGAL_CHAR, argument);
return argument.charAt(0);
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/ConfigElement.java b/args4j/args4j/src/org/kohsuke/args4j/spi/ConfigElement.java
index 474c943..60e8e87 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/ConfigElement.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/ConfigElement.java
@@ -1,7 +1,7 @@
package org.kohsuke.args4j.spi;
/**
- * The ConfigElement is an <tt>&lt;option></tt> or <tt>&lt;argument></tt> tag
+ * The ConfigElement is an <tt>&lt;option&gt;</tt> or <tt>&lt;argument&gt;</tt> tag
* in the xml configuration file.
* @author Jan Materne
*/
@@ -15,6 +15,7 @@ public class ConfigElement {
public String[] aliases = {};
public boolean multiValued = false;
public boolean required = false;
+ public boolean hidden = false;
/**
* Ensures that only a field XOR a method is set.
* @return
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/DelimitedOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/DelimitedOptionHandler.java
new file mode 100644
index 0000000..def390d
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/DelimitedOptionHandler.java
@@ -0,0 +1,48 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * Partial {@link OptionHandler} implementation that takes a single value to the option,
+ * which is then gets split into individual tokens using fixed delimiter.
+ *
+ * <p>
+ * This class is marked as {@code abstract} even though it has no abstract methods
+ * to indicate that the class cannot be used by itself in {@link Option#handler()},
+ * due to the extra argument that it takes.
+ *
+ * @author kmahoney
+ */
+public abstract class DelimitedOptionHandler<T> extends OptionHandler<T> {
+
+ protected final String delimiter;
+ protected final OneArgumentOptionHandler<? extends T> individualOptionHandler;
+
+ public DelimitedOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super T> setter, String delimiter, OneArgumentOptionHandler<? extends T> individualOptionHandler) {
+ super(parser, option, setter);
+ this.delimiter = delimiter;
+ this.individualOptionHandler = individualOptionHandler;
+ }
+
+ @Override
+ public int parseArguments(Parameters params) throws CmdLineException {
+ String full = params.getParameter(0);
+ String[] delimitedStrs = full.split(delimiter);
+ for (String delimitedStr : delimitedStrs) {
+ setter.addValue(individualOptionHandler.parse(delimitedStr));
+ }
+
+ // The number of Parameters consumed (not the number set)
+ return 1;
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ final String tMetaVar = individualOptionHandler.getDefaultMetaVariable();
+ if (tMetaVar == null || tMetaVar.trim().isEmpty()) return tMetaVar;
+ return "<" + tMetaVar + delimiter + tMetaVar + delimiter + "...>";
+ }
+} \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/EnumOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/EnumOptionHandler.java
index a6447ea..f0da768 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/EnumOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/EnumOptionHandler.java
@@ -1,5 +1,7 @@
package org.kohsuke.args4j.spi;
+import java.util.ResourceBundle;
+
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.OptionDef;
@@ -30,9 +32,9 @@ public class EnumOptionHandler<T extends Enum<T>> extends OptionHandler<T> {
if(value==null) {
if (option.isArgument()) {
- throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND.format(option.toString(),s));
+ throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND, option.toString(), s);
} else {
- throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND.format(params.getParameter(-1),s));
+ throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND, params.getParameter(-1),s);
}
}
setter.addValue(value);
@@ -55,4 +57,9 @@ public class EnumOptionHandler<T extends Enum<T>> extends OptionHandler<T> {
rv.append("]");
return rv.toString();
}
+
+ @Override
+ public String getMetaVariable(ResourceBundle rb) {
+ return getDefaultMetaVariable();
+ }
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/ExplicitBooleanOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/ExplicitBooleanOptionHandler.java
index e2fb837..5ede740 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/ExplicitBooleanOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/ExplicitBooleanOptionHandler.java
@@ -52,13 +52,13 @@ public class ExplicitBooleanOptionHandler extends OptionHandler<Boolean> {
private Boolean getBoolean(String parameter) throws CmdLineException {
String valueStr = parameter.toLowerCase();
if (!ACCEPTABLE_VALUES.containsKey(valueStr)) {
- throw new CmdLineException(owner, Messages.ILLEGAL_BOOLEAN.format(valueStr));
+ throw new CmdLineException(owner, Messages.ILLEGAL_BOOLEAN, valueStr);
}
return ACCEPTABLE_VALUES.get(valueStr);
}
@Override
public String getDefaultMetaVariable() {
- return "[VAL]";
+ return Messages.DEFAULT_META_EXPLICIT_BOOLEAN_OPTION_HANDLER.format();
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/FieldSetter.java b/args4j/args4j/src/org/kohsuke/args4j/spi/FieldSetter.java
index af946a7..c196e79 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/FieldSetter.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/FieldSetter.java
@@ -1,7 +1,6 @@
package org.kohsuke.args4j.spi;
-import org.kohsuke.args4j.spi.Setter;
-
+import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
/**
@@ -9,7 +8,7 @@ import java.lang.reflect.Field;
*
* @author Kohsuke Kawaguchi
*/
-final class FieldSetter implements Setter {
+public final class FieldSetter implements Setter {
private final Field f;
private final Object bean;
@@ -23,13 +22,22 @@ final class FieldSetter implements Setter {
}
public boolean isMultiValued() {
+ // a field can only store one value. a collection field is handled via MultiValueFieldSetter
return false;
}
+ public FieldSetter asFieldSetter() {
+ return new FieldSetter(bean,f);
+ }
+
+ public AnnotatedElement asAnnotatedElement() {
+ return f;
+ }
+
public void addValue(Object value) {
try {
f.set(bean,value);
- } catch (IllegalAccessException _) {
+ } catch (IllegalAccessException ex) {
// try again
f.setAccessible(true);
try {
@@ -39,4 +47,18 @@ final class FieldSetter implements Setter {
}
}
}
+
+ public Object getValue() {
+ try {
+ return f.get(bean);
+ } catch (IllegalAccessException ex) {
+ // try again
+ f.setAccessible(true);
+ try {
+ return f.get(bean);
+ } catch (IllegalAccessException e) {
+ throw new IllegalAccessError(e.getMessage());
+ }
+ }
+ }
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/FileOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/FileOptionHandler.java
index e1c23ab..ee08d84 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/FileOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/FileOptionHandler.java
@@ -11,19 +11,18 @@ import org.kohsuke.args4j.CmdLineParser;
*
* @author Kohsuke Kawaguchi
*/
-public class FileOptionHandler extends OptionHandler<File> {
+public class FileOptionHandler extends OneArgumentOptionHandler<File> {
public FileOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super File> setter) {
super(parser, option, setter);
}
@Override
- public int parseArguments(Parameters params) throws CmdLineException {
- setter.addValue(new File(params.getParameter(0)));
- return 1;
+ protected File parse(String argument) throws CmdLineException {
+ return new File(argument);
}
@Override
public String getDefaultMetaVariable() {
- return "FILE";
+ return Messages.DEFAULT_META_FILE_OPTION_HANDLER.format();
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/InetAddressOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/InetAddressOptionHandler.java
new file mode 100644
index 0000000..7dcf3e5
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/InetAddressOptionHandler.java
@@ -0,0 +1,36 @@
+package org.kohsuke.args4j.spi;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link InetAddress} {@link OptionHandler}.
+ *
+ * @author Dipen Lad
+ */
+public class InetAddressOptionHandler extends
+ OneArgumentOptionHandler<InetAddress> {
+ public InetAddressOptionHandler(CmdLineParser parser, OptionDef option,
+ Setter<? super InetAddress> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ protected InetAddress parse(String argument) throws CmdLineException {
+ try {
+ return InetAddress.getByName(argument);
+ } catch (UnknownHostException e) {
+ throw new CmdLineException(owner,
+ Messages.ILLEGAL_IP_ADDRESS, argument);
+ }
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return Messages.DEFAULT_META_INET_ADDRESS_OPTION_HANDLER.format();
+ }
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/MacAddressOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/MacAddressOptionHandler.java
new file mode 100644
index 0000000..d47cd06
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/MacAddressOptionHandler.java
@@ -0,0 +1,77 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link OptionHandler} that parses MAC address to byte[] of length 6.
+ *
+ * <p>
+ * The string representation of a MAC address can be of different forms, e.g.
+ *
+ * <pre>
+ * XXXXXXXXXXXX
+ * XX XX XX XX XX XX
+ * XX-XX-XX-XX-XX-XX
+ * XX:XX:XX:XX:XX:XX
+ * </pre>
+ *
+ * @author Tobias Stolzmann
+ */
+public class MacAddressOptionHandler extends OptionHandler<byte[]> {
+ public MacAddressOptionHandler(CmdLineParser parser, OptionDef option,
+ Setter<? super byte[]> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ public int parseArguments(Parameters params) throws CmdLineException {
+ String macString = params.getParameter(0);
+ String[] macStringArray = null;
+
+ if (macString.matches("[0-9a-fA-F]{12}"))
+ /*
+ * When entering this clause our MAC address is a hexadecimal string
+ * with 12 digit. Hence we have no delimiter to split. So we simply
+ * split after each two characters.
+ */
+ macStringArray = macString.split("(?<=\\G.{2})");
+ else if (macString.matches("([0-9a-fA-F]{1,2}[^0-9a-fA-F]+){5}[0-9a-fA-F]{1,2}"))
+ /*
+ * When entering this clause our MAC address is a in the form
+ * XX#XX#XX#XX#XX#XX where XX is a hexadecimal string with one or two
+ * digits and # is a delimiter which contains no hexadecimal digit.
+ * In most cases # is a dash (-), a colon (:) or a space ( ).
+ * We just need to split by our delimiter.
+ */
+ macStringArray = macString.split("[^0-9a-fA-F]+");
+ else
+ throw new CmdLineException(owner,
+ Messages.ILLEGAL_MAC_ADDRESS, macString);
+
+ byte[] mac = new byte[6];
+ for (int i = 0; i < 6; i++)
+ /*
+ * Yes, we really need to parse a short here... ;-)
+ * Explanation: All six MAC address parts are unsigned bytes in
+ * hexadecimal representation. They lay between 0x00 and 0xff
+ * respectively 0 and 255. The Java data type byte is signed. It
+ * lays between -128 and 127. Therefore we need to "convert" the
+ * upper half of our unsigned values to negative to obtain the
+ * correct bit representation (think of the two's complement). This
+ * is done best by parsing short (or int or long) and casting to
+ * byte.
+ */
+ mac[i] = (byte) Short.parseShort(macStringArray[i], 16);
+
+ setter.asFieldSetter().addValue(mac);
+ return 1;
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return Messages.DEFAULT_META_MAC_ADDRESS_OPTION_HANDLER.format();
+ }
+
+} \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/MapOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/MapOptionHandler.java
index 4502f78..03491f1 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/MapOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/MapOptionHandler.java
@@ -1,17 +1,32 @@
package org.kohsuke.args4j.spi;
+import java.util.HashMap;
import java.util.Map;
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.MapSetter;
-import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.*;
+/**
+ * Parses options into a {@link Map}.
+ *
+ * <pre><code>
+ * class Foo {
+ * {@literal @}Option(name="-P",handler={@link MapOptionHandler}.class)
+ * Map&lt;String,String&gt; args;
+ * }
+ * </code></pre>
+ *
+ * <p>
+ * With this, <code>-P x=1 -P y=2</code> parses to map of size {@code 2}.
+ * This option handler can be subtyped if you want to convert values to different types
+ * or to handle <code>key=value</code> in other formats, like <code>key:=value</code>.
+ * */
public class MapOptionHandler extends OptionHandler<Map<?,?>> {
public MapOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Map<?,?>> setter) {
super(parser, option, setter);
- }
+ if (setter.asFieldSetter()==null)
+ throw new IllegalArgumentException("MapOptionHandler can only work with fields");
+ }
@Override
public String getDefaultMetaVariable() {
@@ -20,13 +35,61 @@ public class MapOptionHandler extends OptionHandler<Map<?,?>> {
@Override
public int parseArguments(Parameters params) throws CmdLineException {
- MapSetter mapSetter = (MapSetter)setter;
- try {
- mapSetter.addValue(params.getParameter(0));
- } catch (RuntimeException e) {
- throw new CmdLineException(owner, e.getMessage());
- }
+ FieldSetter fs = setter.asFieldSetter();
+ Map v = (Map)fs.getValue();
+ if (v==null) {
+ v = createNewCollection(fs.getType());
+ fs.addValue(v);
+ }
+
+ addToMap(params.getParameter(0),v);
+
return 1;
}
+ /**
+ * Creates a new instance of the collection.
+ */
+ protected Map createNewCollection(Class<? extends Map> type) {
+ return new HashMap();
+ }
+
+ /**
+ * Encapsulates how a single string argument gets converted into key and value.
+ */
+ protected void addToMap(String argument, Map m) throws CmdLineException {
+ if (String.valueOf(argument).indexOf('=') == -1) {
+ throw new CmdLineException(owner,Messages.FORMAT_ERROR_FOR_MAP);
+ }
+
+ String mapKey;
+ String mapValue;
+
+ //Splitting off the key from the value
+ int idx = argument.indexOf('=');
+ if (idx>=0) {
+ mapKey = argument.substring(0, idx);
+ mapValue = argument.substring(idx + 1);
+ if (mapValue.length()==0)
+ // Kohsuke: I think this is a bad choice, but this is needed to remain backward compatible
+ mapValue = null;
+ } else {
+ mapKey = argument;
+ mapValue = null;
+ }
+
+ if (mapKey.length()==0) {
+ throw new CmdLineException(owner,Messages.MAP_HAS_NO_KEY);
+ }
+
+ addToMap(m, mapKey, mapValue);
+ }
+
+ /**
+ * This is the opportunity to convert values to some typed objects.
+ */
+ protected void addToMap(Map m, String key, String value) {
+ m.put(key,value);
+ }
+
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/Messages.java b/args4j/args4j/src/org/kohsuke/args4j/spi/Messages.java
index a49ae96..3bbbb79 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/Messages.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/Messages.java
@@ -1,27 +1,50 @@
package org.kohsuke.args4j.spi;
import java.text.MessageFormat;
+import java.util.Locale;
import java.util.ResourceBundle;
+import org.kohsuke.args4j.Localizable;
+
/**
* @author Kohsuke Kawaguchi
*/
-enum Messages {
+public enum Messages implements Localizable {
ILLEGAL_OPERAND,
ILLEGAL_CHAR,
ILLEGAL_BOOLEAN,
ILLEGAL_METHOD_SIGNATURE,
ILLEGAL_FIELD_SIGNATURE,
- ILLEGAL_LIST
+ ILLEGAL_LIST,
+ FORMAT_ERROR_FOR_MAP,
+ MAP_HAS_NO_KEY,
+ ILLEGAL_IP_ADDRESS,
+ ILLEGAL_PATTERN,
+ ILLEGAL_MAC_ADDRESS,
+ ILLEGAL_UUID,
+ ILLEGAL_PATH,
+ DEFAULT_META_EXPLICIT_BOOLEAN_OPTION_HANDLER,
+ DEFAULT_META_FILE_OPTION_HANDLER,
+ DEFAULT_META_INET_ADDRESS_OPTION_HANDLER,
+ DEFAULT_META_MAC_ADDRESS_OPTION_HANDLER,
+ DEFAULT_META_PATH_OPTION_HANDLER,
+ DEFAULT_META_PATTERN_OPTION_HANDLER,
+ DEFAULT_META_REST_OF_ARGUMENTS_HANDLER,
+ DEFAULT_META_STRING_ARRAY_OPTION_HANDLER,
+ DEFAULT_META_STRING_OPTION_HANDLER,
+ DEFAULT_META_SUB_COMMAND_HANDLER,
+ DEFAULT_META_URI_OPTION_HANDLER,
+ DEFAULT_META_URL_OPTION_HANDLER,
+ DEFAULT_META_UUID_OPTION_HANDLER
;
- private static ResourceBundle rb;
+ public String formatWithLocale( Locale locale, Object... args ) {
+ ResourceBundle localized = ResourceBundle.getBundle(Messages.class.getName(), locale);
+ return MessageFormat.format(localized.getString(name()),args);
+ }
+
public String format( Object... args ) {
- synchronized(Messages.class) {
- if(rb==null)
- rb = ResourceBundle.getBundle(Messages.class.getName());
- return MessageFormat.format(rb.getString(name()),args);
- }
+ return formatWithLocale(Locale.getDefault(),args);
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/Messages.properties b/args4j/args4j/src/org/kohsuke/args4j/spi/Messages.properties
index d98e0ae..e03bb6b 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/Messages.properties
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/Messages.properties
@@ -9,4 +9,44 @@ ILLEGAL_METHOD_SIGNATURE = \
ILLEGAL_FIELD_SIGNATURE = \
Field of type {0} isn't supported by args4j
ILLEGAL_LIST = \
- type of {0} is not a List \ No newline at end of file
+ type of {0} is not a List
+FORMAT_ERROR_FOR_MAP = \
+ An argument for setting a Map must contain a "="
+MAP_HAS_NO_KEY = \
+ A key must be set.
+ILLEGAL_IP_ADDRESS = \
+ "{0}" must be an IP address
+ILLEGAL_PATTERN = \
+ "{0}" must be a regular expression
+ILLEGAL_MAC_ADDRESS = \
+ "{0}" must be an MAC address
+ILLEGAL_UUID = \
+ "{0}" must be a UUID
+ILLEGAL_PATH = \
+ Failed to parse path "{0}"
+DEFAULT_META_EXPLICIT_BOOLEAN_OPTION_HANDLER = \
+ VALUE
+DEFAULT_META_FILE_OPTION_HANDLER = \
+ FILE
+DEFAULT_META_INET_ADDRESS_OPTION_HANDLER = \
+ IP ADDRESS
+DEFAULT_META_MAC_ADDRESS_OPTION_HANDLER = \
+ MAC ADDRESS
+DEFAULT_META_PATH_OPTION_HANDLER = \
+ PATH
+DEFAULT_META_PATTERN_OPTION_HANDLER = \
+ REGEX
+DEFAULT_META_REST_OF_ARGUMENTS_HANDLER = \
+ ARGS
+DEFAULT_META_STRING_ARRAY_OPTION_HANDLER = \
+ STRING[]
+DEFAULT_META_STRING_OPTION_HANDLER = \
+ VAL
+DEFAULT_META_SUB_COMMAND_HANDLER = \
+ CMD ARGS...
+DEFAULT_META_URI_OPTION_HANDLER = \
+ URI
+DEFAULT_META_URL_OPTION_HANDLER = \
+ URL
+DEFAULT_META_UUID_OPTION_HANDLER = \
+ UUID
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/Messages_de.properties b/args4j/args4j/src/org/kohsuke/args4j/spi/Messages_de.properties
index c99dc83..b416492 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/Messages_de.properties
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/Messages_de.properties
@@ -13,8 +13,36 @@ ILLEGAL_FIELD_SIGNATURE = \
ILLEGAL_OPERAND = \
"{1}" ist kein g\u00fcltiger Wert f\u00fcr "{0}"
ILLEGAL_BOOLEAN = \
- "{0}" ist kein g\u00fcltiger Boolscher Wert
+ "{0}" ist kein g\u00fcltiger Boolescher Wert
ILLEGAL_CHAR = \
"{0}" muss ein einzelnes Zeichen sein
ILLEGAL_LIST = \
- Der Typ von {0} ist keine List \ No newline at end of file
+ Der Typ von {0} ist keine List
+FORMAT_ERROR_FOR_MAP = \
+ Ein Argument f\u00fcr eine Map muss ein "=" enthalten
+MAP_HAS_NO_KEY = \
+ A Schl\u00fcssel muss gesetzt sein
+ILLEGAL_PATTERN = \
+ "{0}" muss ein regul\u00e4rer Ausdruck sein
+ILLEGAL_IP_ADDRESS = \
+ "{0}" ist keine g\u00fcltige IP-Adresse
+ILLEGAL_MAC_ADDRESS = \
+ "{0}" ist keine g\u00fcltige MAC-Adresse
+ILLEGAL_UUID = \
+ "{0}" ist keine g\u00fcltige UUID
+ILLEGAL_PATH = \
+ Pfad "{0}" ist nicht g\u00fcltig
+DEFAULT_META_EXPLICIT_BOOLEAN_OPTION_HANDLER = \
+ WERT
+DEFAULT_META_FILE_OPTION_HANDLER = \
+ DATEI
+DEFAULT_META_INET_ADDRESS_OPTION_HANDLER = \
+ IP ADRESSE
+DEFAULT_META_MAC_ADDRESS_OPTION_HANDLER = \
+ MAC ADRESSE
+DEFAULT_META_PATH_OPTION_HANDLER = \
+ PFAD
+DEFAULT_META_PATTERN_OPTION_HANDLER = \
+ REGEX
+DEFAULT_META_STRING_OPTION_HANDLER = \
+ WERT
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/Messages_en.properties b/args4j/args4j/src/org/kohsuke/args4j/spi/Messages_en.properties
new file mode 100644
index 0000000..78c56fb
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/Messages_en.properties
@@ -0,0 +1,3 @@
+# this file is intentionally empty to fall back to the default
+# which is the English locale
+
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/MethodSetter.java b/args4j/args4j/src/org/kohsuke/args4j/spi/MethodSetter.java
index e6454f5..66c7657 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/MethodSetter.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/MethodSetter.java
@@ -1,8 +1,8 @@
package org.kohsuke.args4j.spi;
-import org.kohsuke.args4j.spi.Setter;
import org.kohsuke.args4j.*;
+import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -29,14 +29,23 @@ public final class MethodSetter implements Setter {
}
public boolean isMultiValued() {
- return false;
+ // multiple values can be handled by calling methods repeatedly
+ return true;
+ }
+
+ public FieldSetter asFieldSetter() {
+ return null;
+ }
+
+ public AnnotatedElement asAnnotatedElement() {
+ return m;
}
public void addValue(Object value) throws CmdLineException {
try {
try {
m.invoke(bean,value);
- } catch (IllegalAccessException _) {
+ } catch (IllegalAccessException ex) {
// try again
m.setAccessible(true);
try {
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/MultiFileOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/MultiFileOptionHandler.java
new file mode 100644
index 0000000..82c6046
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/MultiFileOptionHandler.java
@@ -0,0 +1,18 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+import java.io.File;
+
+/**
+ * Takes a classpath like option ("-cp a.jar;b.jar;c") and maps them to a collection of {@link File}.
+ *
+ * @author kmahoney
+ */
+public class MultiFileOptionHandler extends DelimitedOptionHandler<File> {
+ protected static String sysPathSeperator = System.getProperty("path.separator");
+ public MultiFileOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super File> setter) {
+ super(parser, option, setter, sysPathSeperator, new FileOptionHandler(parser, option, setter));
+ }
+} \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/MultiPathOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/MultiPathOptionHandler.java
new file mode 100644
index 0000000..97e3c06
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/MultiPathOptionHandler.java
@@ -0,0 +1,18 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+import java.nio.file.Path;
+
+/**
+ * Takes a classpath like option ("-cp a.jar;b.jar;c") and maps them to a collection of {@link Path}.
+ *
+ * @author kmahoney
+ */
+public class MultiPathOptionHandler extends DelimitedOptionHandler<Path> {
+ protected static String sysPathSeperator = System.getProperty("path.separator");
+ public MultiPathOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Path> setter) {
+ super(parser, option, setter, sysPathSeperator, new PathOptionHandler(parser, option, setter));
+ }
+} \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/MultiValueFieldSetter.java b/args4j/args4j/src/org/kohsuke/args4j/spi/MultiValueFieldSetter.java
index 7457070..59dc92e 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/MultiValueFieldSetter.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/MultiValueFieldSetter.java
@@ -1,8 +1,8 @@
package org.kohsuke.args4j.spi;
-import org.kohsuke.args4j.spi.Setter;
import org.kohsuke.args4j.*;
+import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -14,7 +14,7 @@ import java.util.List;
*
* @author Kohsuke Kawaguchi
*/
-final class MultiValueFieldSetter implements Setter {
+final class MultiValueFieldSetter implements Setter {
private final Object bean;
private final Field f;
@@ -30,6 +30,14 @@ final class MultiValueFieldSetter implements Setter {
return true;
}
+ public FieldSetter asFieldSetter() {
+ return new FieldSetter(bean,f);
+ }
+
+ public AnnotatedElement asAnnotatedElement() {
+ return f;
+ }
+
public Class getType() {
// TODO: compute this correctly
Type t = f.getGenericType();
@@ -45,7 +53,7 @@ final class MultiValueFieldSetter implements Setter {
public void addValue(Object value) {
try {
doAddValue(bean, value);
- } catch (IllegalAccessException _) {
+ } catch (IllegalAccessException ex) {
// try again
f.setAccessible(true);
try {
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/OneArgumentOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/OneArgumentOptionHandler.java
index 6501f8f..0cdc79b 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/OneArgumentOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/OneArgumentOptionHandler.java
@@ -29,7 +29,7 @@ public abstract class OneArgumentOptionHandler<T> extends OptionHandler<T> {
setter.addValue(value);
}
catch (NumberFormatException ex) {
- throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND.format(params.getParameter(-1),token));
+ throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND, params.getParameter(-1), token);
}
return 1;
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/OptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/OptionHandler.java
index 3697c5c..7e9ddda 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/OptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/OptionHandler.java
@@ -1,11 +1,13 @@
package org.kohsuke.args4j.spi;
-import java.util.ResourceBundle;
-
-import org.kohsuke.args4j.OptionDef;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.NamedOptionDef;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.ParserProperties;
+import org.kohsuke.args4j.OptionHandlerRegistry;
+
+import java.util.Collection;
+import java.util.ResourceBundle;
/**
@@ -16,10 +18,18 @@ import org.kohsuke.args4j.NamedOptionDef;
*
* <p>
* Implementation of this class needs to be registered to args4j by using
- * {@link CmdLineParser#registerHandler(Class,Class)}
+ * {@link OptionHandlerRegistry#registerHandler(Class,Class)}.
+ * For registration to work, subclasses will need to implement the constructor
+ * with the signature
+ * {@link OptionHandler#OptionHandler(CmdLineParser, OptionDef, Setter)}.
*
* @param <T>
- * The type of the field that this {@link OptionHandler} works with.
+ * The {@code component} type of the field that this {@link OptionHandler} works with.
+ * When I say "component", I mean a field that can hold multiple values
+ * (such as {@link Collection} or array). This should refer to its component time.
+ *
+ * {@link Setter} implementations abstract away multi-value-ness by allowing {@link OptionHandler}
+ * to invoke its {@link Setter#addValue(Object)} multiple times.
*
* @author Kohsuke Kawaguchi
*/
@@ -53,19 +63,23 @@ public abstract class OptionHandler<T> {
* The object is valid only during the method call.
*
* @return
- * The number of arguments consumed. For example, return 0
- * if this option doesn't take any parameter.
+ * The number of arguments consumed. (For example, returns {@code 0}
+ * if this option doesn't take any parameters.)
*/
public abstract int parseArguments( Parameters params ) throws CmdLineException;
/**
* Gets the default meta variable name used to print the usage screen.
+ *
+ * The value returned by this method can be a reference in the
+ * {@code ResourceBundle}, if one was passed to
+ * {@link CmdLineParser}.
*
- * @return null to hide a meta variable.
+ * @return {@code null} to hide a meta variable.
*/
public abstract String getDefaultMetaVariable();
- public final String getMetaVariable(ResourceBundle rb) {
+ public String getMetaVariable(ResourceBundle rb) {
String token = option.metaVar();
if(token.length()==0)
token = getDefaultMetaVariable();
@@ -80,12 +94,28 @@ public abstract class OptionHandler<T> {
return token;
}
+ /**
+ * Get string representing usage for this option, of the form "name metaval",
+ * e.g. "-foo VALUE" or "--foo VALUE"
+ * @param rb ResourceBundle to get localized version of meta string
+ */
public final String getNameAndMeta(ResourceBundle rb) {
- String str = option.isArgument() ? "" : option.toString();
+ return getNameAndMeta(rb, ParserProperties.defaults());
+ }
+
+ /**
+ * Get string representing usage for this option, of the form "name metaval" or "name=metaval,
+ * e.g. "--foo VALUE" or "--foo=VALUE"
+ * @param rb ResourceBundle to get localized version of meta string
+ * @param properties
+ * Affects the formatting behaviours.
+ */
+ public final String getNameAndMeta(ResourceBundle rb, ParserProperties properties) {
+ String str = option.isArgument() ? "" : option.toString();
String meta = getMetaVariable(rb);
if (meta != null) {
if (str.length() > 0) {
- str += " ";
+ str += properties.getOptionValueDelimiter();
}
str += meta;
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/OptionImpl.java b/args4j/args4j/src/org/kohsuke/args4j/spi/OptionImpl.java
index e390fbc..d97b2b5 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/OptionImpl.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/OptionImpl.java
@@ -7,12 +7,23 @@ import org.kohsuke.args4j.Option;
* @author Jan Materne
*/
public class OptionImpl extends AnnotationImpl implements Option {
- public OptionImpl(ConfigElement ce) throws ClassNotFoundException {
- super(Option.class,ce);
- name = ce.name;
- }
- public String name;
- public String name() {
- return name;
- }
+ public OptionImpl(ConfigElement ce) throws ClassNotFoundException {
+ super(Option.class, ce);
+ name = ce.name;
+ }
+
+ public String name;
+ public String name() {
+ return name;
+ }
+
+ public String[] depends;
+ public String[] depends() {
+ return depends;
+ }
+
+ public String[] forbids;
+ public String[] forbids() {
+ return depends;
+ }
} \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/Parameters.java b/args4j/args4j/src/org/kohsuke/args4j/spi/Parameters.java
index 9fc2e6b..e0876fb 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/Parameters.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/Parameters.java
@@ -16,12 +16,12 @@ public interface Parameters {
*
* @param idx
* specifying 0 will retrieve the token next to the option.
- * For example, if the command line looks like "-o abc -d x",
- * then <code>getParameter(0)</code> for "-o" returns "abc"
- * and <code>getParameter(1)</code> will return "-d".
+ * For example, if the command line looks like <code>-o abc -d x</code>,
+ * then {@code getParameter(0)} for <code>-o</code> returns {@code abc}
+ * and {@code getParameter(1)} will return <code>-d</code>.
*
* @return
- * Always return non-null valid String. If an attempt is
+ * Always return non-{@code null} valid {@code String}. If an attempt is
* made to access a non-existent index, this method throws
* appropriate {@link org.kohsuke.args4j.CmdLineException}.
*/
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/PathOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/PathOptionHandler.java
new file mode 100644
index 0000000..9f13f15
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/PathOptionHandler.java
@@ -0,0 +1,34 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Takes a single argument to the option and maps that to {@link Path}.
+ *
+ * @author kmahoney
+ */
+public class PathOptionHandler extends OneArgumentOptionHandler<Path> {
+ public PathOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Path> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ protected Path parse(String argument) throws NumberFormatException, CmdLineException {
+ try {
+ return Paths.get(argument);
+ }
+ catch (Exception e) {
+ throw new CmdLineException(owner, Messages.ILLEGAL_PATH, argument);
+ }
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return Messages.DEFAULT_META_PATH_OPTION_HANDLER.format();
+ }
+} \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/PatternOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/PatternOptionHandler.java
new file mode 100644
index 0000000..7c27b85
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/PatternOptionHandler.java
@@ -0,0 +1,44 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.kohsuke.args4j.spi;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * A regex option handler.
+ * @author Stephan Fuhrmann
+ */
+public class PatternOptionHandler extends OptionHandler<Pattern> {
+
+ public PatternOptionHandler(CmdLineParser parser, OptionDef option, Setter<Pattern> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ public int parseArguments(Parameters params) throws CmdLineException {
+ String s = params.getParameter(0);
+ Pattern p;
+ try {
+ p = Pattern.compile(s);
+ }
+ catch (PatternSyntaxException x) {
+ throw new CmdLineException(owner, Messages.ILLEGAL_PATTERN.format(option.toString(), s));
+ }
+ setter.addValue(p);
+ return 1;
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return Messages.DEFAULT_META_PATTERN_OPTION_HANDLER.format();
+ }
+
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/RestOfArgumentsHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/RestOfArgumentsHandler.java
index 6cfdd7b..ba0a35e 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/RestOfArgumentsHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/RestOfArgumentsHandler.java
@@ -11,8 +11,9 @@ import org.kohsuke.args4j.CmdLineException;
* <p>
* Used with {@link Argument}, this implements a semantics where
* non-option token causes the option parsing to terminate.
- * An example of this is ssh(1), where "ssh -p 222 abc" will treat "-p" as an option
- * to ssh but "ssh abc -p 222" is considered to have no option for ssh.
+ * An example of this is <tt>ssh(1)</tt>, where <code>ssh -p 222 abc</code> will treat
+ * <code>-p</code> as an option to <tt>ssh</tt>, but <code>ssh abc -p 222</code> is
+ * considered to have no option for <tt>ssh</tt>.
*
* @author Kohsuke Kawaguchi
*/
@@ -28,6 +29,6 @@ public class RestOfArgumentsHandler extends OptionHandler<String> {
}
public String getDefaultMetaVariable() {
- return "ARGS";
+ return Messages.DEFAULT_META_REST_OF_ARGUMENTS_HANDLER.format();
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/Setter.java b/args4j/args4j/src/org/kohsuke/args4j/spi/Setter.java
index ac256d4..258eab9 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/Setter.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/Setter.java
@@ -1,10 +1,19 @@
package org.kohsuke.args4j.spi;
+import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.Option;
+
+import java.lang.reflect.AnnotatedElement;
/**
* Abstraction of the value setter.
*
+ * <p>
+ * This abstracts away the difference between a field and a setter method,
+ * which object we are setting the value to,
+ * and/or how we handle collection fields differently.
+ *
* @author Kohsuke Kawaguchi
*/
public interface Setter<T> {
@@ -23,7 +32,44 @@ public interface Setter<T> {
Class<T> getType();
/**
- * Whether this setter is instrinsically multi-valued.
+ * Whether this setter is intrinsically multi-valued.
+ *
+ * <p>
+ * When parsing arguments (instead of options), intrinsically multi-valued setters consume
+ * all the remaining arguments. So, if the setter can store multiple values,
+ * this method should return {@code true}.
+ *
+ * <p>
+ * This characteristics of a setter doesn't affect option parsing at all; any options can be
+ * specified multiple times. In many cases, this is a no-op--but when your shell script expands
+ * multiple environment variables (each of which may contain options), tolerating such
+ * redundant options can be useful.
*/
boolean isMultiValued();
+
+ /**
+ * If this setter encapsulates a field, return the direct access to that field as
+ * {@link FieldSetter}. This method serves two purposes:
+ *
+ * <ol>
+ * <li>This lets {@link OptionHandler}s bypass the collection/array handling of fields.
+ * This is useful if you're defining an option handler that produces array or collection
+ * from a single argument.</li>
+ * <li>The other is to retrieve the current value of the field (via {@link FieldSetter#getValue()}).</li>
+ * </ol>
+ *
+ * @return
+ * {@code null} if this setter wraps a method.
+ */
+ FieldSetter asFieldSetter();
+
+ /**
+ * Returns the {@link AnnotatedElement} by which you can access annotations written on this setter.
+ *
+ * This is the same {@link AnnotatedElement} that had {@link Option}/{@link Argument}.
+ *
+ * <p>
+ * This enables {@link OptionHandler} to further tweak its behavior based on additional annotations.
+ */
+ AnnotatedElement asAnnotatedElement();
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/Setters.java b/args4j/args4j/src/org/kohsuke/args4j/spi/Setters.java
index 0300053..8beeb01 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/Setters.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/Setters.java
@@ -1,13 +1,11 @@
package org.kohsuke.args4j.spi;
-import org.kohsuke.args4j.MapSetter;
import org.kohsuke.args4j.CmdLineParser;
import java.lang.reflect.Field;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.List;
-import java.util.Map;
/**
* Factory of {@link Setter}s.
@@ -15,6 +13,11 @@ import java.util.Map;
* @author Kohsuke Kawaguchi
*/
public class Setters {
+
+ private Setters() {
+ // no instance allowed
+ }
+
public static Setter create(CmdLineParser parser, AccessibleObject fieldOrMethod, Object bean) {
if (fieldOrMethod instanceof Method) {
return new MethodSetter(parser,bean,(Method) fieldOrMethod);
@@ -24,10 +27,10 @@ public class Setters {
}
public static Setter create(Field f, Object bean) {
+ if(f.getType().isArray())
+ return new ArrayFieldSetter(bean,f);
if(List.class.isAssignableFrom(f.getType()))
return new MultiValueFieldSetter(bean,f);
- else if(Map.class.isAssignableFrom(f.getType()))
- return new MapSetter(bean,f);
else
return new FieldSetter(bean,f);
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/StopOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/StopOptionHandler.java
index 16be42f..8176fe9 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/StopOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/StopOptionHandler.java
@@ -5,29 +5,30 @@ import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.OptionDef;
/**
- * {@link OptionHandler} for the option terminator "--".
+ * {@link OptionHandler} for the option terminator <tt>--</tt>.
*
* <p>
* This {@link OptionHandler} can be used to implement the special token
- * "--" that indicates that the rest of tokens are not options, but arguments.
+ * <tt>--</tt> that indicates that the rest of tokens are not options, but arguments.
*
* <p>
* For example, if you have the following class:
*
* <pre>
+ * <code>
* class Foo {
- * &#64;Argument
- * &#64;Option(name="--",handler={@link StopOptionHandler}.class)
- * List&lt;String> args;
+ * {@literal @}Argument
+ * {@literal @}Option(name="--",handler={@link StopOptionHandler}.class)
+ * List&lt;String&gt; args;
*
- * &#64;Option(name="-n")
+ * {@literal @}Option(name="-n")
* int n;
* }
- * </pre>
+ * </code></pre>
*
* <p>
- * The command line {@code -n 5 abc def} would parse into n=5, args={"abc",def"},
- * but {@code -- -n 5 abc def} would parse into n=0, args={"-n","5","abc","def"}.
+ * The command line <code>-n 5 abc def</code> would parse into {@code n=5, args={"abc",def"}},
+ * but <code> -- -n 5 abc def</code> would parse into {@code n=0, args={"-n","5","abc","def"}}.
*
* @author Kohsuke Kawaguchi
*/
@@ -44,6 +45,6 @@ public class StopOptionHandler extends OptionHandler<String> {
@Override
public String getDefaultMetaVariable() {
- return "ARGUMENTS";
+ return Messages.DEFAULT_META_REST_OF_ARGUMENTS_HANDLER.format();
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/StringArrayOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/StringArrayOptionHandler.java
index 2ae31ae..f9bab79 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/StringArrayOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/StringArrayOptionHandler.java
@@ -4,76 +4,69 @@ import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.OptionDef;
-import java.util.ArrayList;
-
/**
* <p>
- * An {@link OptionHandler} for handling {@link String[]} types. Can handle arrays of strings.
+ * An {@link OptionHandler} for greedily mapping a list of tokens into a collection of {@link String}s
+ * (such as {@code String[]}, {@code List<String>}, etc.).
* </p>
- * <p>
+ *
* <h1>How it works:</h1>
- * Example for parameter -s, which is String[] type:<br>
- * java -jar aaa.jar -s banan hruska jablko<br>
- * java -jar aaa.jar -s banan "hruska jablko"<br>
- * java -jar aaa.jar -s "banan hruska jablko"<br>
- * java -jar aaa.jar -s banan hruska jablko -l 4 -r<br>
- * java -jar aaa.jar -t 222 -s banan hruska jablko -r<br><br>
- * It will handle all of these posibilites. This OptionHandler scans for parameter which begins
- * with "-". If it found it, it will stop.
- * </p>
*
- * @author PlainText,LuVar
+ * <p>
+ * Example for parameter {@code -s}, which is type {@code String[]}:</p>
+ *
+ * <pre>{@code
+ * java -jar aaa.jar -s banan hruska jablko
+ * java -jar aaa.jar -s banan "hruska jablko"
+ * java -jar aaa.jar -s "banan hruska jablko"
+ * java -jar aaa.jar -s banan hruska jablko -l 4 -r
+ * java -jar aaa.jar -t 222 -s banan hruska jablko -r
+ * }</pre>
+ *
+ * <p>
+ * All of them result in a single string array that contains three tokens:
+ * <code>banan</code>, <code>hruska</code>, and <code>jablko</code>.</p>
+ *
+ * <p>
+ * This {@code OptionHandler} scans for parameter which begins with <tt>-</tt>. If found, it will stop.</p>
*
+ * @author PlainText,LuVar
*/
-public class StringArrayOptionHandler extends OptionHandler<String[]> {
+public class StringArrayOptionHandler extends OptionHandler<String> {
- public StringArrayOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super String[]> setter) {
+ public StringArrayOptionHandler(CmdLineParser parser, OptionDef option, Setter<String> setter) {
super(parser, option, setter);
}
/**
- * <p>
- * Returns "STRING[]".
- * </p>
+ * Returns {@code "STRING[]"}.
*
* @return return "STRING[]";
*/
@Override
public String getDefaultMetaVariable() {
- return "STRING[]";
+ return Messages.DEFAULT_META_STRING_ARRAY_OPTION_HANDLER.format();
}
/**
- * <p>
- * Tryies to parse String[] argument from {@link Parameters}.
- * </p>
+ * Tries to parse {@code String[]} argument from {@link Parameters}.
*/
@Override
public int parseArguments(Parameters params) throws CmdLineException {
- int counter = 0;
- ArrayList<String> values = new ArrayList<String>();
- while(true) {
- String param;
- try {
- param = params.getParameter(counter);
- } catch (CmdLineException ex) {
- break;
- }
- if(param.startsWith("-")) {
+ int counter=0;
+ for (; counter<params.size(); counter++) {
+ String param = params.getParameter(counter);
+
+ if(param.startsWith("-")) {
break;
}
- for (String str : param.split(" ")) {
- values.add(str);
- }
- counter++;
- }//while true
+ for (String p : param.split(" ")) {
+ setter.addValue(p);
+ }
+ }
- // to work around a javac bug in Java1.5, we need to first assign this to
- // the raw type.
- Setter s = this.setter;
- s.addValue(values.toArray(new String[values.size()]));
- return counter;
+ return counter;
}
} \ No newline at end of file
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/StringOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/StringOptionHandler.java
index 0a9ff09..1b7876f 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/StringOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/StringOptionHandler.java
@@ -22,6 +22,6 @@ public class StringOptionHandler extends OptionHandler<String> {
@Override
public String getDefaultMetaVariable() {
- return "VAL";
+ return Messages.DEFAULT_META_STRING_OPTION_HANDLER.format();
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommand.java b/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommand.java
new file mode 100644
index 0000000..3342a84
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommand.java
@@ -0,0 +1,27 @@
+package org.kohsuke.args4j.spi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Specifies a single sub-command.
+ *
+ * @see SubCommandHandler
+ * @author Kohsuke Kawaguchi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SubCommand {
+ /**
+ * Name of the sub-command.
+ * This must appear as-is in the command line for this sub-command to be activated.
+ */
+ String name();
+
+ /**
+ * The implementation class of this sub command.
+ *
+ * When a sub-command is selected, this class is instantiated and the rest of the arguments
+ * will be parsed against this new instance.
+ */
+ Class<?> impl();
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommandHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommandHandler.java
new file mode 100644
index 0000000..d457a1d
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommandHandler.java
@@ -0,0 +1,166 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+import org.kohsuke.args4j.OptionDef;
+
+import java.util.AbstractList;
+import java.util.ResourceBundle;
+
+/**
+ * {@link OptionHandler} used with {@link Argument} for parsing typical "sub-command" pattern.
+ *
+ * <p>
+ * The "sub-command" pattern refers to the design of the command line like <tt>git</tt> and <tt>svn</tt>, where
+ * the first argument to the command designates a sub-command (say <code>git checkout</code>), then everything
+ * that follows afterward are parsed by this sub-command (which is usually different depending on
+ * which sub-command was selected.)
+ *
+ * <p>
+ * This {@link OptionHandler} models this design pattern with the {@link SubCommands} annotation.
+ * See the following example:
+ *
+ * <pre>{@code
+ * class Git {
+ * &#64;Argument(handler={@link SubCommandHandler}.class)
+ * &#64;SubCommands({
+ * &#64;SubCommand(name="checkout", impl=CheckoutCommand.class),
+ * &#64;SubCommand(name="commit", impl=CommitCommand.class),
+ * ...
+ * })
+ * Command cmd;
+ *
+ * &#64;Option(name="-r")
+ * boolean recursive;
+ *
+ * public static void main(String[] args) {
+ * Git git = new Git();
+ * new CmdLineParser(git).parseArgument(args);
+ * git.cmd.execute();
+ * }
+ * }
+ *
+ * class CheckoutCommand {
+ * &#64;Option(name="-a")
+ * boolean all;
+ *
+ * ...
+ * }
+ * }</pre>
+ *
+ * <p>
+ * An example of legal command line option for this is <code>-r checkout -a</code>.
+ *
+ * <ul>
+ * <li>
+ * {@link SubCommand} only works with {@link Argument} and not with {@link Option}.
+ *
+ * <li>
+ * The same field/setter must be also annotated with {@link SubCommands} that specify possible sub-commands.
+ *
+ * <li>
+ * Any {@link Option}s that you define in the <tt>Git</tt> class above can parse options that appear
+ * prior to the sub-command name. This is useful for defining global options that work across sub-commands.
+ *
+ * <li>
+ * The matching sub-command implementation gets instantiated with the default constructor,
+ * then a new {@link CmdLineParser} will be created to parse its annotations.
+ *
+ * <li>
+ * The rest of the arguments that follow the sub-command will be parsed with this new {@link CmdLineParser}
+ *
+ * <li>
+ * The fully populated sub-command instance is set as the value.
+ * </ul>
+ *
+ * <p>
+ * This class defines a number of protected methods that allow subtypes to customize various parts of the
+ * behaviours. This should also serve as an example if you want to combine this with more sophisticated
+ * sub-command lookup, such as through META-INF/services, <a href="http://sezpoz.java.net/">sezpoz</a>,
+ * or <a href="https://github.com/jenkinsci/lib-annotation-indexer">annotation indexer</a>.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class SubCommandHandler extends OptionHandler<Object> {
+ private final SubCommands commands;
+
+ public SubCommandHandler(CmdLineParser parser, OptionDef option, Setter<Object> setter) {
+ super(parser, option, setter);
+ commands = setter.asAnnotatedElement().getAnnotation(SubCommands.class);
+ if (commands==null)
+ throw new IllegalStateException("SubCommandHandler must be used with @SubCommands annotation");
+ }
+
+ @Override
+ public int parseArguments(Parameters params) throws CmdLineException {
+ String subCmd = params.getParameter(0);
+
+ for (SubCommand c : commands.value()) {
+ if (c.name().equals(subCmd)) {
+ setter.addValue(subCommand(c,params));
+ return params.size(); // consume all the remaining tokens
+ }
+ }
+
+ return fallback(subCmd);
+ }
+
+ protected int fallback(String subCmd) throws CmdLineException {
+ throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND, option.toString(), subCmd);
+ }
+
+ protected Object subCommand(SubCommand c, final Parameters params) throws CmdLineException {
+ Object subCmd = instantiate(c);
+ CmdLineParser p = configureParser(subCmd,c);
+ p.parseArgument(new AbstractList<String>() {
+ @Override
+ public String get(int index) {
+ try {
+ return params.getParameter(index+1);
+ } catch (CmdLineException e) {
+ // invalid index was accessed.
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ @Override
+ public int size() {
+ return params.size()-1;
+ }
+ });
+ return subCmd;
+ }
+
+ protected CmdLineParser configureParser(Object subCmd, SubCommand c) {
+ return new CmdLineParser(subCmd);
+ }
+
+ protected Object instantiate(SubCommand c) {
+ try {
+ return c.impl().newInstance();
+ } catch (InstantiationException e) {
+ throw new IllegalStateException("Failed to instantiate "+c,e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Failed to instantiate "+c,e);
+ }
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ StringBuffer rv = new StringBuffer();
+ rv.append("[");
+ for (SubCommand sc : commands.value()) {
+ rv.append(sc.name()).append(" | ");
+ }
+ rv.delete(rv.length()-3, rv.length());
+ rv.append("]");
+ return rv.toString();
+ }
+
+ @Override
+ public String getMetaVariable(ResourceBundle rb) {
+ return getDefaultMetaVariable();
+ }
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommands.java b/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommands.java
new file mode 100644
index 0000000..e51af4b
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/SubCommands.java
@@ -0,0 +1,18 @@
+package org.kohsuke.args4j.spi;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Collection of {@link SubCommand}s that define possible sub-commands.
+ *
+ * @see SubCommandHandler
+ * @author Kohsuke Kawaguchi
+ */
+@Target({ElementType.FIELD,ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SubCommands {
+ SubCommand[] value();
+}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/URIOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/URIOptionHandler.java
index 3249b93..c563913 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/URIOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/URIOptionHandler.java
@@ -4,8 +4,6 @@ import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.OptionDef;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
@@ -26,12 +24,12 @@ public class URIOptionHandler extends OptionHandler<URI> {
setter.addValue(new URI(param));
return 1;
} catch (URISyntaxException e) {
- throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND.format(params.getParameter(-1),param));
+ throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND, params.getParameter(-1), param);
}
}
@Override
public String getDefaultMetaVariable() {
- return "URI";
+ return Messages.DEFAULT_META_URI_OPTION_HANDLER.format();
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/URLOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/URLOptionHandler.java
index 64cd28a..b801e61 100644
--- a/args4j/args4j/src/org/kohsuke/args4j/spi/URLOptionHandler.java
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/URLOptionHandler.java
@@ -24,13 +24,13 @@ public class URLOptionHandler extends OptionHandler<URL> {
setter.addValue(new URL(param));
return 1;
} catch (MalformedURLException e) {
- throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND.format(
- params.getParameter(-1),param));
+ throw new CmdLineException(owner, Messages.ILLEGAL_OPERAND,
+ params.getParameter(-1), param);
}
}
@Override
public String getDefaultMetaVariable() {
- return "URL";
+ return Messages.DEFAULT_META_URL_OPTION_HANDLER.format();
}
}
diff --git a/args4j/args4j/src/org/kohsuke/args4j/spi/UuidOptionHandler.java b/args4j/args4j/src/org/kohsuke/args4j/spi/UuidOptionHandler.java
new file mode 100644
index 0000000..1dc11c7
--- /dev/null
+++ b/args4j/args4j/src/org/kohsuke/args4j/spi/UuidOptionHandler.java
@@ -0,0 +1,38 @@
+package org.kohsuke.args4j.spi;
+
+import java.util.UUID;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link UUID} {@link OptionHandler}.
+ *
+ * @author Tobias Stolzmann
+ * @see UUID#fromString(String)
+ */
+public class UuidOptionHandler extends
+ OneArgumentOptionHandler<UUID> {
+ public UuidOptionHandler(CmdLineParser parser, OptionDef option,
+ Setter<? super UUID> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ protected UUID parse(String argument) throws CmdLineException {
+ try {
+ if (argument.startsWith("{")) argument=argument.substring(1);
+ if (argument.endsWith("}")) argument=argument.substring(0,argument.length()-1);
+ return UUID.fromString(argument);
+ } catch (IllegalArgumentException e) {
+ throw new CmdLineException(owner,
+ Messages.ILLEGAL_UUID, argument);
+ }
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return Messages.DEFAULT_META_UUID_OPTION_HANDLER.format();
+ }
+}
diff --git a/args4j/args4j/test/ExampleTest.java b/args4j/args4j/test/ExampleTest.java
index 85df342..e825eb0 100644
--- a/args4j/args4j/test/ExampleTest.java
+++ b/args4j/args4j/test/ExampleTest.java
@@ -1,11 +1,9 @@
-import java.io.File;
-
import junit.framework.TestCase;
+import org.kohsuke.args4j.*;
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.ExampleMode;
-import org.kohsuke.args4j.Option;
+import java.io.File;
+import java.net.InetAddress;
+import java.util.Locale;
/**
* Tests {@link CmdLineParser#printExample(ExampleMode)}
@@ -13,15 +11,36 @@ import org.kohsuke.args4j.Option;
* @author Kohsuke Kawaguchi
*/
public class ExampleTest extends TestCase {
+ // DOr sort test, start with these not in alphabetical order
+
+ @Option(name = "-h", usage = "this is H", forbids={"-b", "-c"})
+ boolean h;
+
@Option(required = true, name = "-a", usage = "this is X")
int x;
@Option(name = "-b", usage = "this is Y", metaVar = "<output>")
File y;
+ @Option(name = "-c", usage = "this is Z")
+ InetAddress z;
+
+ private Locale oldDefault;
+
+ @Override
+ public void setUp() {
+ oldDefault = Locale.getDefault();
+ Locale.setDefault(Locale.ENGLISH);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ Locale.setDefault(oldDefault);
+ }
+
public void testPrintExampleModeAll() {
String s = new CmdLineParser(this).printExample(ExampleMode.ALL);
- assertEquals(" -a N -b <output>", s);
+ assertEquals(" -a N -b <output> -c IP ADDRESS -h", s);
}
public void testPrintExampleModeRequired() {
@@ -31,9 +50,10 @@ public class ExampleTest extends TestCase {
public void testParsingAllArgs() throws Exception {
CmdLineParser parser = new CmdLineParser(this);
- parser.parseArgument("-a", "1", "-b", "foo");
+ parser.parseArgument("-a", "1", "-b", "foo", "-c", "1.2.3.4");
assertEquals(1, x);
assertEquals(new File("foo"), y);
+ assertEquals(InetAddress.getByName("1.2.3.4"), z);
}
public void testParsingOnlyRequiredArgs() throws Exception {
@@ -41,6 +61,7 @@ public class ExampleTest extends TestCase {
parser.parseArgument("-a", "1");
assertEquals(1, x);
assertNull(y);
+ assertNull(z);
}
public void testParsingMissingRequiredArgs() throws Exception {
@@ -53,4 +74,21 @@ public class ExampleTest extends TestCase {
assertEquals("Option \"-a\" is required", e.getMessage());
}
}
+
+ public void testForbidArgs() throws Exception {
+ CmdLineParser parser = new CmdLineParser(this);
+ try {
+ parser.parseArgument("-h", "-a", "2", "-b", "1");
+ fail("Should have thrown an exception because"
+ + " arg 'h' forbids 'b'");
+ } catch (CmdLineException e) {
+ assertEquals("option \"-h\" cannot be used with the option(s) [-b, -c]", e.getMessage());
+ }
+ }
+
+ public void testNoOptionsSort() {
+ ParserProperties properties = ParserProperties.defaults().withOptionSorter(null);
+ String s = new CmdLineParser(this, properties).printExample(ExampleMode.ALL);
+ assertEquals(" -h -a N -b <output> -c IP ADDRESS", s);
+ }
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/Aliased.java b/args4j/args4j/test/org/kohsuke/args4j/Aliased.java
index 34f2488..837796c 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/Aliased.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/Aliased.java
@@ -1,7 +1,5 @@
package org.kohsuke.args4j;
-import org.kohsuke.args4j.Option;
-
public class Aliased {
@Option(name="-str",aliases={ "--long-str" },usage="set a string",metaVar="METAVAR")
public String str;
diff --git a/args4j/args4j/test/org/kohsuke/args4j/AliasedTest.java b/args4j/args4j/test/org/kohsuke/args4j/AliasedTest.java
index 2dbc6f0..f4ec88f 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/AliasedTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/AliasedTest.java
@@ -14,10 +14,9 @@ public class AliasedTest extends Args4JTestBase<Aliased> {
} catch (CmdLineException e) {
String expectedError = "Option \"-str (--long-str)\" takes an operand";
String expectedUsage = " -str (--long-str) METAVAR : set a string";
- String errorMessage = e.getMessage();
String[] usageLines = getUsageMessage();
assertUsageLength(1);
- assertTrue("Got wrong error message: " + errorMessage, errorMessage.startsWith(expectedError));
+ assertErrorMessagePrefix(expectedError, e);
assertEquals("Got wrong usage message", expectedUsage, usageLines[0]);
}
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/Args4JTestBase.java b/args4j/args4j/test/org/kohsuke/args4j/Args4JTestBase.java
index 61ef0fd..fc7c174 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/Args4JTestBase.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/Args4JTestBase.java
@@ -20,8 +20,6 @@ public abstract class Args4JTestBase<T> extends TestCase {
CmdLineParser parser;
String[] args;
T testObject;
-
- private Locale defaultLocale;
/**
* Specifies which concrete object to return as test object.
@@ -38,23 +36,12 @@ public abstract class Args4JTestBase<T> extends TestCase {
}
/**
- * Returns the Locale to use for the tests.
- * Defaults to use the US-Locale but should be overwritten by classes
- * which tests I18N.
- */
- public Locale getLocale() {
- return Locale.US;
- }
-
- /**
* Initializes the testObject and the parser for that object.
* @see junit.framework.TestCase#setUp()
*/
@Override
protected void setUp() throws Exception {
super.setUp();
- defaultLocale = Locale.getDefault();
- Locale.setDefault(getLocale());
testObject = getTestObject();
parser = createParser();
}
@@ -64,14 +51,6 @@ public abstract class Args4JTestBase<T> extends TestCase {
}
/**
- * Restores the environment, namely the default Locale.
- */
- @Override
- protected void tearDown() throws Exception {
- Locale.setDefault(defaultLocale);
- }
-
- /**
* Checks the number of lines of the parsers usage message.
* @param expectedLength
* @see TestCase#assertEquals(String, int, int)
@@ -105,10 +84,18 @@ public abstract class Args4JTestBase<T> extends TestCase {
* @see CmdLineParser#printUsage(OutputStream)
*/
public String[] getUsageMessage() {
+ Locale oldDefault = Locale.getDefault();
+ Locale.setDefault(Locale.ENGLISH);
Stream2String s2s = new Stream2String();
parser.printUsage(s2s);
+ Locale.setDefault(oldDefault);
return s2s.getString().split(System.getProperty("line.separator"));
}
+
+ protected void assertErrorMessagePrefix(String exectedPrefix, CmdLineException e) {
+ String errorMessage = e.getMessage();
+ assertTrue("Got wrong error message. Expected prefix: \""+exectedPrefix+"\", actual: \""+errorMessage+"\"", errorMessage.startsWith(exectedPrefix));
+ }
/**
* Utility class for capturing an OutputStream into a String.
diff --git a/args4j/args4j/test/org/kohsuke/args4j/ArgumentTest.java b/args4j/args4j/test/org/kohsuke/args4j/ArgumentTest.java
index 6417dbf..fffcea1 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/ArgumentTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/ArgumentTest.java
@@ -1,26 +1,11 @@
package org.kohsuke.args4j;
-import java.util.List;
-import java.util.Locale;
-
import junit.framework.TestCase;
-public class ArgumentTest extends TestCase {
- private Locale defaultLocale;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- defaultLocale = Locale.getDefault();
- Locale.setDefault(Locale.US);
- }
- @Override
- protected void tearDown() throws Exception {
- Locale.setDefault(defaultLocale);
- }
-
-
+import java.util.List;
- protected static class MultiValueHolder {
+public class ArgumentTest extends TestCase {
+ protected static class MultiValueHolder {
@Argument
public List<String> things;
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/AtOption.java b/args4j/args4j/test/org/kohsuke/args4j/AtOption.java
new file mode 100644
index 0000000..58c1f8e
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/AtOption.java
@@ -0,0 +1,13 @@
+package org.kohsuke.args4j;
+
+@SuppressWarnings("unused")
+public class AtOption {
+ @Option(name="-string",usage="set a string")
+ public String str = "default";
+
+ @Option(name="-noUsage")
+ public String noUsage;
+
+ @Argument
+ public String arguments[];
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/AtOptionTest.java b/args4j/args4j/test/org/kohsuke/args4j/AtOptionTest.java
new file mode 100644
index 0000000..8b5d863
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/AtOptionTest.java
@@ -0,0 +1,90 @@
+package org.kohsuke.args4j;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * Tests the AT sign that reads options from an external file.
+ * @author Stephan Fuhrmann
+ */
+public class AtOptionTest extends Args4JTestBase<AtOption> {
+ @Override
+ public AtOption getTestObject() {
+ return new AtOption();
+ }
+
+ public void testSimpleAt() throws IOException, CmdLineException {
+
+ File tmp = File.createTempFile("atoption", null);
+ PrintWriter printWriter = new PrintWriter(tmp);
+ printWriter.println("-string\nfoo");
+ printWriter.close();
+
+ args = new String[]{"@"+tmp.getAbsolutePath()};
+ parser.parseArgument(args);
+
+ assertEquals("foo", testObject.str);
+ assertNull(testObject.noUsage);
+ assertNull(testObject.arguments);
+
+ tmp.delete();
+ }
+
+ public void testAtAfterOpts() throws IOException, CmdLineException {
+
+ File tmp = File.createTempFile("atoption", null);
+ PrintWriter printWriter = new PrintWriter(tmp);
+ printWriter.println("-string\nfoo");
+ printWriter.close();
+
+ args = new String[]{"-noUsage","lala", "@"+tmp.getAbsolutePath()};
+ parser.parseArgument(args);
+
+ assertEquals("foo", testObject.str);
+ assertEquals("lala", testObject.noUsage);
+ assertNull(testObject.arguments);
+
+ tmp.delete();
+ }
+
+ public void testAtBeforeOpts() throws IOException, CmdLineException {
+
+ File tmp = File.createTempFile("atoption", null);
+ PrintWriter printWriter = new PrintWriter(tmp);
+ printWriter.println("-string\nfoo");
+ printWriter.close();
+
+ args = new String[]{"@"+tmp.getAbsolutePath(), "-noUsage","lala"};
+ parser.parseArgument(args);
+
+ assertEquals("foo", testObject.str);
+ assertEquals("lala", testObject.noUsage);
+ assertNull(testObject.arguments);
+
+ tmp.delete();
+ }
+
+ public void testAtOptsWithBeingDisabled() throws IOException, CmdLineException {
+
+ parser.getProperties().withAtSyntax(false);
+
+ File tmp = File.createTempFile("atoption", null);
+ PrintWriter printWriter = new PrintWriter(tmp);
+ printWriter.println("-string\nfoo");
+ printWriter.close();
+
+ // this time the @-option gets not interpreted because
+ // it's disabled
+ args = new String[]{"-noUsage", "foo", "@"+tmp.getAbsolutePath()};
+ parser.parseArgument(args);
+
+ assertEquals("default", testObject.str);
+ assertEquals("foo", testObject.noUsage);
+ assertEquals(Arrays.asList(new String[] {"@"+tmp.getAbsolutePath()}),
+ Arrays.asList(testObject.arguments));
+
+ tmp.delete();
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/CmdLineExceptionTest.java b/args4j/args4j/test/org/kohsuke/args4j/CmdLineExceptionTest.java
new file mode 100644
index 0000000..ccaa26c
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/CmdLineExceptionTest.java
@@ -0,0 +1,61 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2014 Kohsuke Kawaguchi.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.kohsuke.args4j;
+
+import java.util.Locale;
+import junit.framework.TestCase;
+
+/**
+ * Test case for {@link CmdLineException}.
+ * @author Stephan Fuhrmann <stephan@tynne.de>
+ */
+public class CmdLineExceptionTest extends TestCase {
+
+ private static class TestBean {
+ @Option(name = "-foo")
+ String foo;
+ }
+
+ /***
+ * Test for {@link CmdLineException#CmdLineException(org.kohsuke.args4j.CmdLineParser, Localizable, java.lang.String...) }
+ * and {@link CmdLineException#getLocalizedMessage() }.
+ */
+ public void testGetLocalizedMessage() {
+ TestBean testBean = new TestBean();
+
+ Locale cur = Locale.getDefault();
+ Locale.setDefault(Locale.GERMANY);
+ try {
+ CmdLineParser parser = new CmdLineParser(testBean);
+ CmdLineException e = new CmdLineException(parser, Messages.NO_ARGUMENT_ALLOWED, "foofoo");
+
+ assertEquals("No argument is allowed: foofoo", e.getMessage());
+ assertEquals("Kein Argument erlaubt: foofoo", e.getLocalizedMessage());
+ assertSame(parser, e.getParser());
+ } catch (Exception e1) {
+ Locale.setDefault(cur);
+ }
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/CustomExceptionTest.java b/args4j/args4j/test/org/kohsuke/args4j/CustomExceptionTest.java
index e7835de..cdb1f9a 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/CustomExceptionTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/CustomExceptionTest.java
@@ -6,8 +6,8 @@ import javax.management.InvalidAttributeValueException;
public class CustomExceptionTest extends Args4JTestBase<CustomExceptionTest> {
- private String errMsgX = "this is a usual CLI exception";
- private String errMsgY = "this is a 'custom' exception";
+ private final String errMsgX = "this is a usual CLI exception";
+ private final String errMsgY = "this is a 'custom' exception";
@Option(name="-x")
diff --git a/args4j/args4j/test/org/kohsuke/args4j/DependencyOptions.java b/args4j/args4j/test/org/kohsuke/args4j/DependencyOptions.java
new file mode 100644
index 0000000..8a8c8b2
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/DependencyOptions.java
@@ -0,0 +1,27 @@
+package org.kohsuke.args4j;
+
+/**
+ * @author Nicolas Geraud
+ */
+public class DependencyOptions {
+ @Option(name = "-z", depends ={"-y"})
+ int a;
+
+ @Option(name = "-y", depends ={"-z"})
+ int b;
+
+ @Option(name = "-a", aliases="--alpha")
+ int w;
+
+ @Option(name = "-b", aliases="--bravo")
+ int x;
+
+ @Option(name = "-c", depends ={"--alpha"})
+ int y;
+
+ @Option(name = "-d", depends ={"-b", "-c"})
+ int z;
+
+ @Option(name = "-h", forbids ={"-a", "-b"})
+ int o;
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/DependencyOptionsTest.java b/args4j/args4j/test/org/kohsuke/args4j/DependencyOptionsTest.java
new file mode 100644
index 0000000..0a14197
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/DependencyOptionsTest.java
@@ -0,0 +1,104 @@
+package org.kohsuke.args4j;
+
+/**
+ * @author Nicolas Geraud
+ */
+public class DependencyOptionsTest extends Args4JTestBase<DependencyOptions> {
+
+ public void testEverybodyIsHere() throws Exception {
+ args= new String[]{"-a","4" , "-b","3" , "-c","2" , "-d","1"};
+ try {
+ parser.parseArgument(args);
+ assertEquals(testObject.w,4);
+ assertEquals(testObject.x, 3);
+ assertEquals(testObject.y,2);
+ assertEquals(testObject.z,1);
+ } catch (CmdLineException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEveryoneExceptRequires() throws Exception {
+ args= new String[]{"-a","4" , "-b","3"};
+ try {
+ parser.parseArgument(args);
+ assertEquals(testObject.w, 4);
+ assertEquals(testObject.x,3);
+ assertEquals(testObject.y,0);
+ assertEquals(testObject.z,0);
+ } catch (CmdLineException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testSingleRequires() throws Exception {
+ args= new String[]{"-a","4" , "-c","2"};
+ try {
+ parser.parseArgument(args);
+ assertEquals(testObject.w,4);
+ assertEquals(testObject.x, 0);
+ assertEquals(testObject.y,2);
+ assertEquals(testObject.z,0);
+ } catch (CmdLineException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testSingleRequiresFail() throws Exception {
+ args= new String[]{"-c","2"};
+ try {
+ parser.parseArgument(args);
+ fail();
+ } catch (CmdLineException e) {
+ System.out.println(e.getMessage());
+ assertTrue(e.getMessage().contains("requires the option(s) [--alpha]"));
+ }
+ }
+ public void testMultipleRequiresFail1() throws Exception {
+ args= new String[]{"--bravo","3" , "-d","1"};
+ try {
+ parser.parseArgument(args);
+ fail();
+ } catch (CmdLineException e) {
+ System.out.println(e.getMessage());
+ assertTrue(e.getMessage(), e.getMessage().contains("requires the option(s) [-b, -c]"));
+ }
+ }
+ public void testMultipleRequiresFail2() throws Exception {
+ args= new String[]{"-a","4" , "-c","2" , "-d","1"};
+ try {
+ parser.parseArgument(args);
+ fail();
+ } catch (CmdLineException e) {
+ System.out.println(e.getMessage());
+ assertTrue(e.getMessage().contains("requires the option(s) [-b, -c]"));
+ }
+ }
+
+ public void testForbidFail() throws Exception {
+ args= new String[]{"-a", "5", "-b", "1", "-h", "5"};
+ try {
+ parser.parseArgument(args);
+ fail();
+ } catch (CmdLineException e) {
+ System.out.println(e.getMessage());
+ assertTrue(e.getMessage().contains("cannot be used with the option(s) [-a, -b]"));
+ }
+ }
+
+ public void testRecursive() throws Exception {
+ args= new String[]{"-z","4" , "-y","3"};
+ try {
+ parser.parseArgument(args);
+ assertEquals(testObject.a,4);
+ assertEquals(testObject.b, 3);
+ } catch (CmdLineException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Override
+ public DependencyOptions getTestObject() {
+ return new DependencyOptions();
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanArgumentTest.java b/args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanArgumentTest.java
index 94ff3b4..cab3950 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanArgumentTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanArgumentTest.java
@@ -94,7 +94,7 @@ public class ExplicitBooleanArgumentTest extends Args4JTestBase<BooleanArgumentH
try {
parser.parseArgument(args);
} catch (CmdLineException e) {
- assertUsageContains("Usage message should contain '[VAL]'", "[VAL]");
+ assertUsageContains("Usage message should contain 'VAL'", "VAL");
}
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanOptionTest.java b/args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanOptionTest.java
index 85b710b..cca4545 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanOptionTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/ExplicitBooleanOptionTest.java
@@ -103,7 +103,7 @@ public class ExplicitBooleanOptionTest extends Args4JTestBase<BooleanOptionHolde
try {
parser.parseArgument(args);
} catch (CmdLineException e) {
- assertUsageContains("Usage message should contain '[VAL]'", "[VAL]");
+ assertUsageContains("Usage message should contain 'VAL'", "VAL");
}
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/ExternalConfiguredTest.java b/args4j/args4j/test/org/kohsuke/args4j/ExternalConfiguredTest.java
index 5d09d9b..126c40c 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/ExternalConfiguredTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/ExternalConfiguredTest.java
@@ -1,7 +1,5 @@
package org.kohsuke.args4j;
-import org.kohsuke.args4j.XmlParser;
-import org.xml.sax.InputSource;
import java.io.File;
import java.util.List;
diff --git a/args4j/args4j/test/org/kohsuke/args4j/HelpOption.java b/args4j/args4j/test/org/kohsuke/args4j/HelpOption.java
new file mode 100644
index 0000000..d83497f
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/HelpOption.java
@@ -0,0 +1,12 @@
+package org.kohsuke.args4j;
+
+public class HelpOption {
+ @Option(name="-req",usage="required option",required = true)
+ public String req1;
+
+ @Option(name="-opt",usage="optional option")
+ public String optional1;
+
+ @Option(name="-help",help = true)
+ public boolean help;
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/HelpOptionTest.java b/args4j/args4j/test/org/kohsuke/args4j/HelpOptionTest.java
new file mode 100644
index 0000000..9788216
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/HelpOptionTest.java
@@ -0,0 +1,44 @@
+package org.kohsuke.args4j;
+
+/**
+ * JUnit test for checking whether {@link Option#help() works}.
+ * @author Stephan Fuhrmann
+ */
+public class HelpOptionTest extends Args4JTestBase<HelpOption> {
+ @Override
+ public HelpOption getTestObject() {
+ return new HelpOption();
+ }
+
+ public void testWithRequiredOptionMissing() {
+ args = new String[]{"-opt", "operand"};
+ try {
+ parser.parseArgument(args);
+ fail("Doesnt detect missing parameters.");
+ } catch (CmdLineException e) {
+ String expectedError = "Option \"-req\" is required";
+ String[] usageLines = getUsageMessage();
+ String errorMessage = e.getMessage();
+ assertUsageLength(2);
+ assertTrue("Got wrong error message", errorMessage.startsWith(expectedError));
+ }
+ }
+
+ public void testWithRequiredOptionExisting() throws CmdLineException {
+ args = new String[]{"-req", "operand"};
+ parser.parseArgument(args);
+
+ assertFalse(testObject.help);
+ assertNull(testObject.optional1);
+ assertEquals("operand", testObject.req1);
+ }
+
+ public void testWithHelpExistingButRequiredOptionMissing() throws CmdLineException {
+ args = new String[]{"-help"};
+ parser.parseArgument(args);
+
+ assertTrue(testObject.help);
+ assertNull(testObject.optional1);
+ assertNull(testObject.req1);
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/HiddenOption.java b/args4j/args4j/test/org/kohsuke/args4j/HiddenOption.java
new file mode 100644
index 0000000..9567045
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/HiddenOption.java
@@ -0,0 +1,6 @@
+package org.kohsuke.args4j;
+
+public class HiddenOption {
+ @Option(name="-str",usage="set a string",metaVar="METAVAR",hidden=true)
+ public String str;
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/HiddenOptionTest.java b/args4j/args4j/test/org/kohsuke/args4j/HiddenOptionTest.java
new file mode 100644
index 0000000..0381c9b
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/HiddenOptionTest.java
@@ -0,0 +1,23 @@
+package org.kohsuke.args4j;
+
+public class HiddenOptionTest extends Args4JTestBase<HiddenOption> {
+ @Override
+ public HiddenOption getTestObject() {
+ return new HiddenOption();
+ }
+
+ public void testSettingUsage() {
+ args = new String[]{"-wrong-usage"};
+ try {
+ parser.parseArgument(args);
+ fail("Doesnt detect wrong parameters.");
+ } catch (CmdLineException e) {
+ String expectedError = "\"-wrong-usage\" is not a valid option";
+ String expectedUsage = "";
+ String[] usageLines = getUsageMessage();
+ assertUsageLength(1);
+ assertErrorMessagePrefix(expectedError, e);
+ assertEquals("Got wrong usage message", expectedUsage, usageLines[0]);
+ }
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/KeyValue.java b/args4j/args4j/test/org/kohsuke/args4j/KeyValue.java
new file mode 100644
index 0000000..05fe177
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/KeyValue.java
@@ -0,0 +1,12 @@
+package org.kohsuke.args4j;
+
+@SuppressWarnings("unused")
+public class KeyValue {
+
+ @Option(name="-s", aliases="--string")
+ public String _string;
+
+ @Option(name="-d", aliases="--double")
+ public double _double;
+
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/KeyValueTest.java b/args4j/args4j/test/org/kohsuke/args4j/KeyValueTest.java
new file mode 100644
index 0000000..febc1f1
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/KeyValueTest.java
@@ -0,0 +1,35 @@
+package org.kohsuke.args4j;
+
+public class KeyValueTest extends Args4JTestBase<KeyValue> {
+
+ @Override
+ public KeyValue getTestObject() {
+ return new KeyValue();
+ }
+
+ public void testDouble() throws CmdLineException {
+ args = new String[]{"--double=42.54"};
+ parser.parseArgument(args);
+ assertEquals(42.54, testObject._double, 0);
+ }
+
+ public void testDoubleShort() throws CmdLineException {
+ args = new String[]{"-d=42.54"};
+ parser.parseArgument(args);
+ assertEquals(42.54, testObject._double, 0);
+ }
+
+
+ public void testChar() throws CmdLineException {
+ args = new String[]{"--string=stringValue"};
+ parser.parseArgument(args);
+ assertEquals("stringValue", testObject._string);
+ }
+
+ public void testCharShort() throws CmdLineException {
+ args = new String[]{"-s=stringValue"};
+ parser.parseArgument(args);
+ assertEquals("stringValue", testObject._string);
+ }
+
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/LongUsageTest.java b/args4j/args4j/test/org/kohsuke/args4j/LongUsageTest.java
index 8c25f72..dc05e60 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/LongUsageTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/LongUsageTest.java
@@ -22,5 +22,23 @@ public class LongUsageTest extends Args4JTestBase<LongUsage> {
assertEquals("Second line wrong", expectedLine2, usageLines[1]);
}
}
-
+
+ public void testUsageMessageWithNewWayToSet() {
+ args = new String[]{"-wrong-usage"};
+ // set Widescreen otherwise a line wrapping must occur
+ parser = new CmdLineParser(testObject,
+ ParserProperties.defaults().withUsageWidth(120));
+ try {
+ // start parsing
+ parser.parseArgument(args);
+ } catch (CmdLineException e) {
+ String expectedLine1 = " -LongNamedStringOption USE_A_NICE_STRING : set a string";
+ String expectedLine2 = " -i N : set an int";
+ String[] usageLines = getUsageMessage();
+ assertUsageLength(2);
+ assertEquals("First line wrong", expectedLine1, usageLines[0]);
+ assertEquals("Second line wrong", expectedLine2, usageLines[1]);
+ }
+ }
+
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/MultivaluedTest.java b/args4j/args4j/test/org/kohsuke/args4j/MultivaluedTest.java
index a4ce79d..9d40364 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/MultivaluedTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/MultivaluedTest.java
@@ -1,6 +1,6 @@
package org.kohsuke.args4j;
-import org.kohsuke.args4j.spi.StopOptionHandler;
+import org.kohsuke.args4j.spi.StringArrayOptionHandler;
import java.util.List;
@@ -8,17 +8,18 @@ public class MultivaluedTest extends Args4JTestBase<MultivaluedTest> {
// The JavaBean part of this class as test object.
- // On Lists the @Option(multiValued) defaults to 'true'
@Option(name="-list")
List<String> list;
- @Option(name="-string", multiValued=true)
+ @Option(name="-string")
String string;
-
- // There is no OptionHandler for Arrays
- //@Option(name="-array", multiValued=true)
+
+ @Option(name="-array")
String[] array;
+ @Option(name="-multivalued-array", handler = StringArrayOptionHandler.class)
+ String[] multiValuedArray;
+
// The JUnit part of this class as tester.
@Override
@@ -40,25 +41,33 @@ public class MultivaluedTest extends Args4JTestBase<MultivaluedTest> {
assertTrue(list.contains("two"));
assertTrue(list.contains("three"));
}
-
- //TODO: How to use 'multiValued' on plain fields?
- // We have to option for Strings or CharacterSequence's to specify a separator
- // and concating all values.
- // @Option(... multiValued=true, seperator=",") String s; --> "one,two,three"
- // As the use of 'separator' (new!) implies multiValued this would be more user friendly:
- // @Option(... seperator=",") String s; --> "one,two,three"
- // But how to handle other types like int,MyClass? Concatinating is not an option here...
- public void t_estOnString() throws Exception {
+
+ /**
+ * Specifying an option multiple times can get no-op, such as in the case when the field can only retain one value.
+ */
+ public void testOnString() throws Exception {
// The 'command line invocation'.
parser.parseArgument("-string","one","-string","two","-string","three");
+ assertEquals("three",string);
}
- //TODO: How to use 'multiValued' on arrays?
- // There should be no difference to use on lists (from the user point of view).
- public void t_estOnArray() throws Exception {
+ public void testOnArray() throws Exception {
// The 'command line invocation'.
parser.parseArgument("-array","one","-array","two","-array","three");
// Check the results.
assertEquals("Should got three values", 3, array.length);
+ assertEquals("one",array[0]);
+ assertEquals("two",array[1]);
+ assertEquals("three",array[2]);
+ }
+
+ public void testOnMultiValuedArray() throws Exception {
+ // The 'command line invocation'.
+ parser.parseArgument("-multivalued-array","one", "two","-multivalued-array","three");
+ // Check the results.
+ assertEquals("Should got three values", 3, multiValuedArray.length);
+ assertEquals("one",multiValuedArray[0]);
+ assertEquals("two",multiValuedArray[1]);
+ assertEquals("three",multiValuedArray[2]);
}
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/OptionHandlerRegistryTest.java b/args4j/args4j/test/org/kohsuke/args4j/OptionHandlerRegistryTest.java
new file mode 100644
index 0000000..e93aa04
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/OptionHandlerRegistryTest.java
@@ -0,0 +1,68 @@
+package org.kohsuke.args4j;
+
+import junit.framework.TestCase;
+import org.kohsuke.args4j.spi.OneArgumentOptionHandler;
+
+public class OptionHandlerRegistryTest extends TestCase {
+
+ public static class CustomTypeOptionHandler extends OneArgumentOptionHandler<CustomType> {
+ public CustomTypeOptionHandler(CmdLineParser parser, OptionDef option, org.kohsuke.args4j.spi.Setter<? super CustomType> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ protected CustomType parse(String argument) throws NumberFormatException {
+ CustomType result = new CustomType();
+ result.value = Integer.parseInt(argument);
+ return result;
+ }
+}
+
+ public static class CustomType {
+ int value;
+ }
+
+ private static class TestBean {
+ @Option(name = "-foo")
+ private CustomType foo;
+ }
+
+ /** Tests whether OptionHandlerRegistry.getRegistry() returns an instance. */
+ public void testGetRegistry() {
+ OptionHandlerRegistry instance = OptionHandlerRegistry.getRegistry();
+ assertNotNull(instance);
+ }
+
+ /** Tests whether OptionHandlerRegistry.getRegistry() is a real singleton. */
+ public void testGetRegistryWithSingleton() {
+ OptionHandlerRegistry instance1 = OptionHandlerRegistry.getRegistry();
+ OptionHandlerRegistry instance2 = OptionHandlerRegistry.getRegistry();
+ OptionHandlerRegistry instance3 = OptionHandlerRegistry.getRegistry();
+
+ assertSame(instance1, instance2);
+ assertSame(instance1, instance3);
+ }
+
+ /** Tests whether unknown types raise an exception. */
+ public void testCmdLineParserWithUnregistered() {
+ try {
+ TestBean bean = new TestBean();
+ CmdLineParser parser = new CmdLineParser(bean);
+ assertTrue("Should throw an exception", true);
+ }
+ catch (IllegalAnnotationError e) {
+ assertNotNull(e);
+ }
+ }
+
+ /** Tests whether registering a handler works. */
+ public void testCmdLineParserWithCustomRegistered() throws CmdLineException {
+ TestBean bean = new TestBean();
+ OptionHandlerRegistry.getRegistry().registerHandler(CustomType.class,
+ CustomTypeOptionHandler.class);
+ CmdLineParser parser = new CmdLineParser(bean);
+ parser.parseArgument("-foo", "5");
+
+ assertEquals(5, bean.foo.value);
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/ParserPropertiesUnitTest.java b/args4j/args4j/test/org/kohsuke/args4j/ParserPropertiesUnitTest.java
new file mode 100644
index 0000000..d2223f9
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/ParserPropertiesUnitTest.java
@@ -0,0 +1,46 @@
+package org.kohsuke.args4j;
+
+import junit.framework.TestCase;
+
+public class ParserPropertiesUnitTest extends TestCase {
+ public void testDefaults() {
+ ParserProperties props = ParserProperties.defaults();
+ assertEquals(80, props.getUsageWidth());
+ assertEquals(ParserProperties.DEFAULT_COMPARATOR, props.getOptionSorter());
+ }
+
+ public void testSetToSame() {
+ ParserProperties props = ParserProperties.defaults().withUsageWidth(80);
+ assertEquals(80, props.getUsageWidth());
+ assertEquals(ParserProperties.DEFAULT_COMPARATOR, props.getOptionSorter());
+ }
+
+ public void testSetToDifferent() {
+ ParserProperties props = ParserProperties.defaults().withUsageWidth(90).withOptionSorter(null);
+ assertEquals(90, props.getUsageWidth());
+ assertEquals(null, props.getOptionSorter());
+ }
+
+ public void testSetOnlyOne() {
+ ParserProperties props = ParserProperties.defaults().withOptionSorter(null);
+ assertEquals(80, props.getUsageWidth());
+ assertEquals(null, props.getOptionSorter());
+ }
+
+ public void testFailOnNegativeWidth() {
+ try {
+ ParserProperties.defaults().withUsageWidth(-1);
+ fail("accepted negative width");
+ } catch (IllegalArgumentException x) {
+ // OK
+ }
+ }
+
+ public void testAcceptPositiveWidth() {
+ try {
+ ParserProperties.defaults().withUsageWidth(0);
+ } catch (IllegalArgumentException x) {
+ fail("rejected zero width");
+ }
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/SimpleString.java b/args4j/args4j/test/org/kohsuke/args4j/SimpleString.java
index e098df1..fd258f0 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/SimpleString.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/SimpleString.java
@@ -1,7 +1,5 @@
package org.kohsuke.args4j;
-import org.kohsuke.args4j.Option;
-
@SuppressWarnings("unused")
public class SimpleString {
@Option(name="-str",usage="set a string")
diff --git a/args4j/args4j/test/org/kohsuke/args4j/SimpleStringTest.java b/args4j/args4j/test/org/kohsuke/args4j/SimpleStringTest.java
index 800e7dc..f2a234d 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/SimpleStringTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/SimpleStringTest.java
@@ -39,8 +39,7 @@ public class SimpleStringTest extends Args4JTestBase<SimpleString> {
String expectedError = "\"-wrong-usage\" is not a valid option";
String expectedUsage = " -str VAL : set a string";
String[] usageLines = getUsageMessage();
- String errorMessage = e.getMessage();
- assertTrue("Got wrong error message", errorMessage.startsWith(expectedError));
+ assertErrorMessagePrefix(expectedError, e);
assertUsageLength(1);
assertEquals("Got wrong usage message", expectedUsage, usageLines[0]);
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/StringWithMetavar.java b/args4j/args4j/test/org/kohsuke/args4j/StringWithMetavar.java
index 3b9738b..e1f1c85 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/StringWithMetavar.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/StringWithMetavar.java
@@ -1,7 +1,5 @@
package org.kohsuke.args4j;
-import org.kohsuke.args4j.Option;
-
public class StringWithMetavar {
@Option(name="-str",usage="set a string",metaVar="METAVAR")
public String str;
diff --git a/args4j/args4j/test/org/kohsuke/args4j/StringWithMetavarTest.java b/args4j/args4j/test/org/kohsuke/args4j/StringWithMetavarTest.java
index afeb393..8f817f5 100644
--- a/args4j/args4j/test/org/kohsuke/args4j/StringWithMetavarTest.java
+++ b/args4j/args4j/test/org/kohsuke/args4j/StringWithMetavarTest.java
@@ -1,5 +1,7 @@
package org.kohsuke.args4j;
+import java.io.StringWriter;
+
public class StringWithMetavarTest extends Args4JTestBase<StringWithMetavar> {
@Override
public StringWithMetavar getTestObject() {
@@ -10,15 +12,17 @@ public class StringWithMetavarTest extends Args4JTestBase<StringWithMetavar> {
args = new String[]{"-wrong-usage"};
try {
parser.parseArgument(args);
- fail("Doesnt detect wrong parameters.");
+ fail("Doesn't detect wrong parameters.");
} catch (CmdLineException e) {
String expectedError = "\"-wrong-usage\" is not a valid option";
String expectedUsage = " -str METAVAR : set a string";
+ String expectedSingleLineUsage = " [-str METAVAR]";
String[] usageLines = getUsageMessage();
- String errorMessage = e.getMessage();
+ String singleLineUsage = getSingleLineUsage();
assertUsageLength(1);
- assertTrue("Got wrong error message", errorMessage.startsWith(expectedError));
+ assertErrorMessagePrefix(expectedError, e);
assertEquals("Got wrong usage message", expectedUsage, usageLines[0]);
+ assertEquals("Got wrong usage summary", expectedSingleLineUsage, singleLineUsage);
}
}
@@ -30,12 +34,51 @@ public class StringWithMetavarTest extends Args4JTestBase<StringWithMetavar> {
} catch (CmdLineException e) {
String expectedError = "Option \"-str\" takes an operand";
String expectedUsage = " -str METAVAR : set a string";
- String errorMessage = e.getMessage();
String[] usageLines = getUsageMessage();
assertUsageLength(1);
- assertTrue("Got wrong error message", errorMessage.startsWith(expectedError));
+ assertErrorMessagePrefix(expectedError, e);
assertEquals("Got wrong usage message", expectedUsage, usageLines[0]);
}
}
+ private String getSingleLineUsage() {
+ StringWriter buffer = new StringWriter();
+ parser.printSingleLineUsage(buffer, null);
+ buffer.flush();
+ return buffer.toString();
+ }
+
+ public void testEqualsSeparator() {
+ args = new String[]{"-wrong-usage"};
+ parser.getProperties().withOptionValueDelimiter("=");
+ try {
+ parser.parseArgument(args);
+ fail("Doesn't detect wrong parameters.");
+ } catch (CmdLineException e) {
+ String expectedUsage = " -str=METAVAR : set a string";
+ String expectedSingleLineUsage = " [-str=METAVAR]";
+ String[] usageLines = getUsageMessage();
+ String singleLineUsage = getSingleLineUsage();
+ assertUsageLength(1);
+ assertEquals("Got wrong usage message", expectedUsage, usageLines[0]);
+ assertEquals("Got wrong usage summary", expectedSingleLineUsage, singleLineUsage);
+ }
+ }
+
+ public void testExplicitNoEqualsSeparator() {
+ args = new String[]{"-wrong-usage"};
+ parser.getProperties().withOptionValueDelimiter(" ");
+ try {
+ parser.parseArgument(args);
+ fail("Doesn't detect wrong parameters.");
+ } catch (CmdLineException e) {
+ String expectedUsage = " -str METAVAR : set a string";
+ String expectedSingleLineUsage = " [-str METAVAR]";
+ String[] usageLines = getUsageMessage();
+ String singleLineUsage = getSingleLineUsage();
+ assertUsageLength(1);
+ assertEquals("Got wrong usage message", expectedUsage, usageLines[0]);
+ assertEquals("Got wrong usage summary", expectedSingleLineUsage, singleLineUsage);
+ }
+ }
}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/SubCommandTest.java b/args4j/args4j/test/org/kohsuke/args4j/SubCommandTest.java
new file mode 100644
index 0000000..c20250a
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/SubCommandTest.java
@@ -0,0 +1,50 @@
+package org.kohsuke.args4j;
+
+import org.kohsuke.args4j.spi.SubCommand;
+import org.kohsuke.args4j.spi.SubCommandHandler;
+import org.kohsuke.args4j.spi.SubCommands;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+public class SubCommandTest extends Args4JTestBase<SubCommandTest.Foo> {
+
+ public static class Foo {
+ @Argument(handler= SubCommandHandler.class)
+ @SubCommands({
+ @SubCommand(name="cmd1",impl=Cmd1.class),
+ @SubCommand(name="cmd2",impl=Cmd2.class)
+ })
+ SubCmd value;
+
+ @Option(name="-r")
+ String globalOption1;
+ }
+
+ public static abstract class SubCmd {}
+
+ public static class Cmd1 extends SubCmd {
+ @Option(name="-r")
+ String localOption;
+ }
+ public static class Cmd2 extends SubCmd {}
+
+
+
+ @Override
+ public Foo getTestObject() {
+ return new Foo();
+ }
+
+ public void testCmd1() throws Exception {
+ parser.parseArgument("-r","a","cmd1","-r","b");
+ assertEquals("a",testObject.globalOption1);
+ assertEquals("b",((Cmd1)testObject.value).localOption);
+ }
+
+ public void testCmd2() throws Exception {
+ parser.parseArgument("cmd2");
+ assertTrue(testObject.value instanceof Cmd2);
+ }
+}
+
diff --git a/args4j/args4j/test/org/kohsuke/args4j/spi/InetAddressOptionHandlerTest.java b/args4j/args4j/test/org/kohsuke/args4j/spi/InetAddressOptionHandlerTest.java
new file mode 100644
index 0000000..49f33d2
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/spi/InetAddressOptionHandlerTest.java
@@ -0,0 +1,35 @@
+package org.kohsuke.args4j.spi;
+
+import java.net.InetAddress;
+
+import junit.framework.TestCase;
+
+import org.kohsuke.args4j.CmdLineException;
+
+public class InetAddressOptionHandlerTest extends TestCase {
+
+ private InetAddressOptionHandler handler;
+
+ @Override
+ public void setUp() {
+ handler = new InetAddressOptionHandler(null, null, null);
+ }
+
+ public void testParseSuccess() throws Exception {
+ InetAddress expectedIp = InetAddress.getByAddress(new byte[] { (byte) 1,
+ (byte) 2, (byte) 3, (byte) 4 });
+ InetAddress ip = handler.parse("1.2.3.4");
+
+ assertEquals(expectedIp, ip);
+ }
+
+ public void testParseFailure() throws Exception {
+ try {
+ handler.parse("bogus.ip.address.nosuch.");
+ } catch (CmdLineException e) {
+ assertEquals("\"bogus.ip.address.nosuch.\" must be an IP address", e.getMessage());
+ return;
+ }
+ fail("We should not reach here");
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/spi/MultiPathOptionHandlerTest.java b/args4j/args4j/test/org/kohsuke/args4j/spi/MultiPathOptionHandlerTest.java
new file mode 100644
index 0000000..b91f8a4
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/spi/MultiPathOptionHandlerTest.java
@@ -0,0 +1,114 @@
+package org.kohsuke.args4j.spi;
+
+import junit.framework.TestCase;
+import org.kohsuke.args4j.CmdLineException;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+
+import java.lang.reflect.AnnotatedElement;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: kmahoney
+ * Date: 6/7/13
+ * Time: 6:09 AM
+ */
+
+public class MultiPathOptionHandlerTest extends TestCase {
+ private static final String PSPRTR = System.getProperty("path.separator");
+ private static final String PATH_1 = "/tmp/path/test/1";
+ private static final String PATH_2 = "/tmp/path/test/2.log";
+ private static final String PATH_3 = "3.tst";
+
+ private static final String TEST_1 = PATH_1 + PSPRTR + PATH_2;
+ private static final String TEST_2 = PATH_2 + PSPRTR + PATH_3;
+
+ private MultiPathOptionHandler handler;
+
+ @Override
+ public void setUp() {
+ handler = new MultiPathOptionHandler(null, null, null);
+ }
+
+ public void testParseSuccess() throws Exception {
+ testParse(PathOptionHandlerTest.TEST_1, PathOptionHandlerTest.TEST_1);
+ }
+ public void testSeperatedPathSuccess() throws Exception {
+ testParse(TEST_1, PATH_1, PATH_2);
+ }
+ public void testDualParseSeperatedPathSuccess() throws Exception {
+ CollectorSetter collectorSetter = new CollectorSetter();
+ MultiPathOptionHandler handler = new MultiPathOptionHandler(null, null, collectorSetter);
+ handler.parseArguments(makeSingleParam(TEST_1));
+ handler.parseArguments(makeSingleParam(TEST_2));
+ assertCollectedMatch(collectorSetter, PATH_1, PATH_2, PATH_2, PATH_3);
+ }
+
+
+ public void testParseFailure() throws Exception {
+ try {
+ testParse(PathOptionHandlerTest.TEST_2, PathOptionHandlerTest.TEST_2);
+ fail("Exception not thrown!");
+ }
+ catch (CmdLineException e) {
+ //We hope to get here
+ }
+ }
+
+ private static void testParse(final String arg, String... paths) throws CmdLineException {
+ CollectorSetter collectorSetter = new CollectorSetter();
+ MultiPathOptionHandler handler = new MultiPathOptionHandler(null, null, collectorSetter);
+ handler.parseArguments(makeSingleParam(arg));
+ assertCollectedMatch(collectorSetter, paths);
+ }
+ private static void assertCollectedMatch(CollectorSetter collectorSetter, String... paths) {
+ assertEquals(paths.length, collectorSetter.getCollection().size());
+ for (int i = 0; i < paths.length; i++) {
+ assertEquals(collectorSetter.getCollection().get(i), Paths.get(paths[i]));
+ }
+ }
+ private static Parameters makeSingleParam(final String path) {
+ return new Parameters() {
+ public String getParameter(int idx) throws CmdLineException {
+ if (idx == 0) return path;
+ throw new ArrayIndexOutOfBoundsException(idx);
+ }
+
+ public int size() {
+ return 1;
+ }
+ };
+ }
+
+ static class CollectorSetter implements Setter<Path> {
+
+ private List<Path> collector = new LinkedList<Path>();
+
+ public void addValue(Path value) throws CmdLineException {
+ collector.add(value);
+ }
+
+ public Class<Path> getType() {
+ return Path.class;
+ }
+
+ public boolean isMultiValued() {
+ return true;
+ }
+
+ public FieldSetter asFieldSetter() {
+ throw new NotImplementedException();
+ }
+
+ public AnnotatedElement asAnnotatedElement() {
+ throw new NotImplementedException();
+ }
+
+ List<Path> getCollection() {
+ return collector;
+ }
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/spi/PathOptionHandlerTest.java b/args4j/args4j/test/org/kohsuke/args4j/spi/PathOptionHandlerTest.java
new file mode 100644
index 0000000..f45ce4f
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/spi/PathOptionHandlerTest.java
@@ -0,0 +1,51 @@
+package org.kohsuke.args4j.spi;
+
+import junit.framework.TestCase;
+import org.kohsuke.args4j.CmdLineException;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: kmahoney
+ * Date: 6/7/13
+ * Time: 6:09 AM
+ */
+
+public class PathOptionHandlerTest extends TestCase {
+ static final String TEST_1 = "/path/test";
+ static final String TEST_2 = "bad/path/\0";
+
+ private PathOptionHandler handler;
+
+ @Override
+ public void setUp() {
+ handler = new PathOptionHandler(null, null, null);
+ }
+
+ public void testParseSuccess() throws Exception {
+ Path expectedPath = Paths.get(TEST_1);
+ Path path = handler.parse(TEST_1);
+
+ assertEquals(expectedPath, path);
+ }
+
+ public void testParseFailure() throws Exception {
+ try {
+ handler.parse(TEST_2);
+ } catch (CmdLineException e) {
+ return;
+ }
+ fail("Invalid Path Should Have Thrown Exception");
+ }
+
+ public void testNullParseFailure() throws Exception {
+ try {
+ handler.parse(null);
+ } catch (CmdLineException e) {
+ return;
+ }
+ fail("Null Path Should Have Thrown Exception");
+ }
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/spi/PatternOptionHandlerTest.java b/args4j/args4j/test/org/kohsuke/args4j/spi/PatternOptionHandlerTest.java
new file mode 100644
index 0000000..74fd5b2
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/spi/PatternOptionHandlerTest.java
@@ -0,0 +1,50 @@
+package org.kohsuke.args4j.spi;
+
+import java.util.Locale;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+import org.kohsuke.args4j.CmdLineException;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+
+/** Simple test for the {@link PatternOptionHandler}.
+ * @author Stephan Fuhrmann
+ */
+public class PatternOptionHandlerTest extends TestCase {
+
+ private class TestBean {
+ @Option(name="-pattern")
+ private Pattern pattern;
+ }
+
+ public void testParseSuccess() throws Exception {
+
+ TestBean bean = new TestBean();
+ CmdLineParser parser = new CmdLineParser(bean);
+ parser.parseArgument("-pattern", ".*");
+
+ assertEquals(Pattern.compile(".*").toString(), bean.pattern.toString());
+ }
+
+
+ public void testParseFail() throws Exception {
+
+ Locale old = Locale.getDefault();
+ Locale.setDefault(Locale.ENGLISH);
+ TestBean bean = new TestBean();
+ CmdLineParser parser = new CmdLineParser(bean);
+ try {
+ parser.parseArgument("-pattern", "*");
+ fail("Expecting exception");
+ }
+ catch (CmdLineException e) {
+ assertEquals("\"-pattern\" must be a regular expression", e.getMessage());
+ }
+ finally {
+ Locale.setDefault(old);
+ }
+ }
+
+}
diff --git a/args4j/args4j/test/org/kohsuke/args4j/spi/StringArrayOptionHandlerTest.java b/args4j/args4j/test/org/kohsuke/args4j/spi/StringArrayOptionHandlerTest.java
new file mode 100644
index 0000000..bfaf046
--- /dev/null
+++ b/args4j/args4j/test/org/kohsuke/args4j/spi/StringArrayOptionHandlerTest.java
@@ -0,0 +1,75 @@
+package org.kohsuke.args4j.spi;
+
+import java.util.Arrays;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.kohsuke.args4j.Argument;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+
+/**
+ * Test for {@link StringArrayOptionHandler}.
+ *
+ * This test is for a possible design problem in the old version of {@link ArrayFieldSetter}
+ * that I discovered today. The fix could break existing code, I think it will need
+ * some discussion.
+ *
+ * @author Stephan Fuhrmann
+ */
+public class StringArrayOptionHandlerTest extends TestCase {
+
+ private static class TestBean {
+
+ @Option(name = "-opt")
+ private String stringArray[] = new String[]{"def1", "def2", "def3"};
+
+ @Argument
+ private String rest[];
+ }
+
+ public void testParseWithDefault() throws Exception {
+
+ TestBean bean = new TestBean();
+
+ CmdLineParser parser = new CmdLineParser(bean);
+ parser.parseArgument("test1", "test2", "test3");
+
+ Assert.assertEquals(Arrays.asList("def1", "def2", "def3"), Arrays.asList(bean.stringArray));
+ Assert.assertEquals(Arrays.asList("test1", "test2", "test3"), Arrays.asList(bean.rest));
+ }
+
+ public void testParseWithOneParam() throws Exception {
+
+ TestBean bean = new TestBean();
+
+ CmdLineParser parser = new CmdLineParser(bean);
+ parser.parseArgument("test1", "test2", "-opt", "test3");
+
+ Assert.assertEquals(Arrays.asList("test3"), Arrays.asList(bean.stringArray));
+ Assert.assertEquals(Arrays.asList("test1", "test2"), Arrays.asList(bean.rest));
+ }
+
+ public void testParseWithTwoParams() throws Exception {
+
+ TestBean bean = new TestBean();
+
+ CmdLineParser parser = new CmdLineParser(bean);
+ parser.parseArgument("test1", "test2", "-opt", "test3", "-opt", "test4");
+
+ Assert.assertEquals(Arrays.asList("test3", "test4"), Arrays.asList(bean.stringArray));
+ Assert.assertEquals(Arrays.asList("test1", "test2"), Arrays.asList(bean.rest));
+ }
+
+ public void testParseWithNoDefault() throws Exception {
+
+ TestBean bean = new TestBean();
+ bean.stringArray = null; // remove
+
+ CmdLineParser parser = new CmdLineParser(bean);
+ parser.parseArgument("test1", "test2", "-opt", "test3", "-opt", "test4");
+
+ Assert.assertEquals(Arrays.asList("test3", "test4"), Arrays.asList(bean.stringArray));
+ Assert.assertEquals(Arrays.asList("test1", "test2"), Arrays.asList(bean.rest));
+ }
+}
diff --git a/args4j/pom.xml b/args4j/pom.xml
index e43638a..608c623 100644
--- a/args4j/pom.xml
+++ b/args4j/pom.xml
@@ -3,16 +3,16 @@
<parent>
<groupId>org.kohsuke</groupId>
<artifactId>pom</artifactId>
- <version>3</version>
+ <version>10</version>
</parent>
<groupId>args4j</groupId>
<artifactId>args4j-site</artifactId>
<name>args4j parent</name>
- <version>2.0.22</version>
+ <version>2.0.30</version>
<packaging>pom</packaging>
<description>args4j : Java command line arguments parser</description>
- <url>http://args4j.dev.java.net/</url>
+ <url>http://args4j.kohsuke.org/</url>
<issueManagement>
<url>https://args4j.dev.java.net/issues</url>
</issueManagement>
@@ -64,6 +64,7 @@
<connection>scm:git:git@github.com/kohsuke/args4j.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/args4j.git</developerConnection>
<url>http://args4j.kohsuke.org/</url>
+ <tag>HEAD</tag>
</scm>
<distributionManagement>
@@ -87,10 +88,11 @@
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
- <version>2.3.2</version>
+ <version>3.1</version>
<configuration>
- <source>1.5</source>
- <target>1.5</target>
+ <source>1.6</source>
+ <target>1.6</target>
+ <compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
<plugin>
@@ -105,7 +107,16 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
- <version>3.0-beta-3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>org.kohsuke.${pom.artifactId}</Bundle-SymbolicName>
+ </instructions>
+ </configuration>
</plugin>
</plugins>
</build>
diff --git a/args4j/project.properties b/args4j/project.properties
deleted file mode 100644
index bc1988a..0000000
--- a/args4j/project.properties
+++ /dev/null
@@ -1,44 +0,0 @@
-# -------------------------------------------------------------------
-# P R O J E C T P R O P E R T I E S
-# -------------------------------------------------------------------
-maven.repo.remote=http://www.ibiblio.org/maven
-# use the lib directory as the repository
-
-maven.junit.fork=true
-
-compile.debug = on
-compile.optimize = off
-compile.deprecation = off
-maven.compile.source=1.5
-maven.compile.target=1.5
-
-maven.jarResources.basedir = ${basedir}/src
-
-maven.changes.issue.template=https://args4j.dev.java.net/issues/show_bug.cgi?id=%ISSUE%
-
-# -------------------------------------------------------------------
-# J A V A D O C P R O P E R T I E S
-# -------------------------------------------------------------------
-
-# Display the date on the Maven web site
-maven.xdoc.date = left
-
-# Display the project version the web site is documenting
-maven.xdoc.version = ${pom.currentVersion}
-
-maven.javadoc.links = \
- http://java.sun.com/j2se/5.0/docs/api/
-
-maven.javadoc.locale = en_US
-maven.javadoc.public = true
-
-# java.net setting
-maven.javanet.project=args4j
-
-maven.multiproject.basedir=${basedir}
-
-
-
-# load tools jar from JDK
-maven.jar.override = true
-maven.jar.tools = ${java.home}/../lib/tools.jar
diff --git a/args4j/project.xml b/args4j/project.xml
deleted file mode 100644
index 29d041d..0000000
--- a/args4j/project.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project>
- <pomVersion>3</pomVersion>
- <name>args4j</name>
- <groupId>args4j</groupId>
- <artifactId>args4j-site</artifactId>
- <currentVersion>2.0.16</currentVersion>
-
- <organization>
- <name>Kohsuke Kawaguchi</name>
- <url>http://www.kohsuke.org/</url>
- </organization>
-
- <logo>/images/args4j.png</logo>
- <inceptionYear>2003</inceptionYear>
-
- <package>org.kohsuke.args4j</package>
-
-
- <shortDescription>args4j : Java command line arguments parser</shortDescription>
-
- <description>args4j : Java command line arguments parser</description>
-
- <url>http://args4j.dev.java.net/</url>
-
- <reports>
- <report>maven-changes-plugin</report>
- </reports>
-
- <repository>
- <connection>scm:cvs:pserver:guest@cvs.dev.java.net:/cvsroot:args4j</connection>
- <developerConnection>scm:cvs:ext:${maven.username}@cvs.dev.java.net:/cvsroot:args4j</developerConnection>
- <url>https://args4j.dev.java.net/source/browse/args4j/</url>
- </repository>
-
- <issueTrackingUrl>https://args4j.dev.java.net/issues</issueTrackingUrl>
-
- <mailingLists>
- <mailingList>
- <name>discussion list</name>
- <subscribe>users-subscribe@args4j.dev.java.net</subscribe>
- <unsubscribe>users-ubsubscribe@args4j.dev.java.net</unsubscribe>
- <archive>https://args4j.dev.java.net/servlets/SummarizeList?listName=users</archive>
- </mailingList>
- </mailingLists>
-
-
- <developers>
- <developer>
- <name>Kohsuke Kawaguchi</name>
- <id>kohsuke</id>
- <email>kk@kohsuke.org</email>
- <organization>Sun Microsystems</organization>
- </developer>
- <developer>
- <name>Jan Materne</name>
- <id>jhm</id>
- <email>jhm@apache.org</email>
- </developer>
- <developer>
- <name>Mark Sinke</name>
- <id>marksinke</id>
- <email>marksinke@dev.java.net</email>
- </developer>
- </developers>
-</project>
diff --git a/args4j/release.sh b/args4j/release.sh
index bedbac2..af606c7 100644
--- a/args4j/release.sh
+++ b/args4j/release.sh
@@ -2,9 +2,3 @@
# run this after manually updating project.xml and xdocs/changes.xml
# to point to the next release version
mvn -B release:prepare release:perform
-cd args4j
-maven clean:clean javanet:dist javanet:site jar:install
-cd ../args4j-tools
-maven clean:clean javanet:dist jar:install
-cd ..
-maven javanet:site
diff --git a/args4j/src/site/apt/apt.apt b/args4j/src/site/apt/apt.apt
index fbde596..16135ca 100644
--- a/args4j/src/site/apt/apt.apt
+++ b/args4j/src/site/apt/apt.apt
@@ -1,4 +1,4 @@
- args4j can examine your annotated source code and generate HTML table or XML for the list of command line options. You can use this in the build process to generate your documentation, so that it will be always in sync with your code.
+ args4j can examine your annotated source code and generate HTML table or XML for the list of command line options. You can use this in your build process to generate your documentation, so it's always in sync with your code.
To do so, download {{{http://maven.jenkins-ci.org/content/repositories/releases/args4j/args4j-tools/}args4j-tools}} and run it as follows:
@@ -6,4 +6,4 @@
$ java -jar args4j-tools.jar path/to/my/OptionBean.java
----------------------------------------
- To see all the options, run it withouy any parameter.
+ To see all the options, run it without any parameters.
diff --git a/args4j/src/site/apt/implementOptionhandler.apt b/args4j/src/site/apt/implementOptionhandler.apt
index be08376..337e8b0 100644
--- a/args4j/src/site/apt/implementOptionhandler.apt
+++ b/args4j/src/site/apt/implementOptionhandler.apt
@@ -1,3 +1,3 @@
- args4j comes with a built-in support for parsing options into several Java datatypes, such as <<<int>>>, <<<String>>>, and <<<Enum>>>. This support can be extended by writing {{{apidocs/org/kohsuke/args4j/spi/OptionHandler.html}OptionHandler}} implementation in an application and registering it to the <<<CmdLineParser>>> class.
+ args4j comes with a built-in support for parsing options into several Java datatypes (such as <<<int>>>, <<<String>>>, and <<<Enum>>>). You can extend this further by writing your own {{{apidocs/org/kohsuke/args4j/spi/OptionHandler.html}OptionHandler}} implementation, then registering it to the <<<CmdLineParser>>> class.
- In fact most of the built-in suppor is implemented as using this mechanism. See the source code for some of the OptionHandler class for details of how to do this.
+ In fact, most of the built-in support is implemented using this mechanism. The <<<OptionHandler>>> class's source code details how to do this.
diff --git a/args4j/src/site/apt/index.apt b/args4j/src/site/apt/index.apt
index 46a187e..7575eb0 100644
--- a/args4j/src/site/apt/index.apt
+++ b/args4j/src/site/apt/index.apt
@@ -10,17 +10,17 @@ Why should I use it?
See {{{http://weblogs.java.net/blog/kohsuke/archive/2005/05/parsing_command.html}my quick intro}}.
- * It makes the command line parsing very easy by using annotations.
+ * It makes command line parsing very easy by using annotations
- * You can generate the usage screen very easily.
+ * Generate usage text very easily
- * You can generate HTML/XML that lists all options for your documentation.
+ * Generate HTML/XML documentation listing all options
- * Fully supports localization.
+ * Full localization support
- * It is designed to parse <<<javac>>> like options (as opposed to GNU-style where ls <<<-lR>>> is considered to have two options <<<l>>> and <<<R>>>.)
+ * Designed to parse <<<javac>>> like options, as opposed to GNU-style (where <<<ls -lR>>> is considered to have two options <<<l>>> and <<<R>>>).
- * It is licensed under {{{http://www.opensource.org/licenses/mit-license.php}the MIT license}}.
+ * Licensed under {{{http://www.opensource.org/licenses/mit-license.php}the MIT license}}.
[]
@@ -34,7 +34,7 @@ How can I use it?
[]
-More Resource
+More Resources
[[1]] {{{./sample.html}A small tutorial}} for the use of the Starter and Args4J
diff --git a/args4j/src/site/apt/sample.apt b/args4j/src/site/apt/sample.apt
index 0c2a9be..4de9da9 100644
--- a/args4j/src/site/apt/sample.apt
+++ b/args4j/src/site/apt/sample.apt
@@ -4,7 +4,7 @@
Prepare your environment
- Because we only want to have a very small example, we use only one single directory containing all the stuff - sources, class files and the args4j jarfile. You need a JDK 1.5 or higher.
+ Because we only want to have a very small example, we use only one single directory containing all the stuff— sources, class files and the args4j jarfile. You need a JDK 1.5 or higher.
[[1]] Create a directory args4j-sample this will be our project directory.
@@ -16,7 +16,7 @@ Prepare your environment
Implementing pure business logic
- Create the business bean Business.java. At this step it contains only the business logic. To run this logic, we want to have a run() method.
+ Create the business bean <<<Business.java>>>. At this point, it only contains the business logic. To run this logic, we want a <<<run()>>> method.
------------------------------
import java.io.File;
@@ -59,7 +59,7 @@ Start the class
[]
- Ok, because this is a args4j sample, the first method is not the right solution here ;-) In the first step we just use the Starter.
+ Okay...because this is a sample, the first method isn't the right solution here ;-) In the first step we just use the <<<Starter>>>.
Start the class
@@ -67,7 +67,7 @@ Start the class
java -classpath .;args4j-2.0.5.jar -Dmainclass=Business org.kohsuke.args4j.Starter
------------------------------
- and we will get
+ and we get
------------------------------
Business-Logic
@@ -75,9 +75,9 @@ Business-Logic
- file: null
------------------------------
- What happened? The starter class had a look into the java system property <<<mainclass>>> loads that class, instantiates it and executes their run() method. We provide the classpath so the Java VM could find the starter class and our business class.
+ What happened? The starter class had a look into the Java system property <<<mainclass>>> loads that class, instantiates it, and executes their <<<run()>>> method. We provide the <<<classpath>>> so the Java VM could find the starter class and our business class.
- Next we try to start the class with arguments:
+ Next, let's try to start the class with arguments:
------------------------------
java -classpath .;args4j-2.0.5.jar -Dmainclass=Business org.kohsuke.args4j.Starter -name "Hrld" -file args4j-2.0.5.jar
@@ -92,7 +92,7 @@ Business
Adding Args4J Annotations
- Ok, we don't have any annotations for handling the command line parameters yet. So we modify to the source:
+ Well, we don't have any annotations to handle the command line parameters yet. Let's fix that:
------------------------------
...
@@ -106,7 +106,7 @@ Adding Args4J Annotations
...
------------------------------
- recompile it and try the start again
+ Recompile and try the start again
------------------------------
Business-Logic
@@ -114,13 +114,15 @@ Business-Logic
- file: C:\temp\args4j-sample\args4j-2.0.5.jar
------------------------------
- Ok, so far so good. What is with wrong parameters? We will type a
+ So far so good.
+
+ What is with wrong parameters?
------------------------------
java -classpath .;args4j-2.0.5.jar -Dmainclass=Business org.kohsuke.args4j.Starter -wrong
------------------------------
- and the output is
+ which outputs
------------------------------
"-wrong" is not a valid option
@@ -129,13 +131,19 @@ Business [options]
-name VAL : Sets a name
------------------------------
- Again - what happened? args4j throws a CmdLineException when we type an incorrect parameter (<<<-wrong>>>). The starter class catches this and prints out a help message: the classname and an <<<[Option]>>> because we have some @Option's in the code. (We dont have an @Argument so that line is not <<<Business [options] arguments>>>). After that it shows the possible options, as given by the parsers printUsage() method.
+ Again—what happened?
+
+ args4j throws a <<<CmdLineException>>> when we wrote an incorrect parameter (<<<-wrong>>>). The starter class catches this and prints a help message: the classname and an <<<[Option]>>> (since we have some <<<@Option>>>s in the code). (Since we don't have an <<<@Argument>>>, that line is not <<<Business [options] arguments>>>.)
+
+ Then it shows the possible options, as given by the parser's <<<printUsage()>>> method.
- As you can see we added an @Option to an attribute and to a setter method. Adding to an attribute is the simplest thing. If we want to do some checks (like our file existance check) you could add the annotation to a setter.
+ As you can see, we added an <<<@Option>>> to an attribute and to a setter method. Using this with attributes is the simplest way to use args4j. But if you wanted to do some checks (e.g. our file existence check), you could add the annotation to a setter.
Enhancing the parsing
- If you want to have more control about the parsing and error handling - dont use the starter. Use the CmdLineParser directly. Base steps are shown below:
+ If you want to have more control over parsing and error handling, don't use the starter. Use <<<CmdLineParser>>> directly.
+
+ Here are the main steps:
------------------------------
import org.kohsuke.args4j.CmdLineParser;
@@ -155,13 +163,13 @@ Enhancing the parsing
}
------------------------------
- Because we dont use the Starter we also have to supply the main method and start this. So after compiling we could start that with
+ Since we're not using the <<<Starter>>>, we also have to supply the main method and start it. So, after compiling, we could start that with:
------------------------------
java -classpath .;args4j-2.0.5.jar Business -name "Hello World" -file args4j-2.0.5.jar
------------------------------
- and we will get
+ and we get
------------------------------
Business-Logic
@@ -175,7 +183,7 @@ Business-Logic
java -classpath .;args4j-2.0.5.jar Business -wrong
------------------------------
-will result in
+results in
------------------------------
"-wrong" is not a valid option