Skip to content

refactor: use macro to remove duplication of workspace inheritable fields getters #12317

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 29, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 71 additions & 159 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1595,178 +1595,89 @@ pub struct InheritableFields {
ws_root: PathBuf,
}

impl InheritableFields {
pub fn update_deps(&mut self, deps: Option<BTreeMap<String, TomlDependency>>) {
self.dependencies = deps;
}

pub fn update_lints(&mut self, lints: Option<TomlLints>) {
self.lints = lints;
}

pub fn update_ws_path(&mut self, ws_root: PathBuf) {
self.ws_root = ws_root;
}

pub fn dependencies(&self) -> CargoResult<BTreeMap<String, TomlDependency>> {
self.dependencies.clone().map_or(
Err(anyhow!("`workspace.dependencies` was not defined")),
|d| Ok(d),
)
}

pub fn lints(&self) -> CargoResult<TomlLints> {
self.lints
.clone()
.map_or(Err(anyhow!("`workspace.lints` was not defined")), |d| Ok(d))
}
/// Defines simple getter methods for inheritable fields.
macro_rules! inheritable_field_getter {
( $(($key:literal, $field:ident -> $ret:ty),)* ) => (
$(
#[doc = concat!("Gets the field `workspace.", $key, "`.")]
pub fn $field(&self) -> CargoResult<$ret> {
let Some(val) = &self.$field else {
bail!("`workspace.{}` was not defined", $key);
};
Ok(val.clone())
}
)*
)
}

impl InheritableFields {
inheritable_field_getter! {
// Please keep this list lexicographically ordered.
("dependencies", dependencies -> BTreeMap<String, TomlDependency>),
("lints", lints -> TomlLints),
("package.authors", authors -> Vec<String>),
("package.badges", badges -> BTreeMap<String, BTreeMap<String, String>>),
("package.categories", categories -> Vec<String>),
("package.description", description -> String),
("package.documentation", documentation -> String),
("package.edition", edition -> String),
("package.exclude", exclude -> Vec<String>),
("package.homepage", homepage -> String),
("package.include", include -> Vec<String>),
("package.keywords", keywords -> Vec<String>),
("package.license", license -> String),
("package.publish", publish -> VecStringOrBool),
("package.repository", repository -> String),
("package.rust-version", rust_version -> String),
("package.version", version -> semver::Version),
}

/// Gets a workspace dependency with the `name`.
pub fn get_dependency(&self, name: &str, package_root: &Path) -> CargoResult<TomlDependency> {
self.dependencies.clone().map_or(
Err(anyhow!("`workspace.dependencies` was not defined")),
|deps| {
deps.get(name).map_or(
Err(anyhow!(
"`dependency.{}` was not found in `workspace.dependencies`",
name
)),
|dep| {
let mut dep = dep.clone();
if let TomlDependency::Detailed(detailed) = &mut dep {
detailed.resolve_path(name, self.ws_root(), package_root)?
}
Ok(dep)
},
)
},
)
}

pub fn version(&self) -> CargoResult<semver::Version> {
self.version.clone().map_or(
Err(anyhow!("`workspace.package.version` was not defined")),
|d| Ok(d),
)
}

pub fn authors(&self) -> CargoResult<Vec<String>> {
self.authors.clone().map_or(
Err(anyhow!("`workspace.package.authors` was not defined")),
|d| Ok(d),
)
}

pub fn description(&self) -> CargoResult<String> {
self.description.clone().map_or(
Err(anyhow!("`workspace.package.description` was not defined")),
|d| Ok(d),
)
}

pub fn homepage(&self) -> CargoResult<String> {
self.homepage.clone().map_or(
Err(anyhow!("`workspace.package.homepage` was not defined")),
|d| Ok(d),
)
}

pub fn documentation(&self) -> CargoResult<String> {
self.documentation.clone().map_or(
Err(anyhow!("`workspace.package.documentation` was not defined")),
|d| Ok(d),
)
}

pub fn readme(&self, package_root: &Path) -> CargoResult<StringOrBool> {
readme_for_package(self.ws_root.as_path(), self.readme.clone()).map_or(
Err(anyhow!("`workspace.package.readme` was not defined")),
|readme| {
let rel_path =
resolve_relative_path("readme", &self.ws_root, package_root, &readme)?;
Ok(StringOrBool::String(rel_path))
},
)
}

pub fn keywords(&self) -> CargoResult<Vec<String>> {
self.keywords.clone().map_or(
Err(anyhow!("`workspace.package.keywords` was not defined")),
|d| Ok(d),
)
}

pub fn categories(&self) -> CargoResult<Vec<String>> {
self.categories.clone().map_or(
Err(anyhow!("`workspace.package.categories` was not defined")),
|d| Ok(d),
)
}

pub fn license(&self) -> CargoResult<String> {
self.license.clone().map_or(
Err(anyhow!("`workspace.package.license` was not defined")),
|d| Ok(d),
)
let Some(deps) = &self.dependencies else {
bail!("`workspace.dependencies` was not defined");
};
let Some(dep) = deps.get(name) else {
bail!("`dependency.{name}` was not found in `workspace.dependencies`");
};
let mut dep = dep.clone();
if let TomlDependency::Detailed(detailed) = &mut dep {
detailed.resolve_path(name, self.ws_root(), package_root)?;
}
Ok(dep)
}

/// Gets the field `workspace.package.license-file`.
pub fn license_file(&self, package_root: &Path) -> CargoResult<String> {
self.license_file.clone().map_or(
Err(anyhow!("`workspace.package.license_file` was not defined")),
|d| resolve_relative_path("license-file", &self.ws_root, package_root, &d),
)
}

pub fn repository(&self) -> CargoResult<String> {
self.repository.clone().map_or(
Err(anyhow!("`workspace.package.repository` was not defined")),
|d| Ok(d),
)
}

pub fn publish(&self) -> CargoResult<VecStringOrBool> {
self.publish.clone().map_or(
Err(anyhow!("`workspace.package.publish` was not defined")),
|d| Ok(d),
)
}

pub fn edition(&self) -> CargoResult<String> {
self.edition.clone().map_or(
Err(anyhow!("`workspace.package.edition` was not defined")),
|d| Ok(d),
)
let Some(license_file) = &self.license_file else {
bail!("`workspace.package.license-file` was not defined");
};
resolve_relative_path("license-file", &self.ws_root, package_root, license_file)
}

pub fn rust_version(&self) -> CargoResult<String> {
self.rust_version.clone().map_or(
Err(anyhow!("`workspace.package.rust-version` was not defined")),
|d| Ok(d),
)
/// Gets the field `workspace.package.readme`.
pub fn readme(&self, package_root: &Path) -> CargoResult<StringOrBool> {
let Some(readme) = readme_for_package(self.ws_root.as_path(), self.readme.as_ref()) else {
bail!("`workspace.package.readme` was not defined");
};
resolve_relative_path("readme", &self.ws_root, package_root, &readme)
.map(StringOrBool::String)
}

pub fn badges(&self) -> CargoResult<BTreeMap<String, BTreeMap<String, String>>> {
self.badges.clone().map_or(
Err(anyhow!("`workspace.package.badges` was not defined")),
|d| Ok(d),
)
pub fn ws_root(&self) -> &PathBuf {
&self.ws_root
}

pub fn exclude(&self) -> CargoResult<Vec<String>> {
self.exclude.clone().map_or(
Err(anyhow!("`workspace.package.exclude` was not defined")),
|d| Ok(d),
)
pub fn update_deps(&mut self, deps: Option<BTreeMap<String, TomlDependency>>) {
self.dependencies = deps;
}

pub fn include(&self) -> CargoResult<Vec<String>> {
self.include.clone().map_or(
Err(anyhow!("`workspace.package.include` was not defined")),
|d| Ok(d),
)
pub fn update_lints(&mut self, lints: Option<TomlLints>) {
self.lints = lints;
}

pub fn ws_root(&self) -> &PathBuf {
&self.ws_root
pub fn update_ws_path(&mut self, ws_root: PathBuf) {
self.ws_root = ws_root;
}
}

Expand Down Expand Up @@ -2464,7 +2375,8 @@ impl TomlManifest {
.readme
.clone()
.map(|mw| mw.resolve("readme", || inherit()?.readme(package_root)))
.transpose()?,
.transpose()?
.as_ref(),
),
authors: package
.authors
Expand Down Expand Up @@ -3062,7 +2974,7 @@ fn inheritable_from_path(
}

/// Returns the name of the README file for a [`TomlPackage`].
pub fn readme_for_package(package_root: &Path, readme: Option<StringOrBool>) -> Option<String> {
pub fn readme_for_package(package_root: &Path, readme: Option<&StringOrBool>) -> Option<String> {
match &readme {
None => default_readme_from_package_root(package_root),
Some(value) => match value {
Expand Down