diff options
author | crowlKats <13135287+crowlKats@users.noreply.github.com> | 2020-11-22 16:07:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-22 16:07:05 +0100 |
commit | 750f179aebf450db37c51e021a7b0352c7ffd42a (patch) | |
tree | 49ccb34342a7e2e735c5290bab41c2522824d716 | |
parent | 7405356e23cc20b69e0f5d4313110d7780665f2b (diff) |
refactor(cli/tools/upgrade): rework upgrade (#8331)
This commit does major overhaul of "upgrade" subcommand,
reducing complexity & giving more sensible console output.
Removes gz support for archives.
Uses last part of url instead of scraping to get latest version.
-rw-r--r-- | cli/tools/upgrade.rs | 177 |
1 files changed, 56 insertions, 121 deletions
diff --git a/cli/tools/upgrade.rs b/cli/tools/upgrade.rs index 2bc28ec7d..f183540cf 100644 --- a/cli/tools/upgrade.rs +++ b/cli/tools/upgrade.rs @@ -1,54 +1,23 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. //! This module provides feature to upgrade deno executable -//! -//! At the moment it is only consumed using CLI but in -//! the future it can be easily extended to provide -//! the same functions as ops available in JS runtime. -use crate::http_util::fetch_once; -use crate::http_util::FetchOnceResult; use crate::AnyError; -use deno_core::error::custom_error; -use deno_core::futures::FutureExt; -use deno_core::url::Url; use deno_fetch::reqwest; -use deno_fetch::reqwest::redirect::Policy; use deno_fetch::reqwest::Client; -use regex::Regex; use semver_parser::version::parse as semver_parse; -use semver_parser::version::Version; use std::fs; -use std::future::Future; -use std::io::prelude::*; use std::path::Path; use std::path::PathBuf; -use std::pin::Pin; use std::process::Command; -use std::process::Stdio; -use std::string::String; use tempfile::TempDir; lazy_static! { static ref ARCHIVE_NAME: String = format!("deno-{}.zip", env!("TARGET")); } -async fn get_latest_version(client: &Client) -> Result<Version, AnyError> { - println!("Checking for latest version"); - let body = client - .get(Url::parse( - "https://github.com/denoland/deno/releases/latest", - )?) - .send() - .await? - .text() - .await?; - let v = find_version(&body)?; - Ok(semver_parse(&v).unwrap()) -} +const RELEASE_URL: &str = "https://github.com/denoland/deno/releases"; -/// Asynchronously updates deno executable to greatest version -/// if greatest version is available. pub async fn upgrade_command( dry_run: bool, force: bool, @@ -56,55 +25,55 @@ pub async fn upgrade_command( output: Option<PathBuf>, ca_file: Option<String>, ) -> Result<(), AnyError> { - let mut client_builder = Client::builder().redirect(Policy::none()); + let mut client_builder = Client::builder(); // If we have been provided a CA Certificate, add it into the HTTP client if let Some(ca_file) = ca_file { - let buf = std::fs::read(ca_file); - let cert = reqwest::Certificate::from_pem(&buf.unwrap())?; + let buf = std::fs::read(ca_file)?; + let cert = reqwest::Certificate::from_pem(&buf)?; client_builder = client_builder.add_root_certificate(cert); } let client = client_builder.build()?; - let current_version = semver_parse(crate::version::DENO).unwrap(); - 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); - return Ok(()); - } else { - ver - } - } - Err(_) => { - eprintln!("Invalid semver passed"); - std::process::exit(1) + Some(passed_version) => { + if !force && output.is_none() && crate::version::DENO == passed_version { + println!("Version {} is already installed", passed_version); + return Ok(()); + } else { + passed_version } - }, + } None => { let latest_version = get_latest_version(&client).await?; - if !force && current_version >= latest_version { + let current = semver_parse(crate::version::DENO).unwrap(); + let latest = match semver_parse(&latest_version) { + Ok(v) => v, + Err(_) => { + eprintln!("Invalid semver passed"); + std::process::exit(1) + } + }; + + if !force && output.is_none() && current >= latest { println!( "Local deno version {} is the most recent release", - &crate::version::DENO + crate::version::DENO ); return Ok(()); } else { + println!("Found latest version {}", &latest_version); latest_version } } }; - let archive_data = download_package( - &compose_url_to_exec(&install_version)?, - client, - &install_version, - ) - .await?; + let archive_data = download_package(client, &install_version).await?; + + println!("Deno is upgrading to version {}", &install_version); + let old_exe_path = std::env::current_exe()?; let new_exe_path = unpack(archive_data)?; let permissions = fs::metadata(&old_exe_path)?.permissions(); @@ -121,58 +90,43 @@ pub async fn upgrade_command( } } - println!("Upgrade done successfully"); + println!("Upgraded successfully"); Ok(()) } -fn download_package( - url: &Url, - client: Client, - version: &Version, -) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, AnyError>>>> { - println!("downloading {}", url); - let url = url.clone(); - let version = version.clone(); - let fut = async move { - match fetch_once(client.clone(), &url, None).await { - Ok(result) => { - println!( - "Version has been found\nDeno is upgrading to version {}", - &version - ); - match result { - FetchOnceResult::Code(source, _) => Ok(source), - FetchOnceResult::NotModified => unreachable!(), - FetchOnceResult::Redirect(_url, _) => { - download_package(&_url, client, &version).await - } - } - } - Err(_) => { - println!("Version has not been found, aborting"); - std::process::exit(1) - } - } - }; - fut.boxed_local() +async fn get_latest_version(client: &Client) -> Result<String, AnyError> { + println!("Looking up latest version"); + + let res = client + .get(&format!("{}/latest", RELEASE_URL)) + .send() + .await?; + let version = res.url().path_segments().unwrap().last().unwrap(); + + Ok(version.replace("v", "")) } -fn compose_url_to_exec(version: &Version) -> Result<Url, AnyError> { - let s = format!( - "https://github.com/denoland/deno/releases/download/v{}/{}", - version, *ARCHIVE_NAME +async fn download_package( + client: Client, + install_version: &str, +) -> Result<Vec<u8>, AnyError> { + let download_url = format!( + "{}/download/v{}/{}", + RELEASE_URL, install_version, *ARCHIVE_NAME ); - Url::parse(&s).map_err(AnyError::from) -} -fn find_version(text: &str) -> Result<String, AnyError> { - let re = Regex::new(r#"v([^\?]+)?""#)?; - if let Some(_mat) = re.find(text) { - let mat = _mat.as_str(); - return Ok(mat[1..mat.len() - 1].to_string()); + println!("Checking {}", &download_url); + + let res = client.get(&download_url).send().await?; + + if res.status().is_success() { + println!("Download has been found"); + Ok(res.bytes().await?.to_vec()) + } else { + println!("Download could not be found, aborting"); + std::process::exit(1) } - Err(custom_error("NotFound", "Cannot read latest tag version")) } fn unpack(archive_data: Vec<u8>) -> Result<PathBuf, std::io::Error> { @@ -189,16 +143,6 @@ fn unpack(archive_data: Vec<u8>) -> Result<PathBuf, std::io::Error> { .and_then(|ext| ext.to_str()) .unwrap(); let unpack_status = match archive_ext { - "gz" => { - let exe_file = fs::File::create(&exe_path)?; - let mut cmd = Command::new("gunzip") - .arg("-c") - .stdin(Stdio::piped()) - .stdout(Stdio::from(exe_file)) - .spawn()?; - cmd.stdin.as_mut().unwrap().write_all(&archive_data)?; - cmd.wait()? - } "zip" if cfg!(windows) => { let archive_path = temp_dir.join("deno.zip"); fs::write(&archive_path, &archive_data)?; @@ -255,10 +199,7 @@ fn replace_exe(new: &Path, old: &Path) -> Result<(), std::io::Error> { Ok(()) } -fn check_exe( - exe_path: &Path, - expected_version: &Version, -) -> Result<(), AnyError> { +fn check_exe(exe_path: &Path, expected_version: &str) -> Result<(), AnyError> { let output = Command::new(exe_path) .arg("-V") .stderr(std::process::Stdio::inherit()) @@ -268,9 +209,3 @@ fn check_exe( assert_eq!(stdout.trim(), format!("deno {}", expected_version)); Ok(()) } - -#[test] -fn test_find_version() { - let url = "<html><body>You are being <a href=\"https://github.com/denoland/deno/releases/tag/v0.36.0\">redirected</a>.</body></html>"; - assert_eq!(find_version(url).unwrap(), "0.36.0".to_string()); -} |