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, }) } diff --git a/src/cargo/util/toml/implicit_deps.rs b/src/cargo/util/toml/implicit_deps.rs new file mode 100644 index 00000000000..f10a2dfe94e --- /dev/null +++ b/src/cargo/util/toml/implicit_deps.rs @@ -0,0 +1,76 @@ +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, + S: Into +{ + name_ver + .map(|(n, v)| (n.into(), + TomlDependency::Detailed(DetailedTomlDependency { + version: Some(v.into()), + stdlib: Some(true), + .. Default::default() + }))) + .collect() +} + +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() + } +} + +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 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.rs b/src/cargo/util/toml/mod.rs similarity index 85% rename from src/cargo/util/toml.rs rename to src/cargo/util/toml/mod.rs index 4686eb9a29d..40e0967ce23 100644 --- a/src/cargo/util/toml.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. @@ -223,6 +225,7 @@ pub struct DetailedTomlDependency { branch: Option, tag: Option, rev: Option, + stdlib: Option, features: Option>, optional: Option, default_features: Option, @@ -297,6 +300,7 @@ pub struct TomlProject { include: Option>, publish: Option, workspace: Option, + implicit_dependencies: Option, // package metadata description: Option, @@ -577,43 +581,132 @@ impl TomlManifest { layout: &layout, }; - fn process_dependencies( + fn process_deps( cx: &mut Context, new_deps: Option<&HashMap>, + allow_explicit_stdlib: bool, + keep_stdlib_deps: bool, kind: Option) - -> CargoResult<()> + -> CargoResult { - let dependencies = match new_deps { - Some(ref dependencies) => dependencies, - None => return Ok(()) - }; - for (n, v) in dependencies.iter() { - let dep = try!(v.to_dependency(n, cx, kind)); - cx.deps.push(dep); + let mut has_explicit_stdlib = false; + + for (n, v) in new_deps.iter().flat_map(|t| *t) { + let detailed = v.elaborate(); + 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)); + // 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(()) + 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 - try!(process_dependencies(&mut cx, self.dependencies.as_ref(), - None)); - try!(process_dependencies(&mut cx, self.dev_dependencies.as_ref(), - Some(Kind::Development))); - try!(process_dependencies(&mut cx, self.build_dependencies.as_ref(), - Some(Kind::Build))); + let mut explicit_primary = try!(process_deps( + &mut cx, self.dependencies.as_ref(), + true, keep_stdlib_deps, None)); + let mut explicit_dev = try!(process_deps( + &mut cx, self.dev_dependencies.as_ref(), + false, keep_stdlib_deps, Some(Kind::Development))); + let mut explicit_build = try!(process_deps( + &mut cx, self.build_dependencies.as_ref(), + false, keep_stdlib_deps, 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)); - try!(process_dependencies(&mut cx, - platform.build_dependencies.as_ref(), - Some(Kind::Build))); - try!(process_dependencies(&mut cx, - platform.dev_dependencies.as_ref(), - Some(Kind::Development))); + explicit_primary |= try!(process_deps( + &mut cx, platform.dependencies.as_ref(), + true, keep_stdlib_deps, None)); + explicit_dev |= try!(process_deps( + &mut cx, platform.build_dependencies.as_ref(), + false, keep_stdlib_deps, Some(Kind::Build))); + explicit_build |= try!(process_deps( + &mut cx, platform.dev_dependencies.as_ref(), + false, keep_stdlib_deps, Some(Kind::Development))); + } + + if explicit_primary || explicit_dev || explicit_build { + 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 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(&try!(implicit_deps::primary(config))), + true, keep_stdlib_deps, None)); + } + if !explicit_dev { + 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(&try!(implicit_deps::build(config))), + true, keep_stdlib_deps, Some(Kind::Build))); } replace = try!(self.replace(&mut cx)); @@ -746,16 +839,20 @@ 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)); + 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 = { let version = try!(spec.version().chain_error(|| { human(format!("replacements must specify a version \ @@ -797,21 +894,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 \ @@ -819,11 +920,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() { @@ -836,16 +937,22 @@ 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 (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(); @@ -857,14 +964,18 @@ 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) }, - (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,10 +993,11 @@ 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[..]); + 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, @@ -893,9 +1005,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); 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/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: [..] diff --git a/tests/stdlib-deps.rs b/tests/stdlib-deps.rs new file mode 100644 index 00000000000..83217facb8a --- /dev/null +++ b/tests/stdlib-deps.rs @@ -0,0 +1,350 @@ +#[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#" + keep-stdlib-dependencies = true + + [source.compiler] + registry = 'https://wut' + replace-with = 'my-awesome-local-registry' + + [source.my-awesome-local-registry] + local-registry = 'registry' + "#)); +} + +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#" + [package] + name = "local" + version = "0.0.1" + authors = [] + + [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 `keep-stdlib-dependencies` config key is unstable") + .with_stderr_contains( + "[WARNING] the \"compiler source\" is unstable [..]") + .with_stderr_contains( + "[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] + name = "local" + version = "0.0.1" + authors = [] + + [dependencies] + foo = { version = "1", stdlib = true } + "#) + .file("src/lib.rs", ""); + 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] the `keep-stdlib-dependencies` config key is unstable") + .with_stderr_contains( + "[WARNING] explicit dependencies are unstable") + .with_stderr_contains("\ +[ERROR] no matching package named `foo` found (required by `local`) +location searched: registry file://[..] +version required: ^1 +")); +} + +#[test] +fn unresolved_implicit_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 = [] + "#) + .file("src/lib.rs", ""); + + 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 +")); +} + + +#[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(); + 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` +")); +} + +#[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: + [..] +")); +} + + +#[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 +")); +}