mirror of
https://github.com/rustic-rs/rustic.git
synced 2025-10-26 11:18:51 +00:00
better error handling
This commit is contained in:
parent
6c62fa5c00
commit
68e99447d8
@ -5,7 +5,7 @@ use std::io::{BufRead, BufReader};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use crate::backend::DecryptWriteBackend;
|
||||
use crate::blob::{BlobType, Node, Packer, Tree};
|
||||
@ -19,8 +19,7 @@ pub type SharedIndexer<BE> = Rc<RefCell<Indexer<BE>>>;
|
||||
pub struct Archiver<BE: DecryptWriteBackend, I: ReadIndex> {
|
||||
path: PathBuf,
|
||||
tree: Tree,
|
||||
names: Vec<OsString>,
|
||||
trees: Vec<Tree>,
|
||||
stack: Vec<(Node, Tree)>,
|
||||
size: u64,
|
||||
count: u64,
|
||||
be: BE,
|
||||
@ -37,8 +36,7 @@ impl<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
|
||||
Ok(Self {
|
||||
path: PathBuf::from("/"),
|
||||
tree: Tree::new(),
|
||||
names: Vec::new(),
|
||||
trees: Vec::new(),
|
||||
stack: Vec::new(),
|
||||
size: 0,
|
||||
count: 0,
|
||||
index,
|
||||
@ -54,7 +52,8 @@ impl<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
|
||||
let basepath = if file_type.is_dir() {
|
||||
path
|
||||
} else {
|
||||
path.parent().unwrap()
|
||||
path.parent()
|
||||
.ok_or(anyhow!("file path should have a parent!"))?
|
||||
};
|
||||
|
||||
self.finish_trees(&basepath)?;
|
||||
@ -65,8 +64,8 @@ impl<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
|
||||
for p in missing_dirs.iter() {
|
||||
// new subdir
|
||||
let tree = std::mem::replace(&mut self.tree, Tree::new());
|
||||
self.trees.push(tree);
|
||||
self.names.push(p.to_os_string());
|
||||
let node = Node::new_tree(p.to_os_string())?;
|
||||
self.stack.push((node, tree));
|
||||
self.path.push(p);
|
||||
println!("add tree {:?}, path: {:?}", p, self.path);
|
||||
}
|
||||
@ -87,10 +86,10 @@ impl<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
|
||||
if !self.index.has(&id) {
|
||||
self.tree_packer.add(&chunk, &id, BlobType::Tree)?;
|
||||
}
|
||||
self.tree = self.trees.pop().unwrap();
|
||||
let name = self.names.pop().unwrap();
|
||||
|
||||
let (mut node, name) = self.stack.pop().ok_or(anyhow!("tree stack empty??"))?;
|
||||
println!("finish: {:?}", name);
|
||||
let node = Node::from_tree(name, id)?;
|
||||
node.set_subtree(id);
|
||||
|
||||
self.tree.add(node);
|
||||
self.path.pop();
|
||||
@ -135,7 +134,10 @@ impl<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
|
||||
// save snapshot
|
||||
let snap = SnapshotFile::new(
|
||||
id,
|
||||
vec![backup_path.to_str().unwrap().to_string()],
|
||||
vec![backup_path
|
||||
.to_str()
|
||||
.ok_or(anyhow!("non-unicode path {:?}", backup_path))?
|
||||
.to_string()],
|
||||
"host".to_string(),
|
||||
"user".to_string(),
|
||||
0,
|
||||
|
||||
@ -76,4 +76,18 @@ impl Node {
|
||||
meta: Metadata::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_tree(name: OsString) -> Result<Self> {
|
||||
Ok(Self {
|
||||
name: name.to_str().expect("no unicode").to_string(),
|
||||
node_type: NodeType::Dir,
|
||||
content: Vec::new(),
|
||||
subtree: None,
|
||||
meta: Metadata::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_subtree(&mut self, id: Id) {
|
||||
self.subtree = Some(id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,16 +38,15 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
|
||||
type TreeIterItem = Result<(PathBuf, Node)>;
|
||||
|
||||
/// tree_iterator creates an Iterator over the trees given by ids using the backend be and the index
|
||||
/// index
|
||||
pub fn tree_iterator(
|
||||
be: &impl IndexedBackend,
|
||||
ids: Vec<Id>,
|
||||
) -> impl Iterator<Item = (PathBuf, Node)> + '_ {
|
||||
TreeIterator::new(
|
||||
|i| Tree::from_backend(be, i).unwrap().nodes.into_iter(),
|
||||
ids,
|
||||
)
|
||||
) -> Result<impl Iterator<Item = TreeIterItem> + '_> {
|
||||
TreeIterator::new(|i| Ok(Tree::from_backend(be, i)?.nodes.into_iter()), ids)
|
||||
}
|
||||
|
||||
/// tree_iterator_once creates an Iterator over the trees given by ids using the backend be and the index
|
||||
@ -55,14 +54,14 @@ pub fn tree_iterator(
|
||||
pub fn tree_iterator_once(
|
||||
be: &impl IndexedBackend,
|
||||
ids: Vec<Id>,
|
||||
) -> impl Iterator<Item = (PathBuf, Node)> + '_ {
|
||||
) -> Result<impl Iterator<Item = TreeIterItem> + '_> {
|
||||
let mut visited = HashSet::new();
|
||||
TreeIterator::new(
|
||||
move |i| {
|
||||
if visited.insert(*i) {
|
||||
Tree::from_backend(be, i).unwrap().nodes.into_iter()
|
||||
Ok(Tree::from_backend(be, i)?.nodes.into_iter())
|
||||
} else {
|
||||
Vec::new().into_iter()
|
||||
Ok(Vec::new().into_iter())
|
||||
}
|
||||
},
|
||||
ids,
|
||||
@ -74,7 +73,7 @@ pub fn tree_iterator_once(
|
||||
pub struct TreeIterator<IT, F>
|
||||
where
|
||||
IT: Iterator<Item = Node>,
|
||||
F: FnMut(&Id) -> IT,
|
||||
F: FnMut(&Id) -> Result<IT>,
|
||||
{
|
||||
open_iterators: Vec<IT>,
|
||||
inner: IT,
|
||||
@ -85,40 +84,40 @@ where
|
||||
impl<IT, F> TreeIterator<IT, F>
|
||||
where
|
||||
IT: Iterator<Item = Node>,
|
||||
F: FnMut(&Id) -> IT,
|
||||
F: FnMut(&Id) -> Result<IT>,
|
||||
{
|
||||
fn new(mut getter: F, ids: Vec<Id>) -> Self {
|
||||
fn new(mut getter: F, ids: Vec<Id>) -> Result<Self> {
|
||||
// TODO: empty ids vector will panic here!
|
||||
let mut iters = ids.iter().map(&mut getter).collect::<Vec<_>>();
|
||||
let mut iters: Vec<_> = ids.iter().map(&mut getter).collect::<Result<_>>()?;
|
||||
iters.rotate_right(1);
|
||||
Self {
|
||||
Ok(Self {
|
||||
inner: iters.pop().unwrap(),
|
||||
open_iterators: iters,
|
||||
path: PathBuf::new(),
|
||||
getter,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<IT, F> Iterator for TreeIterator<IT, F>
|
||||
where
|
||||
IT: Iterator<Item = Node>,
|
||||
F: FnMut(&Id) -> IT,
|
||||
F: FnMut(&Id) -> Result<IT>,
|
||||
{
|
||||
type Item = (PathBuf, Node);
|
||||
type Item = Result<(PathBuf, Node)>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
match self.inner.next() {
|
||||
Some(node) => {
|
||||
let path = self.path.join(node.name());
|
||||
if let Some(subtree) = node.subtree() {
|
||||
let old_inner = mem::replace(&mut self.inner, (self.getter)(subtree));
|
||||
if let Some(id) = node.subtree() {
|
||||
let old_inner = mem::replace(&mut self.inner, (self.getter)(id).unwrap());
|
||||
self.open_iterators.push(old_inner);
|
||||
self.path.push(node.name());
|
||||
}
|
||||
|
||||
return Some((path, node));
|
||||
return Some(Ok((path, node)));
|
||||
}
|
||||
None => match self.open_iterators.pop() {
|
||||
Some(it) => {
|
||||
|
||||
@ -46,7 +46,7 @@ impl<R: Read> Iterator for ChunkIter<R> {
|
||||
|
||||
let mut vec = Vec::new();
|
||||
let size = match (&mut self.reader)
|
||||
.take(self.min_size.try_into().unwrap())
|
||||
.take(self.min_size as u64)
|
||||
.read_to_end(&mut vec)
|
||||
{
|
||||
Ok(size) => size,
|
||||
|
||||
@ -80,7 +80,8 @@ fn check_snapshots(index: &impl IndexedBackend) -> Result<()> {
|
||||
.map(|id| Ok(SnapshotFile::from_backend(index.be(), &id)?.tree))
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
for (path, node) in tree_iterator_once(index, snap_ids) {
|
||||
for item in tree_iterator_once(index, snap_ids)? {
|
||||
let (path, node) = item?;
|
||||
match node.node_type() {
|
||||
NodeType::File => {
|
||||
for (i, id) in node.content().iter().enumerate() {
|
||||
|
||||
@ -36,11 +36,10 @@ pub(super) fn execute(be: &impl DecryptReadBackend, opts: Opts) -> Result<()> {
|
||||
|
||||
println!("reading index...");
|
||||
let index = IndexBackend::new(be)?;
|
||||
let iterator1 = tree_iterator(&index, vec![snap.tree])?.filter_map(Result::ok);
|
||||
let iterator2 = tree_iterator(&index, vec![snap_with.tree])?.filter_map(Result::ok);
|
||||
|
||||
for file in tree_iterator(&index, vec![snap.tree]).merge_join_by(
|
||||
tree_iterator(&index, vec![snap_with.tree]),
|
||||
|(path1, _), (path2, _)| path1.cmp(path2),
|
||||
) {
|
||||
for file in iterator1.merge_join_by(iterator2, |(path1, _), (path2, _)| path1.cmp(path2)) {
|
||||
match file {
|
||||
Left((path, _)) => println!("- {:?}", path),
|
||||
Right((path, _)) => println!("+ {:?}", path),
|
||||
|
||||
@ -23,7 +23,8 @@ pub(super) fn execute(be: &impl DecryptReadBackend, opts: Opts) -> Result<()> {
|
||||
let snap = SnapshotFile::from_backend(be, &id)?;
|
||||
let index = IndexBackend::new(be)?;
|
||||
|
||||
for (path, _) in tree_iterator(&index, vec![snap.tree]) {
|
||||
let tree_iter = tree_iterator(&index, vec![snap.tree])?.filter_map(Result::ok);
|
||||
for (path, _) in tree_iter {
|
||||
println!("{:?} ", path);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::Parser;
|
||||
use derive_getters::Dissolve;
|
||||
use itertools::{
|
||||
@ -68,10 +68,10 @@ fn allocate_and_collect(
|
||||
// collect dirs to delete as they need to be deleted in reverse order
|
||||
// let mut dirs_to_delete = Vec::new();
|
||||
|
||||
let tree_iter = tree_iterator(index, vec![tree])?.filter_map(Result::ok);
|
||||
|
||||
// walk over tree in repository and compare with tree in dest
|
||||
for file in
|
||||
tree_iterator(index, vec![tree]).merge_join_by(dest.walker(), |(path, _), j| path.cmp(j))
|
||||
{
|
||||
for file in tree_iter.merge_join_by(dest.walker(), |(path, _), j| path.cmp(j)) {
|
||||
match file {
|
||||
// node is only in snapshot
|
||||
Left((path, node)) => {
|
||||
@ -81,7 +81,7 @@ fn allocate_and_collect(
|
||||
}
|
||||
NodeType::File => {
|
||||
// collect blobs needed for restoring
|
||||
let size = file_infos.add_file(&node, path.clone(), index);
|
||||
let size = file_infos.add_file(&node, path.clone(), index)?;
|
||||
// create the file
|
||||
if !opts.dry_run {
|
||||
dest.create_file(&path, size);
|
||||
@ -148,7 +148,8 @@ fn restore_metadata(
|
||||
opts: &Opts,
|
||||
) -> Result<()> {
|
||||
// walk over tree in repository and compare with tree in dest
|
||||
for (path, node) in tree_iterator(index, vec![tree]) {
|
||||
let tree_iter = tree_iterator(index, vec![tree])?.filter_map(Result::ok);
|
||||
for (path, node) in tree_iter {
|
||||
if !opts.dry_run {
|
||||
if let NodeType::Symlink { linktarget } = node.node_type() {
|
||||
dest.create_symlink(&path, linktarget);
|
||||
@ -194,13 +195,15 @@ impl FileInfos {
|
||||
|
||||
/// Add the file to FilesInfos using index to get blob information.
|
||||
/// Returns the computed length of the file
|
||||
fn add_file(&mut self, file: &Node, name: PathBuf, index: &impl IndexedBackend) -> u64 {
|
||||
fn add_file(&mut self, file: &Node, name: PathBuf, index: &impl IndexedBackend) -> Result<u64> {
|
||||
let mut file_pos = 0;
|
||||
if !file.content().is_empty() {
|
||||
let file_idx = self.names.len();
|
||||
self.names.push(name);
|
||||
for id in file.content().iter() {
|
||||
let ie = index.get_id(id).unwrap();
|
||||
let ie = index
|
||||
.get_id(id)
|
||||
.ok_or(anyhow!("did not find id {} in index", id))?;
|
||||
let bl = BlobLocation {
|
||||
offset: *ie.offset(),
|
||||
length: *ie.length(),
|
||||
@ -216,6 +219,6 @@ impl FileInfos {
|
||||
file_pos += *ie.length() as u64 - 32; // blob crypto overhead
|
||||
}
|
||||
}
|
||||
file_pos
|
||||
Ok(file_pos)
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,9 +63,7 @@ const fn num_bits<T>() -> usize {
|
||||
|
||||
fn log_2(x: u32) -> u8 {
|
||||
assert!(x > 0);
|
||||
(num_bits::<u32>() as u32 - x.leading_zeros() - 1)
|
||||
.try_into()
|
||||
.unwrap()
|
||||
num_bits::<u32>() as u8 - x.leading_zeros() as u8 - 1
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user