Skip to content

Commit

Permalink
Merge pull request #110 from r-lib/feature/aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
gaborcsardi authored Aug 6, 2022
2 parents 35555b4 + f5f7c71 commit 34cace4
Show file tree
Hide file tree
Showing 13 changed files with 531 additions and 55 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
201 changes: 201 additions & 0 deletions src/alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@

use std::error::Error;
#[cfg(target_os = "windows")]
use std::io::Write;
#[cfg(target_os = "windows")]
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;
#[cfg(any(target_os = "macos", target_os = "linux"))]
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::*;

#[cfg(target_os = "macos")]
pub fn get_alias(args: &ArgMatches) -> Option<String> {
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 = "linux")]
pub fn get_alias(args: &ArgMatches) -> Option<String> {
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 = "windows")]
pub fn get_alias(args: &ArgMatches) -> Option<String> {
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<dyn Error>> {
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: &str, alias: &str) -> Result<(), Box<dyn Error>> {
let msg = "Adding R-".to_string() + alias + " alias";
escalate(&msg)?;
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 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")]
pub fn add_alias(ver: &str, alias: &str) -> Result<(), Box<dyn Error>> {
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(())
}
30 changes: 23 additions & 7 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,20 @@ use crate::rversion::*;
use crate::run::*;
use crate::utils::*;

pub fn check_installed(ver: &String) -> Result<bool, Box<dyn Error>> {
let inst = sc_get_list()?;
if !inst.contains(&ver) {
bail!("R version <b>{}</b> is not installed", &ver);
pub fn check_installed(x: &String) -> Result<String, Box<dyn Error>> {
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 <b>{}</b> is not installed", &x);
}

// -- rig default ---------------------------------------------------------
Expand All @@ -55,6 +63,7 @@ pub fn set_default_if_none(ver: String) -> Result<(), Box<dyn Error>> {

pub fn sc_get_list_details() -> Result<Vec<InstalledVersion>, Box<dyn Error>> {
let names = sc_get_list()?;
let aliases = find_aliases()?;
let mut res: Vec<InstalledVersion> = vec![];
let re = Regex::new("^Version:[ ]?")?;

Expand All @@ -74,11 +83,18 @@ pub fn sc_get_list_details() -> Result<Vec<InstalledVersion>, Box<dyn Error>> {
};
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<String> = 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
});
}

Expand All @@ -98,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 {
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn empty_stringmap() -> HashMap<String, String> {
fn rig_config_file() -> Result<PathBuf, Box<dyn Error>> {
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");
Expand Down
3 changes: 3 additions & 0 deletions src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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::*;
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use lazy_static::lazy_static;
use libc;
use simple_error::bail;

mod alias;
mod args;
mod common;
mod config;
Expand Down
Loading

0 comments on commit 34cace4

Please sign in to comment.