Skip to content

Commit

Permalink
rig rstudio --config-path on Windows
Browse files Browse the repository at this point in the history
Towards fixing #134.
  • Loading branch information
gaborcsardi committed Aug 18, 2023
1 parent e8f67ab commit 2e7b2db
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 1 deletion.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ tokio = { version = "1", features = ["full"] }
[target.'cfg(windows)'.dependencies]
is_elevated = "0.1.2"
remove_dir_all = "0.7.0"
whoami = "1.4.1"
winreg = "0.10"

[build-dependencies]
Expand Down
9 changes: 8 additions & 1 deletion src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,14 @@ pub fn rig_app() -> Command {
Arg::new("project-file")
.help("RStudio project file (.Rproj) to open")
.required(false),
);
)
.arg(
Arg::new("config-path")
.help("Do not start RStudio, only print the path of the RStudio config directory")
.long("config-path")
.required(false)
.num_args(0)
);

let cmd_library = Command::new("library")
.about("Manage package libraries [alias: lib] (experimental)")
Expand Down
9 changes: 9 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ pub fn sc_rstudio(args: &ArgMatches) -> Result<(), Box<dyn Error>> {
let mut ver: Option<&String> = args.get_one("version");
let mut prj: Option<&String> = args.get_one("project-file");

if args.get_flag("config-path") {
let cp = get_rstudio_config_path();
match cp {
Ok(x) => println!("{}", x.display()),
Err(x) => bail!("Error: {}", x.to_string())
};
return Ok(());
}

if let Some(ver2) = ver {
if ver2.ends_with("renv.lock") {
let lockfile = PathBuf::new().join(ver2);
Expand Down
122 changes: 122 additions & 0 deletions src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ use std::process::Command;
use std::{thread, time};

use clap::ArgMatches;
use directories::BaseDirs;
use remove_dir_all::remove_dir_all;
use semver;
use simple_error::{bail, SimpleError};
use simplelog::*;
use whoami::{hostname, username};
use winreg::enums::*;
use winreg::RegKey;

Expand Down Expand Up @@ -867,6 +869,126 @@ fn get_latest_install_path() -> Result<Option<String>, Box<dyn Error>> {
Ok(None)
}

// All this is from https://github.com/rstudio/rstudio/blob/44f09c50d469a14d5a9c3840c7a239f3bf21ace9/src/cpp/core/system/Xdg.cpp#L85
//
// 1. RSTUDIO_CONFIG_HOME might point to the final path.
// 2. XDG_CONFIG_HOME might point to the user config path (append RStudio).
// 3. Otherwise query FOLDERID_RoamingAppData for the user config path.
// 4. Or fall back to `~/.config` if that fails (it really should not).
// 5. Set USER, HOME and HOSTNAME env vars for expansion.
// 6. Expand env vars, both $ENV and ${ENV} types.
// 7. Expand ~ to home dir
//
// 5-6 are only needed if the path has a '$' or '~' character.
// 7 is only needed if the path has a '~' character or if it is empty.

pub fn get_rstudio_config_path() -> Result<std::path::PathBuf, Box<dyn Error>> {
let mut final_path = true;
let mut xdg: Option<std::path::PathBuf> = None;

// RSTUDIO_CONFIG_HOME may point to the final path
match std::env::var("RSTUDIO_CONFIG_HOME") {
Ok(x) => xdg = Some(std::path::PathBuf::from(x)),
Err(_) => { }
};

// XDG_CONFIG_HOME may point to the user config path
if xdg.is_none() {
final_path = false;
match std::env::var("XDG_CONFIG_HOME") {
Ok(x) => {
let mut xdg2 = std::path::PathBuf::new();
xdg2.push(x);
xdg = Some(xdg2);
},
Err(_) => { }
};
}

// Get user config path from system
if xdg.is_none() {
if let Some(bd) = BaseDirs::new() {
xdg = Some(std::path::PathBuf::from(bd.config_dir()));
}
}

// Fall back to `~/.config`
if xdg.is_none() {
xdg = Some(std::path::PathBuf::from("~/.config"));
}

// We have a path at this point
let xdg = xdg.unwrap();

// Set USER, HOME, HOSTNAME, for expansion, if needed
let mut path = match xdg.to_str() {
Some(x) => String::from(x),
None => bail!("RStudio config path cannot be represented as Unicode. :(")
};
let has_dollar = path.contains("$");
let empty = path.len() == 0;
let has_tilde = path.contains("~");

if has_dollar || empty || has_tilde {
match std::env::var("USER") {
Ok(_) => { },
Err(_) => {
let username = username();
std::env::set_var("USER", username);
}
};
}

if has_dollar {
match std::env::var("HOME") {
Ok(_) => { },
Err(_) => {
let bd = BaseDirs::new();
match bd {
Some(x) => {
std::env::set_var("HOME", x.home_dir().as_os_str());
},
None => {
warn!("Cannot determine HOME directory");
}
};
}
};
}

if has_dollar {
match std::env::var("HOSTNAME") {
Ok(_) => { },
Err(_) => {
let hostname = hostname();
std::env::set_var("HOSTNAME", hostname);
}
};
}

// Expand env vars
if has_dollar {
path = match shellexpand::env(&path) {
Ok(x) => x.to_string(),
Err(e) => {
bail!("RStudio config path contains unknown environment variable: {}", e.var_name);
}
};
}

// Expand empty path and ~
if empty || has_tilde {
path = shellexpand::tilde(&path).to_string();
}

let mut xdg = std::path::PathBuf::from(path);
if !final_path {
xdg.push("RStudio");
}

Ok(xdg)
}

pub fn sc_rstudio_(version: Option<&str>, project: Option<&str>, arg: Option<&OsStr>)
-> Result<(), Box<dyn Error>> {
// we only need to restore if 'ver' is given, there is a default and
Expand Down

0 comments on commit 2e7b2db

Please sign in to comment.