use crate::config::RSourceStatus;
use crate::external;
use anyhow::{Context, Result};
use std::path::PathBuf;
#[derive(Debug)]
pub(super) struct ResolvedRSource {
pub(super) status: RSourceStatus,
pub(super) r_home: Option<PathBuf>,
}
pub(super) fn resolve_r_home_from_path(path: &std::path::Path) -> Result<std::path::PathBuf> {
let r_binary = path.join("bin").join("R");
if r_binary.exists() {
let output = std::process::Command::new(&r_binary)
.arg("RHOME")
.output()
.with_context(|| format!("Failed to run {} RHOME", r_binary.display()))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("{} RHOME failed: {}", r_binary.display(), stderr);
}
let r_home = arf_libr::r_home_from_rhome_output(&String::from_utf8_lossy(&output.stdout))
.unwrap_or_default();
if r_home.is_empty() {
anyhow::bail!("{} RHOME returned empty result", r_binary.display());
}
log::debug!(
"Resolved R_HOME from installation prefix: {} -> {}",
path.display(),
r_home
);
return Ok(std::path::PathBuf::from(r_home));
}
let renviron = path.join("etc").join("Renviron");
if !renviron.exists() {
log::warn!(
"Path {} does not look like R_HOME (missing etc/Renviron). \
Consider providing the installation prefix instead.",
path.display()
);
}
Ok(path.to_path_buf())
}
pub(super) fn setup_r_via_rig(version_spec: &str) -> Result<ResolvedRSource> {
if let Err(error) = external::rig::rig_available() {
let context = match &error {
external::rig::RigError::NotInstalled => {
"--with-r-version requires rig to be installed.\n\
Install rig from https://github.com/r-lib/rig"
}
external::rig::RigError::CommandFailed(_) => {
"Failed to run rig while checking whether it is available."
}
_ => "Failed to check whether rig is available.",
};
return Err(anyhow::Error::new(error).context(context));
}
match external::rig::resolve_version(version_spec) {
Ok(resolved) => resolve_rig_resolution(resolved),
Err(error) => Err(anyhow::Error::new(error)
.context(format!("Failed to resolve R version '{version_spec}'"))),
}
}
pub(super) fn setup_r_via_selected_rig_version(
selected: &semver::Version,
versions: &[external::rig::RigVersion],
) -> Result<ResolvedRSource> {
match external::rig::resolve_selected_version_from_versions(selected, versions) {
Ok(resolved) => resolve_rig_resolution(resolved),
Err(error) => anyhow::bail!("Failed to resolve R version '{}': {}", selected, error),
}
}
fn resolve_rig_resolution(resolved: external::rig::ResolvedVersion) -> Result<ResolvedRSource> {
log::info!(
"Using R version {} from {}",
resolved.version,
resolved.r_home
);
Ok(ResolvedRSource {
status: RSourceStatus::Rig {
version: resolved.version,
override_info: None,
},
r_home: Some(PathBuf::from(resolved.r_home)),
})
}