lib

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

commit a83d1e2378dab33903741b2562d86badbf68506d
parent 1871733edd8c81a1a2f907cafb1fae1ef270fdfc
Author: triesap <tyson@radroots.org>
Date:   Tue, 11 Aug 2026 09:40:34 +0000

runtime-paths: adopt service instance authority

- remove generic namespaces, ambient selectors, raw roots, and bootstrap helpers
- make RuntimeContext the sole public service-instance path constructor
- retain exact Linux, macOS, Windows, and repository-local path behavior
- verify the reviewed API boundary and complete workspace consumer gates

Diffstat:
MAGENTS.md | 6++++++
Acontracts/api_baselines/radroots_runtime_paths.txt | 996+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/runtime_paths/README | 27+++++++++++++++++----------
Mcrates/runtime_paths/src/context.rs | 286++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mcrates/runtime_paths/src/conventions.rs | 359+++++++------------------------------------------------------------------------
Mcrates/runtime_paths/src/error.rs | 6------
Mcrates/runtime_paths/src/lib.rs | 340++-----------------------------------------------------------------------------
Dcrates/runtime_paths/src/namespace.rs | 236-------------------------------------------------------------------------------
Mcrates/runtime_paths/src/platform.rs | 54+-----------------------------------------------------
Mcrates/runtime_paths/src/roots.rs | 451++++++++++++++-----------------------------------------------------------------
Mcrates/runtime_paths/src/service.rs | 692+++----------------------------------------------------------------------------
Acrates/runtime_paths/tests/package_boundary.rs | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 files changed, 1556 insertions(+), 2021 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md @@ -167,6 +167,12 @@ Before editing code: names are validated single path components, and ordinary manager errors and `Debug` output must not expose filesystem paths, file contents, or raw dependency-owned causes. +- Runtime-path consumers must use the sole typed + `services/<service>/<instance>` model through `RuntimeContext`. The generic + app/service/worker/shared namespace, public raw root containers, path + overrides, ambient process-environment selectors, bootstrap helpers, and + duplicate service-instance path constructors are removed breaking surfaces; + do not restore them or add compatibility aliases. - Runtime-distribution and runtime-management service metadata is the sealed exact Myc/RHI v1 inventory. Both services support multiple validated instances, one TOML config, explicit initialization with existing-only run, diff --git a/contracts/api_baselines/radroots_runtime_paths.txt b/contracts/api_baselines/radroots_runtime_paths.txt @@ -0,0 +1,996 @@ +pub mod radroots_runtime_paths +pub mod radroots_runtime_paths::context +pub enum radroots_runtime_paths::context::RuntimeContextError +pub radroots_runtime_paths::context::RuntimeContextError::InvalidBootstrapBinding +pub radroots_runtime_paths::context::RuntimeContextError::PathSelection +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContextError +pub fn radroots_runtime_paths::context::RuntimeContextError::clone(&self) -> radroots_runtime_paths::context::RuntimeContextError +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContextError +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContextError +pub fn radroots_runtime_paths::context::RuntimeContextError::eq(&self, &radroots_runtime_paths::context::RuntimeContextError) -> bool +impl core::error::Error for radroots_runtime_paths::context::RuntimeContextError +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContextError +pub fn radroots_runtime_paths::context::RuntimeContextError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::context::RuntimeContextError +pub fn radroots_runtime_paths::context::RuntimeContextError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContextError +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContextError +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContextError +pub enum radroots_runtime_paths::context::RuntimeContextSource +pub radroots_runtime_paths::context::RuntimeContextSource::BootstrapCli +pub radroots_runtime_paths::context::RuntimeContextSource::DerivedPath +pub radroots_runtime_paths::context::RuntimeContextSource::SafeDefault +pub radroots_runtime_paths::context::RuntimeContextSource::Toml +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSource::clone(&self) -> radroots_runtime_paths::context::RuntimeContextSource +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContextSource +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSource::eq(&self, &radroots_runtime_paths::context::RuntimeContextSource) -> bool +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSource::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContextSource +impl serde_core::ser::Serialize for radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSource::serialize<__S>(&self, __S) -> core::result::Result<<__S as serde_core::ser::Serializer>::Ok, <__S as serde_core::ser::Serializer>::Error> where __S: serde_core::ser::Serializer +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContextSource +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContextSource +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContextSource +pub struct radroots_runtime_paths::context::RuntimeContext +impl radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::instance(&self) -> &radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::context::RuntimeContext::paths(&self) -> &radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::context::RuntimeContext::profile(&self) -> radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::context::RuntimeContext::resolve(&radroots_runtime_paths::roots::RadrootsPathResolver, radroots_runtime_paths::context::RuntimeContextBootstrap, radroots_runtime_paths::identifier::ServiceId, radroots_runtime_paths::identifier::InstanceId) -> core::result::Result<Self, radroots_runtime_paths::context::RuntimeContextError> +pub fn radroots_runtime_paths::context::RuntimeContext::service(&self) -> &radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::context::RuntimeContext::sources(&self) -> &radroots_runtime_paths::context::RuntimeContextSources +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::clone(&self) -> radroots_runtime_paths::context::RuntimeContext +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContext +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::eq(&self, &radroots_runtime_paths::context::RuntimeContext) -> bool +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContext +impl serde_core::ser::Serialize for radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContext +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContext +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContext +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContext +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContext +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContext +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContext +pub struct radroots_runtime_paths::context::RuntimeContextBootstrap +impl radroots_runtime_paths::context::RuntimeContextBootstrap +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::new(radroots_runtime_paths::platform::RadrootsPathProfile, core::option::Option<std::path::PathBuf>, radroots_runtime_paths::context::RuntimeContextSource, radroots_runtime_paths::context::RuntimeContextSource) -> core::result::Result<Self, radroots_runtime_paths::context::RuntimeContextError> +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::profile(&self) -> radroots_runtime_paths::platform::RadrootsPathProfile +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContextBootstrap +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::clone(&self) -> radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContextBootstrap +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::eq(&self, &radroots_runtime_paths::context::RuntimeContextBootstrap) -> bool +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContextBootstrap +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContextBootstrap +pub struct radroots_runtime_paths::context::RuntimeContextSources +impl radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::instance(&self) -> radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSources::paths(&self) -> radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSources::profile(&self) -> radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSources::repo_local_root(&self) -> core::option::Option<radroots_runtime_paths::context::RuntimeContextSource> +pub fn radroots_runtime_paths::context::RuntimeContextSources::service(&self) -> radroots_runtime_paths::context::RuntimeContextSource +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::clone(&self) -> radroots_runtime_paths::context::RuntimeContextSources +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContextSources +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::eq(&self, &radroots_runtime_paths::context::RuntimeContextSources) -> bool +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContextSources +impl serde_core::ser::Serialize for radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::serialize<__S>(&self, __S) -> core::result::Result<<__S as serde_core::ser::Serializer>::Ok, <__S as serde_core::ser::Serializer>::Error> where __S: serde_core::ser::Serializer +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContextSources +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContextSources +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContextSources +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContextSources +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContextSources +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContextSources +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContextSources +pub mod radroots_runtime_paths::conventions +pub enum radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::Empty +pub radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::InvalidBoundary +pub radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::InvalidCharacter +pub radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::TooLong +pub radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::TooLong::maximum: usize +impl core::clone::Clone for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::clone(&self) -> radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::cmp::Eq for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::cmp::PartialEq for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::eq(&self, &radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError) -> bool +impl core::error::Error for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::fmt::Debug for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::StructuralPartialEq for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::Freeze for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::Send for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::Sync for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::Unpin for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::UnsafeUnpin for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub struct radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::admin_socket(&self) -> &std::path::Path +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::config(&self) -> &std::path::Path +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::state_database(&self) -> &std::path::Path +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::state_lock(&self) -> &std::path::Path +impl core::clone::Clone for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::clone(&self) -> radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::cmp::Eq for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::cmp::PartialEq for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::eq(&self, &radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts) -> bool +impl core::fmt::Debug for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::Freeze for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::Send for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::Sync for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::Unpin for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::UnsafeUnpin for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub struct radroots_runtime_paths::conventions::ServiceCredentialArtifactName(_) +impl radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::as_str(&self) -> &str +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError> +impl core::clone::Clone for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::clone(&self) -> radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::cmp::Eq for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::cmp::Ord for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::cmp(&self, &radroots_runtime_paths::conventions::ServiceCredentialArtifactName) -> core::cmp::Ordering +impl core::cmp::PartialEq for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::eq(&self, &radroots_runtime_paths::conventions::ServiceCredentialArtifactName) -> bool +impl core::cmp::PartialOrd for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::partial_cmp(&self, &radroots_runtime_paths::conventions::ServiceCredentialArtifactName) -> core::option::Option<core::cmp::Ordering> +impl core::convert::AsRef<str> for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::as_ref(&self) -> &str +impl core::fmt::Debug for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::hash<__H: core::hash::Hasher>(&self, &mut __H) +impl core::marker::StructuralPartialEq for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::Freeze for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::Send for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::Sync for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::Unpin for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::UnsafeUnpin for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub const radroots_runtime_paths::conventions::DEFAULT_CONFIG_FILE_NAME: &str +pub const radroots_runtime_paths::conventions::DEFAULT_SHARED_GEONAMES_NAMESPACE: &str +pub const radroots_runtime_paths::conventions::DEFAULT_SHARED_GEONAMES_NAMESPACE_KIND: &str +pub const radroots_runtime_paths::conventions::DEFAULT_SHARED_GEONAMES_NAMESPACE_VALUE: &str +pub const radroots_runtime_paths::conventions::DEFAULT_SHARED_RUNTIME_STORE_DB_FILE_NAME: &str +pub const radroots_runtime_paths::conventions::DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE: &str +pub const radroots_runtime_paths::conventions::DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_KIND: &str +pub const radroots_runtime_paths::conventions::DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_VALUE: &str +pub const radroots_runtime_paths::conventions::SERVICE_ADMIN_SOCKET_FILE_NAME: &str +pub const radroots_runtime_paths::conventions::SERVICE_CREDENTIAL_ARTIFACT_NAME_MAX_BYTES: usize +pub const radroots_runtime_paths::conventions::SERVICE_STATE_DATABASE_FILE_NAME: &str +pub const radroots_runtime_paths::conventions::SERVICE_STATE_LOCK_FILE_NAME: &str +pub fn radroots_runtime_paths::conventions::default_service_instance_artifacts(&radroots_runtime_paths::service::RadrootsServiceInstancePaths) -> radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::default_shared_geonames_database_file_name(&str) -> alloc::string::String +pub fn radroots_runtime_paths::conventions::default_shared_geonames_database_path_from_cache_root(impl core::convert::AsRef<std::path::Path>, &str) -> std::path::PathBuf +pub fn radroots_runtime_paths::conventions::default_shared_geonames_root_from_cache_root(impl core::convert::AsRef<std::path::Path>) -> std::path::PathBuf +pub fn radroots_runtime_paths::conventions::default_shared_runtime_store_database_path_from_data_root(impl core::convert::AsRef<std::path::Path>) -> std::path::PathBuf +pub fn radroots_runtime_paths::conventions::default_shared_runtime_store_database_path_from_shared_accounts_data_root(impl core::convert::AsRef<std::path::Path>) -> core::result::Result<std::path::PathBuf, radroots_runtime_paths::error::RadrootsRuntimePathsError> +pub fn radroots_runtime_paths::conventions::default_shared_runtime_store_root_from_data_root(impl core::convert::AsRef<std::path::Path>) -> std::path::PathBuf +pub fn radroots_runtime_paths::conventions::default_shared_runtime_store_root_from_shared_accounts_data_root(impl core::convert::AsRef<std::path::Path>) -> core::result::Result<std::path::PathBuf, radroots_runtime_paths::error::RadrootsRuntimePathsError> +pub fn radroots_runtime_paths::conventions::service_credential_artifact_path(&radroots_runtime_paths::service::RadrootsServiceInstancePaths, &radroots_runtime_paths::conventions::ServiceCredentialArtifactName) -> std::path::PathBuf +pub mod radroots_runtime_paths::error +pub enum radroots_runtime_paths::error::RadrootsRuntimePathsError +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::InvalidHomeDir +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::InvalidHomeDir::platform: radroots_runtime_paths::platform::RadrootsPlatform +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::InvalidRepoLocalRoot +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::MissingHomeDir +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::MissingHomeDir::platform: radroots_runtime_paths::platform::RadrootsPlatform +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::MissingRepoLocalRoot +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::MissingWindowsUserDirs +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::MissingXdgRuntimeDir +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::SharedAccountsDataRootMissingParent +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::SharedAccountsDataRootMissingParent::path: std::path::PathBuf +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::UnsupportedProfilePlatform +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::UnsupportedProfilePlatform::platform: radroots_runtime_paths::platform::RadrootsPlatform +pub radroots_runtime_paths::error::RadrootsRuntimePathsError::UnsupportedProfilePlatform::profile: radroots_runtime_paths::platform::RadrootsPathProfile +impl core::clone::Clone for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub fn radroots_runtime_paths::error::RadrootsRuntimePathsError::clone(&self) -> radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::cmp::Eq for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::cmp::PartialEq for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub fn radroots_runtime_paths::error::RadrootsRuntimePathsError::eq(&self, &radroots_runtime_paths::error::RadrootsRuntimePathsError) -> bool +impl core::error::Error for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::fmt::Debug for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub fn radroots_runtime_paths::error::RadrootsRuntimePathsError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub fn radroots_runtime_paths::error::RadrootsRuntimePathsError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::Freeze for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::Send for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::Sync for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::Unpin for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::UnsafeUnpin for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub mod radroots_runtime_paths::identifier +pub enum radroots_runtime_paths::identifier::ServiceIdentityError +pub radroots_runtime_paths::identifier::ServiceIdentityError::Empty +pub radroots_runtime_paths::identifier::ServiceIdentityError::Empty::kind: radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::identifier::ServiceIdentityError::InvalidBoundary +pub radroots_runtime_paths::identifier::ServiceIdentityError::InvalidBoundary::kind: radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::identifier::ServiceIdentityError::InvalidCharacter +pub radroots_runtime_paths::identifier::ServiceIdentityError::InvalidCharacter::kind: radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::identifier::ServiceIdentityError::TooLong +pub radroots_runtime_paths::identifier::ServiceIdentityError::TooLong::kind: radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::identifier::ServiceIdentityError::TooLong::maximum: usize +impl core::clone::Clone for radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceIdentityError::clone(&self) -> radroots_runtime_paths::identifier::ServiceIdentityError +impl core::cmp::Eq for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::cmp::PartialEq for radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceIdentityError::eq(&self, &radroots_runtime_paths::identifier::ServiceIdentityError) -> bool +impl core::error::Error for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::fmt::Debug for radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceIdentityError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceIdentityError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::StructuralPartialEq for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::Freeze for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::Send for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::Sync for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::Unpin for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::UnsafeUnpin for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::identifier::ServiceIdentityError +pub enum radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::identifier::ServiceIdentityKind::Instance +pub radroots_runtime_paths::identifier::ServiceIdentityKind::Service +impl core::clone::Clone for radroots_runtime_paths::identifier::ServiceIdentityKind +pub fn radroots_runtime_paths::identifier::ServiceIdentityKind::clone(&self) -> radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::cmp::Eq for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::cmp::PartialEq for radroots_runtime_paths::identifier::ServiceIdentityKind +pub fn radroots_runtime_paths::identifier::ServiceIdentityKind::eq(&self, &radroots_runtime_paths::identifier::ServiceIdentityKind) -> bool +impl core::fmt::Debug for radroots_runtime_paths::identifier::ServiceIdentityKind +pub fn radroots_runtime_paths::identifier::ServiceIdentityKind::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::identifier::ServiceIdentityKind +pub fn radroots_runtime_paths::identifier::ServiceIdentityKind::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::StructuralPartialEq for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::Freeze for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::Send for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::Sync for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::Unpin for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::UnsafeUnpin for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::identifier::ServiceIdentityKind +pub struct radroots_runtime_paths::identifier::InstanceId(_) +impl radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::as_str(&self) -> &str +pub fn radroots_runtime_paths::identifier::InstanceId::into_string(self) -> alloc::string::String +pub fn radroots_runtime_paths::identifier::InstanceId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::identifier::ServiceIdentityError> +impl core::clone::Clone for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::clone(&self) -> radroots_runtime_paths::identifier::InstanceId +impl core::cmp::Eq for radroots_runtime_paths::identifier::InstanceId +impl core::cmp::Ord for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::cmp(&self, &radroots_runtime_paths::identifier::InstanceId) -> core::cmp::Ordering +impl core::cmp::PartialEq for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::eq(&self, &radroots_runtime_paths::identifier::InstanceId) -> bool +impl core::cmp::PartialOrd for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::partial_cmp(&self, &radroots_runtime_paths::identifier::InstanceId) -> core::option::Option<core::cmp::Ordering> +impl core::convert::AsRef<str> for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::as_ref(&self) -> &str +impl core::convert::From<radroots_runtime_paths::identifier::InstanceId> for alloc::string::String +pub fn alloc::string::String::from(radroots_runtime_paths::identifier::InstanceId) -> Self +impl core::convert::TryFrom<alloc::string::String> for radroots_runtime_paths::identifier::InstanceId +pub type radroots_runtime_paths::identifier::InstanceId::Error = radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::InstanceId::try_from(alloc::string::String) -> core::result::Result<Self, Self::Error> +impl core::fmt::Debug for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::hash<__H: core::hash::Hasher>(&self, &mut __H) +impl core::marker::StructuralPartialEq for radroots_runtime_paths::identifier::InstanceId +impl core::str::traits::FromStr for radroots_runtime_paths::identifier::InstanceId +pub type radroots_runtime_paths::identifier::InstanceId::Err = radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::InstanceId::from_str(&str) -> core::result::Result<Self, Self::Err> +impl serde_core::ser::Serialize for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer +impl<'de> serde_core::de::Deserialize<'de> for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::deserialize<D>(D) -> core::result::Result<Self, <D as serde_core::de::Deserializer>::Error> where D: serde_core::de::Deserializer<'de> +impl core::marker::Freeze for radroots_runtime_paths::identifier::InstanceId +impl core::marker::Send for radroots_runtime_paths::identifier::InstanceId +impl core::marker::Sync for radroots_runtime_paths::identifier::InstanceId +impl core::marker::Unpin for radroots_runtime_paths::identifier::InstanceId +impl core::marker::UnsafeUnpin for radroots_runtime_paths::identifier::InstanceId +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::identifier::InstanceId +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::identifier::InstanceId +pub struct radroots_runtime_paths::identifier::ServiceId(_) +impl radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::as_str(&self) -> &str +pub fn radroots_runtime_paths::identifier::ServiceId::into_string(self) -> alloc::string::String +pub fn radroots_runtime_paths::identifier::ServiceId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::identifier::ServiceIdentityError> +impl core::clone::Clone for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::clone(&self) -> radroots_runtime_paths::identifier::ServiceId +impl core::cmp::Eq for radroots_runtime_paths::identifier::ServiceId +impl core::cmp::Ord for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::cmp(&self, &radroots_runtime_paths::identifier::ServiceId) -> core::cmp::Ordering +impl core::cmp::PartialEq for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::eq(&self, &radroots_runtime_paths::identifier::ServiceId) -> bool +impl core::cmp::PartialOrd for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::partial_cmp(&self, &radroots_runtime_paths::identifier::ServiceId) -> core::option::Option<core::cmp::Ordering> +impl core::convert::AsRef<str> for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::as_ref(&self) -> &str +impl core::convert::From<radroots_runtime_paths::identifier::ServiceId> for alloc::string::String +pub fn alloc::string::String::from(radroots_runtime_paths::identifier::ServiceId) -> Self +impl core::convert::TryFrom<alloc::string::String> for radroots_runtime_paths::identifier::ServiceId +pub type radroots_runtime_paths::identifier::ServiceId::Error = radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceId::try_from(alloc::string::String) -> core::result::Result<Self, Self::Error> +impl core::fmt::Debug for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::hash<__H: core::hash::Hasher>(&self, &mut __H) +impl core::marker::StructuralPartialEq for radroots_runtime_paths::identifier::ServiceId +impl core::str::traits::FromStr for radroots_runtime_paths::identifier::ServiceId +pub type radroots_runtime_paths::identifier::ServiceId::Err = radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceId::from_str(&str) -> core::result::Result<Self, Self::Err> +impl serde_core::ser::Serialize for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer +impl<'de> serde_core::de::Deserialize<'de> for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::deserialize<D>(D) -> core::result::Result<Self, <D as serde_core::de::Deserializer>::Error> where D: serde_core::de::Deserializer<'de> +impl core::marker::Freeze for radroots_runtime_paths::identifier::ServiceId +impl core::marker::Send for radroots_runtime_paths::identifier::ServiceId +impl core::marker::Sync for radroots_runtime_paths::identifier::ServiceId +impl core::marker::Unpin for radroots_runtime_paths::identifier::ServiceId +impl core::marker::UnsafeUnpin for radroots_runtime_paths::identifier::ServiceId +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::identifier::ServiceId +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::identifier::ServiceId +pub const radroots_runtime_paths::identifier::INSTANCE_ID_MAX_BYTES: usize +pub const radroots_runtime_paths::identifier::SERVICE_ID_MAX_BYTES: usize +pub mod radroots_runtime_paths::platform +pub enum radroots_runtime_paths::platform::RadrootsPathProfile +pub radroots_runtime_paths::platform::RadrootsPathProfile::InteractiveUser +pub radroots_runtime_paths::platform::RadrootsPathProfile::MobileNative +pub radroots_runtime_paths::platform::RadrootsPathProfile::RepoLocal +pub radroots_runtime_paths::platform::RadrootsPathProfile::ServiceHost +impl core::clone::Clone for radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::platform::RadrootsPathProfile::clone(&self) -> radroots_runtime_paths::platform::RadrootsPathProfile +impl core::cmp::Eq for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::cmp::PartialEq for radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::platform::RadrootsPathProfile::eq(&self, &radroots_runtime_paths::platform::RadrootsPathProfile) -> bool +impl core::fmt::Debug for radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::platform::RadrootsPathProfile::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::platform::RadrootsPathProfile::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::StructuralPartialEq for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::Freeze for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::Send for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::Sync for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::Unpin for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::UnsafeUnpin for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::platform::RadrootsPathProfile +pub enum radroots_runtime_paths::platform::RadrootsPlatform +pub radroots_runtime_paths::platform::RadrootsPlatform::Android +pub radroots_runtime_paths::platform::RadrootsPlatform::Ios +pub radroots_runtime_paths::platform::RadrootsPlatform::Linux +pub radroots_runtime_paths::platform::RadrootsPlatform::Macos +pub radroots_runtime_paths::platform::RadrootsPlatform::Other +pub radroots_runtime_paths::platform::RadrootsPlatform::Windows +impl radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::current() -> Self +pub fn radroots_runtime_paths::platform::RadrootsPlatform::is_unix_like(self) -> bool +impl core::clone::Clone for radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::clone(&self) -> radroots_runtime_paths::platform::RadrootsPlatform +impl core::cmp::Eq for radroots_runtime_paths::platform::RadrootsPlatform +impl core::cmp::PartialEq for radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::eq(&self, &radroots_runtime_paths::platform::RadrootsPlatform) -> bool +impl core::fmt::Debug for radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::StructuralPartialEq for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::Freeze for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::Send for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::Sync for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::Unpin for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::UnsafeUnpin for radroots_runtime_paths::platform::RadrootsPlatform +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::platform::RadrootsPlatform +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::platform::RadrootsPlatform +pub struct radroots_runtime_paths::platform::RadrootsHostEnvironment +pub radroots_runtime_paths::platform::RadrootsHostEnvironment::appdata_dir: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::platform::RadrootsHostEnvironment::home_dir: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::platform::RadrootsHostEnvironment::localappdata_dir: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::platform::RadrootsHostEnvironment::xdg_cache_home: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::platform::RadrootsHostEnvironment::xdg_config_home: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::platform::RadrootsHostEnvironment::xdg_data_home: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::platform::RadrootsHostEnvironment::xdg_runtime_dir: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::platform::RadrootsHostEnvironment::xdg_state_home: core::option::Option<std::path::PathBuf> +impl core::clone::Clone for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub fn radroots_runtime_paths::platform::RadrootsHostEnvironment::clone(&self) -> radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::cmp::Eq for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::cmp::PartialEq for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub fn radroots_runtime_paths::platform::RadrootsHostEnvironment::eq(&self, &radroots_runtime_paths::platform::RadrootsHostEnvironment) -> bool +impl core::default::Default for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub fn radroots_runtime_paths::platform::RadrootsHostEnvironment::default() -> radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::fmt::Debug for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub fn radroots_runtime_paths::platform::RadrootsHostEnvironment::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::Freeze for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::Send for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::Sync for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::Unpin for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::UnsafeUnpin for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub mod radroots_runtime_paths::roots +pub struct radroots_runtime_paths::roots::RadrootsPathResolver +impl radroots_runtime_paths::roots::RadrootsPathResolver +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::new(radroots_runtime_paths::platform::RadrootsPlatform, radroots_runtime_paths::platform::RadrootsHostEnvironment) -> Self +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::platform(&self) -> radroots_runtime_paths::platform::RadrootsPlatform +impl core::clone::Clone for radroots_runtime_paths::roots::RadrootsPathResolver +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::clone(&self) -> radroots_runtime_paths::roots::RadrootsPathResolver +impl core::cmp::Eq for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::cmp::PartialEq for radroots_runtime_paths::roots::RadrootsPathResolver +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::eq(&self, &radroots_runtime_paths::roots::RadrootsPathResolver) -> bool +impl core::fmt::Debug for radroots_runtime_paths::roots::RadrootsPathResolver +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::Freeze for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::Send for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::Sync for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::Unpin for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::UnsafeUnpin for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::roots::RadrootsPathResolver +pub mod radroots_runtime_paths::service +pub struct radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::cache(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::config(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::logs(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::run(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::secrets(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::state(&self) -> &std::path::Path +impl core::clone::Clone for radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::clone(&self) -> radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::cmp::Eq for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::cmp::PartialEq for radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::eq(&self, &radroots_runtime_paths::service::RadrootsServiceInstancePaths) -> bool +impl core::fmt::Debug for radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::Freeze for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::Send for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::Sync for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::Unpin for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::UnsafeUnpin for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub enum radroots_runtime_paths::RadrootsPathProfile +pub radroots_runtime_paths::RadrootsPathProfile::InteractiveUser +pub radroots_runtime_paths::RadrootsPathProfile::MobileNative +pub radroots_runtime_paths::RadrootsPathProfile::RepoLocal +pub radroots_runtime_paths::RadrootsPathProfile::ServiceHost +impl core::clone::Clone for radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::platform::RadrootsPathProfile::clone(&self) -> radroots_runtime_paths::platform::RadrootsPathProfile +impl core::cmp::Eq for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::cmp::PartialEq for radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::platform::RadrootsPathProfile::eq(&self, &radroots_runtime_paths::platform::RadrootsPathProfile) -> bool +impl core::fmt::Debug for radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::platform::RadrootsPathProfile::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::platform::RadrootsPathProfile::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::StructuralPartialEq for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::Freeze for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::Send for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::Sync for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::Unpin for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::marker::UnsafeUnpin for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::platform::RadrootsPathProfile +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::platform::RadrootsPathProfile +pub enum radroots_runtime_paths::RadrootsPlatform +pub radroots_runtime_paths::RadrootsPlatform::Android +pub radroots_runtime_paths::RadrootsPlatform::Ios +pub radroots_runtime_paths::RadrootsPlatform::Linux +pub radroots_runtime_paths::RadrootsPlatform::Macos +pub radroots_runtime_paths::RadrootsPlatform::Other +pub radroots_runtime_paths::RadrootsPlatform::Windows +impl radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::current() -> Self +pub fn radroots_runtime_paths::platform::RadrootsPlatform::is_unix_like(self) -> bool +impl core::clone::Clone for radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::clone(&self) -> radroots_runtime_paths::platform::RadrootsPlatform +impl core::cmp::Eq for radroots_runtime_paths::platform::RadrootsPlatform +impl core::cmp::PartialEq for radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::eq(&self, &radroots_runtime_paths::platform::RadrootsPlatform) -> bool +impl core::fmt::Debug for radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::platform::RadrootsPlatform +pub fn radroots_runtime_paths::platform::RadrootsPlatform::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::StructuralPartialEq for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::Freeze for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::Send for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::Sync for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::Unpin for radroots_runtime_paths::platform::RadrootsPlatform +impl core::marker::UnsafeUnpin for radroots_runtime_paths::platform::RadrootsPlatform +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::platform::RadrootsPlatform +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::platform::RadrootsPlatform +pub enum radroots_runtime_paths::RadrootsRuntimePathsError +pub radroots_runtime_paths::RadrootsRuntimePathsError::InvalidHomeDir +pub radroots_runtime_paths::RadrootsRuntimePathsError::InvalidHomeDir::platform: radroots_runtime_paths::platform::RadrootsPlatform +pub radroots_runtime_paths::RadrootsRuntimePathsError::InvalidRepoLocalRoot +pub radroots_runtime_paths::RadrootsRuntimePathsError::MissingHomeDir +pub radroots_runtime_paths::RadrootsRuntimePathsError::MissingHomeDir::platform: radroots_runtime_paths::platform::RadrootsPlatform +pub radroots_runtime_paths::RadrootsRuntimePathsError::MissingRepoLocalRoot +pub radroots_runtime_paths::RadrootsRuntimePathsError::MissingWindowsUserDirs +pub radroots_runtime_paths::RadrootsRuntimePathsError::MissingXdgRuntimeDir +pub radroots_runtime_paths::RadrootsRuntimePathsError::SharedAccountsDataRootMissingParent +pub radroots_runtime_paths::RadrootsRuntimePathsError::SharedAccountsDataRootMissingParent::path: std::path::PathBuf +pub radroots_runtime_paths::RadrootsRuntimePathsError::UnsupportedProfilePlatform +pub radroots_runtime_paths::RadrootsRuntimePathsError::UnsupportedProfilePlatform::platform: radroots_runtime_paths::platform::RadrootsPlatform +pub radroots_runtime_paths::RadrootsRuntimePathsError::UnsupportedProfilePlatform::profile: radroots_runtime_paths::platform::RadrootsPathProfile +impl core::clone::Clone for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub fn radroots_runtime_paths::error::RadrootsRuntimePathsError::clone(&self) -> radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::cmp::Eq for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::cmp::PartialEq for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub fn radroots_runtime_paths::error::RadrootsRuntimePathsError::eq(&self, &radroots_runtime_paths::error::RadrootsRuntimePathsError) -> bool +impl core::error::Error for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::fmt::Debug for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub fn radroots_runtime_paths::error::RadrootsRuntimePathsError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub fn radroots_runtime_paths::error::RadrootsRuntimePathsError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::Freeze for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::Send for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::Sync for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::Unpin for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::marker::UnsafeUnpin for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::error::RadrootsRuntimePathsError +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::error::RadrootsRuntimePathsError +pub enum radroots_runtime_paths::RuntimeContextError +pub radroots_runtime_paths::RuntimeContextError::InvalidBootstrapBinding +pub radroots_runtime_paths::RuntimeContextError::PathSelection +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContextError +pub fn radroots_runtime_paths::context::RuntimeContextError::clone(&self) -> radroots_runtime_paths::context::RuntimeContextError +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContextError +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContextError +pub fn radroots_runtime_paths::context::RuntimeContextError::eq(&self, &radroots_runtime_paths::context::RuntimeContextError) -> bool +impl core::error::Error for radroots_runtime_paths::context::RuntimeContextError +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContextError +pub fn radroots_runtime_paths::context::RuntimeContextError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::context::RuntimeContextError +pub fn radroots_runtime_paths::context::RuntimeContextError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContextError +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContextError +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContextError +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContextError +pub enum radroots_runtime_paths::RuntimeContextSource +pub radroots_runtime_paths::RuntimeContextSource::BootstrapCli +pub radroots_runtime_paths::RuntimeContextSource::DerivedPath +pub radroots_runtime_paths::RuntimeContextSource::SafeDefault +pub radroots_runtime_paths::RuntimeContextSource::Toml +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSource::clone(&self) -> radroots_runtime_paths::context::RuntimeContextSource +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContextSource +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSource::eq(&self, &radroots_runtime_paths::context::RuntimeContextSource) -> bool +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSource::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContextSource +impl serde_core::ser::Serialize for radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSource::serialize<__S>(&self, __S) -> core::result::Result<<__S as serde_core::ser::Serializer>::Ok, <__S as serde_core::ser::Serializer>::Error> where __S: serde_core::ser::Serializer +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContextSource +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContextSource +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContextSource +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContextSource +pub enum radroots_runtime_paths::ServiceCredentialArtifactNameError +pub radroots_runtime_paths::ServiceCredentialArtifactNameError::Empty +pub radroots_runtime_paths::ServiceCredentialArtifactNameError::InvalidBoundary +pub radroots_runtime_paths::ServiceCredentialArtifactNameError::InvalidCharacter +pub radroots_runtime_paths::ServiceCredentialArtifactNameError::TooLong +pub radroots_runtime_paths::ServiceCredentialArtifactNameError::TooLong::maximum: usize +impl core::clone::Clone for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::clone(&self) -> radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::cmp::Eq for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::cmp::PartialEq for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::eq(&self, &radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError) -> bool +impl core::error::Error for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::fmt::Debug for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::StructuralPartialEq for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::Freeze for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::Send for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::Sync for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::Unpin for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::marker::UnsafeUnpin for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError +pub enum radroots_runtime_paths::ServiceIdentityError +pub radroots_runtime_paths::ServiceIdentityError::Empty +pub radroots_runtime_paths::ServiceIdentityError::Empty::kind: radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::ServiceIdentityError::InvalidBoundary +pub radroots_runtime_paths::ServiceIdentityError::InvalidBoundary::kind: radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::ServiceIdentityError::InvalidCharacter +pub radroots_runtime_paths::ServiceIdentityError::InvalidCharacter::kind: radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::ServiceIdentityError::TooLong +pub radroots_runtime_paths::ServiceIdentityError::TooLong::kind: radroots_runtime_paths::identifier::ServiceIdentityKind +pub radroots_runtime_paths::ServiceIdentityError::TooLong::maximum: usize +impl core::clone::Clone for radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceIdentityError::clone(&self) -> radroots_runtime_paths::identifier::ServiceIdentityError +impl core::cmp::Eq for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::cmp::PartialEq for radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceIdentityError::eq(&self, &radroots_runtime_paths::identifier::ServiceIdentityError) -> bool +impl core::error::Error for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::fmt::Debug for radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceIdentityError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceIdentityError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::StructuralPartialEq for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::Freeze for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::Send for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::Sync for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::Unpin for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::marker::UnsafeUnpin for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::identifier::ServiceIdentityError +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::identifier::ServiceIdentityError +pub enum radroots_runtime_paths::ServiceIdentityKind +pub radroots_runtime_paths::ServiceIdentityKind::Instance +pub radroots_runtime_paths::ServiceIdentityKind::Service +impl core::clone::Clone for radroots_runtime_paths::identifier::ServiceIdentityKind +pub fn radroots_runtime_paths::identifier::ServiceIdentityKind::clone(&self) -> radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::cmp::Eq for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::cmp::PartialEq for radroots_runtime_paths::identifier::ServiceIdentityKind +pub fn radroots_runtime_paths::identifier::ServiceIdentityKind::eq(&self, &radroots_runtime_paths::identifier::ServiceIdentityKind) -> bool +impl core::fmt::Debug for radroots_runtime_paths::identifier::ServiceIdentityKind +pub fn radroots_runtime_paths::identifier::ServiceIdentityKind::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::identifier::ServiceIdentityKind +pub fn radroots_runtime_paths::identifier::ServiceIdentityKind::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::StructuralPartialEq for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::Freeze for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::Send for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::Sync for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::Unpin for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::marker::UnsafeUnpin for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::identifier::ServiceIdentityKind +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::identifier::ServiceIdentityKind +pub struct radroots_runtime_paths::InstanceId(_) +impl radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::as_str(&self) -> &str +pub fn radroots_runtime_paths::identifier::InstanceId::into_string(self) -> alloc::string::String +pub fn radroots_runtime_paths::identifier::InstanceId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::identifier::ServiceIdentityError> +impl core::clone::Clone for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::clone(&self) -> radroots_runtime_paths::identifier::InstanceId +impl core::cmp::Eq for radroots_runtime_paths::identifier::InstanceId +impl core::cmp::Ord for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::cmp(&self, &radroots_runtime_paths::identifier::InstanceId) -> core::cmp::Ordering +impl core::cmp::PartialEq for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::eq(&self, &radroots_runtime_paths::identifier::InstanceId) -> bool +impl core::cmp::PartialOrd for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::partial_cmp(&self, &radroots_runtime_paths::identifier::InstanceId) -> core::option::Option<core::cmp::Ordering> +impl core::convert::AsRef<str> for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::as_ref(&self) -> &str +impl core::convert::From<radroots_runtime_paths::identifier::InstanceId> for alloc::string::String +pub fn alloc::string::String::from(radroots_runtime_paths::identifier::InstanceId) -> Self +impl core::convert::TryFrom<alloc::string::String> for radroots_runtime_paths::identifier::InstanceId +pub type radroots_runtime_paths::identifier::InstanceId::Error = radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::InstanceId::try_from(alloc::string::String) -> core::result::Result<Self, Self::Error> +impl core::fmt::Debug for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::hash<__H: core::hash::Hasher>(&self, &mut __H) +impl core::marker::StructuralPartialEq for radroots_runtime_paths::identifier::InstanceId +impl core::str::traits::FromStr for radroots_runtime_paths::identifier::InstanceId +pub type radroots_runtime_paths::identifier::InstanceId::Err = radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::InstanceId::from_str(&str) -> core::result::Result<Self, Self::Err> +impl serde_core::ser::Serialize for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer +impl<'de> serde_core::de::Deserialize<'de> for radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::identifier::InstanceId::deserialize<D>(D) -> core::result::Result<Self, <D as serde_core::de::Deserializer>::Error> where D: serde_core::de::Deserializer<'de> +impl core::marker::Freeze for radroots_runtime_paths::identifier::InstanceId +impl core::marker::Send for radroots_runtime_paths::identifier::InstanceId +impl core::marker::Sync for radroots_runtime_paths::identifier::InstanceId +impl core::marker::Unpin for radroots_runtime_paths::identifier::InstanceId +impl core::marker::UnsafeUnpin for radroots_runtime_paths::identifier::InstanceId +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::identifier::InstanceId +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::identifier::InstanceId +pub struct radroots_runtime_paths::RadrootsHostEnvironment +pub radroots_runtime_paths::RadrootsHostEnvironment::appdata_dir: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::RadrootsHostEnvironment::home_dir: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::RadrootsHostEnvironment::localappdata_dir: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_cache_home: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_config_home: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_data_home: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_runtime_dir: core::option::Option<std::path::PathBuf> +pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_state_home: core::option::Option<std::path::PathBuf> +impl core::clone::Clone for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub fn radroots_runtime_paths::platform::RadrootsHostEnvironment::clone(&self) -> radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::cmp::Eq for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::cmp::PartialEq for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub fn radroots_runtime_paths::platform::RadrootsHostEnvironment::eq(&self, &radroots_runtime_paths::platform::RadrootsHostEnvironment) -> bool +impl core::default::Default for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub fn radroots_runtime_paths::platform::RadrootsHostEnvironment::default() -> radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::fmt::Debug for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub fn radroots_runtime_paths::platform::RadrootsHostEnvironment::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::Freeze for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::Send for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::Sync for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::Unpin for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::marker::UnsafeUnpin for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::platform::RadrootsHostEnvironment +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::platform::RadrootsHostEnvironment +pub struct radroots_runtime_paths::RadrootsPathResolver +impl radroots_runtime_paths::roots::RadrootsPathResolver +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::new(radroots_runtime_paths::platform::RadrootsPlatform, radroots_runtime_paths::platform::RadrootsHostEnvironment) -> Self +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::platform(&self) -> radroots_runtime_paths::platform::RadrootsPlatform +impl core::clone::Clone for radroots_runtime_paths::roots::RadrootsPathResolver +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::clone(&self) -> radroots_runtime_paths::roots::RadrootsPathResolver +impl core::cmp::Eq for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::cmp::PartialEq for radroots_runtime_paths::roots::RadrootsPathResolver +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::eq(&self, &radroots_runtime_paths::roots::RadrootsPathResolver) -> bool +impl core::fmt::Debug for radroots_runtime_paths::roots::RadrootsPathResolver +pub fn radroots_runtime_paths::roots::RadrootsPathResolver::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::Freeze for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::Send for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::Sync for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::Unpin for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::marker::UnsafeUnpin for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::roots::RadrootsPathResolver +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::roots::RadrootsPathResolver +pub struct radroots_runtime_paths::RadrootsServiceInstanceArtifacts +impl radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::admin_socket(&self) -> &std::path::Path +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::config(&self) -> &std::path::Path +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::state_database(&self) -> &std::path::Path +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::state_lock(&self) -> &std::path::Path +impl core::clone::Clone for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::clone(&self) -> radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::cmp::Eq for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::cmp::PartialEq for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::eq(&self, &radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts) -> bool +impl core::fmt::Debug for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::Freeze for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::Send for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::Sync for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::Unpin for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::marker::UnsafeUnpin for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub struct radroots_runtime_paths::RadrootsServiceInstancePaths +impl radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::cache(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::config(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::logs(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::run(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::secrets(&self) -> &std::path::Path +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::state(&self) -> &std::path::Path +impl core::clone::Clone for radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::clone(&self) -> radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::cmp::Eq for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::cmp::PartialEq for radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::eq(&self, &radroots_runtime_paths::service::RadrootsServiceInstancePaths) -> bool +impl core::fmt::Debug for radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::service::RadrootsServiceInstancePaths::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::Freeze for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::Send for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::Sync for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::Unpin for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::marker::UnsafeUnpin for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::service::RadrootsServiceInstancePaths +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub struct radroots_runtime_paths::RuntimeContext +impl radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::instance(&self) -> &radroots_runtime_paths::identifier::InstanceId +pub fn radroots_runtime_paths::context::RuntimeContext::paths(&self) -> &radroots_runtime_paths::service::RadrootsServiceInstancePaths +pub fn radroots_runtime_paths::context::RuntimeContext::profile(&self) -> radroots_runtime_paths::platform::RadrootsPathProfile +pub fn radroots_runtime_paths::context::RuntimeContext::resolve(&radroots_runtime_paths::roots::RadrootsPathResolver, radroots_runtime_paths::context::RuntimeContextBootstrap, radroots_runtime_paths::identifier::ServiceId, radroots_runtime_paths::identifier::InstanceId) -> core::result::Result<Self, radroots_runtime_paths::context::RuntimeContextError> +pub fn radroots_runtime_paths::context::RuntimeContext::service(&self) -> &radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::context::RuntimeContext::sources(&self) -> &radroots_runtime_paths::context::RuntimeContextSources +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::clone(&self) -> radroots_runtime_paths::context::RuntimeContext +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContext +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::eq(&self, &radroots_runtime_paths::context::RuntimeContext) -> bool +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContext +impl serde_core::ser::Serialize for radroots_runtime_paths::context::RuntimeContext +pub fn radroots_runtime_paths::context::RuntimeContext::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContext +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContext +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContext +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContext +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContext +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContext +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContext +pub struct radroots_runtime_paths::RuntimeContextBootstrap +impl radroots_runtime_paths::context::RuntimeContextBootstrap +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::new(radroots_runtime_paths::platform::RadrootsPathProfile, core::option::Option<std::path::PathBuf>, radroots_runtime_paths::context::RuntimeContextSource, radroots_runtime_paths::context::RuntimeContextSource) -> core::result::Result<Self, radroots_runtime_paths::context::RuntimeContextError> +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::profile(&self) -> radroots_runtime_paths::platform::RadrootsPathProfile +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContextBootstrap +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::clone(&self) -> radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContextBootstrap +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::eq(&self, &radroots_runtime_paths::context::RuntimeContextBootstrap) -> bool +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContextBootstrap +pub fn radroots_runtime_paths::context::RuntimeContextBootstrap::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContextBootstrap +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContextBootstrap +pub struct radroots_runtime_paths::RuntimeContextSources +impl radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::instance(&self) -> radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSources::paths(&self) -> radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSources::profile(&self) -> radroots_runtime_paths::context::RuntimeContextSource +pub fn radroots_runtime_paths::context::RuntimeContextSources::repo_local_root(&self) -> core::option::Option<radroots_runtime_paths::context::RuntimeContextSource> +pub fn radroots_runtime_paths::context::RuntimeContextSources::service(&self) -> radroots_runtime_paths::context::RuntimeContextSource +impl core::clone::Clone for radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::clone(&self) -> radroots_runtime_paths::context::RuntimeContextSources +impl core::cmp::Eq for radroots_runtime_paths::context::RuntimeContextSources +impl core::cmp::PartialEq for radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::eq(&self, &radroots_runtime_paths::context::RuntimeContextSources) -> bool +impl core::fmt::Debug for radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for radroots_runtime_paths::context::RuntimeContextSources +impl serde_core::ser::Serialize for radroots_runtime_paths::context::RuntimeContextSources +pub fn radroots_runtime_paths::context::RuntimeContextSources::serialize<__S>(&self, __S) -> core::result::Result<<__S as serde_core::ser::Serializer>::Ok, <__S as serde_core::ser::Serializer>::Error> where __S: serde_core::ser::Serializer +impl core::marker::Freeze for radroots_runtime_paths::context::RuntimeContextSources +impl core::marker::Send for radroots_runtime_paths::context::RuntimeContextSources +impl core::marker::Sync for radroots_runtime_paths::context::RuntimeContextSources +impl core::marker::Unpin for radroots_runtime_paths::context::RuntimeContextSources +impl core::marker::UnsafeUnpin for radroots_runtime_paths::context::RuntimeContextSources +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::context::RuntimeContextSources +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::context::RuntimeContextSources +pub struct radroots_runtime_paths::ServiceCredentialArtifactName(_) +impl radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::as_str(&self) -> &str +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::conventions::ServiceCredentialArtifactNameError> +impl core::clone::Clone for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::clone(&self) -> radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::cmp::Eq for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::cmp::Ord for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::cmp(&self, &radroots_runtime_paths::conventions::ServiceCredentialArtifactName) -> core::cmp::Ordering +impl core::cmp::PartialEq for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::eq(&self, &radroots_runtime_paths::conventions::ServiceCredentialArtifactName) -> bool +impl core::cmp::PartialOrd for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::partial_cmp(&self, &radroots_runtime_paths::conventions::ServiceCredentialArtifactName) -> core::option::Option<core::cmp::Ordering> +impl core::convert::AsRef<str> for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::as_ref(&self) -> &str +impl core::fmt::Debug for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub fn radroots_runtime_paths::conventions::ServiceCredentialArtifactName::hash<__H: core::hash::Hasher>(&self, &mut __H) +impl core::marker::StructuralPartialEq for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::Freeze for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::Send for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::Sync for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::Unpin for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::marker::UnsafeUnpin for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::conventions::ServiceCredentialArtifactName +pub struct radroots_runtime_paths::ServiceId(_) +impl radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::as_str(&self) -> &str +pub fn radroots_runtime_paths::identifier::ServiceId::into_string(self) -> alloc::string::String +pub fn radroots_runtime_paths::identifier::ServiceId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::identifier::ServiceIdentityError> +impl core::clone::Clone for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::clone(&self) -> radroots_runtime_paths::identifier::ServiceId +impl core::cmp::Eq for radroots_runtime_paths::identifier::ServiceId +impl core::cmp::Ord for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::cmp(&self, &radroots_runtime_paths::identifier::ServiceId) -> core::cmp::Ordering +impl core::cmp::PartialEq for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::eq(&self, &radroots_runtime_paths::identifier::ServiceId) -> bool +impl core::cmp::PartialOrd for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::partial_cmp(&self, &radroots_runtime_paths::identifier::ServiceId) -> core::option::Option<core::cmp::Ordering> +impl core::convert::AsRef<str> for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::as_ref(&self) -> &str +impl core::convert::From<radroots_runtime_paths::identifier::ServiceId> for alloc::string::String +pub fn alloc::string::String::from(radroots_runtime_paths::identifier::ServiceId) -> Self +impl core::convert::TryFrom<alloc::string::String> for radroots_runtime_paths::identifier::ServiceId +pub type radroots_runtime_paths::identifier::ServiceId::Error = radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceId::try_from(alloc::string::String) -> core::result::Result<Self, Self::Error> +impl core::fmt::Debug for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::hash<__H: core::hash::Hasher>(&self, &mut __H) +impl core::marker::StructuralPartialEq for radroots_runtime_paths::identifier::ServiceId +impl core::str::traits::FromStr for radroots_runtime_paths::identifier::ServiceId +pub type radroots_runtime_paths::identifier::ServiceId::Err = radroots_runtime_paths::identifier::ServiceIdentityError +pub fn radroots_runtime_paths::identifier::ServiceId::from_str(&str) -> core::result::Result<Self, Self::Err> +impl serde_core::ser::Serialize for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer +impl<'de> serde_core::de::Deserialize<'de> for radroots_runtime_paths::identifier::ServiceId +pub fn radroots_runtime_paths::identifier::ServiceId::deserialize<D>(D) -> core::result::Result<Self, <D as serde_core::de::Deserializer>::Error> where D: serde_core::de::Deserializer<'de> +impl core::marker::Freeze for radroots_runtime_paths::identifier::ServiceId +impl core::marker::Send for radroots_runtime_paths::identifier::ServiceId +impl core::marker::Sync for radroots_runtime_paths::identifier::ServiceId +impl core::marker::Unpin for radroots_runtime_paths::identifier::ServiceId +impl core::marker::UnsafeUnpin for radroots_runtime_paths::identifier::ServiceId +impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::identifier::ServiceId +impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::identifier::ServiceId +pub const radroots_runtime_paths::DEFAULT_CONFIG_FILE_NAME: &str +pub const radroots_runtime_paths::DEFAULT_SHARED_GEONAMES_NAMESPACE: &str +pub const radroots_runtime_paths::DEFAULT_SHARED_GEONAMES_NAMESPACE_KIND: &str +pub const radroots_runtime_paths::DEFAULT_SHARED_GEONAMES_NAMESPACE_VALUE: &str +pub const radroots_runtime_paths::DEFAULT_SHARED_RUNTIME_STORE_DB_FILE_NAME: &str +pub const radroots_runtime_paths::DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE: &str +pub const radroots_runtime_paths::DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_KIND: &str +pub const radroots_runtime_paths::DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_VALUE: &str +pub const radroots_runtime_paths::INSTANCE_ID_MAX_BYTES: usize +pub const radroots_runtime_paths::SERVICE_ADMIN_SOCKET_FILE_NAME: &str +pub const radroots_runtime_paths::SERVICE_CREDENTIAL_ARTIFACT_NAME_MAX_BYTES: usize +pub const radroots_runtime_paths::SERVICE_ID_MAX_BYTES: usize +pub const radroots_runtime_paths::SERVICE_STATE_DATABASE_FILE_NAME: &str +pub const radroots_runtime_paths::SERVICE_STATE_LOCK_FILE_NAME: &str +pub fn radroots_runtime_paths::default_service_instance_artifacts(&radroots_runtime_paths::service::RadrootsServiceInstancePaths) -> radroots_runtime_paths::conventions::RadrootsServiceInstanceArtifacts +pub fn radroots_runtime_paths::default_shared_geonames_database_file_name(&str) -> alloc::string::String +pub fn radroots_runtime_paths::default_shared_geonames_database_path_from_cache_root(impl core::convert::AsRef<std::path::Path>, &str) -> std::path::PathBuf +pub fn radroots_runtime_paths::default_shared_geonames_root_from_cache_root(impl core::convert::AsRef<std::path::Path>) -> std::path::PathBuf +pub fn radroots_runtime_paths::default_shared_runtime_store_database_path_from_data_root(impl core::convert::AsRef<std::path::Path>) -> std::path::PathBuf +pub fn radroots_runtime_paths::default_shared_runtime_store_database_path_from_shared_accounts_data_root(impl core::convert::AsRef<std::path::Path>) -> core::result::Result<std::path::PathBuf, radroots_runtime_paths::error::RadrootsRuntimePathsError> +pub fn radroots_runtime_paths::default_shared_runtime_store_root_from_data_root(impl core::convert::AsRef<std::path::Path>) -> std::path::PathBuf +pub fn radroots_runtime_paths::default_shared_runtime_store_root_from_shared_accounts_data_root(impl core::convert::AsRef<std::path::Path>) -> core::result::Result<std::path::PathBuf, radroots_runtime_paths::error::RadrootsRuntimePathsError> +pub fn radroots_runtime_paths::service_credential_artifact_path(&radroots_runtime_paths::service::RadrootsServiceInstancePaths, &radroots_runtime_paths::conventions::ServiceCredentialArtifactName) -> std::path::PathBuf diff --git a/crates/runtime_paths/README b/crates/runtime_paths/README @@ -1,18 +1,25 @@ # radroots_runtime_paths -This is the README for `radroots_runtime_paths`, which provides canonical -runtime path selection and contract helpers for the `radroots` core libraries. +This is the README for `radroots_runtime_paths`, which provides canonical, +typed runtime paths for the `radroots` core libraries. ## Overview - * default file-name and bootstrap-path helpers for local runtime layouts; - * platform, host-environment, namespace, and path-profile types for path - decisions; - * validated service and instance identifiers for canonical service paths; - * resolver, override, and runtime-selection helpers that produce structured - `RadrootsPaths` outputs; - * service and app contract helpers for active profile, override, and root - selection reporting. + * validated service and instance identifiers for the sole canonical + `services/<service>/<instance>` namespace; + * an injected platform, host-environment, and profile resolver with no ambient + process-environment constructor; + * a sealed `RuntimeContext` as the only public service-instance path + construction boundary; + * non-forgeable service path and common-artifact views with immutable + accessors; and + * pure shared geonames and runtime-store path helpers that do not participate + in service-instance path selection. + +The former generic app/service/worker/shared namespace, raw root containers, +path overrides, process-environment selectors, and bootstrap path helpers are +intentionally removed. Callers must construct typed bootstrap provenance and +resolve a `RuntimeContext` from an explicitly injected resolver. ## Copyright diff --git a/crates/runtime_paths/src/context.rs b/crates/runtime_paths/src/context.rs @@ -7,8 +7,7 @@ use serde::{Serialize, Serializer, ser::SerializeStruct}; use thiserror::Error; use crate::{ - InstanceId, RadrootsPathOverrides, RadrootsPathProfile, RadrootsPathResolver, - RadrootsServiceInstancePaths, ServiceId, default_service_instance_paths, + InstanceId, RadrootsPathProfile, RadrootsPathResolver, RadrootsServiceInstancePaths, ServiceId, }; /// Closed provenance vocabulary for effective runtime configuration. @@ -158,18 +157,10 @@ impl RuntimeContext { service: ServiceId, instance: InstanceId, ) -> Result<Self, RuntimeContextError> { - let overrides = match bootstrap.repo_local_root.as_ref() { - Some(root) => RadrootsPathOverrides::repo_local(root), - None => RadrootsPathOverrides::default(), - }; - let paths = default_service_instance_paths( - resolver, - bootstrap.profile, - &overrides, - &service, - &instance, - ) - .map_err(|_| RuntimeContextError::PathSelection)?; + let roots = resolver + .resolve(bootstrap.profile, bootstrap.repo_local_root.as_deref()) + .map_err(|_| RuntimeContextError::PathSelection)?; + let paths = RadrootsServiceInstancePaths::from_resolved_roots(&roots, &service, &instance); let sources = RuntimeContextSources { service: RuntimeContextSource::SafeDefault, instance: bootstrap.instance_source, @@ -268,6 +259,10 @@ mod tests { }; fn repo_local_context(base: PathBuf) -> RuntimeContext { + repo_local_context_for(base, "myc", "primary") + } + + fn repo_local_context_for(base: PathBuf, service: &str, instance: &str) -> RuntimeContext { RuntimeContext::resolve( &RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()), RuntimeContextBootstrap::new( @@ -277,10 +272,271 @@ mod tests { RuntimeContextSource::BootstrapCli, ) .expect("bootstrap"), + ServiceId::new(service).expect("service"), + InstanceId::new(instance).expect("instance"), + ) + .expect("runtime context") + } + + #[test] + fn one_repo_local_base_derives_exact_noncolliding_service_instances() { + let base = PathBuf::from("/repo/.local/radroots"); + let mut configs = Vec::new(); + + for (service, instance) in [("myc", "primary"), ("myc", "secondary"), ("rhi", "default")] { + let context = repo_local_context_for(base.clone(), service, instance); + let suffix = PathBuf::from("services").join(service).join(instance); + assert_eq!(context.paths().config(), base.join("config").join(&suffix)); + assert_eq!(context.paths().state(), base.join("data").join(&suffix)); + assert_eq!(context.paths().cache(), base.join("cache").join(&suffix)); + assert_eq!(context.paths().logs(), base.join("logs").join(&suffix)); + assert_eq!(context.paths().run(), base.join("run").join(&suffix)); + assert_eq!( + context.paths().secrets(), + base.join("secrets").join(&suffix) + ); + configs.push(context.paths().config().to_path_buf()); + } + + configs.sort(); + configs.dedup(); + assert_eq!(configs.len(), 3); + } + + #[test] + fn retained_macos_and_windows_profiles_derive_exact_context_paths() { + let macos = RuntimeContext::resolve( + &RadrootsPathResolver::new( + RadrootsPlatform::Macos, + RadrootsHostEnvironment { + home_dir: Some(PathBuf::from("/Users/treesap")), + ..RadrootsHostEnvironment::default() + }, + ), + RuntimeContextBootstrap::new( + RadrootsPathProfile::InteractiveUser, + None, + RuntimeContextSource::SafeDefault, + RuntimeContextSource::BootstrapCli, + ) + .expect("macOS bootstrap"), ServiceId::new("myc").expect("service"), InstanceId::new("primary").expect("instance"), ) - .expect("runtime context") + .expect("macOS context"); + assert_eq!( + macos.paths().config(), + PathBuf::from( + "/Users/treesap/Library/Application Support/Radroots/config/services/myc/primary" + ) + ); + assert_eq!( + macos.paths().state(), + PathBuf::from( + "/Users/treesap/Library/Application Support/Radroots/data/services/myc/primary" + ) + ); + assert_eq!( + macos.paths().cache(), + PathBuf::from("/Users/treesap/Library/Caches/Radroots/services/myc/primary") + ); + assert_eq!( + macos.paths().logs(), + PathBuf::from("/Users/treesap/Library/Logs/Radroots/services/myc/primary") + ); + assert_eq!( + macos.paths().run(), + PathBuf::from( + "/Users/treesap/Library/Application Support/Radroots/run/services/myc/primary" + ) + ); + assert_eq!( + macos.paths().secrets(), + PathBuf::from( + "/Users/treesap/Library/Application Support/Radroots/secrets/services/myc/primary" + ) + ); + + let appdata = PathBuf::from(r"C:\Users\treesap\AppData\Roaming"); + let localappdata = PathBuf::from(r"C:\Users\treesap\AppData\Local"); + let windows = RuntimeContext::resolve( + &RadrootsPathResolver::new( + RadrootsPlatform::Windows, + RadrootsHostEnvironment { + appdata_dir: Some(appdata.clone()), + localappdata_dir: Some(localappdata.clone()), + ..RadrootsHostEnvironment::default() + }, + ), + RuntimeContextBootstrap::new( + RadrootsPathProfile::InteractiveUser, + None, + RuntimeContextSource::SafeDefault, + RuntimeContextSource::BootstrapCli, + ) + .expect("Windows bootstrap"), + ServiceId::new("rhi").expect("service"), + InstanceId::new("default").expect("instance"), + ) + .expect("Windows context"); + let suffix = PathBuf::from("services/rhi/default"); + assert_eq!( + windows.paths().config(), + appdata.join("Radroots/config").join(&suffix) + ); + assert_eq!( + windows.paths().state(), + localappdata.join("Radroots/data").join(&suffix) + ); + assert_eq!( + windows.paths().cache(), + localappdata.join("Radroots/cache").join(&suffix) + ); + assert_eq!( + windows.paths().logs(), + localappdata.join("Radroots/logs").join(&suffix) + ); + assert_eq!( + windows.paths().run(), + localappdata.join("Radroots/run").join(&suffix) + ); + assert_eq!( + windows.paths().secrets(), + appdata.join("Radroots/secrets").join(&suffix) + ); + + assert_eq!( + RuntimeContext::resolve( + &RadrootsPathResolver::new( + RadrootsPlatform::Windows, + RadrootsHostEnvironment::default(), + ), + RuntimeContextBootstrap::new( + RadrootsPathProfile::InteractiveUser, + None, + RuntimeContextSource::SafeDefault, + RuntimeContextSource::BootstrapCli, + ) + .expect("missing-directory bootstrap"), + ServiceId::new("myc").expect("service"), + InstanceId::new("primary").expect("instance"), + ), + Err(RuntimeContextError::PathSelection) + ); + } + + #[test] + fn retained_linux_xdg_vectors_are_exact_and_ignore_invalid_optional_values() { + fn resolve( + environment: RadrootsHostEnvironment, + ) -> Result<RuntimeContext, RuntimeContextError> { + RuntimeContext::resolve( + &RadrootsPathResolver::new(RadrootsPlatform::Linux, environment), + RuntimeContextBootstrap::new( + RadrootsPathProfile::InteractiveUser, + None, + RuntimeContextSource::SafeDefault, + RuntimeContextSource::BootstrapCli, + ) + .expect("Linux bootstrap"), + ServiceId::new("myc").expect("service"), + InstanceId::new("primary").expect("instance"), + ) + } + + let configured = resolve(RadrootsHostEnvironment { + home_dir: Some(PathBuf::from("/home/treesap")), + xdg_config_home: Some(PathBuf::from("/xdg/config")), + xdg_data_home: Some(PathBuf::from("/xdg/data")), + xdg_state_home: Some(PathBuf::from("/xdg/state")), + xdg_cache_home: Some(PathBuf::from("/xdg/cache")), + xdg_runtime_dir: Some(PathBuf::from("/xdg/run")), + ..RadrootsHostEnvironment::default() + }) + .expect("configured XDG context"); + assert_eq!( + configured.paths().config(), + PathBuf::from("/xdg/config/radroots/services/myc/primary") + ); + assert_eq!( + configured.paths().state(), + PathBuf::from("/xdg/data/radroots/services/myc/primary") + ); + assert_eq!( + configured.paths().cache(), + PathBuf::from("/xdg/cache/radroots/services/myc/primary") + ); + assert_eq!( + configured.paths().logs(), + PathBuf::from("/xdg/state/radroots/logs/services/myc/primary") + ); + assert_eq!( + configured.paths().run(), + PathBuf::from("/xdg/run/radroots/services/myc/primary") + ); + assert_eq!( + configured.paths().secrets(), + PathBuf::from("/xdg/config/radroots/secrets/services/myc/primary") + ); + + for invalid in ["", "relative"] { + let config = resolve(RadrootsHostEnvironment { + home_dir: Some(PathBuf::from("/home/treesap")), + xdg_config_home: Some(PathBuf::from(invalid)), + xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), + ..RadrootsHostEnvironment::default() + }) + .expect("invalid config override is ignored"); + assert_eq!( + config.paths().config(), + PathBuf::from("/home/treesap/.config/radroots/services/myc/primary") + ); + + let data = resolve(RadrootsHostEnvironment { + home_dir: Some(PathBuf::from("/home/treesap")), + xdg_data_home: Some(PathBuf::from(invalid)), + xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), + ..RadrootsHostEnvironment::default() + }) + .expect("invalid data override is ignored"); + assert_eq!( + data.paths().state(), + PathBuf::from("/home/treesap/.local/share/radroots/services/myc/primary") + ); + + let state = resolve(RadrootsHostEnvironment { + home_dir: Some(PathBuf::from("/home/treesap")), + xdg_state_home: Some(PathBuf::from(invalid)), + xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), + ..RadrootsHostEnvironment::default() + }) + .expect("invalid state override is ignored"); + assert_eq!( + state.paths().logs(), + PathBuf::from("/home/treesap/.local/state/radroots/logs/services/myc/primary") + ); + + let cache = resolve(RadrootsHostEnvironment { + home_dir: Some(PathBuf::from("/home/treesap")), + xdg_cache_home: Some(PathBuf::from(invalid)), + xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), + ..RadrootsHostEnvironment::default() + }) + .expect("invalid cache override is ignored"); + assert_eq!( + cache.paths().cache(), + PathBuf::from("/home/treesap/.cache/radroots/services/myc/primary") + ); + + assert_eq!( + resolve(RadrootsHostEnvironment { + home_dir: Some(PathBuf::from("/home/treesap")), + xdg_runtime_dir: Some(PathBuf::from(invalid)), + ..RadrootsHostEnvironment::default() + }), + Err(RuntimeContextError::PathSelection) + ); + } } #[test] diff --git a/crates/runtime_paths/src/conventions.rs b/crates/runtime_paths/src/conventions.rs @@ -5,19 +5,13 @@ use std::{ use thiserror::Error; -use crate::{ - InstanceId, RadrootsPathOverrides, RadrootsPathProfile, RadrootsPathResolver, - RadrootsRuntimeNamespace, RadrootsRuntimePathsError, RadrootsServiceInstanceNamespace, - RadrootsServiceInstancePaths, ServiceId, -}; +use crate::{RadrootsRuntimePathsError, RadrootsServiceInstancePaths}; pub const DEFAULT_CONFIG_FILE_NAME: &str = "config.toml"; pub const SERVICE_STATE_DATABASE_FILE_NAME: &str = "state.sqlite"; pub const SERVICE_STATE_LOCK_FILE_NAME: &str = "state.lock"; pub const SERVICE_ADMIN_SOCKET_FILE_NAME: &str = "admin.sock"; pub const SERVICE_CREDENTIAL_ARTIFACT_NAME_MAX_BYTES: usize = 128; -pub const DEFAULT_SERVICE_IDENTITY_FILE_NAME: &str = "identity.secret.json"; -pub const DEFAULT_SHARED_IDENTITY_FILE_NAME: &str = "default.json"; pub const DEFAULT_SHARED_GEONAMES_NAMESPACE_KIND: &str = "shared"; pub const DEFAULT_SHARED_GEONAMES_NAMESPACE_VALUE: &str = "geonames"; pub const DEFAULT_SHARED_GEONAMES_NAMESPACE: &str = "shared/geonames"; @@ -26,13 +20,6 @@ pub const DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_VALUE: &str = "runtime_store"; pub const DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE: &str = "shared/runtime_store"; pub const DEFAULT_SHARED_RUNTIME_STORE_DB_FILE_NAME: &str = "runtime_store.sqlite"; -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RadrootsBootstrapPaths { - pub config_path: PathBuf, - pub logs_dir: PathBuf, - pub identity_path: PathBuf, -} - /// A validated service-owned credential artifact filename. #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ServiceCredentialArtifactName(String); @@ -168,55 +155,6 @@ pub fn service_credential_artifact_path( paths.secrets().join(name.as_str()) } -pub fn default_service_instance_paths( - resolver: &RadrootsPathResolver, - profile: RadrootsPathProfile, - overrides: &RadrootsPathOverrides, - service_id: &ServiceId, - instance_id: &InstanceId, -) -> Result<RadrootsServiceInstancePaths, RadrootsRuntimePathsError> { - let namespace = RadrootsServiceInstanceNamespace::new(service_id.clone(), instance_id.clone()); - let roots = resolver.resolve(profile, overrides)?; - Ok(RadrootsServiceInstancePaths::from_resolved_roots( - &roots, &namespace, - )) -} - -pub fn default_namespaced_bootstrap_paths( - resolver: &RadrootsPathResolver, - profile: RadrootsPathProfile, - overrides: &RadrootsPathOverrides, - namespace: &RadrootsRuntimeNamespace, - identity_file_name: &str, -) -> Result<RadrootsBootstrapPaths, RadrootsRuntimePathsError> { - let namespaced = resolver.resolve(profile, overrides)?.namespaced(namespace); - Ok(RadrootsBootstrapPaths { - config_path: namespaced.config.join(DEFAULT_CONFIG_FILE_NAME), - logs_dir: namespaced.logs, - identity_path: namespaced.secrets.join(identity_file_name), - }) -} - -pub fn default_shared_identity_path( - resolver: &RadrootsPathResolver, - profile: RadrootsPathProfile, - overrides: &RadrootsPathOverrides, -) -> Result<PathBuf, RadrootsRuntimePathsError> { - let namespace = RadrootsRuntimeNamespace::shared("identities")?; - let namespaced = resolver.resolve(profile, overrides)?.namespaced(&namespace); - Ok(namespaced.secrets.join(DEFAULT_SHARED_IDENTITY_FILE_NAME)) -} - -pub fn default_shared_runtime_logs_dir( - resolver: &RadrootsPathResolver, - profile: RadrootsPathProfile, - overrides: &RadrootsPathOverrides, -) -> Result<PathBuf, RadrootsRuntimePathsError> { - let namespace = RadrootsRuntimeNamespace::shared("runtime")?; - let namespaced = resolver.resolve(profile, overrides)?.namespaced(&namespace); - Ok(namespaced.logs) -} - #[must_use] pub fn default_shared_runtime_store_root_from_data_root(data_root: impl AsRef<Path>) -> PathBuf { data_root @@ -278,111 +216,41 @@ pub fn default_shared_runtime_store_database_path_from_shared_accounts_data_root mod tests { use std::path::PathBuf; - use crate::{ - RadrootsHostEnvironment, RadrootsPlatform, RadrootsRuntimeNamespace, - RadrootsRuntimePathsError, - }; - use super::{ - DEFAULT_CONFIG_FILE_NAME, DEFAULT_SERVICE_IDENTITY_FILE_NAME, - DEFAULT_SHARED_GEONAMES_NAMESPACE, DEFAULT_SHARED_IDENTITY_FILE_NAME, + DEFAULT_CONFIG_FILE_NAME, DEFAULT_SHARED_GEONAMES_NAMESPACE, DEFAULT_SHARED_RUNTIME_STORE_DB_FILE_NAME, DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE, SERVICE_ADMIN_SOCKET_FILE_NAME, SERVICE_CREDENTIAL_ARTIFACT_NAME_MAX_BYTES, SERVICE_STATE_DATABASE_FILE_NAME, SERVICE_STATE_LOCK_FILE_NAME, ServiceCredentialArtifactName, ServiceCredentialArtifactNameError, - default_namespaced_bootstrap_paths, default_service_instance_artifacts, - default_service_instance_paths, default_shared_geonames_database_file_name, + default_service_instance_artifacts, default_shared_geonames_database_file_name, default_shared_geonames_database_path_from_cache_root, - default_shared_geonames_root_from_cache_root, default_shared_identity_path, - default_shared_runtime_logs_dir, default_shared_runtime_store_database_path_from_data_root, + default_shared_geonames_root_from_cache_root, + default_shared_runtime_store_database_path_from_data_root, default_shared_runtime_store_database_path_from_shared_accounts_data_root, default_shared_runtime_store_root_from_data_root, default_shared_runtime_store_root_from_shared_accounts_data_root, service_credential_artifact_path, }; - use crate::{InstanceId, ServiceId}; - - #[test] - fn service_instance_paths_are_exact_for_linux_and_xdg_profiles() { - let service_id = ServiceId::new("myc").expect("service id"); - let instance_id = InstanceId::new("primary").expect("instance id"); - let service_host = crate::RadrootsPathResolver::new( - RadrootsPlatform::Linux, - RadrootsHostEnvironment::default(), - ); - let service_paths = default_service_instance_paths( - &service_host, - crate::RadrootsPathProfile::ServiceHost, - &crate::RadrootsPathOverrides::default(), - &service_id, - &instance_id, - ) - .expect("service-host paths"); - assert_eq!( - service_paths.config(), - PathBuf::from("/etc/radroots/services/myc/primary") - ); - assert_eq!( - service_paths.state(), - PathBuf::from("/var/lib/radroots/services/myc/primary") - ); - assert_eq!( - service_paths.cache(), - PathBuf::from("/var/cache/radroots/services/myc/primary") - ); - assert_eq!( - service_paths.logs(), - PathBuf::from("/var/log/radroots/services/myc/primary") - ); - assert_eq!( - service_paths.run(), - PathBuf::from("/run/radroots/services/myc/primary") - ); - assert_eq!( - service_paths.secrets(), - PathBuf::from("/etc/radroots/secrets/services/myc/primary") - ); + use crate::{ + InstanceId, RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPathResolver, + RadrootsPlatform, RadrootsRuntimePathsError, RuntimeContext, RuntimeContextBootstrap, + RuntimeContextSource, ServiceId, + }; - let interactive = crate::RadrootsPathResolver::new( - RadrootsPlatform::Linux, - RadrootsHostEnvironment { - home_dir: Some(PathBuf::from("/home/treesap")), - xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), - ..RadrootsHostEnvironment::default() - }, - ); - let interactive_paths = default_service_instance_paths( - &interactive, - crate::RadrootsPathProfile::InteractiveUser, - &crate::RadrootsPathOverrides::default(), - &service_id, - &instance_id, + fn service_context(service: &str, instance: &str) -> RuntimeContext { + RuntimeContext::resolve( + &RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()), + RuntimeContextBootstrap::new( + RadrootsPathProfile::ServiceHost, + None, + RuntimeContextSource::SafeDefault, + RuntimeContextSource::BootstrapCli, + ) + .expect("bootstrap"), + ServiceId::new(service).expect("service"), + InstanceId::new(instance).expect("instance"), ) - .expect("XDG paths"); - assert_eq!( - interactive_paths.config(), - PathBuf::from("/home/treesap/.config/radroots/services/myc/primary") - ); - assert_eq!( - interactive_paths.state(), - PathBuf::from("/home/treesap/.local/share/radroots/services/myc/primary") - ); - assert_eq!( - interactive_paths.cache(), - PathBuf::from("/home/treesap/.cache/radroots/services/myc/primary") - ); - assert_eq!( - interactive_paths.logs(), - PathBuf::from("/home/treesap/.local/state/radroots/logs/services/myc/primary") - ); - assert_eq!( - interactive_paths.run(), - PathBuf::from("/run/user/1000/radroots/services/myc/primary") - ); - assert_eq!( - interactive_paths.secrets(), - PathBuf::from("/home/treesap/.config/radroots/secrets/services/myc/primary") - ); + .expect("context") } #[test] @@ -392,19 +260,8 @@ mod tests { assert_eq!(SERVICE_STATE_LOCK_FILE_NAME, "state.lock"); assert_eq!(SERVICE_ADMIN_SOCKET_FILE_NAME, "admin.sock"); - let resolver = crate::RadrootsPathResolver::new( - RadrootsPlatform::Linux, - RadrootsHostEnvironment::default(), - ); - let paths = default_service_instance_paths( - &resolver, - crate::RadrootsPathProfile::ServiceHost, - &crate::RadrootsPathOverrides::default(), - &ServiceId::new("myc").expect("service id"), - &InstanceId::new("primary").expect("instance id"), - ) - .expect("instance paths"); - let artifacts = default_service_instance_artifacts(&paths); + let context = service_context("myc", "primary"); + let artifacts = default_service_instance_artifacts(context.paths()); assert_eq!( artifacts.config(), @@ -426,18 +283,8 @@ mod tests { #[test] fn credential_artifact_names_are_validated_and_remain_outside_state() { - let resolver = crate::RadrootsPathResolver::new( - RadrootsPlatform::Linux, - RadrootsHostEnvironment::default(), - ); - let paths = default_service_instance_paths( - &resolver, - crate::RadrootsPathProfile::ServiceHost, - &crate::RadrootsPathOverrides::default(), - &ServiceId::new("rhi").expect("service id"), - &InstanceId::new("default").expect("instance id"), - ) - .expect("instance paths"); + let context = service_context("rhi", "default"); + let paths = context.paths(); let name = ServiceCredentialArtifactName::new("identity.secret.json").expect("credential name"); assert_eq!( @@ -445,14 +292,14 @@ mod tests { "ServiceCredentialArtifactName([redacted])" ); assert!(!format!("{name:?}").contains("identity.secret.json")); - let credential = service_credential_artifact_path(&paths, &name); + let credential = service_credential_artifact_path(paths, &name); assert_eq!( credential, PathBuf::from("/etc/radroots/secrets/services/rhi/default/identity.secret.json") ); assert!(!credential.starts_with(paths.state())); - let artifacts = default_service_instance_artifacts(&paths); + let artifacts = default_service_instance_artifacts(paths); let artifacts_debug = format!("{artifacts:?}"); assert_eq!( artifacts_debug, @@ -501,83 +348,8 @@ mod tests { } #[test] - fn namespaced_bootstrap_paths_use_canonical_interactive_roots() { - let resolver = crate::RadrootsPathResolver::new( - RadrootsPlatform::Linux, - RadrootsHostEnvironment { - home_dir: Some(PathBuf::from("/home/treesap")), - xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), - ..RadrootsHostEnvironment::default() - }, - ); - let namespace = - RadrootsRuntimeNamespace::service("radrootsd").expect("service namespace should parse"); - - let paths = default_namespaced_bootstrap_paths( - &resolver, - crate::RadrootsPathProfile::InteractiveUser, - &crate::RadrootsPathOverrides::default(), - &namespace, - DEFAULT_SERVICE_IDENTITY_FILE_NAME, - ) - .expect("service bootstrap paths should resolve"); - - assert_eq!( - paths.config_path, - PathBuf::from("/home/treesap/.config/radroots/services/radrootsd/config.toml") - ); - assert_eq!( - paths.logs_dir, - PathBuf::from("/home/treesap/.local/state/radroots/logs/services/radrootsd") - ); - assert_eq!( - paths.identity_path, - PathBuf::from( - "/home/treesap/.config/radroots/secrets/services/radrootsd/identity.secret.json" - ) - ); - } - - #[test] - fn shared_defaults_use_shared_namespaces() { - let resolver = crate::RadrootsPathResolver::new( - RadrootsPlatform::Macos, - RadrootsHostEnvironment { - home_dir: Some(PathBuf::from("/Users/treesap")), - ..RadrootsHostEnvironment::default() - }, - ); - - let identity_path = default_shared_identity_path( - &resolver, - crate::RadrootsPathProfile::InteractiveUser, - &crate::RadrootsPathOverrides::default(), - ) - .expect("shared identity path should resolve"); - assert_eq!( - identity_path, - PathBuf::from( - "/Users/treesap/Library/Application Support/Radroots/secrets/shared/identities" - ) - .join(DEFAULT_SHARED_IDENTITY_FILE_NAME) - ); - - let logs_dir = default_shared_runtime_logs_dir( - &resolver, - crate::RadrootsPathProfile::InteractiveUser, - &crate::RadrootsPathOverrides::default(), - ) - .expect("shared runtime logs dir should resolve"); - assert_eq!( - logs_dir, - PathBuf::from("/Users/treesap/Library/Logs/Radroots/shared/runtime") - ); - } - - #[test] fn shared_runtime_store_paths_use_canonical_shared_namespace() { let data_root = PathBuf::from("/repo/infra/local/runtime/radroots/data"); - assert_eq!( default_shared_runtime_store_root_from_data_root(&data_root), data_root.join(DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE) @@ -593,7 +365,6 @@ mod tests { #[test] fn shared_geonames_paths_use_canonical_shared_cache_namespace() { let cache_root = PathBuf::from("/repo/infra/local/runtime/radroots/cache"); - assert_eq!( default_shared_geonames_root_from_cache_root(&cache_root), cache_root.join(DEFAULT_SHARED_GEONAMES_NAMESPACE) @@ -614,7 +385,6 @@ mod tests { fn shared_runtime_store_paths_derive_from_shared_accounts_data_root() { let shared_accounts_data_root = PathBuf::from("/repo/infra/local/runtime/radroots/data/shared/accounts"); - assert_eq!( default_shared_runtime_store_root_from_shared_accounts_data_root( &shared_accounts_data_root @@ -623,13 +393,6 @@ mod tests { PathBuf::from("/repo/infra/local/runtime/radroots/data/shared/runtime_store") ); assert_eq!( - default_shared_runtime_store_root_from_shared_accounts_data_root( - shared_accounts_data_root.clone() - ) - .expect("shared runtime-store root from owned path"), - PathBuf::from("/repo/infra/local/runtime/radroots/data/shared/runtime_store") - ); - assert_eq!( default_shared_runtime_store_database_path_from_shared_accounts_data_root( &shared_accounts_data_root ) @@ -639,72 +402,12 @@ mod tests { ) ); - let err = - default_shared_runtime_store_root_from_shared_accounts_data_root(PathBuf::from("/")) - .expect_err("root path has no parent shared data root"); assert_eq!( - err, + default_shared_runtime_store_root_from_shared_accounts_data_root(PathBuf::from("/")) + .expect_err("root path has no parent"), RadrootsRuntimePathsError::SharedAccountsDataRootMissingParent { path: PathBuf::from("/") } ); } - - #[test] - fn namespaced_bootstrap_paths_propagate_resolver_errors() { - let resolver = - crate::RadrootsPathResolver::new(RadrootsPlatform::Linux, Default::default()); - let namespace = - RadrootsRuntimeNamespace::service("radrootsd").expect("service namespace should parse"); - - let err = default_namespaced_bootstrap_paths( - &resolver, - crate::RadrootsPathProfile::InteractiveUser, - &crate::RadrootsPathOverrides::default(), - &namespace, - DEFAULT_SERVICE_IDENTITY_FILE_NAME, - ) - .expect_err("interactive user should require a home dir"); - - assert_eq!( - err, - crate::RadrootsRuntimePathsError::MissingHomeDir { - platform: RadrootsPlatform::Linux, - } - ); - } - - #[test] - fn shared_defaults_propagate_profile_errors() { - let resolver = - crate::RadrootsPathResolver::new(RadrootsPlatform::Android, Default::default()); - - let identity_err = default_shared_identity_path( - &resolver, - crate::RadrootsPathProfile::InteractiveUser, - &crate::RadrootsPathOverrides::default(), - ) - .expect_err("interactive_user should be unsupported on android"); - assert_eq!( - identity_err, - crate::RadrootsRuntimePathsError::UnsupportedProfilePlatform { - profile: crate::RadrootsPathProfile::InteractiveUser, - platform: RadrootsPlatform::Android, - } - ); - - let logs_err = default_shared_runtime_logs_dir( - &resolver, - crate::RadrootsPathProfile::ServiceHost, - &crate::RadrootsPathOverrides::default(), - ) - .expect_err("service_host should be unsupported on android"); - assert_eq!( - logs_err, - crate::RadrootsRuntimePathsError::UnsupportedProfilePlatform { - profile: crate::RadrootsPathProfile::ServiceHost, - platform: RadrootsPlatform::Android, - } - ); - } } diff --git a/crates/runtime_paths/src/error.rs b/crates/runtime_paths/src/error.rs @@ -24,18 +24,12 @@ pub enum RadrootsRuntimePathsError { #[error("repo_local base root must be an absolute non-root path without parent traversal")] InvalidRepoLocalRoot, - #[error("mobile_native requires explicit logical roots")] - MissingMobileRoots, - #[error("{profile} is not supported on {platform}")] UnsupportedProfilePlatform { profile: RadrootsPathProfile, platform: RadrootsPlatform, }, - #[error("runtime namespace `{value}` must be one non-empty path component")] - InvalidNamespaceComponent { value: String }, - #[error("shared accounts data root `{path:?}` has no parent shared data root")] SharedAccountsDataRootMissingParent { path: PathBuf }, } diff --git a/crates/runtime_paths/src/lib.rs b/crates/runtime_paths/src/lib.rs @@ -4,7 +4,6 @@ pub mod context; pub mod conventions; pub mod error; pub mod identifier; -pub mod namespace; pub mod platform; pub mod roots; pub mod service; @@ -14,20 +13,18 @@ pub use context::{ RuntimeContextSources, }; pub use conventions::{ - DEFAULT_CONFIG_FILE_NAME, DEFAULT_SERVICE_IDENTITY_FILE_NAME, - DEFAULT_SHARED_GEONAMES_NAMESPACE, DEFAULT_SHARED_GEONAMES_NAMESPACE_KIND, - DEFAULT_SHARED_GEONAMES_NAMESPACE_VALUE, DEFAULT_SHARED_IDENTITY_FILE_NAME, + DEFAULT_CONFIG_FILE_NAME, DEFAULT_SHARED_GEONAMES_NAMESPACE, + DEFAULT_SHARED_GEONAMES_NAMESPACE_KIND, DEFAULT_SHARED_GEONAMES_NAMESPACE_VALUE, DEFAULT_SHARED_RUNTIME_STORE_DB_FILE_NAME, DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE, DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_KIND, DEFAULT_SHARED_RUNTIME_STORE_NAMESPACE_VALUE, - RadrootsBootstrapPaths, RadrootsServiceInstanceArtifacts, SERVICE_ADMIN_SOCKET_FILE_NAME, + RadrootsServiceInstanceArtifacts, SERVICE_ADMIN_SOCKET_FILE_NAME, SERVICE_CREDENTIAL_ARTIFACT_NAME_MAX_BYTES, SERVICE_STATE_DATABASE_FILE_NAME, SERVICE_STATE_LOCK_FILE_NAME, ServiceCredentialArtifactName, - ServiceCredentialArtifactNameError, default_namespaced_bootstrap_paths, - default_service_instance_artifacts, default_service_instance_paths, + ServiceCredentialArtifactNameError, default_service_instance_artifacts, default_shared_geonames_database_file_name, default_shared_geonames_database_path_from_cache_root, - default_shared_geonames_root_from_cache_root, default_shared_identity_path, - default_shared_runtime_logs_dir, default_shared_runtime_store_database_path_from_data_root, + default_shared_geonames_root_from_cache_root, + default_shared_runtime_store_database_path_from_data_root, default_shared_runtime_store_database_path_from_shared_accounts_data_root, default_shared_runtime_store_root_from_data_root, default_shared_runtime_store_root_from_shared_accounts_data_root, @@ -38,327 +35,6 @@ pub use identifier::{ INSTANCE_ID_MAX_BYTES, InstanceId, SERVICE_ID_MAX_BYTES, ServiceId, ServiceIdentityError, ServiceIdentityKind, }; -pub use namespace::{ - RadrootsRuntimeNamespace, RadrootsRuntimeNamespaceKind, RadrootsServiceInstanceNamespace, -}; pub use platform::{RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPlatform}; -pub use roots::{RadrootsPathOverrides, RadrootsPathResolver, RadrootsPaths}; -pub use service::{ - RadrootsRuntimePathConfigEntry, RadrootsRuntimePathPolicyContract, - RadrootsRuntimePathSelection, RadrootsRuntimePathSelectionError, - RadrootsRuntimeSelectionContract, RadrootsRuntimeSelectionOverrideContract, - RadrootsServiceInstancePaths, -}; - -#[cfg(test)] -mod tests { - use std::path::PathBuf; - - use super::{ - RadrootsHostEnvironment, RadrootsPathOverrides, RadrootsPathProfile, RadrootsPathResolver, - RadrootsPaths, RadrootsPlatform, RadrootsRuntimeNamespace, RadrootsRuntimePathsError, - }; - - #[test] - fn interactive_user_linux_uses_xdg_defaults_and_explicit_runtime() { - let resolver = RadrootsPathResolver::new( - RadrootsPlatform::Linux, - RadrootsHostEnvironment { - home_dir: Some(PathBuf::from("/home/treesap")), - xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), - ..RadrootsHostEnvironment::default() - }, - ); - - let roots = resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect("resolve linux interactive roots"); - - assert_eq!( - roots.config, - PathBuf::from("/home/treesap/.config/radroots") - ); - assert_eq!( - roots.data, - PathBuf::from("/home/treesap/.local/share/radroots") - ); - assert_eq!( - roots.logs, - PathBuf::from("/home/treesap/.local/state/radroots/logs") - ); - assert_eq!(roots.run, PathBuf::from("/run/user/1000/radroots")); - assert_eq!( - roots.secrets, - PathBuf::from("/home/treesap/.config/radroots/secrets") - ); - } - - #[test] - fn interactive_user_macos_uses_native_library_roots() { - let resolver = RadrootsPathResolver::new( - RadrootsPlatform::Macos, - RadrootsHostEnvironment { - home_dir: Some(PathBuf::from("/Users/treesap")), - ..RadrootsHostEnvironment::default() - }, - ); - - let roots = resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect("resolve macos interactive roots"); - - assert_eq!( - roots, - RadrootsPaths { - config: PathBuf::from("/Users/treesap/Library/Application Support/Radroots/config",), - data: PathBuf::from("/Users/treesap/Library/Application Support/Radroots/data",), - cache: PathBuf::from("/Users/treesap/Library/Caches/Radroots"), - logs: PathBuf::from("/Users/treesap/Library/Logs/Radroots"), - run: PathBuf::from("/Users/treesap/Library/Application Support/Radroots/run",), - secrets: PathBuf::from( - "/Users/treesap/Library/Application Support/Radroots/secrets", - ), - } - ); - } - - #[test] - fn interactive_user_windows_uses_native_user_roots() { - let resolver = RadrootsPathResolver::new( - RadrootsPlatform::Windows, - RadrootsHostEnvironment { - appdata_dir: Some(PathBuf::from(r"C:\Users\treesap\AppData\Roaming")), - localappdata_dir: Some(PathBuf::from(r"C:\Users\treesap\AppData\Local")), - ..RadrootsHostEnvironment::default() - }, - ); - - let roots = resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect("resolve windows interactive roots"); - - assert_eq!( - roots, - RadrootsPaths { - config: PathBuf::from(r"C:\Users\treesap\AppData\Roaming") - .join("Radroots") - .join("config"), - data: PathBuf::from(r"C:\Users\treesap\AppData\Local") - .join("Radroots") - .join("data"), - cache: PathBuf::from(r"C:\Users\treesap\AppData\Local") - .join("Radroots") - .join("cache"), - logs: PathBuf::from(r"C:\Users\treesap\AppData\Local") - .join("Radroots") - .join("logs"), - run: PathBuf::from(r"C:\Users\treesap\AppData\Local") - .join("Radroots") - .join("run"), - secrets: PathBuf::from(r"C:\Users\treesap\AppData\Roaming") - .join("Radroots") - .join("secrets"), - } - ); - } - - #[test] - fn service_host_linux_uses_canonical_service_roots() { - let resolver = - RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); - - let roots = resolver - .resolve( - RadrootsPathProfile::ServiceHost, - &RadrootsPathOverrides::default(), - ) - .expect("resolve service_host roots"); - - assert_eq!( - roots, - RadrootsPaths { - config: PathBuf::from("/etc/radroots"), - data: PathBuf::from("/var/lib/radroots"), - cache: PathBuf::from("/var/cache/radroots"), - logs: PathBuf::from("/var/log/radroots"), - run: PathBuf::from("/run/radroots"), - secrets: PathBuf::from("/etc/radroots/secrets"), - } - ); - } - - #[test] - fn service_host_is_unsupported_outside_linux() { - for platform in [ - RadrootsPlatform::Macos, - RadrootsPlatform::Windows, - 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] - fn repo_local_requires_explicit_base_root() { - let resolver = - RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); - - let err = resolver - .resolve( - RadrootsPathProfile::RepoLocal, - &RadrootsPathOverrides::default(), - ) - .expect_err("repo_local should require an explicit base root"); - - assert_eq!(err, RadrootsRuntimePathsError::MissingRepoLocalRoot); - } - - #[test] - fn repo_local_uses_explicit_base_root() { - let resolver = - RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); - - let roots = resolver - .resolve( - RadrootsPathProfile::RepoLocal, - &RadrootsPathOverrides::repo_local("/repo/.local/radroots"), - ) - .expect("resolve repo_local roots"); - - assert_eq!( - roots, - RadrootsPaths::from_base_root("/repo/.local/radroots") - ); - } - - #[test] - fn mobile_native_requires_explicit_roots() { - let resolver = RadrootsPathResolver::new( - RadrootsPlatform::Android, - RadrootsHostEnvironment::default(), - ); - - let err = resolver - .resolve( - RadrootsPathProfile::MobileNative, - &RadrootsPathOverrides::default(), - ) - .expect_err("mobile_native should require explicit roots"); - - assert_eq!(err, RadrootsRuntimePathsError::MissingMobileRoots); - } - - #[test] - fn mobile_native_returns_explicit_roots() { - let resolver = - RadrootsPathResolver::new(RadrootsPlatform::Ios, RadrootsHostEnvironment::default()); - let mobile_roots = RadrootsPaths { - config: PathBuf::from("/sandbox/config"), - data: PathBuf::from("/sandbox/data"), - cache: PathBuf::from("/sandbox/cache"), - logs: PathBuf::from("/sandbox/logs"), - run: PathBuf::from("/sandbox/run"), - secrets: PathBuf::from("/sandbox/secrets"), - }; - - let roots = resolver - .resolve( - RadrootsPathProfile::MobileNative, - &RadrootsPathOverrides::mobile(mobile_roots.clone()), - ) - .expect("resolve mobile_native roots"); - - assert_eq!(roots, mobile_roots); - } - - #[test] - fn namespace_derivation_keeps_runtime_segments_explicit() { - let namespace = RadrootsRuntimeNamespace::service("myc").expect("namespace"); - let roots = RadrootsPaths::from_base_root("/logical-root"); - let namespaced = roots.namespaced(&namespace); - - assert_eq!( - namespaced.config, - PathBuf::from("/logical-root/config/services/myc") - ); - assert_eq!( - namespaced.data, - PathBuf::from("/logical-root/data/services/myc") - ); - assert_eq!( - namespaced.secrets, - PathBuf::from("/logical-root/secrets/services/myc") - ); - } - - #[test] - fn namespace_validation_rejects_path_escape_values() { - let err = RadrootsRuntimeNamespace::app("../cli").expect_err("invalid namespace"); - assert_eq!( - err, - RadrootsRuntimePathsError::InvalidNamespaceComponent { - value: "../cli".to_owned(), - } - ); - } - - #[test] - fn interactive_user_linux_requires_home_for_xdg_defaults() { - let resolver = - RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); - - let err = resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect_err("interactive_user on linux should require a home dir"); - - assert_eq!( - err, - RadrootsRuntimePathsError::MissingHomeDir { - platform: RadrootsPlatform::Linux, - } - ); - } - - #[test] - fn interactive_user_windows_requires_native_dirs() { - let resolver = RadrootsPathResolver::new( - RadrootsPlatform::Windows, - RadrootsHostEnvironment::default(), - ); - - let err = resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect_err("interactive_user on windows should require native dirs"); - - assert_eq!(err, RadrootsRuntimePathsError::MissingWindowsUserDirs); - } -} +pub use roots::RadrootsPathResolver; +pub use service::RadrootsServiceInstancePaths; diff --git a/crates/runtime_paths/src/namespace.rs b/crates/runtime_paths/src/namespace.rs @@ -1,236 +0,0 @@ -use std::path::PathBuf; - -use crate::{InstanceId, RadrootsRuntimePathsError, ServiceId, ServiceIdentityError}; - -/// A validated canonical `services/<service>/<instance>` namespace. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RadrootsServiceInstanceNamespace { - service_id: ServiceId, - instance_id: InstanceId, -} - -impl RadrootsServiceInstanceNamespace { - /// Constructs a namespace from already validated identities. - #[must_use] - pub fn new(service_id: ServiceId, instance_id: InstanceId) -> Self { - Self { - service_id, - instance_id, - } - } - - /// Parses both canonical path components before constructing a namespace. - pub fn parse( - service_id: impl Into<String>, - instance_id: impl Into<String>, - ) -> Result<Self, ServiceIdentityError> { - Ok(Self::new( - ServiceId::new(service_id)?, - InstanceId::new(instance_id)?, - )) - } - - /// Returns the validated service identity. - #[must_use] - pub fn service_id(&self) -> &ServiceId { - &self.service_id - } - - /// Returns the validated instance identity. - #[must_use] - pub fn instance_id(&self) -> &InstanceId { - &self.instance_id - } - - /// Returns the canonical relative namespace path. - #[must_use] - pub fn relative_path(&self) -> PathBuf { - PathBuf::from(RadrootsRuntimeNamespaceKind::Service.path_segment()) - .join(self.service_id.as_str()) - .join(self.instance_id.as_str()) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum RadrootsRuntimeNamespaceKind { - App, - Service, - Worker, - Shared, -} - -impl RadrootsRuntimeNamespaceKind { - #[must_use] - pub fn path_segment(self) -> &'static str { - match self { - Self::App => "apps", - Self::Service => "services", - Self::Worker => "workers", - Self::Shared => "shared", - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RadrootsRuntimeNamespace { - kind: RadrootsRuntimeNamespaceKind, - value: String, -} - -impl RadrootsRuntimeNamespace { - pub fn app(value: impl Into<String>) -> Result<Self, RadrootsRuntimePathsError> { - Self::new(RadrootsRuntimeNamespaceKind::App, value) - } - - pub fn service(value: impl Into<String>) -> Result<Self, RadrootsRuntimePathsError> { - Self::new(RadrootsRuntimeNamespaceKind::Service, value) - } - - pub fn worker(value: impl Into<String>) -> Result<Self, RadrootsRuntimePathsError> { - Self::new(RadrootsRuntimeNamespaceKind::Worker, value) - } - - pub fn shared(value: impl Into<String>) -> Result<Self, RadrootsRuntimePathsError> { - Self::new(RadrootsRuntimeNamespaceKind::Shared, value) - } - - pub fn new( - kind: RadrootsRuntimeNamespaceKind, - value: impl Into<String>, - ) -> Result<Self, RadrootsRuntimePathsError> { - let value = value.into(); - validate_component(&value)?; - Ok(Self { kind, value }) - } - - #[must_use] - pub fn kind(&self) -> RadrootsRuntimeNamespaceKind { - self.kind - } - - #[must_use] - pub fn value(&self) -> &str { - self.value.as_str() - } - - #[must_use] - pub fn relative_path(&self) -> PathBuf { - PathBuf::from(self.kind.path_segment()).join(self.value.as_str()) - } -} - -fn validate_component(value: &str) -> Result<(), RadrootsRuntimePathsError> { - let trimmed = value.trim(); - if trimmed.is_empty() - || trimmed == "." - || trimmed == ".." - || trimmed.contains('/') - || trimmed.contains('\\') - { - return Err(RadrootsRuntimePathsError::InvalidNamespaceComponent { - value: value.to_owned(), - }); - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use std::path::PathBuf; - - use super::{ - RadrootsRuntimeNamespace, RadrootsRuntimeNamespaceKind, RadrootsServiceInstanceNamespace, - }; - use crate::{ - InstanceId, RadrootsRuntimePathsError, ServiceId, ServiceIdentityError, ServiceIdentityKind, - }; - - #[test] - fn namespace_kind_path_segments_are_canonical() { - assert_eq!(RadrootsRuntimeNamespaceKind::App.path_segment(), "apps"); - assert_eq!( - RadrootsRuntimeNamespaceKind::Service.path_segment(), - "services" - ); - assert_eq!( - RadrootsRuntimeNamespaceKind::Worker.path_segment(), - "workers" - ); - assert_eq!( - RadrootsRuntimeNamespaceKind::Shared.path_segment(), - "shared" - ); - } - - #[test] - fn namespace_constructors_preserve_kind_and_value() { - let app = RadrootsRuntimeNamespace::app("cli").expect("app namespace"); - assert_eq!(app.kind(), RadrootsRuntimeNamespaceKind::App); - assert_eq!(app.value(), "cli"); - assert_eq!(app.relative_path(), PathBuf::from("apps/cli")); - - let service = RadrootsRuntimeNamespace::service("myc").expect("service namespace"); - assert_eq!(service.kind(), RadrootsRuntimeNamespaceKind::Service); - assert_eq!(service.value(), "myc"); - assert_eq!(service.relative_path(), PathBuf::from("services/myc")); - - let worker = RadrootsRuntimeNamespace::worker("rhi").expect("worker namespace"); - assert_eq!(worker.kind(), RadrootsRuntimeNamespaceKind::Worker); - assert_eq!(worker.value(), "rhi"); - assert_eq!(worker.relative_path(), PathBuf::from("workers/rhi")); - - let shared = RadrootsRuntimeNamespace::shared("runtime").expect("shared namespace"); - assert_eq!(shared.kind(), RadrootsRuntimeNamespaceKind::Shared); - assert_eq!(shared.value(), "runtime"); - assert_eq!(shared.relative_path(), PathBuf::from("shared/runtime")); - } - - #[test] - fn namespace_validation_rejects_invalid_components() { - for invalid in ["", " ", ".", "..", "a/b", r"a\b"] { - let err = RadrootsRuntimeNamespace::new(RadrootsRuntimeNamespaceKind::App, invalid) - .expect_err("invalid namespace component should fail"); - assert_eq!( - err, - RadrootsRuntimePathsError::InvalidNamespaceComponent { - value: invalid.to_owned(), - } - ); - } - } - - #[test] - fn service_instance_namespace_requires_both_validated_identities() { - let namespace = RadrootsServiceInstanceNamespace::new( - ServiceId::new("myc").expect("service id"), - InstanceId::new("primary-01").expect("instance id"), - ); - assert_eq!(namespace.service_id().as_str(), "myc"); - assert_eq!(namespace.instance_id().as_str(), "primary-01"); - assert_eq!( - namespace.relative_path(), - PathBuf::from("services/myc/primary-01") - ); - - for invalid in ["../myc", "/absolute", "myc/other", "Myc"] { - let error = RadrootsServiceInstanceNamespace::parse(invalid, "primary") - .expect_err("invalid service path component"); - assert_identity_error_kind(error, ServiceIdentityKind::Service); - } - for invalid in ["../primary", "/absolute", "primary/other", "Primary"] { - let error = RadrootsServiceInstanceNamespace::parse("myc", invalid) - .expect_err("invalid instance path component"); - assert_identity_error_kind(error, ServiceIdentityKind::Instance); - } - } - - fn assert_identity_error_kind(error: ServiceIdentityError, expected: ServiceIdentityKind) { - let actual = match error { - ServiceIdentityError::Empty { kind } - | ServiceIdentityError::TooLong { kind, .. } - | ServiceIdentityError::InvalidBoundary { kind } - | ServiceIdentityError::InvalidCharacter { kind } => kind, - }; - assert_eq!(actual, expected); - } -} diff --git a/crates/runtime_paths/src/platform.rs b/crates/runtime_paths/src/platform.rs @@ -104,27 +104,9 @@ pub struct RadrootsHostEnvironment { pub localappdata_dir: Option<PathBuf>, } -impl RadrootsHostEnvironment { - #[must_use] - pub fn from_current_process() -> Self { - Self { - home_dir: std::env::var_os("HOME").map(PathBuf::from), - xdg_config_home: std::env::var_os("XDG_CONFIG_HOME").map(PathBuf::from), - xdg_data_home: std::env::var_os("XDG_DATA_HOME").map(PathBuf::from), - xdg_state_home: std::env::var_os("XDG_STATE_HOME").map(PathBuf::from), - xdg_cache_home: std::env::var_os("XDG_CACHE_HOME").map(PathBuf::from), - xdg_runtime_dir: std::env::var_os("XDG_RUNTIME_DIR").map(PathBuf::from), - appdata_dir: std::env::var_os("APPDATA").map(PathBuf::from), - localappdata_dir: std::env::var_os("LOCALAPPDATA").map(PathBuf::from), - } - } -} - #[cfg(test)] mod tests { - use std::path::PathBuf; - - use super::{RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPlatform}; + use super::{RadrootsPathProfile, RadrootsPlatform}; #[test] fn current_matches_compiled_target_platform() { @@ -180,38 +162,4 @@ mod tests { "mobile_native" ); } - - #[test] - fn host_environment_reads_current_process_variables() { - let env = RadrootsHostEnvironment::from_current_process(); - assert_eq!(env.home_dir, std::env::var_os("HOME").map(PathBuf::from)); - assert_eq!( - env.xdg_config_home, - std::env::var_os("XDG_CONFIG_HOME").map(PathBuf::from) - ); - assert_eq!( - env.xdg_data_home, - std::env::var_os("XDG_DATA_HOME").map(PathBuf::from) - ); - assert_eq!( - env.xdg_state_home, - std::env::var_os("XDG_STATE_HOME").map(PathBuf::from) - ); - assert_eq!( - env.xdg_cache_home, - std::env::var_os("XDG_CACHE_HOME").map(PathBuf::from) - ); - assert_eq!( - env.xdg_runtime_dir, - std::env::var_os("XDG_RUNTIME_DIR").map(PathBuf::from) - ); - assert_eq!( - env.appdata_dir, - std::env::var_os("APPDATA").map(PathBuf::from) - ); - assert_eq!( - env.localappdata_dir, - std::env::var_os("LOCALAPPDATA").map(PathBuf::from) - ); - } } diff --git a/crates/runtime_paths/src/roots.rs b/crates/runtime_paths/src/roots.rs @@ -1,8 +1,7 @@ use std::path::{Component, Path, PathBuf}; use crate::{ - RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPlatform, RadrootsRuntimeNamespace, - RadrootsRuntimePathsError, + RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPlatform, RadrootsRuntimePathsError, }; const APPLICATION_DIRECTORY: &str = "radroots"; @@ -30,18 +29,18 @@ impl XdgDirectory { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RadrootsPaths { - pub config: PathBuf, - pub data: PathBuf, - pub cache: PathBuf, - pub logs: PathBuf, - pub run: PathBuf, - pub secrets: PathBuf, +pub(crate) struct RadrootsPaths { + pub(crate) config: PathBuf, + pub(crate) data: PathBuf, + pub(crate) cache: PathBuf, + pub(crate) logs: PathBuf, + pub(crate) run: PathBuf, + pub(crate) secrets: PathBuf, } impl RadrootsPaths { #[must_use] - pub fn from_base_root(base_root: impl AsRef<Path>) -> Self { + pub(crate) fn from_base_root(base_root: impl AsRef<Path>) -> Self { let base_root = base_root.as_ref(); Self { config: base_root.join("config"), @@ -52,43 +51,6 @@ impl RadrootsPaths { secrets: base_root.join("secrets"), } } - - #[must_use] - pub fn namespaced(&self, namespace: &RadrootsRuntimeNamespace) -> Self { - let relative = namespace.relative_path(); - Self { - config: self.config.join(&relative), - data: self.data.join(&relative), - cache: self.cache.join(&relative), - logs: self.logs.join(&relative), - run: self.run.join(&relative), - secrets: self.secrets.join(relative), - } - } -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct RadrootsPathOverrides { - pub repo_local_root: Option<PathBuf>, - pub mobile_roots: Option<RadrootsPaths>, -} - -impl RadrootsPathOverrides { - #[must_use] - pub fn repo_local(base_root: impl Into<PathBuf>) -> Self { - Self { - repo_local_root: Some(base_root.into()), - mobile_roots: None, - } - } - - #[must_use] - pub fn mobile(roots: RadrootsPaths) -> Self { - Self { - repo_local_root: None, - mobile_roots: Some(roots), - } - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -107,49 +69,30 @@ impl RadrootsPathResolver { } #[must_use] - pub fn current() -> Self { - Self::new( - RadrootsPlatform::current(), - RadrootsHostEnvironment::from_current_process(), - ) - } - - #[must_use] pub fn platform(&self) -> RadrootsPlatform { self.platform } - pub fn resolve( + pub(crate) fn resolve( &self, profile: RadrootsPathProfile, - overrides: &RadrootsPathOverrides, + repo_local_root: Option<&Path>, ) -> Result<RadrootsPaths, RadrootsRuntimePathsError> { match profile { RadrootsPathProfile::InteractiveUser => self.resolve_interactive_user(), RadrootsPathProfile::ServiceHost => self.resolve_service_host(), RadrootsPathProfile::RepoLocal => { - let root = overrides - .repo_local_root - .as_deref() - .ok_or(RadrootsRuntimePathsError::MissingRepoLocalRoot)?; + let root = + repo_local_root.ok_or(RadrootsRuntimePathsError::MissingRepoLocalRoot)?; validate_repo_local_root(root)?; Ok(RadrootsPaths::from_base_root(root)) } - RadrootsPathProfile::MobileNative => match self.platform { - RadrootsPlatform::Android | RadrootsPlatform::Ios => overrides - .mobile_roots - .clone() - .ok_or(RadrootsRuntimePathsError::MissingMobileRoots), - RadrootsPlatform::Linux - | RadrootsPlatform::Macos - | RadrootsPlatform::Windows - | RadrootsPlatform::Other => { - Err(RadrootsRuntimePathsError::UnsupportedProfilePlatform { - profile, - platform: self.platform, - }) - } - }, + RadrootsPathProfile::MobileNative => { + Err(RadrootsRuntimePathsError::UnsupportedProfilePlatform { + profile, + platform: self.platform, + }) + } } } @@ -295,127 +238,57 @@ pub(crate) fn validate_repo_local_root(root: &Path) -> Result<(), RadrootsRuntim #[cfg(test)] mod tests { - use std::path::PathBuf; + use std::path::{Path, PathBuf}; - use super::{RadrootsPathOverrides, RadrootsPathResolver, RadrootsPaths}; + use super::{RadrootsPathResolver, RadrootsPaths}; use crate::{ RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPlatform, RadrootsRuntimePathsError, }; #[test] - fn path_override_helpers_only_populate_their_owned_slot() { - let repo_local = RadrootsPathOverrides::repo_local("/repo/.local/radroots"); - assert_eq!( - repo_local.repo_local_root, - Some(PathBuf::from("/repo/.local/radroots")) - ); - assert!(repo_local.mobile_roots.is_none()); - - let mobile_roots = RadrootsPaths::from_base_root("/sandbox"); - let mobile = RadrootsPathOverrides::mobile(mobile_roots.clone()); - assert!(mobile.repo_local_root.is_none()); - assert_eq!(mobile.mobile_roots, Some(mobile_roots)); - } - - #[test] - fn repo_local_root_rejects_missing_relative_root_and_parent_traversal() { + fn repo_local_is_explicit_validated_and_one_base() { let resolver = RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); - assert_eq!( resolver - .resolve( - RadrootsPathProfile::RepoLocal, - &RadrootsPathOverrides::default(), - ) + .resolve(RadrootsPathProfile::RepoLocal, None) .expect_err("missing root"), RadrootsRuntimePathsError::MissingRepoLocalRoot ); - - for root in [ - "", - ".", - "relative/root", - "../escape", - "/", - "/repo/../escape", - ] { + for invalid in ["", ".", "relative/root", "/", "/repo/../escape"] { assert_eq!( resolver - .resolve( - RadrootsPathProfile::RepoLocal, - &RadrootsPathOverrides::repo_local(root), - ) - .expect_err("invalid repo-local root"), - RadrootsRuntimePathsError::InvalidRepoLocalRoot, - "accepted invalid repo-local root `{root}`" + .resolve(RadrootsPathProfile::RepoLocal, Some(Path::new(invalid))) + .expect_err("invalid root"), + RadrootsRuntimePathsError::InvalidRepoLocalRoot ); } - } - - #[test] - fn resolver_current_uses_process_platform_and_environment() { - let resolver = RadrootsPathResolver::current(); - assert_eq!(resolver.platform(), RadrootsPlatform::current()); - assert_eq!( - resolver, - RadrootsPathResolver::new( - RadrootsPlatform::current(), - RadrootsHostEnvironment::from_current_process() - ) - ); - } - - #[test] - fn linux_interactive_uses_exact_config_data_state_cache_and_runtime_roots() { - let resolver = RadrootsPathResolver::new( - RadrootsPlatform::Linux, - RadrootsHostEnvironment { - xdg_config_home: Some(PathBuf::from("/xdg/config")), - xdg_data_home: Some(PathBuf::from("/xdg/data")), - xdg_state_home: Some(PathBuf::from("/xdg/state")), - xdg_cache_home: Some(PathBuf::from("/xdg/cache")), - xdg_runtime_dir: Some(PathBuf::from("/xdg/run")), - ..RadrootsHostEnvironment::default() - }, - ); - assert_eq!( resolver .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), + RadrootsPathProfile::RepoLocal, + Some(Path::new("/repo/.local/radroots")), ) - .expect("configured XDG roots"), - RadrootsPaths { - config: PathBuf::from("/xdg/config/radroots"), - data: PathBuf::from("/xdg/data/radroots"), - cache: PathBuf::from("/xdg/cache/radroots"), - logs: PathBuf::from("/xdg/state/radroots/logs"), - run: PathBuf::from("/xdg/run/radroots"), - secrets: PathBuf::from("/xdg/config/radroots/secrets"), - } + .expect("repo roots"), + RadrootsPaths::from_base_root("/repo/.local/radroots") ); } #[test] - fn linux_interactive_uses_xdg_home_defaults_but_never_invents_runtime() { + fn linux_interactive_uses_injected_xdg_and_home_defaults() { let resolver = RadrootsPathResolver::new( RadrootsPlatform::Linux, RadrootsHostEnvironment { home_dir: Some(PathBuf::from("/home/treesap")), + xdg_config_home: Some(PathBuf::from("relative-ignored")), xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), ..RadrootsHostEnvironment::default() }, ); - assert_eq!( resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect("defaulted XDG roots"), + .resolve(RadrootsPathProfile::InteractiveUser, None) + .expect("linux interactive"), RadrootsPaths { config: PathBuf::from("/home/treesap/.config/radroots"), data: PathBuf::from("/home/treesap/.local/share/radroots"), @@ -425,8 +298,11 @@ mod tests { secrets: PathBuf::from("/home/treesap/.config/radroots/secrets"), } ); + } - let missing_runtime = RadrootsPathResolver::new( + #[test] + fn linux_interactive_never_invents_runtime_root() { + let resolver = RadrootsPathResolver::new( RadrootsPlatform::Linux, RadrootsHostEnvironment { home_dir: Some(PathBuf::from("/home/treesap")), @@ -434,241 +310,74 @@ mod tests { }, ); assert_eq!( - missing_runtime - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect_err("XDG runtime has no home fallback"), + resolver + .resolve(RadrootsPathProfile::InteractiveUser, None) + .expect_err("runtime root is required"), RadrootsRuntimePathsError::MissingXdgRuntimeDir ); } #[test] - fn linux_interactive_ignores_empty_and_relative_xdg_directories() { - let valid = RadrootsHostEnvironment { - home_dir: Some(PathBuf::from("/home/treesap")), - xdg_config_home: Some(PathBuf::from("/xdg/config")), - xdg_data_home: Some(PathBuf::from("/xdg/data")), - xdg_state_home: Some(PathBuf::from("/xdg/state")), - xdg_cache_home: Some(PathBuf::from("/xdg/cache")), - xdg_runtime_dir: Some(PathBuf::from("/xdg/run")), - ..RadrootsHostEnvironment::default() - }; - for (environment, expected) in [ - ( - RadrootsHostEnvironment { - xdg_config_home: Some(PathBuf::new()), - ..valid.clone() - }, - PathBuf::from("/home/treesap/.config/radroots"), - ), - ( - RadrootsHostEnvironment { - xdg_config_home: Some(PathBuf::from("relative/config")), - ..valid.clone() - }, - PathBuf::from("/home/treesap/.config/radroots"), - ), - ( - RadrootsHostEnvironment { - xdg_data_home: Some(PathBuf::new()), - ..valid.clone() - }, - PathBuf::from("/home/treesap/.local/share/radroots"), - ), - ( - RadrootsHostEnvironment { - xdg_data_home: Some(PathBuf::from("relative/data")), - ..valid.clone() - }, - PathBuf::from("/home/treesap/.local/share/radroots"), - ), - ( - RadrootsHostEnvironment { - xdg_state_home: Some(PathBuf::new()), - ..valid.clone() - }, - PathBuf::from("/home/treesap/.local/state/radroots/logs"), - ), - ( - RadrootsHostEnvironment { - xdg_state_home: Some(PathBuf::from("relative/state")), - ..valid.clone() - }, - PathBuf::from("/home/treesap/.local/state/radroots/logs"), - ), - ( - RadrootsHostEnvironment { - xdg_cache_home: Some(PathBuf::new()), - ..valid.clone() - }, - PathBuf::from("/home/treesap/.cache/radroots"), - ), - ( - RadrootsHostEnvironment { - xdg_cache_home: Some(PathBuf::from("relative/cache")), - ..valid.clone() - }, - PathBuf::from("/home/treesap/.cache/radroots"), - ), - ] { - let resolver = RadrootsPathResolver::new(RadrootsPlatform::Linux, environment); - let roots = resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect("invalid optional XDG directory is ignored"); - assert!( - [roots.config, roots.data, roots.logs, roots.cache].contains(&expected), - "expected fallback root {expected:?}" - ); - } - - for xdg_runtime_dir in [Some(PathBuf::new()), Some(PathBuf::from("relative/run"))] { + fn home_derived_roots_require_absolute_home() { + for platform in [RadrootsPlatform::Linux, RadrootsPlatform::Macos] { let resolver = RadrootsPathResolver::new( - RadrootsPlatform::Linux, + platform, RadrootsHostEnvironment { - xdg_runtime_dir, - ..valid.clone() - }, - ); - assert_eq!( - resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect_err("invalid XDG runtime is treated as missing"), - RadrootsRuntimePathsError::MissingXdgRuntimeDir - ); - } - } - - #[test] - fn interactive_home_derived_roots_require_an_absolute_nonempty_home() { - for home_dir in [Some(PathBuf::new()), Some(PathBuf::from("relative/home"))] { - let linux = RadrootsPathResolver::new( - RadrootsPlatform::Linux, - RadrootsHostEnvironment { - home_dir: home_dir.clone(), + home_dir: Some(PathBuf::from("relative")), xdg_runtime_dir: Some(PathBuf::from("/run/user/1000")), ..RadrootsHostEnvironment::default() }, ); assert_eq!( - linux - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect_err("Linux HOME defaults require an absolute HOME"), - RadrootsRuntimePathsError::InvalidHomeDir { - platform: RadrootsPlatform::Linux, - } - ); - - let macos = RadrootsPathResolver::new( - RadrootsPlatform::Macos, - RadrootsHostEnvironment { - home_dir, - ..RadrootsHostEnvironment::default() - }, - ); - assert_eq!( - macos - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect_err("macOS native roots require an absolute HOME"), - RadrootsRuntimePathsError::InvalidHomeDir { - platform: RadrootsPlatform::Macos, - } + resolver + .resolve(RadrootsPathProfile::InteractiveUser, None) + .expect_err("relative home"), + RadrootsRuntimePathsError::InvalidHomeDir { platform } ); } } #[test] - fn macos_interactive_uses_native_library_roots_and_ignores_xdg() { - let resolver = RadrootsPathResolver::new( - RadrootsPlatform::Macos, - RadrootsHostEnvironment { - home_dir: Some(PathBuf::from("/Users/treesap")), - xdg_config_home: Some(PathBuf::from("relative/config")), - xdg_data_home: Some(PathBuf::from("relative/data")), - xdg_state_home: Some(PathBuf::from("relative/state")), - xdg_cache_home: Some(PathBuf::from("relative/cache")), - xdg_runtime_dir: Some(PathBuf::from("relative/run")), - ..RadrootsHostEnvironment::default() - }, - ); - - assert_eq!( - resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect("macOS native roots"), - RadrootsPaths { - config: PathBuf::from("/Users/treesap/Library/Application Support/Radroots/config",), - data: PathBuf::from("/Users/treesap/Library/Application Support/Radroots/data",), - cache: PathBuf::from("/Users/treesap/Library/Caches/Radroots"), - logs: PathBuf::from("/Users/treesap/Library/Logs/Radroots"), - run: PathBuf::from("/Users/treesap/Library/Application Support/Radroots/run",), - secrets: PathBuf::from( - "/Users/treesap/Library/Application Support/Radroots/secrets", - ), - } - ); - } - - #[test] - fn mobile_profile_is_rejected_on_non_mobile_platforms() { + fn service_host_linux_uses_canonical_roots() { let resolver = RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); - - let err = resolver - .resolve( - RadrootsPathProfile::MobileNative, - &RadrootsPathOverrides::default(), - ) - .expect_err("mobile profile should be rejected on linux"); - assert_eq!( - err, - RadrootsRuntimePathsError::UnsupportedProfilePlatform { - profile: RadrootsPathProfile::MobileNative, - platform: RadrootsPlatform::Linux, + resolver + .resolve(RadrootsPathProfile::ServiceHost, None) + .expect("service host"), + RadrootsPaths { + config: PathBuf::from("/etc/radroots"), + data: PathBuf::from("/var/lib/radroots"), + cache: PathBuf::from("/var/cache/radroots"), + logs: PathBuf::from("/var/log/radroots"), + run: PathBuf::from("/run/radroots"), + secrets: PathBuf::from("/etc/radroots/secrets"), } ); } #[test] - fn interactive_user_is_rejected_on_mobile_platforms() { - for platform in [RadrootsPlatform::Android, RadrootsPlatform::Ios] { + fn unsupported_profile_platform_pairs_fail_closed() { + for platform in [ + RadrootsPlatform::Macos, + RadrootsPlatform::Windows, + RadrootsPlatform::Android, + RadrootsPlatform::Ios, + RadrootsPlatform::Other, + ] { let resolver = RadrootsPathResolver::new(platform, RadrootsHostEnvironment::default()); - let err = resolver - .resolve( - RadrootsPathProfile::InteractiveUser, - &RadrootsPathOverrides::default(), - ) - .expect_err("interactive_user should be unsupported on mobile"); assert_eq!( - err, + resolver + .resolve(RadrootsPathProfile::ServiceHost, None) + .expect_err("unsupported service host"), RadrootsRuntimePathsError::UnsupportedProfilePlatform { - profile: RadrootsPathProfile::InteractiveUser, + profile: RadrootsPathProfile::ServiceHost, platform, } ); } - } - - #[test] - fn service_host_is_rejected_outside_linux() { for platform in [ + RadrootsPlatform::Linux, RadrootsPlatform::Macos, RadrootsPlatform::Windows, RadrootsPlatform::Android, @@ -676,16 +385,12 @@ mod tests { RadrootsPlatform::Other, ] { let resolver = RadrootsPathResolver::new(platform, RadrootsHostEnvironment::default()); - let err = resolver - .resolve( - RadrootsPathProfile::ServiceHost, - &RadrootsPathOverrides::default(), - ) - .expect_err("service_host should be unsupported outside linux"); assert_eq!( - err, + resolver + .resolve(RadrootsPathProfile::MobileNative, None) + .expect_err("mobile roots require a product-owned adapter"), RadrootsRuntimePathsError::UnsupportedProfilePlatform { - profile: RadrootsPathProfile::ServiceHost, + profile: RadrootsPathProfile::MobileNative, platform, } ); diff --git a/crates/runtime_paths/src/service.rs b/crates/runtime_paths/src/service.rs @@ -1,17 +1,6 @@ -use std::{ - ffi::OsString, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; -use serde::Serialize; -use thiserror::Error; - -use crate::roots::validate_repo_local_root; -use crate::{ - InstanceId, RadrootsPathOverrides, RadrootsPathProfile, RadrootsPathResolver, RadrootsPaths, - RadrootsRuntimeNamespace, RadrootsRuntimePathsError, RadrootsServiceInstanceNamespace, - ServiceId, -}; +use crate::{InstanceId, ServiceId, roots::RadrootsPaths}; /// Canonical directories owned by one validated service instance. /// @@ -44,9 +33,12 @@ pub struct RadrootsServiceInstancePaths { impl RadrootsServiceInstancePaths { pub(crate) fn from_resolved_roots( roots: &RadrootsPaths, - namespace: &RadrootsServiceInstanceNamespace, + service: &ServiceId, + instance: &InstanceId, ) -> Self { - let relative = namespace.relative_path(); + let relative = Path::new("services") + .join(service.as_str()) + .join(instance.as_str()); Self { config: roots.config.join(&relative), state: roots.data.join(&relative), @@ -88,664 +80,28 @@ impl RadrootsServiceInstancePaths { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RadrootsRuntimePathSelection { - pub profile: RadrootsPathProfile, - pub profile_source: String, - pub repo_local_root: Option<PathBuf>, - pub repo_local_root_source: Option<String>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RadrootsRuntimePathConfigEntry { - pub key: String, - pub value: String, - pub source_label: String, -} - -impl RadrootsRuntimePathConfigEntry { - #[must_use] - pub fn new( - key: impl Into<String>, - value: impl Into<String>, - source_label: impl Into<String>, - ) -> Self { - Self { - key: key.into(), - value: value.into(), - source_label: source_label.into(), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] -pub struct RadrootsRuntimeSelectionContract { - pub active_profile: String, - pub allowed_profiles: Vec<String>, - pub path_overrides: RadrootsRuntimeSelectionOverrideContract, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] -pub struct RadrootsRuntimeSelectionOverrideContract { - pub profile_source: String, - pub root_source: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub repo_local_root: Option<PathBuf>, - #[serde(skip_serializing_if = "Option::is_none")] - pub repo_local_root_source: Option<String>, - pub subordinate_path_override_source: String, - pub subordinate_path_override_keys: Vec<String>, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] -pub struct RadrootsRuntimePathPolicyContract { - pub canonical_root_selection: String, - pub canonical_subordinate_path_override: String, - pub leaf_path_env_posture: String, -} - -impl RadrootsRuntimePathPolicyContract { - pub fn new( - canonical_root_selection: &str, - canonical_subordinate_path_override: &str, - leaf_path_env_posture: &str, - ) -> Self { - Self { - canonical_root_selection: canonical_root_selection.to_owned(), - canonical_subordinate_path_override: canonical_subordinate_path_override.to_owned(), - leaf_path_env_posture: leaf_path_env_posture.to_owned(), - } - } -} - -#[derive(Debug, Error, Clone, PartialEq, Eq)] -pub enum RadrootsRuntimePathSelectionError { - #[error("{env_var} must be valid utf-8 when set")] - NonUnicodeEnv { env_var: String }, - - #[error( - "{env_var} must be `interactive_user`, `service_host`, or `repo_local`; found `{value}`" - )] - InvalidProfileEnv { env_var: String, value: String }, - - #[error( - "profile must be `interactive_user`, `service_host`, `repo_local`, or `mobile_native`; found `{value}`" - )] - InvalidProfileValue { value: String }, - - #[error("{repo_local_root_env} must be set when {profile_env}=repo_local")] - MissingRepoLocalRoot { - profile_env: String, - repo_local_root_env: String, - }, - - #[error(transparent)] - Paths(#[from] RadrootsRuntimePathsError), -} - -impl RadrootsRuntimePathSelection { - pub fn caller(profile: RadrootsPathProfile, repo_local_root: Option<PathBuf>) -> Self { - Self { - profile, - profile_source: "caller".to_owned(), - repo_local_root_source: repo_local_root.as_ref().map(|_| "caller".to_owned()), - repo_local_root, - } - } - - pub fn from_profile_value( - profile: &str, - repo_local_root: Option<PathBuf>, - ) -> Result<Self, RadrootsRuntimePathSelectionError> { - Ok(Self::caller(parse_profile_value(profile)?, repo_local_root)) - } - - pub fn from_config_entries( - profile_entry: Option<RadrootsRuntimePathConfigEntry>, - repo_local_root_entry: Option<RadrootsRuntimePathConfigEntry>, - default_profile: RadrootsPathProfile, - ) -> Result<Self, RadrootsRuntimePathSelectionError> { - let (profile, profile_source) = match profile_entry { - Some(entry) => ( - parse_profile(entry.key.as_str(), entry.value.as_str())?, - entry.source_label, - ), - None => (default_profile, "default".to_owned()), - }; - let (repo_local_root, repo_local_root_source) = match repo_local_root_entry { - Some(entry) => (Some(PathBuf::from(entry.value)), Some(entry.source_label)), - None => (None, None), - }; - Ok(Self { - profile, - profile_source, - repo_local_root, - repo_local_root_source, - }) - } - - pub fn from_env( - profile_env: &'static str, - repo_local_root_env: &'static str, - default_profile: RadrootsPathProfile, - ) -> Result<Self, RadrootsRuntimePathSelectionError> { - Self::from_env_values( - profile_env, - std::env::var(profile_env), - repo_local_root_env, - std::env::var_os(repo_local_root_env), - default_profile, - ) - } - - fn from_env_values( - profile_env: &'static str, - profile_value: Result<String, std::env::VarError>, - repo_local_root_env: &'static str, - repo_local_root_raw: Option<OsString>, - default_profile: RadrootsPathProfile, - ) -> Result<Self, RadrootsRuntimePathSelectionError> { - let (profile, profile_source) = match profile_value { - Ok(value) => ( - parse_profile(profile_env, value.as_str())?, - format!("process_env:{profile_env}"), - ), - Err(std::env::VarError::NotPresent) => (default_profile, "default".to_owned()), - Err(std::env::VarError::NotUnicode(_)) => { - return Err(RadrootsRuntimePathSelectionError::NonUnicodeEnv { - env_var: profile_env.to_owned(), - }); - } - }; - let repo_local_root = repo_local_root_raw.as_ref().map(PathBuf::from); - Ok(Self { - profile, - profile_source, - repo_local_root, - repo_local_root_source: repo_local_root_raw - .as_ref() - .map(|_| format!("process_env:{repo_local_root_env}")), - }) - } - - pub fn root_source(&self) -> &'static str { - match self.profile { - RadrootsPathProfile::InteractiveUser => "host_defaults", - RadrootsPathProfile::ServiceHost => "service_host_defaults", - RadrootsPathProfile::RepoLocal => "repo_local_root", - RadrootsPathProfile::MobileNative => "mobile_native_defaults", - } - } - - pub fn overrides( - &self, - profile_env: &'static str, - repo_local_root_env: &'static str, - ) -> Result<RadrootsPathOverrides, RadrootsRuntimePathSelectionError> { - self.overrides_with_labels(profile_env, repo_local_root_env) - } - - pub fn caller_overrides( - &self, - ) -> Result<RadrootsPathOverrides, RadrootsRuntimePathSelectionError> { - self.overrides_with_labels("caller_profile", "caller_repo_local_root") - } - - pub fn contract( - &self, - allowed_profiles: &[&str], - subordinate_path_override_source: &str, - subordinate_path_override_keys: &[&str], - ) -> RadrootsRuntimeSelectionContract { - RadrootsRuntimeSelectionContract { - active_profile: self.profile.to_string(), - allowed_profiles: allowed_profiles - .iter() - .map(|entry| (*entry).to_owned()) - .collect(), - path_overrides: RadrootsRuntimeSelectionOverrideContract { - profile_source: self.profile_source.clone(), - root_source: self.root_source().to_owned(), - repo_local_root: self.repo_local_root.clone(), - repo_local_root_source: self.repo_local_root_source.clone(), - subordinate_path_override_source: subordinate_path_override_source.to_owned(), - subordinate_path_override_keys: subordinate_path_override_keys - .iter() - .map(|entry| (*entry).to_owned()) - .collect(), - }, - } - } - - fn overrides_with_labels( - &self, - profile_label: &str, - repo_local_root_label: &str, - ) -> Result<RadrootsPathOverrides, RadrootsRuntimePathSelectionError> { - match self.profile { - RadrootsPathProfile::RepoLocal => { - let Some(repo_local_root) = self.repo_local_root.as_ref() else { - return Err(RadrootsRuntimePathSelectionError::MissingRepoLocalRoot { - profile_env: profile_label.to_owned(), - repo_local_root_env: repo_local_root_label.to_owned(), - }); - }; - validate_repo_local_root(repo_local_root)?; - Ok(RadrootsPathOverrides::repo_local(repo_local_root)) - } - _ => Ok(RadrootsPathOverrides::default()), - } - } - - pub fn resolve_service_roots( - &self, - resolver: &RadrootsPathResolver, - service_id: &str, - profile_env: &'static str, - repo_local_root_env: &'static str, - ) -> Result<RadrootsPaths, RadrootsRuntimePathSelectionError> { - let namespace = RadrootsRuntimeNamespace::service(service_id)?; - let overrides = self.overrides(profile_env, repo_local_root_env)?; - let roots = resolver.resolve(self.profile, &overrides)?; - Ok(roots.namespaced(&namespace)) - } - - pub fn resolve_service_instance_paths( - &self, - resolver: &RadrootsPathResolver, - service_id: &ServiceId, - instance_id: &InstanceId, - profile_env: &'static str, - repo_local_root_env: &'static str, - ) -> Result<RadrootsServiceInstancePaths, RadrootsRuntimePathSelectionError> { - let namespace = - RadrootsServiceInstanceNamespace::new(service_id.clone(), instance_id.clone()); - let overrides = self.overrides(profile_env, repo_local_root_env)?; - let roots = resolver.resolve(self.profile, &overrides)?; - Ok(RadrootsServiceInstancePaths::from_resolved_roots( - &roots, &namespace, - )) - } -} - -fn parse_profile( - env_var: &str, - value: &str, -) -> Result<RadrootsPathProfile, RadrootsRuntimePathSelectionError> { - parse_profile_value(value).map_err(|_| RadrootsRuntimePathSelectionError::InvalidProfileEnv { - env_var: env_var.to_owned(), - value: value.to_owned(), - }) -} - -fn parse_profile_value( - value: &str, -) -> Result<RadrootsPathProfile, RadrootsRuntimePathSelectionError> { - match value { - "interactive_user" => Ok(RadrootsPathProfile::InteractiveUser), - "service_host" => Ok(RadrootsPathProfile::ServiceHost), - "repo_local" => Ok(RadrootsPathProfile::RepoLocal), - "mobile_native" => Ok(RadrootsPathProfile::MobileNative), - other => Err(RadrootsRuntimePathSelectionError::InvalidProfileValue { - value: other.to_owned(), - }), - } -} - #[cfg(test)] mod tests { use std::path::PathBuf; - use crate::{ - RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPathResolver, RadrootsPlatform, - }; - - use super::{ - RadrootsRuntimePathConfigEntry, RadrootsRuntimePathPolicyContract, - RadrootsRuntimePathSelection, RadrootsRuntimePathSelectionError, - }; - use crate::{InstanceId, ServiceId}; + use super::RadrootsServiceInstancePaths; + use crate::{InstanceId, ServiceId, roots::RadrootsPaths}; #[test] - fn caller_selection_preserves_profile_and_sources() { - let selection = - RadrootsRuntimePathSelection::caller(RadrootsPathProfile::InteractiveUser, None); - assert_eq!(selection.profile, RadrootsPathProfile::InteractiveUser); - assert_eq!(selection.profile_source, "caller"); - assert_eq!(selection.repo_local_root, None); - assert_eq!(selection.repo_local_root_source, None); - assert_eq!(selection.root_source(), "host_defaults"); - - let overrides = selection - .caller_overrides() - .expect("non-repo-local caller overrides should be empty"); - assert_eq!(overrides.repo_local_root, None); - - let service_selection = - RadrootsRuntimePathSelection::caller(RadrootsPathProfile::ServiceHost, None); - assert_eq!(service_selection.root_source(), "service_host_defaults"); - } - - #[test] - fn caller_selection_marks_repo_local_source() { - let selection = RadrootsRuntimePathSelection::caller( - RadrootsPathProfile::RepoLocal, - Some(PathBuf::from("/repo/.local/radroots")), - ); - - assert_eq!(selection.profile_source, "caller"); - assert_eq!(selection.repo_local_root_source.as_deref(), Some("caller")); - assert_eq!(selection.root_source(), "repo_local_root"); - - let overrides = selection - .caller_overrides() - .expect("caller overrides should use repo-local root"); - assert_eq!( - overrides.repo_local_root, - Some(PathBuf::from("/repo/.local/radroots")) - ); - } - - #[test] - fn resolve_service_roots_uses_repo_local_override() { - let selection = RadrootsRuntimePathSelection::caller( - RadrootsPathProfile::RepoLocal, - Some(PathBuf::from("/repo/.local/radroots")), - ); - let resolver = - RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); - - let roots = selection - .resolve_service_roots(&resolver, "radrootsd", "PROFILE_ENV", "ROOT_ENV") - .expect("service roots"); - - assert_eq!( - roots.config, - PathBuf::from("/repo/.local/radroots/config/services/radrootsd") - ); - assert_eq!( - roots.data, - PathBuf::from("/repo/.local/radroots/data/services/radrootsd") - ); - assert_eq!( - roots.logs, - PathBuf::from("/repo/.local/radroots/logs/services/radrootsd") - ); - assert_eq!( - roots.run, - PathBuf::from("/repo/.local/radroots/run/services/radrootsd") - ); - assert_eq!( - roots.secrets, - PathBuf::from("/repo/.local/radroots/secrets/services/radrootsd") - ); - } - - #[test] - fn resolve_myc_and_rhi_instance_paths_use_one_repo_local_base() { - let selection = RadrootsRuntimePathSelection::caller( - RadrootsPathProfile::RepoLocal, - Some(PathBuf::from("/repo/.local/radroots")), - ); - let resolver = - RadrootsPathResolver::new(RadrootsPlatform::Linux, RadrootsHostEnvironment::default()); - for (service, instance) in [("myc", "primary"), ("rhi", "west-01")] { - let service_id = ServiceId::new(service).expect("service id"); - let instance_id = InstanceId::new(instance).expect("instance id"); - let paths = selection - .resolve_service_instance_paths( - &resolver, - &service_id, - &instance_id, - "PROFILE_ENV", - "ROOT_ENV", - ) - .expect("service instance paths"); - let suffix = format!("services/{service}/{instance}"); - - assert_eq!( - paths.config(), - PathBuf::from("/repo/.local/radroots/config").join(&suffix) - ); - assert_eq!( - paths.state(), - PathBuf::from("/repo/.local/radroots/data").join(&suffix) - ); - assert_eq!( - paths.cache(), - PathBuf::from("/repo/.local/radroots/cache").join(&suffix) - ); - assert_eq!( - paths.logs(), - PathBuf::from("/repo/.local/radroots/logs").join(&suffix) - ); - assert_eq!( - paths.run(), - PathBuf::from("/repo/.local/radroots/run").join(&suffix) - ); - assert_eq!( - paths.secrets(), - PathBuf::from("/repo/.local/radroots/secrets").join(&suffix) - ); - } - } - - #[test] - fn overrides_require_repo_local_root_for_repo_local_profile() { - let selection = RadrootsRuntimePathSelection::caller(RadrootsPathProfile::RepoLocal, None); - let err = selection - .overrides("RADROOTS_TEST_PROFILE", "RADROOTS_TEST_ROOT") - .expect_err("repo local root"); - - assert_eq!( - err, - RadrootsRuntimePathSelectionError::MissingRepoLocalRoot { - profile_env: "RADROOTS_TEST_PROFILE".to_owned(), - repo_local_root_env: "RADROOTS_TEST_ROOT".to_owned(), - } - ); - } - - #[test] - fn repo_local_selection_rejects_relative_empty_and_escaping_roots() { - for root in [ - "", - ".", - "relative/root", - "../escape", - "/", - "/repo/../escape", - ] { - let selection = RadrootsRuntimePathSelection::caller( - RadrootsPathProfile::RepoLocal, - Some(PathBuf::from(root)), - ); - assert_eq!( - selection - .caller_overrides() - .expect_err("invalid caller root"), - RadrootsRuntimePathSelectionError::Paths( - crate::RadrootsRuntimePathsError::InvalidRepoLocalRoot - ), - "accepted invalid repo-local selection `{root}`" - ); - } - } - - #[test] - fn profile_value_selection_accepts_mobile_native() { - let selection = RadrootsRuntimePathSelection::from_profile_value("mobile_native", None) - .expect("mobile native profile"); - - assert_eq!(selection.profile, RadrootsPathProfile::MobileNative); - assert_eq!(selection.profile_source, "caller"); - assert_eq!(selection.root_source(), "mobile_native_defaults"); - - let selection = RadrootsRuntimePathSelection::from_profile_value("interactive_user", None) - .expect("interactive profile"); - assert_eq!(selection.profile, RadrootsPathProfile::InteractiveUser); - - let selection = RadrootsRuntimePathSelection::from_profile_value("service_host", None) - .expect("service-host profile"); - assert_eq!(selection.profile, RadrootsPathProfile::ServiceHost); - } - - #[test] - fn env_selection_covers_absent_present_and_error_paths() { - let selection = RadrootsRuntimePathSelection::from_env( - "RADROOTS_RUNTIME_PATHS_TEST_UNSET_PROFILE_DFA3ED5D", - "RADROOTS_RUNTIME_PATHS_TEST_UNSET_ROOT_DFA3ED5D", - RadrootsPathProfile::ServiceHost, - ) - .expect("absent env selection should use default profile"); - assert_eq!(selection.profile, RadrootsPathProfile::ServiceHost); - assert_eq!(selection.profile_source, "default"); - assert_eq!(selection.repo_local_root, None); - assert_eq!(selection.repo_local_root_source, None); - - let selection = RadrootsRuntimePathSelection::from_env_values( - "RADROOTS_TEST_PROFILE", - Ok("repo_local".to_owned()), - "RADROOTS_TEST_ROOT", - Some(std::ffi::OsString::from("/repo/.local/radroots")), - RadrootsPathProfile::InteractiveUser, - ) - .expect("present env values should select repo-local profile"); - assert_eq!(selection.profile, RadrootsPathProfile::RepoLocal); - assert_eq!( - selection.profile_source, - "process_env:RADROOTS_TEST_PROFILE" - ); - assert_eq!( - selection.repo_local_root, - Some(PathBuf::from("/repo/.local/radroots")) - ); - assert_eq!( - selection.repo_local_root_source.as_deref(), - Some("process_env:RADROOTS_TEST_ROOT") - ); - - let err = RadrootsRuntimePathSelection::from_env_values( - "RADROOTS_TEST_PROFILE", - Err(std::env::VarError::NotUnicode(std::ffi::OsString::from( - "not-unicode", - ))), - "RADROOTS_TEST_ROOT", - None, - RadrootsPathProfile::InteractiveUser, - ) - .expect_err("non-unicode profile env should fail"); - assert_eq!( - err, - RadrootsRuntimePathSelectionError::NonUnicodeEnv { - env_var: "RADROOTS_TEST_PROFILE".to_owned() - } - ); - - let err = RadrootsRuntimePathSelection::from_env_values( - "RADROOTS_TEST_PROFILE", - Ok("unknown".to_owned()), - "RADROOTS_TEST_ROOT", - None, - RadrootsPathProfile::InteractiveUser, - ) - .expect_err("invalid profile env should fail"); - assert_eq!( - err, - RadrootsRuntimePathSelectionError::InvalidProfileEnv { - env_var: "RADROOTS_TEST_PROFILE".to_owned(), - value: "unknown".to_owned() - } - ); - } - - #[test] - fn config_entry_selection_preserves_sources() { - let selection = RadrootsRuntimePathSelection::from_config_entries( - Some(RadrootsRuntimePathConfigEntry::new( - "RADROOTS_CLI_PATHS_PROFILE", - "repo_local", - "env_file:RADROOTS_CLI_PATHS_PROFILE", - )), - Some(RadrootsRuntimePathConfigEntry::new( - "RADROOTS_CLI_PATHS_REPO_LOCAL_ROOT", - "/repo/.local/radroots", - "env_file:RADROOTS_CLI_PATHS_REPO_LOCAL_ROOT", - )), - RadrootsPathProfile::InteractiveUser, - ) - .expect("config entries should select paths"); - - assert_eq!(selection.profile, RadrootsPathProfile::RepoLocal); - assert_eq!( - selection.profile_source, - "env_file:RADROOTS_CLI_PATHS_PROFILE" - ); - assert_eq!( - selection.repo_local_root, - Some(PathBuf::from("/repo/.local/radroots")) - ); - assert_eq!( - selection.repo_local_root_source.as_deref(), - Some("env_file:RADROOTS_CLI_PATHS_REPO_LOCAL_ROOT") - ); - } - - #[test] - fn config_entry_selection_uses_default_profile_without_sources() { - let selection = RadrootsRuntimePathSelection::from_config_entries( - None, - None, - RadrootsPathProfile::InteractiveUser, - ) - .expect("default selection"); - - assert_eq!(selection.profile, RadrootsPathProfile::InteractiveUser); - assert_eq!(selection.profile_source, "default"); - assert_eq!(selection.repo_local_root, None); - assert_eq!(selection.repo_local_root_source, None); - } - - #[test] - fn contract_captures_selection_sources() { - let selection = RadrootsRuntimePathSelection::caller( - RadrootsPathProfile::RepoLocal, - Some(PathBuf::from("/repo/.local/radroots")), - ); - - let contract = selection.contract( - &["interactive_user", "repo_local"], - "config_artifact", - &["config.service.logs_dir"], - ); - - assert_eq!(contract.active_profile, "repo_local"); - assert_eq!( - contract.allowed_profiles, - vec!["interactive_user".to_owned(), "repo_local".to_owned()] - ); - assert_eq!(contract.path_overrides.profile_source, "caller"); - assert_eq!( - contract.path_overrides.repo_local_root, - Some(PathBuf::from("/repo/.local/radroots")) - ); - } - - #[test] - fn path_policy_contract_preserves_policy_strings() { - let contract = RadrootsRuntimePathPolicyContract::new( - "profile_root_env_or_repo_wrapper", - "config_artifact", - "runtime_owned_leaf_overrides", - ); - - assert_eq!( - contract.canonical_root_selection, - "profile_root_env_or_repo_wrapper" - ); - assert_eq!( - contract.leaf_path_env_posture, - "runtime_owned_leaf_overrides" - ); + fn canonical_service_instance_suffix_uses_validated_ids() { + let roots = RadrootsPaths::from_base_root("/repo/.local/radroots"); + let paths = RadrootsServiceInstancePaths::from_resolved_roots( + &roots, + &ServiceId::new("myc").expect("service"), + &InstanceId::new("primary").expect("instance"), + ); + let suffix = PathBuf::from("services/myc/primary"); + + assert_eq!(paths.config(), roots.config.join(&suffix)); + assert_eq!(paths.state(), roots.data.join(&suffix)); + assert_eq!(paths.cache(), roots.cache.join(&suffix)); + assert_eq!(paths.logs(), roots.logs.join(&suffix)); + assert_eq!(paths.run(), roots.run.join(&suffix)); + assert_eq!(paths.secrets(), roots.secrets.join(&suffix)); } } diff --git a/crates/runtime_paths/tests/package_boundary.rs b/crates/runtime_paths/tests/package_boundary.rs @@ -0,0 +1,124 @@ +use std::collections::BTreeSet; + +const MANIFEST: &str = include_str!("../Cargo.toml"); +const README: &str = include_str!("../README"); +const PUBLIC_API: &str = + include_str!("../../../contracts/api_baselines/radroots_runtime_paths.txt"); +const ROOT: &str = include_str!("../src/lib.rs"); +const SOURCES: &[&str] = &[ + include_str!("../src/context.rs"), + include_str!("../src/conventions.rs"), + include_str!("../src/error.rs"), + include_str!("../src/identifier.rs"), + include_str!("../src/platform.rs"), + include_str!("../src/roots.rs"), + include_str!("../src/service.rs"), +]; + +#[test] +fn runtime_paths_is_unpublished_lint_governed_and_dependency_bounded() { + for required in [ + "name = \"radroots_runtime_paths\"", + "publish = false", + "version = \"0.1.0-alpha\"", + ] { + assert!( + MANIFEST.contains(required), + "manifest is missing `{required}`" + ); + } + assert_eq!( + dependency_keys(MANIFEST), + BTreeSet::from(["serde", "thiserror"]) + ); + assert!(!ROOT.contains("pub mod namespace;")); + for source in SOURCES { + let production = source.split("#[cfg(test)]").next().unwrap_or(source); + assert!(!production.contains("std::env")); + } +} + +#[test] +fn removed_namespace_selection_and_raw_root_surfaces_cannot_return() { + for forbidden in [ + "RadrootsRuntimeNamespace", + "RadrootsRuntimeNamespaceKind", + "RadrootsServiceInstanceNamespace", + "RadrootsRuntimePathSelection", + "RadrootsRuntimePathConfigEntry", + "RadrootsRuntimePathPolicyContract", + "RadrootsRuntimeSelectionContract", + "RadrootsRuntimeSelectionOverrideContract", + "RadrootsPathOverrides", + "RadrootsBootstrapPaths", + "default_service_instance_paths", + "default_namespaced_bootstrap_paths", + "default_shared_identity_path", + "default_shared_runtime_logs_dir", + "from_current_process", + "MissingMobileRoots", + "InvalidNamespaceComponent", + ] { + assert!( + SOURCES.iter().all(|source| !source.contains(forbidden)) && !ROOT.contains(forbidden), + "removed runtime-path surface `{forbidden}` returned" + ); + } + + for forbidden in [ + "pub struct radroots_runtime_paths::RadrootsPaths", + "pub struct radroots_runtime_paths::RadrootsPathOverrides", + "pub struct radroots_runtime_paths::RadrootsRuntimeNamespace", + "pub struct radroots_runtime_paths::RadrootsServiceInstanceNamespace", + "pub struct radroots_runtime_paths::RadrootsRuntimePathSelection", + "pub fn radroots_runtime_paths::RadrootsPathResolver::current", + "pub fn radroots_runtime_paths::RadrootsPathResolver::resolve", + ] { + assert!( + !PUBLIC_API.contains(forbidden), + "reviewed API baseline exposes `{forbidden}`" + ); + } +} + +#[test] +fn reviewed_api_requires_the_typed_runtime_context_boundary() { + for required in [ + "pub struct radroots_runtime_paths::RuntimeContext", + "pub struct radroots_runtime_paths::RuntimeContextBootstrap", + "pub enum radroots_runtime_paths::RuntimeContextSource", + "pub struct radroots_runtime_paths::RadrootsPathResolver", + "pub struct radroots_runtime_paths::RadrootsServiceInstancePaths", + "pub struct radroots_runtime_paths::RadrootsServiceInstanceArtifacts", + "pub struct radroots_runtime_paths::ServiceId", + "pub struct radroots_runtime_paths::InstanceId", + "pub fn radroots_runtime_paths::context::RuntimeContext::resolve", + ] { + assert!( + PUBLIC_API.contains(required), + "reviewed API baseline is missing `{required}`" + ); + } + + for required in [ + "sole canonical", + "sealed `RuntimeContext`", + "process-environment constructor", + "intentionally removed", + ] { + assert!(README.contains(required), "README is missing `{required}`"); + } +} + +fn dependency_keys(manifest: &str) -> BTreeSet<&str> { + manifest + .split_once("[dependencies]") + .map(|(_, dependencies)| dependencies) + .unwrap_or_default() + .lines() + .skip(1) + .take_while(|line| !line.starts_with('[')) + .filter_map(|line| line.split_once('=').map(|(key, _)| key.trim())) + .filter(|key| !key.is_empty()) + .collect() +}