1use crate::error::FilesystemError;
2use crate::fs::backup::{Backup, ZipBackup, ZstdBackup};
3use crate::repository::CompressionFormat;
4
5use chrono::{Local, NaiveDateTime};
6use std::convert::TryFrom;
7use std::path::{Path, PathBuf};
8
9pub async fn backup_folders(
12 src_folders: Vec<BackupFolder>,
13 mut dest: PathBuf,
14 compression: CompressionFormat,
15) -> Result<NaiveDateTime, FilesystemError> {
16 let now = Local::now();
17
18 dest.push(format!(
19 "ajour_backup_{}.{}",
20 now.format("%Y-%m-%d_%H-%M-%S"),
21 compression.file_ext(),
22 ));
23
24 match compression {
25 CompressionFormat::Zip => ZipBackup::new(src_folders, &dest).backup()?,
26 CompressionFormat::Zstd => ZstdBackup::new(src_folders, &dest).backup()?,
27 }
28
29 let as_of = Archive::try_from(dest).unwrap().as_of;
31
32 Ok(as_of)
33}
34
35pub async fn latest_backup(backup_dir: PathBuf) -> Option<NaiveDateTime> {
38 let zip_pattern = format!("{}/ajour_backup_[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9].zip", backup_dir.display());
39 let zstd_pattern = format!("{}/ajour_backup_[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9].tar.zst", backup_dir.display());
40
41 let mut backups = vec![];
42
43 for entry in glob::glob(&zip_pattern)
44 .unwrap()
45 .chain(glob::glob(&zstd_pattern).unwrap())
46 {
47 if let Ok(path) = entry {
48 if let Ok(archive) = Archive::try_from(path) {
49 backups.push(archive.as_of);
50 }
51 }
52 }
53
54 backups.sort();
56 backups.pop()
57}
58
59pub struct BackupFolder {
62 pub path: PathBuf,
63 pub prefix: PathBuf,
64}
65
66impl BackupFolder {
67 pub fn new(path: impl AsRef<Path>, prefix: impl AsRef<Path>) -> BackupFolder {
68 BackupFolder {
69 path: path.as_ref().to_owned(),
70 prefix: prefix.as_ref().to_owned(),
71 }
72 }
73}
74
75struct Archive {
78 pub as_of: NaiveDateTime,
79}
80
81impl TryFrom<PathBuf> for Archive {
82 type Error = chrono::ParseError;
83
84 fn try_from(path: PathBuf) -> Result<Archive, chrono::ParseError> {
85 let mut file_stem = path.file_stem().unwrap().to_str().unwrap();
86
87 if let Some(i) = file_stem.find('.') {
90 file_stem = file_stem.split_at(i).0;
91 }
92
93 let date_str = format!(
94 "{} {}",
95 file_stem.split('_').nth(2).unwrap_or_default(),
96 file_stem.split('_').nth(3).unwrap_or_default()
97 );
98
99 let as_of = NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%d %H-%M-%S")?;
100
101 Ok(Archive { as_of })
102 }
103}