1use serde::Deserialize;
2use std::fs;
3use std::path::PathBuf;
4
5#[derive(Deserialize, Debug)]
8pub struct Config {
9 pub sync: Vec<SyncTask>,
11}
12
13#[derive(Deserialize, Debug)]
15pub struct SyncTask {
16 pub name: String,
18
19 pub source: PathBuf,
21
22 pub target: PathBuf,
24
25 #[serde(default)]
27 pub exclude: Vec<String>,
28
29 #[serde(default = "default_delete_extra")]
30 pub delete_extra: bool,
31
32 #[serde(default)]
33 pub delete_extra_exclude: Vec<String>,
34}
35
36fn default_delete_extra() -> bool {
37 false
38}
39
40impl Config {
41 pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> anyhow::Result<Self> {
43 let path = path.as_ref();
44
45 if !path.exists() {
47 anyhow::bail!("Config file not found: {}", path.display());
48 }
49
50 let content = fs::read_to_string(path)
52 .map_err(|e| anyhow::anyhow!("Failed to read config file: {}", e))?;
53
54 let config: Config = toml::from_str(&content)
56 .map_err(|e| anyhow::anyhow!("Failed to parse config file: {}", e))?;
57
58 Ok(config)
60 }
61
62 pub fn find_task(&self, name: &str) -> Option<&SyncTask> {
64 self.sync.iter().find(|task| task.name == name)
65 }
66}