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

Preserving order between separate options (e.g., --include and `--exclude) #761

Closed
adamsmd opened this issue Jul 2, 2019 · 4 comments
Closed

Comments

@adamsmd
Copy link

adamsmd commented Jul 2, 2019

Is there a way to define rsync-style --include and --exclude commands where the order of these commands relative to each other is important? In rsync the first --include or --exclude in the command line that a file matches determines whether the file is included or not.

For example, consider rsync --include=pattern1 --exclude=pattern2 --include=pattern3 --exclude=pattern4.

  • If a file matches pattern1, rsync includes the file.
  • If a file doesn't match pattern1 but matches pattern2, rsync excludes the file.
  • If a file doesn't match pattern1 or pattern2 but matches pattern3, rsync includes the file.
  • If a file doesn't match pattern1, pattern2 or pattern3 but matches pattern4, rsync excludes the file.
  • If a file doesn't match pattern1, pattern2, pattern3 or pattern4, rsync uses some default handling for the file.

If I use a list @Option for --include and a separate list @Option for --exclude, the order between includes and the order between excludes is preserved but not the order between includes and excludes.

If I use a list @Option for both --include and --exclude as names, then the order between includes and excludes is preserved, but I don't see a way to know which were includes and which were excludes.

@remkop
Copy link
Owner

remkop commented Jul 2, 2019

Makes sense. I thought that this was already supported in the ParseResult class, but it is not (yet).

The API will probably look something like this: (feedback welcome)

@Command(name = "rsync")
static class Rsync implements Runnable {

    @Option(names = "--include")
    List<String> includes;

    @Option(names = "--exclude")
    List<String> excludes;

    @Spec CommandSpec spec;

    public void run() {
        ParseResult pr = spec.commandLine().getParseResult();
        List<ArgSpec> optionSpecs = pr.matchedArgs();
        // do something
    }
}

@Test
public void testOrderedOptionsWithParseResult() {
    CommandLine cmd = new CommandLine(new Rsync());
    ParseResult parseResult = cmd.parseArgs("--include", "a", "--exclude", "b", "--include", "c", "--exclude", "d");
    List<ArgSpec> argSpecs = parseResult.matchedArgs();
    assertEquals(4, argSpecs.size());
    assertEquals("--include", ((OptionSpec) argSpecs.get(0)).longestName());
    assertEquals("--exclude", ((OptionSpec) argSpecs.get(1)).longestName());
    assertEquals("--include", ((OptionSpec) argSpecs.get(2)).longestName());
    assertEquals("--exclude", ((OptionSpec) argSpecs.get(3)).longestName());
}

@adamsmd
Copy link
Author

adamsmd commented Jul 3, 2019

By that do you mean, matchedArgs() would be the addition to the API? And to get the actual values you could use either stringValues() or typedValues() (or counting as you go along the includes and excludes lists)?

@remkop
Copy link
Owner

remkop commented Jul 3, 2019

Correct, I plan to add a matchedArgs() method that returns all matched options and positional parameters in the order they were matched on the command line.

And, yes, at the moment I’m thinking that applications can get the values via ArgSpec.stringValues() or ArgSpec.typedValues(). Let me know if you have suggestions for alternatives.

Note that the current matchedOptions() and matchedPositionals() methods are a bit misleading: they return a List but during parsing the matched arguments are actually added to a Set. I’m planning to modify the behavior of these methods from 4.0 to return the full List of OptionSpec objects, including duplicates if the option was matched multiple times. (Similarly for positional params.)

For applications interested in the current behavior I’ll add matchedOptionSet() and matchedPositionalSet() methods that return a Set whose iterator returns elements in the order they were matched.

remkop added a commit that referenced this issue Jul 3, 2019
… matched options and positional params

* Add `ParseResult.matchedArgs()` method to return all matched arguments in order;
* change `ParseResult.matchedOptions()` and `ParseResult.matchedPositionals()` to return the full list of matched options and positional parameters, including duplicates if the option or positional parameter was matched multiple times.
* Add new `ParseResult.matchedOptionSet()` and `ParseResult.matchedPositionalSet()` methods that return a `Set`.
@remkop
Copy link
Owner

remkop commented Jul 3, 2019

This has been implemented and pushed to master.
See this test for example usage.

Please verify.

@remkop remkop closed this as completed Jul 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants