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 23, 2022
1 parent 168747c commit 2c810af
Show file tree
Hide file tree
Showing 45 changed files with 165 additions and 277 deletions.
2 changes: 1 addition & 1 deletion src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,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
36 changes: 36 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,44 @@ 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 `workspace = true`.

Along with the `workspace` key, dependencies can also include these keys:
- [`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]`

Other than `optional` and `features`, inherited dependencies cannot use any other
dependency key (such as `version` or `default-features`).

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

```toml
[project]
name = "bar"
version = "0.2.0"

[dependencies]
regex = { workspace = true, features = ["unicode"] }

[build-dependencies]
cc.workspace = true

[dev-dependencies]
rand = { workspace = true, optional = 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
10 changes: 9 additions & 1 deletion src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ Each new feature described below should explain how to use it.
* [avoid-dev-deps](#avoid-dev-deps) — Prevents the resolver from including dev-dependencies during resolution.
* [minimal-versions](#minimal-versions) — Forces the resolver to use the lowest compatible version instead of the highest.
* [public-dependency](#public-dependency) — Allows dependencies to be classified as either public or private.
* [workspace-inheritance](#workspace-inheritance) - Allow workspace members to share fields and dependencies
* Output behavior
* [out-dir](#out-dir) — Adds a directory where artifacts are copied to.
* [terminal-width](#terminal-width) — Tells rustc the width of the terminal so that long diagnostic messages can be truncated to be more readable.
Expand Down Expand Up @@ -1536,3 +1535,12 @@ setting the default target platform triples.
The `--crate-type` flag for `cargo rustc` has been stabilized in the 1.64
release. See the [`cargo rustc` documentation](../commands/cargo-rustc.md)
for more information.


### Workspace Inheritance

Workspace Inheritance has been stabilized in the 1.64 release.
See [workspace.package](workspaces.md#the-workspacepackage-table),
[workspace.dependencies](workspaces.md#the-workspacedependencies-table),
and [inheriting-a-dependency-from-a-workspace](specifying-dependencies.md#inheriting-a-dependency-from-a-workspace)
for more information.
Loading

0 comments on commit 2c810af

Please sign in to comment.