Skip to content

Commit

Permalink
Ensure R doesn't run the .Rprofile on Windows (#581)
Browse files Browse the repository at this point in the history
  • Loading branch information
DavisVaughan authored Oct 15, 2024
1 parent 738afba commit 564e419
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
7 changes: 7 additions & 0 deletions crates/ark/src/sys/windows/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use libr::R_DefParamsEx;
use libr::R_HomeDir;
use libr::R_SetParams;
use libr::R_SignalHandlers;
use libr::Rboolean_FALSE;
use stdext::cargs;

use crate::interface::r_busy;
Expand Down Expand Up @@ -69,6 +70,12 @@ pub fn setup_r(mut _args: Vec<*mut c_char>) {
(*params).R_Interactive = 1;
(*params).CharacterMode = libr::UImode_RGui;

// Never load the user or site `.Rprofile`s during `setup_Rmainloop()`.
// We do it for the user once ark is ready. We faithfully reimplement
// R's behavior for finding these files in `startup.rs`.
(*params).LoadInitFile = Rboolean_FALSE;
(*params).LoadSiteFile = Rboolean_FALSE;

(*params).WriteConsole = None;
(*params).WriteConsoleEx = Some(r_write_console);
(*params).ReadConsole = Some(r_read_console);
Expand Down
50 changes: 50 additions & 0 deletions crates/ark/tests/r-profile-once.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::io::Write;

use amalthea::fixtures::dummy_frontend::ExecuteRequestOptions;
use ark::fixtures::DummyArkFrontendRprofile;

// SAFETY:
// Do not write any other tests related to `.Rprofile` in
// this integration test file. We can only start R up once
// per process, so we can only run one `.Rprofile`. Use a
// separate integration test (i.e. separate process) if you
// need to test more details related to `.Rprofile` usage.

/// See https://github.com/posit-dev/positron/issues/4253
#[test]
fn test_r_profile_is_only_run_once() {
// The trailing `\n` is critical, otherwise R's `source()` silently fails
let contents = r#"
if (exists("x")) {
x <- 2
} else {
x <- 1
}
"#;

// Write `contents` to a tempfile that we declare to be
// the `.Rprofile` that R should use
let mut file = tempfile::NamedTempFile::new().unwrap();
write!(file, "{contents}").unwrap();

let path = file.path();
let path = path.to_str().unwrap();

unsafe { std::env::set_var("R_PROFILE_USER", path) };

// Ok, start R. If we've set everything correctly, R should not run
// the `.Rprofile`, but ark should - i.e. it should run exactly 1 time.
let frontend = DummyArkFrontendRprofile::lock();

frontend.send_execute_request("x", ExecuteRequestOptions::default());
frontend.recv_iopub_busy();

let input = frontend.recv_iopub_execute_input();
assert_eq!(input.code, "x");
assert_eq!(frontend.recv_iopub_execute_result(), "[1] 1");

frontend.recv_iopub_idle();

assert_eq!(frontend.recv_shell_execute_reply(), input.execution_count);
}

0 comments on commit 564e419

Please sign in to comment.