Skip to content
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

Add support for workspace.metadata table #8323

Merged
merged 7 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
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
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 @@ -1229,6 +1230,7 @@ impl TomlManifest {
&config.members,
&config.default_members,
&config.exclude,
&config.metadata,
)),
(None, root) => WorkspaceConfig::Member {
root: root.cloned(),
Expand Down Expand Up @@ -1413,6 +1415,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 @@ -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
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"]
# ...
```

naerbnic marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -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()
Expand Down
Loading