README
“The
REFCODES.ORG
codes represent a group of artifacts consolidating parts of my work in the past years. Several topics are covered which I consider useful for you, programmers, developers and software engineers.”
What is this repository for?
This artifact defines some helpful toolkit to parse your command line arguments (as passed to your public static void main( String[] args) { ... }
method. It lets you define the exact valid combinations of command line arguments, it parses them arguments for you and it lets you print the syntax as you programmatically defined it. Let’s get started.
Quick start archetype
Use the refcodes-archetype-alt-cli
archetype to create a bare metal command line interface (CLI
) driven Java
application:
Please adjust
my.corp
with your actual Group-ID andmyapp
with your actual Artifact-ID!
mvn archetype:generate \
-DarchetypeGroupId=org.refcodes \
-DarchetypeArtifactId=refcodes-archetype-alt-cli \
-DarchetypeVersion=3.0.0 \
-DgroupId=my.corp \
-DartifactId=myapp \
-Dversion=1.0-SNAPSHOT
Using the defaults, this will generate a CLI
application providing a command line interface by harnessing the refcodes-cli
library.
ANSI Escape-Codes
You can start right off by playing around with ANSI Escape-Codes
to tweak your ArgsParser
instantiated in your freshly generated CLI
application:
![]() |
![]() |
![]() |
---|---|---|
Default ANSI-Console | Tweaked ANSI-Console | Crazy ANSI-Console |
As a foundation for working with ANSI Escape-Codes
the refcodes-data
artifact provides the AnsiEscapeCode
enumeration for easy construction of ANSI Escape-Code
sequences. Below we use the AnsiEscapeCode
enumeration to color our ArgsParser
’s output (the code corresponds to the last screenshot above):
1
2
3
4
5
6
7
...
ArgsParser theArgsParser = new ArgsParserImpl( ... );
theArgsParser.setBannerEscapeCode( AnsiEscapeCode.toEscapeSequence( AnsiEscapeCode.REVERSE_VIDEO ) );
theArgsParser.setBannerBorderEscapeCode( AnsiEscapeCode.toEscapeSequence( AnsiEscapeCode.FG_BRIGHT_CYAN, AnsiEscapeCode.BOLD ) );
theArgsParser.setParameterEscapeCode( AnsiEscapeCode.toEscapeSequence( AnsiEscapeCode.FG_RED, AnsiEscapeCode.UNDERLINE ) );
theArgsParser.setParameterDescriptionEscapeCode( AnsiEscapeCode.toEscapeSequence( AnsiEscapeCode.FG_BRIGHT_YELLOW, AnsiEscapeCode.BOLD ) );
...
How do I get set up?
To get up and running, include the following dependency (without the three dots “…”) in your pom.xml
:
1
2
3
4
5
6
7
8
9
<dependencies>
...
<dependency>
<groupId>org.refcodes</groupId>
<artifactId>refcodes-cli</artifactId>
<version>3.0.0</version>
</dependency>
...
</dependencies>
The artifact is hosted directly at Maven Central. Jump straight to the source codes at Bitbucket. Read the artifact’s javadoc at javadoc.io.
How do I get started?
Consider you have a tool called foo-bar
to be invoked with the below allowed argument combinations (syntax):
foo-bar [{ -a | -d }] -f <file>
foo-bar
can be invoked either with an optional -a
or with an optional -d
switch, but not both of them at the same time, and a file -f <file>
must be provided, else the passed arguments are rejected as not being valid.
Valid arguments would be:
- foo-bar -f someFile
- foo-bar -d -f anyFile
- foo-bar -f otherFile -a
- foo-bar -a -f otherFile
Invalid arguments would be:
- foo-bar -f someFile -b
- foo-bar -a someFile -f
- foo-bar -a -d -f anyFile
- foo-bar -a -x -f otherFile
This means that additional switches not supported are not valid. The parser detects such situations and you can print out a help message in such cases.
Construct your parser
First build your syntax using Flags
, Options
and Conditions
. You actually https://www.javadoc.io/docr your command line tool’s supported arguments:
1
2
3
4
5
6
7
8
9
10
StringOption theFile = new StringOption( "-f", "--file", "file", "A file" );
Flag theAdd = new Flag( "-a", null, "Add the specified file" );
Flag theDelete = new Flag( "-d", null, "Delete the specified file" );
ArgsSyntax theXor = new XorCondition( theAdd, theDelete );
ArgsSyntax theOptional = new AnyCondition( theXor );
ArgsSyntax theAnd = new AndCondition( theOptional, theFile );
ArgsParser theArgsParser = new ArgsParserImpl( theAnd );
theArgsParser.printUsage();
// theArgsParser.printHelp();
Using syntactic sugar
The TinyRestfulServer
demo application uses syntactic sugar
for setting up the command line arguments parser:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import static org.refcodes.cli.CliSugar.*;
...
public static void main( String args[] ) {
IntOption theWidth = intOption( "-w", "--width", "width", "Sets the console width" );
IntOption thePort = intOption( "-p", "--port", "port", "Sets the port for the server" );
IntOption theMaxConns = intOption( "-c", "--connections", "connections", "Sets the number of max. connections" );
StringOption theUsername = stringOption( "-u", "--user", "username", "The username for HTTP basic authentication" );
StringOption theSecret = stringOption( "-s", "--secret", "secret", "The password for HTTP basic authentication" );
Flag theHelp = helpFlag( "Shows this help" );
ArgsSyntax theRootCondition = xor(
and(
thePort, optional( theMaxConns ), optional( and( theUsername, theSecret ) ), optional( theWidth )
),
theHelp
);
ArgsParser theArgsParser = new ArgsParserImpl( theRootCondition );
theArgsParser.withSyntaxNotation( SyntaxNotation.REFCODES );
theArgsParser.withName( "TinyRestful" ).withTitle( "TINYRESTFUL" ).withCopyrightNote( "Copyright (c) by FUNCODES.CLUB, Munich, Germany." ).withLicenseNote( "Licensed under GNU General Public License, v3.0 and Apache License, v2.0" );
theArgsParser.withBannerFont( new FontImpl( FontFamily.DIALOG, FontStyle.BOLD, 14 ) ).withBannerFontPalette( AsciiColorPalette.MAX_LEVEL_GRAY.getPalette() );
theArgsParser.setDescription( "Tiny evil RESTful server. TinyRestfulServer makes heavy use of the REFCODES.ORG artifacts found together with the FUNCODES.CLUB sources at <http://bitbucket.org/metacodez>." );
theArgsParser.addExampleUsage( "To use a specific port", thePort );
theArgsParser.addExampleUsage( "To secure with a user's credentials", theUsername, theSecret);
List<? extends Operand<?>> theResult = theArgsParser.evalArgs( args );
...
}
...
Most obvious is the missing new
statement for instantiating the parts of your command line parser as this is done by the statically imported methods.
Flip through fluent methods provided by the
CliSugar
class to find out about further possibilities of therefcodes-cli
](https://bitbucket.org/refcodes/refcodes-cli) artifact, such as the creation of arrays fromOption
arguments by invokingasArray(...)
.
Under the hood
As seen above, you pass your root ArgsSyntax
to the [`ArgsPhttps://www.javadoc.io/docvadoc.io/org.refcodes/refcodes-cli/latest/org/refcodes/cli/ArgsParser.html) which then alhttps://www.javadoc.io/doc command line tool’s usage string:
1
2
3
...
theArgsParser.printUsage();
...
Test (invoke) your parser: In real live you would pass your main-method’s args[] array to the parser. Now just for a test-run, pass a java.lang.String array to your parser and let it parse it:
1
2
3
4
5
String[] args = new String[] {
"-f", "someFile", "-d"
};
List<? extends Operand<?>> theResult = theArgsParser.evalArgs( args );
File theConfigFile = new File( theFile.getValue() );
Now the leaves of your syntax tree are filled with the argument’s values according to the syntax you have been setting up: Your StringOption
instance alhttps://www.javadoc.io/docains the value “someFile”.
The theResult
contains the parsed arguments for you to use in your business logic.
In case of argument rejection, a sub-type of the ArgsSyntaxException
ishttps://www.javadoc.io/docone of the exceptions UnknownArgsException
, https://www.javadoc.io/doc(https://www.javadoc.io/doc/org.refcodes/refcodes-cli/latest/org/refcodes/cli/AmbiguousArgsException.html), https://www.javadoc.io/docon
https://www.javadoc.io/doc](https://www.javadoc.io/doc/org.refcodes/refcodes-cli/latest/org/refcodes/cli/ParseArgsException.html) is behttps://www.javadoc.io/doc the cause of the rejection. So you can either catch the [
ArgsSyntaxException`](https://www.javadoc.io/doc/org.refcodes/refcodes-cli/latest/org/refcodes/cli/ArgsSyntaxException.html) orhttps://www.javadoc.io/docls on the cause, the other sub-exceptions.
Syntaxable
A Syntaxable
defines the mhttps://www.javadoc.io/doc when building a command line arguments syntax tree for traversing the syntax tree; either for parsing command line arguments or for constructing the command line arguments syntax.
By providing various implementations of the Syntaxable
’s subclasses https://www.javadoc.io/doc://static.javadoc.io/org.refcodes/refcodes-cli/latest/org/refcodes/cli/Operand.html), Option
, ArgsSyntax
or Flag
, a command line arghttps://www.javadoc.io/doce constructed. This syntax tree can be used to create a human readable (verbose) command line arguments syntax and to parse an array of command line arguments for determining the Operands
’, the Flag
es’ or the [`Optionshttps://www.javadoc.io/doc.io/org.refcodes/refcodes-cli/latest/org/refcodes/cli/Option.html)’ values.
Operand
An Operand
represents a value parsed from command line arguments. An Operand
has a state which changes with each invocation of the parseArgs(String[])
method.
It is recommended to put your Operand
instance(s) at the end of your top ArgsSyntax
to enforce it to be the last Syntaxable(s) when parsing the command line arguments - this makes sure that any Options
pick their option arguments so that the Operand
(s) will correctly be left over for parsing command line argument(s); the Operand
will not pick by mistake an Option
argument.
Option
An Option
represents a command line option with the according option’s value. An Option
can be seen as a key / value(s) pair defined in the command line arguments parsed via the parseArgs(String[])
method.
An Option
has a state which changes with each invocation of the parseArgs(String[])
method.
Flag
A Flag
is an Option
with a Boolean
https://www.javadoc.io/docare just set or omitted in the command line arguments with no value provided; former representing a true
status and latter representing a false
status.
Operation
The Operation
is an argument representing a function or a method and is either provided or not provided as of the isEnabled()
method. It must neither be prefixed with -
nor with --
in contrast to the Option
or the Flag
type.
ArgsSyntax
The ArgsSyntax
interface reprhttps://www.javadoc.io/docmand line arguments syntax tree; simply extending the Syntaxable interface and adding the functionality of providing access to the added Operands (leafs). In future extensions, a ArgsSyntax might provide access to the child Syntaxable elements contained in a ArgsSyntax instance. As of the current findings, access to the children of the ArgsSyntax node is not required and would make the interface unnecessarily complicated.
Happy coding
Want more than just the usage text? You can print out each building block of the help text on its own, below is all you can get:
1
2
3
4
...
// theArgsParser.printUsage();
theArgsParser.printHelp();
...
See also Parsing arguments to a Java command line program at StackOverflow.
Resources
- See
StringOption
- See [`Flahttps://www.javadoc.io/docc.io/org.refcodes/refcodes-cli/latest/org/refcodes/cli/Flag.html)
- See [`StringOperahttps://www.javadoc.io/dococ.io/org.refcodes/refcodes-cli/latest/org/refcodes/cli/StringOperand.html)
- See [`Xohttps://www.javadoc.io/docic.javadoc.io/org.refcodes/refcodes-cli/latest/org/refcodes/cli/XorCondition.html)
- See [`Andhttps://www.javadoc.io/docc.javadoc.io/org.refcodes/refcodes-cli/latest/org/refcodes/cli/AndCondition.html)
- See [`Opthttps://www.javadoc.io/docstatic.javadoc.io/org.refcodes/refcodes-cli/latest/org/refcodes/cli/AnyCondition.html)
Chttps://www.javadoc.io/doc#
- When printing out the usage, concatenate switches something like
-a
,-d
,-x
and-h
(which are set or omitted without any argument) to become-adxh
- When printing out the POSIX like usage text, it should look more POSIX like than it currently does (though I like the way it is)
- Code review
- Other guidelines
Who do I talk to?
- Siegfried Steiner (steiner@refcodes.org)
Terms and conditions
The REFCODES.ORG
group of artifacts is published under some open source licenses; covered by the refcodes-licensing
(org.refcodes
group) artifact - evident in each artifact in question as of the pom.xml
dependency included in such artifact.