Skip to content

Commit

Permalink
Deduplicate entries in cargo --list
Browse files Browse the repository at this point in the history
Fixes #6088
  • Loading branch information
nipunn1313 committed Aug 9, 2021
1 parent 0a2581d commit 0ab79d7
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 42 deletions.
8 changes: 4 additions & 4 deletions src/bin/cargo/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,21 @@ Run with 'cargo -Z [FLAG] [SUBCOMMAND]'",

if args.is_present("list") {
drop_println!(config, "Installed Commands:");
for command in list_commands(config) {
for (name, command) in list_commands(config) {
match command {
CommandInfo::BuiltIn { name, about } => {
CommandInfo::BuiltIn { about } => {
let summary = about.unwrap_or_default();
let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
drop_println!(config, " {:<20} {}", name, summary);
}
CommandInfo::External { name, path } => {
CommandInfo::External { path } => {
if is_verbose {
drop_println!(config, " {:<20} {}", name, path.display());
} else {
drop_println!(config, " {}", name);
}
}
CommandInfo::Alias { name, target } => {
CommandInfo::Alias { target } => {
drop_println!(config, " {:<20} {}", name, target.iter().join(" "));
}
}
Expand Down
53 changes: 28 additions & 25 deletions src/bin/cargo/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use cargo::util::toml::StringOrVec;
use cargo::util::CliError;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
use cargo_util::{ProcessBuilder, ProcessError};
use std::collections::{BTreeMap, BTreeSet};
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -84,10 +84,10 @@ fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<Str
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<CommandInfo> {
fn list_commands(config: &Config) -> BTreeMap<String, CommandInfo> {
let prefix = "cargo-";
let suffix = env::consts::EXE_SUFFIX;
let mut commands = BTreeSet::new();
let mut commands = BTreeMap::new();
for dir in search_directories(config) {
let entries = match fs::read_dir(dir) {
Ok(entries) => entries,
Expand All @@ -104,37 +104,43 @@ fn list_commands(config: &Config) -> BTreeSet<CommandInfo> {
}
if is_executable(entry.path()) {
let end = filename.len() - suffix.len();
commands.insert(CommandInfo::External {
name: filename[prefix.len()..end].to_string(),
path: path.clone(),
});
commands.insert(
filename[prefix.len()..end].to_string(),
CommandInfo::External { path: path.clone() },
);
}
}
}

for cmd in commands::builtin() {
commands.insert(CommandInfo::BuiltIn {
name: cmd.get_name().to_string(),
about: cmd.p.meta.about.map(|s| s.to_string()),
});
commands.insert(
cmd.get_name().to_string(),
CommandInfo::BuiltIn {
about: cmd.p.meta.about.map(|s| s.to_string()),
},
);
}

// Add the builtin_aliases and them descriptions to the
// `commands` `BTreeSet`.
// `commands` `BTreeMap`.
for command in &BUILTIN_ALIASES {
commands.insert(CommandInfo::BuiltIn {
name: command.0.to_string(),
about: Some(command.2.to_string()),
});
commands.insert(
command.0.to_string(),
CommandInfo::BuiltIn {
about: Some(command.2.to_string()),
},
);
}

// Add the user-defined aliases
if let Ok(aliases) = config.get::<BTreeMap<String, StringOrVec>>("alias") {
for (name, target) in aliases.iter() {
commands.insert(CommandInfo::Alias {
name: name.to_string(),
target: target.clone(),
});
commands.insert(
name.to_string(),
CommandInfo::Alias {
target: target.clone(),
},
);
}
}

Expand All @@ -150,11 +156,8 @@ fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> Cli
let command = match path {
Some(command) => command,
None => {
let suggestions: Vec<_> = list_commands(config)
.iter()
.map(|c| c.name().to_string())
.collect();
let did_you_mean = closest_msg(cmd, suggestions.iter(), |c| c);
let suggestions = list_commands(config);
let did_you_mean = closest_msg(cmd, suggestions.keys(), |c| c);
let err = anyhow::format_err!("no such subcommand: `{}`{}", cmd, did_you_mean);
return Err(CliError::new(err, 101));
}
Expand Down
16 changes: 3 additions & 13 deletions src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,17 +718,7 @@ pub fn values_os(args: &ArgMatches<'_>, name: &str) -> Vec<OsString> {

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum CommandInfo {
BuiltIn { name: String, about: Option<String> },
External { name: String, path: PathBuf },
Alias { name: String, target: StringOrVec },
}

impl CommandInfo {
pub fn name(&self) -> &str {
match self {
CommandInfo::BuiltIn { name, .. } => name,
CommandInfo::External { name, .. } => name,
CommandInfo::Alias { name, .. } => name,
}
}
BuiltIn { about: Option<String> },
External { path: PathBuf },
Alias { target: StringOrVec },
}
18 changes: 18 additions & 0 deletions tests/testsuite/cargo_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ fn list_custom_aliases_with_descriptions() {
.run();
}

#[cargo_test]
fn list_dedupe() {
let p = project()
.executable(Path::new("path-test-1").join("cargo-dupe"), "")
.executable(Path::new("path-test-2").join("cargo-dupe"), "")
.build();

let mut path = path();
path.push(p.root().join("path-test-1"));
path.push(p.root().join("path-test-2"));
let path = env::join_paths(path.iter()).unwrap();

p.cargo("--list")
.env("PATH", &path)
.with_stdout_contains_n(" dupe", 1)
.run();
}

#[cargo_test]
fn list_command_looks_at_path() {
let proj = project()
Expand Down

0 comments on commit 0ab79d7

Please sign in to comment.