diff --git a/crates/rustic_core/src/commands.rs b/crates/rustic_core/src/commands.rs
index f1720ec51..f450b03a4 100644
--- a/crates/rustic_core/src/commands.rs
+++ b/crates/rustic_core/src/commands.rs
@@ -1,5 +1,6 @@
pub mod cat;
pub mod check;
+pub mod dump;
pub mod forget;
pub mod prune;
pub mod repoinfo;
diff --git a/crates/rustic_core/src/commands/dump.rs b/crates/rustic_core/src/commands/dump.rs
new file mode 100644
index 000000000..374f24f57
--- /dev/null
+++ b/crates/rustic_core/src/commands/dump.rs
@@ -0,0 +1,23 @@
+use std::io::Write;
+
+use crate::{
+ error::CommandErrorKind, repository::IndexedRepository, BlobType, IndexedBackend, Node,
+ NodeType, RusticResult,
+};
+
+pub(crate) fn dump
(
+ repo: &IndexedRepository
,
+ node: &Node,
+ w: &mut impl Write,
+) -> RusticResult<()> {
+ if node.node_type != NodeType::File {
+ return Err(CommandErrorKind::DumpNotSupported(node.node_type.clone()).into());
+ }
+
+ for id in node.content.as_ref().unwrap() {
+ // TODO: cache blobs which are needed later
+ let data = repo.index.blob_from_backend(BlobType::Data, id)?;
+ w.write_all(&data)?;
+ }
+ Ok(())
+}
diff --git a/crates/rustic_core/src/error.rs b/crates/rustic_core/src/error.rs
index a37386107..13be3e151 100644
--- a/crates/rustic_core/src/error.rs
+++ b/crates/rustic_core/src/error.rs
@@ -21,7 +21,7 @@ use chrono::OutOfRangeError;
use displaydoc::Display;
use thiserror::Error;
-use crate::{id::Id, repofile::indexfile::IndexPack};
+use crate::{id::Id, repofile::indexfile::IndexPack, NodeType};
/// Result type often returned from methods that can have rustic `Error`s.
pub type RusticResult = Result;
@@ -160,6 +160,8 @@ pub enum CommandErrorKind {
RepackUncompressedRepoV1,
/// datetime out of range: `{0:?}`
FromOutOfRangeError(#[from] OutOfRangeError),
+ /// node type {0:?} not supported by dump
+ DumpNotSupported(NodeType),
}
/// [`CryptoErrorKind`] describes the errors that can happen while dealing with Cryptographic functions
diff --git a/crates/rustic_core/src/repository.rs b/crates/rustic_core/src/repository.rs
index fd24a9c0c..4080ee1ce 100644
--- a/crates/rustic_core/src/repository.rs
+++ b/crates/rustic_core/src/repository.rs
@@ -1,8 +1,8 @@
use std::{
collections::HashMap,
fs::File,
- io::{BufRead, BufReader},
- path::PathBuf,
+ io::{BufRead, BufReader, Write},
+ path::{Path, PathBuf},
process::{Command, Stdio},
};
@@ -37,8 +37,8 @@ use crate::{
crypto::aespoly1305::Key,
error::RepositoryErrorKind,
repofile::{configfile::ConfigFile, keyfile::find_key_in_backend},
- BlobType, Id, IndexBackend, NoProgressBars, ProgressBars, PruneOpts, PrunePlan, RusticResult,
- SnapshotFile, SnapshotGroup, SnapshotGroupCriterion,
+ BlobType, Id, IndexBackend, NoProgressBars, Node, ProgressBars, PruneOpts, PrunePlan,
+ RusticResult, SnapshotFile, SnapshotGroup, SnapshotGroupCriterion, Tree,
};
pub(super) mod constants {
@@ -448,9 +448,23 @@ pub struct IndexedRepository {
}
impl IndexedRepository {
+ pub fn node_from_snapshot_path(
+ &self,
+ snap_path: &str,
+ filter: impl FnMut(&SnapshotFile) -> bool + Send + Sync,
+ ) -> RusticResult {
+ let (id, path) = snap_path.split_once(':').unwrap_or((snap_path, ""));
+
+ let p = &self.repo.pb.progress_counter("getting snapshot...");
+ let snap = SnapshotFile::from_str(&self.repo.dbe, id, filter, p)?;
+
+ Tree::node_from_path(&self.index, snap.tree, Path::new(path))
+ }
+
pub fn cat_blob(&self, tpe: BlobType, id: &str) -> RusticResult {
commands::cat::cat_blob(self, tpe, id)
}
+
pub fn cat_tree(
&self,
snap: &str,
@@ -458,4 +472,8 @@ impl IndexedRepository {
) -> RusticResult {
commands::cat::cat_tree(self, snap, sn_filter)
}
+
+ pub fn dump(&self, node: &Node, w: &mut impl Write) -> RusticResult<()> {
+ commands::dump::dump(self, node, w)
+ }
}
diff --git a/src/commands/dump.rs b/src/commands/dump.rs
index e478cd112..451dd9142 100644
--- a/src/commands/dump.rs
+++ b/src/commands/dump.rs
@@ -2,19 +2,10 @@
/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()`
/// accessors along with logging macros. Customize as you see fit.
-use crate::{
- commands::{get_repository, open_repository},
- status_err, Application, RUSTIC_APP,
-};
+use crate::{commands::get_repository, status_err, Application, RUSTIC_APP};
use abscissa_core::{Command, Runnable, Shutdown};
-use anyhow::{bail, Result};
-
-use std::{io::Write, path::Path};
-
-use rustic_core::{
- BlobType, IndexBackend, IndexedBackend, NodeType, ProgressBars, SnapshotFile, Tree,
-};
+use anyhow::Result;
/// `dump` subcommand
#[derive(clap::Parser, Command, Debug)]
@@ -37,31 +28,12 @@ impl DumpCmd {
fn inner_run(&self) -> Result<()> {
let config = RUSTIC_APP.config();
- let repo = open_repository(get_repository(&config));
-
- let be = &repo.dbe;
- let progress_options = &config.global.progress_options;
-
- let (id, path) = self.snap.split_once(':').unwrap_or((&self.snap, ""));
- let snap = SnapshotFile::from_str(
- be,
- id,
- |sn| config.snapshot_filter.matches(sn),
- &progress_options.progress_counter(""),
- )?;
- let index = IndexBackend::new(be, &progress_options.progress_counter(""))?;
- let node = Tree::node_from_path(&index, snap.tree, Path::new(path))?;
-
- if node.node_type != NodeType::File {
- bail!("dump only supports regular files!");
- }
+ let repo = get_repository(&config).open()?.to_indexed()?;
+ let node =
+ repo.node_from_snapshot_path(&self.snap, |sn| config.snapshot_filter.matches(sn))?;
let mut stdout = std::io::stdout();
- for id in node.content.unwrap() {
- // TODO: cache blobs which are needed later
- let data = index.blob_from_backend(BlobType::Data, &id)?;
- stdout.write_all(&data)?;
- }
+ repo.dump(&node, &mut stdout)?;
Ok(())
}