lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit fa2a8c862607216d340ea97c74a1c3cbb70f84e9
parent f662dd6fb7bef74fe87554e43bb79224aef8c122
Author: triesap <tyson@radroots.org>
Date:   Tue, 11 Aug 2026 06:35:35 +0000

runtime-paths: define linux service host roots

- resolve the service-host profile only on explicit Linux
- reject macOS Windows mobile and unknown host platforms
- stop classifying unknown targets as Linux service hosts
- preserve tested interactive mobile and repo-local behavior

Diffstat:
Mcrates/runtime_paths/src/error.rs | 3---
Mcrates/runtime_paths/src/lib.rs | 61++++++++++++++++++++++---------------------------------------
Mcrates/runtime_paths/src/platform.rs | 44++++++++++++++++++++++++++------------------
Mcrates/runtime_paths/src/roots.rs | 66++++++++++++++++++++++++------------------------------------------
4 files changed, 72 insertions(+), 102 deletions(-)

diff --git a/crates/runtime_paths/src/error.rs b/crates/runtime_paths/src/error.rs @@ -12,9 +12,6 @@ pub enum RadrootsRuntimePathsError { #[error("interactive_user on windows requires APPDATA and LOCALAPPDATA roots")] MissingWindowsUserDirs, - #[error("service_host on windows requires a ProgramData root")] - MissingWindowsProgramDataDir, - #[error("repo_local requires an explicit repo-local base root")] MissingRepoLocalRoot, diff --git a/crates/runtime_paths/src/lib.rs b/crates/runtime_paths/src/lib.rs @@ -136,7 +136,7 @@ mod tests { } #[test] - fn service_host_unix_uses_canonical_service_roots() { + fn service_host_linux_uses_canonical_service_roots() { let resolver = RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); @@ -161,45 +161,28 @@ mod tests { } #[test] - fn service_host_windows_uses_programdata_roots() { - let resolver = RadrootsPathResolver::new( + fn service_host_is_unsupported_outside_linux() { + for platform in [ + RadrootsPlatform::Macos, RadrootsPlatform::Windows, - RadrootsHostEnvironment { - programdata_dir: Some(PathBuf::from(r"C:\ProgramData")), - ..RadrootsHostEnvironment::default() - }, - ); - - let roots = resolver - .resolve( - RadrootsPathProfile::ServiceHost, - &RadrootsPathOverrides::default(), - ) - .expect("resolve service_host roots"); - - assert_eq!( - roots, - RadrootsPaths { - config: PathBuf::from(r"C:\ProgramData") - .join("Radroots") - .join("config"), - data: PathBuf::from(r"C:\ProgramData") - .join("Radroots") - .join("data"), - cache: PathBuf::from(r"C:\ProgramData") - .join("Radroots") - .join("cache"), - logs: PathBuf::from(r"C:\ProgramData") - .join("Radroots") - .join("logs"), - run: PathBuf::from(r"C:\ProgramData") - .join("Radroots") - .join("run"), - secrets: PathBuf::from(r"C:\ProgramData") - .join("Radroots") - .join("secrets"), - } - ); + RadrootsPlatform::Android, + RadrootsPlatform::Ios, + RadrootsPlatform::Other, + ] { + let resolver = RadrootsPathResolver::new(platform, RadrootsHostEnvironment::default()); + assert_eq!( + resolver + .resolve( + RadrootsPathProfile::ServiceHost, + &RadrootsPathOverrides::default(), + ) + .expect_err("service_host must be unsupported outside linux"), + RadrootsRuntimePathsError::UnsupportedProfilePlatform { + profile: RadrootsPathProfile::ServiceHost, + platform, + } + ); + } } #[test] diff --git a/crates/runtime_paths/src/platform.rs b/crates/runtime_paths/src/platform.rs @@ -8,6 +8,7 @@ pub enum RadrootsPlatform { Windows, Android, Ios, + Other, } impl RadrootsPlatform { @@ -36,17 +37,24 @@ impl RadrootsPlatform { } #[must_use] - #[cfg(all( - not(target_os = "android"), - not(target_os = "ios"), - not(target_os = "macos"), - not(target_os = "windows") - ))] + #[cfg(target_os = "linux")] pub fn current() -> Self { Self::Linux } #[must_use] + #[cfg(not(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "windows" + )))] + pub fn current() -> Self { + Self::Other + } + + #[must_use] pub fn is_unix_like(self) -> bool { matches!(self, Self::Linux | Self::Macos) } @@ -60,6 +68,7 @@ impl fmt::Display for RadrootsPlatform { Self::Windows => "windows", Self::Android => "android", Self::Ios => "ios", + Self::Other => "other", }) } } @@ -88,7 +97,6 @@ pub struct RadrootsHostEnvironment { pub home_dir: Option<PathBuf>, pub appdata_dir: Option<PathBuf>, pub localappdata_dir: Option<PathBuf>, - pub programdata_dir: Option<PathBuf>, } impl RadrootsHostEnvironment { @@ -98,7 +106,6 @@ impl RadrootsHostEnvironment { home_dir: std::env::var_os("HOME").map(PathBuf::from), appdata_dir: std::env::var_os("APPDATA").map(PathBuf::from), localappdata_dir: std::env::var_os("LOCALAPPDATA").map(PathBuf::from), - programdata_dir: std::env::var_os("ProgramData").map(PathBuf::from), } } } @@ -119,13 +126,16 @@ mod tests { let expected = RadrootsPlatform::Macos; #[cfg(target_os = "windows")] let expected = RadrootsPlatform::Windows; - #[cfg(all( - not(target_os = "android"), - not(target_os = "ios"), - not(target_os = "macos"), - not(target_os = "windows") - ))] + #[cfg(target_os = "linux")] let expected = RadrootsPlatform::Linux; + #[cfg(not(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "windows" + )))] + let expected = RadrootsPlatform::Other; assert_eq!(RadrootsPlatform::current(), expected); } @@ -137,6 +147,7 @@ mod tests { assert!(!RadrootsPlatform::Windows.is_unix_like()); assert!(!RadrootsPlatform::Android.is_unix_like()); assert!(!RadrootsPlatform::Ios.is_unix_like()); + assert!(!RadrootsPlatform::Other.is_unix_like()); } #[test] @@ -146,6 +157,7 @@ mod tests { assert_eq!(RadrootsPlatform::Windows.to_string(), "windows"); assert_eq!(RadrootsPlatform::Android.to_string(), "android"); assert_eq!(RadrootsPlatform::Ios.to_string(), "ios"); + assert_eq!(RadrootsPlatform::Other.to_string(), "other"); assert_eq!( RadrootsPathProfile::InteractiveUser.to_string(), @@ -171,9 +183,5 @@ mod tests { env.localappdata_dir, std::env::var_os("LOCALAPPDATA").map(PathBuf::from) ); - assert_eq!( - env.programdata_dir, - std::env::var_os("ProgramData").map(PathBuf::from) - ); } } diff --git a/crates/runtime_paths/src/roots.rs b/crates/runtime_paths/src/roots.rs @@ -113,10 +113,15 @@ impl RadrootsPathResolver { .mobile_roots .clone() .ok_or(RadrootsRuntimePathsError::MissingMobileRoots), - _ => Err(RadrootsRuntimePathsError::UnsupportedProfilePlatform { - profile, - platform: self.platform, - }), + RadrootsPlatform::Linux + | RadrootsPlatform::Macos + | RadrootsPlatform::Windows + | RadrootsPlatform::Other => { + Err(RadrootsRuntimePathsError::UnsupportedProfilePlatform { + profile, + platform: self.platform, + }) + } }, } } @@ -153,7 +158,7 @@ impl RadrootsPathResolver { secrets: config_root.join("secrets"), }) } - RadrootsPlatform::Android | RadrootsPlatform::Ios => { + RadrootsPlatform::Android | RadrootsPlatform::Ios | RadrootsPlatform::Other => { Err(RadrootsRuntimePathsError::UnsupportedProfilePlatform { profile: RadrootsPathProfile::InteractiveUser, platform: self.platform, @@ -164,23 +169,7 @@ impl RadrootsPathResolver { fn resolve_service_host(&self) -> Result<RadrootsPaths, RadrootsRuntimePathsError> { match self.platform { - RadrootsPlatform::Windows => { - let programdata = self - .host_environment - .programdata_dir - .as_ref() - .ok_or(RadrootsRuntimePathsError::MissingWindowsProgramDataDir)?; - let base = programdata.join("Radroots"); - Ok(RadrootsPaths { - config: base.join("config"), - data: base.join("data"), - cache: base.join("cache"), - logs: base.join("logs"), - run: base.join("run"), - secrets: base.join("secrets"), - }) - } - RadrootsPlatform::Linux | RadrootsPlatform::Macos => Ok(RadrootsPaths { + RadrootsPlatform::Linux => Ok(RadrootsPaths { config: PathBuf::from("/etc/radroots"), data: PathBuf::from("/var/lib/radroots"), cache: PathBuf::from("/var/cache/radroots"), @@ -188,7 +177,11 @@ impl RadrootsPathResolver { run: PathBuf::from("/run/radroots"), secrets: PathBuf::from("/etc/radroots/secrets"), }), - RadrootsPlatform::Android | RadrootsPlatform::Ios => { + RadrootsPlatform::Macos + | RadrootsPlatform::Windows + | RadrootsPlatform::Android + | RadrootsPlatform::Ios + | RadrootsPlatform::Other => { Err(RadrootsRuntimePathsError::UnsupportedProfilePlatform { profile: RadrootsPathProfile::ServiceHost, platform: self.platform, @@ -277,32 +270,21 @@ mod tests { } #[test] - fn service_host_windows_requires_programdata() { - let resolver = RadrootsPathResolver::new( + fn service_host_is_rejected_outside_linux() { + for platform in [ + RadrootsPlatform::Macos, RadrootsPlatform::Windows, - RadrootsHostEnvironment::default(), - ); - - let err = resolver - .resolve( - RadrootsPathProfile::ServiceHost, - &RadrootsPathOverrides::default(), - ) - .expect_err("service_host on windows should require programdata"); - - assert_eq!(err, RadrootsRuntimePathsError::MissingWindowsProgramDataDir); - } - - #[test] - fn service_host_is_rejected_on_mobile_platforms() { - for platform in [RadrootsPlatform::Android, RadrootsPlatform::Ios] { + RadrootsPlatform::Android, + RadrootsPlatform::Ios, + RadrootsPlatform::Other, + ] { let resolver = RadrootsPathResolver::new(platform, RadrootsHostEnvironment::default()); let err = resolver .resolve( RadrootsPathProfile::ServiceHost, &RadrootsPathOverrides::default(), ) - .expect_err("service_host should be unsupported on mobile"); + .expect_err("service_host should be unsupported outside linux"); assert_eq!( err, RadrootsRuntimePathsError::UnsupportedProfilePlatform {