vivo 0.7.0

restic backup orchestrator with multi-remote sync and SOPS-encrypted secrets
Documentation
use crate::backup_config::BackupConfig;

#[derive(Clone, Copy, PartialEq)]
pub enum Pane {
    Tasks,
    Remotes,
}

pub struct TaskEntry {
    pub name: String,
    pub remotes: Vec<RemoteEntry>,
}

pub struct RemoteEntry {
    pub url: String,
    pub credentials: String,
}

pub struct App {
    pub tasks: Vec<TaskEntry>,
    pub selected_task: usize,
    pub selected_remote: usize,
    pub focused_pane: Pane,
    pub config_path: String,
    pub should_quit: bool,
    pub status_message: Option<String>,
}

impl App {
    pub fn new(config: &BackupConfig, config_path: String) -> Self {
        let tasks = config
            .tasks
            .iter()
            .map(|t| TaskEntry {
                name: t.name.clone(),
                remotes: t
                    .backup_remotes()
                    .into_iter()
                    .map(|(url, creds)| RemoteEntry {
                        url: url.to_string(),
                        credentials: creds.to_string(),
                    })
                    .collect(),
            })
            .collect();

        App {
            tasks,
            selected_task: 0,
            selected_remote: 0,
            focused_pane: Pane::Tasks,
            config_path,
            should_quit: false,
            status_message: None,
        }
    }

    pub fn current_remotes(&self) -> &[RemoteEntry] {
        self.tasks
            .get(self.selected_task)
            .map(|t| t.remotes.as_slice())
            .unwrap_or(&[])
    }

    pub fn reload(&mut self) {
        if let Ok(content) = std::fs::read_to_string(&self.config_path) {
            if let Ok(config) =
                knuffel::parse::<BackupConfig>(&self.config_path, &content)
            {
                let new = App::new(&config, self.config_path.clone());
                let prev_task = self.selected_task;
                let prev_remote = self.selected_remote;
                *self = new;
                self.selected_task =
                    prev_task.min(self.tasks.len().saturating_sub(1));
                self.selected_remote =
                    prev_remote.min(self.current_remotes().len().saturating_sub(1));
            }
        }
    }
}