Skip to content

Commit

Permalink
[#358][#635][#199][#295][#450] update user manual and release notes
Browse files Browse the repository at this point in the history
  • Loading branch information
remkop committed Mar 29, 2019
1 parent b7eb995 commit 66809f2
Show file tree
Hide file tree
Showing 2 changed files with 242 additions and 3 deletions.
10 changes: 7 additions & 3 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ This release adds support for argument groups (incubating). Argument groups enab

See the [New and Noteworthy section](#4.0.0-alpha-1-new) below for more details.

_The purpose of this release is to give people a chance to try this out and provide feedback._

_What do you think of the annotations API? What about the programmatic API? Does it work as expected? Is the documentation clear and complete? Anything you want to change or improve? Any other feedback?_


This is the fifty-first public release.
Picocli follows [semantic versioning](http://semver.org/).
Expand Down Expand Up @@ -241,13 +245,13 @@ assert c2.dependent.c == 2;

#### Positional Parameters

When a `@Parameters` positional parameter is part of a group, its `index` is the index <em>within the group</em>, not within the command.
When a `@Parameters` positional parameter is part of a group, its `index` is the index _within the group_, not within the command.


#### Limitations and Points of Caution

* Options with the same name cannot be defined in multiple groups, and similarly it is not possible to define multiple options with the same name where one option is part of a group and another is part of the command (and not in a group).
* It is probably not a good idea to define positional parameters that are part of a group at the same time (with the same index) as `@Parameters` positional parameters that are part of the command (and not in a group).
* Options with the same name cannot be defined in multiple groups. Similarly, it is not possible to define an option outside of a group with the same name as a different option that is part of a group.
* Positional parameters in a single group work fine, but take care (or avoid) defining positional parameters in multiple groups or positional parameters in a group as well as outside a group. Positional parameters are matched by index, and while the index of a group is reset when a new group multiple is encountered, the index of positional parameters outside a group only increases and is never reset.


## <a name="4.0.0-alpha-1-fixes"></a> Fixed issues
Expand Down
235 changes: 235 additions & 0 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,7 @@ x = 'null'
From picocli 3.0, options with non-String types can specify a <<Custom Type Converters,type converter>> to convert the empty String to a strongly typed value when the option is specified without a value.



== Required Arguments
=== Required Options
Options can be marked `required` to make it mandatory for the user to specify them on the command line. When a required option is not specified, a `MissingParameterException` is thrown from the `parse` method. For example:
Expand Down Expand Up @@ -938,6 +939,240 @@ The following command line arguments would be accepted:
----


== Argument Groups
Picocli 4.0 introduces a new `@ArgGroup` annotation and its `ArgGroupSpec` programmatic equivalent.

Argument Groups can be used to define:

* mutually exclusive options
* options that must co-occur (dependent options)
* option sections in the usage help message
* repeating composite arguments

To create a group using the annotations API, annotate a field or method with `@ArgGroup`.
The field's type refers to the class containing the options and positional parameters in the group.
(For annotated interface methods this would be the return type, for annotated setter methods in a concrete class this would be the setter's parameter type.)

Picocli will instantiate this class when needed to capture command line argument values in the `@Option` and `@Parameters`-annotated fields and methods of this class.

=== Mutually Exclusive Options

Annotate a field or method with `@ArgGroup(exclusive = true)` to create a group of mutually exclusive options and positional parameters. For example:

[source, java]
----
@Command(name = "exclusivedemo")
public class MutuallyExclusiveOptionsDemo {
@ArgGroup(exclusive = true, multiplicity = "1")
Exclusive exclusive;
static class Exclusive {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
}
----

The above example defines a command with mutually exclusive options `-a`, `-b` and `-c`.

The group itself has a `multiplicity` attribute that defines how many times the group may be specified within the command.
The default is `multiplicity = "0..1"`, meaning that by default a group may be omitted or specified once.
In this example the group has `multiplicity = "1"`, so the group must occur once: one of the exclusive options must occur on the command line.

The synopsis of this command is `exclusivedemo (-a=<a> | -b=<b> | -c=<c>)`.

Note that the options are defined as `required = true`; this means required _within the group_, not required within the command.

Picocli will validate the arguments and throw a `MutuallyExclusiveArgsException` if multiple mutually exclusive arguments were specified. For example:

[source, java]
----
MutuallyExclusiveOptionsDemo example = new MutuallyExclusiveOptionsDemo();
CommandLine cmd = new CommandLine(example);
try {
cmd.parseArgs("-a=1", "-b=2");
} catch (MutuallyExclusiveArgsException ex) {
assert "Error: -a=<a>, -b=<b> are mutually exclusive (specify only one)"
.equals(ex.getMessage());
}
----

For the above group, only one of the options can be specified. Any other combination of options, or the absence of options, is invalid.

=== Co-occurring (Dependent) Options

Annotate a field or method with `@ArgGroup(exclusive = false)` to create a group of dependent options and positional parameters that must co-occur. For example:

[source, java]
----
@Command(name = "co-occur")
public class DependentOptionsDemo {
@ArgGroup(exclusive = false)
Dependent dependent;
static class Dependent {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
}
----

The above example defines a command with dependent options `-a`, `-b` and `-c` that must co-occur.

The group itself has a `multiplicity` attribute that defines how many times the group may be specified within the command.
In this example the group uses the default multiplicity, `multiplicity = "0..1"`, meaning that the group may be omitted or specified once.

The synopsis of this command is `co-occur [-a=<a> -b=<b> -c=<c>]`.

Note that the options are defined as `required = true`; this means required _within the group_, not required within the command.

Picocli will validate the arguments and throw a `MissingParameterException` if not all dependent arguments were specified. For example:

[source, java]
----
DependentOptionsDemo example = new DependentOptionsDemo();
CommandLine cmd = new CommandLine(example);
try {
cmd.parseArgs("-a=1", "-b=2");
} catch (MissingParameterException ex) {
assert "Error: Missing required argument(s): -c=<c>".equals(ex.getMessage());
}
----

=== Option Sections in Usage Help

The example below uses groups to define options sections in the usage help.
When a group has a non-null `heading` (or `headingKey`), the options in the group are given the specified heading in the usage help message.
The `headingKey` attribute can be used to get the heading text from the command's resource bundle.

This works for mutually exclusive or co-occurring groups, but it is also possible to define a group that does no validation but only creates an option section in the usage help.

Annotate a field or method with `@ArgGroup(validate = false)` to create a group for display purposes only. For example:

[source, java]
----
@Command(name = "sectiondemo", description = "Section demo")
public class OptionSectionDemo {
@ArgGroup(validate = false, heading = "This is the first section%n")
Section1 section1;
static class Section1 {
@Option(names = "-a", description = "Option A") int a;
@Option(names = "-b", description = "Option B") int b;
@Option(names = "-c", description = "Option C") int c;
}
@ArgGroup(validate = false, heading = "This is the second section%n")
Section2 section2;
static class Section2 {
@Option(names = "-x", description = "Option X") int x;
@Option(names = "-y", description = "Option Y") int y;
@Option(names = "-z", description = "Option X") int z;
}
public static void main(String[] args) {
new CommandLine(new OptionSectionDemo()).usage(System.out);
}
}
----

This prints the following usage help message:

----
Usage: sectiondemo [-a=<a>] [-b=<b>] [-c=<c>] [-x=<x>] [-y=<y>] [-z=<z>]
Section demo
This is the first section
-a=<a> Option A
-b=<b> Option B
-c=<c> Option C
This is the second section
-x=<x> Option X
-y=<y> Option Y
-z=<z> Option X
----

Note that the heading text must end with `%n` to insert a newline between the heading text and the first option.
This is for consistency with other headings in the usage help, like `@Command(headerHeading = "Usage:%n", optionListHeading = "%nOptions:%n")`.

=== Repeating Composite Argument Groups

The below example shows how groups can be composed of other groups, and how arrays and collections can be used to capture repeating groups (with a `multiplicity` greater than one):

[source, java]
----
public class CompositeGroupDemo {
@ArgGroup(exclusive = false, multiplicity = "1..*")
List<Composite> composites;
static class Composite {
@ArgGroup(exclusive = false, multiplicity = "1")
Dependent dependent;
@ArgGroup(exclusive = true, multiplicity = "1")
Exclusive exclusive;
}
static class Dependent {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
static class Exclusive {
@Option(names = "-x", required = true) boolean x;
@Option(names = "-y", required = true) boolean y;
@Option(names = "-z", required = true) boolean z;
}
}
----

In the above example, the annotated `composites` field defines a composite group that must be specified at least once, and may be specified many times, on the command line.
Each time the group is matched, picocli creates an instance of the `Composite` class and adds it to the `composites` list.

The `Composite` class itself contains two groups: a group of dependent options that must co-occur, and another group of mutually exclusive options.
Both of these subgroups have `multiplicity = "1"`, so they can occur exactly once for each multiple of the `Composite` group. The below example illustrates:

[source, java]
----
CompositeGroupDemo example = new CompositeGroupDemo();
CommandLine cmd = new CommandLine(example);
cmd.parseArgs("-x", "-a=1", "-b=1", "-c=1", "-a=2", "-b=2", "-c=2", "-y");
assert example.composites.size() == 2;
Composite c1 = example.composites.get(0);
assert c1.exclusive.x;
assert c1.dependent.a == 1;
assert c1.dependent.b == 1;
assert c1.dependent.c == 1;
Composite c2 = example.composites.get(1);
assert c2.exclusive.y;
assert c2.dependent.a == 2;
assert c2.dependent.b == 2;
assert c2.dependent.c == 2;
----

=== Positional Parameters

When a `@Parameters` positional parameter is part of a group, its `index` is the index _within the group_, not within the command.


=== Argument Group Limitations

* Options with the same name cannot be defined in multiple groups. Similarly, it is not possible to define an option outside of a group with the same name as a different option that is part of a group.
* Positional parameters in a single group work fine, but take care (or avoid) defining positional parameters in multiple groups or positional parameters in a group as well as outside a group. Positional parameters are matched by index, and while the index of a group is reset when a new group multiple is encountered, the index of positional parameters outside a group only increases and is never reset.


== Parser Configuration

=== Overwriting Single Options
Expand Down

0 comments on commit 66809f2

Please sign in to comment.