Skip to content

Commit 879f483

Browse files
committed
Auto merge of #5012 - infinity0:pr4988, r=alexcrichton
Don't require dev-dependencies when not needed in certain cases Specifically, when running `cargo install` and add a flag for this behaviour in `cargo build`. This closes #4988.
2 parents 3ea4f3b + d46db71 commit 879f483

File tree

10 files changed

+159
-30
lines changed

10 files changed

+159
-30
lines changed

src/bin/build.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ pub fn execute(options: Options, config: &mut Config) -> CliResult {
9898
&options.flag_z)?;
9999

100100
let root = find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())?;
101-
let ws = Workspace::new(&root, config)?;
101+
let mut ws = Workspace::new(&root, config)?;
102+
if config.cli_unstable().avoid_dev_deps {
103+
ws.set_require_optional_deps(false);
104+
}
102105

103106
let spec = Packages::from_flags(options.flag_all,
104107
&options.flag_exclude,

src/cargo/core/features.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ pub struct CliUnstable {
278278
pub unstable_options: bool,
279279
pub offline: bool,
280280
pub no_index_update: bool,
281+
pub avoid_dev_deps: bool,
281282
}
282283

283284
impl CliUnstable {
@@ -310,6 +311,7 @@ impl CliUnstable {
310311
"unstable-options" => self.unstable_options = true,
311312
"offline" => self.offline = true,
312313
"no-index-update" => self.no_index_update = true,
314+
"avoid-dev-deps" => self.avoid_dev_deps = true,
313315
_ => bail!("unknown `-Z` flag specified: {}", k),
314316
}
315317

src/cargo/core/resolver/mod.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,26 @@ pub struct DepsNotReplaced<'a> {
9898

9999
#[derive(Clone, Copy)]
100100
pub enum Method<'a> {
101-
Everything,
101+
Everything, // equivalent to Required { dev_deps: true, all_features: true, .. }
102102
Required {
103103
dev_deps: bool,
104104
features: &'a [String],
105+
all_features: bool,
105106
uses_default_features: bool,
106107
},
107108
}
108109

110+
impl<'r> Method<'r> {
111+
pub fn split_features(features: &[String]) -> Vec<String> {
112+
features.iter()
113+
.flat_map(|s| s.split_whitespace())
114+
.flat_map(|s| s.split(','))
115+
.filter(|s| !s.is_empty())
116+
.map(|s| s.to_string())
117+
.collect::<Vec<String>>()
118+
}
119+
}
120+
109121
// Information about the dependencies for a crate, a tuple of:
110122
//
111123
// (dependency info, candidates, features activated)
@@ -910,6 +922,7 @@ fn activate_deps_loop(
910922
let method = Method::Required {
911923
dev_deps: false,
912924
features: &features,
925+
all_features: false,
913926
uses_default_features: dep.uses_default_features(),
914927
};
915928
trace!("{}[{}]>{} trying {}", parent.name(), cur, dep.name(), candidate.summary.version());
@@ -1255,7 +1268,8 @@ fn build_requirements<'a, 'b: 'a>(s: &'a Summary, method: &'b Method)
12551268
-> CargoResult<Requirements<'a>> {
12561269
let mut reqs = Requirements::new(s);
12571270
match *method {
1258-
Method::Everything => {
1271+
Method::Everything |
1272+
Method::Required { all_features: true, .. } => {
12591273
for key in s.features().keys() {
12601274
reqs.require_feature(key)?;
12611275
}
@@ -1308,10 +1322,11 @@ impl Context {
13081322
}
13091323
debug!("checking if {} is already activated", summary.package_id());
13101324
let (features, use_default) = match *method {
1325+
Method::Everything |
1326+
Method::Required { all_features: true, .. } => return Ok(false),
13111327
Method::Required { features, uses_default_features, .. } => {
13121328
(features, uses_default_features)
13131329
}
1314-
Method::Everything => return Ok(false),
13151330
};
13161331

13171332
let has_default_feature = summary.features().contains_key("default");

src/cargo/core/workspace.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ pub struct Workspace<'cfg> {
6464

6565
// True if this workspace should enforce optional dependencies even when
6666
// not needed; false if this workspace should only enforce dependencies
67-
// needed by the current configuration (such as in cargo install).
67+
// needed by the current configuration (such as in cargo install). In some
68+
// cases `false` also results in the non-enforcement of dev-dependencies.
6869
require_optional_deps: bool,
6970
}
7071

@@ -296,6 +297,11 @@ impl<'cfg> Workspace<'cfg> {
296297
self.require_optional_deps
297298
}
298299

300+
pub fn set_require_optional_deps<'a>(&'a mut self, require_optional_deps: bool) -> &mut Workspace<'cfg> {
301+
self.require_optional_deps = require_optional_deps;
302+
self
303+
}
304+
299305
/// Finds the root of a workspace for the crate whose manifest is located
300306
/// at `manifest_path`.
301307
///

src/cargo/ops/cargo_compile.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use std::sync::Arc;
2929

3030
use core::{Source, Package, Target};
3131
use core::{Profile, TargetKind, Profiles, Workspace, PackageId, PackageIdSpec};
32-
use core::resolver::Resolve;
32+
use core::resolver::{Resolve, Method};
3333
use ops::{self, BuildOutput, Executor, DefaultExecutor};
3434
use util::config::Config;
3535
use util::{CargoResult, profile};
@@ -233,12 +233,18 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>,
233233
let profiles = ws.profiles();
234234

235235
let specs = spec.into_package_id_specs(ws)?;
236-
let resolve = ops::resolve_ws_precisely(ws,
237-
source,
238-
features,
239-
all_features,
240-
no_default_features,
241-
&specs)?;
236+
let features = Method::split_features(features);
237+
let method = Method::Required {
238+
dev_deps: ws.require_optional_deps() || filter.need_dev_deps(),
239+
features: &features,
240+
all_features,
241+
uses_default_features: !no_default_features,
242+
};
243+
let resolve = ops::resolve_ws_with_method(ws,
244+
source,
245+
method,
246+
&specs,
247+
)?;
242248
let (packages, resolve_with_overrides) = resolve;
243249

244250
let to_builds = specs.iter().map(|p| {
@@ -414,6 +420,14 @@ impl<'a> CompileFilter<'a> {
414420
}
415421
}
416422

423+
pub fn need_dev_deps(&self) -> bool {
424+
match *self {
425+
CompileFilter::Default { .. } => true,
426+
CompileFilter::Only { examples, tests, benches, .. } =>
427+
examples.is_specific() || tests.is_specific() || benches.is_specific()
428+
}
429+
}
430+
417431
pub fn matches(&self, target: &Target) -> bool {
418432
match *self {
419433
CompileFilter::Default { .. } => true,

src/cargo/ops/cargo_install.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,11 @@ fn install_one(root: &Filesystem,
176176

177177
let ws = match overidden_target_dir {
178178
Some(dir) => Workspace::ephemeral(pkg, config, Some(dir), false)?,
179-
None => Workspace::new(pkg.manifest_path(), config)?,
179+
None => {
180+
let mut ws = Workspace::new(pkg.manifest_path(), config)?;
181+
ws.set_require_optional_deps(false);
182+
ws
183+
}
180184
};
181185
let pkg = ws.current()?;
182186

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub use self::registry::{modify_owners, yank, OwnersOptions, PublishOpts};
2222
pub use self::registry::configure_http_handle;
2323
pub use self::cargo_fetch::fetch;
2424
pub use self::cargo_pkgid::pkgid;
25-
pub use self::resolve::{resolve_ws, resolve_ws_precisely, resolve_with_previous};
25+
pub use self::resolve::{resolve_ws, resolve_ws_precisely, resolve_ws_with_method, resolve_with_previous};
2626
pub use self::cargo_output_metadata::{output_metadata, OutputMetadataOptions, ExportInfo};
2727

2828
mod cargo_clean;

src/cargo/ops/resolve.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,25 @@ pub fn resolve_ws_precisely<'a>(ws: &Workspace<'a>,
2929
no_default_features: bool,
3030
specs: &[PackageIdSpec])
3131
-> CargoResult<(PackageSet<'a>, Resolve)> {
32-
let features = features.iter()
33-
.flat_map(|s| s.split_whitespace())
34-
.flat_map(|s| s.split(','))
35-
.filter(|s| !s.is_empty())
36-
.map(|s| s.to_string())
37-
.collect::<Vec<String>>();
32+
let features = Method::split_features(features);
33+
let method = if all_features {
34+
Method::Everything
35+
} else {
36+
Method::Required {
37+
dev_deps: true,
38+
features: &features,
39+
all_features: false,
40+
uses_default_features: !no_default_features,
41+
}
42+
};
43+
resolve_ws_with_method(ws, source, method, specs)
44+
}
3845

46+
pub fn resolve_ws_with_method<'a>(ws: &Workspace<'a>,
47+
source: Option<Box<Source + 'a>>,
48+
method: Method,
49+
specs: &[PackageIdSpec])
50+
-> CargoResult<(PackageSet<'a>, Resolve)> {
3951
let mut registry = PackageRegistry::new(ws.config())?;
4052
if let Some(source) = source {
4153
registry.add_preloaded(source);
@@ -68,16 +80,6 @@ pub fn resolve_ws_precisely<'a>(ws: &Workspace<'a>,
6880
ops::load_pkg_lockfile(ws)?
6981
};
7082

71-
let method = if all_features {
72-
Method::Everything
73-
} else {
74-
Method::Required {
75-
dev_deps: true, // TODO: remove this option?
76-
features: &features,
77-
uses_default_features: !no_default_features,
78-
}
79-
};
80-
8183
let resolved_with_overrides =
8284
ops::resolve_with_previous(&mut registry,
8385
ws,
@@ -236,6 +238,7 @@ pub fn resolve_with_previous<'a>(registry: &mut PackageRegistry,
236238
let base = Method::Required {
237239
dev_deps,
238240
features: &[],
241+
all_features: false,
239242
uses_default_features: true,
240243
};
241244
let member_id = member.package_id();

tests/testsuite/build.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4290,3 +4290,28 @@ fn no_linkable_target() {
42904290
[WARNING] The package `the_lib` provides no linkable [..] \
42914291
while compiling `foo`. [..] in `the_lib`'s Cargo.toml. [..]"));
42924292
}
4293+
4294+
#[test]
4295+
fn avoid_dev_deps() {
4296+
Package::new("foo", "1.0.0").publish();
4297+
let p = project("foo")
4298+
.file("Cargo.toml", r#"
4299+
[package]
4300+
name = "bar"
4301+
version = "0.1.0"
4302+
authors = []
4303+
4304+
[dev-dependencies]
4305+
baz = "1.0.0"
4306+
"#)
4307+
.file("src/main.rs", "fn main() {}")
4308+
.build();
4309+
4310+
// --bins is needed because of #5134
4311+
assert_that(p.cargo("build").arg("--bins"),
4312+
execs().with_status(101));
4313+
assert_that(p.cargo("build").arg("--bins")
4314+
.masquerade_as_nightly_cargo()
4315+
.arg("-Zavoid-dev-deps"),
4316+
execs().with_status(0));
4317+
}

tests/testsuite/install.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fs::{self, File, OpenOptions};
33
use std::io::prelude::*;
44

55
use cargo::util::ProcessBuilder;
6+
use cargotest::ChannelChanger;
67
use cargotest::install::{cargo_home, has_installed_exe};
78
use cargotest::support::git;
89
use cargotest::support::paths;
@@ -904,6 +905,62 @@ fn use_path_workspace() {
904905
assert_eq!(lock, lock2, "different lockfiles");
905906
}
906907

908+
#[test]
909+
fn dev_dependencies_no_check() {
910+
Package::new("foo", "1.0.0").publish();
911+
let p = project("foo")
912+
.file("Cargo.toml", r#"
913+
[package]
914+
name = "bar"
915+
version = "0.1.0"
916+
authors = []
917+
918+
[dev-dependencies]
919+
baz = "1.0.0"
920+
"#)
921+
.file("src/main.rs", "fn main() {}")
922+
.build();
923+
924+
// --bins is needed because of #5134
925+
assert_that(p.cargo("build").arg("--bins"),
926+
execs().with_status(101));
927+
assert_that(p.cargo("install").arg("--bins"),
928+
execs().with_status(0));
929+
}
930+
931+
#[test]
932+
fn dev_dependencies_lock_file_untouched() {
933+
Package::new("foo", "1.0.0").publish();
934+
let p = project("foo")
935+
.file("Cargo.toml", r#"
936+
[package]
937+
name = "foo"
938+
version = "0.1.0"
939+
authors = []
940+
941+
[dev-dependencies]
942+
bar = { path = "a" }
943+
"#)
944+
.file("src/main.rs", "fn main() {}")
945+
.file("a/Cargo.toml", r#"
946+
[package]
947+
name = "bar"
948+
version = "0.1.0"
949+
authors = []
950+
"#)
951+
.file("a/src/lib.rs", "")
952+
.build();
953+
954+
// --bins is needed because of #5134
955+
assert_that(p.cargo("build").arg("--bins"),
956+
execs().with_status(0));
957+
let lock = p.read_lockfile();
958+
assert_that(p.cargo("install").arg("--bins"),
959+
execs().with_status(0));
960+
let lock2 = p.read_lockfile();
961+
assert!(lock == lock2, "different lockfiles");
962+
}
963+
907964
#[test]
908965
fn vers_precise() {
909966
pkg("foo", "0.1.1");

0 commit comments

Comments
 (0)