Skip to content

Commit

Permalink
Implement support for rust-version field in project metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
djc committed Jan 20, 2021
1 parent 50cc40b commit c221fec
Show file tree
Hide file tree
Showing 21 changed files with 445 additions and 6 deletions.
1 change: 1 addition & 0 deletions crates/cargo-test-support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ lazy_static = "1.0"
remove_dir_all = "0.5"
serde_json = "1.0"
tar = { version = "0.4.18", default-features = false }
toml = "0.5.7"
url = "2.0"
33 changes: 31 additions & 2 deletions crates/cargo-test-support/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ pub struct Package {
invalid_json: bool,
proc_macro: bool,
links: Option<String>,
rust_version: Option<String>,
cargo_features: Vec<String>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -247,6 +249,8 @@ impl Package {
invalid_json: false,
proc_macro: false,
links: None,
rust_version: None,
cargo_features: Vec::new(),
}
}

Expand Down Expand Up @@ -363,6 +367,12 @@ impl Package {
self
}

/// Specify a minimal Rust version.
pub fn rust_version(&mut self, rust_version: &str) -> &mut Package {
self.rust_version = Some(rust_version.into());
self
}

/// Causes the JSON line emitted in the index to be invalid, presumably
/// causing Cargo to skip over this version.
pub fn invalid_json(&mut self, invalid: bool) -> &mut Package {
Expand All @@ -375,6 +385,11 @@ impl Package {
self
}

pub fn cargo_feature(&mut self, feature: &str) -> &mut Package {
self.cargo_features.push(feature.to_owned());
self
}

/// Creates the package and place it in the registry.
///
/// This does not actually use Cargo's publishing system, but instead
Expand Down Expand Up @@ -502,15 +517,29 @@ impl Package {
}

fn append_manifest<W: Write>(&self, ar: &mut Builder<W>) {
let mut manifest = format!(
let mut manifest = String::new();

if !self.cargo_features.is_empty() {
manifest.push_str(&format!(
"cargo-features = {}\n\n",
toml::to_string(&self.cargo_features).unwrap()
));
}

manifest.push_str(&format!(
r#"
[package]
name = "{}"
version = "{}"
authors = []
"#,
self.name, self.vers
);
));

if let Some(version) = &self.rust_version {
manifest.push_str(&format!("rust-version = \"{}\"", version));
}

for dep in self.deps.iter() {
let target = match dep.target {
None => String::new(),
Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub fn cli() -> App {
.arg_target_triple("Build for the target triple")
.arg_target_dir()
.arg_manifest_path()
.arg_ignore_rust_version()
.arg_message_format()
.arg(opt(
"no-fail-fast",
Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub fn cli() -> App {
.value_name("PATH"),
)
.arg_manifest_path()
.arg_ignore_rust_version()
.arg_message_format()
.arg_build_plan()
.arg_unit_graph()
Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub fn cli() -> App {
.arg_target_triple("Check for the target triple")
.arg_target_dir()
.arg_manifest_path()
.arg_ignore_rust_version()
.arg_message_format()
.arg_unit_graph()
.after_help("Run `cargo help check` for more detailed information.\n")
Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn cli() -> App {
.arg_target_dir()
.arg_manifest_path()
.arg_message_format()
.arg_ignore_rust_version()
.arg_unit_graph()
.after_help("Run `cargo help doc` for more detailed information.\n")
}
Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub fn cli() -> App {
.long("allow-staged")
.help("Fix code even if the working directory has staged changes"),
)
.arg_ignore_rust_version()
.after_help("Run `cargo help fix` for more detailed information.\n")
}

Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub fn cli() -> App {
.arg_manifest_path()
.arg_message_format()
.arg_unit_graph()
.arg_ignore_rust_version()
.after_help("Run `cargo help run` for more detailed information.\n")
}

Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn cli() -> App {
.arg_manifest_path()
.arg_message_format()
.arg_unit_graph()
.arg_ignore_rust_version()
.after_help("Run `cargo help rustc` for more detailed information.\n")
}

Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub fn cli() -> App {
.arg_manifest_path()
.arg_message_format()
.arg_unit_graph()
.arg_ignore_rust_version()
.after_help("Run `cargo help rustdoc` for more detailed information.\n")
}

Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo/commands/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub fn cli() -> App {
.arg_target_triple("Build for the target triple")
.arg_target_dir()
.arg_manifest_path()
.arg_ignore_rust_version()
.arg_message_format()
.arg_unit_graph()
.after_help("Run `cargo help test` for more detailed information.\n")
Expand Down
14 changes: 14 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ pub enum Edition {
Edition2021,
}

impl Edition {
pub(crate) fn first_version(&self) -> Option<semver::Version> {
use Edition::*;
match self {
Edition2015 => None,
Edition2018 => Some(semver::Version::new(1, 31, 0)),
Edition2021 => Some(semver::Version::new(1, 62, 0)),
}
}
}

impl fmt::Display for Edition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Expand Down Expand Up @@ -218,6 +229,9 @@ features! {

// Allow to specify whether binaries should be stripped.
[unstable] strip: bool,

// Specifying a minimal 'rust-version' attribute for crates
[unstable] rust_version: bool,
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/cargo/core/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub struct Manifest {
original: Rc<TomlManifest>,
unstable_features: Features,
edition: Edition,
rust_version: Option<String>,
im_a_teapot: Option<bool>,
default_run: Option<String>,
metabuild: Option<Vec<String>>,
Expand Down Expand Up @@ -379,6 +380,7 @@ impl Manifest {
workspace: WorkspaceConfig,
unstable_features: Features,
edition: Edition,
rust_version: Option<String>,
im_a_teapot: Option<bool>,
default_run: Option<String>,
original: Rc<TomlManifest>,
Expand All @@ -401,6 +403,7 @@ impl Manifest {
workspace,
unstable_features,
edition,
rust_version,
original,
im_a_teapot,
default_run,
Expand Down Expand Up @@ -520,6 +523,10 @@ impl Manifest {
self.edition
}

pub fn rust_version(&self) -> Option<&str> {
self.rust_version.as_deref()
}

pub fn custom_metadata(&self) -> Option<&toml::Value> {
self.custom_metadata.as_ref()
}
Expand Down
4 changes: 4 additions & 0 deletions src/cargo/core/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ impl Package {
pub fn proc_macro(&self) -> bool {
self.targets().iter().any(|target| target.proc_macro())
}
/// Gets the package's minimum Rust version.
pub fn rust_version(&self) -> Option<&str> {
self.manifest().rust_version()
}

/// Returns `true` if the package uses a custom build script for any target.
pub fn has_custom_build(&self) -> bool {
Expand Down
35 changes: 35 additions & 0 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ pub struct CompileOptions {
/// Whether the `--document-private-items` flags was specified and should
/// be forwarded to `rustdoc`.
pub rustdoc_document_private_items: bool,
/// Whether the build process should check the minimum Rust version
/// defined in the cargo metadata for a crate.
pub honor_rust_version: bool,
}

impl<'a> CompileOptions {
Expand All @@ -95,6 +98,7 @@ impl<'a> CompileOptions {
target_rustc_args: None,
local_rustdoc_args: None,
rustdoc_document_private_items: false,
honor_rust_version: true,
})
}
}
Expand Down Expand Up @@ -306,6 +310,7 @@ pub fn create_bcx<'a, 'cfg>(
ref target_rustc_args,
ref local_rustdoc_args,
rustdoc_document_private_items,
honor_rust_version,
} = *options;
let config = ws.config();

Expand Down Expand Up @@ -551,6 +556,36 @@ pub fn create_bcx<'a, 'cfg>(
}
}

if honor_rust_version {
// Remove any pre-release identifiers for easier comparison
let current_version = &target_data.rustc.version;
let untagged_version = semver::Version::new(
current_version.major,
current_version.minor,
current_version.patch,
);

for unit in unit_graph.keys() {
let version = match unit.pkg.rust_version() {
Some(v) => v,
None => continue,
};

let req = semver::VersionReq::parse(version).unwrap();
if req.matches(&untagged_version) {
continue;
}

anyhow::bail!(
"package `{}` cannot be built because it requires rustc {} or newer, \
while the currently active rustc version is {}",
unit.pkg,
version,
current_version,
);
}
}

let bcx = BuildContext::new(
ws,
pkg_set,
Expand Down
1 change: 1 addition & 0 deletions src/cargo/ops/cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ fn run_verify(ws: &Workspace<'_>, tar: &FileLock, opts: &PackageOpts<'_>) -> Car
target_rustc_args: rustc_args,
local_rustdoc_args: None,
rustdoc_document_private_items: false,
honor_rust_version: true,
},
&exec,
)?;
Expand Down
17 changes: 17 additions & 0 deletions src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ pub trait AppExt: Sized {
fn arg_dry_run(self, dry_run: &'static str) -> Self {
self._arg(opt("dry-run", dry_run))
}

fn arg_ignore_rust_version(self) -> Self {
self._arg(
opt(
"ignore-rust-version",
"Ignore `rust-version` specification in packages",
)
.hidden(true), // nightly only (`rust-version` feature)
)
}
}

impl AppExt for App {
Expand Down Expand Up @@ -488,8 +498,15 @@ pub trait ArgMatchesExt {
target_rustc_args: None,
local_rustdoc_args: None,
rustdoc_document_private_items: false,
honor_rust_version: !self._is_present("ignore-rust-version"),
};

if !opts.honor_rust_version {
config
.cli_unstable()
.fail_if_stable_opt("--ignore-rust-version", 8072)?;
}

if let Some(ws) = workspace {
self.check_optional_opts(ws, &opts)?;
} else if self.is_present_with_zero_values("package") {
Expand Down
Loading

0 comments on commit c221fec

Please sign in to comment.