Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand rustup show #406

Merged
merged 3 commits into from
May 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/rustup-cli/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {
Ok(())
}

fn rustc_version(toolchain: &Toolchain) -> String {
pub fn rustc_version(toolchain: &Toolchain) -> String {
if toolchain.exists() {
let rustc_path = toolchain.binary_file("rustc");
if utils::is_file(&rustc_path) {
Expand Down Expand Up @@ -293,9 +293,7 @@ pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
let mut toolchains = try!(cfg.list_toolchains());

toolchains.sort();
let toolchains = try!(cfg.list_toolchains());

if toolchains.is_empty() {
println!("no installed toolchains");
Expand Down
84 changes: 75 additions & 9 deletions src/rustup-cli/rustup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use rustup_dist::dist::TargetTriple;
use rustup_utils::utils;
use self_update;
use std::path::Path;
use std::iter;
use term2;
use std::io::Write;

pub fn main() -> Result<()> {
try!(::self_update::cleanup_self_updater());
Expand Down Expand Up @@ -276,19 +279,82 @@ fn which(cfg: &Cfg, m: &ArgMatches) -> Result<()> {

fn show(cfg: &Cfg) -> Result<()> {
let ref cwd = try!(utils::current_dir());
let override_ = try!(cfg.find_override(cwd));
if let Some((toolchain, reason)) = override_ {
println!("{} ({})", toolchain.name(), reason);
return Ok(());
let installed_toolchains = try!(cfg.list_toolchains());
let active_toolchain = try!(cfg.find_override_toolchain_or_default(cwd));
let active_targets = if let Some((ref t, _)) = active_toolchain {
try!(t.list_components())
.into_iter()
.filter(|c| c.component.pkg == "rust-std")
.filter(|c| c.installed)
.collect()
} else {
vec![]
};

let show_installed_toolchains = installed_toolchains.len() > 1;
let show_active_targets = active_targets.len() > 1;
let show_active_toolchain = true;

// Only need to display headers if we have multiple sections
let show_headers = [
show_installed_toolchains,
show_active_targets,
show_active_toolchain
].iter().filter(|x| **x).count() > 1;

if show_installed_toolchains {
if show_headers { print_header("installed toolchains") }
let default = try!(cfg.find_default());
let default_name = default.map(|t| t.name().to_string())
.unwrap_or("".into());
for t in installed_toolchains {
if default_name == t {
println!("{} (default)", t);
} else {
println!("{}", t);
}
}
if show_headers { println!("") };
}

let toolchain = try!(cfg.find_default());
if let Some(toolchain) = toolchain {
println!("{} (default toolchain)", toolchain.name());
return Ok(());
if show_active_targets {
if show_headers {
print_header("installed targets for active toolchain");
}
for t in active_targets {
println!("{}", t.component.target);
}
if show_headers { println!("") };
}

println!("no active toolchain");
if show_active_toolchain {
if show_headers { print_header("active toolchain") }

match active_toolchain {
Some((ref toolchain, Some(ref reason))) => {
println!("{} ({})", toolchain.name(), reason);
println!("{}", common::rustc_version(toolchain));
}
Some((ref toolchain, None)) => {
println!("{} (default)", toolchain.name());
println!("{}", common::rustc_version(toolchain));
}
None => {
println!("no active toolchain");
}
}

if show_headers { println!("") };
}

fn print_header(s: &str) {
let mut t = term2::stdout();
let _ = t.attr(term2::Attr::Bold);
let _ = writeln!(t, "{}", s);
let _ = writeln!(t, "{}", iter::repeat("-").take(s.len()).collect::<String>());
let _ = writeln!(t, "");
let _ = t.reset();
}

Ok(())
}
Expand Down
23 changes: 23 additions & 0 deletions src/rustup-utils/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use raw;
use winapi::DWORD;
#[cfg(windows)]
use winreg;
use std::cmp::Ord;

pub use raw::{is_directory, is_file, path_exists, if_not_empty, random_string, prefix_arg,
has_cmd, find_cmd};
Expand Down Expand Up @@ -489,3 +490,25 @@ pub fn string_from_winreg_value(val: &winreg::RegValue) -> Option<String> {
_ => None
}
}

pub fn toolchain_sort<T: AsRef<str>>(v: &mut Vec<T>) {
fn toolchain_sort_key(s: &str) -> String {
if s.starts_with("stable") {
format!("0{}", s)
} else if s.starts_with("beta") {
format!("1{}", s)
} else if s.starts_with("nightly") {
format!("2{}", s)
} else {
format!("3{}", s)
}
}

v.sort_by(|a, b| {
let a_str: &str = a.as_ref();
let b_str: &str = b.as_ref();
let a_key = toolchain_sort_key(a_str);
let b_key = toolchain_sort_key(b_str);
a_key.cmp(&b_key)
});
}
37 changes: 4 additions & 33 deletions src/rustup/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,13 @@ impl Cfg {

pub fn list_toolchains(&self) -> Result<Vec<String>> {
if utils::is_directory(&self.toolchains_dir) {
let toolchains: Vec<_> = try!(utils::read_dir("toolchains", &self.toolchains_dir))
let mut toolchains: Vec<_> = try!(utils::read_dir("toolchains", &self.toolchains_dir))
.filter_map(io::Result::ok)
.filter_map(|e| e.file_name().into_string().ok())
.collect();

utils::toolchain_sort(&mut toolchains);

Ok(toolchains)
} else {
Ok(Vec::new())
Expand All @@ -275,39 +277,8 @@ impl Cfg {
pub fn update_all_channels(&self) -> Result<Vec<(String, Result<UpdateStatus>)>> {
let toolchains = try!(self.list_toolchains());

let mut toolchains: Vec<(dist::ToolchainDesc, String)> = toolchains.into_iter()
.filter_map(|name| {
let desc = dist::ToolchainDesc::from_str(&name);
let tracked = desc.into_iter().filter(|d| d.is_tracking()).next();
tracked.map(|d| (d, name))
}).collect();

fn channel_sort_key(s: &str) -> String {
if s == "stable" {
String::from("0")
} else if s == "beta" {
String::from("1")
} else if s == "nightly" {
String::from("2")
} else {
format!("3{}", s)
}
}

toolchains.sort_by(|&(ref a, _), &(ref b, _)| {
let a = format!("{}-{}-{}",
channel_sort_key(&a.channel),
a.date.as_ref().map(String::as_str).unwrap_or(""),
a.target);
let b = format!("{}-{}-{}",
channel_sort_key(&b.channel),
b.date.as_ref().map(String::as_str).unwrap_or(""),
b.target);
a.cmp(&b)
});

let updates = toolchains.into_iter()
.map(|(_, name)| {
.map(|name| {
let result = self.get_toolchain(&name, true)
.and_then(|t| t.install_from_dist());
if let Err(ref e) = result {
Expand Down
100 changes: 95 additions & 5 deletions tests/cli-rustup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,97 @@ fn show_toolchain_default() {
setup(&|config| {
expect_ok(config, &["rustup", "default", "nightly"]);
expect_ok_ex(config, &["rustup", "show"],
for_host!(r"nightly-{0} (default toolchain)
for_host!(r"nightly-{0} (default)
1.3.0 (hash-n-2)
"),
r"");
});
}

#[test]
fn show_multiple_toolchains() {
setup(&|config| {
expect_ok(config, &["rustup", "default", "nightly"]);
expect_ok(config, &["rustup", "update", "stable"]);
expect_ok_ex(config, &["rustup", "show"],
for_host!(r"installed toolchains
--------------------

stable-{0}
nightly-{0} (default)

active toolchain
----------------

nightly-{0} (default)
1.3.0 (hash-n-2)

"),
r"");
});
}

#[test]
fn show_multiple_targets() {
// Using the MULTI_ARCH1 target doesn't work on i686 linux
if cfg!(target_os = "linux") && cfg!(target_arch = "x86") { return }

clitools::setup(Scenario::MultiHost, &|config| {
expect_ok(config, &["rustup", "default",
&format!("nightly-{}", clitools::MULTI_ARCH1)]);
expect_ok(config, &["rustup", "target", "add", clitools::CROSS_ARCH2]);
expect_ok_ex(config, &["rustup", "show"],
&format!(r"installed targets for active toolchain
--------------------------------------

{1}
{0}

active toolchain
----------------

nightly-{0} (default)
1.3.0 (xxxx-n-2)

", clitools::MULTI_ARCH1, clitools::CROSS_ARCH2),
r"");
});
}

#[test]
fn show_multiple_toolchains_and_targets() {
if cfg!(target_os = "linux") && cfg!(target_arch = "x86") { return }

clitools::setup(Scenario::MultiHost, &|config| {
expect_ok(config, &["rustup", "default",
&format!("nightly-{}", clitools::MULTI_ARCH1)]);
expect_ok(config, &["rustup", "target", "add", clitools::CROSS_ARCH2]);
expect_ok(config, &["rustup", "update",
&format!("stable-{}", clitools::MULTI_ARCH1)]);
expect_ok_ex(config, &["rustup", "show"],
&format!(r"installed toolchains
--------------------

stable-{0}
nightly-{0} (default)

installed targets for active toolchain
--------------------------------------

{1}
{0}

active toolchain
----------------

nightly-{0} (default)
1.3.0 (xxxx-n-2)

", clitools::MULTI_ARCH1, clitools::CROSS_ARCH2),
r"");
});
}

#[test]
fn list_default_toolchain() {
setup(&|config| {
Expand All @@ -296,14 +381,17 @@ r"");
}

#[test]
#[ignore(windows)] // FIXME rustup displays UNC paths
fn show_toolchain_override() {
// FIXME rustup displays UNC paths
if cfg!(windows) { return }

setup(&|config| {
let cwd = ::std::env::current_dir().unwrap();
expect_ok(config, &["rustup", "override", "add", "nightly"]);
expect_ok_ex(config, &["rustup", "show"],
&format!(r"nightly (directory override for '{}')
", cwd.display()),
&format!(r"nightly-{} (directory override for '{}')
1.3.0 (hash-n-2)
", this_host_triple(), cwd.display()),
r"");
});
}
Expand All @@ -330,7 +418,9 @@ fn show_toolchain_env() {
let out = cmd.output().unwrap();
assert!(out.status.success());
let stdout = String::from_utf8(out.stdout).unwrap();
assert!(&stdout == for_host!("nightly-{0} (environment override by RUSTUP_TOOLCHAIN)\n"));
assert!(&stdout == for_host!(r"nightly-{0} (environment override by RUSTUP_TOOLCHAIN)
1.3.0 (hash-n-2)
"));
});
}

Expand Down