diff --git a/crates/shturman-common/src/paths.rs b/crates/shturman-common/src/paths.rs index 33bed61..9a45872 100644 --- a/crates/shturman-common/src/paths.rs +++ b/crates/shturman-common/src/paths.rs @@ -1 +1,63 @@ -//! Канонические пути персистентного раздела `/data` (наполняется в Task 2). +//! Канонические пути персистентного раздела `/data` (a-base §3, §11). +//! Все писатели в `/data` берут пути отсюда — без хардкода. Корень настраивается +//! (тесты/dev) — по умолчанию `/data` или env `SHTURMAN_DATA_DIR`. + +use std::path::{Path, PathBuf}; + +/// Раскладка `/data`. +#[derive(Debug, Clone)] +pub struct Layout { + root: PathBuf, +} + +impl Layout { + /// Явный корень (тесты, known-mount). + pub fn new(root: impl Into) -> Self { + Self { root: root.into() } + } + + /// Корень из окружения (`SHTURMAN_DATA_DIR`) или дефолт `/data`. + pub fn from_env() -> Self { + let root = std::env::var_os("SHTURMAN_DATA_DIR") + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from("/data")); + Self { root } + } + + pub fn root(&self) -> &Path { + &self.root + } + pub fn apps(&self) -> PathBuf { + self.root.join("apps") + } + pub fn settings(&self) -> PathBuf { + self.root.join("settings") + } + pub fn state(&self) -> PathBuf { + self.root.join("state") + } + pub fn log(&self) -> PathBuf { + self.root.join("log") + } + /// Маркер завершённого first-boot (§7.2). + pub fn provisioned_marker(&self) -> PathBuf { + self.root.join(".shturman-provisioned") + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::path::Path; + + #[test] + fn subdirs_are_under_root() { + let l = Layout::new("/tmp/x"); + assert_eq!(l.root(), Path::new("/tmp/x")); + assert_eq!(l.apps(), Path::new("/tmp/x/apps")); + assert_eq!(l.settings(), Path::new("/tmp/x/settings")); + assert_eq!(l.state(), Path::new("/tmp/x/state")); + assert_eq!(l.log(), Path::new("/tmp/x/log")); + assert_eq!(l.provisioned_marker(), Path::new("/tmp/x/.shturman-provisioned")); + } +}