Skip to content

Commit 48f8f54

Browse files
authored
Auto merge of #3280 - alexcrichton:test-features, r=brson
Fix passing --features when testing multiple packages The wrong method was being passed to resolution accidentally. Features specified via `--features` and `--no-default-features` are spec'd as only applying to the *current* package, not all packages. Closes #3279
2 parents be0873c + d21cb9a commit 48f8f54

File tree

4 files changed

+90
-22
lines changed

4 files changed

+90
-22
lines changed

src/cargo/ops/cargo_compile.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub fn resolve_dependencies<'a>(ws: &Workspace<'a>,
103103
features: &[String],
104104
all_features: bool,
105105
no_default_features: bool,
106-
spec: &'a [String])
106+
specs: &[PackageIdSpec])
107107
-> CargoResult<(PackageSet<'a>, Resolve)> {
108108
let features = features.iter().flat_map(|s| {
109109
s.split_whitespace()
@@ -137,13 +137,10 @@ pub fn resolve_dependencies<'a>(ws: &Workspace<'a>,
137137
}
138138
};
139139

140-
let specs = try!(spec.iter().map(|p| PackageIdSpec::parse(p))
141-
.collect::<CargoResult<Vec<_>>>());
142-
143140
let resolved_with_overrides =
144141
try!(ops::resolve_with_previous(&mut registry, ws,
145142
method, Some(&resolve), None,
146-
&specs));
143+
specs));
147144

148145
let packages = ops::get_resolved_packages(&resolved_with_overrides,
149146
registry);
@@ -174,8 +171,16 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>,
174171
try!(generate_targets(root_package, profiles, mode, filter, release));
175172
}
176173

177-
let (packages, resolve_with_overrides) =
178-
try!(resolve_dependencies(ws, source, features, all_features, no_default_features, spec));
174+
let specs = try!(spec.iter().map(|p| PackageIdSpec::parse(p))
175+
.collect::<CargoResult<Vec<_>>>());
176+
177+
let pair = try!(resolve_dependencies(ws,
178+
source,
179+
features,
180+
all_features,
181+
no_default_features,
182+
&specs));
183+
let (packages, resolve_with_overrides) = pair;
179184

180185
let mut pkgids = Vec::new();
181186
if spec.len() > 0 {

src/cargo/ops/cargo_output_metadata.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_serialize::{Encodable, Encoder};
22

33
use core::resolver::Resolve;
4-
use core::{Package, PackageId, Workspace};
4+
use core::{Package, PackageId, PackageIdSpec, Workspace};
55
use ops;
66
use util::CargoResult;
77

@@ -43,12 +43,15 @@ fn metadata_no_deps(ws: &Workspace,
4343

4444
fn metadata_full(ws: &Workspace,
4545
opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
46+
let specs = ws.members().map(|pkg| {
47+
PackageIdSpec::from_package_id(pkg.package_id())
48+
}).collect::<Vec<_>>();
4649
let deps = try!(ops::resolve_dependencies(ws,
4750
None,
4851
&opt.features,
4952
opt.all_features,
5053
opt.no_default_features,
51-
&[]));
54+
&specs));
5255
let (packages, resolve) = deps;
5356

5457
let packages = try!(packages.package_ids()

src/cargo/ops/resolve.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -90,24 +90,50 @@ pub fn resolve_with_previous<'a>(registry: &mut PackageRegistry,
9090
for member in ws.members() {
9191
try!(registry.add_sources(&[member.package_id().source_id()
9292
.clone()]));
93+
let method_to_resolve = match method {
94+
// When everything for a workspace we want to be sure to resolve all
95+
// members in the workspace, so propagate the `Method::Everything`.
96+
Method::Everything => Method::Everything,
9397

94-
// If we're resolving everything then we include all members of the
95-
// workspace. If we want a specific set of requirements and we're
96-
// compiling only a single workspace crate then resolve only it. This
97-
// case should only happen after we have a previous resolution, however,
98-
// so assert that the previous exists.
99-
if let Method::Required { .. } = method {
100-
assert!(previous.is_some());
101-
if let Some(current) = ws.current_opt() {
102-
if member.package_id() != current.package_id() &&
103-
!specs.iter().any(|spec| spec.matches(member.package_id())) {
104-
continue;
98+
// If we're not resolving everything though then the workspace is
99+
// already resolved and now we're drilling down from that to the
100+
// exact crate graph we're going to build. Here we don't necessarily
101+
// want to keep around all workspace crates as they may not all be
102+
// built/tested.
103+
//
104+
// Additionally, the `method` specified represents command line
105+
// flags, which really only matters for the current package
106+
// (determined by the cwd). If other packages are specified (via
107+
// `-p`) then the command line flags like features don't apply to
108+
// them.
109+
//
110+
// As a result, if this `member` is the current member of the
111+
// workspace, then we use `method` specified. Otherwise we use a
112+
// base method with no features specified but using default features
113+
// for any other packages specified with `-p`.
114+
Method::Required { dev_deps, .. } => {
115+
assert!(previous.is_some());
116+
let base = Method::Required {
117+
dev_deps: dev_deps,
118+
features: &[],
119+
uses_default_features: true,
120+
};
121+
let member_id = member.package_id();
122+
match ws.current_opt() {
123+
Some(current) if member_id == current.package_id() => method,
124+
_ => {
125+
if specs.iter().any(|spec| spec.matches(member_id)) {
126+
base
127+
} else {
128+
continue
129+
}
130+
}
105131
}
106132
}
107-
}
133+
};
108134

109135
let summary = registry.lock(member.summary().clone());
110-
summaries.push((summary, method));
136+
summaries.push((summary, method_to_resolve));
111137
}
112138

113139
let root_replace = ws.root_replace();

tests/test.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,3 +2364,37 @@ fn test_release_ignore_panic() {
23642364
println!("bench");
23652365
assert_that(p.cargo("bench").arg("-v"), execs().with_status(0));
23662366
}
2367+
2368+
#[test]
2369+
fn test_many_with_features() {
2370+
let p = project("foo")
2371+
.file("Cargo.toml", r#"
2372+
[package]
2373+
name = "foo"
2374+
version = "0.0.1"
2375+
authors = []
2376+
2377+
[dependencies]
2378+
a = { path = "a" }
2379+
2380+
[features]
2381+
foo = []
2382+
2383+
[workspace]
2384+
"#)
2385+
.file("src/lib.rs", "")
2386+
.file("a/Cargo.toml", r#"
2387+
[package]
2388+
name = "a"
2389+
version = "0.0.1"
2390+
authors = []
2391+
"#)
2392+
.file("a/src/lib.rs", "");
2393+
p.build();
2394+
2395+
assert_that(p.cargo("test").arg("-v")
2396+
.arg("-p").arg("a")
2397+
.arg("-p").arg("foo")
2398+
.arg("--features").arg("foo"),
2399+
execs().with_status(0));
2400+
}

0 commit comments

Comments
 (0)