blob: d38d70c0f1382eae51b5e528421a9fb6447717fe [file] [log] [blame] [edit]
use crate::command_prelude::*;
use anyhow::bail;
use cargo::{drop_println, CargoResult};
use serde::Serialize;
pub fn cli() -> Command {
subcommand("locate-project")
.about("Print a JSON representation of a Cargo.toml file's location")
.arg(flag("workspace", "Locate Cargo.toml of the workspace root"))
.arg(
opt(
"message-format",
"Output representation [possible values: json, plain]",
)
.value_name("FMT"),
)
.arg_silent_suggestion()
.arg_manifest_path()
.after_help(color_print::cstr!(
"Run `<cyan,bold>cargo help locate-project</>` for more detailed information.\n"
))
}
#[derive(Serialize)]
pub struct ProjectLocation<'a> {
root: &'a str,
}
pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let root_manifest;
let workspace;
let root = match WhatToFind::parse(args) {
WhatToFind::CurrentManifest => {
root_manifest = args.root_manifest(gctx)?;
&root_manifest
}
WhatToFind::Workspace => {
workspace = args.workspace(gctx)?;
workspace.root_manifest()
}
};
let root = root
.to_str()
.ok_or_else(|| {
anyhow::format_err!(
"your package path contains characters \
not representable in Unicode"
)
})
.map_err(|e| CliError::new(e, 1))?;
let location = ProjectLocation { root };
match MessageFormat::parse(args)? {
MessageFormat::Json => gctx.shell().print_json(&location)?,
MessageFormat::Plain => drop_println!(gctx, "{}", location.root),
}
Ok(())
}
enum WhatToFind {
CurrentManifest,
Workspace,
}
impl WhatToFind {
fn parse(args: &ArgMatches) -> Self {
if args.flag("workspace") {
WhatToFind::Workspace
} else {
WhatToFind::CurrentManifest
}
}
}
enum MessageFormat {
Json,
Plain,
}
impl MessageFormat {
fn parse(args: &ArgMatches) -> CargoResult<Self> {
let fmt = match args.get_one::<String>("message-format") {
Some(fmt) => fmt,
None => return Ok(MessageFormat::Json),
};
match fmt.to_ascii_lowercase().as_str() {
"json" => Ok(MessageFormat::Json),
"plain" => Ok(MessageFormat::Plain),
s => bail!("invalid message format specifier: `{}`", s),
}
}
}