lib

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

conventions.rs (11205B)


      1 use std::path::{Path, PathBuf};
      2 
      3 use crate::{
      4     RadrootsPathOverrides, RadrootsPathProfile, RadrootsPathResolver, RadrootsRuntimeNamespace,
      5     RadrootsRuntimePathsError,
      6 };
      7 
      8 pub const DEFAULT_CONFIG_FILE_NAME: &str = "config.toml";
      9 pub const DEFAULT_SERVICE_IDENTITY_FILE_NAME: &str = "identity.secret.json";
     10 pub const DEFAULT_SHARED_IDENTITY_FILE_NAME: &str = "default.json";
     11 pub const DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE_KIND: &str = "shared";
     12 pub const DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE_VALUE: &str = "local_events";
     13 pub const DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE: &str = "shared/local_events";
     14 pub const DEFAULT_SHARED_LOCAL_EVENTS_DB_FILE_NAME: &str = "local_events.sqlite";
     15 
     16 #[derive(Debug, Clone, PartialEq, Eq)]
     17 pub struct RadrootsBootstrapPaths {
     18     pub config_path: PathBuf,
     19     pub logs_dir: PathBuf,
     20     pub identity_path: PathBuf,
     21 }
     22 
     23 pub fn default_namespaced_bootstrap_paths(
     24     resolver: &RadrootsPathResolver,
     25     profile: RadrootsPathProfile,
     26     overrides: &RadrootsPathOverrides,
     27     namespace: &RadrootsRuntimeNamespace,
     28     identity_file_name: &str,
     29 ) -> Result<RadrootsBootstrapPaths, RadrootsRuntimePathsError> {
     30     let namespaced = resolver.resolve(profile, overrides)?.namespaced(namespace);
     31     Ok(RadrootsBootstrapPaths {
     32         config_path: namespaced.config.join(DEFAULT_CONFIG_FILE_NAME),
     33         logs_dir: namespaced.logs,
     34         identity_path: namespaced.secrets.join(identity_file_name),
     35     })
     36 }
     37 
     38 pub fn default_shared_identity_path(
     39     resolver: &RadrootsPathResolver,
     40     profile: RadrootsPathProfile,
     41     overrides: &RadrootsPathOverrides,
     42 ) -> Result<PathBuf, RadrootsRuntimePathsError> {
     43     let namespace = RadrootsRuntimeNamespace::shared("identities")?;
     44     let namespaced = resolver.resolve(profile, overrides)?.namespaced(&namespace);
     45     Ok(namespaced.secrets.join(DEFAULT_SHARED_IDENTITY_FILE_NAME))
     46 }
     47 
     48 pub fn default_shared_runtime_logs_dir(
     49     resolver: &RadrootsPathResolver,
     50     profile: RadrootsPathProfile,
     51     overrides: &RadrootsPathOverrides,
     52 ) -> Result<PathBuf, RadrootsRuntimePathsError> {
     53     let namespace = RadrootsRuntimeNamespace::shared("runtime")?;
     54     let namespaced = resolver.resolve(profile, overrides)?.namespaced(&namespace);
     55     Ok(namespaced.logs)
     56 }
     57 
     58 #[must_use]
     59 pub fn default_shared_local_events_root_from_data_root(data_root: impl AsRef<Path>) -> PathBuf {
     60     data_root
     61         .as_ref()
     62         .join(DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE_KIND)
     63         .join(DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE_VALUE)
     64 }
     65 
     66 #[must_use]
     67 pub fn default_shared_local_events_database_path_from_data_root(
     68     data_root: impl AsRef<Path>,
     69 ) -> PathBuf {
     70     default_shared_local_events_root_from_data_root(data_root)
     71         .join(DEFAULT_SHARED_LOCAL_EVENTS_DB_FILE_NAME)
     72 }
     73 
     74 pub fn default_shared_local_events_root_from_shared_accounts_data_root(
     75     shared_accounts_data_root: impl AsRef<Path>,
     76 ) -> Result<PathBuf, RadrootsRuntimePathsError> {
     77     let shared_accounts_data_root = shared_accounts_data_root.as_ref();
     78     let shared_data_root = shared_accounts_data_root.parent().ok_or_else(|| {
     79         RadrootsRuntimePathsError::SharedAccountsDataRootMissingParent {
     80             path: shared_accounts_data_root.to_path_buf(),
     81         }
     82     })?;
     83     Ok(shared_data_root.join(DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE_VALUE))
     84 }
     85 
     86 pub fn default_shared_local_events_database_path_from_shared_accounts_data_root(
     87     shared_accounts_data_root: impl AsRef<Path>,
     88 ) -> Result<PathBuf, RadrootsRuntimePathsError> {
     89     default_shared_local_events_root_from_shared_accounts_data_root(shared_accounts_data_root)
     90         .map(|root| root.join(DEFAULT_SHARED_LOCAL_EVENTS_DB_FILE_NAME))
     91 }
     92 
     93 #[cfg(test)]
     94 mod tests {
     95     use std::path::PathBuf;
     96 
     97     use crate::{
     98         RadrootsHostEnvironment, RadrootsPlatform, RadrootsRuntimeNamespace,
     99         RadrootsRuntimePathsError,
    100     };
    101 
    102     use super::{
    103         DEFAULT_SERVICE_IDENTITY_FILE_NAME, DEFAULT_SHARED_IDENTITY_FILE_NAME,
    104         DEFAULT_SHARED_LOCAL_EVENTS_DB_FILE_NAME, DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE,
    105         default_namespaced_bootstrap_paths, default_shared_identity_path,
    106         default_shared_local_events_database_path_from_data_root,
    107         default_shared_local_events_database_path_from_shared_accounts_data_root,
    108         default_shared_local_events_root_from_data_root,
    109         default_shared_local_events_root_from_shared_accounts_data_root,
    110         default_shared_runtime_logs_dir,
    111     };
    112 
    113     #[test]
    114     fn namespaced_bootstrap_paths_use_canonical_interactive_roots() {
    115         let resolver = crate::RadrootsPathResolver::new(
    116             RadrootsPlatform::Linux,
    117             RadrootsHostEnvironment {
    118                 home_dir: Some(PathBuf::from("/home/treesap")),
    119                 ..RadrootsHostEnvironment::default()
    120             },
    121         );
    122         let namespace =
    123             RadrootsRuntimeNamespace::service("radrootsd").expect("service namespace should parse");
    124 
    125         let paths = default_namespaced_bootstrap_paths(
    126             &resolver,
    127             crate::RadrootsPathProfile::InteractiveUser,
    128             &crate::RadrootsPathOverrides::default(),
    129             &namespace,
    130             DEFAULT_SERVICE_IDENTITY_FILE_NAME,
    131         )
    132         .expect("service bootstrap paths should resolve");
    133 
    134         assert_eq!(
    135             paths.config_path,
    136             PathBuf::from("/home/treesap/.radroots/config/services/radrootsd/config.toml")
    137         );
    138         assert_eq!(
    139             paths.logs_dir,
    140             PathBuf::from("/home/treesap/.radroots/logs/services/radrootsd")
    141         );
    142         assert_eq!(
    143             paths.identity_path,
    144             PathBuf::from(
    145                 "/home/treesap/.radroots/secrets/services/radrootsd/identity.secret.json"
    146             )
    147         );
    148     }
    149 
    150     #[test]
    151     fn shared_defaults_use_shared_namespaces() {
    152         let resolver = crate::RadrootsPathResolver::new(
    153             RadrootsPlatform::Macos,
    154             RadrootsHostEnvironment {
    155                 home_dir: Some(PathBuf::from("/Users/treesap")),
    156                 ..RadrootsHostEnvironment::default()
    157             },
    158         );
    159 
    160         let identity_path = default_shared_identity_path(
    161             &resolver,
    162             crate::RadrootsPathProfile::InteractiveUser,
    163             &crate::RadrootsPathOverrides::default(),
    164         )
    165         .expect("shared identity path should resolve");
    166         assert_eq!(
    167             identity_path,
    168             PathBuf::from("/Users/treesap/.radroots/secrets/shared/identities")
    169                 .join(DEFAULT_SHARED_IDENTITY_FILE_NAME)
    170         );
    171 
    172         let logs_dir = default_shared_runtime_logs_dir(
    173             &resolver,
    174             crate::RadrootsPathProfile::InteractiveUser,
    175             &crate::RadrootsPathOverrides::default(),
    176         )
    177         .expect("shared runtime logs dir should resolve");
    178         assert_eq!(
    179             logs_dir,
    180             PathBuf::from("/Users/treesap/.radroots/logs/shared/runtime")
    181         );
    182     }
    183 
    184     #[test]
    185     fn shared_local_events_paths_use_canonical_shared_namespace() {
    186         let data_root = PathBuf::from("/repo/infra/local/runtime/radroots/data");
    187 
    188         assert_eq!(
    189             default_shared_local_events_root_from_data_root(&data_root),
    190             data_root.join(DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE)
    191         );
    192         assert_eq!(
    193             default_shared_local_events_database_path_from_data_root(&data_root),
    194             data_root
    195                 .join(DEFAULT_SHARED_LOCAL_EVENTS_NAMESPACE)
    196                 .join(DEFAULT_SHARED_LOCAL_EVENTS_DB_FILE_NAME)
    197         );
    198     }
    199 
    200     #[test]
    201     fn shared_local_events_paths_derive_from_shared_accounts_data_root() {
    202         let shared_accounts_data_root =
    203             PathBuf::from("/repo/infra/local/runtime/radroots/data/shared/accounts");
    204 
    205         assert_eq!(
    206             default_shared_local_events_root_from_shared_accounts_data_root(
    207                 &shared_accounts_data_root
    208             )
    209             .expect("shared local-events root"),
    210             PathBuf::from("/repo/infra/local/runtime/radroots/data/shared/local_events")
    211         );
    212         assert_eq!(
    213             default_shared_local_events_root_from_shared_accounts_data_root(
    214                 shared_accounts_data_root.clone()
    215             )
    216             .expect("shared local-events root from owned path"),
    217             PathBuf::from("/repo/infra/local/runtime/radroots/data/shared/local_events")
    218         );
    219         assert_eq!(
    220             default_shared_local_events_database_path_from_shared_accounts_data_root(
    221                 &shared_accounts_data_root
    222             )
    223             .expect("shared local-events database path"),
    224             PathBuf::from(
    225                 "/repo/infra/local/runtime/radroots/data/shared/local_events/local_events.sqlite"
    226             )
    227         );
    228 
    229         let err =
    230             default_shared_local_events_root_from_shared_accounts_data_root(PathBuf::from("/"))
    231                 .expect_err("root path has no parent shared data root");
    232         assert_eq!(
    233             err,
    234             RadrootsRuntimePathsError::SharedAccountsDataRootMissingParent {
    235                 path: PathBuf::from("/")
    236             }
    237         );
    238     }
    239 
    240     #[test]
    241     fn namespaced_bootstrap_paths_propagate_resolver_errors() {
    242         let resolver =
    243             crate::RadrootsPathResolver::new(RadrootsPlatform::Linux, Default::default());
    244         let namespace =
    245             RadrootsRuntimeNamespace::service("radrootsd").expect("service namespace should parse");
    246 
    247         let err = default_namespaced_bootstrap_paths(
    248             &resolver,
    249             crate::RadrootsPathProfile::InteractiveUser,
    250             &crate::RadrootsPathOverrides::default(),
    251             &namespace,
    252             DEFAULT_SERVICE_IDENTITY_FILE_NAME,
    253         )
    254         .expect_err("interactive user should require a home dir");
    255 
    256         assert_eq!(
    257             err,
    258             crate::RadrootsRuntimePathsError::MissingHomeDir {
    259                 platform: RadrootsPlatform::Linux,
    260             }
    261         );
    262     }
    263 
    264     #[test]
    265     fn shared_defaults_propagate_profile_errors() {
    266         let resolver =
    267             crate::RadrootsPathResolver::new(RadrootsPlatform::Android, Default::default());
    268 
    269         let identity_err = default_shared_identity_path(
    270             &resolver,
    271             crate::RadrootsPathProfile::InteractiveUser,
    272             &crate::RadrootsPathOverrides::default(),
    273         )
    274         .expect_err("interactive_user should be unsupported on android");
    275         assert_eq!(
    276             identity_err,
    277             crate::RadrootsRuntimePathsError::UnsupportedProfilePlatform {
    278                 profile: crate::RadrootsPathProfile::InteractiveUser,
    279                 platform: RadrootsPlatform::Android,
    280             }
    281         );
    282 
    283         let logs_err = default_shared_runtime_logs_dir(
    284             &resolver,
    285             crate::RadrootsPathProfile::ServiceHost,
    286             &crate::RadrootsPathOverrides::default(),
    287         )
    288         .expect_err("service_host should be unsupported on android");
    289         assert_eq!(
    290             logs_err,
    291             crate::RadrootsRuntimePathsError::UnsupportedProfilePlatform {
    292                 profile: crate::RadrootsPathProfile::ServiceHost,
    293                 platform: RadrootsPlatform::Android,
    294             }
    295         );
    296     }
    297 }