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

Add --include-features option #66

Merged
merged 2 commits into from
Oct 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@ This project adheres to [Semantic Versioning](https://semver.org).

## [Unreleased]

* Remove `--ignore-non-exist-features` flag, use `--ignore-unknown-features` flag instead.
* [Remove `--ignore-non-exist-features` flag.][62] Use `--ignore-unknown-features` flag instead.

* Treat `--all-features` flag as one of feature combinations. See [#42][42] for details.
* [Treat `--all-features` flag as one of feature combinations.][61] See [#42][42] for details.

* Add `--exclude-all-features` flag. See [#42][42] for details.
* Add `--exclude-all-features` flag. ([#61][61], [#65][65]) See [#42][42] for details.

* Add `--exclude-features` option. This is an alias of `--skip` option.
* [Add `--exclude-features` option. This is an alias of `--skip` option.][65]

* Rename `--skip-no-default-features` flag to `--exclude-no-default-features`.
* [Rename `--skip-no-default-features` flag to `--exclude-no-default-features`.][65]
The old name can be used as an alias, but is deprecated.

* Fix an issue where using `--features` with `--each-feature` or `--feature-powerset` together would result in the same feature combination being performed multiple times.
* [Add `--include-features` option.][66] See [#66][66] for details.

* [Fix an issue where using `--features` with `--each-feature` or `--feature-powerset` together would result in the same feature combination being performed multiple times.][64]

[42]: https://github.com/taiki-e/cargo-hack/pull/42
[61]: https://github.com/taiki-e/cargo-hack/pull/61
[62]: https://github.com/taiki-e/cargo-hack/pull/62
[63]: https://github.com/taiki-e/cargo-hack/pull/63
[64]: https://github.com/taiki-e/cargo-hack/pull/64
[65]: https://github.com/taiki-e/cargo-hack/pull/65
[66]: https://github.com/taiki-e/cargo-hack/pull/66

## [0.3.14] - 2020-10-10

Expand Down
37 changes: 30 additions & 7 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const HELP: &[(&str, &str, &str, &[&str])] = &[
("", "--skip <FEATURES>...", "Alias for --exclude-features", &[]),
("", "--exclude-features <FEATURES>...", "Space-separated list of features to exclude", &[
"To exclude run of default feature, using value `--exclude-features default`.",
"To exclude run of just --no-default-features flag, using --exclude-no-default-features flag.",
"To exclude run of just --all-features flag, using --exclude-all-features flag.",
"This flag can only be used together with either --each-feature flag or --feature-powerset flag.",
]),
("", "--exclude-no-default-features", "Exclude run of just --no-default-features flag", &[
Expand All @@ -48,6 +50,14 @@ const HELP: &[(&str, &str, &str, &[&str])] = &[
"This flag can only be used together with --feature-powerset flag.",
],
),
(
"",
"--include-features <FEATURES>...",
"Include only the specified features in the feature combinations instead of package features",
&[
"This flag can only be used together with either --each-feature flag or --feature-powerset flag.",
],
),
("", "--no-dev-deps", "Perform without dev-dependencies", &[
"Note that this flag removes dev-dependencies from real `Cargo.toml` while cargo-hack is running and restores it when finished.",
]),
Expand All @@ -62,9 +72,7 @@ const HELP: &[(&str, &str, &str, &[&str])] = &[
"",
"--ignore-unknown-features",
"Skip passing --features flag to `cargo` if that feature does not exist in the package",
&[
"This flag can only be used in the root of a virtual workspace or together with --workspace.",
],
&["This flag can only be used together with either --features or --include-features."],
),
("", "--clean-per-run", "Remove artifacts for that package before running the command", &[
"If used this flag with --workspace, --each-feature, or --feature-powerset, artifacts will be removed before each run.",
Expand Down Expand Up @@ -197,6 +205,8 @@ pub(crate) struct Args {
pub(crate) clean_per_run: bool,
/// --depth <NUM>
pub(crate) depth: Option<usize>,
/// --include-features
pub(crate) include_features: Vec<String>,

/// --no-default-features
pub(crate) no_default_features: bool,
Expand Down Expand Up @@ -278,6 +288,7 @@ pub(crate) fn args(coloring: &mut Option<Coloring>) -> Result<Option<Args>> {
let mut exclude = Vec::new();
let mut features = Vec::new();
let mut optional_deps = None;
let mut include_features = Vec::new();

let mut workspace = None;
let mut no_dev_deps = false;
Expand Down Expand Up @@ -408,6 +419,13 @@ pub(crate) fn args(coloring: &mut Option<Coloring>) -> Result<Option<Args>> {
"--exclude-features",
"--exclude-features <FEATURES>..."
);
parse_multi_opt!(
include_features,
true,
true,
"--include-features",
"--include-features <FEATURES>..."
);

if arg.starts_with("--optional-deps") {
if optional_deps.is_some() {
Expand Down Expand Up @@ -497,10 +515,10 @@ pub(crate) fn args(coloring: &mut Option<Coloring>) -> Result<Option<Args>> {
// in the root of a virtual workspace as well?
bail!("--exclude can only be used together with --workspace");
}
if ignore_unknown_features && features.is_empty() {
// TODO: Once https://github.com/taiki-e/cargo-hack/issues/52 implemented,
// allow --include-features.
bail!("--ignore-unknown-features can only be used together with --features");
if ignore_unknown_features && features.is_empty() && include_features.is_empty() {
bail!(
"--ignore-unknown-features can only be used together with either --features or --include-features"
);
}
if !each_feature && !feature_powerset {
if optional_deps.is_some() {
Expand All @@ -519,6 +537,10 @@ pub(crate) fn args(coloring: &mut Option<Coloring>) -> Result<Option<Args>> {
bail!(
"--exclude-all-features can only be used together with either --each-feature or --feature-powerset"
);
} else if !include_features.is_empty() {
bail!(
"--include-features can only be used together with either --each-feature or --feature-powerset"
);
}
}
if depth.is_some() && !feature_powerset {
Expand Down Expand Up @@ -617,6 +639,7 @@ For more information try --help
optional_deps,
clean_per_run,
depth,
include_features,

no_default_features,
verbose,
Expand Down
52 changes: 30 additions & 22 deletions src/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,34 @@ impl<'a> Kind<'a> {
return Kind::Nomal { show_progress: false };
}

let features = package
.features
.keys()
.filter(|f| *f != "default" && !args.exclude_features.contains(f));
let opt_deps = args.optional_deps.as_ref().map(|opt_deps| {
package.dependencies.iter().filter_map(Dependency::as_feature).filter(move |f| {
!args.exclude_features.contains(f) && (opt_deps.is_empty() || opt_deps.contains(f))
})
});
let features = if args.include_features.is_empty() {
let mut features: Vec<_> = package
.features
.keys()
.filter(|f| *f != "default" && !args.exclude_features.contains(f))
.collect();
if let Some(opt_deps) = &args.optional_deps {
features.extend(
package.dependencies.iter().filter_map(Dependency::as_feature).filter(
move |f| {
!args.exclude_features.contains(f)
&& (opt_deps.is_empty() || opt_deps.contains(f))
},
),
);
}
features
} else {
args.include_features
.iter()
.filter(|f| *f != "default" && !args.exclude_features.contains(f))
.collect()
};

if args.each_feature {
let features: Vec<_> = if let Some(opt_deps) = opt_deps {
features.chain(opt_deps).collect()
} else {
features.collect()
};

if package.features.is_empty() && features.is_empty() {
if (package.features.is_empty() || !args.include_features.is_empty())
&& features.is_empty()
{
*total += 1;
Kind::Nomal { show_progress: true }
} else {
Expand All @@ -90,13 +100,11 @@ impl<'a> Kind<'a> {
Kind::Each { features }
}
} else if args.feature_powerset {
let features = if let Some(opt_deps) = opt_deps {
powerset(features.chain(opt_deps), args.depth)
} else {
powerset(features, args.depth)
};
let features = powerset(features, args.depth);

if package.features.is_empty() && features.is_empty() {
if (package.features.is_empty() || !args.include_features.is_empty())
&& features.is_empty()
{
*total += 1;
Kind::Nomal { show_progress: true }
} else {
Expand Down
11 changes: 10 additions & 1 deletion tests/long-help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ OPTIONS:

To exclude run of default feature, using value `--exclude-features default`.

To exclude run of just --no-default-features flag, using --exclude-no-default-features flag.

To exclude run of just --all-features flag, using --exclude-all-features flag.

This flag can only be used together with either --each-feature flag or --feature-powerset flag.

--exclude-no-default-features
Expand All @@ -71,6 +75,11 @@ OPTIONS:

This flag can only be used together with --feature-powerset flag.

--include-features <FEATURES>...
Include only the specified features in the feature combinations instead of package features.

This flag can only be used together with either --each-feature flag or --feature-powerset flag.

--no-dev-deps
Perform without dev-dependencies.

Expand All @@ -85,7 +94,7 @@ OPTIONS:
--ignore-unknown-features
Skip passing --features flag to `cargo` if that feature does not exist in the package.

This flag can only be used in the root of a virtual workspace or together with --workspace.
This flag can only be used together with either --features or --include-features.

--clean-per-run
Remove artifacts for that package before running the command.
Expand Down
1 change: 1 addition & 0 deletions tests/short-help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ OPTIONS:
--exclude-no-default-features Exclude run of just --no-default-features flag
--exclude-all-features Exclude run of just --all-features flag
--depth <NUM> Specify a max number of simultaneous feature flags of --feature-powerset
--include-features <FEATURES>... Include only the specified features in the feature combinations instead of package features
--no-dev-deps Perform without dev-dependencies
--remove-dev-deps Equivalent to --no-dev-deps flag except for does not restore the original `Cargo.toml` after performed
--ignore-private Skip to perform on `publish = false` packages
Expand Down
45 changes: 44 additions & 1 deletion tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ fn ignore_unknown_features_failure() {
.unwrap()
.assert_failure()
.assert_stderr_contains(
"--ignore-unknown-features can only be used together with --features",
"--ignore-unknown-features can only be used together with either --features or --include-features",
);
}

Expand Down Expand Up @@ -654,6 +654,49 @@ fn depth_failure() {
.assert_stderr_contains("--depth can only be used together with --feature-powerset");
}

#[test]
fn include_features() {
cargo_hack()
.args(&["check", "--each-feature", "--include-features", "a,b"])
.current_dir(test_dir("tests/fixtures/real"))
.output()
.unwrap()
.assert_success()
.assert_stderr_contains("running `cargo check` on real (1/5)")
.assert_stderr_contains("running `cargo check --no-default-features` on real (2/5)")
.assert_stderr_contains(
"running `cargo check --no-default-features --features a` on real (3/5)",
)
.assert_stderr_contains(
"running `cargo check --no-default-features --features b` on real (4/5)",
)
.assert_stderr_not_contains("--features c")
.assert_stderr_contains(
"running `cargo check --no-default-features --all-features` on real (5/5)",
);

cargo_hack()
.args(&["check", "--feature-powerset", "--include-features", "a,b"])
.current_dir(test_dir("tests/fixtures/real"))
.output()
.unwrap()
.assert_success()
.assert_stderr_contains("running `cargo check` on real (1/6)")
.assert_stderr_contains("running `cargo check --no-default-features` on real (2/6)")
.assert_stderr_contains(
"running `cargo check --no-default-features --features a` on real (3/6)",
)
.assert_stderr_contains(
"running `cargo check --no-default-features --features b` on real (4/6)",
)
.assert_stderr_contains(
"running `cargo check --no-default-features --features a,b` on real (5/6)",
)
.assert_stderr_contains(
"running `cargo check --no-default-features --all-features` on real (6/6)",
);
}

#[test]
fn exclude_features_failure() {
cargo_hack()
Expand Down