Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
kbknapp authored Dec 28, 2016
2 parents 17d70dc + e20009d commit a7186fa
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 70 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
<a name="v2.19.3"></a>
### v2.19.3 (2016-12-28)


#### Bug Fixes

* fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands ([a0ee4993](https://github.com/kbknapp/clap-rs/commit/a0ee4993015ea97b06b5bc9f378d8bcb18f1c51c), closes [#789](https://github.com/kbknapp/clap-rs/issues/789))



<a name="v2.19.2"></a>
### v2.19.2 (2016-12-08)

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "clap"
version = "2.19.2"
version = "2.19.3"
authors = ["Kevin K. <kbknapp@gmail.com>"]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
repository = "https://github.com/kbknapp/clap-rs.git"
Expand Down
30 changes: 14 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,22 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)

## What's New

Here's the highlights for v2.19.2

* Fixes a bug by escaping square brackets in ZSH completions which were causing conflicts and errors.
* Adds subcommand examples (`examples/20_subcommands.rs`)
* Adds guidance on when to use ~ in version pinning, and clarifies breaking change policy
Here's the highlights for v2.19.3

* Fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands

Here's the highlights from v2.0.0 to v2.19.1
Here's the highlights from v2.0.0 to v2.19.2

* **Bash Completion:** allows bash completion to fall back to traditional bash completion upon no matching completing function
* Fixes a bug by escaping square brackets in ZSH completions which were causing conflicts and errors.
* **Bash Completion:** allows bash completion to fall back to traidtional bash completion upon no matching completing function
* **Arg Setting**: Allows specifying an `AllowLeadingHyphen` style setting for values only for specific args, vice command wide
* **Validators:** improves the error messages for validators
* **Required Unless:** fixes a bug where having required_unless set doesn't work when conflicts are also set
* **ZSH Completions:** fixes an issue where zsh completions caused panics if there were no subcommands
* **Completions:** Adds completion support for Microsoft PowerShell! (Thanks to @Arnavion)
* Allows specifying the second to last positional argument as `multiple(true)` (i.e. things such as `mv <files>... <target>`)
* Adds an `App::get_name` and `App::get_bin_name`
* Conflicting argument errors are now symmetrical, meaning more consistent and better usage suggestions
* Conflicting argument errors are now symetrical, meaning more consistent and better usage suggestions
* **Completions:** adds automatic ZSH completion script generation support! :tada: :tada:
* **AppSettings:** adds new setting `AppSettings::AllowNegativeNumbers` which functions like `AllowLeadingHyphen` except only allows undefined negative numbers to pass parsing.
* Stabilize `clap_app!` macro (i.e. no longer need to use `unstable` feature)
Expand Down Expand Up @@ -104,7 +102,7 @@ Here's the highlights from v2.0.0 to v2.19.1
* Allows adding multiple ArgGroups per Arg
* **Global Settings:** One can now set an `AppSetting` which is propogated down through child subcommands
* **Terminal Wrapping:** Allows wrapping at specified term width (Even on Windows!) (can now set an absolute width to "smart" wrap at)
* **SubCommands/Aliases:** adds support for visible aliases for subcommands (i.e. aliases that are displayed in the help message)
* **SubCommands/Aliases:** adds support for visible aliases for subcommands (i.e. aliases that are dipslayed in the help message)
* **Subcommands/Aliases:** when viewing the help of an alias, it now display help of the aliased subcommand
* Adds new setting to stop delimiting values with `--` or `AppSettings::TrailingVarArg`
* Subcommands now support aliases - think of them as hidden subcommands that dispatch to said subcommand automatically
Expand Down Expand Up @@ -504,7 +502,7 @@ Then run `cargo build` or `cargo update && cargo build` for your project.

* **"suggestions"**: Turns on the `Did you mean '--myoption'?` feature for when users make typos. (builds dependency `strsim`)
* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` and `libc`)
* **"wrap_help"**: Wraps the help at the actual terminal width when available, instead of 120 characters. (builds dependency `term_size`, and `libc`)
* **"wrap_help"**: Wraps the help at the actual terminal width when available, instead of 120 chracters. (builds dependency `term_size`, and `libc`)

To disable these, add this to your `Cargo.toml`:

Expand Down Expand Up @@ -563,14 +561,14 @@ Please read [CONTRIBUTING.md](.github/CONTRIBUTING.md) before you start contribu

### Testing Code

To test with all features both enabled and disabled, you can run these commands:
To test with all features both enabled and disabled, you can run theese commands:

```sh
$ cargo test --no-default-features
$ cargo test --features "yaml unstable"
```

Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the prebuilt recipes. *Not* using `just` is perfectly fine as well, it simply bundles commands automatically.
Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the prebuilt recipies. *Not* using `just` is prfeclty fine as well, it simply bundles commands automatically.

For example, to test the code, as above simply run:

Expand Down Expand Up @@ -640,7 +638,7 @@ Because `clap` takes SemVer and compatibility seriously, this is the official po

`clap` will pin the minimum required version of Rust to the CI builds. Bumping the minimum version of Rust is considered a minor breaking change, meaning *at a minimum* the minor version of `clap` will be bumped.

In order to keep from being surprised of breaking changes, it is **highly** recommended to use the `~major.minor.patch` style in your `Cargo.toml` only if you wish to target a version of Rust that is *older* than current stable minus two releases:
In order to keep from being suprised of breaking changes, it is **highly** recommended to use the `~major.minor.patch` style in your `Cargo.toml` only if you wish to target a version of Rust that is *older* than current stable minus two releases:

```toml
[dependencies]
Expand All @@ -651,14 +649,14 @@ This will cause *only* the patch version to be updated upon a `cargo update` cal

#### Minimum Version of Rust

`clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.13.0, meaning `clap` is guaranteed to compile with 1.11.0 and beyond.
At the 1.14.0 release, `clap` will be guaranteed to compile with 1.12.0 and beyond, etc.
`clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.13.0, meaning `clap` is garunteed to compile with 1.11.0 and beyond.
At the 1.14.0 release, `clap` will be garunteed to compile with 1.12.0 and beyond, etc.

Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be clearly annotated in the `CHANGELOG.md`

#### Breaking Changes

`clap` takes a similar policy to Rust and will bump the major version number upon breaking changes with only the following exceptions:
`clap` takes a similar policy to Rust and will bump the major veresion number upon breaking changes with only the following exceptions:

* The breaking change is to fix a security concern
* The breaking change is to be fixing a bug (i.e. relying on a bug as a feature)
Expand Down
100 changes: 49 additions & 51 deletions src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,10 +817,10 @@ impl<'a, 'b> Parser<'a, 'b>
subcmd_name = Some(arg_os.to_str().expect(INVALID_UTF8).to_owned());
break;
} else if let Some(cdate) =
suggestions::did_you_mean(&*arg_os.to_string_lossy(),
self.subcommands
.iter()
.map(|s| &s.p.meta.name)) {
suggestions::did_you_mean(&*arg_os.to_string_lossy(),
self.subcommands
.iter()
.map(|s| &s.p.meta.name)) {
return Err(Error::invalid_subcommand(arg_os.to_string_lossy().into_owned(),
cdate,
self.meta
Expand Down Expand Up @@ -894,51 +894,13 @@ impl<'a, 'b> Parser<'a, 'b>
}
}

self.validate(needs_val_of, subcmd_name, matcher, it)
}

fn validate<I, T>(&mut self,
needs_val_of: Option<&'a str>,
subcmd_name: Option<String>,
matcher: &mut ArgMatcher<'a>,
it: &mut Peekable<I>)
-> ClapResult<()>
where I: Iterator<Item = T>,
T: Into<OsString> + Clone
{
let mut reqs_validated = false;
if let Some(a) = needs_val_of {
debugln!("needs_val_of={:?}", a);
let o = find_by_name!(self, &a, opts, iter).expect(INTERNAL_ERROR_MSG);
try!(self.validate_required(matcher));
reqs_validated = true;
let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
} else {
true
};
if should_err {
return Err(Error::empty_value(o,
&*self.create_current_usage(matcher),
self.color()));
}
}

try!(self.add_defaults(matcher));
try!(self.validate_blacklist(matcher));
try!(self.validate_num_args(matcher));
matcher.usage(self.create_usage(&[]));

if !(self.settings.is_set(AppSettings::SubcommandsNegateReqs) && subcmd_name.is_some()) &&
!reqs_validated {
try!(self.validate_required(matcher));
}
if let Some(pos_sc_name) = subcmd_name {
if let Some(ref pos_sc_name) = subcmd_name {
// is this is a real subcommand, or an alias
let sc_name = if self.subcommands.iter().any(|sc| sc.p.meta.name == pos_sc_name) {
pos_sc_name
if self.subcommands.iter().any(|sc| &sc.p.meta.name == pos_sc_name) {

try!(self.parse_subcommand(&*pos_sc_name, matcher, it));
} else {
self.subcommands
let sc_name = &*self.subcommands
.iter()
.filter(|sc| sc.p.meta.aliases.is_some())
.filter_map(|sc| if sc.p
Expand All @@ -953,9 +915,9 @@ impl<'a, 'b> Parser<'a, 'b>
None
})
.next()
.expect(INTERNAL_ERROR_MSG)
.expect(INTERNAL_ERROR_MSG);
try!(self.parse_subcommand(sc_name, matcher, it));
};
try!(self.parse_subcommand(sc_name, matcher, it));
} else if self.is_set(AppSettings::SubcommandRequired) {
let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
return Err(Error::missing_subcommand(bn,
Expand All @@ -970,6 +932,42 @@ impl<'a, 'b> Parser<'a, 'b>
info: None,
});
}

self.validate(needs_val_of, subcmd_name, matcher)
}

fn validate(&mut self,
needs_val_of: Option<&'a str>,
subcmd_name: Option<String>,
matcher: &mut ArgMatcher<'a>)
-> ClapResult<()> {
let mut reqs_validated = false;
if let Some(a) = needs_val_of {
debugln!("needs_val_of={:?}", a);
let o = find_by_name!(self, &a, opts, iter).expect(INTERNAL_ERROR_MSG);
try!(self.validate_required(matcher));
reqs_validated = true;
let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
} else {
true
};
if should_err {
return Err(Error::empty_value(o,
&*self.create_current_usage(matcher),
self.color()));
}
}

try!(self.add_defaults(matcher));
try!(self.validate_blacklist(matcher));
try!(self.validate_num_args(matcher));
matcher.usage(self.create_usage(&[]));

if !(self.settings.is_set(AppSettings::SubcommandsNegateReqs) && subcmd_name.is_some()) &&
!reqs_validated {
try!(self.validate_required(matcher));
}
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
self.is_set(AppSettings::ArgRequiredElseHelp) {
let mut out = vec![];
Expand Down Expand Up @@ -1019,7 +1017,7 @@ impl<'a, 'b> Parser<'a, 'b>
}

fn parse_subcommand<I, T>(&mut self,
sc_name: String,
sc_name: &str,
matcher: &mut ArgMatcher<'a>,
it: &mut Peekable<I>)
-> ClapResult<()>
Expand Down Expand Up @@ -1755,7 +1753,7 @@ impl<'a, 'b> Parser<'a, 'b>
return true;
}
}
}
}
if let Some(ru) = a.required_unless() {
debugln!("Required unless found...{:?}", ru);
let mut found_any = false;
Expand Down
2 changes: 0 additions & 2 deletions src/usage_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ use INTERNAL_ERROR_MSG;
use args::Arg;
use args::settings::ArgSettings;

type ParseResult = Result<(), ()>;

#[derive(PartialEq, Debug)]
enum UsageToken {
Name,
Expand Down

0 comments on commit a7186fa

Please sign in to comment.