Skip to content

Commit

Permalink
Auto merge of #5715 - euclio:third-party-help, r=alexcrichton
Browse files Browse the repository at this point in the history
help: display external subcommand help

When invoking `cargo help <subcommand>`, if the subcommand isn't found, but it *is* an external subcommand, call that subcommand with `--help`.

A test should probably be written for this, but I'm not sure how best to mock an external subcommand.
  • Loading branch information
bors committed Jul 13, 2018
2 parents 5cddc4b + dca0db2 commit 738c42d
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 6 deletions.
14 changes: 13 additions & 1 deletion src/bin/cargo/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ use super::commands;
use command_prelude::*;

pub fn main(config: &mut Config) -> CliResult {
let args = cli().get_matches_safe()?;
let args = match cli().get_matches_safe() {
Ok(args) => args,
Err(e) => {
if e.kind == clap::ErrorKind::UnrecognizedSubcommand {
// An unrecognized subcommand might be an external subcommand.
let cmd = &e.info.as_ref().unwrap()[0].to_owned();
return super::execute_external_subcommand(config, cmd, &[cmd, "--help"])
.map_err(|_| e.into());
} else {
return Err(e)?;
}
}
};

if args.value_of("unstable-features") == Some("help") {
println!(
Expand Down
21 changes: 16 additions & 5 deletions src/doc/src/reference/external-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,24 @@ the `.d` files alongside the artifacts.
Cargo is designed to be extensible with new subcommands without having to modify
Cargo itself. This is achieved by translating a cargo invocation of the form
cargo `(?<command>[^ ]+)` into an invocation of an external tool
`cargo-${command}` that then needs to be present in one of the user's `$PATH`
directories.
`cargo-${command}`. The external tool must be present in one of the user's
`$PATH` directories.

Custom subcommand may use `CARGO` environment variable to call back to
When Cargo invokes a custom subcommand, the first argument to the subcommand
will be the filename of the custom subcommand, as usual. The second argument
will be the subcommand name itself. For example, the second argument would be
`${command}` when invoking `cargo-${command}`. Any additional arguments on the
command line will be forwarded unchanged.

Cargo can also display the help output of a custom subcommand with `cargo help
${command}`. Cargo assumes that the subcommand will print a help message if its
third argument is `--help`. So, `cargo help ${command}` would invoke
`cargo-${command} ${command} --help`.

Custom subcommands may use the `CARGO` environment variable to call back to
Cargo. Alternatively, it can link to `cargo` crate as a library, but this
approach has drawbacks:

* Cargo as a library is unstable, API changes without deprecation,
* Cargo as a library is unstable: the API may change without deprecation

* versions of Cargo library and Cargo binary may be different.
* versions of the linked Cargo library may be different from the Cargo binary
23 changes: 23 additions & 0 deletions tests/testsuite/cargo_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,29 @@ fn cargo_help() {
);
}

#[test]
fn cargo_help_external_subcommand() {
Package::new("cargo-fake-help", "1.0.0")
.file(
"src/main.rs",
r#"
fn main() {
if ::std::env::args().nth(2) == Some(String::from("--help")) {
println!("fancy help output");
}
}"#,
)
.publish();
assert_that(
cargo_process().args(&["install", "cargo-fake-help"]),
execs().with_status(0),
);
assert_that(
cargo_process().args(&["help", "fake-help"]),
execs().with_status(0).with_stdout("fancy help output\n")
);
}

#[test]
fn explain() {
assert_that(
Expand Down

0 comments on commit 738c42d

Please sign in to comment.