Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 64 additions & 72 deletions crates/core/src/commands/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@ use derive_setters::Setters;
use jiff::Timestamp;
use log::{debug, error, info, trace, warn};

use std::{
cmp::Ordering,
collections::BTreeMap,
path::{Path, PathBuf},
sync::Mutex,
};
use std::{cmp::Ordering, collections::BTreeMap, path::PathBuf, sync::Mutex};

use ignore::{DirEntry, WalkBuilder};
use itertools::Itertools;
use rayon::ThreadPoolBuilder;
use walkdir::{DirEntry, WalkDir};

use crate::{
backend::{
Expand Down Expand Up @@ -170,59 +165,65 @@ pub(crate) fn collect_and_prepare<S: IndexedFull>(
let mut stats = RestoreStats::default();
let mut restore_infos = RestorePlan::default();
let mut additional_existing = false;
let mut removed_dir = None;

let mut process_existing = |entry: &DirEntry| -> RusticResult<_> {
if entry.depth() == 0 {
// don't process the root dir which should be existing
return Ok(());
}
let next_entry = |walker: &mut walkdir::IntoIter| -> Option<DirEntry> {
walker
.inspect(|r| {
if let Err(err) = r {
error!("Error during collection of files: {err:?}");
}
})
.find_map(Result::ok)
};

debug!("additional {}", entry.path().display());
if entry.file_type().unwrap().is_dir() {
stats.dirs.additional += 1;
} else {
stats.files.additional += 1;
}
match (opts.delete, dry_run, entry.file_type().unwrap().is_dir()) {
(true, true, true) => {
info!(
"would have removed the additional dir: {}",
entry.path().display()
);
let mut process_existing =
|walker: &mut walkdir::IntoIter, entry: &DirEntry| -> RusticResult<Option<DirEntry>> {
if entry.depth() == 0 {
// don't process the root dir which should be existing
return Ok(next_entry(walker));
}
(true, true, false) => {
info!(
"would have removed the additional file: {}",
entry.path().display()
);

debug!("additional {}", entry.path().display());
let is_dir = entry.file_type().is_dir();
if is_dir {
stats.dirs.additional += 1;
} else {
stats.files.additional += 1;
}
(true, false, true) => {
let path = entry.path();
match &removed_dir {
Some(dir) if path.starts_with(dir) => {}
_ => match dest.remove_dir(path) {
Ok(()) => {
removed_dir = Some(path.to_path_buf());
}
Err(err) => {
error!("error removing {}: {err}", path.display());
}
},
match (opts.delete, dry_run, is_dir) {
(true, true, true) => {
info!(
"would have removed the additional dir: {}",
entry.path().display()
);
}
}
(true, false, false) => {
if let Err(err) = dest.remove_file(entry.path()) {
error!("error removing {}: {err}", entry.path().display());
(true, true, false) => {
info!(
"would have removed the additional file: {}",
entry.path().display()
);
}
(true, false, true) => {
if let Err(err) = dest.remove_dir(entry.path()) {
error!("error removing {}: {err}", entry.path().display());
}
}
(true, false, false) => {
if let Err(err) = dest.remove_file(entry.path()) {
error!("error removing {}: {err}", entry.path().display());
}
}
(false, _, _) => {
additional_existing = true;
}
}
(false, _, _) => {
additional_existing = true;
}
}

Ok(())
};
// don't descend into extra dirs
if is_dir {
walker.skip_current_dir();
}
Ok(next_entry(walker))
};

let mut process_node = |path: &PathBuf, node: &Node, exists: bool| -> RusticResult<_> {
match node.node_type {
Expand Down Expand Up @@ -288,20 +289,12 @@ pub(crate) fn collect_and_prepare<S: IndexedFull>(
Ok(())
};

let mut dst_iter = WalkBuilder::new(dest_path)
let mut walker = WalkDir::new(&dest_path)
.follow_links(false)
.hidden(false)
.ignore(false)
.sort_by_file_path(Path::cmp)
.build()
.inspect(|r| {
if let Err(err) = r {
error!("Error during collection of files: {err:?}");
}
})
.filter_map(Result::ok);
.sort_by_file_name()
.into_iter();

let mut next_dst = dst_iter.next();
let mut next_dst = next_entry(&mut walker);

let mut next_node = node_streamer.next().transpose()?;

Expand All @@ -310,26 +303,25 @@ pub(crate) fn collect_and_prepare<S: IndexedFull>(
(None, None) => break,

(Some(destination), None) => {
process_existing(destination)?;
next_dst = dst_iter.next();
next_dst = process_existing(&mut walker, destination)?;
}
(Some(destination), Some((path, node))) => {
match destination.path().cmp(&dest.path(path)) {
Ordering::Less => {
process_existing(destination)?;
next_dst = dst_iter.next();
next_dst = process_existing(&mut walker, destination)?;
}
Ordering::Equal => {
// process existing node
if (node.is_dir() && !destination.file_type().unwrap().is_dir())
|| (node.is_file() && !destination.metadata().unwrap().is_file())
if (node.is_dir() && !destination.file_type().is_dir())
|| (node.is_file() && !destination.file_type().is_file())
|| node.is_special()
{
// if types do not match, first remove the existing file
process_existing(destination)?;
next_dst = process_existing(&mut walker, destination)?;
} else {
next_dst = next_entry(&mut walker);
}
process_node(path, node, true)?;
next_dst = dst_iter.next();
next_node = node_streamer.next().transpose()?;
}
Ordering::Greater => {
Expand Down
Loading