From 6c6bc32e622137cbb2c9fe75ba77e319c2aab014 Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Mon, 1 May 2023 21:06:04 +0800 Subject: [PATCH] Automatically inherit workspace fields when running cargo new Signed-off-by: hi-rustin --- src/cargo/ops/cargo_new.rs | 115 ++++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 7 deletions(-) diff --git a/src/cargo/ops/cargo_new.rs b/src/cargo/ops/cargo_new.rs index caa1d2fa8cc1..697d054960d6 100644 --- a/src/cargo/ops/cargo_new.rs +++ b/src/cargo/ops/cargo_new.rs @@ -1,5 +1,6 @@ use crate::core::{Edition, Shell, Workspace}; use crate::util::errors::CargoResult; +use crate::util::toml::parse_document; use crate::util::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo}; use crate::util::{restricted_names, Config}; use anyhow::{anyhow, Context as _}; @@ -866,15 +867,115 @@ mod tests { } } } - - if let Err(e) = Workspace::new(&path.join("Cargo.toml"), config) { - crate::display_warning_with_error( - "compiling this new package may not work due to invalid \ + match Workspace::new(&path.join("Cargo.toml"), config) { + Ok(ws) => { + // Because we only inherit the package field of workspace for valid members of workspace, + // we did not inherit it directly above. + let root_manifest = paths::read(ws.root_manifest())?; + let workspace_document = + parse_document(root_manifest.as_str(), ws.root_manifest(), config)?; + if let Some(workspace_package_keys) = workspace_document + .get("workspace") + .and_then(|workspace| workspace.get("package")) + .and_then(|package| package.as_table()) + { + // Because we need to keep the format of the `Cargo.toml` file, + // we can not use `toml_edit`/`toml` to modify the `Cargo.toml` file directly. + // Instead, we need to rewrite the `Cargo.toml` file with the inherited package fields. + return create_manifest_with_inherited_workspace_package_fields( + opts, + path, + name, + cargotoml_path_specifier.as_str(), + workspace_package_keys, + ); + } + } + Err(e) => { + crate::display_warning_with_error( + "compiling this new package may not work due to invalid \ workspace configuration", - &e, - &mut config.shell(), - ); + &e, + &mut config.shell(), + ); + } } Ok(()) } + +fn create_manifest_with_inherited_workspace_package_fields( + opts: &MkOptions<'_>, + path: &Path, + name: &str, + cargotoml_path_specifier: &str, + workspace_package_keys: &toml::value::Table, +) -> CargoResult<()> { + if workspace_package_keys.is_empty() { + return Ok(()); + } + // Try inherit the edition from the workspace if it is not specified. + let edition = match opts.edition { + Some(edition) => { + format!("edition = {}", toml::Value::String(edition.to_string())) + } + None => { + if workspace_package_keys.contains_key("edition") { + format!("edition.workspace = {}", toml::Value::Boolean(true)) + } else { + format!( + "edition = {}", + toml::Value::String(Edition::LATEST_STABLE.to_string()) + ) + } + } + }; + // Try inherit the version from the workspace if it is not specified. + let version = if workspace_package_keys.contains_key("version") { + format!("version.workspace = {}", toml::Value::Boolean(true)) + } else { + "version = \"0.1.0\"".to_string() + }; + // Try inherit the publish from the workspace if it is not specified. + let publish = match opts.registry { + Some(registry) => format!( + "publish = {}\n", + toml::Value::Array(vec!(toml::Value::String(registry.to_string()))) + ), + None => { + if workspace_package_keys.contains_key("publish") { + format!("publish.workspace = {}\n", toml::Value::Boolean(true)) + } else { + "".to_string() + } + } + }; + // Inherit other keys from the workspace. + let workspace_package_fields = workspace_package_keys + .iter() + .filter(|(key, _)| *key != "edition" && *key != "version" && *key != "publish") + .map(|(key, _)| format!("{}.workspace = {}", key, toml::Value::Boolean(true))) + .collect::>(); + paths::write( + &path.join("Cargo.toml"), + format!( + r#"[package] +name = "{}" +{} +{} +{}{} +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +{}"#, + name, + version, + edition, + publish, + workspace_package_fields.join("\n"), + cargotoml_path_specifier + ) + .as_bytes(), + )?; + return Ok(()); +}