From 07eca1ee9b06e10c4907300e63e8fecb39cc6a88 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 24 Aug 2016 22:27:34 -0700 Subject: [PATCH 01/12] Cargo is aware of the sysroot and compiler source The location of the compiler source can be overwritten, but ca --- src/cargo/core/source.rs | 10 ++++++++++ src/cargo/sources/config.rs | 10 ++++++++++ src/cargo/util/rustc.rs | 13 ++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index 4a46c19294d..92fa8753307 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -242,6 +242,16 @@ impl SourceId { Ok(SourceId::for_registry(&url)) } + /// Returns the `SourceId` corresponding to the compiler source + /// + /// This is located in the sysroot in /rustlib/src. + pub fn compiler(config: &Config) -> CargoResult { + let mut loc = try!(config.rustc()).sysroot.clone(); + loc.push("rustlib"); + loc.push("src"); + Self::for_local_registry(&loc) + } + pub fn url(&self) -> &Url { &self.inner.url } diff --git a/src/cargo/sources/config.rs b/src/cargo/sources/config.rs index ac254f147ec..6d9f9156e61 100644 --- a/src/cargo/sources/config.rs +++ b/src/cargo/sources/config.rs @@ -59,6 +59,10 @@ impl<'cfg> SourceConfigMap<'cfg> { id: try!(SourceId::crates_io(config)), replace_with: None, }); + base.add("compiler", SourceConfig { + id: try!(SourceId::compiler(config)), + replace_with: None, + }); Ok(base) } @@ -165,6 +169,12 @@ a lock file compatible with `{orig}` cannot be generated in this situation `source.{}`", name))) } + if name == "compiler" || src == try!(SourceId::compiler(self.config)) { + try!(self.config.shell().warn( + "the \"compiler source\" is unstable \ + and may be removed in any later version of Cargo")); + } + let mut replace_with = None; if let Some(val) = table.get("replace-with") { let (s, path) = try!(val.string(&format!("source.{}.replace-with", diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs index 59a6e17e1fe..fd21888fc68 100644 --- a/src/cargo/util/rustc.rs +++ b/src/cargo/util/rustc.rs @@ -6,6 +6,7 @@ pub struct Rustc { pub path: PathBuf, pub verbose_version: String, pub host: String, + pub sysroot: PathBuf, /// Backwards compatibility: does this compiler support `--cap-lints` flag? pub cap_lints: bool, } @@ -29,9 +30,18 @@ impl Rustc { }; let verbose_version = try!(String::from_utf8(output.stdout).map_err(|_| { - internal("rustc -v didn't return utf8 output") + internal("rustc -v didn't return UTF-8 output") })); + let mut sysroot_raw = try!(util::process(&path).arg("--print").arg("sysroot") + .exec_with_output()).stdout; + // Trim final newline + assert_eq!(sysroot_raw.pop(), Some(b'\n')); + // What about invalid code sequences on Windows? + let sysroot = From::from(try!(String::from_utf8(sysroot_raw).map_err(|_| { + internal("rustc --print sysroot didn't not return UTF-8 output") + }))); + let host = { let triple = verbose_version.lines().find(|l| { l.starts_with("host: ") @@ -46,6 +56,7 @@ impl Rustc { path: path, verbose_version: verbose_version, host: host, + sysroot: sysroot, cap_lints: cap_lints, }) } From 398448c59e15e0fa6492f8803257e811814b5a80 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 26 Aug 2016 15:20:50 -0700 Subject: [PATCH 02/12] Explicit stdlib deps --- src/cargo/util/toml.rs | 53 ++++++++++++++++++++--------- tests/bad-config.rs | 2 +- tests/stdlib-deps.rs | 75 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 16 deletions(-) create mode 100644 tests/stdlib-deps.rs diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 4686eb9a29d..74e786244b9 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -223,6 +223,7 @@ pub struct DetailedTomlDependency { branch: Option, tag: Option, rev: Option, + stdlib: Option, features: Option>, optional: Option, default_features: Option, @@ -580,6 +581,7 @@ impl TomlManifest { fn process_dependencies( cx: &mut Context, new_deps: Option<&HashMap>, + allow_explicit_stdlib: bool, kind: Option) -> CargoResult<()> { @@ -588,6 +590,16 @@ impl TomlManifest { None => return Ok(()) }; for (n, v) in dependencies.iter() { + if let &TomlDependency::Detailed(DetailedTomlDependency { + stdlib: Some(true), + .. + }) = v { + if !allow_explicit_stdlib { + return Err(human(format!( + "dependency {} cannot have `stdlib = true`", + n))) + } + } let dep = try!(v.to_dependency(n, cx, kind)); cx.deps.push(dep); } @@ -597,23 +609,23 @@ impl TomlManifest { // Collect the deps try!(process_dependencies(&mut cx, self.dependencies.as_ref(), - None)); + true, None)); try!(process_dependencies(&mut cx, self.dev_dependencies.as_ref(), - Some(Kind::Development))); + false, Some(Kind::Development))); try!(process_dependencies(&mut cx, self.build_dependencies.as_ref(), - Some(Kind::Build))); + false, Some(Kind::Build))); for (name, platform) in self.target.iter().flat_map(|t| t) { cx.platform = Some(try!(name.parse())); try!(process_dependencies(&mut cx, platform.dependencies.as_ref(), - None)); + true, None)); try!(process_dependencies(&mut cx, platform.build_dependencies.as_ref(), - Some(Kind::Build))); + false, Some(Kind::Build))); try!(process_dependencies(&mut cx, platform.dev_dependencies.as_ref(), - Some(Kind::Development))); + false, Some(Kind::Development))); } replace = try!(self.replace(&mut cx)); @@ -836,13 +848,19 @@ impl TomlDependency { } } - let new_source_id = match (details.git.as_ref(), details.path.as_ref()) { - (Some(git), maybe_path) => { - if maybe_path.is_some() { - let msg = format!("dependency ({}) specification is ambiguous. \ - Only one of `git` or `path` is allowed. \ - This will be considered an error in future versions", name); - cx.warnings.push(msg) + let one_source_message = format!( + "dependency ({}) specification is ambiguous. \ + Only one of `git` or `path` or `stdlib = true` is allowed. \ + This will be considered an error in future versions", + name); + + let new_source_id = match (details.git.as_ref(), + details.path.as_ref(), + details.stdlib) + { + (Some(git), maybe_path, maybe_stdlib) => { + if maybe_path.is_some() || (maybe_stdlib == Some(true)) { + cx.warnings.push(one_source_message) } let n_details = [&details.branch, &details.tag, &details.rev] @@ -864,7 +882,11 @@ impl TomlDependency { let loc = try!(git.to_url()); SourceId::for_git(&loc, reference) }, - (None, Some(path)) => { + (None, Some(path), maybe_stdlib) => { + if maybe_stdlib == Some(true) { + cx.warnings.push(one_source_message) + } + cx.nested_paths.push(PathBuf::from(path)); // If the source id for the package we're parsing is a path // source, then we normalize the path here to get rid of @@ -882,7 +904,8 @@ impl TomlDependency { cx.source_id.clone() } }, - (None, None) => try!(SourceId::crates_io(cx.config)), + (None, None, Some(true)) => try!(SourceId::compiler(cx.config)), + (None, None, _) => try!(SourceId::crates_io(cx.config)), }; let version = details.version.as_ref().map(|v| &v[..]); diff --git a/tests/bad-config.rs b/tests/bad-config.rs index f4a28e51d90..fedbd71ca25 100644 --- a/tests/bad-config.rs +++ b/tests/bad-config.rs @@ -822,7 +822,7 @@ fn both_git_and_path_specified() { assert_that(foo.cargo_process("build").arg("-v"), execs().with_stderr_contains("\ [WARNING] dependency (bar) specification is ambiguous. \ -Only one of `git` or `path` is allowed. \ +Only one of `git` or `path` or `stdlib = true` is allowed. \ This will be considered an error in future versions ")); } diff --git a/tests/stdlib-deps.rs b/tests/stdlib-deps.rs new file mode 100644 index 00000000000..a96e67c0cec --- /dev/null +++ b/tests/stdlib-deps.rs @@ -0,0 +1,75 @@ +#[macro_use] +extern crate cargotest; +extern crate hamcrest; + +use std::fs::{self, File}; +use std::io::prelude::*; + +use cargotest::support::{paths, project, execs}; +use cargotest::support::registry::Package; +use hamcrest::assert_that; + +fn setup() { + let root = paths::root(); + t!(fs::create_dir(&root.join(".cargo"))); + t!(t!(File::create(root.join(".cargo/config"))).write_all(br#" + [source.compiler] + registry = 'https://wut' + replace-with = 'my-awesome-local-registry' + + [source.my-awesome-local-registry] + local-registry = 'registry' + "#)); +} + +#[test] +fn explicit_stdlib_deps() { + setup(); + Package::new("core", "1.0.0").local(true).publish(); + + let p = project("local") + .file("Cargo.toml", r#" + [package] + name = "local" + version = "0.0.1" + authors = [] + + [dependencies] + core = { version = "1", stdlib = true } + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("update").arg("--verbose"), + execs().with_status(0).with_stderr( + "[WARNING] the \"compiler source\" is unstable [..]")); +} + +#[test] +fn unresolved_explicit_stdlib_deps() { + setup(); + let p = project("local") + .file("Cargo.toml", r#" + [package] + name = "local" + version = "0.0.1" + authors = [] + + [dependencies] + core = { version = "1", stdlib = true } + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("update").arg("--verbose"), + execs().with_status(101).with_stderr_contains("\ +[ERROR] failed to load source for a dependency on `core` + +Caused by: + Unable to update registry file://[..] + +Caused by: + failed to update replaced source `registry file://[..] + +Caused by: + local registry path is not a directory: [..] +")); +} From 88be50311b89d0b410744cb2580073514e3a2da1 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 24 Aug 2016 12:35:49 -0700 Subject: [PATCH 03/12] `to_dependency` takes a DetailedTomlDependency, elaboration is its own fn --- src/cargo/util/toml.rs | 71 +++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 74e786244b9..75cc4209882 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -590,17 +590,15 @@ impl TomlManifest { None => return Ok(()) }; for (n, v) in dependencies.iter() { - if let &TomlDependency::Detailed(DetailedTomlDependency { - stdlib: Some(true), - .. - }) = v { + let detailed = v.elaborate(); + if let Some(true) = detailed.stdlib { if !allow_explicit_stdlib { return Err(human(format!( "dependency {} cannot have `stdlib = true`", n))) } } - let dep = try!(v.to_dependency(n, cx, kind)); + let dep = try!(detailed.to_dependency(n, cx, kind)); cx.deps.push(dep); } @@ -758,16 +756,15 @@ impl TomlManifest { spec)) })); - let version_specified = match *replacement { - TomlDependency::Detailed(ref d) => d.version.is_some(), - TomlDependency::Simple(..) => true, - }; - if version_specified { + let replacement = replacement.elaborate(); + + if replacement.version.is_some() { bail!("replacements cannot specify a version \ requirement, but found one for `{}`", spec); } - let dep = try!(replacement.to_dependency(spec.name(), cx, None)); + let dep = try!(replacement + .to_dependency(spec.name(), cx, None)); let dep = { let version = try!(spec.version().chain_error(|| { human(format!("replacements must specify a version \ @@ -809,21 +806,25 @@ fn unique_build_targets(targets: &[Target], layout: &Layout) -> Result<(), Strin } impl TomlDependency { - fn to_dependency(&self, - name: &str, - cx: &mut Context, - kind: Option) - -> CargoResult { - let details = match *self { + fn elaborate(&self) -> DetailedTomlDependency { + match *self { TomlDependency::Simple(ref version) => DetailedTomlDependency { version: Some(version.clone()), .. Default::default() }, TomlDependency::Detailed(ref details) => details.clone(), - }; + } + } +} - if details.version.is_none() && details.path.is_none() && - details.git.is_none() { +impl DetailedTomlDependency { + fn to_dependency(self, + name: &str, + cx: &mut Context, + kind: Option) + -> CargoResult { + if self.version.is_none() && self.path.is_none() && + self.git.is_none() { let msg = format!("dependency ({}) specified without \ providing a local path, Git repository, or \ version to use. This will be considered an \ @@ -831,11 +832,11 @@ impl TomlDependency { cx.warnings.push(msg); } - if details.git.is_none() { + if self.git.is_none() { let git_only_keys = [ - (&details.branch, "branch"), - (&details.tag, "tag"), - (&details.rev, "rev") + (&self.branch, "branch"), + (&self.tag, "tag"), + (&self.rev, "rev") ]; for &(key, key_name) in git_only_keys.iter() { @@ -854,16 +855,16 @@ impl TomlDependency { This will be considered an error in future versions", name); - let new_source_id = match (details.git.as_ref(), - details.path.as_ref(), - details.stdlib) + let new_source_id = match (self.git.as_ref(), + self.path.as_ref(), + self.stdlib) { (Some(git), maybe_path, maybe_stdlib) => { if maybe_path.is_some() || (maybe_stdlib == Some(true)) { cx.warnings.push(one_source_message) } - let n_details = [&details.branch, &details.tag, &details.rev] + let n_details = [&self.branch, &self.tag, &self.rev] .iter() .filter(|d| d.is_some()) .count(); @@ -875,9 +876,9 @@ impl TomlDependency { cx.warnings.push(msg) } - let reference = details.branch.clone().map(GitReference::Branch) - .or_else(|| details.tag.clone().map(GitReference::Tag)) - .or_else(|| details.rev.clone().map(GitReference::Rev)) + let reference = self.branch.clone().map(GitReference::Branch) + .or_else(|| self.tag.clone().map(GitReference::Tag)) + .or_else(|| self.rev.clone().map(GitReference::Rev)) .unwrap_or_else(|| GitReference::Branch("master".to_string())); let loc = try!(git.to_url()); SourceId::for_git(&loc, reference) @@ -908,7 +909,7 @@ impl TomlDependency { (None, None, _) => try!(SourceId::crates_io(cx.config)), }; - let version = details.version.as_ref().map(|v| &v[..]); + let version = self.version.as_ref().map(|v| &v[..]); let mut dep = match cx.pkgid { Some(id) => { try!(DependencyInner::parse(name, version, &new_source_id, @@ -916,9 +917,9 @@ impl TomlDependency { } None => try!(DependencyInner::parse(name, version, &new_source_id, None)), }; - dep = dep.set_features(details.features.unwrap_or(Vec::new())) - .set_default_features(details.default_features.unwrap_or(true)) - .set_optional(details.optional.unwrap_or(false)) + dep = dep.set_features(self.features.unwrap_or(Vec::new())) + .set_default_features(self.default_features.unwrap_or(true)) + .set_optional(self.optional.unwrap_or(false)) .set_platform(cx.platform.clone()); if let Some(kind) = kind { dep = dep.set_kind(kind); From 734eefe78bfb6ae908bc5a7b33ed730759dcc1b7 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sat, 27 Aug 2016 14:50:56 -0700 Subject: [PATCH 04/12] Disallow stdlib deps in as replacements --- src/cargo/util/toml.rs | 5 +++++ tests/stdlib-deps.rs | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 75cc4209882..c21f463feca 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -763,6 +763,11 @@ impl TomlManifest { requirement, but found one for `{}`", spec); } + if let Some(true) = replacement.stdlib { + bail!("replacements cannot be standard library packages, \ + but found one for `{}`", spec); + } + let dep = try!(replacement .to_dependency(spec.name(), cx, None)); let dep = { diff --git a/tests/stdlib-deps.rs b/tests/stdlib-deps.rs index a96e67c0cec..4a87ddb8fbe 100644 --- a/tests/stdlib-deps.rs +++ b/tests/stdlib-deps.rs @@ -73,3 +73,27 @@ Caused by: local registry path is not a directory: [..] ")); } + +#[test] +fn stdlib_replacement() { + setup(); + let p = project("local") + .file("Cargo.toml", r#" + [package] + name = "local" + version = "0.0.1" + authors = [] + + [replace] + "foo:1.0.0" = { stdlib = true } + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("update").arg("--verbose"), + execs().with_status(101).with_stderr_contains("\ +[ERROR] failed to parse manifest at [..] + +Caused by: + replacements cannot be standard library packages, but found one for `foo:1.0.0` +")); +} From ae22bdc07007961e9b39ea35611ac439c6720b9a Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 26 Aug 2016 15:34:16 -0700 Subject: [PATCH 05/12] deps-parsing tiny refeactor & reformat --- src/cargo/util/toml.rs | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index c21f463feca..060ce985b9d 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -578,18 +578,14 @@ impl TomlManifest { layout: &layout, }; - fn process_dependencies( + fn process_deps( cx: &mut Context, new_deps: Option<&HashMap>, allow_explicit_stdlib: bool, kind: Option) -> CargoResult<()> { - let dependencies = match new_deps { - Some(ref dependencies) => dependencies, - None => return Ok(()) - }; - for (n, v) in dependencies.iter() { + for (n, v) in new_deps.iter().flat_map(|t| *t) { let detailed = v.elaborate(); if let Some(true) = detailed.stdlib { if !allow_explicit_stdlib { @@ -606,24 +602,27 @@ impl TomlManifest { } // Collect the deps - try!(process_dependencies(&mut cx, self.dependencies.as_ref(), - true, None)); - try!(process_dependencies(&mut cx, self.dev_dependencies.as_ref(), - false, Some(Kind::Development))); - try!(process_dependencies(&mut cx, self.build_dependencies.as_ref(), - false, Some(Kind::Build))); + try!(process_deps( + &mut cx, self.dependencies.as_ref(), + true, None)); + try!(process_deps( + &mut cx, self.dev_dependencies.as_ref(), + false, Some(Kind::Development))); + try!(process_deps( + &mut cx, self.build_dependencies.as_ref(), + false, Some(Kind::Build))); for (name, platform) in self.target.iter().flat_map(|t| t) { cx.platform = Some(try!(name.parse())); - try!(process_dependencies(&mut cx, - platform.dependencies.as_ref(), - true, None)); - try!(process_dependencies(&mut cx, - platform.build_dependencies.as_ref(), - false, Some(Kind::Build))); - try!(process_dependencies(&mut cx, - platform.dev_dependencies.as_ref(), - false, Some(Kind::Development))); + try!(process_deps( + &mut cx, platform.dependencies.as_ref(), + true, None)); + try!(process_deps( + &mut cx, platform.build_dependencies.as_ref(), + false, Some(Kind::Build))); + try!(process_deps( + &mut cx, platform.dev_dependencies.as_ref(), + false, Some(Kind::Development))); } replace = try!(self.replace(&mut cx)); From 98b1eacd653f375d34fc164d7d226789d40ab01e Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 1 Sep 2016 13:14:21 -0700 Subject: [PATCH 06/12] Add warning for explicit deps --- src/cargo/util/toml.rs | 23 +++++++++++++++-------- tests/stdlib-deps.rs | 18 +++++++++++++----- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 060ce985b9d..d54260d3c3f 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -583,11 +583,14 @@ impl TomlManifest { new_deps: Option<&HashMap>, allow_explicit_stdlib: bool, kind: Option) - -> CargoResult<()> + -> CargoResult { + let mut has_explicit_stdlib = false; + for (n, v) in new_deps.iter().flat_map(|t| *t) { let detailed = v.elaborate(); if let Some(true) = detailed.stdlib { + has_explicit_stdlib |= true; if !allow_explicit_stdlib { return Err(human(format!( "dependency {} cannot have `stdlib = true`", @@ -598,33 +601,37 @@ impl TomlManifest { cx.deps.push(dep); } - Ok(()) + Ok(has_explicit_stdlib) } // Collect the deps - try!(process_deps( + let mut explicit_primary = try!(process_deps( &mut cx, self.dependencies.as_ref(), true, None)); - try!(process_deps( + let mut explicit_dev = try!(process_deps( &mut cx, self.dev_dependencies.as_ref(), false, Some(Kind::Development))); - try!(process_deps( + let mut explicit_build = try!(process_deps( &mut cx, self.build_dependencies.as_ref(), false, Some(Kind::Build))); for (name, platform) in self.target.iter().flat_map(|t| t) { cx.platform = Some(try!(name.parse())); - try!(process_deps( + explicit_primary |= try!(process_deps( &mut cx, platform.dependencies.as_ref(), true, None)); - try!(process_deps( + explicit_dev |= try!(process_deps( &mut cx, platform.build_dependencies.as_ref(), false, Some(Kind::Build))); - try!(process_deps( + explicit_build |= try!(process_deps( &mut cx, platform.dev_dependencies.as_ref(), false, Some(Kind::Development))); } + if explicit_primary || explicit_dev || explicit_build { + cx.warnings.push("explicit dependencies are unstable".to_string()); + } + replace = try!(self.replace(&mut cx)); } diff --git a/tests/stdlib-deps.rs b/tests/stdlib-deps.rs index 4a87ddb8fbe..58c9087ca71 100644 --- a/tests/stdlib-deps.rs +++ b/tests/stdlib-deps.rs @@ -39,9 +39,12 @@ fn explicit_stdlib_deps() { "#) .file("src/lib.rs", ""); - assert_that(p.cargo_process("update").arg("--verbose"), - execs().with_status(0).with_stderr( - "[WARNING] the \"compiler source\" is unstable [..]")); + assert_that(p.cargo_process("build").arg("--verbose"), + execs().with_status(0) + .with_stderr_contains( + "[WARNING] the \"compiler source\" is unstable [..]") + .with_stderr_contains( + "[WARNING] explicit dependencies are unstable")); } #[test] @@ -59,8 +62,13 @@ fn unresolved_explicit_stdlib_deps() { "#) .file("src/lib.rs", ""); - assert_that(p.cargo_process("update").arg("--verbose"), - execs().with_status(101).with_stderr_contains("\ + assert_that(p.cargo_process("build").arg("--verbose"), + execs().with_status(101) + .with_stderr_contains( + "[WARNING] the \"compiler source\" is unstable [..]") + .with_stderr_contains( + "[WARNING] explicit dependencies are unstable") + .with_stderr_contains("\ [ERROR] failed to load source for a dependency on `core` Caused by: From 06b7d9a240db7e86d2c7a674110de750871c80cd Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 31 Aug 2016 12:38:46 -0700 Subject: [PATCH 07/12] Stdlib deps (explicit or implicit) are pruned and ignored by default --- src/cargo/util/toml.rs | 53 +++++++++++++++++++++++++++++++----------- tests/stdlib-deps.rs | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index d54260d3c3f..f720ca8fec3 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -582,6 +582,7 @@ impl TomlManifest { cx: &mut Context, new_deps: Option<&HashMap>, allow_explicit_stdlib: bool, + keep_stdlib_deps: bool, kind: Option) -> CargoResult { @@ -589,43 +590,67 @@ impl TomlManifest { for (n, v) in new_deps.iter().flat_map(|t| *t) { let detailed = v.elaborate(); - if let Some(true) = detailed.stdlib { - has_explicit_stdlib |= true; - if !allow_explicit_stdlib { - return Err(human(format!( - "dependency {} cannot have `stdlib = true`", - n))) + let is_stdlib = match detailed.stdlib { + None => false, + Some(true) => { + has_explicit_stdlib |= true; + if !allow_explicit_stdlib { + bail!( + "dependency {} cannot have `stdlib = true`", + n); + } + true } - } + Some(false) => bail!( + "`stdlib = false` is not allowed. \ + Just remove the field from dependency {}.", + n), + }; let dep = try!(detailed.to_dependency(n, cx, kind)); - cx.deps.push(dep); + // We still do everything up to here for basic error + // checking of stdlib deps + if if is_stdlib { keep_stdlib_deps } else { true } { + cx.deps.push(dep); + } } Ok(has_explicit_stdlib) } + let keep_stdlib_deps = match + try!(config.get_bool("keep-stdlib-dependencies")) + { + None => false, + Some(b) => { + cx.warnings.push( + "the `keep-stdlib-dependencies` config key is unstable" + .to_string()); + b.val + }, + }; + // Collect the deps let mut explicit_primary = try!(process_deps( &mut cx, self.dependencies.as_ref(), - true, None)); + true, keep_stdlib_deps, None)); let mut explicit_dev = try!(process_deps( &mut cx, self.dev_dependencies.as_ref(), - false, Some(Kind::Development))); + false, keep_stdlib_deps, Some(Kind::Development))); let mut explicit_build = try!(process_deps( &mut cx, self.build_dependencies.as_ref(), - false, Some(Kind::Build))); + false, keep_stdlib_deps, Some(Kind::Build))); for (name, platform) in self.target.iter().flat_map(|t| t) { cx.platform = Some(try!(name.parse())); explicit_primary |= try!(process_deps( &mut cx, platform.dependencies.as_ref(), - true, None)); + true, keep_stdlib_deps, None)); explicit_dev |= try!(process_deps( &mut cx, platform.build_dependencies.as_ref(), - false, Some(Kind::Build))); + false, keep_stdlib_deps, Some(Kind::Build))); explicit_build |= try!(process_deps( &mut cx, platform.dev_dependencies.as_ref(), - false, Some(Kind::Development))); + false, keep_stdlib_deps, Some(Kind::Development))); } if explicit_primary || explicit_dev || explicit_build { diff --git a/tests/stdlib-deps.rs b/tests/stdlib-deps.rs index 58c9087ca71..0bfea25ca52 100644 --- a/tests/stdlib-deps.rs +++ b/tests/stdlib-deps.rs @@ -13,6 +13,8 @@ fn setup() { let root = paths::root(); t!(fs::create_dir(&root.join(".cargo"))); t!(t!(File::create(root.join(".cargo/config"))).write_all(br#" + keep-stdlib-dependencies = true + [source.compiler] registry = 'https://wut' replace-with = 'my-awesome-local-registry' @@ -41,6 +43,8 @@ fn explicit_stdlib_deps() { assert_that(p.cargo_process("build").arg("--verbose"), execs().with_status(0) + .with_stderr_contains( + "[WARNING] the `keep-stdlib-dependencies` config key is unstable") .with_stderr_contains( "[WARNING] the \"compiler source\" is unstable [..]") .with_stderr_contains( @@ -66,6 +70,8 @@ fn unresolved_explicit_stdlib_deps() { execs().with_status(101) .with_stderr_contains( "[WARNING] the \"compiler source\" is unstable [..]") + .with_stderr_contains( + "[WARNING] the `keep-stdlib-dependencies` config key is unstable") .with_stderr_contains( "[WARNING] explicit dependencies are unstable") .with_stderr_contains("\ @@ -105,3 +111,50 @@ Caused by: replacements cannot be standard library packages, but found one for `foo:1.0.0` ")); } + +#[test] +fn good_explicit_stdlib_deps_pruned() { + let foo = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + + [dependencies] + core = { version = "1", stdlib = true } + alloc = { version = "1", stdlib = true } + "#) + .file("src/lib.rs", "") + .file(".cargo/config", r#" + keep-stdlib-dependencies = false + "#); + assert_that(foo.cargo_process("build").arg("-v"), + execs().with_status(0)); +} + +#[test] +fn bad_explicit_deps_enabled_pruned_still_error() { + setup(); + let foo = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + + [dependencies] + core = { version = "bad bad bad", stdlib = true } + "#) + .file("src/lib.rs", "") + .file(".cargo/config", r#" + keep-stdlib-dependecies = false + "#); + assert_that(foo.cargo_process("build").arg("-v"), + execs().with_status(101).with_stderr("\ +error: failed to parse manifest at [..] + +Caused by: + [..] +")); +} From 67b029dac44990e5f0a4069290f5c91d03c3b45d Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 1 Sep 2016 01:11:24 -0700 Subject: [PATCH 08/12] toml.rs => toml/mod.rs --- src/cargo/util/{toml.rs => toml/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/cargo/util/{toml.rs => toml/mod.rs} (100%) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml/mod.rs similarity index 100% rename from src/cargo/util/toml.rs rename to src/cargo/util/toml/mod.rs From 2306e1ff16ab87870bfb2b932ec76767a6e1b1b4 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 1 Sep 2016 01:16:22 -0700 Subject: [PATCH 09/12] Add implicit deps --- src/cargo/util/toml/implicit_deps.rs | 38 +++++++++++++++ src/cargo/util/toml/mod.rs | 18 +++++++ tests/stdlib-deps.rs | 73 ++++++++++++++++++++++++---- 3 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 src/cargo/util/toml/implicit_deps.rs diff --git a/src/cargo/util/toml/implicit_deps.rs b/src/cargo/util/toml/implicit_deps.rs new file mode 100644 index 00000000000..c1477c91624 --- /dev/null +++ b/src/cargo/util/toml/implicit_deps.rs @@ -0,0 +1,38 @@ +use std::collections::HashMap; + +use util::toml::{TomlDependency, DetailedTomlDependency}; + + +fn marshall(name_ver: I) + -> HashMap + where I: Iterator, + S: Into +{ + name_ver + .map(|(n, v)| (n.into(), + TomlDependency::Detailed(DetailedTomlDependency { + version: Some(v.into()), + stdlib: Some(true), + .. Default::default() + }))) + .collect() +} + +pub fn primary() -> HashMap { + marshall(vec![ + ("core", "^1.0"), + ("std", "^1.0"), + ].into_iter()) +} + +pub fn dev() -> HashMap { + let mut map = marshall(vec![ + ("test", "^1.0"), + ].into_iter()); + map.extend(self::primary().into_iter()); + map +} + +pub fn build() -> HashMap { + self::primary() +} diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index f720ca8fec3..feecc0f010d 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -17,6 +17,8 @@ use core::manifest::{LibKind, Profile, ManifestMetadata}; use core::package_id::Metadata; use util::{self, CargoResult, human, ToUrl, ToSemver, ChainError, Config}; +mod implicit_deps; + /// Representation of the projects file layout. /// /// This structure is used to hold references to all project files that are relevant to cargo. @@ -657,6 +659,22 @@ impl TomlManifest { cx.warnings.push("explicit dependencies are unstable".to_string()); } + // Add implicit deps + cx.platform = None; + + if !explicit_primary { + try!(process_deps(&mut cx, Some(&implicit_deps::primary()), + true, keep_stdlib_deps, None)); + } + if !explicit_dev { + try!(process_deps(&mut cx, Some(&implicit_deps::dev()), + true, keep_stdlib_deps, Some(Kind::Development))); + } + if !explicit_build { + try!(process_deps(&mut cx, Some(&implicit_deps::build()), + true, keep_stdlib_deps, Some(Kind::Build))); + } + replace = try!(self.replace(&mut cx)); } diff --git a/tests/stdlib-deps.rs b/tests/stdlib-deps.rs index 0bfea25ca52..ffc1296f1d1 100644 --- a/tests/stdlib-deps.rs +++ b/tests/stdlib-deps.rs @@ -24,10 +24,19 @@ fn setup() { "#)); } +static STD: &'static str = r#" +pub mod prelude { + pub mod v1 { + } +} +"#; + #[test] fn explicit_stdlib_deps() { setup(); Package::new("core", "1.0.0").local(true).publish(); + Package::new("std", "1.0.0").local(true).file("src/lib.rs", STD).publish(); + Package::new("test", "1.0.0").local(true).publish(); let p = project("local") .file("Cargo.toml", r#" @@ -38,6 +47,8 @@ fn explicit_stdlib_deps() { [dependencies] core = { version = "1", stdlib = true } + std = { version = "1", stdlib = true } + test = { version = "1", stdlib = true } "#) .file("src/lib.rs", ""); @@ -51,9 +62,36 @@ fn explicit_stdlib_deps() { "[WARNING] explicit dependencies are unstable")); } +#[test] +fn implicit_stdlib_deps() { + setup(); + Package::new("core", "1.0.0").local(true).publish(); + Package::new("std", "1.0.0").local(true).file("src/lib.rs", STD).publish(); + Package::new("test", "1.0.0").local(true).publish(); + + let p = project("local") + .file("Cargo.toml", r#" + [package] + name = "local" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("build").arg("--verbose"), + execs().with_status(0) + .with_stderr_contains( + "[WARNING] the \"compiler source\" is unstable [..]")); +} + #[test] fn unresolved_explicit_stdlib_deps() { setup(); + Package::new("core", "1.0.0").local(true).publish(); + // For dev & build + Package::new("std", "1.0.0").local(true).publish(); + Package::new("test", "1.0.0").local(true).publish(); + let p = project("local") .file("Cargo.toml", r#" [package] @@ -62,10 +100,9 @@ fn unresolved_explicit_stdlib_deps() { authors = [] [dependencies] - core = { version = "1", stdlib = true } + foo = { version = "1", stdlib = true } "#) .file("src/lib.rs", ""); - assert_that(p.cargo_process("build").arg("--verbose"), execs().with_status(101) .with_stderr_contains( @@ -75,16 +112,34 @@ fn unresolved_explicit_stdlib_deps() { .with_stderr_contains( "[WARNING] explicit dependencies are unstable") .with_stderr_contains("\ -[ERROR] failed to load source for a dependency on `core` +[ERROR] no matching package named `foo` found (required by `local`) +location searched: registry file://[..] +version required: ^1 +")); +} -Caused by: - Unable to update registry file://[..] +#[test] +fn unresolved_implicit_stdlib_deps() { + setup(); + Package::new("core", "1.0.0").local(true).publish(); -Caused by: - failed to update replaced source `registry file://[..] + let p = project("local") + .file("Cargo.toml", r#" + [package] + name = "local" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", ""); -Caused by: - local registry path is not a directory: [..] + assert_that(p.cargo_process("build").arg("--verbose"), + execs().with_status(101) + .with_stderr_contains( + "[WARNING] the \"compiler source\" is unstable [..]") + .with_stderr_contains("\ +[ERROR] no matching package named `std` found (required by `local`) +location searched: registry file://[..] +version required: ^1.0 ")); } From 43ecceb750f3e4f90d141c10105fa0a9392de0aa Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 29 Aug 2016 14:57:22 -0700 Subject: [PATCH 10/12] Fix test: rustc is now needed at parse-time to resolve the location of the compiler source --- tests/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/build.rs b/tests/build.rs index 739a5b9c467..ef38772f4d7 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -1967,7 +1967,10 @@ fn rustc_env_var() { .env("RUSTC", "rustc-that-does-not-exist").arg("-v"), execs().with_status(101) .with_stderr("\ -[ERROR] could not execute process `rustc-that-does-not-exist -vV` ([..]) +[ERROR] failed to parse manifest at [..] + +Caused by: + could not execute process `rustc-that-does-not-exist -vV` ([..]) Caused by: [..] From 2e3935591e52df0c46c710f8fb954295f5c0c1ac Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 26 Aug 2016 23:13:02 -0700 Subject: [PATCH 11/12] Add `implicit-dependencies = ` package key, add warnings --- src/cargo/util/toml/mod.rs | 27 +++++++++- tests/stdlib-deps.rs | 101 +++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index feecc0f010d..633e91245e7 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -300,6 +300,7 @@ pub struct TomlProject { include: Option>, publish: Option, workspace: Option, + implicit_dependencies: Option, // package metadata description: Option, @@ -659,10 +660,34 @@ impl TomlManifest { cx.warnings.push("explicit dependencies are unstable".to_string()); } + if project.implicit_dependencies.is_some() { + cx.warnings.push( + "the implicit-dependencies flag is unstable \ + (and furthermore is not currently planned on being stabilized)." + .to_string()); + } + + // Based on "implicit_dependencies" flag and actual usage of + // explicit stdlib dependencies + let implicit_primary = match (explicit_primary, + project.implicit_dependencies) + { + (true, Some(true)) => bail!( + "cannot use explicit stdlib deps when implicit deps \ + were explicitly enabled."), + // With explicit deps, and flag not "yes", resolve "no" + (true, _) => false, + // With no explcit deps and no flag, resolve "yes" for + // backwards-compat + (false, None) => true, + // With no explcit deps and the flag, obey the flag + (false, Some(x)) => x, + }; + // Add implicit deps cx.platform = None; - if !explicit_primary { + if implicit_primary { try!(process_deps(&mut cx, Some(&implicit_deps::primary()), true, keep_stdlib_deps, None)); } diff --git a/tests/stdlib-deps.rs b/tests/stdlib-deps.rs index ffc1296f1d1..b1887b89a56 100644 --- a/tests/stdlib-deps.rs +++ b/tests/stdlib-deps.rs @@ -143,6 +143,107 @@ version required: ^1.0 ")); } + +#[test] +fn explicit_stdlib_deps_with_flag() { + setup(); + Package::new("core", "1.0.0").local(true).publish(); + Package::new("std", "1.0.0").local(true).file("src/lib.rs", STD).publish(); + Package::new("test", "1.0.0").local(true).publish(); + + let p = project("local") + .file("Cargo.toml", r#" + [package] + name = "local" + version = "0.0.1" + authors = [] + implicit-dependencies = false + + [dependencies] + core = { version = "1", stdlib = true } + std = { version = "1", stdlib = true } + test = { version = "1", stdlib = true } + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("build").arg("--verbose"), + execs().with_status(0) + .with_stderr_contains( + "[WARNING] the \"compiler source\" is unstable [..]") + .with_stderr_contains( + "[WARNING] explicit dependencies are unstable")); +} + +#[test] +fn implicit_stdlib_dep_with_flag() { + setup(); + Package::new("core", "1.0.0").local(true).publish(); + Package::new("std", "1.0.0").local(true).file("src/lib.rs", STD).publish(); + Package::new("test", "1.0.0").local(true).publish(); + + let p = project("local") + .file("Cargo.toml", r#" + [package] + name = "local" + version = "0.0.1" + authors = [] + implicit-dependencies = true + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("build").arg("--verbose"), + execs().with_status(0) + .with_stderr_contains( + "[WARNING] the \"compiler source\" is unstable [..]")); +} + +#[test] +fn no_primary_stdlib_deps_at_all() { + setup(); + // For dev & build + Package::new("core", "1.0.0") + .file("src/lib.rs", "I AM INVALID SYNTAX CANNOT COMPILE") + .local(true).publish(); + Package::new("std", "1.0.0").local(true).publish(); + Package::new("test", "1.0.0").local(true).publish(); + + let foo = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + implicit-dependencies = false + "#) + .file("src/lib.rs", ""); + assert_that(foo.cargo_process("build").arg("-v"), + execs().with_status(0)); +} + +#[test] +fn mixed_expicit_and_implicit_stdlib_deps() { + setup(); + let foo = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + implicit-dependencies = true + + [dependencies] + foo = { stdlib = true } + "#) + .file("src/lib.rs", ""); + assert_that(foo.cargo_process("build").arg("-v"), + execs().with_status(101).with_stderr("\ +[ERROR] failed to parse manifest at `[..]` + +Caused by: + cannot use explicit stdlib deps when implicit deps were explicitly enabled. +")); +} + #[test] fn stdlib_replacement() { setup(); From 334378554bfc02a9d0a4b5d2fcd06cf5ec4d4fb1 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 1 Sep 2016 15:09:05 -0700 Subject: [PATCH 12/12] Add temporary `custom-implicit-stdlib-dependencies` key --- src/cargo/util/toml/implicit_deps.rs | 68 ++++++++++++++++++++++------ src/cargo/util/toml/mod.rs | 21 ++++++--- tests/stdlib-deps.rs | 34 ++++++++++++++ 3 files changed, 102 insertions(+), 21 deletions(-) diff --git a/src/cargo/util/toml/implicit_deps.rs b/src/cargo/util/toml/implicit_deps.rs index c1477c91624..f10a2dfe94e 100644 --- a/src/cargo/util/toml/implicit_deps.rs +++ b/src/cargo/util/toml/implicit_deps.rs @@ -1,11 +1,12 @@ use std::collections::HashMap; +use util::CargoResult; +use util::config::Config; use util::toml::{TomlDependency, DetailedTomlDependency}; - fn marshall(name_ver: I) -> HashMap - where I: Iterator, + where I: Iterator, S: Into { name_ver @@ -18,21 +19,58 @@ fn marshall(name_ver: I) .collect() } -pub fn primary() -> HashMap { - marshall(vec![ - ("core", "^1.0"), - ("std", "^1.0"), - ].into_iter()) +mod default { + use std::collections::HashMap; + use util::toml::TomlDependency; + use super::marshall; + + pub fn primary() -> HashMap { + marshall(vec![ + ("core", "^1.0"), + ("std", "^1.0"), + ].into_iter()) + } + + pub fn dev() -> HashMap { + let mut map = marshall(vec![ + ("test", "^1.0"), + ].into_iter()); + map.extend(self::primary().into_iter()); + map + } + + pub fn build() -> HashMap { + self::primary() + } } -pub fn dev() -> HashMap { - let mut map = marshall(vec![ - ("test", "^1.0"), - ].into_iter()); - map.extend(self::primary().into_iter()); - map +fn get_custom(sort: &'static str, config: &Config) + -> CargoResult>> +{ + let overrides = try!(config.get_list(&format!( + "custom-implicit-stdlib-dependencies.{}", + sort))); + + Ok(overrides.map(|os| marshall(os.val.into_iter().map(|o| (o.0, "^1.0"))))) } -pub fn build() -> HashMap { - self::primary() +pub fn primary(config: &Config) + -> CargoResult> +{ + Ok(try!(get_custom("dependencies", config)) + .unwrap_or_else(|| default::primary())) +} + +pub fn dev(config: &Config) + -> CargoResult> +{ + Ok(try!(get_custom("dev-dependencies", config)) + .unwrap_or_else(|| default::dev())) +} + +pub fn build(config: &Config) + -> CargoResult> +{ + Ok(try!(get_custom("build-dependencies", config)) + .unwrap_or_else(|| default::build())) } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 633e91245e7..40e0967ce23 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -687,17 +687,26 @@ impl TomlManifest { // Add implicit deps cx.platform = None; + if try!(config.get_table("custom-implicit-stdlib-dependencies")).is_some() { + cx.warnings.push( + "the `custom-implicit-stdlib-dependencies` config key is unstable" + .to_string()); + } + if implicit_primary { - try!(process_deps(&mut cx, Some(&implicit_deps::primary()), - true, keep_stdlib_deps, None)); + try!(process_deps( + &mut cx, Some(&try!(implicit_deps::primary(config))), + true, keep_stdlib_deps, None)); } if !explicit_dev { - try!(process_deps(&mut cx, Some(&implicit_deps::dev()), - true, keep_stdlib_deps, Some(Kind::Development))); + try!(process_deps( + &mut cx, Some(&try!(implicit_deps::dev(config))), + true, keep_stdlib_deps, Some(Kind::Development))); } if !explicit_build { - try!(process_deps(&mut cx, Some(&implicit_deps::build()), - true, keep_stdlib_deps, Some(Kind::Build))); + try!(process_deps( + &mut cx, Some(&try!(implicit_deps::build(config))), + true, keep_stdlib_deps, Some(Kind::Build))); } replace = try!(self.replace(&mut cx)); diff --git a/tests/stdlib-deps.rs b/tests/stdlib-deps.rs index b1887b89a56..83217facb8a 100644 --- a/tests/stdlib-deps.rs +++ b/tests/stdlib-deps.rs @@ -314,3 +314,37 @@ Caused by: [..] ")); } + + +#[test] +fn override_implicit_deps() { + setup(); + Package::new("not-wanted", "0.0.1").local(true).publish(); + let foo = project("asdf") + .file("Cargo.toml", r#" + [package] + name = "local" + version = "0.0.0" + authors = [] + "#) + .file("src/lib.rs", "") + .file(".cargo/config", r#" + [custom-implicit-stdlib-dependencies] + dependencies = [ "foo" ] + dev-dependencies = [ ] + build-dependencies = [ ] + "#); + assert_that(foo.cargo_process("build").arg("-v"), + execs().with_status(101) + .with_stderr_contains( + "[WARNING] the \"compiler source\" is unstable [..]") + .with_stderr_contains( + "[WARNING] the `keep-stdlib-dependencies` config key is unstable") + .with_stderr_contains( + "[WARNING] the `custom-implicit-stdlib-dependencies` config key is unstable") + .with_stderr_contains("\ +[ERROR] no matching package named `foo` found (required by `local`) +location searched: registry file://[..] +version required: ^1.0 +")); +}