summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: dad98c618b1f932194ad1c40592a09fea1c6d249 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use backup::Backup;
use clap::Parser;
use cli::Subcommands;
use config::Config;
use error::{Error, Result};
use tracing::{debug, error, level_filters::LevelFilter};
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

mod backup;
mod cli;
mod config;
mod error;
mod packages;
mod pathinfo;

fn main() -> Result<()> {
    let file_appender = tracing_appender::rolling::never("./", "arbs.log");
    let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);

    tracing_subscriber::registry()
        .with(
            fmt::layer()
                .with_writer(non_blocking)
                .with_file(false)
                .with_ansi(false)
                .without_time(),
        )
        .with(fmt::layer().with_file(false).without_time())
        .with(
            EnvFilter::builder()
                .with_default_directive(LevelFilter::INFO.into())
                .from_env_lossy(),
        )
        .init();
    debug!("logging initialized");
    
    match run_cli() {
        Ok(()) => { println!("OK") ; Ok(())},
        Err(err) => {
            error!(?err);
            error!("{:?}", std::error::Error::source(&err));
            send_notification("Backup Error", &err.to_string(), Urgency::Critical)?;
            Err(err)
        }
    }
}

fn run_cli() -> Result<()> {
    let cli = cli::Cli::parse();

    let config = Config::load(cli.config)?;

    match cli.subcommand {
        Subcommands::GenerateConfig => Config::generate()?,
        Subcommands::Save => {
            let backup = Backup::create(&config)?;
            backup.save(&config)?;
        }
        Subcommands::Restore { package_install } => {
            let Some(last_backup) = Backup::get_last(&config)? else {
                return Err(Error::BackupNotFound)?;
            };

            if package_install {
                last_backup.packages.install()?;
            }

            last_backup.restore(&config)?;
        },
    };
    Ok(())
}

enum Urgency {
    Normal,
    Critical
}

#[cfg(feature = "notifications")]
impl From<Urgency> for notify_rust::Urgency {
    fn from(value: Urgency) -> Self {
        match value {
            Urgency::Normal => Self::Normal,
            Urgency::Critical => Self::Critical,
        }
    }
}

fn send_notification(summary: &str, body: &str, urgency: Urgency) -> Result<()> {
    #[cfg(feature = "notifications")]
    {
        let Some(mut icon) = dirs::data_dir() else {
            return Err(Error::NoSysDir);
        };
        icon.push(env!("CARGO_PKG_NAME"));
        icon.push("icon.png");

    notify_rust::Notification::new()
        .summary(summary)
        .body(body)
        .icon(&icon.to_string_lossy())
        .timeout(0)
        .urgency(urgency.into())
        .show()?;
    }
    Ok(())
}