Skip to content

Commit

Permalink
Stabilize Workspace Inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
Muscraft committed Jul 13, 2022
1 parent 92ff479 commit e503329
Show file tree
Hide file tree
Showing 45 changed files with 172 additions and 454 deletions.
2 changes: 1 addition & 1 deletion src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ features! {
(unstable, profile_rustflags, "", "reference/unstable.html#profile-rustflags-option"),

// Allow specifying rustflags directly in a profile
(unstable, workspace_inheritance, "", "reference/unstable.html#workspace-inheritance"),
(stable, workspace_inheritance, "1.64", "reference/unstable.html#workspace-inheritance"),
}

pub struct Feature {
Expand Down
65 changes: 24 additions & 41 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1017,19 +1017,16 @@ pub enum MaybeWorkspace<T> {
impl<T> MaybeWorkspace<T> {
fn resolve<'a>(
self,
cargo_features: &Features,
label: &str,
get_ws_field: impl FnOnce() -> CargoResult<T>,
) -> CargoResult<T> {
match self {
MaybeWorkspace::Defined(value) => Ok(value),
MaybeWorkspace::Workspace(TomlWorkspaceField { workspace: true }) => {
cargo_features.require(Feature::workspace_inheritance())?;
get_ws_field().context(format!(
MaybeWorkspace::Workspace(TomlWorkspaceField { workspace: true }) => get_ws_field()
.context(format!(
"error inheriting `{}` from workspace root manifest's `workspace.package.{}`",
label, label
))
}
)),
MaybeWorkspace::Workspace(TomlWorkspaceField { workspace: false }) => Err(anyhow!(
"`workspace=false` is unsupported for `package.{}`",
label,
Expand Down Expand Up @@ -1592,15 +1589,15 @@ impl TomlManifest {
let version = project
.version
.clone()
.resolve(&features, "version", || inherit()?.version())?;
.resolve("version", || inherit()?.version())?;

project.version = MaybeWorkspace::Defined(version.clone());

let pkgid = project.to_package_id(source_id, version)?;

let edition = if let Some(edition) = project.edition.clone() {
let edition: Edition = edition
.resolve(&features, "edition", || inherit()?.edition())?
.resolve("edition", || inherit()?.edition())?
.parse()
.with_context(|| "failed to parse the `edition` key")?;
project.edition = Some(MaybeWorkspace::Defined(edition.to_string()));
Expand All @@ -1625,7 +1622,7 @@ impl TomlManifest {
let rust_version = if let Some(rust_version) = &project.rust_version {
let rust_version = rust_version
.clone()
.resolve(&features, "rust_version", || inherit()?.rust_version())?;
.resolve("rust_version", || inherit()?.rust_version())?;
let req = match semver::VersionReq::parse(&rust_version) {
// Exclude semver operators like `^` and pre-release identifiers
Ok(req) if rust_version.chars().all(|c| c.is_ascii_digit() || c == '.') => req,
Expand Down Expand Up @@ -1716,7 +1713,6 @@ impl TomlManifest {
};

fn process_dependencies(
features: &Features,
cx: &mut Context<'_, '_>,
new_deps: Option<&BTreeMap<String, TomlDependency>>,
kind: Option<DepKind>,
Expand All @@ -1736,7 +1732,7 @@ impl TomlManifest {

let mut deps: BTreeMap<String, TomlDependency> = BTreeMap::new();
for (n, v) in dependencies.iter() {
let resolved = v.clone().resolve(features, n, cx, || inherit())?;
let resolved = v.clone().resolve(n, cx, || inherit())?;
let dep = resolved.to_dependency(n, cx, kind)?;
validate_package_name(dep.name_in_toml().as_str(), "dependency name", "")?;
cx.deps.push(dep);
Expand All @@ -1747,7 +1743,6 @@ impl TomlManifest {

// Collect the dependencies.
let dependencies = process_dependencies(
&features,
&mut cx,
me.dependencies.as_ref(),
None,
Expand All @@ -1762,7 +1757,6 @@ impl TomlManifest {
.as_ref()
.or_else(|| me.dev_dependencies2.as_ref());
let dev_deps = process_dependencies(
&features,
&mut cx,
dev_deps,
Some(DepKind::Development),
Expand All @@ -1777,7 +1771,6 @@ impl TomlManifest {
.as_ref()
.or_else(|| me.build_dependencies2.as_ref());
let build_deps = process_dependencies(
&features,
&mut cx,
build_deps,
Some(DepKind::Build),
Expand All @@ -1793,7 +1786,6 @@ impl TomlManifest {
Some(platform)
};
let deps = process_dependencies(
&features,
&mut cx,
platform.dependencies.as_ref(),
None,
Expand All @@ -1809,7 +1801,6 @@ impl TomlManifest {
.as_ref()
.or_else(|| platform.build_dependencies2.as_ref());
let build_deps = process_dependencies(
&features,
&mut cx,
build_deps,
Some(DepKind::Build),
Expand All @@ -1825,7 +1816,6 @@ impl TomlManifest {
.as_ref()
.or_else(|| platform.dev_dependencies2.as_ref());
let dev_deps = process_dependencies(
&features,
&mut cx,
dev_deps,
Some(DepKind::Development),
Expand Down Expand Up @@ -1872,13 +1862,13 @@ impl TomlManifest {
let exclude = project
.exclude
.clone()
.map(|mw| mw.resolve(&features, "exclude", || inherit()?.exclude()))
.map(|mw| mw.resolve("exclude", || inherit()?.exclude()))
.transpose()?
.unwrap_or_default();
let include = project
.include
.clone()
.map(|mw| mw.resolve(&features, "include", || inherit()?.include()))
.map(|mw| mw.resolve("include", || inherit()?.include()))
.transpose()?
.unwrap_or_default();
let empty_features = BTreeMap::new();
Expand All @@ -1895,67 +1885,63 @@ impl TomlManifest {
description: project
.description
.clone()
.map(|mw| mw.resolve(&features, "description", || inherit()?.description()))
.map(|mw| mw.resolve("description", || inherit()?.description()))
.transpose()?,
homepage: project
.homepage
.clone()
.map(|mw| mw.resolve(&features, "homepage", || inherit()?.homepage()))
.map(|mw| mw.resolve("homepage", || inherit()?.homepage()))
.transpose()?,
documentation: project
.documentation
.clone()
.map(|mw| mw.resolve(&features, "documentation", || inherit()?.documentation()))
.map(|mw| mw.resolve("documentation", || inherit()?.documentation()))
.transpose()?,
readme: readme_for_project(
package_root,
project
.readme
.clone()
.map(|mw| mw.resolve(&features, "readme", || inherit()?.readme(package_root)))
.map(|mw| mw.resolve("readme", || inherit()?.readme(package_root)))
.transpose()?,
),
authors: project
.authors
.clone()
.map(|mw| mw.resolve(&features, "authors", || inherit()?.authors()))
.map(|mw| mw.resolve("authors", || inherit()?.authors()))
.transpose()?
.unwrap_or_default(),
license: project
.license
.clone()
.map(|mw| mw.resolve(&features, "license", || inherit()?.license()))
.map(|mw| mw.resolve("license", || inherit()?.license()))
.transpose()?,
license_file: project
.license_file
.clone()
.map(|mw| {
mw.resolve(&features, "license", || {
inherit()?.license_file(package_root)
})
})
.map(|mw| mw.resolve("license", || inherit()?.license_file(package_root)))
.transpose()?,
repository: project
.repository
.clone()
.map(|mw| mw.resolve(&features, "repository", || inherit()?.repository()))
.map(|mw| mw.resolve("repository", || inherit()?.repository()))
.transpose()?,
keywords: project
.keywords
.clone()
.map(|mw| mw.resolve(&features, "keywords", || inherit()?.keywords()))
.map(|mw| mw.resolve("keywords", || inherit()?.keywords()))
.transpose()?
.unwrap_or_default(),
categories: project
.categories
.clone()
.map(|mw| mw.resolve(&features, "categories", || inherit()?.categories()))
.map(|mw| mw.resolve("categories", || inherit()?.categories()))
.transpose()?
.unwrap_or_default(),
badges: me
.badges
.clone()
.map(|mw| mw.resolve(&features, "badges", || inherit()?.badges()))
.map(|mw| mw.resolve("badges", || inherit()?.badges()))
.transpose()?
.unwrap_or_default(),
links: project.links.clone(),
Expand Down Expand Up @@ -2015,11 +2001,10 @@ impl TomlManifest {
profiles.validate(&features, &mut warnings)?;
}

let publish = project.publish.clone().map(|publish| {
publish
.resolve(&features, "publish", || inherit()?.publish())
.unwrap()
});
let publish = project
.publish
.clone()
.map(|publish| publish.resolve("publish", || inherit()?.publish()).unwrap());

project.publish = publish.clone().map(|p| MaybeWorkspace::Defined(p));

Expand Down Expand Up @@ -2479,7 +2464,6 @@ impl<P: ResolveToPath + Clone> TomlDependency<P> {
impl TomlDependency {
fn resolve<'a>(
self,
cargo_features: &Features,
label: &str,
cx: &mut Context<'_, '_>,
get_inheritable: impl FnOnce() -> CargoResult<&'a InheritableFields>,
Expand All @@ -2492,7 +2476,6 @@ impl TomlDependency {
features,
optional,
}) => {
cargo_features.require(Feature::workspace_inheritance())?;
let inheritable = get_inheritable()?;
inheritable.get_dependency(label).context(format!(
"error reading `dependencies.{}` from workspace root manifest's `workspace.dependencies.{}`",
Expand Down
43 changes: 43 additions & 0 deletions src/doc/src/reference/specifying-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,51 @@ following to the above manifest:
log-debug = ['bar/log-debug'] # using 'foo/log-debug' would be an error!
```

### Inheriting a dependency from a workspace

Dependencies can be inherited from a workspace by specifying the
dependency in the workspace's [`[workspace.dependencies]`][workspace.dependencies] table.
After that add it to the `[dependencies]` table with `dep.workspace = true`.

The `workspace` key can be defined with:
- [`optional`][optional]: Note that the`[workspace.dependencies]` table is not allowed to specify `optional`.
- [`features`][features]: These are additive with the features declared in the `[workspace.dependencies]`

The `workspace` key cannot be defined with:

| | |
|------------------|--------------------|
| `branch` | `default-features` |
| `git` | `package` |
| `path` | `registry` |
| `registry-index` | `rev` |
| `tag` | `version` |


Dependencies in the `[dependencies]`, `[dev-dependencies]`, `[build-dependencies]`, and
`[target."...".dependencies]` sections support the ability to reference the
`[workspace.dependencies]` definition of dependencies.

Example:
```toml
[dependencies]
dep.workspace = true
dep2 = { workspace = true, features = ["fancy"] }
dep3 = { workspace = true, optional = true }
dep4 = { workspace = true, optional = true, features = ["fancy"] }

[build-dependencies]
dep-build.workspace = true

[dev-dependencies]
dep-dev.workspace = true
```

[crates.io]: https://crates.io/
[dev-dependencies]: #development-dependencies
[workspace.dependencies]: workspaces.md#the-workspacedependencies-table
[optional]: features.md#optional-dependencies
[features]: features.md

<script>
(function() {
Expand Down
Loading

0 comments on commit e503329

Please sign in to comment.