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
  • Loading branch information
hi-rustin committed Dec 19, 2020
1 parent 50fbbeb commit d6d1346
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 73 deletions.
19 changes: 17 additions & 2 deletions src/cli/rustup_mode.rs
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,21 @@ 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()?;

if current_version != available_version {
let _ = t.attr(term2::Attr::Bold);
write!(t, "{} - ", "rustup")?;
let _ = t.fg(term2::color::YELLOW);
write!(t, "Update available")?;
let _ = t.reset();
writeln!(t, " : {} -> {}", current_version, available_version)?;
}
Ok(utils::ExitCode(0))
}

Expand Down
76 changes: 44 additions & 32 deletions src/cli/self_update.rs
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
23 changes: 22 additions & 1 deletion tests/cli-exact.rs
@@ -1,12 +1,12 @@
//! Yet more cli test cases. These are testing that the output
//! is exactly as expected.

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,
};
use mock::clitools::self_update_setup;
use rustup::for_host;
use rustup::test::this_host_triple;

Expand Down Expand Up @@ -107,6 +107,27 @@ 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_with_update() {
setup(&|config| {
Expand Down
41 changes: 3 additions & 38 deletions tests/cli-self-upd.rs
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
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 d6d1346

Please sign in to comment.