From 0470d775755367f7784291ce938eb1e8859602f2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 8 Mar 2018 23:19:27 +0300 Subject: [PATCH] Support list subcommand All tests are green :tada: --- src/bin/cli/mod.rs | 127 +++++++++++++++++++++++-------- tests/testsuite/cargo_command.rs | 18 ++--- tests/testsuite/install.rs | 2 - 3 files changed, 104 insertions(+), 43 deletions(-) diff --git a/src/bin/cli/mod.rs b/src/bin/cli/mod.rs index 0c410e978..bd1585358 100644 --- a/src/bin/cli/mod.rs +++ b/src/bin/cli/mod.rs @@ -22,13 +22,19 @@ use cargo::ops::{self, MessageFormat, Packages, CompileOptions, CompileMode, Ver use cargo::sources::{GitSource, RegistrySource}; use self::utils::*; +use std::collections::BTreeSet; +use std::env; +use std::fs; +use search_directories; +use is_executable; pub fn do_main(config: &mut Config) -> CliResult { let args = cli().get_matches(); + let is_verbose = args.occurrences_of("verbose") > 0; if args.is_present("version") { let version = cargo::version(); println!("{}", version); - if args.occurrences_of("verbose") > 0 { + if is_verbose { println!("release: {}.{}.{}", version.major, version.minor, @@ -43,6 +49,22 @@ pub fn do_main(config: &mut Config) -> CliResult { return Ok(()); } + if args.is_present("list") { + println!("Installed Commands:"); + for command in list_commands(config) { + let (command, path) = command; + if is_verbose { + match path { + Some(p) => println!(" {:<20} {}", command, p), + None => println!(" {:<20}", command), + } + } else { + println!(" {}", command); + } + } + return Ok(()); + } + execte_subcommand(config, args) } @@ -595,41 +617,82 @@ Some common cargo commands are (see all commands with --list): See 'cargo help ' for more information on a specific command. ") - .subcommands(vec![ - bench::cli(), - build::cli(), - check::cli(), - clean::cli(), - doc::cli(), - fetch::cli(), - generate_lockfile::cli(), - git_checkout::cli(), - init::cli(), - install::cli(), - locate_project::cli(), - login::cli(), - metadata::cli(), - new::cli(), - owner::cli(), - package::cli(), - pkgid::cli(), - publish::cli(), - read_manifest::cli(), - run::cli(), - rustc::cli(), - rustdoc::cli(), - search::cli(), - test::cli(), - uninstall::cli(), - update::cli(), - verify_project::cli(), - version::cli(), - yank::cli(), - ]) + .subcommands(builtin_subcommands()) ; app } +fn builtin_subcommands() -> Vec { + vec![ + bench::cli(), + build::cli(), + check::cli(), + clean::cli(), + doc::cli(), + fetch::cli(), + generate_lockfile::cli(), + git_checkout::cli(), + init::cli(), + install::cli(), + locate_project::cli(), + login::cli(), + metadata::cli(), + new::cli(), + owner::cli(), + package::cli(), + pkgid::cli(), + publish::cli(), + read_manifest::cli(), + run::cli(), + rustc::cli(), + rustdoc::cli(), + search::cli(), + test::cli(), + uninstall::cli(), + update::cli(), + verify_project::cli(), + version::cli(), + yank::cli(), + ] +} + +/// List all runnable commands +fn list_commands(config: &Config) -> BTreeSet<(String, Option)> { + let prefix = "cargo-"; + let suffix = env::consts::EXE_SUFFIX; + let mut commands = BTreeSet::new(); + for dir in search_directories(config) { + let entries = match fs::read_dir(dir) { + Ok(entries) => entries, + _ => continue, + }; + for entry in entries.filter_map(|e| e.ok()) { + let path = entry.path(); + let filename = match path.file_name().and_then(|s| s.to_str()) { + Some(filename) => filename, + _ => continue, + }; + if !filename.starts_with(prefix) || !filename.ends_with(suffix) { + continue; + } + if is_executable(entry.path()) { + let end = filename.len() - suffix.len(); + commands.insert( + (filename[prefix.len()..end].to_string(), + Some(path.display().to_string())) + ); + } + } + } + + for cmd in builtin_subcommands() { + commands.insert((cmd.get_name().to_string(), None)); + } + + commands +} + + mod bench; mod build; mod check; diff --git a/tests/testsuite/cargo_command.rs b/tests/testsuite/cargo_command.rs index b211d2699..598f5a717 100644 --- a/tests/testsuite/cargo_command.rs +++ b/tests/testsuite/cargo_command.rs @@ -59,7 +59,6 @@ fn path() -> Vec { } #[test] -#[ignore] fn list_command_looks_at_path() { let proj = project("list-non-overlapping").build(); let proj = fake_file(proj, Path::new("path-test"), "cargo-1", &FakeKind::Executable); @@ -78,7 +77,6 @@ fn list_command_looks_at_path() { // windows and symlinks don't currently agree that well #[cfg(unix)] #[test] -#[ignore] fn list_command_resolves_symlinks() { use cargotest::support::cargo_exe; @@ -98,23 +96,26 @@ fn list_command_resolves_symlinks() { } #[test] -#[ignore] fn find_closest_biuld_to_build() { let mut pr = cargo_process(); pr.arg("biuld"); assert_that(pr, - execs().with_status(101) - .with_stderr("[ERROR] no such subcommand: `biuld` + execs().with_status(1) + .with_stderr("\ +error: The subcommand 'biuld' wasn't recognized +Did you mean 'build'? -Did you mean `build`? +If you believe you received this message in error, try re-running with 'cargo -- biuld' -")); +USAGE: + cargo [OPTIONS] [SUBCOMMAND] + +For more information try --help")); } // if a subcommand is more than 3 edit distance away, we don't make a suggestion #[test] -#[ignore] fn find_closest_dont_correct_nonsense() { let mut pr = cargo_process(); pr.arg("there-is-no-way-that-there-is-a-command-close-to-this") @@ -128,7 +129,6 @@ fn find_closest_dont_correct_nonsense() { } #[test] -#[ignore] fn displays_subcommand_on_error() { let mut pr = cargo_process(); pr.arg("invalid-command"); diff --git a/tests/testsuite/install.rs b/tests/testsuite/install.rs index f95c36a05..f7272b1cb 100644 --- a/tests/testsuite/install.rs +++ b/tests/testsuite/install.rs @@ -726,7 +726,6 @@ fn uninstall_piecemeal() { } #[test] -#[ignore] fn subcommand_works_out_of_the_box() { Package::new("cargo-foo", "1.0.0") .file("src/main.rs", r#" @@ -787,7 +786,6 @@ warning: be sure to add `[..]` to your PATH to be able to run the installed bina } #[test] -#[ignore] fn reports_unsuccessful_subcommand_result() { Package::new("cargo-fail", "1.0.0") .file("src/main.rs", r#" -- 2.30.2