Skip to content

Add support for workspace.metadata table #8323

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 7 commits into from
Jun 23, 2020
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
1 change: 1 addition & 0 deletions src/cargo/core/compiler/standard_lib.rs
Original file line number Diff line number Diff line change
@@ -65,6 +65,7 @@ pub fn resolve_std<'cfg>(
&Some(members),
/*default_members*/ &None,
/*exclude*/ &None,
/*custom_metadata*/ &None,
));
let virtual_manifest = crate::core::VirtualManifest::new(
/*replace*/ Vec::new(),
74 changes: 49 additions & 25 deletions src/cargo/core/workspace.rs
Original file line number Diff line number Diff line change
@@ -88,6 +88,9 @@ pub struct Workspace<'cfg> {

/// The resolver behavior specified with the `resolver` field.
resolve_behavior: Option<ResolveBehavior>,

/// Workspace-level custom metadata
custom_metadata: Option<toml::Value>,
}

// Separate structure for tracking loaded packages (to avoid loading anything
@@ -126,6 +129,7 @@ pub struct WorkspaceRootConfig {
members: Option<Vec<String>>,
default_members: Option<Vec<String>>,
exclude: Vec<String>,
custom_metadata: Option<toml::Value>,
}

/// An iterator over the member packages of a workspace, returned by
@@ -155,6 +159,9 @@ impl<'cfg> Workspace<'cfg> {
ws.root_manifest = ws.find_root(manifest_path)?;
}

ws.custom_metadata = ws
.load_workspace_config()?
.and_then(|cfg| cfg.custom_metadata);
ws.find_members()?;
ws.resolve_behavior = match ws.root_maybe() {
MaybePackage::Package(p) => p.manifest().resolve_behavior(),
@@ -182,6 +189,7 @@ impl<'cfg> Workspace<'cfg> {
loaded_packages: RefCell::new(HashMap::new()),
ignore_lock: false,
resolve_behavior: None,
custom_metadata: None,
}
}

@@ -395,6 +403,30 @@ impl<'cfg> Workspace<'cfg> {
self
}

pub fn custom_metadata(&self) -> Option<&toml::Value> {
self.custom_metadata.as_ref()
}

pub fn load_workspace_config(&mut self) -> CargoResult<Option<WorkspaceRootConfig>> {
// If we didn't find a root, it must mean there is no [workspace] section, and thus no
// metadata.
if let Some(root_path) = &self.root_manifest {
let root_package = self.packages.load(root_path)?;
match root_package.workspace_config() {
WorkspaceConfig::Root(ref root_config) => {
return Ok(Some(root_config.clone()));
}

_ => anyhow::bail!(
"root of a workspace inferred but wasn't a root: {}",
root_path.display()
),
}
}

Ok(None)
}

/// Finds the root of a workspace for the crate whose manifest is located
/// at `manifest_path`.
///
@@ -476,8 +508,8 @@ impl<'cfg> Workspace<'cfg> {
/// will transitively follow all `path` dependencies looking for members of
/// the workspace.
fn find_members(&mut self) -> CargoResult<()> {
let root_manifest_path = match self.root_manifest {
Some(ref path) => path.clone(),
let workspace_config = match self.load_workspace_config()? {
Some(workspace_config) => workspace_config,
None => {
debug!("find_members - only me as a member");
self.members.push(self.current_manifest.clone());
@@ -490,30 +522,20 @@ impl<'cfg> Workspace<'cfg> {
}
};

let members_paths;
let default_members_paths;
{
let root_package = self.packages.load(&root_manifest_path)?;
match *root_package.workspace_config() {
WorkspaceConfig::Root(ref root_config) => {
members_paths = root_config
.members_paths(root_config.members.as_ref().unwrap_or(&vec![]))?;
default_members_paths = if root_manifest_path == self.current_manifest {
if let Some(ref default) = root_config.default_members {
Some(root_config.members_paths(default)?)
} else {
None
}
} else {
None
};
}
_ => anyhow::bail!(
"root of a workspace inferred but wasn't a root: {}",
root_manifest_path.display()
),
// self.root_manifest must be Some to have retrieved workspace_config
let root_manifest_path = self.root_manifest.clone().unwrap();

let members_paths =
workspace_config.members_paths(workspace_config.members.as_ref().unwrap_or(&vec![]))?;
let default_members_paths = if root_manifest_path == self.current_manifest {
if let Some(ref default) = workspace_config.default_members {
Some(workspace_config.members_paths(default)?)
} else {
None
}
}
} else {
None
};

for path in members_paths {
self.find_path_deps(&path.join("Cargo.toml"), &root_manifest_path, false)?;
@@ -1129,12 +1151,14 @@ impl WorkspaceRootConfig {
members: &Option<Vec<String>>,
default_members: &Option<Vec<String>>,
exclude: &Option<Vec<String>>,
custom_metadata: &Option<toml::Value>,
) -> WorkspaceRootConfig {
WorkspaceRootConfig {
root_dir: root_dir.to_path_buf(),
members: members.clone(),
default_members: default_members.clone(),
exclude: exclude.clone().unwrap_or_default(),
custom_metadata: custom_metadata.clone(),
}
}

2 changes: 2 additions & 0 deletions src/cargo/ops/cargo_output_metadata.rs
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo
target_directory: ws.target_dir().into_path_unlocked(),
version: VERSION,
workspace_root: ws.root().to_path_buf(),
metadata: ws.custom_metadata().cloned(),
})
}

@@ -60,6 +61,7 @@ pub struct ExportInfo {
target_directory: PathBuf,
version: u32,
workspace_root: PathBuf,
metadata: Option<toml::Value>,
}

#[derive(Serialize)]
3 changes: 3 additions & 0 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
@@ -825,6 +825,7 @@ pub struct TomlWorkspace {
#[serde(rename = "default-members")]
default_members: Option<Vec<String>>,
exclude: Option<Vec<String>>,
metadata: Option<toml::Value>,
resolver: Option<String>,
}

@@ -1229,6 +1230,7 @@ impl TomlManifest {
&config.members,
&config.default_members,
&config.exclude,
&config.metadata,
)),
(None, root) => WorkspaceConfig::Member {
root: root.cloned(),
@@ -1413,6 +1415,7 @@ impl TomlManifest {
&config.members,
&config.default_members,
&config.exclude,
&config.metadata,
)),
None => {
bail!("virtual manifests must be configured with [workspace]");
9 changes: 9 additions & 0 deletions src/doc/man/cargo-metadata.adoc
Original file line number Diff line number Diff line change
@@ -268,6 +268,15 @@ The output has the following format:
"version": 1,
/* The absolute path to the root of the workspace. */
"workspace_root": "/path/to/my-package"
/* Workspace metadata.
This is null if no metadata is specified. */
"metadata": {
"docs": {
"rs": {
"all-features": true
}
}
}
}
----

9 changes: 9 additions & 0 deletions src/doc/src/reference/manifest.md
Original file line number Diff line number Diff line change
@@ -420,6 +420,15 @@ package-name = "my-awesome-android-app"
assets = "path/to/static"
```

There is a similar table at the workspace level at
[`workspace.metadata`][workspace-metadata]. While cargo does not specify a
format for the content of either of these tables, it is suggested that
external tools may wish to use them in a consistent fashion, such as referring
to the data in `workspace.metadata` if data is missing from `package.metadata`,
if that makes sense for the tool in question.

[workspace-metadata]: workspaces.md#the-workspacemetadata-table

#### The `default-run` field

The `default-run` field in the `[package]` section of the manifest can be used
24 changes: 24 additions & 0 deletions src/doc/src/reference/workspaces.md
Original file line number Diff line number Diff line change
@@ -82,7 +82,31 @@ default-members = ["path/to/member2", "path/to/member3/foo"]

When specified, `default-members` must expand to a subset of `members`.

### The `workspace.metadata` table

The `workspace.metadata` table is ignored by Cargo and will not be warned
about. This section can be used for tools that would like to store workspace
configuration in `Cargo.toml`. For example:

```toml
[workspace]
members = ["member1", "member2"]

[workspace.metadata.webcontents]
root = "path/to/webproject"
tool = ["npm", "run", "build"]
# ...
```

There is a similar set of tables at the package level at
[`package.metadata`][package-metadata]. While cargo does not specify a
format for the content of either of these tables, it is suggested that
external tools may wish to use them in a consistent fashion, such as referring
to the data in `workspace.metadata` if data is missing from `package.metadata`,
if that makes sense for the tool in question.

[package]: manifest.md#the-package-section
[package-metadata]: manifest.md#the-metadata-table
[output directory]: ../guide/build-cache.md
[patch]: overriding-dependencies.md#the-patch-section
[replace]: overriding-dependencies.md#the-replace-section
9 changes: 6 additions & 3 deletions tests/testsuite/alt_registry.rs
Original file line number Diff line number Diff line change
@@ -824,7 +824,8 @@ fn alt_reg_metadata() {
"resolve": null,
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -1003,7 +1004,8 @@ fn alt_reg_metadata() {
"resolve": "{...}",
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -1152,7 +1154,8 @@ fn unknown_registry() {
"resolve": "{...}",
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}
"#,
)
37 changes: 37 additions & 0 deletions tests/testsuite/build.rs
Original file line number Diff line number Diff line change
@@ -3298,6 +3298,43 @@ fn no_warn_about_package_metadata() {
.run();
}

#[cargo_test]
fn no_warn_about_workspace_metadata() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["foo"]
[workspace.metadata]
something = "something_else"
x = 1
y = 2
[workspace.metadata.another]
bar = 12
"#,
)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
"#,
)
.file("foo/src/lib.rs", "")
.build();

p.cargo("build")
.with_stderr(
"[..] foo v0.0.1 ([..])\n\
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
)
.run();
}

#[cargo_test]
fn cargo_build_empty_target() {
let p = project()
79 changes: 58 additions & 21 deletions tests/testsuite/metadata.rs
Original file line number Diff line number Diff line change
@@ -67,7 +67,8 @@ fn cargo_metadata_simple() {
},
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -159,7 +160,8 @@ crate-type = ["lib", "staticlib"]
},
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -248,7 +250,8 @@ optional_feat = []
},
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -537,7 +540,8 @@ fn cargo_metadata_with_deps_and_version() {
"workspace_members": [
"foo 0.5.0 (path+file:[..]foo)"
],
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -622,7 +626,8 @@ name = "ex"
},
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -708,7 +713,8 @@ crate-type = ["rlib", "dylib"]
},
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -722,6 +728,14 @@ fn workspace_metadata() {
r#"
[workspace]
members = ["bar", "baz"]
[workspace.metadata]
tool1 = "hello"
tool2 = [1, 2, 3]
[workspace.metadata.foo]
bar = 3
"#,
)
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
@@ -822,7 +836,14 @@ fn workspace_metadata() {
},
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": {
"tool1": "hello",
"tool2": [1, 2, 3],
"foo": {
"bar": 3
}
}
}"#,
)
.run();
@@ -920,7 +941,8 @@ fn workspace_metadata_no_deps() {
"resolve": null,
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -979,7 +1001,8 @@ const MANIFEST_OUTPUT: &str = r#"
"resolve": null,
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#;

#[cargo_test]
@@ -1163,7 +1186,8 @@ fn package_metadata() {
"resolve": null,
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -1230,7 +1254,8 @@ fn package_publish() {
"resolve": null,
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
@@ -1315,7 +1340,8 @@ fn cargo_metadata_path_to_cargo_toml_project() {
"workspace_members": [
"bar 0.5.0 (path+file:[..])"
],
"workspace_root": "[..]"
"workspace_root": "[..]",
"metadata": null
}
"#,
)
@@ -1396,7 +1422,8 @@ fn package_edition_2018() {
"workspace_members": [
"foo 0.1.0 (path+file:[..])"
],
"workspace_root": "[..]"
"workspace_root": "[..]",
"metadata": null
}
"#,
)
@@ -1493,7 +1520,8 @@ fn target_edition_2018() {
"workspace_members": [
"foo 0.1.0 (path+file:[..])"
],
"workspace_root": "[..]"
"workspace_root": "[..]",
"metadata": null
}
"#,
)
@@ -1710,7 +1738,8 @@ fn rename_dependency() {
"workspace_members": [
"foo 0.0.1[..]"
],
"workspace_root": "[..]"
"workspace_root": "[..]",
"metadata": null
}"#,
)
.run();
@@ -1801,7 +1830,8 @@ fn metadata_links() {
"workspace_members": [
"foo 0.5.0 [..]"
],
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}
"#,
)
@@ -1896,7 +1926,8 @@ fn deps_with_bin_only() {
},
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]foo"
"workspace_root": "[..]foo",
"metadata": null
}
"#,
)
@@ -2280,7 +2311,8 @@ fn filter_platform() {
},
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}
"#
.replace("$ALT_TRIPLE", alt_target)
@@ -2354,7 +2386,8 @@ fn filter_platform() {
},
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]foo"
"workspace_root": "[..]foo",
"metadata": null
}
"#
.replace("$ALT_TRIPLE", alt_target)
@@ -2425,7 +2458,8 @@ fn filter_platform() {
},
"target_directory": "[..]foo/target",
"version": 1,
"workspace_root": "[..]foo"
"workspace_root": "[..]foo",
"metadata": null
}
"#
.replace("$HOST_TRIPLE", &rustc_host())
@@ -2515,7 +2549,8 @@ fn filter_platform() {
},
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}
"#
.replace("$HOST_TRIPLE", &rustc_host())
@@ -2565,6 +2600,7 @@ fn dep_kinds() {
"target_directory": "{...}",
"version": 1,
"workspace_root": "{...}",
"metadata": null,
"resolve": {
"nodes": [
{
@@ -2679,6 +2715,7 @@ fn dep_kinds_workspace() {
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]/foo",
"metadata": null,
"resolve": {
"nodes": [
{
3 changes: 2 additions & 1 deletion tests/testsuite/update.rs
Original file line number Diff line number Diff line change
@@ -549,7 +549,8 @@ fn update_precise_first_run() {
"workspace_members": [
"bar 0.0.1 (path+file://[..]/foo)"
],
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();