From 1d82d2b38c6f0d1d7c28b229376da3f3a9271b3f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 5 Feb 2018 10:23:07 -0500 Subject: [PATCH 1/6] Add epoch key to [package] --- src/cargo/core/features.rs | 21 +++++++++++++++++++++ src/cargo/core/manifest.rs | 5 ++++- src/cargo/core/mod.rs | 2 +- src/cargo/util/toml/mod.rs | 14 +++++++++++++- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 414e6a4a8b6..30c2b433ffc 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -40,9 +40,30 @@ //! we'll be sure to update this documentation! use std::env; +use std::str::FromStr; use util::errors::CargoResult; +/// The epoch of the compiler (RFC 2052) +#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, Eq, PartialEq)] +pub enum Epoch { + /// The 2015 epoch + Epoch2015, + /// The 2018 epoch + Epoch2018, +} + +impl FromStr for Epoch { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "2015" => Ok(Epoch::Epoch2015), + "2018" => Ok(Epoch::Epoch2018), + _ => Err(()) + } + } +} + enum Status { Stable, Unstable, diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 5ba9419e467..98d87abd0b4 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -9,7 +9,7 @@ use serde::ser; use url::Url; use core::{Dependency, PackageId, Summary, SourceId, PackageIdSpec}; -use core::{WorkspaceConfig, Features, Feature}; +use core::{WorkspaceConfig, Epoch, Features, Feature}; use util::Config; use util::toml::TomlManifest; use util::errors::*; @@ -36,6 +36,7 @@ pub struct Manifest { workspace: WorkspaceConfig, original: Rc, features: Features, + epoch: Epoch, im_a_teapot: Option, } @@ -269,6 +270,7 @@ impl Manifest { patch: HashMap>, workspace: WorkspaceConfig, features: Features, + epoch: Epoch, im_a_teapot: Option, original: Rc) -> Manifest { Manifest { @@ -285,6 +287,7 @@ impl Manifest { patch: patch, workspace: workspace, features: features, + epoch: epoch, original: original, im_a_teapot: im_a_teapot, } diff --git a/src/cargo/core/mod.rs b/src/cargo/core/mod.rs index 6b4e3906f8e..df1eff0725e 100644 --- a/src/cargo/core/mod.rs +++ b/src/cargo/core/mod.rs @@ -1,5 +1,5 @@ pub use self::dependency::Dependency; -pub use self::features::{Features, Feature, CliUnstable}; +pub use self::features::{Epoch, Features, Feature, CliUnstable}; pub use self::manifest::{EitherManifest, VirtualManifest}; pub use self::manifest::{Manifest, Target, TargetKind, Profile, LibKind, Profiles}; pub use self::package::{Package, PackageSet}; diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index a088598e9ba..d2e47a692c4 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -14,7 +14,7 @@ use url::Url; use core::{SourceId, Profiles, PackageIdSpec, GitReference, WorkspaceConfig, WorkspaceRootConfig}; use core::{Summary, Manifest, Target, Dependency, PackageId}; -use core::{EitherManifest, VirtualManifest, Features, Feature}; +use core::{EitherManifest, Epoch, VirtualManifest, Features, Feature}; use core::dependency::{Kind, Platform}; use core::manifest::{LibKind, Profile, ManifestMetadata, Lto}; use sources::CRATES_IO; @@ -441,6 +441,7 @@ pub struct TomlProject { license_file: Option, repository: Option, metadata: Option, + epoch: Option, } #[derive(Debug, Deserialize, Serialize)] @@ -715,6 +716,16 @@ impl TomlManifest { Some(VecStringOrBool::Bool(false)) => Some(vec![]), None | Some(VecStringOrBool::Bool(true)) => None, }; + + let epoch = if let Some(ref epoch) = project.epoch { + if let Ok(epoch) = epoch.parse() { + epoch + } else { + bail!("the `epoch` key must be one of: `2015`, `2018`") + } + } else { + Epoch::Epoch2015 + }; let mut manifest = Manifest::new(summary, targets, exclude, @@ -727,6 +738,7 @@ impl TomlManifest { patch, workspace_config, features, + epoch, project.im_a_teapot, Rc::clone(me)); if project.license_file.is_some() && project.license.is_some() { From fa5be237c5268810c1a677a28a21fa227d0a54a7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 5 Feb 2018 10:28:17 -0500 Subject: [PATCH 2/6] Feature gate epoches --- src/cargo/core/features.rs | 3 +++ src/cargo/util/toml/mod.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 30c2b433ffc..10597e55ee6 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -146,6 +146,9 @@ features! { // Downloading packages from alternative registry indexes. [unstable] alternative_registries: bool, + + // Using epochs + [unstable] epoch: bool, } } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index d2e47a692c4..623d794af82 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -718,6 +718,9 @@ impl TomlManifest { }; let epoch = if let Some(ref epoch) = project.epoch { + features.require(Feature::epoch()).chain_err(|| { + "epoches are unstable" + })?; if let Ok(epoch) = epoch.parse() { epoch } else { From 2d1af7b56e88e3ac3de8ac9e9c57fb152d55aa3b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 5 Feb 2018 11:29:31 -0500 Subject: [PATCH 3/6] Pass -Zepoch flag when epoch feature exists --- src/cargo/core/features.rs | 13 +++++++++++++ src/cargo/core/manifest.rs | 4 ++++ src/cargo/ops/cargo_rustc/mod.rs | 7 ++++++- src/cargo/util/toml/mod.rs | 2 +- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 10597e55ee6..f5b6c7e720d 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -40,6 +40,7 @@ //! we'll be sure to update this documentation! use std::env; +use std::fmt; use std::str::FromStr; use util::errors::CargoResult; @@ -53,6 +54,14 @@ pub enum Epoch { Epoch2018, } +impl fmt::Display for Epoch { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Epoch::Epoch2015 => f.write_str("2015"), + Epoch::Epoch2018 => f.write_str("2018"), + } + } +} impl FromStr for Epoch { type Err = (); fn from_str(s: &str) -> Result { @@ -225,6 +234,10 @@ impl Features { bail!("{}", msg); } } + + pub fn is_enabled(&self, feature: &Feature) -> bool { + feature.is_enabled(self) + } } /// A parsed representation of all unstable flags that Cargo accepts. diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 98d87abd0b4..18eb96b5ff8 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -359,6 +359,10 @@ impl Manifest { } } } + + pub fn epoch(&self) -> Epoch { + self.epoch + } } impl VirtualManifest { diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 7a413194e20..b3294857608 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -9,7 +9,7 @@ use std::sync::Arc; use same_file::is_same_file; use serde_json; -use core::{Package, PackageId, PackageSet, Target, Resolve}; +use core::{Feature, Package, PackageId, PackageSet, Target, Resolve}; use core::{Profile, Profiles, Workspace}; use core::manifest::Lto; use core::shell::ColorChoice; @@ -804,6 +804,11 @@ fn build_base_args<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, cmd.arg("-C").arg(format!("panic={}", panic)); } } + let manifest = unit.pkg.manifest(); + + if manifest.features().is_enabled(Feature::epoch()) { + cmd.arg(format!("-Zepoch={}", manifest.epoch())); + } // Disable LTO for host builds as prefer_dynamic and it are mutually // exclusive. diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 623d794af82..e66ac74943b 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -727,7 +727,7 @@ impl TomlManifest { bail!("the `epoch` key must be one of: `2015`, `2018`") } } else { - Epoch::Epoch2015 + Epoch::Epoch2015 }; let mut manifest = Manifest::new(summary, targets, From 711b4fa3f415565c7eac03e5fcb00afb61dc8b44 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 5 Feb 2018 16:21:40 -0500 Subject: [PATCH 4/6] Include the epoch in the fingerprint --- src/cargo/core/features.rs | 1 + src/cargo/ops/cargo_rustc/fingerprint.rs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index f5b6c7e720d..323366b9bce 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -47,6 +47,7 @@ use util::errors::CargoResult; /// The epoch of the compiler (RFC 2052) #[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, Eq, PartialEq)] +#[derive(Serialize, Deserialize)] pub enum Epoch { /// The 2015 epoch Epoch2015, diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs index 847008eb7a7..3080cee3dda 100644 --- a/src/cargo/ops/cargo_rustc/fingerprint.rs +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -9,7 +9,7 @@ use serde::ser::{self, Serialize}; use serde::de::{self, Deserialize}; use serde_json; -use core::{Package, TargetKind}; +use core::{Epoch, Package, TargetKind}; use util; use util::{Fresh, Dirty, Freshness, internal, profile}; use util::errors::{CargoResult, CargoResultExt}; @@ -145,6 +145,7 @@ pub struct Fingerprint { #[serde(skip_serializing, skip_deserializing)] memoized_hash: Mutex>, rustflags: Vec, + epoch: Epoch, } fn serialize_deps(deps: &[(String, Arc)], ser: S) @@ -170,6 +171,7 @@ fn deserialize_deps<'de, D>(d: D) -> Result)>, D:: features: String::new(), deps: Vec::new(), memoized_hash: Mutex::new(Some(hash)), + epoch: Epoch::Epoch2015, rustflags: Vec::new(), })) }).collect()) @@ -252,6 +254,9 @@ impl Fingerprint { if self.local.len() != old.local.len() { bail!("local lens changed"); } + if self.epoch != old.epoch { + bail!("epoch changed") + } for (new, old) in self.local.iter().zip(&old.local) { match (new, old) { (&LocalFingerprint::Precalculated(ref a), @@ -315,9 +320,10 @@ impl hash::Hash for Fingerprint { ref deps, ref local, memoized_hash: _, + epoch, ref rustflags, } = *self; - (rustc, features, target, path, profile, local, rustflags).hash(h); + (rustc, features, target, path, profile, local, epoch, rustflags).hash(h); h.write_usize(deps.len()); for &(ref name, ref fingerprint) in deps { @@ -416,6 +422,7 @@ fn calculate<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) deps: deps, local: vec![local], memoized_hash: Mutex::new(None), + epoch: unit.pkg.manifest().epoch(), rustflags: extra_flags, }); cx.fingerprints.insert(*unit, Arc::clone(&fingerprint)); @@ -468,6 +475,7 @@ pub fn prepare_build_cmd<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) deps: Vec::new(), local: local, memoized_hash: Mutex::new(None), + epoch: Epoch::Epoch2015, rustflags: Vec::new(), }; let compare = compare_old_fingerprint(&loc, &fingerprint); From 5d615a69b7b72c47d198d281c92cc25ca243a9b8 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 5 Feb 2018 16:42:42 -0500 Subject: [PATCH 5/6] Add tests for epoch --- tests/package.rs | 117 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/tests/package.rs b/tests/package.rs index d90e76e95a2..4f10b9e531e 100644 --- a/tests/package.rs +++ b/tests/package.rs @@ -887,3 +887,120 @@ fn package_two_kinds_of_deps() { assert_that(p.cargo("package").arg("--no-verify"), execs().with_status(0)); } + +#[test] +fn test_epoch() { + let p = project("foo") + .file("Cargo.toml", r#" + cargo-features = ["epoch"] + [package] + name = "foo" + version = "0.0.1" + authors = [] + epoch = "2018" + "#) + .file("src/lib.rs", r#" "#) + .build(); + + assert_that(p.cargo("build").arg("-v") + .masquerade_as_nightly_cargo(), + execs() + // -Zepoch is still in flux and we're not passing -Zunstable-options + // from Cargo so it will probably error. Only partially match the output + // until stuff stabilizes + .with_stderr_contains(format!("\ +[COMPILING] foo v0.0.1 ({url}) +[RUNNING] `rustc --crate-name foo src[/]lib.rs --crate-type lib \ + --emit=dep-info,link -Zepoch=2018 -C debuginfo=2 \ + -C metadata=[..] \ + --out-dir [..] \ + -L dependency={dir}[/]target[/]debug[/]deps` +", dir = p.root().display(), url = p.url()))); +} + +#[test] +fn test_epoch_missing() { + // no epoch = 2015 + let p = project("foo") + .file("Cargo.toml", r#" + cargo-features = ["epoch"] + [package] + name = "foo" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", r#" "#) + .build(); + + assert_that(p.cargo("build").arg("-v") + .masquerade_as_nightly_cargo(), + execs() + // -Zepoch is still in flux and we're not passing -Zunstable-options + // from Cargo so it will probably error. Only partially match the output + // until stuff stabilizes + .with_stderr_contains(format!("\ +[COMPILING] foo v0.0.1 ({url}) +[RUNNING] `rustc --crate-name foo src[/]lib.rs --crate-type lib \ + --emit=dep-info,link -Zepoch=2015 -C debuginfo=2 \ + -C metadata=[..] \ + --out-dir [..] \ + -L dependency={dir}[/]target[/]debug[/]deps` +", dir = p.root().display(), url = p.url()))); +} + +#[test] +fn test_epoch_malformed() { + let p = project("foo") + .file("Cargo.toml", r#" + cargo-features = ["epoch"] + [package] + name = "foo" + version = "0.0.1" + authors = [] + epoch = "chicken" + "#) + .file("src/lib.rs", r#" "#) + .build(); + + assert_that(p.cargo("build").arg("-v") + .masquerade_as_nightly_cargo(), + execs() + .with_status(101) + .with_stderr(format!("\ +error: failed to parse manifest at `[..]` + +Caused by: + the `epoch` key must be one of: `2015`, `2018` +"))); +} + + +#[test] +fn test_epoch_nightly() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + epoch = "2015" + "#) + .file("src/lib.rs", r#" "#) + .build(); + + assert_that(p.cargo("build").arg("-v") + .masquerade_as_nightly_cargo(), + execs() + .with_status(101) + .with_stderr(format!("\ +error: failed to parse manifest at `[..]` + +Caused by: + epoches are unstable + +Caused by: + feature `epoch` is required + +consider adding `cargo-features = [\"epoch\"]` to the manifest +"))); +} \ No newline at end of file From 270f6e28a028fd8b24b56c17fb509ab275860612 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 6 Feb 2018 09:33:30 -0800 Subject: [PATCH 6/6] epoch -> rust --- src/cargo/util/toml/mod.rs | 6 +++--- tests/package.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index e66ac74943b..c33aaef93e9 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -441,7 +441,7 @@ pub struct TomlProject { license_file: Option, repository: Option, metadata: Option, - epoch: Option, + rust: Option, } #[derive(Debug, Deserialize, Serialize)] @@ -717,14 +717,14 @@ impl TomlManifest { None | Some(VecStringOrBool::Bool(true)) => None, }; - let epoch = if let Some(ref epoch) = project.epoch { + let epoch = if let Some(ref epoch) = project.rust { features.require(Feature::epoch()).chain_err(|| { "epoches are unstable" })?; if let Ok(epoch) = epoch.parse() { epoch } else { - bail!("the `epoch` key must be one of: `2015`, `2018`") + bail!("the `rust` key must be one of: `2015`, `2018`") } } else { Epoch::Epoch2015 diff --git a/tests/package.rs b/tests/package.rs index 4f10b9e531e..f49a56193aa 100644 --- a/tests/package.rs +++ b/tests/package.rs @@ -897,7 +897,7 @@ fn test_epoch() { name = "foo" version = "0.0.1" authors = [] - epoch = "2018" + rust = "2018" "#) .file("src/lib.rs", r#" "#) .build(); @@ -957,7 +957,7 @@ fn test_epoch_malformed() { name = "foo" version = "0.0.1" authors = [] - epoch = "chicken" + rust = "chicken" "#) .file("src/lib.rs", r#" "#) .build(); @@ -970,7 +970,7 @@ fn test_epoch_malformed() { error: failed to parse manifest at `[..]` Caused by: - the `epoch` key must be one of: `2015`, `2018` + the `rust` key must be one of: `2015`, `2018` "))); } @@ -983,7 +983,7 @@ fn test_epoch_nightly() { name = "foo" version = "0.0.1" authors = [] - epoch = "2015" + rust = "2015" "#) .file("src/lib.rs", r#" "#) .build();