Skip to content

Commit

Permalink
Adjust optional dependencies handling to fix breakage on nightly-2022…
Browse files Browse the repository at this point in the history
…-01-20+
  • Loading branch information
taiki-e committed Jan 21, 2022
1 parent 7846e42 commit 59f438b
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 32 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com

## [Unreleased]

- Fix breakage on nightly-2022-01-20 or later. ([#146](https://github.com/taiki-e/cargo-hack/pull/146))

## [0.5.10] - 2022-01-05

- Fix handling of combined short flags. ([#143](https://github.com/taiki-e/cargo-hack/pull/143))
Expand Down
35 changes: 19 additions & 16 deletions src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ use std::{

use crate::{metadata::Metadata, PackageId};

#[derive(Debug)]
pub(crate) struct Features {
features: Vec<Feature>,
/// [package features len, package features + optional deps len]
len: [usize; 2],
optional_deps_start: usize,
deps_features_start: usize,
}

impl Features {
Expand All @@ -17,14 +18,19 @@ impl Features {
let node = &metadata.resolve.nodes[id];

let mut features = Vec::with_capacity(package.features.len());
let mut optional_deps = vec![];

for name in package.features.keys() {
features.push(name.into());
}
for name in package.optional_deps() {
features.push(name.into());
optional_deps.push(name);
}
for name in package.features.keys() {
if !optional_deps.contains(&&**name) {
features.push(name.into());
}
}
let len = [package.features.len(), features.len()];
let optional_deps_start = features.len();
features.extend(optional_deps.into_iter().map(Into::into));
let deps_features_start = features.len();

// TODO: Unpublished dependencies are not included in `node.deps`.
for dep in node.deps.iter().filter(|dep| {
Expand All @@ -42,19 +48,19 @@ impl Features {
// TODO: Optional deps of `dep_package`.
}

Self { features, len }
Self { features, optional_deps_start, deps_features_start }
}

pub(crate) fn normal(&self) -> &[Feature] {
&self.features[..self.len[0]]
&self.features[..self.optional_deps_start]
}

pub(crate) fn optional_deps(&self) -> &[Feature] {
&self.features[self.len[0]..self.len[1]]
&self.features[self.optional_deps_start..self.deps_features_start]
}

pub(crate) fn deps_features(&self) -> &[Feature] {
&self.features[self.len[1]..]
&self.features[self.deps_features_start..]
}

pub(crate) fn contains(&self, name: &str) -> bool {
Expand All @@ -66,26 +72,23 @@ impl Features {
#[derive(Debug)]
pub(crate) enum Feature {
/// A feature of the current crate.
#[allow(dead_code)] // false positive that fixed in Rust 1.44
Normal {
/// Feature name. It is considered indivisible.
name: String,
},
/// Grouped features.
#[allow(dead_code)] // false positive that fixed in Rust 1.44
Group {
/// Feature name concatenated with `,`.
name: String,
/// Original feature list.
list: Vec<String>,
},
/// A feature of a dependency.
#[allow(dead_code)] // false positive that fixed in Rust 1.44
Path {
/// Feature path separated with `/`.
name: String,
/// Index of `/`.
slash: usize,
_slash: usize,
},
}

Expand All @@ -96,7 +99,7 @@ impl Feature {
}

pub(crate) fn path(parent: &str, name: &str) -> Self {
Self::Path { name: format!("{}/{}", parent, name), slash: parent.len() }
Self::Path { name: format!("{}/{}", parent, name), _slash: parent.len() }
}

pub(crate) fn name(&self) -> &str {
Expand Down
33 changes: 20 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,27 +145,26 @@ fn determine_kind<'a>(cx: &'a Context, id: &PackageId, progress: &mut Progress)
}

let package = cx.packages(id);
let pkg_features = cx.pkg_features(id);
let filter = |&f: &&Feature| {
!cx.exclude_features.iter().any(|s| f == s)
&& !cx.group_features.iter().any(|g| g.matches(f.name()))
};
let features = if cx.include_features.is_empty() {
let feature_list = cx.pkg_features(id);

cx.exclude_features.iter().for_each(|d| {
if !feature_list.contains(d) {
if !pkg_features.contains(d) {
warn!("specified feature `{}` not found in package `{}`", d, package.name);
}
});

let mut features: Vec<_> = feature_list.normal().iter().filter(filter).collect();
let mut features: Vec<_> = pkg_features.normal().iter().filter(filter).collect();

if let Some(opt_deps) = &cx.optional_deps {
if opt_deps.len() == 1 && opt_deps[0].is_empty() {
// --optional-deps=
} else {
for d in opt_deps {
if !feature_list.optional_deps().iter().any(|f| f == d) {
if !pkg_features.optional_deps().iter().any(|f| f == d) {
warn!(
"specified optional dependency `{}` not found in package `{}`",
d, package.name
Expand All @@ -174,13 +173,13 @@ fn determine_kind<'a>(cx: &'a Context, id: &PackageId, progress: &mut Progress)
}
}

features.extend(feature_list.optional_deps().iter().filter(|f| {
features.extend(pkg_features.optional_deps().iter().filter(|f| {
filter(f) && (opt_deps.is_empty() || opt_deps.iter().any(|x| *f == x))
}));
}

if cx.include_deps_features {
features.extend(feature_list.deps_features().iter().filter(filter));
features.extend(pkg_features.deps_features().iter().filter(filter));
}

if !cx.group_features.is_empty() {
Expand All @@ -193,29 +192,35 @@ fn determine_kind<'a>(cx: &'a Context, id: &PackageId, progress: &mut Progress)
};

if cx.each_feature {
if (package.features.is_empty() || !cx.include_features.is_empty()) && features.is_empty() {
if (pkg_features.normal().is_empty() && pkg_features.optional_deps().is_empty()
|| !cx.include_features.is_empty())
&& features.is_empty()
{
progress.total += 1;
Kind::Normal
} else {
progress.total += features.len()
+ !cx.exclude_no_default_features as usize
+ (!cx.exclude_all_features
&& package.features.len() + package.optional_deps().count() > 1)
&& pkg_features.normal().len() + pkg_features.optional_deps().len() > 1)
as usize;
Kind::Each { features }
}
} else if cx.feature_powerset {
let features = features::feature_powerset(features, cx.depth, &package.features);

if (package.features.is_empty() || !cx.include_features.is_empty()) && features.is_empty() {
if (pkg_features.normal().is_empty() && pkg_features.optional_deps().is_empty()
|| !cx.include_features.is_empty())
&& features.is_empty()
{
progress.total += 1;
Kind::Normal
} else {
// -1: the first element of a powerset is `[]`
progress.total += features.len() - 1
+ !cx.exclude_no_default_features as usize
+ (!cx.exclude_all_features
&& package.features.len() + package.optional_deps().count() > 1)
&& pkg_features.normal().len() + pkg_features.optional_deps().len() > 1)
as usize;
Kind::Powerset { features }
}
Expand Down Expand Up @@ -350,8 +355,10 @@ fn exec_actual(
_ => unreachable!(),
}

let pkg = cx.packages(id);
if !cx.exclude_all_features && pkg.features.len() + pkg.optional_deps().count() > 1 {
let pkg_features = cx.pkg_features(id);
if !cx.exclude_all_features
&& pkg_features.normal().len() + pkg_features.optional_deps().len() > 1
{
// run with all features
// https://github.com/taiki-e/cargo-hack/issues/42
line.arg("--all-features");
Expand Down
15 changes: 12 additions & 3 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1083,10 +1083,14 @@ fn optional_deps() {

cargo_hack(["check", "--each-feature"])
.assert_success2("optional_deps", Some(31))
.stderr_contains("running `cargo check` on optional_deps (1/1)")
.stderr_contains(
"
running `cargo check --no-default-features` on optional_deps (1/2)
running `cargo check --no-default-features --all-features` on optional_deps (2/2)
",
)
.stderr_not_contains(
"
--no-default-features
--features real
--features renemed
",
Expand Down Expand Up @@ -1127,7 +1131,12 @@ fn optional_deps() {

cargo_hack(["check", "--each-feature", "--optional-deps="])
.assert_success2("optional_deps", Some(31))
.stderr_contains("running `cargo check` on optional_deps (1/1)");
.stderr_contains(
"
running `cargo check --no-default-features` on optional_deps (1/2)
running `cargo check --no-default-features --all-features` on optional_deps (2/2)
",
);
}

#[test]
Expand Down

0 comments on commit 59f438b

Please sign in to comment.