rattlebeaver 0.1.1

Manage rolling backups
Documentation
use crate::timestamp::Range;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

const DEFAULT_CONFIG_TOML: &str = r#"# Automatically generated config
[archive]
prefix = ".rattlebeaver."
timestamp_format = "%Y-%m-%d_%H-%M-%S"

[ranges]
latest = 10

[ranges.minutes]
total = 3
allow_sparse = true
include_first = true
include_last = true

[ranges.hours]
total = 5
allow_sparse = true
include_first = true
include_last = true

[ranges.days]
total = 10
allow_sparse = true
include_first = true
include_last = true

[ranges.months]
total = 12
allow_sparse = true
include_first = true
include_last = true

[ranges.years]
total = 10
allow_sparse = true
include_first = true
include_last = true
"#;

#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
    pub archive: Archive,
    pub ranges: Ranges,
}

impl Config {
    pub fn from_path(path: impl AsRef<std::path::Path>) -> Result<Self> {
        let s = std::fs::read_to_string(path).context("read config file")?;
        toml::from_str(&s).context("decode config toml")
    }

    pub fn from_toml(toml_str: impl AsRef<str>) -> Result<Self> {
        Ok(toml::from_str(toml_str.as_ref())?)
    }

    pub fn as_toml(&self) -> Result<String> {
        Ok(toml::to_string_pretty(&self)?)
    }
}

impl Default for Config {
    fn default() -> Self {
        toml::from_str(DEFAULT_CONFIG_TOML).expect("builtin default toml")
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Archive {
    pub prefix: String,
    pub timestamp_format: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Ranges {
    pub latest: usize,
    pub minutes: RollingRange,
    pub hours: RollingRange,
    pub days: RollingRange,
    pub months: RollingRange,
    pub years: RollingRange,
}

impl Ranges {
    #[must_use]
    pub fn iter_ranges(&self) -> [(Range, &RollingRange); 5] {
        [
            (Range::Minute, &self.minutes),
            (Range::Hour, &self.hours),
            (Range::Day, &self.days),
            (Range::Month, &self.months),
            (Range::Year, &self.years),
        ]
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RollingRange {
    pub total: usize,
    pub allow_sparse: bool,
    pub include_first: bool,
    pub include_last: bool,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn default_config() {
        Config::default();
    }
}