diff --git a/src/bin/cargo/commands/locate_project.rs b/src/bin/cargo/commands/locate_project.rs index 4e29c9524b1..e0cfaaf054f 100644 --- a/src/bin/cargo/commands/locate_project.rs +++ b/src/bin/cargo/commands/locate_project.rs @@ -15,6 +15,7 @@ pub fn cli() -> App { ) .value_name("FMT"), ) + .arg(opt("workspace", "Locate Cargo.toml of the workspace root")) .after_help("Run `cargo help locate-project` for more detailed information.\n") } @@ -24,7 +25,18 @@ pub struct ProjectLocation<'a> { } pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { - let root = args.root_manifest(config)?; + let root_manifest; + let workspace; + let root = match WhatToFind::parse(args) { + WhatToFind::CurrentManifest => { + root_manifest = args.root_manifest(config)?; + &root_manifest + } + WhatToFind::Workspace => { + workspace = args.workspace(config)?; + workspace.root_manifest() + } + }; let root = root .to_str() @@ -46,6 +58,21 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { Ok(()) } +enum WhatToFind { + CurrentManifest, + Workspace, +} + +impl WhatToFind { + fn parse(args: &ArgMatches<'_>) -> Self { + if args.is_present("workspace") { + WhatToFind::Workspace + } else { + WhatToFind::CurrentManifest + } + } +} + enum MessageFormat { Json, Plain, diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index a8f95fcddeb..b53329015d3 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -315,21 +315,20 @@ impl<'cfg> Workspace<'cfg> { /// That is, this returns the path of the directory containing the /// `Cargo.toml` which is the root of this workspace. pub fn root(&self) -> &Path { - match self.root_manifest { - Some(ref p) => p, - None => &self.current_manifest, - } - .parent() - .unwrap() + self.root_manifest().parent().unwrap() + } + + /// Returns the path of the `Cargo.toml` which is the root of this + /// workspace. + pub fn root_manifest(&self) -> &Path { + self.root_manifest + .as_ref() + .unwrap_or(&self.current_manifest) } /// Returns the root Package or VirtualManifest. fn root_maybe(&self) -> &MaybePackage { - let root = self - .root_manifest - .as_ref() - .unwrap_or(&self.current_manifest); - self.packages.get(root) + self.packages.get(self.root_manifest()) } pub fn target_dir(&self) -> Filesystem { diff --git a/src/doc/man/cargo-locate-project.md b/src/doc/man/cargo-locate-project.md index f5f88af6c7b..89ff79abd77 100644 --- a/src/doc/man/cargo-locate-project.md +++ b/src/doc/man/cargo-locate-project.md @@ -13,11 +13,17 @@ cargo-locate-project - Print a JSON representation of a Cargo.toml file's locati This command will print a JSON object to stdout with the full path to the `Cargo.toml` manifest. -See also {{man "cargo-metadata" 1}} which is capable of returning the path to a -workspace root. - ## OPTIONS +{{#options}} + +{{#option "`--workspace`" }} +Locate the `Cargo.toml` at the root of the workspace, as opposed to the current +workspace member. +{{/option}} + +{{/options}} + ### Display Options {{#options}} diff --git a/src/doc/man/generated_txt/cargo-locate-project.txt b/src/doc/man/generated_txt/cargo-locate-project.txt index 7afd01ddf78..6d4ed21a68d 100644 --- a/src/doc/man/generated_txt/cargo-locate-project.txt +++ b/src/doc/man/generated_txt/cargo-locate-project.txt @@ -11,10 +11,11 @@ DESCRIPTION This command will print a JSON object to stdout with the full path to the Cargo.toml manifest. - See also cargo-metadata(1) which is capable of returning the path to a - workspace root. - OPTIONS + --workspace + Locate the Cargo.toml at the root of the workspace, as opposed to + the current workspace member. + Display Options --message-format fmt The representation in which to print the project location. Valid diff --git a/src/doc/src/commands/cargo-locate-project.md b/src/doc/src/commands/cargo-locate-project.md index 8dde35015ba..6751b5b3e76 100644 --- a/src/doc/src/commands/cargo-locate-project.md +++ b/src/doc/src/commands/cargo-locate-project.md @@ -13,11 +13,17 @@ cargo-locate-project - Print a JSON representation of a Cargo.toml file's locati This command will print a JSON object to stdout with the full path to the `Cargo.toml` manifest. -See also [cargo-metadata(1)](cargo-metadata.md) which is capable of returning the path to a -workspace root. - ## OPTIONS +
+ +
--workspace
+
Locate the Cargo.toml at the root of the workspace, as opposed to the current +workspace member.
+ + +
+ ### Display Options
diff --git a/src/etc/_cargo b/src/etc/_cargo index 28c8b081c2f..ab150546bb0 100644 --- a/src/etc/_cargo +++ b/src/etc/_cargo @@ -162,6 +162,7 @@ _cargo() { locate-project) _arguments -s -S $common $manifest \ '--message-format=[specify output representation]:output representation [json]:(json plain)' + '--workspace[locate Cargo.toml of the workspace root]' ;; login) diff --git a/src/etc/cargo.bashcomp.sh b/src/etc/cargo.bashcomp.sh index 8a3334c4811..5859d33be5c 100644 --- a/src/etc/cargo.bashcomp.sh +++ b/src/etc/cargo.bashcomp.sh @@ -59,7 +59,7 @@ _cargo() local opt__help="$opt_help" local opt__init="$opt_common $opt_lock --bin --lib --name --vcs --edition --registry" local opt__install="$opt_common $opt_feat $opt_jobs $opt_lock $opt_force --bin --bins --branch --debug --example --examples --git --list --path --rev --root --tag --version --registry --target --profile --no-track" - local opt__locate_project="$opt_common $opt_mani $opt_lock --message-format" + local opt__locate_project="$opt_common $opt_mani $opt_lock --message-format --workspace" local opt__login="$opt_common $opt_lock --registry" local opt__metadata="$opt_common $opt_feat $opt_mani $opt_lock --format-version=1 --no-deps --filter-platform" local opt__new="$opt_common $opt_lock --vcs --bin --lib --name --edition --registry" diff --git a/src/etc/man/cargo-locate-project.1 b/src/etc/man/cargo-locate-project.1 index 86fa9ebb36b..cef4e16141f 100644 --- a/src/etc/man/cargo-locate-project.1 +++ b/src/etc/man/cargo-locate-project.1 @@ -10,10 +10,13 @@ cargo\-locate\-project \- Print a JSON representation of a Cargo.toml file's loc .SH "DESCRIPTION" This command will print a JSON object to stdout with the full path to the \fBCargo.toml\fR manifest. -.sp -See also \fBcargo\-metadata\fR(1) which is capable of returning the path to a -workspace root. .SH "OPTIONS" +.sp +\fB\-\-workspace\fR +.RS 4 +Locate the \fBCargo.toml\fR at the root of the workspace, as opposed to the current +workspace member. +.RE .SS "Display Options" .sp \fB\-\-message\-format\fR \fIfmt\fR diff --git a/tests/testsuite/locate_project.rs b/tests/testsuite/locate_project.rs index 5ff3677e844..adff37516cd 100644 --- a/tests/testsuite/locate_project.rs +++ b/tests/testsuite/locate_project.rs @@ -34,3 +34,55 @@ fn message_format() { .with_status(101) .run(); } + +#[cargo_test] +fn workspace() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "outer" + version = "0.0.0" + + [workspace] + members = ["inner"] + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "inner/Cargo.toml", + r#" + [package] + name = "inner" + version = "0.0.0" + "#, + ) + .file("inner/src/lib.rs", "") + .build(); + + let outer_manifest = format!( + r#"{{"root":"{}"}}"#, + p.root().join("Cargo.toml").to_str().unwrap(), + ); + let inner_manifest = format!( + r#"{{"root":"{}"}}"#, + p.root().join("inner").join("Cargo.toml").to_str().unwrap(), + ); + + p.cargo("locate-project").with_stdout(&outer_manifest).run(); + + p.cargo("locate-project") + .cwd("inner") + .with_stdout(&inner_manifest) + .run(); + + p.cargo("locate-project --workspace") + .with_stdout(&outer_manifest) + .run(); + + p.cargo("locate-project --workspace") + .cwd("inner") + .with_stdout(&outer_manifest) + .run(); +}