Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to Require One or Both Options But Not None? #947

Closed
andrewauclair opened this issue Feb 11, 2020 · 2 comments
Closed

How to Require One or Both Options But Not None? #947

andrewauclair opened this issue Feb 11, 2020 · 2 comments
Labels
theme: parser An issue or change related to the parser type: question ❔

Comments

@andrewauclair
Copy link

Hi There!

I'm in the process of converting a command line style app I'm writing to picocli from my own command parsing. So far picocli has been excellent and has improved the code a lot. I tried to find this in the documentation but couldn't find something that matched exactly.

I want to have the following command: "set --project "Foo" --feature "Bar"", where project and feature are both optional options, but the user must have at least one of them present. So they can call "set --project "Foo"" or "set --feature "Foo"" or "set --project "Foo" --feature "Bar"", but never just "set".

Is there a way that I can achieve this with picocli?

Thanks!

@remkop
Copy link
Owner

remkop commented Feb 12, 2020

@andrewauclair Sorry for my late reply.

Yes, this is possible with a picocli argument group.
Key points:

  • make a group with the --feature and --project options
  • set exclusive=false on the group to make the options mutually dependent
  • set multiplicity = "1" on the group to make the group mandatory
  • make sure both options are non-required in the group (this is the default, you can also explicitly say required = false)

Because the group is mandatory, one or both of the options must be specified, or picocli will give an error that the group is missing. Because the options are optional in the group, either one can be omitted.

Example code:

static class Issue947RequireOneOrBothNotNoneGroup {
    @Option(names = {"-f", "--feature"}) String feature;
    @Option(names = {"-p", "--project"}) String project;
}

@Command
static class Issue947Cmd {
    @ArgGroup(multiplicity = "1", exclusive = false)
    Issue947RequireOneOrBothNotNoneGroup group;
}

@Test
public void testIssue947RequireOneOrBothNotNone() {
    Issue947Cmd ok1 = CommandLine.populateCommand(new Issue947Cmd(), "--project", "Foo");
    assertNotNull(ok1.group);
    assertEquals("Foo", ok1.group.project);
    assertNull(ok1.group.feature);

    Issue947Cmd ok2 = CommandLine.populateCommand(new Issue947Cmd(), "--feature", "Bar");
    assertNotNull(ok2.group);
    assertNull(ok2.group.project);
    assertEquals("Bar", ok2.group.feature);

    Issue947Cmd ok3 = CommandLine.populateCommand(new Issue947Cmd(), "--project", "Foo", "--feature", "Bar");
    assertNotNull(ok3.group);
    assertEquals("Foo", ok3.group.project);
    assertEquals("Bar", ok3.group.feature);

    try {
        CommandLine.populateCommand(new Issue947Cmd());
        fail("Expected exception");
    } catch (ParameterException ok) {
        assertEquals("Error: Missing required argument(s): ([-f=<feature>] [-p=<project>])", ok.getMessage());
    }
}

@andrewauclair
Copy link
Author

Works great, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme: parser An issue or change related to the parser type: question ❔
Projects
None yet
Development

No branches or pull requests

2 participants