tmux_backup/management/
backup.rs

1//! High-level representation of a backup for catalog operations and reporting.
2
3use std::fmt;
4use std::path::PathBuf;
5
6use chrono::{Duration, NaiveDateTime};
7use clap::ValueEnum;
8
9/// Quick access, high-level representation of a backup.
10///
11/// `Backup` provides only information which can be derived from the file name, avoiding to open
12/// the file, deal with the format, parse the metadata, etc.
13///
14/// This is sufficient for the [`Catalog`](crate::management::catalog::Catalog) to list backups
15/// and decide whether or not a backup should be deleted or kept.
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct Backup {
18    /// Path to the backup file.
19    pub filepath: PathBuf,
20
21    /// Backup date.
22    pub creation_date: NaiveDateTime,
23}
24
25impl Backup {
26    /// Return a string representing the duration since the backup file was created.
27    ///
28    // This function can only receive properly formatted files
29    pub fn age(&self, now: NaiveDateTime) -> String {
30        let duration = now.signed_duration_since(self.creation_date);
31        let duration_secs = duration.num_seconds();
32
33        // Month scale -> "n months ago"
34        let month = Duration::weeks(4).num_seconds();
35        if duration_secs >= 2 * month {
36            return format!("{} months", duration_secs / month);
37        }
38        if duration_secs >= month {
39            return "1 month".into();
40        }
41
42        // Week scale -> "n weeks ago"
43        let week = Duration::weeks(1).num_seconds();
44        if duration_secs >= 2 * week {
45            return format!("{} weeks", duration_secs / week);
46        }
47        if duration_secs >= week {
48            return "1 week".into();
49        }
50
51        // Day scale -> "n days ago"
52        let day = Duration::days(1).num_seconds();
53        if duration_secs >= 2 * day {
54            return format!("{} days", duration_secs / day);
55        }
56        if duration_secs >= day {
57            return "1 day".into();
58        }
59
60        // Hour scale -> "n hours ago"
61        let hour = Duration::hours(1).num_seconds();
62        if duration_secs >= 2 * hour {
63            return format!("{} hours", duration_secs / hour);
64        }
65        if duration_secs >= hour {
66            return "1 hour".into();
67        }
68
69        // Minute scale -> "n minutes ago"
70        let minute = Duration::minutes(1).num_seconds();
71        if duration_secs >= 2 * minute {
72            return format!("{} minutes", duration_secs / minute);
73        }
74        if duration_secs >= minute {
75            return "1 minute".into();
76        }
77
78        format!("{duration_secs} seconds")
79    }
80}
81
82/// Which subset of backups to print.
83#[derive(Debug, Clone, ValueEnum)]
84pub enum BackupStatus {
85    /// Retainable backups only.
86    Retainable,
87
88    /// Purgeable backups only.
89    Purgeable,
90}
91
92impl fmt::Display for BackupStatus {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        match self {
95            BackupStatus::Retainable => write!(f, "{:12}", "retainable"),
96            BackupStatus::Purgeable => write!(f, "{:12}", "purgeable"),
97        }
98    }
99}