Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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