From abbf0339cd0013ba7d691adf76460631c6a03e9f Mon Sep 17 00:00:00 2001 From: crowlKats <13135287+crowlKats@users.noreply.github.com> Date: Sat, 9 May 2020 12:31:15 +0200 Subject: [PATCH] feat(upgrade): allow specifying a version (#5156) --- cli/flags.rs | 22 ++++++++-- cli/lib.rs | 8 ++-- cli/tests/integration_tests.rs | 31 ++++++++++++++ cli/upgrade.rs | 74 +++++++++++++++++++++++----------- 4 files changed, 105 insertions(+), 30 deletions(-) diff --git a/cli/flags.rs b/cli/flags.rs index bb81f0d01d..216fcd4744 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -65,6 +65,7 @@ pub enum DenoSubcommand { Upgrade { dry_run: bool, force: bool, + version: Option, }, } @@ -563,7 +564,12 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { fn upgrade_parse(flags: &mut Flags, matches: &clap::ArgMatches) { let dry_run = matches.is_present("dry-run"); let force = matches.is_present("force"); - flags.subcommand = DenoSubcommand::Upgrade { dry_run, force }; + let version = matches.value_of("version").map(|s| s.to_string()); + flags.subcommand = DenoSubcommand::Upgrade { + dry_run, + force, + version, + }; } fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { @@ -811,14 +817,21 @@ Future runs of this module will trigger no downloads or compilation unless fn upgrade_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("upgrade") - .about("Upgrade deno executable to newest version") + .about("Upgrade deno executable to given version") .long_about( - "Upgrade deno executable to newest available version. + "Upgrade deno executable to the given version. +Defaults to latest. -The latest version is downloaded from +The version is downloaded from https://github.com/denoland/deno/releases and is used to replace the current executable.", ) + .arg( + Arg::with_name("version") + .long("version") + .help("The version to upgrade to") + .takes_value(true), + ) .arg( Arg::with_name("dry-run") .long("dry-run") @@ -1354,6 +1367,7 @@ mod tests { subcommand: DenoSubcommand::Upgrade { force: true, dry_run: true, + version: None }, ..Flags::default() } diff --git a/cli/lib.rs b/cli/lib.rs index 060c86b55c..957637719c 100644 --- a/cli/lib.rs +++ b/cli/lib.rs @@ -616,9 +616,11 @@ pub fn main() { } return; } - DenoSubcommand::Upgrade { force, dry_run } => { - upgrade_command(dry_run, force).boxed_local() - } + DenoSubcommand::Upgrade { + force, + dry_run, + version, + } => upgrade_command(dry_run, force, version).boxed_local(), _ => unreachable!(), }; diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index 28df472508..7ad7781de7 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -224,6 +224,37 @@ fn upgrade_in_tmpdir() { // TODO(ry) assert!(mtime1 < mtime2); } +// Warning: this test requires internet access. +#[test] +fn upgrade_with_version_in_tmpdir() { + let temp_dir = TempDir::new().unwrap(); + let exe_path = if cfg!(windows) { + temp_dir.path().join("deno") + } else { + temp_dir.path().join("deno.exe") + }; + let _ = std::fs::copy(util::deno_exe_path(), &exe_path).unwrap(); + assert!(exe_path.exists()); + let _mtime1 = std::fs::metadata(&exe_path).unwrap().modified().unwrap(); + let status = Command::new(&exe_path) + .arg("upgrade") + .arg("--force") + .arg("--version") + .arg("0.42.0") + .spawn() + .unwrap() + .wait() + .unwrap(); + assert!(status.success()); + let upgraded_deno_version = String::from_utf8( + Command::new(&exe_path).arg("-V").output().unwrap().stdout, + ) + .unwrap(); + assert!(upgraded_deno_version.contains("0.42.0")); + let _mtime2 = std::fs::metadata(&exe_path).unwrap().modified().unwrap(); + // TODO(ry) assert!(mtime1 < mtime2); +} + #[test] fn installer_test_local_module_run() { let temp_dir = TempDir::new().expect("tempdir fail"); diff --git a/cli/upgrade.rs b/cli/upgrade.rs index 519f8d6bc1..b4f207643b 100644 --- a/cli/upgrade.rs +++ b/cli/upgrade.rs @@ -52,36 +52,64 @@ async fn get_latest_version(client: &Client) -> Result { /// Asynchronously updates deno executable to greatest version /// if greatest version is available. -pub async fn upgrade_command(dry_run: bool, force: bool) -> Result<(), ErrBox> { +pub async fn upgrade_command( + dry_run: bool, + force: bool, + version: Option, +) -> Result<(), ErrBox> { let client = Client::builder().redirect(Policy::none()).build()?; - let latest_version = get_latest_version(&client).await?; let current_version = semver_parse(crate::version::DENO).unwrap(); - if !force && current_version >= latest_version { - println!( - "Local deno version {} is the most recent release", - &crate::version::DENO - ); - } else { - println!( - "New version has been found\nDeno is upgrading to version {}", - &latest_version - ); - let archive_data = - download_package(&compose_url_to_exec(&latest_version)?, client).await?; + let install_version = match version { + Some(passed_version) => match semver_parse(&passed_version) { + Ok(ver) => { + if !force && current_version == ver { + println!("Version {} is already installed", &ver); + std::process::exit(1) + } else { + ver + } + } + Err(_) => { + eprintln!("Invalid semver passed"); + std::process::exit(1) + } + }, + None => { + let latest_version = get_latest_version(&client).await?; - let old_exe_path = std::env::current_exe()?; - let new_exe_path = unpack(archive_data)?; - let permissions = fs::metadata(&old_exe_path)?.permissions(); - fs::set_permissions(&new_exe_path, permissions)?; - check_exe(&new_exe_path, &latest_version)?; - - if !dry_run { - replace_exe(&new_exe_path, &old_exe_path)?; + if !force && current_version >= latest_version { + println!( + "Local deno version {} is the most recent release", + &crate::version::DENO + ); + std::process::exit(1) + } else { + latest_version + } } + }; - println!("Upgrade done successfully") + println!( + "Version has been found\nDeno is upgrading to version {}", + &install_version + ); + + let archive_data = + download_package(&compose_url_to_exec(&install_version)?, client).await?; + + let old_exe_path = std::env::current_exe()?; + let new_exe_path = unpack(archive_data)?; + let permissions = fs::metadata(&old_exe_path)?.permissions(); + fs::set_permissions(&new_exe_path, permissions)?; + check_exe(&new_exe_path, &install_version)?; + + if !dry_run { + replace_exe(&new_exe_path, &old_exe_path)?; } + + println!("Upgrade done successfully"); + Ok(()) }