Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110//! Non-secret local folder inventory used for bulk import.
use std::{ fs, path::{Path, PathBuf},};
use serde::{Deserialize, Serialize};
use crate::{domain::FolderMode, storage::FolderConfig};
/// Version of the local folder inventory format.pub const CONFIG_VERSION: u16 = 1;pub const DEFAULT_CONFIG_PATH: &str = "appa.toml";
#[derive(Clone, Debug, Deserialize, Serialize)]#[serde(deny_unknown_fields)]pub struct AppaConfig { #[serde(default)] pub(crate) version: u16, #[serde(default)] pub(crate) folders: Vec<ConfiguredFolder>,}
#[derive(Clone, Debug, Deserialize, Serialize)]#[serde(deny_unknown_fields)]pub struct ConfiguredFolder { pub(crate) path: PathBuf, pub(crate) name: Option<String>, #[serde(default)] pub(crate) mode: FolderMode,}
impl AppaConfig { pub fn read(path: &Path) -> anyhow::Result<Self> { let contents = fs::read_to_string(path) .map_err(|error| anyhow::anyhow!("could not read {}: {error}", path.display()))?; let config: Self = toml::from_str(&contents) .map_err(|error| anyhow::anyhow!("could not parse {}: {error}", path.display()))?; config.validate()?; Ok(config) }
pub fn write_template(path: &Path, folders: &[FolderConfig]) -> anyhow::Result<()> { if path.exists() { anyhow::bail!("{} already exists", path.display()); } let config = Self { version: CONFIG_VERSION, folders: folders .iter() .map(ConfiguredFolder::from_storage_config) .collect(), }; fs::write(path, toml::to_string_pretty(&config)?)?; Ok(()) }
fn validate(&self) -> anyhow::Result<()> { if self.version != CONFIG_VERSION { anyhow::bail!("unsupported Appa config version {}", self.version); } Ok(()) }}
impl ConfiguredFolder { fn from_storage_config(folder: &FolderConfig) -> Self { Self { path: folder.path.clone(), name: Some(folder.name.clone()), mode: folder.mode, } }}
#[cfg(test)]mod tests { use std::fs;
use tempfile::TempDir;
use super::{AppaConfig, CONFIG_VERSION};
#[test] fn rejects_shared_folder_fields() { let directory = TempDir::new().expect("temporary directory"); let config_path = directory.path().join("appa.toml"); fs::write(&config_path, format!("version = {CONFIG_VERSION}\n[[folders]]\npath = \"notes\"\nfolder_id = \"00000000-0000-0000-0000-000000000000\"\n")).expect("write config");
assert!(AppaConfig::read(&config_path).is_err()); }
#[test] fn rejects_unknown_fields_and_reports_missing_versions() { let directory = TempDir::new().expect("temporary directory"); let config_path = directory.path().join("appa.toml"); fs::write(&config_path, "unknown = true\n").expect("write config"); assert!(AppaConfig::read(&config_path).is_err());
fs::write(&config_path, "[[folders]]\npath = \"notes\"\n").expect("write config"); let error = AppaConfig::read(&config_path).expect_err("missing version must fail"); assert!( error .to_string() .contains("unsupported Appa config version 0") ); }}