borg-hive 0.0.2

Automated backups using Borg Backup
// borg-hive - Zero-configuration wrapper for borg
// Copyright (C) 2017  Lorenzo Villani
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::env;

use rpassword;

use borg;
use config;
use password;
use state;
use utils;

use errors::*;

pub fn ask_and_set_new_password() -> Result<()> {
    let pwd1 = rpassword::prompt_password_stdout("New password: ")?;
    let pwd2 = rpassword::prompt_password_stdout("Confirm password: ")?;

    if pwd1 != pwd2 {
        bail!("passwords do not match");
    }

    password::set_password(pwd1.as_str())
}

pub fn backup() -> Result<()> {
    let config = config::Config::load_user()?;

    let home_dir = match env::home_dir() {
        None => bail!("cannot determine home directory"),
        Some(x) => x,
    };

    let passphrase = password::get_password()?;

    let mut state = state::State::load()?;

    for destination in &config.destinations {
        let repo = utils::expanded(destination.repo.as_ref())?;
        let repo = repo.as_ref();

        macro_rules! or_continue {
            ($x:expr) => {
                match $x {
                    Err(ref e) => {
                        warn!("backup to {} failed", repo);
                        warn!("caused by: {}", e);
                        continue;
                    },
                    Ok(x) => x,
                }
            }
        }

        if !destination.before_backup.is_empty() {
            info!("before backup: {}", destination.before_backup.join(" "));
            or_continue!(utils::run(&destination.before_backup));
        }

        info!("backing up to {}", repo);
        or_continue!(borg::borg_init(repo, passphrase.as_str()));
        or_continue!(borg::borg_create(
            repo,
            passphrase.as_str(),
            &home_dir,
            &config.exclude,
        ));

        info!("pruning old backups");
        or_continue!(borg::borg_prune(repo, passphrase.as_str()));

        if !destination.after_backup.is_empty() {
            info!("after backup: {}", destination.after_backup.join(" "));
            or_continue!(utils::run(&destination.after_backup));
        }

        debug!("updating state file");
        state.mark_success(destination)?;
    }

    Ok(())
}