diff options
author | mdecimus <mauro@stalw.art> | 2024-09-20 09:59:10 +0200 |
---|---|---|
committer | mdecimus <mauro@stalw.art> | 2024-09-20 09:59:10 +0200 |
commit | 58351bdcad696e1e1ada6da114ec3f9f3dcb135b (patch) | |
tree | fd0dfe0b1b76f6d925dbbaee5d9f58f90d26f4da | |
parent | 39d0a168d480eb5b94bd031dd28fc4ba03d9a42e (diff) |
Support specifying which data types to export (closes #497)
-rw-r--r-- | crates/common/src/manager/backup.rs | 120 | ||||
-rw-r--r-- | crates/common/src/manager/boot.rs | 13 |
2 files changed, 111 insertions, 22 deletions
diff --git a/crates/common/src/manager/backup.rs b/crates/common/src/manager/backup.rs index 378474d8..c4f3e509 100644 --- a/crates/common/src/manager/backup.rs +++ b/crates/common/src/manager/backup.rs @@ -42,7 +42,7 @@ pub(super) enum Op { KeyValue((Vec<u8>, Vec<u8>)), } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub(super) enum Family { Property = 0, FtsIndex = 1, @@ -61,30 +61,61 @@ pub(super) enum Family { type TaskHandle = (tokio::task::JoinHandle<()>, std::thread::JoinHandle<()>); +#[derive(Debug, Default, PartialEq, Eq)] +pub struct BackupParams { + dest: PathBuf, + families: AHashSet<Family>, +} + impl Core { - pub async fn backup(&self, dest: PathBuf) { - if !dest.exists() { - std::fs::create_dir_all(&dest).failed("Failed to create backup directory"); - } else if !dest.is_dir() { - eprintln!("Backup destination {dest:?} is not a directory."); + pub async fn backup(&self, params: BackupParams) { + if !params.dest.exists() { + std::fs::create_dir_all(¶ms.dest).failed("Failed to create backup directory"); + } else if !params.dest.is_dir() { + eprintln!("Backup destination {:?} is not a directory.", params.dest); std::process::exit(1); } let mut sync_handles = Vec::new(); for (async_handle, sync_handle) in [ - self.backup_properties(&dest), - self.backup_fts_index(&dest), - self.backup_acl(&dest), - self.backup_blob(&dest), - self.backup_config(&dest), - self.backup_lookup(&dest), - self.backup_directory(&dest), - self.backup_queue(&dest), - self.backup_index(&dest), - self.backup_bitmaps(&dest), - self.backup_logs(&dest), - ] { + params + .has_family(Family::Property) + .then(|| self.backup_properties(¶ms.dest)), + params + .has_family(Family::FtsIndex) + .then(|| self.backup_fts_index(¶ms.dest)), + params + .has_family(Family::Acl) + .then(|| self.backup_acl(¶ms.dest)), + params + .has_family(Family::Blob) + .then(|| self.backup_blob(¶ms.dest)), + params + .has_family(Family::Config) + .then(|| self.backup_config(¶ms.dest)), + params + .has_family(Family::LookupValue) + .then(|| self.backup_lookup(¶ms.dest)), + params + .has_family(Family::Directory) + .then(|| self.backup_directory(¶ms.dest)), + params + .has_family(Family::Queue) + .then(|| self.backup_queue(¶ms.dest)), + params + .has_family(Family::Index) + .then(|| self.backup_index(¶ms.dest)), + params + .has_family(Family::Bitmap) + .then(|| self.backup_bitmaps(¶ms.dest)), + params + .has_family(Family::Log) + .then(|| self.backup_logs(¶ms.dest)), + ] + .into_iter() + .flatten() + { async_handle.await.failed("Task failed"); sync_handles.push(sync_handle); } @@ -1133,6 +1164,59 @@ impl DeserializeBytes for &[u8] { } } +impl BackupParams { + pub fn new(dest: PathBuf) -> Self { + let mut params = Self { + dest, + families: AHashSet::new(), + }; + + if let Ok(families) = std::env::var("EXPORT_TYPES") { + params.parse_families(&families); + } + + params + } + + fn parse_families(&mut self, families: &str) { + for family in families.split(',') { + let family = family.trim(); + match Family::parse(family) { + Ok(family) => { + self.families.insert(family); + } + Err(err) => { + eprintln!("Backup failed: {err}."); + std::process::exit(1); + } + } + } + } + + fn has_family(&self, family: Family) -> bool { + self.families.is_empty() || self.families.contains(&family) + } +} + +impl Family { + pub fn parse(family: &str) -> Result<Self, String> { + match family { + "property" => Ok(Family::Property), + "fts_index" => Ok(Family::FtsIndex), + "acl" => Ok(Family::Acl), + "blob" => Ok(Family::Blob), + "config" => Ok(Family::Config), + "lookup" => Ok(Family::LookupValue), + "directory" => Ok(Family::Directory), + "queue" => Ok(Family::Queue), + "index" => Ok(Family::Index), + "bitmap" => Ok(Family::Bitmap), + "log" => Ok(Family::Log), + _ => Err(format!("Unknown family {}", family)), + } + } +} + struct RawBytes(Vec<u8>); impl Deserialize for RawBytes { diff --git a/crates/common/src/manager/boot.rs b/crates/common/src/manager/boot.rs index 26493213..b11b5988 100644 --- a/crates/common/src/manager/boot.rs +++ b/crates/common/src/manager/boot.rs @@ -23,6 +23,7 @@ use crate::{ }; use super::{ + backup::BackupParams, config::{ConfigManager, Patterns}, WEBADMIN_KEY, }; @@ -33,7 +34,10 @@ pub struct BootManager { pub servers: Servers, } -const HELP: &str = r#"Stalwart Mail Server +const HELP: &str = concat!( + "Stalwart Mail Server v", + env!("CARGO_PKG_VERSION"), + r#" Usage: stalwart-mail [OPTIONS] @@ -44,11 +48,12 @@ Options: -I, --init <PATH> Initialize a new server at a specific path -h, --help Print help -V, --version Print version -"#; +"# +); #[derive(PartialEq, Eq)] enum ImportExport { - Export(PathBuf), + Export(BackupParams), Import(PathBuf), None, } @@ -89,7 +94,7 @@ impl BootManager { std::process::exit(0); } ("export" | "e", Some(value)) => { - import_export = ImportExport::Export(value.into()); + import_export = ImportExport::Export(BackupParams::new(value.into())); } ("import" | "i", Some(value)) => { import_export = ImportExport::Import(value.into()); |