From 50affe45158deda6a2a20a5c0c2653c32a9930f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Tue, 19 Jul 2022 09:56:40 +0200 Subject: [PATCH 01/16] Add alias in rig add --- src/alias.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/macos.rs | 6 ++++ src/main.rs | 1 + 4 files changed, 101 insertions(+) create mode 100644 src/alias.rs diff --git a/src/alias.rs b/src/alias.rs new file mode 100644 index 0000000..9decd1d --- /dev/null +++ b/src/alias.rs @@ -0,0 +1,93 @@ + +use std::error::Error; +use std::os::unix::fs::symlink; +use std::path::Path; + +use clap::ArgMatches; +use simple_error::*; +use simplelog::*; + +#[cfg(target_os = "macos")] +use crate::macos::*; + +#[cfg(target_os = "windows")] +use crate::windows::*; + +#[cfg(target_os = "linux")] +use crate::linux::*; + +use crate::escalate::*; + +pub fn get_alias(args: &ArgMatches) -> Option { + match args.value_of("str") { + None => None, + Some(str) => { + match str { + "oldrel" | "oldrel/1" => Some("oldrel".to_string()), + "release" | "devel" | "next" => Some(str.to_string()), + _ => None + } + } + } +} + +#[cfg(target_os = "macos")] +pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { + let msg = "Adding R-".to_string() + alias + " alias"; + escalate(&msg)?; + + info!("Adding R-{} alias to R {}", alias, ver); + + let base = Path::new(R_ROOT); + let target = base.join(ver).join("Resources/bin/R"); + let linkfile = Path::new("/usr/local/bin/").join("R-".to_string() + alias); + + // If it exists then we check that it points to the right place + // Cannot use .exists(), because it follows symlinks + let meta = std::fs::symlink_metadata(&linkfile); + if meta.is_ok() { + match std::fs::read_link(&linkfile) { + Err(_) => bail!("{} is not a symlink, aborting", linkfile.display()), + Ok(xtarget) => { + if xtarget == target { + return Ok(()) + } else { + debug!("{} is wrong, updating", linkfile.display()); + match std::fs::remove_file(&linkfile) { + Err(err) => { + bail!( + "Failed to delete {}, cannot update alias: {}", + linkfile.display(), + err.to_string() + ); + }, + _ => {} + } + } + } + } + } + + // If we are still here, then we need to create the link + debug!("Adding {} -> {}", linkfile.display(), target.display()); + match symlink(&target, &linkfile) { + Err(err) => bail!( + "Cannot create alias {}: {}", + linkfile.display(), + err.to_string() + ), + _ => {} + }; + + Ok(()) +} + +#[cfg(target_os = "windows")] +pub fn add_alias(ver: String, alias: String) { + // TODO +} + +#[cfg(target_os = "linux")] +pub fn add_alias(ver: String, alias: String) { + // TODO +} diff --git a/src/lib.rs b/src/lib.rs index a1c8425..e4b9948 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ use lazy_static::lazy_static; use libc; use simple_error::bail; +mod alias; mod args; mod common; mod config; diff --git a/src/macos.rs b/src/macos.rs index 327a981..f3caa46 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -14,6 +14,7 @@ use semver::Version; use simple_error::*; use simplelog::{debug, info, warn}; +use crate::alias::*; use crate::common::*; use crate::download::*; use crate::escalate::*; @@ -32,6 +33,7 @@ const R_CUR: &str = "/Library/Frameworks/R.framework/Versions/Current"; pub fn sc_add(args: &ArgMatches) -> Result<(), Box> { escalate("adding new R versions")?; let mut version = get_resolve(args)?; + let alias = get_alias(args); let ver = version.version.to_owned(); let verstr = match ver { Some(ref x) => x, @@ -91,6 +93,10 @@ pub fn sc_add(args: &ArgMatches) -> Result<(), Box> { system_fix_permissions(None)?; library_update_rprofile(&dirname.to_string())?; sc_system_make_links()?; + match alias { + Some(alias) => add_alias(dirname, &alias)?, + None => { } + }; if !args.is_present("without-cran-mirror") { set_cloud_mirror(Some(vec![dirname.to_string()]))?; diff --git a/src/main.rs b/src/main.rs index e044871..9e1312b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ mod linux; #[cfg(target_os = "linux")] use linux::*; +mod alias; mod library; mod common; mod config; From 42834e7de78541b66c90ee99c9f1873cc7e159f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sat, 23 Jul 2022 11:51:29 +0200 Subject: [PATCH 02/16] Improve debug messages --- src/config.rs | 2 +- src/macos.rs | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/config.rs b/src/config.rs index df9c525..1321fcf 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,7 +23,7 @@ fn empty_stringmap() -> HashMap { fn rig_config_file() -> Result> { let proj_dirs = match ProjectDirs::from("com", "gaborcsardi", "rig") { Some(x) => x, - None => bail!("Config file if not supported on this system"), + None => bail!("Config file is not supported on this system"), }; let config_dir = proj_dirs.data_dir(); let config_file = config_dir.join("config.json"); diff --git a/src/macos.rs b/src/macos.rs index f3caa46..a103c65 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -281,11 +281,7 @@ pub fn sc_system_make_links() -> Result<(), Box> { let linkfile = Path::new("/usr/local/bin/").join("R-".to_string() + &ver); let target = base.join(&ver).join("Resources/bin/R"); if !linkfile.exists() { - debug!( - "[DEBUG] Adding {} -> {}", - linkfile.display(), - target.display() - ); + debug!("Adding {} -> {}", linkfile.display(), target.display()); match symlink(&target, &linkfile) { Err(err) => bail!( "Cannot create symlink {}: {}", @@ -314,10 +310,10 @@ pub fn sc_system_make_links() -> Result<(), Box> { }; if re.is_match(&fnamestr) { match std::fs::read_link(&path) { - Err(_) => debug!("[DEBUG] {} is not a symlink", path.display()), + Err(_) => debug!("{} is not a symlink", path.display()), Ok(target) => { if !target.exists() { - debug!("[DEBUG] Cleaning up {}", target.display()); + debug!("Cleaning up {}", target.display()); match std::fs::remove_file(&path) { Err(err) => { warn!("Failed to remove {}: {}", path.display(), err.to_string()) @@ -570,7 +566,7 @@ fn system_fix_permissions(vers: Option>) -> Result<(), Box>) -> Result<(), Box Result<(), Box> { // TODO: this can fail, but if it fails it will still have exit // status 0, so we would need to check stderr to see if it failed. for line in output.lines() { - debug!("[DEBUG] Calling pkgutil --forget {}", line.trim()); + debug!("Calling pkgutil --forget {}", line.trim()); Command::new("pkgutil") .args(["--forget", line.trim()]) .output()?; From 28c5d3877c3773613bcc78fff849f70af9f78d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sat, 23 Jul 2022 18:03:42 +0200 Subject: [PATCH 03/16] rig ls lists aliases - on macOS only, for now - for --json as well --- src/common.rs | 10 +++++++- src/macos.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 10 ++++++-- src/renv.rs | 6 ++++- src/rversion.rs | 15 ++++++++++- 5 files changed, 103 insertions(+), 6 deletions(-) diff --git a/src/common.rs b/src/common.rs index 94689cd..763ed1e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -55,6 +55,7 @@ pub fn set_default_if_none(ver: String) -> Result<(), Box> { pub fn sc_get_list_details() -> Result, Box> { let names = sc_get_list()?; + let aliases = find_aliases()?; let mut res: Vec = vec![]; let re = Regex::new("^Version:[ ]?")?; @@ -74,11 +75,18 @@ pub fn sc_get_list_details() -> Result, Box> { }; let path = Path::new(R_ROOT).join(R_VERSIONDIR.replace("{}", &name)); let binary = Path::new(R_ROOT).join(R_BINPATH.replace("{}", &name)); + let mut myaliases: Vec = vec![]; + for a in &aliases { + if a.version == name { + myaliases.push(a.alias.to_owned()); + } + } res.push(InstalledVersion { name: name.to_string(), version: version, path: path.to_str().and_then(|x| Some(x.to_string())), - binary: binary.to_str().and_then(|x| Some(x.to_string())) + binary: binary.to_str().and_then(|x| Some(x.to_string())), + aliases: myaliases }); } diff --git a/src/macos.rs b/src/macos.rs index a103c65..0b67ccd 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -293,7 +293,7 @@ pub fn sc_system_make_links() -> Result<(), Box> { } } - // Remove danglink links + // Remove dangling links let paths = std::fs::read_dir("/usr/local/bin")?; let re = Regex::new("^R-[0-9]+[.][0-9]+")?; for file in paths { @@ -329,6 +329,72 @@ pub fn sc_system_make_links() -> Result<(), Box> { Ok(()) } +pub fn find_aliases() -> Result, Box> { + debug!("Finding existing aliaes"); + + let paths = std::fs::read_dir("/usr/local/bin")?; + let re = re_alias(); + let mut result: Vec = vec![]; + + for file in paths { + let path = file?.path(); + // If no path name, then path ends with ..., so we can skip + let fnamestr = match path.file_name() { + Some(x) => x, + None => continue, + }; + // If the path is not UTF-8, we'll skip it, this should not happen + let fnamestr = match fnamestr.to_str() { + Some(x) => x, + None => continue, + }; + if re.is_match(&fnamestr) { + match std::fs::read_link(&path) { + Err(_) => debug!("{} is not a symlink", path.display()), + Ok(target) => { + if !target.exists() { + debug!("Target does not exist at {}", target.display()); + + } else { + let version = version_from_link(target); + match version { + None => continue, + Some(version) => { + let als = Alias { + alias: fnamestr[2..].to_string(), + version: version.to_string() + }; + result.push(als); + } + }; + } + } + }; + } + } + + Ok(result) +} + +// /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/bin/R -> +// 4.2-arm64 +fn version_from_link(pb: PathBuf) -> Option { + let osver = match pb.parent() + .and_then(|x| x.parent()) + .and_then(|x| x.parent()) + .and_then(|x| x.file_name()) { + None => None, + Some(s) => Some(s.to_os_string()) + }; + + let s = match osver { + None => None, + Some(os) => os.into_string().ok() + }; + + s +} + pub fn sc_system_allow_core_dumps(args: &ArgMatches) -> Result<(), Box> { escalate("updating code signature of R and /cores permissions")?; sc_system_allow_debugger(args)?; diff --git a/src/main.rs b/src/main.rs index 9e1312b..b0b28d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -186,10 +186,15 @@ fn sc_list(args: &ArgMatches, mainargs: &ArgMatches) -> Result<(), Box = ver.aliases.iter() + .map(|v| "\"".to_string() + v + "\"") + .collect(); + let als = "[".to_string() + &alsq.join(", ") + "]"; println!(" {{"); println!(" \"name\": \"{}\",", ver.name); println!(" \"default\": {},", dflt); println!(" \"version\": \"{}\",", or_null(&ver.version)); + println!(" \"aliases\": {},", als); println!(" \"path\": \"{}\",", or_null(&ver.path)); println!(" \"binary\": \"{}\"", or_null(&ver.binary)); println!(" }}{}", if idx == num - 1 { "" } else { "," }); @@ -197,7 +202,7 @@ fn sc_list(args: &ArgMatches, mainargs: &ArgMatches) -> Result<(), Box Result<(), Box) for ver in all.iter() { match ver { InstalledVersion { - name: n, version: Some(v), path: Some(p), binary: Some(b) + name: n, + version: Some(v), + path: Some(p), + binary: Some(b), + aliases: _ } => { if let Ok(sv) = semver::Version::parse(v) { ok.push(OKInstalledVersion { diff --git a/src/rversion.rs b/src/rversion.rs index 55ac1bc..53526fc 100644 --- a/src/rversion.rs +++ b/src/rversion.rs @@ -1,4 +1,5 @@ +use regex::Regex; use std::cmp::Ordering; #[cfg(any(target_os = "macos", target_os = "linux"))] @@ -16,7 +17,8 @@ pub struct InstalledVersion { pub name: String, pub version: Option, pub path: Option, - pub binary: Option + pub binary: Option, + pub aliases: Vec, } #[derive(Debug, Clone)] @@ -73,3 +75,14 @@ pub struct User { pub dir: OsString, pub sudo: bool, } + +#[derive(Default, Debug)] +pub struct Alias { + pub alias: String, + pub version: String, +} + +pub fn re_alias() -> Regex { + let re= Regex::new("^R-(next|devel|release|oldrel)$").unwrap(); + re +} From 336633b3a35692a71d9453a9a2aeadbb4385df58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sun, 24 Jul 2022 13:45:17 +0200 Subject: [PATCH 04/16] More alias support on macOS, rig ls heading - rig rm - rig system allow-debugger - rig system make-orthogonal - rig system fix-permissions - rig system no-openmp - when setting the cloud mirror (although this is probably not needed) - rig rstudio - rig default - plus add a heading line to rig ls, otherwise people might not know what the last column is --- src/common.rs | 18 +++++++++++++----- src/macos.rs | 44 ++++++++++++++++++++++++++++++++++---------- src/main.rs | 6 ++++-- 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/common.rs b/src/common.rs index 763ed1e..e93bf08 100644 --- a/src/common.rs +++ b/src/common.rs @@ -23,12 +23,20 @@ use crate::rversion::*; use crate::run::*; use crate::utils::*; -pub fn check_installed(ver: &String) -> Result> { - let inst = sc_get_list()?; - if !inst.contains(&ver) { - bail!("R version {} is not installed", &ver); +pub fn check_installed(x: &String) -> Result> { + let inst = sc_get_list_details()?; + + for ver in inst { + if &ver.name == x { + return Ok(ver.name); + } + if ver.aliases.contains(x) { + debug!("Alias {} is resolved to version {}", x, ver.name); + return Ok(ver.name); + } } - Ok(true) + + bail!("R version {} is not installed", &x); } // -- rig default --------------------------------------------------------- diff --git a/src/macos.rs b/src/macos.rs index 0b67ccd..65fdcd3 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -245,10 +245,11 @@ pub fn sc_rm(args: &ArgMatches) -> Result<(), Box> { let default = sc_get_default()?; for ver in vers { - check_installed(&ver.to_string())?; + + let ver = check_installed(&ver.to_string())?; if let Some(ref default) = default { - if default == ver { + if default == &ver { warn!("Removing default version, set new default with \ rig default "); } @@ -376,6 +377,29 @@ pub fn find_aliases() -> Result, Box> { Ok(result) } +// Might not be needed in the end +pub fn resolve_alias(alias: &str) -> Result> { + let path = Path::new("/usr/local/bin").join("R-".to_string() + alias); + if !path.exists() { + bail!("Could not find alias: {}", alias); + } + match std::fs::read_link(&path) { + Err(_) => bail!("{} is not a symlink", path.display()), + Ok(target) => { + if !target.exists() { + bail!("Target does not exist at {}", target.display()); + + } else { + let version = version_from_link(target); + match version { + None => bail!("target file name not UTF-8"), + Some(v) => return Ok(v.to_string()) + }; + } + } + }; +} + // /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/bin/R -> // 4.2-arm64 fn version_from_link(pb: PathBuf) -> Option { @@ -419,7 +443,7 @@ pub fn sc_system_allow_debugger(args: &ArgMatches) -> Result<(), Box> }; for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; let path = PathBuf::new() .join(R_ROOT) .join(ver.as_str()) @@ -555,7 +579,7 @@ fn system_make_orthogonal(vers: Option>) -> Result<(), Box>) -> Result<(), Box>) -> Result<(), Box> { let re = Regex::new("[-]fopenmp")?; for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; let path = Path::new(R_ROOT).join(ver.as_str()); let makevars = path.join("Resources/etc/Makeconf".to_string()); if !makevars.exists() { @@ -767,7 +791,7 @@ fn set_cloud_mirror(vers: Option>) -> Result<(), Box> { info!("Setting default CRAN mirror"); for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; let path = Path::new(R_ROOT).join(ver.as_str()); let profile = path.join("Resources/library/base/R/Rprofile".to_string()); if !profile.exists() { @@ -809,8 +833,8 @@ pub fn sc_rstudio_(version: Option<&str>, let path; if let Some(ver) = version { - check_installed(&ver.to_string())?; - if !is_orthogonal(ver)? { + let ver = check_installed(&ver.to_string())?; + if !is_orthogonal(&ver)? { bail!("R {} is not orthogonal, it cannot run as a non-default. \ Run `rig system make-orthogonal`.", ver) } @@ -845,7 +869,7 @@ pub fn check_has_pak(ver: &String) -> Result> { } pub fn sc_set_default(ver: &str) -> Result<(), Box> { - check_installed(&ver.to_string())?; + let ver = check_installed(&ver.to_string())?; // Maybe it does not exist, ignore error here match std::fs::remove_file(R_CUR) { _ => {} diff --git a/src/main.rs b/src/main.rs index b0b28d8..ddcaada 100644 --- a/src/main.rs +++ b/src/main.rs @@ -203,13 +203,15 @@ fn sc_list(args: &ArgMatches, mainargs: &ArgMatches) -> Result<(), Box " (broken?)".to_string(), + None => "(broken?)".to_string(), Some(v) => { if v != ver.name { - format!(" (R {})", v) + format!("(R {})", v) } else { "".to_string() } From 0d3f35768710e157ca1217e90048e357cbe25305 Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Sun, 24 Jul 2022 15:25:48 +0200 Subject: [PATCH 05/16] Start with alias support on Linux - rig ls - rig system add-pak (all OS) - rig rm - rig default - set cloud mirror (not really needed) - RSPM setup (not really needed) - set sysreqs (not really needed) - rig rstudio --- src/common.rs | 2 +- src/linux.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++----- src/macos.rs | 5 +++ src/rversion.rs | 5 --- 4 files changed, 84 insertions(+), 14 deletions(-) diff --git a/src/common.rs b/src/common.rs index e93bf08..e5e6543 100644 --- a/src/common.rs +++ b/src/common.rs @@ -114,7 +114,7 @@ pub fn system_add_pak( }; for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; if update { info!("Installing pak for R {}", ver); } else { diff --git a/src/linux.rs b/src/linux.rs index 15275d8..328f600 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -10,7 +10,7 @@ use std::{file, line}; use clap::ArgMatches; use simple_error::*; -use simplelog::{debug, info, warn}; +use simplelog::{trace,debug, info, warn}; use crate::resolve::resolve_versions; use crate::rversion::*; @@ -214,9 +214,9 @@ pub fn sc_rm(args: &ArgMatches) -> Result<(), Box> { let vers = require_with!(vers, "clap error"); for ver in vers { - check_installed(&ver.to_string())?; + let ver = check_installed(&ver.to_string())?; - let pkgname = "r-".to_string() + ver; + let pkgname = "r-".to_string() + &ver; let out = try_with!( Command::new("dpkg").args(["-s", &pkgname]).output(), "Failed to run dpkg -s {} @{}:{}", @@ -314,6 +314,76 @@ pub fn sc_system_make_links() -> Result<(), Box> { Ok(()) } +pub fn re_alias() -> Regex { + let re= Regex::new("^R-(release|oldrel)$").unwrap(); + re +} + +pub fn find_aliases() -> Result, Box> { + debug!("Finding existing aliases"); + + let paths = std::fs::read_dir("/usr/local/bin")?; + let re = re_alias(); + let mut result: Vec = vec![]; + + for file in paths { + let path = file?.path(); + // If no path name, then path ends with ..., so we can skip + let fnamestr = match path.file_name() { + Some(x) => x, + None => continue, + }; + // If the path is not UTF-8, we'll skip it, this should not happen + let fnamestr = match fnamestr.to_str() { + Some(x) => x, + None => continue, + }; + if re.is_match(&fnamestr) { + trace!("Checking {}", path.display()); + match std::fs::read_link(&path) { + Err(_) => debug!("{} is not a symlink", path.display()), + Ok(target) => { + if !target.exists() { + debug!("Target does not exist at {}", target.display()); + + } else { + let version = version_from_link(target); + match version { + None => continue, + Some(version) => { + trace!("{} -> {}", fnamestr, version); + let als = Alias { + alias: fnamestr[2..].to_string(), + version: version.to_string() + }; + result.push(als); + } + }; + } + } + }; + } + } + + Ok(result) +} + +fn version_from_link(pb: PathBuf) -> Option { + let osver = match pb.parent() + .and_then(|x| x.parent()) + .and_then(|x| x.file_name()) { + None => None, + Some(s) => Some(s.to_os_string()) + }; + + let s = match osver { + None => None, + Some(os) => os.into_string().ok() + }; + + s +} + pub fn get_resolve(args: &ArgMatches) -> Result> { let str = args .value_of("str") @@ -362,7 +432,7 @@ pub fn sc_get_list() -> Result, Box> { pub fn sc_set_default(ver: &str) -> Result<(), Box> { escalate("setting the default R version")?; - check_installed(&ver.to_string())?; + let ver = check_installed(&ver.to_string())?; // Remove current link if Path::new(R_CUR).exists() { @@ -409,7 +479,7 @@ fn set_cloud_mirror(vers: Option>) -> Result<(), Box> { info!("Setting default CRAN mirror"); for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; let path = Path::new(R_ROOT).join(ver.as_str()); let profile = path.join("lib/R/library/base/R/Rprofile".to_string()); if !profile.exists() { @@ -454,7 +524,7 @@ options(HTTPUserAgent = sprintf("R/%s R (%s)", getRversion(), paste(getRversion( let rcode = rcode.to_string().replace("%url%", &linux.rspm_url); for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; let path = Path::new(R_ROOT).join(ver.as_str()); let profile = path.join("lib/R/library/base/R/Rprofile".to_string()); if !profile.exists() { @@ -487,7 +557,7 @@ Sys.setenv(PKG_SYSREQS = "true") "#; for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; let path = Path::new(R_ROOT).join(ver.as_str()); let profile = path.join("lib/R/library/base/R/Rprofile".to_string()); if !profile.exists() { @@ -684,7 +754,7 @@ pub fn sc_rstudio_(version: Option<&str>, project: Option<&str>, arg: Option<&Os let mut envname = "dummy"; let mut path = "".to_string(); if let Some(ver) = version { - check_installed(&ver.to_string())?; + let ver = check_installed(&ver.to_string())?; envname = "RSTUDIO_WHICH_R"; path = R_ROOT.to_string() + "/" + &ver + "/bin/R" }; diff --git a/src/macos.rs b/src/macos.rs index 65fdcd3..e336a1c 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -330,6 +330,11 @@ pub fn sc_system_make_links() -> Result<(), Box> { Ok(()) } +pub fn re_alias() -> Regex { + let re= Regex::new("^R-(next|devel|release|oldrel)$").unwrap(); + re +} + pub fn find_aliases() -> Result, Box> { debug!("Finding existing aliaes"); diff --git a/src/rversion.rs b/src/rversion.rs index 53526fc..0282e70 100644 --- a/src/rversion.rs +++ b/src/rversion.rs @@ -81,8 +81,3 @@ pub struct Alias { pub alias: String, pub version: String, } - -pub fn re_alias() -> Regex { - let re= Regex::new("^R-(next|devel|release|oldrel)$").unwrap(); - re -} From 70cbce25efce2a79b4c626ac7aa6a0f88269d399 Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Sun, 24 Jul 2022 16:13:30 +0200 Subject: [PATCH 06/16] rig add create alias(es) on Linux --- src/alias.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/linux.rs | 8 ++++++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/alias.rs b/src/alias.rs index 9decd1d..ae5dc46 100644 --- a/src/alias.rs +++ b/src/alias.rs @@ -18,6 +18,7 @@ use crate::linux::*; use crate::escalate::*; +#[cfg(target_os = "macos")] pub fn get_alias(args: &ArgMatches) -> Option { match args.value_of("str") { None => None, @@ -31,6 +32,20 @@ pub fn get_alias(args: &ArgMatches) -> Option { } } +#[cfg(target_os = "linux")] +pub fn get_alias(args: &ArgMatches) -> Option { + match args.value_of("str") { + None => None, + Some(str) => { + match str { + "oldrel" | "oldrel/1" => Some("oldrel".to_string()), + "release" => Some(str.to_string()), + _ => None + } + } + } +} + #[cfg(target_os = "macos")] pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { let msg = "Adding R-".to_string() + alias + " alias"; @@ -88,6 +103,52 @@ pub fn add_alias(ver: String, alias: String) { } #[cfg(target_os = "linux")] -pub fn add_alias(ver: String, alias: String) { - // TODO +pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { + let msg = "Adding R-".to_string() + alias + " alias"; + escalate(&msg)?; + + info!("Adding R-{} alias to R {}", alias, ver); + + let base = Path::new(R_ROOT); + let target = base.join(ver).join("bin/R"); + let linkfile = Path::new("/usr/local/bin/").join("R-".to_string() + alias); + + // If it exists then we check that it points to the right place + // Cannot use .exists(), because it follows symlinks + let meta = std::fs::symlink_metadata(&linkfile); + if meta.is_ok() { + match std::fs::read_link(&linkfile) { + Err(_) => bail!("{} is not a symlink, aborting", linkfile.display()), + Ok(xtarget) => { + if xtarget == target { + return Ok(()) + } else { + debug!("{} is wrong, updating", linkfile.display()); + match std::fs::remove_file(&linkfile) { + Err(err) => { + bail!( + "Failed to delete {}, cannot update alias: {}", + linkfile.display(), + err.to_string() + ); + }, + _ => {} + } + } + } + } + } + + // If we are still here, then we need to create the link + debug!("Adding {} -> {}", linkfile.display(), target.display()); + match symlink(&target, &linkfile) { + Err(err) => bail!( + "Cannot create alias {}: {}", + linkfile.display(), + err.to_string() + ), + _ => {} + }; + + Ok(()) } diff --git a/src/linux.rs b/src/linux.rs index 328f600..5c3bf9b 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -15,6 +15,7 @@ use simplelog::{trace,debug, info, warn}; use crate::resolve::resolve_versions; use crate::rversion::*; +use crate::alias::*; use crate::common::*; use crate::download::*; use crate::escalate::*; @@ -73,7 +74,8 @@ pub fn sc_add(args: &ArgMatches) -> Result<(), Box> { } let linux = detect_linux()?; - let version = get_resolve(args)?; + let mut version = get_resolve(args)?; + let alias = get_alias(args); let ver = version.version.to_owned(); let verstr = match ver { Some(ref x) => x, @@ -108,6 +110,10 @@ pub fn sc_add(args: &ArgMatches) -> Result<(), Box> { library_update_rprofile(&dirname.to_string())?; sc_system_make_links()?; + match alias { + Some(alias) => add_alias(&dirname, &alias)?, + None => { } + }; if !args.is_present("without-cran-mirror") { set_cloud_mirror(Some(vec![dirname.to_string()]))?; From 68ad45e35d3e77247468ca3f2544f2cd97c8a02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sun, 24 Jul 2022 10:57:48 -0400 Subject: [PATCH 07/16] Remove dangling aliases when updating links (macOS) So they are also removed after `rig rm`. Plus remove function that resolves an alias, we don't need it, apparently. --- src/macos.rs | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/src/macos.rs b/src/macos.rs index e336a1c..2e988a8 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -275,7 +275,7 @@ pub fn sc_system_make_links() -> Result<(), Box> { let vers = sc_get_list()?; let base = Path::new(R_ROOT); - info!("Adding R-* quick links (if needed)"); + info!("Updating R-* quick links (as needed)"); // Create new links for ver in vers { @@ -297,6 +297,7 @@ pub fn sc_system_make_links() -> Result<(), Box> { // Remove dangling links let paths = std::fs::read_dir("/usr/local/bin")?; let re = Regex::new("^R-[0-9]+[.][0-9]+")?; + let re2 = re_alias(); for file in paths { let path = file?.path(); // If no path name, then path ends with ..., so we can skip @@ -309,7 +310,7 @@ pub fn sc_system_make_links() -> Result<(), Box> { Some(x) => x, None => continue, }; - if re.is_match(&fnamestr) { + if re.is_match(&fnamestr) || re2.is_match(&fnamestr) { match std::fs::read_link(&path) { Err(_) => debug!("{} is not a symlink", path.display()), Ok(target) => { @@ -382,29 +383,6 @@ pub fn find_aliases() -> Result, Box> { Ok(result) } -// Might not be needed in the end -pub fn resolve_alias(alias: &str) -> Result> { - let path = Path::new("/usr/local/bin").join("R-".to_string() + alias); - if !path.exists() { - bail!("Could not find alias: {}", alias); - } - match std::fs::read_link(&path) { - Err(_) => bail!("{} is not a symlink", path.display()), - Ok(target) => { - if !target.exists() { - bail!("Target does not exist at {}", target.display()); - - } else { - let version = version_from_link(target); - match version { - None => bail!("target file name not UTF-8"), - Some(v) => return Ok(v.to_string()) - }; - } - } - }; -} - // /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/bin/R -> // 4.2-arm64 fn version_from_link(pb: PathBuf) -> Option { From 86ec1be40336ad49de06228f6913638e7df24b5d Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Mon, 25 Jul 2022 10:46:02 +0200 Subject: [PATCH 08/16] Remove dangling links for alises after `rig rm` Or whenever we run the link update, internally, or explicitly, really. --- src/linux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linux.rs b/src/linux.rs index 5c3bf9b..e4d5831 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -287,7 +287,7 @@ pub fn sc_system_make_links() -> Result<(), Box> { // Remove dangling links let paths = std::fs::read_dir("/usr/local/bin")?; - let re = Regex::new("^R-[0-9]+[.][0-9]+")?; + let re = Regex::new("^R-([0-9]+[.][0-9]+[.][0-9]+|oldrel|next|release|devel)$")?; for file in paths { let path = file?.path(); // If no path name, then path ends with ..., so we can skip From 333ff9113c5fd586157ae9301818ea08dd5c9ff7 Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Mon, 25 Jul 2022 10:50:35 +0000 Subject: [PATCH 09/16] rig add adds alias on Windows --- src/alias.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- src/windows.rs | 28 +++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/alias.rs b/src/alias.rs index ae5dc46..ce649b0 100644 --- a/src/alias.rs +++ b/src/alias.rs @@ -1,8 +1,12 @@ use std::error::Error; -use std::os::unix::fs::symlink; +use std::io::Write; +use std::fs::File; use std::path::Path; +#[cfg(any(target_os = "macos", target_os = "linux"))] +use std::os::unix::fs::symlink; + use clap::ArgMatches; use simple_error::*; use simplelog::*; @@ -46,6 +50,20 @@ pub fn get_alias(args: &ArgMatches) -> Option { } } +#[cfg(target_os = "windows")] +pub fn get_alias(args: &ArgMatches) -> Option { + match args.value_of("str") { + None => None, + Some(str) => { + match str { + "oldrel" | "oldrel/1" => Some("oldrel".to_string()), + "release" | "next" => Some(str.to_string()), + _ => None + } + } + } +} + #[cfg(target_os = "macos")] pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { let msg = "Adding R-".to_string() + alias + " alias"; @@ -98,8 +116,33 @@ pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { } #[cfg(target_os = "windows")] -pub fn add_alias(ver: String, alias: String) { - // TODO +pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { + let base = Path::new(R_ROOT); + let bin = base.join("bin"); + + // should exist at this point, but make sure + std::fs::create_dir_all(&bin)?; + + let filename = "R-".to_string() + alias + ".bat"; + let linkfile = bin.join(&filename); + let target = base.join("R-".to_string() + ver); + + let cnt = "@\"C:\\Program Files\\R\\R-".to_string() + &ver + "\\bin\\R\" %*\n"; + let op; + if linkfile.exists() { + op = "Updating"; + let orig = std::fs::read_to_string(&linkfile)?; + if orig == cnt { + return Ok(()); + } + } else { + op = "Adding"; + }; + info!("{} R-{} -> {} alias", op, alias, ver); + let mut file = File::create(&linkfile)?; + file.write_all(cnt.as_bytes())?; + + Ok(()) } #[cfg(target_os = "linux")] diff --git a/src/windows.rs b/src/windows.rs index 7f314f5..1beae8e 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -18,12 +18,13 @@ use simplelog::{debug, info, warn}; use winreg::enums::*; use winreg::RegKey; +use crate::alias::*; use crate::common::*; use crate::download::*; use crate::escalate::*; use crate::library::*; use crate::resolve::resolve_versions; -use crate::rversion::Rversion; +use crate::rversion::*; use crate::run::*; use crate::utils::*; @@ -35,6 +36,7 @@ pub const R_BINPATH: &str = "R-{}\\bin\\R.exe"; #[warn(unused_variables)] pub fn sc_add(args: &ArgMatches) -> Result<(), Box> { escalate("adding new R version")?; + let alias = get_alias(args); sc_clean_registry()?; let str = args .value_of("str") @@ -75,6 +77,15 @@ pub fn sc_add(args: &ArgMatches) -> Result<(), Box> { } }; sc_system_make_links()?; + match dirname { + None => {}, + Some(ref dirname) => { + match alias { + Some(alias) => add_alias(&dirname, &alias)?, + None => { } + } + } + }; patch_for_rtools()?; maybe_update_registry_default()?; @@ -428,6 +439,21 @@ pub fn sc_system_make_links() -> Result<(), Box> { Ok(()) } +fn re_alias() -> Regex { + let re = Regex::new("^R-(oldrel|release|next)$").unwrap(); + re +} + +pub fn find_aliases() -> Result, Box> { + debug!("Finding existing aliases"); + + let mut result: Vec = vec![]; + + // TODO + + Ok(result) +} + pub fn sc_system_allow_core_dumps(_args: &ArgMatches) -> Result<(), Box> { // Nothing to do on Windows Ok(()) From 99c513df800baded401ce4bd2ad0df192cf219df Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Thu, 28 Jul 2022 18:01:48 +0000 Subject: [PATCH 10/16] Windows aliases: support `rig ls` Plus fix alias cleanup. --- src/windows.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/src/windows.rs b/src/windows.rs index 1beae8e..2ddc07c 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -14,7 +14,7 @@ use std::{thread, time}; use clap::ArgMatches; use remove_dir_all::remove_dir_all; use simple_error::{bail, SimpleError}; -use simplelog::{debug, info, warn}; +use simplelog::*; use winreg::enums::*; use winreg::RegKey; @@ -411,6 +411,7 @@ pub fn sc_system_make_links() -> Result<(), Box> { } // Delete the ones we don't need + let re_als = re_alias(); let old_links = std::fs::read_dir(base.join("bin"))?; for path in old_links { let path = path?; @@ -423,6 +424,13 @@ pub fn sc_system_make_links() -> Result<(), Box> { if !filename.starts_with("R-") { continue; } + if re_als.is_match(&filename) { + let rver = find_r_version_in_link(&path.path())?; + let realname = "R-".to_string() + &rver + ".bat"; + if new_links.contains(&realname) { + continue; + } + } if !new_links.contains(&filename) { info!("Deleting unused {}", filename); match std::fs::remove_file(path.path()) { @@ -440,20 +448,62 @@ pub fn sc_system_make_links() -> Result<(), Box> { } fn re_alias() -> Regex { - let re = Regex::new("^R-(oldrel|release|next)$").unwrap(); + let re = Regex::new("^R-(oldrel|release|next)[.]bat$").unwrap(); re } pub fn find_aliases() -> Result, Box> { debug!("Finding existing aliases"); + let bin = Path::new(R_ROOT).join("bin"); + let paths = std::fs::read_dir(bin)?; + let re = re_alias(); let mut result: Vec = vec![]; + let re_cmd = Regex::new("R\\R-4.1.3\\bin\\R\\"); - // TODO + for file in paths { + let path = file?.path(); + // If no path name, then path ends with ..., so we can skip + let fnamestr = match path.file_name() { + Some(x) => x, + None => continue, + }; + // If the path is not UTF-8, we'll skip it, this should not happen + let fnamestr = match fnamestr.to_str() { + Some(x) => x, + None => continue, + }; + if re.is_match(&fnamestr) { + trace!("Checking {}", path.display()); + let rver = find_r_version_in_link(&path)?; + let als = Alias { + alias: fnamestr[2..fnamestr.len()-4].to_string(), + version: rver + }; + result.push(als); + } + } Ok(result) } +fn find_r_version_in_link(path: &PathBuf) -> Result> { + let lines = read_lines(path)?; + if lines.len() == 0 { + bail!("Invalid R link file: {}", path.display()); + } + let split = lines[0].split("\\").collect::>(); + for s in split { + if s == "R-devel" { + return Ok("devel".to_string()); + } + if s.starts_with("R-") { + return Ok(s[2..].to_string()); + } + } + bail!("Cannot extract R version from {}, invalid R link file?", path.display()); +} + pub fn sc_system_allow_core_dumps(_args: &ArgMatches) -> Result<(), Box> { // Nothing to do on Windows Ok(()) From f7105fa69efa7620f9dc4d78f1c1f54ce16252e9 Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Thu, 28 Jul 2022 20:27:18 +0200 Subject: [PATCH 11/16] Eliminate rustc warnings --- src/download.rs | 3 +++ src/linux.rs | 2 +- src/rversion.rs | 1 - src/utils.rs | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/download.rs b/src/download.rs index 62043a6..4aa2300 100644 --- a/src/download.rs +++ b/src/download.rs @@ -2,6 +2,7 @@ use futures::future; use futures_util::StreamExt; use std::error::Error; use std::ffi::OsStr; +#[cfg(any(target_os = "macos", target_os = "windows"))] use std::ffi::OsString; use std::fs::File; use std::io::Write; @@ -11,10 +12,12 @@ use std::path::Path; use clap::ArgMatches; use simple_error::bail; +#[cfg(any(target_os = "macos", target_os = "windows"))] use simplelog::info; #[cfg(target_os = "windows")] use crate::rversion::Rversion; +#[cfg(any(target_os = "macos", target_os = "windows"))] use crate::utils::*; #[cfg(target_os = "windows")] use crate::windows::*; diff --git a/src/linux.rs b/src/linux.rs index 16ce6d0..32a42a4 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -76,7 +76,7 @@ pub fn sc_add(args: &ArgMatches) -> Result<(), Box> { } let linux = detect_linux()?; - let mut version = get_resolve(args)?; + let version = get_resolve(args)?; let alias = get_alias(args); let ver = version.version.to_owned(); let verstr = match ver { diff --git a/src/rversion.rs b/src/rversion.rs index 0282e70..538bc2a 100644 --- a/src/rversion.rs +++ b/src/rversion.rs @@ -1,5 +1,4 @@ -use regex::Regex; use std::cmp::Ordering; #[cfg(any(target_os = "macos", target_os = "linux"))] diff --git a/src/utils.rs b/src/utils.rs index f9edaf6..8f47b39 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -23,6 +23,7 @@ pub fn os(x: &str) -> OsString { ostr } +#[cfg(any(target_os = "macos", target_os = "windows"))] pub fn osjoin(x: Vec, sep: &str) -> String { let mut buffer = String::new(); From 8699a40e67e25a8b3ad750dfb7c67421685e9363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 28 Jul 2022 14:15:01 -0400 Subject: [PATCH 12/16] Unused code cleanup --- src/alias.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/alias.rs b/src/alias.rs index ce649b0..f78f4ac 100644 --- a/src/alias.rs +++ b/src/alias.rs @@ -1,6 +1,8 @@ use std::error::Error; +#[cfg(target_os = "windows")] use std::io::Write; +#[cfg(target_os = "windows")] use std::fs::File; use std::path::Path; From 4897862a13946532616c750339a22e8eb9c68d14 Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Thu, 4 Aug 2022 10:39:31 +0000 Subject: [PATCH 13/16] fix warnings on Windows --- src/alias.rs | 4 +++- src/windows.rs | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/alias.rs b/src/alias.rs index f78f4ac..ae3b01b 100644 --- a/src/alias.rs +++ b/src/alias.rs @@ -10,6 +10,7 @@ use std::path::Path; use std::os::unix::fs::symlink; use clap::ArgMatches; +#[cfg(any(target_os = "macos", target_os = "linux"))] use simple_error::*; use simplelog::*; @@ -119,6 +120,8 @@ pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { #[cfg(target_os = "windows")] pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { + let msg = "Adding R-".to_string() + alias + " alias"; + escalate(&msg)?; let base = Path::new(R_ROOT); let bin = base.join("bin"); @@ -127,7 +130,6 @@ pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box> { let filename = "R-".to_string() + alias + ".bat"; let linkfile = bin.join(&filename); - let target = base.join("R-".to_string() + ver); let cnt = "@\"C:\\Program Files\\R\\R-".to_string() + &ver + "\\bin\\R\" %*\n"; let op; diff --git a/src/windows.rs b/src/windows.rs index 2ddc07c..8c54ca2 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -459,7 +459,6 @@ pub fn find_aliases() -> Result, Box> { let paths = std::fs::read_dir(bin)?; let re = re_alias(); let mut result: Vec = vec![]; - let re_cmd = Regex::new("R\\R-4.1.3\\bin\\R\\"); for file in paths { let path = file?.path(); From 11a5501ed2c2a0f9071f1456e4d1a3e36c31a0ac Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Fri, 5 Aug 2022 08:09:20 +0000 Subject: [PATCH 14/16] Win alias: fix rig ls when no R versions are installed and the Program Files/R/bin directory does not exist. --- src/windows.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/windows.rs b/src/windows.rs index 8c54ca2..4f3b65f 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -455,10 +455,15 @@ fn re_alias() -> Regex { pub fn find_aliases() -> Result, Box> { debug!("Finding existing aliases"); + let mut result: Vec = vec![]; let bin = Path::new(R_ROOT).join("bin"); + + if !bin.exists() { + return Ok(result); + } + let paths = std::fs::read_dir(bin)?; let re = re_alias(); - let mut result: Vec = vec![]; for file in paths { let path = file?.path(); From 93329b70809244ffbcdcd5e91f591e3322a71536 Mon Sep 17 00:00:00 2001 From: Gabor Csardi Date: Sat, 6 Aug 2022 05:35:31 +0000 Subject: [PATCH 15/16] Win: allow aliases in commands - `rig rm` - `rig rstudio` - `rig system *` --- src/windows.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/windows.rs b/src/windows.rs index 4f3b65f..1e1f1c9 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -263,7 +263,7 @@ fn set_cloud_mirror(vers: Option>) -> Result<(), Box> { info!("Setting default CRAN mirror"); for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; let path = Path::new(R_ROOT).join("R-".to_string() + ver.as_str()); let profile = path.join("library/base/R/Rprofile".to_string()); if !profile.exists() { @@ -296,7 +296,7 @@ options(repos = c(RSPM="https://packagemanager.rstudio.com/all/latest", getOptio "#; for ver in vers { - check_installed(&ver)?; + let ver = check_installed(&ver)?; let path = Path::new(R_ROOT).join("R-".to_string() + ver.as_str()); let profile = path.join("library/base/R/Rprofile".to_string()); if !profile.exists() { @@ -324,10 +324,10 @@ pub fn sc_rm(args: &ArgMatches) -> Result<(), Box> { rm_rtools(verstr)?; continue; } - check_installed(&verstr)?; + let ver = check_installed(&verstr)?; if let Some(ref default) = default { - if default == ver { + if default == &ver { warn!("Removing default version, set new default with \ rig default "); match unset_default() { @@ -337,7 +337,7 @@ pub fn sc_rm(args: &ArgMatches) -> Result<(), Box> { } } - let ver = "R-".to_string() + ver; + let ver = "R-".to_string() + &ver; let dir = Path::new(R_ROOT); let dir = dir.join(ver); info!("Removing {}", dir.display()); @@ -587,7 +587,7 @@ pub fn sc_get_list() -> Result, Box> { } pub fn sc_set_default(ver: &str) -> Result<(), Box> { - check_installed(&ver.to_string())?; + let ver = check_installed(&ver.to_string())?; escalate("setting the default R version")?; let base = Path::new(R_ROOT); let bin = base.join("bin"); @@ -862,7 +862,7 @@ pub fn sc_rstudio_(version: Option<&str>, project: Option<&str>, arg: Option<&Os if let Some(version) = version { let ver = version.to_string(); - check_installed(&ver)?; + let ver = check_installed(&ver)?; update_registry_default_to(&ver)?; } From f5f7c713a4fdfd43025d0c99358f0d91346cda4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sat, 6 Aug 2022 07:53:06 +0200 Subject: [PATCH 16/16] NEWS about aliases [ci skip] --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 85bedeb..79d5053 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,9 @@ * rig now prints output from `apt`, etc. like regular logging output on Linux. +* rig now supports the alises `oldrel`, `release`, `next`, `devel` in + `rig default`, `rig rm`, `rig rstudio`, etc. (#108). + # rig 0.5.0 * rig can now open renv projects in RStudio, with the correct R version.