Skip to content

Commit

Permalink
Auto merge of #8323 - naerbnic:add_workspace_metadata_table, r=alexcr…
Browse files Browse the repository at this point in the history
…ichton

Add support for `workspace.metadata` table

Implements feature request #8309

Additionally includes the information in the output of "cargo metadata" through a new top-level field `metadata`, similar to the per-package `metadata` field
  • Loading branch information
bors committed Jun 23, 2020
2 parents 10ae887 + 16f3b8d commit 78c1671
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 50 deletions.
1 change: 1 addition & 0 deletions src/cargo/core/compiler/standard_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
74 changes: 49 additions & 25 deletions src/cargo/core/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -182,6 +189,7 @@ impl<'cfg> Workspace<'cfg> {
loaded_packages: RefCell::new(HashMap::new()),
ignore_lock: false,
resolve_behavior: None,
custom_metadata: None,
}
}

Expand Down Expand Up @@ -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`.
///
Expand Down Expand Up @@ -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());
Expand All @@ -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)?;
Expand Down Expand Up @@ -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(),
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/cargo/ops/cargo_output_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
})
}

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

#[derive(Serialize)]
Expand Down
3 changes: 3 additions & 0 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
}

Expand Down Expand Up @@ -1230,6 +1231,7 @@ impl TomlManifest {
&config.members,
&config.default_members,
&config.exclude,
&config.metadata,
)),
(None, root) => WorkspaceConfig::Member {
root: root.cloned(),
Expand Down Expand Up @@ -1414,6 +1416,7 @@ impl TomlManifest {
&config.members,
&config.default_members,
&config.exclude,
&config.metadata,
)),
None => {
bail!("virtual manifests must be configured with [workspace]");
Expand Down
9 changes: 9 additions & 0 deletions src/doc/man/cargo-metadata.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
}
----

Expand Down
9 changes: 9 additions & 0 deletions src/doc/src/reference/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,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
Expand Down
24 changes: 24 additions & 0 deletions src/doc/src/reference/workspaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions tests/testsuite/alt_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -1003,7 +1004,8 @@ fn alt_reg_metadata() {
"resolve": "{...}",
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}"#,
)
.run();
Expand Down Expand Up @@ -1152,7 +1154,8 @@ fn unknown_registry() {
"resolve": "{...}",
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]/foo"
"workspace_root": "[..]/foo",
"metadata": null
}
"#,
)
Expand Down
37 changes: 37 additions & 0 deletions tests/testsuite/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3310,6 +3310,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()
Expand Down
Loading

0 comments on commit 78c1671

Please sign in to comment.