dvm 1.9.3

Deno Version Manager - Easy way to manage multiple active deno versions.
use crate::{
  commands::install,
  consts::{DVM_VERSION_CANARY, DVM_VERSION_INVALID, DVM_VERSION_SELF},
  utils::best_version,
  version::{remote_versions, VersionArg},
  DvmMeta,
};
use anyhow::{Ok, Result};
use colored::Colorize;
use std::fs;
use std::str::FromStr;

pub fn exec(meta: &mut DvmMeta, alias: Option<String>) -> Result<()> {
  let versions = remote_versions().expect("Fetching version list failed.");
  if let Some(alias) = alias {
    if alias == DVM_VERSION_SELF {
      upgrade_self()?;
      return Ok(());
    }

    if alias == DVM_VERSION_CANARY {
      println!("Upgrading {}", alias.bright_black());
      install::exec(meta, true, Some(alias)).unwrap();
      println!("All aliases have been upgraded");
      return Ok(());
    }

    if !meta.has_alias(&alias) {
      eprintln!(
        "{} is not a valid semver version or tag and will not be upgraded",
        alias.bright_black()
      );
      std::process::exit(1);
    }
    println!("Upgrading alias {}", alias.bright_black());
    let current = meta
      .get_version_mapping(alias.as_str())
      .unwrap_or_else(|| DVM_VERSION_INVALID.to_string());
    let version_req = meta.resolve_version_req(&alias);
    match version_req {
      VersionArg::Exact(v) => {
        if current == v.to_string() {
          println!("{} is already the latest version", alias);
          std::process::exit(0);
        } else {
          install::exec(meta, true, Some(v.to_string())).expect("Install failed");
        }
      }
      VersionArg::Range(r) => {
        let version = best_version(versions.iter().map(AsRef::as_ref), r).unwrap();
        install::exec(meta, true, Some(version.to_string())).expect("Install failed");
        meta.set_version_mapping(alias, version.to_string());
      }
    }
  } else {
    for alias in meta.list_alias() {
      let current = meta
        .get_version_mapping(alias.name.as_str())
        .unwrap_or_else(|| DVM_VERSION_INVALID.to_string());

      let latest = match VersionArg::from_str(alias.required.clone().as_str()).unwrap() {
        VersionArg::Exact(v) => v.to_string(),
        VersionArg::Range(v) => best_version(versions.iter().map(AsRef::as_ref), v).unwrap().to_string(),
      };

      if current == latest {
        continue;
      }

      println!(
        "Upgrading {} from {} to {}",
        alias.name.bright_black(),
        current.bright_red(),
        latest.clone().bright_green()
      );
      install::exec(meta, true, Some(latest.clone()))?;
      meta.set_version_mapping(alias.name, latest);

      println!("Upgrading {}", DVM_VERSION_CANARY.bright_black());
      install::exec(meta, true, Some(DVM_VERSION_CANARY.to_string())).unwrap();
    }

    println!("All aliases have been upgraded");
  }

  Ok(())
}

fn upgrade_self() -> Result<()> {
  cfg_if::cfg_if! {
    if #[cfg(windows)] {
      let url = "https://raw.githubusercontent.com/justjavac/dvm/main/install.ps1";
      let script = tinyget::get(url).send()?;
      let script = script.as_str()?;
      let tmp = tempfile::tempdir()?;
      let tmp = tmp.path().join("install.ps1");
      fs::write(&tmp, script)?;
      let mut cmd = std::process::Command::new("powershell");
      cmd.arg("-ExecutionPolicy").arg("Bypass").arg("-File").arg(tmp);
      cmd.status()?;
    } else {
      let url = "https://raw.githubusercontent.com/justjavac/dvm/main/install.sh";
      let script = tinyget::get(url).send()?;
      let script = script.as_str()?;
      let tmp = tempfile::tempdir()?;
      let tmp = tmp.path().join("install.sh");
      fs::write(tmp, script)?;
      std::process::Command::new("bash").arg(script).status()?;
    }
  }

  Ok(())
}