diff --git a/src/rustup-cli/common.rs b/src/rustup-cli/common.rs index 0b167ccef4..c976eb54da 100644 --- a/src/rustup-cli/common.rs +++ b/src/rustup-cli/common.rs @@ -320,9 +320,25 @@ pub fn list_targets(toolchain: &Toolchain) -> Result<()> { Ok(()) } -pub fn list_components(toolchain: &Toolchain) -> Result<()> { +pub enum ComponentFilter { + Required, + Available, + Installed, + None, +} + +pub fn list_components(toolchain: &Toolchain, filter: &ComponentFilter) -> Result<()> { let mut t = term2::stdout(); - for component in toolchain.list_components()? { + let components = toolchain + .list_components()? + .into_iter() + .filter(|c| match filter { + ComponentFilter::Required => c.required, + ComponentFilter::Available => c.available && !c.installed, + ComponentFilter::Installed => c.installed, + ComponentFilter::None => c.required || c.available || c.installed, + }); + for component in components { let name = component.name; if component.required { let _ = t.attr(term2::Attr::Bold); diff --git a/src/rustup-cli/help.rs b/src/rustup-cli/help.rs index 0a781d2514..0877599bb1 100644 --- a/src/rustup-cli/help.rs +++ b/src/rustup-cli/help.rs @@ -254,3 +254,6 @@ r"DISCUSSION: pub static TOOLCHAIN_ARG_HELP: &'static str = "Toolchain name, such as 'stable', 'nightly', \ or '1.8.0'. For more information see `rustup \ help toolchain`"; + +pub static FILTER_ARG_HELP: &'static str = + "Component status: 'required', 'available', or 'installed'"; diff --git a/src/rustup-cli/rustup_mode.rs b/src/rustup-cli/rustup_mode.rs index afdfca8740..35362d9d22 100644 --- a/src/rustup-cli/rustup_mode.rs +++ b/src/rustup-cli/rustup_mode.rs @@ -296,6 +296,12 @@ pub fn cli() -> App<'static, 'static> { .help(TOOLCHAIN_ARG_HELP) .long("toolchain") .takes_value(true), + ) + .arg( + Arg::with_name("filter") + .help(FILTER_ARG_HELP) + .long("filter") + .takes_value(true), ), ) .subcommand( @@ -825,7 +831,13 @@ fn target_remove(cfg: &Cfg, m: &ArgMatches) -> Result<()> { fn component_list(cfg: &Cfg, m: &ArgMatches) -> Result<()> { let toolchain = explicit_or_dir_toolchain(cfg, m)?; - common::list_components(&toolchain) + let filter = match m.value_of("filter") { + Some("required") => common::ComponentFilter::Required, + Some("available") => common::ComponentFilter::Available, + Some("installed") => common::ComponentFilter::Installed, + _ => common::ComponentFilter::None, + }; + common::list_components(&toolchain, &filter) } fn component_add(cfg: &Cfg, m: &ArgMatches) -> Result<()> { diff --git a/tests/cli-rustup.rs b/tests/cli-rustup.rs index 8a4aafd762..bb65f7885c 100644 --- a/tests/cli-rustup.rs +++ b/tests/cli-rustup.rs @@ -1093,6 +1093,80 @@ fn add_remove_multiple_components() { }); } +#[test] +fn list_components_filter() { + setup(&|config| { + expect_err( + config, + &["rustup", "component", "list", "--filter", "required"], + "error: no default toolchain configured", + ); + expect_ok(config, &["rustup", "default", "nightly"]); + expect_ok_ex( + config, + &["rustup", "component", "list", "--filter", "required"], + for_host!( + r"cargo-{0} (default) +rust-docs-{0} (default) +rust-std-{0} (default) +rustc-{0} (default) +" + ), + "", + ); + expect_ok( + config, + &["rustup", "component", "list", "--filter", "available"], + ); + expect_ok_ex( + config, + &["rustup", "component", "list", "--filter", "installed"], + for_host!( + "cargo-{0} (default) +rust-docs-{0} (default) +rust-std-{0} (default) +rustc-{0} (default) +" + ), + "", + ); + expect_ok(config, &["rustup", "component", "add", "rls"]); + expect_ok_ex( + config, + &["rustup", "component", "list", "--filter", "installed"], + for_host!( + "cargo-{0} (default) +rls-{0} (installed) +rust-docs-{0} (default) +rust-std-{0} (default) +rustc-{0} (default) +" + ), + "", + ); + expect_err( + config, + &["rustup", "component", "list", "--filter"], + "error: The argument '--filter ' requires a value but none was supplied", + ); + + // Don't show installed/default components in available filter + let mut cmd = clitools::cmd( + config, + "rustup", + &["component", "list", "--filter", "available"], + ); + clitools::env(config, &mut cmd); + let out = cmd.output().unwrap(); + assert!(!String::from_utf8(out.stdout.clone()) + .unwrap() + .contains("(installed)")); + assert!(!String::from_utf8(out.stdout.clone()) + .unwrap() + .contains("(default)")); + }); +} + // Run without setting RUSTUP_HOME, with setting HOME and USERPROFILE fn run_no_home(config: &Config, args: &[&str], env: &[(&str, &str)]) -> process::Output { let home_dir_str = &format!("{}", config.homedir.display());