feat: add stage 2

This commit is contained in:
Xory 2024-09-10 11:02:19 +03:00
parent 4e366d10e9
commit 28f0988f5f
8 changed files with 87 additions and 10 deletions

View file

@ -0,0 +1,4 @@
I: Begin backup log - 1725955295
I: Beginning stage 1 backup.
I: Beginning stage 2 backup.

4
resetenv.sh Normal file
View file

@ -0,0 +1,4 @@
#! /bin/bash
rm -r testfiles/dir/*
echo "" > log.txt
rm -r /run/media/xory/Ventoy/backup/*

View file

@ -15,12 +15,20 @@ pub struct StageConfig {
#[derive(Deserialize, Debug, PartialEq)] #[derive(Deserialize, Debug, PartialEq)]
pub struct Config { pub struct Config {
pub stage_1: StageConfig pub stage_1: StageConfig,
pub stage_2: StageConfig
} }
impl Config { impl Config {
pub fn new(config_toml: String) -> Config { pub fn new(config_toml: String) -> Config {
toml::from_str(&config_toml).expect("Invalid Config") let config = match toml::from_str(&config_toml) {
Ok(config) => config,
Err(err) => {
let _ = log("./log.txt".to_string(), format!("Failed to parse config, got error {err}"), LogLevel::Error);
std::process::exit(1);
}
};
config
} }
} }
@ -55,6 +63,44 @@ pub fn stage1(config: &Config) -> io::Result<()> {
Ok(()) Ok(())
} }
pub fn stage2(config: &Config) -> io::Result<()> {
for file in &config.stage_2.src_files {
let filename = match file.split('/').last() {
Some(filename) => filename,
None => { eprintln!("E: Failed to derive filename from {file}"); break }
};
let target_path = format!("{}/{filename}", &config.stage_2.target_dir);
if !Path::new(&config.stage_2.target_dir).exists() {
log(".log.txt".to_string(), "External drive missing or not mounted, please insert and/or mount the drive and try again.".to_string(), LogLevel::Error)?;
break
}
if Path::new(file).is_file() {
if let Err(err) = fs::copy(file, target_path) {
log("./log.txt".to_string(), err.to_string(), LogLevel::Error)?;
break
};
} else if Path::new(file).is_dir() && config.stage_2.recursive {
if let Err(err) = fs::create_dir(target_path) {
log("./log.txt".to_string(), err.to_string(), LogLevel::Error)?;
break
}
for entry in fs::read_dir(file)? {
let target_dir = format!("{}/{}", &config.stage_2.target_dir, filename);
let file = entry?;
if let Err(err) = fs::copy(Path::new(&file.path()), format!("{}/{}", target_dir, file.file_name().to_str().unwrap())) {
log("./log.txt".to_string(), err.to_string(), LogLevel::Error)?;
break
};
}
} else {
log("./log.txt".to_string(), "Copy conditions not matched for file {file}, skipping.".to_string(), LogLevel::Warning)?;
}
}
Ok(())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -64,7 +110,12 @@ mod tests {
let toml_config = "[stage_1] let toml_config = "[stage_1]
src_files = [ './testfiles/src/file1.txt', './testfiles/src/file2.txt', './testfiles/src/a' ] src_files = [ './testfiles/src/file1.txt', './testfiles/src/file2.txt', './testfiles/src/a' ]
target_dir = './testfiles/dir' target_dir = './testfiles/dir'
recursive = true"; recursive = true
[stage_2]
src_files = [ './testfiles/src/file1.txt', './testfiles/src/file2.txt', './testfiles/src/a' ]
target_dir = '/run/media/xory/Ventoy/backup'
recursive = true
";
let parsed_config = Config::new(toml_config.to_string()); let parsed_config = Config::new(toml_config.to_string());
assert_eq!( assert_eq!(
@ -73,7 +124,12 @@ mod tests {
src_files: vec![ "./testfiles/src/file1.txt".to_string(), "./testfiles/src/file2.txt".to_string(), "./testfiles/src/a".to_string() ], src_files: vec![ "./testfiles/src/file1.txt".to_string(), "./testfiles/src/file2.txt".to_string(), "./testfiles/src/a".to_string() ],
target_dir: "./testfiles/dir".to_string(), target_dir: "./testfiles/dir".to_string(),
recursive: true recursive: true
} },
stage_2: StageConfig {
src_files: vec![ "./testfiles/src/file1.txt".to_string(), "./testfiles/src/file2.txt".to_string(), "./testfiles/src/a".to_string() ],
target_dir: "/run/media/xory/Ventoy/backup".to_string(),
recursive: true
}
}, },
parsed_config parsed_config
); );

View file

@ -1,13 +1,18 @@
use cynewave::{Config, stage1}; use cynewave::{Config, stage1, stage2};
mod logger; mod logger;
use logger::{log, LogLevel}; use logger::{log, LogLevel};
use std::fs; use std::fs;
use std::time::{UNIX_EPOCH, SystemTime};
fn main() { fn main() -> Result<(), Box<dyn std::error::Error>> {
let current_epoch = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
log("./log.txt".to_string(), format!("Begin backup log - {current_epoch}"), LogLevel::Info)?;
let config_file: String = fs::read_to_string("./testconfig.toml").expect("Failed to read config"); let config_file: String = fs::read_to_string("./testconfig.toml").expect("Failed to read config");
let config: Config = Config::new(config_file); let config: Config = Config::new(config_file);
dbg!(&config); dbg!(&config);
log("./log.txt".to_string(), "Beginning stage 1 backup.".to_string(), LogLevel::Info).unwrap(); log("./log.txt".to_string(), "Beginning stage 1 backup.".to_string(), LogLevel::Info)?;
stage1(&config).unwrap(); stage1(&config)?;
log("./log.txt".to_string(), "Beginning stage 2 backup.".to_string(), LogLevel::Info)?;
stage2(&config)?;
Ok(())
} }

View file

@ -1,5 +1,11 @@
[stage_1] [stage_1]
src_files = [ "./testfiles/src/file1.txt", "./testfiles/src/file2.txt", "./testfiles/src/a" ] src_files = [ "./testfiles/src/file1.txt", "./testfiles/src/file2.txt", "./testfiles/src/a" ]
target_dir = "./testfiles/dir" target_dir = "./testfiles/dir"
recursive = false recursive = true
[stage_2]
src_files = [ "./testfiles/src/file1.txt", "./testfiles/src/file2.txt", "./testfiles/src/a" ]
target_dir = "/run/media/xory/Ventoy/backup"
recursive = true

View file

1
testfiles/dir/file1.txt Normal file
View file

@ -0,0 +1 @@
a

1
testfiles/dir/file2.txt Normal file
View file

@ -0,0 +1 @@
b