Do some small fixes & update deps

This commit is contained in:
2022-05-20 00:26:42 +02:00
parent 37498f5b33
commit 4d866f9608
9 changed files with 132 additions and 143 deletions

View File

@ -1,13 +1,13 @@
use crate::{local, planner, remote, Opt};
pub fn run(opt: &Opt) -> anyhow::Result<()> {
pub fn run(opt: &Opt, include_all: bool) -> anyhow::Result<()> {
info!("showing backup plan");
let local_list = local::file_list(opt)?;
let session = remote::connect(opt)?;
let remote_list = remote::file_list(opt, &session)?;
let plan = planner::plan(&local_list, &remote_list);
let plan = planner::plan(&local_list, &remote_list, include_all);
let presence = planner::presence(&local_list, &remote_list);
println!(

View File

@ -12,20 +12,13 @@ use std::time::Instant;
const TMP_FOLDER: &str = ".tmp";
pub fn run(opt: &Opt, sync_all: bool) -> anyhow::Result<()> {
// TODO: currently we only sync the latest local files
// --all will force a sync of ALL files on local which does not exist on remote
if sync_all {
error!("backup --all is not yet implemented");
unimplemented!();
}
pub fn run(opt: &Opt, include_all: bool) -> anyhow::Result<()> {
info!("generating backup plan");
let local_list = local::file_list(opt)?;
let session = remote::connect(opt)?;
let remote_list = remote::file_list(opt, &session)?;
let plan = planner::plan(&local_list, &remote_list);
let plan = planner::plan(&local_list, &remote_list, include_all);
if plan.transfers.is_empty() {
info!("nothing to do");
@ -144,14 +137,14 @@ fn send_snapshot(
.ok_or_else(|| anyhow::format_err!("failed to take stdout"))?;
// #### UPLOAD SNAPSHOT FILE ####
const CHUNK_SIZE: usize = 1024 * 1024 * 100; // 100MB
const CHUNK_SIZE: usize = 1024 * 1024 * 100; // 100MiB
let (data_tx, data_rx) = mpsc::sync_channel(10);
let tmp_path = opt.remote.path.join(TMP_FOLDER);
// spawn a thread to stream data from btrfs send in chunks
// spawn a thread to stream data from `btrfs send` in chunks
thread::spawn(move || -> io::Result<()> {
'outer: for _ in 0.. {
'outer: for _chunk in 0.. {
let mut buf: Vec<u8> = vec![0u8; CHUNK_SIZE];
let mut len = 0;
loop {

View File

@ -16,7 +16,7 @@ pub fn file_list(opt: &Opt) -> anyhow::Result<FileList> {
let name = match entry.file_name().into_string() {
Ok(name) => name,
Err(_) => continue,
Err(_) => continue, // ignore names that aren't valid utf-8
};
let date = DateTime::parse_from_rfc3339(&name)?;

View File

@ -5,12 +5,11 @@ mod actions;
mod local;
mod planner;
mod remote;
mod snapshot;
mod util;
use actions::{list, show_plan, sync};
use chrono::{DateTime, FixedOffset};
use clap::{crate_version, AppSettings, Clap};
use clap::{crate_version, Parser};
use remote::Remote;
use std::collections::BTreeMap;
use std::path::PathBuf;
@ -19,8 +18,8 @@ pub type TimeStamp = DateTime<FixedOffset>;
pub type FileList = BTreeMap<TimeStamp, String>;
/// Backup btrfs snapshots over SSH
#[derive(Clap)]
#[clap(version = crate_version!(), setting = AppSettings::ColoredHelp)]
#[derive(Parser)]
#[clap(version = crate_version!())]
pub struct Opt {
/// The path of the backup directory on the local filesystem
#[clap(short = 'l', long)]
@ -42,16 +41,21 @@ pub struct Opt {
action: Action,
}
#[derive(Clap)]
#[derive(Parser)]
pub enum Action {
/// Perform a backup
Backup {
/// Backup all files, not just the most recent ones
#[clap(long)]
all: bool,
},
/// Generate and show a backup plan
ShowPlan,
ShowPlan {
/// Backup all files, not just the most recent ones
#[clap(long)]
all: bool,
},
/// List all backups, and where they reside
List,
@ -64,7 +68,7 @@ fn main() -> anyhow::Result<()> {
match opt.action {
Action::Backup { all } => sync::run(&opt, all)?,
Action::ShowPlan => show_plan::run(&opt)?,
Action::ShowPlan { all } => show_plan::run(&opt, all)?,
Action::List => list::run(&opt)?,
}

View File

@ -8,7 +8,7 @@ pub enum Presence {
LocalAndRemote,
}
/// For every local file that is not in the remote, return a backup plan.
/// Check which files exist on remote, local, or both
pub fn presence(local: &FileList, remote: &FileList) -> BTreeMap<TimeStamp, Presence> {
let mut presence = BTreeMap::new();
@ -41,17 +41,24 @@ pub struct Plan {
pub transfers: BTreeMap<TimeStamp, TransferKind>,
}
/// For every local file that is not in the remote, return a backup plan.
/// For every trailing local file that is not in the remote, return a backup plan.
///
/// The backup plans may depend on each other, so they must be executed in order.
pub fn plan(local: &FileList, remote: &FileList) -> Plan {
// go through the local files in order, starting with the latest
let upload_list: BTreeSet<_> = local
.keys()
.rev()
// keep going while the file doesn't exist in the remote
.take_while(|ts| !remote.contains_key(ts))
.collect();
///
/// Set `include_all` to include all local files, not just the most recent.
pub fn plan(local: &FileList, remote: &FileList, include_all: bool) -> Plan {
let upload_list: BTreeSet<_> = {
// go through the local files in order, starting with the most recent
let local = local.keys().rev();
if include_all {
// take all files that doesn't exist in the remote
local.filter(|ts| !remote.contains_key(ts)).collect()
} else {
// take only the most recent files that doesn't exist in the remote
local.take_while(|ts| !remote.contains_key(ts)).collect()
}
};
// find the closest parent file of the first planned upload
let head_item = upload_list.iter().next().copied();

View File

@ -41,7 +41,7 @@ pub fn connect(opt: &Opt) -> anyhow::Result<Session> {
pub fn file_list(opt: &Opt, session: &Session) -> anyhow::Result<FileList> {
let mut channel = session.channel_session()?;
channel.exec(&format!(
r#"ls -1N "{}""#,
r#"ls -1NU "{}""#,
opt.remote
.path
.to_str()
@ -53,7 +53,6 @@ pub fn file_list(opt: &Opt, session: &Session) -> anyhow::Result<FileList> {
let mut list = BTreeMap::new();
for file in output.lines() {
let date = DateTime::parse_from_rfc3339(file)?;
//let path = PathBuf::from(file);
list.insert(date, file.to_string());
}

View File