Skip to content

Commit

Permalink
Include rustup self-update status in check
Browse files Browse the repository at this point in the history
Update check command desc

Add test

Refine use

Add no update output

add name

fix typo

fix typo

add new line

Add test case
  • Loading branch information
Rustin170506 committed Dec 24, 2020
1 parent 50fbbeb commit 0743dc8
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 74 deletions.
25 changes: 23 additions & 2 deletions src/cli/rustup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ use std::str::FromStr;

use clap::{App, AppSettings, Arg, ArgGroup, ArgMatches, Shell, SubCommand};

use super::common;
use super::errors::*;
use super::help::*;
use super::self_update;
use super::term2;
use super::term2::Terminal;
use super::topical_doc;
use super::{common, self_update::get_available_rustup_version};
use crate::dist::dist::{
PartialTargetTriple, PartialToolchainDesc, Profile, TargetTriple, ToolchainDesc,
};
Expand Down Expand Up @@ -316,7 +316,7 @@ pub fn cli() -> App<'static, 'static> {
.takes_value(false),
),
)
.subcommand(SubCommand::with_name("check").about("Check for updates to Rust toolchains"))
.subcommand(SubCommand::with_name("check").about("Check for updates to Rust toolchains and rustup"))
.subcommand(
SubCommand::with_name("default")
.about("Set the default toolchain")
Expand Down Expand Up @@ -890,6 +890,27 @@ fn check_updates(cfg: &Cfg) -> Result<utils::ExitCode> {
(_, Err(err)) => return Err(err.into()),
}
}

// Get current rustup version
let current_version = env!("CARGO_PKG_VERSION");

// Get available rustup version
let available_version = get_available_rustup_version()?;

let _ = t.attr(term2::Attr::Bold);
write!(t, "{} - ", "rustup")?;

if current_version != available_version {
let _ = t.fg(term2::color::YELLOW);
write!(t, "Update available")?;
let _ = t.reset();
writeln!(t, " : {} -> {}", current_version, available_version)?;
} else {
let _ = t.fg(term2::color::GREEN);
write!(t, "Up to date")?;
let _ = t.reset();
writeln!(t, " : {}", current_version)?;
}
Ok(utils::ExitCode(0))
}

Expand Down
76 changes: 44 additions & 32 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1010,46 +1010,17 @@ pub fn prepare_update() -> Result<Option<PathBuf>> {
#[cfg(windows)]
let triple = dist::TargetTriple::from_host().unwrap_or(triple);

// Get update root.
let update_root = process()
.var("RUSTUP_UPDATE_ROOT")
.unwrap_or_else(|_| String::from(UPDATE_ROOT));

let tempdir = tempfile::Builder::new()
.prefix("rustup-update")
.tempdir()
.chain_err(|| "error creating temp directory")?;

// Get current version
let current_version = env!("CARGO_PKG_VERSION");

// Download available version
// Get available version
info!("checking for self-updates");
let release_file_url = format!("{}/release-stable.toml", update_root);
let release_file_url = utils::parse_url(&release_file_url)?;
let release_file = tempdir.path().join("release-stable.toml");
utils::download_file(&release_file_url, &release_file, None, &|_| ())?;
let release_toml_str = utils::read_file("rustup release", &release_file)?;
let release_toml: toml::Value = toml::from_str(&release_toml_str)
.map_err(|_| Error::from("unable to parse rustup release file"))?;

let schema = release_toml
.get("schema-version")
.ok_or_else(|| Error::from("no schema key in rustup release file"))?
.as_str()
.ok_or_else(|| Error::from("invalid schema key in rustup release file"))?;

let available_version = release_toml
.get("version")
.ok_or_else(|| Error::from("no version key in rustup release file"))?
.as_str()
.ok_or_else(|| Error::from("invalid version key in rustup release file"))?;

if schema != "1" {
return Err(Error::from(&*format!(
"unknown schema version '{}' in rustup release file",
schema
)));
}
let available_version = get_available_rustup_version()?;

// If up-to-date
if available_version == current_version {
Expand All @@ -1075,6 +1046,47 @@ pub fn prepare_update() -> Result<Option<PathBuf>> {
Ok(Some(setup_path))
}

pub fn get_available_rustup_version() -> Result<String> {
let update_root = process()
.var("RUSTUP_UPDATE_ROOT")
.unwrap_or_else(|_| String::from(UPDATE_ROOT));
let tempdir = tempfile::Builder::new()
.prefix("rustup-update")
.tempdir()
.chain_err(|| "error creating temp directory")?;

// Parse the release file.
let release_file_url = format!("{}/release-stable.toml", update_root);
let release_file_url = utils::parse_url(&release_file_url)?;
let release_file = tempdir.path().join("release-stable.toml");
utils::download_file(&release_file_url, &release_file, None, &|_| ())?;
let release_toml_str = utils::read_file("rustup release", &release_file)?;
let release_toml: toml::Value = toml::from_str(&release_toml_str)
.map_err(|_| Error::from("unable to parse rustup release file"))?;

// Check the release file schema.
let schema = release_toml
.get("schema-version")
.ok_or_else(|| Error::from("no schema key in rustup release file"))?
.as_str()
.ok_or_else(|| Error::from("invalid schema key in rustup release file"))?;
if schema != "1" {
return Err(Error::from(&*format!(
"unknown schema version '{}' in rustup release file",
schema
)));
}

// Get the version.
let available_version = release_toml
.get("version")
.ok_or_else(|| Error::from("no version key in rustup release file"))?
.as_str()
.ok_or_else(|| Error::from("invalid version key in rustup release file"))?;

Ok(String::from(available_version))
}

pub fn cleanup_self_updater() -> Result<()> {
let cargo_home = utils::cargo_home()?;
let setup = cargo_home.join(&format!("bin/rustup-init{}", EXE_SUFFIX));
Expand Down
45 changes: 43 additions & 2 deletions tests/cli-exact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
pub mod mock;

use crate::mock::clitools::{
self, expect_err_ex, expect_ok, expect_ok_ex, expect_stdout_ok, set_current_dist_date, Config,
Scenario,
self, expect_err_ex, expect_ok, expect_ok_ex, expect_stdout_ok, self_update_setup,
set_current_dist_date, Config, Scenario,
};
use rustup::for_host;
use rustup::test::this_host_triple;
Expand Down Expand Up @@ -107,6 +107,47 @@ nightly-{0} - Update available : 1.2.0 (hash-nightly-1) -> 1.3.0 (hash-nightly-2
})
}

#[test]
fn check_updates_self() {
let test_version = "2.0.0";

self_update_setup(
&|config, _| {
let current_version = env!("CARGO_PKG_VERSION");

expect_stdout_ok(
config,
&["rustup", "check"],
&format!(
r"rustup - Update available : {} -> {}
",
current_version, test_version
),
);
},
test_version,
)
}

#[test]
fn check_updates_self_no_change() {
let current_version = env!("CARGO_PKG_VERSION");

self_update_setup(
&|config, _| {
expect_stdout_ok(
config,
&["rustup", "check"],
&format!(
r"rustup - Up to date : {}
",
current_version
),
);
},
current_version,
)
}
#[test]
fn check_updates_with_update() {
setup(&|config| {
Expand Down
41 changes: 3 additions & 38 deletions tests/cli-self-upd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,15 @@ use rustup::Notification;

use crate::mock::clitools::{
self, expect_component_executable, expect_component_not_executable, expect_err, expect_err_ex,
expect_ok, expect_ok_contains, expect_ok_ex, expect_stderr_ok, expect_stdout_ok, run, Config,
Scenario,
expect_ok, expect_ok_contains, expect_ok_ex, expect_stderr_ok, expect_stdout_ok,
output_release_file, run, self_update_setup, Config, Scenario,
};
use crate::mock::dist::calc_hash;

const TEST_VERSION: &str = "1.1.1";

pub fn update_setup(f: &dyn Fn(&Config, &Path)) {
clitools::setup(Scenario::SimpleV2, &|config| {
// Create a mock self-update server
let self_dist_tmp = tempfile::Builder::new()
.prefix("self_dist")
.tempdir()
.unwrap();
let self_dist = self_dist_tmp.path();

let trip = this_host_triple();
let dist_dir = self_dist.join(&format!("archive/{}/{}", TEST_VERSION, trip));
let dist_exe = dist_dir.join(&format!("rustup-init{}", EXE_SUFFIX));
let rustup_bin = config.exedir.join(&format!("rustup-init{}", EXE_SUFFIX));

fs::create_dir_all(dist_dir).unwrap();
output_release_file(self_dist, "1", TEST_VERSION);
fs::copy(&rustup_bin, &dist_exe).unwrap();
// Modify the exe so it hashes different
raw::append_file(&dist_exe, "").unwrap();

let root_url = format!("file://{}", self_dist.display());
config.rustup_update_root = Some(root_url);

f(config, self_dist);
});
self_update_setup(f, TEST_VERSION)
}

/// Empty dist server, rustup installed with no toolchain
Expand Down Expand Up @@ -76,18 +53,6 @@ fn setup_installed(f: &dyn Fn(&Config)) {
})
}

fn output_release_file(dist_dir: &Path, schema: &str, version: &str) {
let contents = format!(
r#"
schema-version = "{}"
version = "{}"
"#,
schema, version
);
let file = dist_dir.join("release-stable.toml");
utils::write_file("release", &file, &contents).unwrap();
}

#[test]
/// This is the primary smoke test testing the full end to end behaviour of the
/// installation code path: everything that is output, the proxy installation,
Expand Down
39 changes: 39 additions & 0 deletions tests/mock/clitools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,45 @@ pub fn setup(s: Scenario, f: &dyn Fn(&mut Config)) {
assert!(!PathBuf::from("./bogus-cargo-home").exists());
}

pub fn self_update_setup(f: &dyn Fn(&Config, &Path), version: &str) {
setup(Scenario::SimpleV2, &|config| {
// Create a mock self-update server
let self_dist_tmp = tempfile::Builder::new()
.prefix("self_dist")
.tempdir()
.unwrap();
let self_dist = self_dist_tmp.path();

let trip = this_host_triple();
let dist_dir = self_dist.join(&format!("archive/{}/{}", version, trip));
let dist_exe = dist_dir.join(&format!("rustup-init{}", EXE_SUFFIX));
let rustup_bin = config.exedir.join(&format!("rustup-init{}", EXE_SUFFIX));

fs::create_dir_all(dist_dir).unwrap();
output_release_file(self_dist, "1", version);
fs::copy(&rustup_bin, &dist_exe).unwrap();
// Modify the exe so it hashes different
raw::append_file(&dist_exe, "").unwrap();

let root_url = format!("file://{}", self_dist.display());
config.rustup_update_root = Some(root_url);

f(config, self_dist);
});
}

pub fn output_release_file(dist_dir: &Path, schema: &str, version: &str) {
let contents = format!(
r#"
schema-version = "{}"
version = "{}"
"#,
schema, version
);
let file = dist_dir.join("release-stable.toml");
utils::write_file("release", &file, &contents).unwrap();
}

impl Config {
pub fn current_dir(&self) -> PathBuf {
self.workdir.borrow().clone()
Expand Down

0 comments on commit 0743dc8

Please sign in to comment.