use crate::commands::install;
use crate::configrc::{rc_get_with_fix, rc_update};
use crate::consts::{
DVM_CONFIGRC_KEY_DENO_VERSION, DVM_CONFIGRC_KEY_REGISTRY_BINARY, DVM_VERSION_CANARY, DVM_VERSION_LATEST,
DVM_VERSION_SYSTEM, REGISTRY_OFFICIAL,
};
use crate::deno_bin_path;
use crate::meta::DvmMeta;
use crate::utils::{best_version, deno_canary_path, deno_version_path, prompt_request, run_with_spinner, update_stub};
use crate::utils::{is_exact_version, load_dvmrc};
use crate::version::remote_versions;
use crate::version::{get_latest_version, VersionArg};
use anyhow::Result;
use semver::Version;
use std::fs;
use std::path::Path;
use std::process::Command;
pub fn exec(meta: &mut DvmMeta, version: Option<String>, write_local: bool) -> Result<()> {
let rc_binary_url =
rc_get_with_fix(DVM_CONFIGRC_KEY_REGISTRY_BINARY).unwrap_or_else(|_| REGISTRY_OFFICIAL.to_string());
let version_req: VersionArg;
if let Some(ref version) = version {
if version == &DVM_VERSION_CANARY.to_string() {
let canary_path = deno_canary_path();
if !canary_path.exists() {
if prompt_request("deno canary is not installed. do you want to install it?") {
install::exec(meta, true, Some(DVM_VERSION_CANARY.to_string())).unwrap();
use_canary_bin_path(write_local).unwrap();
} else {
std::process::exit(1);
}
}
use_canary_bin_path(write_local).unwrap();
return Ok(());
} else if version == &DVM_VERSION_SYSTEM.to_string() {
std::fs::remove_file(deno_bin_path()).unwrap();
println!("Deno that was previously installed on your system will be activated now.");
return Ok(());
}
if is_exact_version(version) {
version_req = VersionArg::Exact(Version::parse(version).unwrap());
} else if meta.has_alias(version) {
version_req = meta.resolve_version_req(version);
} else {
eprintln!(
"`{}` is not a valid semver version or tag and will not be used\ntype `dvm help` for more info",
version
);
std::process::exit(1);
}
} else {
println!("No version input detect, try to use version in .dvmrc file");
version_req = load_dvmrc();
println!("Using semver range: {}", version_req);
}
let used_version = if version_req.to_string() == "*" {
println!("Checking for latest version");
let version = get_latest_version(&rc_binary_url).expect("Get latest version failed");
println!("The latest version is v{}", version);
version
} else {
match version_req {
VersionArg::Exact(ref v) => v.clone(),
VersionArg::Range(ref r) => {
println!("Fetching version list");
let versions = remote_versions().expect("Fetching version list failed.");
best_version(versions.iter().map(AsRef::as_ref), r.clone()).unwrap()
}
}
};
let new_exe_path = deno_version_path(&used_version);
if !new_exe_path.exists() {
if prompt_request(format!("deno v{} is not installed. do you want to install it?", used_version).as_str()) {
install::exec(meta, true, Some(used_version.to_string())).unwrap();
let temp = version_req.to_string();
let version = version.as_ref().unwrap_or(&temp);
if !is_exact_version(version) {
meta.set_version_mapping(version.clone(), used_version.to_string());
}
} else {
std::process::exit(1);
}
}
use_this_bin_path(
&new_exe_path,
&used_version,
version.unwrap_or_else(|| DVM_VERSION_LATEST.to_string()),
write_local,
)?;
update_stub(used_version.to_string().as_str());
Ok(())
}
pub fn use_canary_bin_path(local: bool) -> Result<()> {
run_with_spinner("Processing".to_string(), "Now using deno canary".to_string(), |_| {
let canary_dir = deno_canary_path();
if !canary_dir.exists() {
eprintln!("Canary dir not found, will not be used");
std::process::exit(1);
}
let bin_path = deno_bin_path();
if !bin_path.parent().unwrap().exists() {
fs::create_dir_all(bin_path.parent().unwrap()).unwrap();
}
if bin_path.exists() {
fs::remove_file(&bin_path)?;
}
fs::hard_link(&canary_dir, &bin_path)?;
rc_update(local, DVM_CONFIGRC_KEY_DENO_VERSION, DVM_VERSION_CANARY)?;
Ok(())
})
}
pub fn use_this_bin_path(exe_path: &Path, version: &Version, raw_version: String, local: bool) -> Result<()> {
run_with_spinner("Processing".to_string(), format!("Now using deno {}", &version), |_| {
check_exe(exe_path, version)?;
let bin_path = deno_bin_path();
if !bin_path.parent().unwrap().exists() {
fs::create_dir_all(bin_path.parent().unwrap()).unwrap();
}
if bin_path.exists() {
fs::remove_file(&bin_path)?;
}
fs::hard_link(exe_path, &bin_path)?;
rc_update(local, DVM_CONFIGRC_KEY_DENO_VERSION, raw_version.as_str())?;
Ok(())
})
}
fn check_exe(exe_path: &Path, expected_version: &Version) -> Result<()> {
let output = Command::new(exe_path)
.arg("-V")
.stderr(std::process::Stdio::inherit())
.output()?;
let stdout = String::from_utf8(output.stdout)?;
assert!(output.status.success());
assert_eq!(stdout.trim(), format!("deno {}", expected_version));
Ok(())
}