diff --git a/crates/rustic_core/src/commands/backup.rs b/crates/rustic_core/src/commands/backup.rs
index 60474866b..8c9ed567e 100644
--- a/crates/rustic_core/src/commands/backup.rs
+++ b/crates/rustic_core/src/commands/backup.rs
@@ -12,8 +12,8 @@ use crate::{
backend::{dry_run::DryRunBackend, stdin::StdinSource},
repofile::SnapshotFile,
repository::{IndexedIds, IndexedTree},
- Id, LocalSource, LocalSourceFilterOptions, LocalSourceSaveOptions, Open, PathList,
- ProgressBars, Repository, RusticResult, SnapshotGroup, SnapshotGroupCriterion,
+ Id, LocalSource, LocalSourceFilterOptions, LocalSourceSaveOptions, PathList, ProgressBars,
+ Repository, RusticResult, SnapshotGroup, SnapshotGroupCriterion,
};
#[cfg_attr(feature = "clap", derive(clap::Parser))]
diff --git a/crates/rustic_core/src/commands/config.rs b/crates/rustic_core/src/commands/config.rs
index beb0c45ed..b15c67c37 100644
--- a/crates/rustic_core/src/commands/config.rs
+++ b/crates/rustic_core/src/commands/config.rs
@@ -6,7 +6,8 @@ use crate::{
backend::decrypt::{DecryptBackend, DecryptWriteBackend},
error::CommandErrorKind,
repofile::ConfigFile,
- Key, Open, Repository, RusticResult,
+ repository::Open,
+ Key, Repository, RusticResult,
};
pub(crate) fn apply_config
(
diff --git a/crates/rustic_core/src/commands/copy.rs b/crates/rustic_core/src/commands/copy.rs
index 3996bb337..13a86bdcd 100644
--- a/crates/rustic_core/src/commands/copy.rs
+++ b/crates/rustic_core/src/commands/copy.rs
@@ -8,8 +8,8 @@ use crate::{
blob::{packer::Packer, tree::TreeStreamerOnce, BlobType},
index::{indexer::Indexer, IndexedBackend, ReadIndex},
repofile::SnapshotFile,
- repository::{IndexedFull, IndexedIds, IndexedTree},
- Open, ProgressBars, Repository, RusticResult,
+ repository::{IndexedFull, IndexedIds, IndexedTree, Open},
+ ProgressBars, Repository, RusticResult,
};
#[derive(Debug)]
diff --git a/crates/rustic_core/src/commands/key.rs b/crates/rustic_core/src/commands/key.rs
index 8744a4c88..622f0cb60 100644
--- a/crates/rustic_core/src/commands/key.rs
+++ b/crates/rustic_core/src/commands/key.rs
@@ -6,7 +6,8 @@ use crate::{
crypto::hasher::hash,
error::CommandErrorKind,
repofile::KeyFile,
- Id, Key, Open, Repository, RusticResult,
+ repository::Open,
+ Id, Key, Repository, RusticResult,
};
#[cfg_attr(feature = "clap", derive(clap::Parser))]
diff --git a/crates/rustic_core/src/commands/merge.rs b/crates/rustic_core/src/commands/merge.rs
index be00d4136..f20861a77 100644
--- a/crates/rustic_core/src/commands/merge.rs
+++ b/crates/rustic_core/src/commands/merge.rs
@@ -15,7 +15,7 @@ use crate::{
index::{indexer::Indexer, ReadIndex},
repofile::{SnapshotFile, SnapshotSummary},
repository::IndexedTree,
- Id, Open, PathList, Progress, ProgressBars, Repository, RusticResult,
+ Id, PathList, Progress, ProgressBars, Repository, RusticResult,
};
pub(crate) fn merge_snapshots(
diff --git a/crates/rustic_core/src/commands/repair/index.rs b/crates/rustic_core/src/commands/repair/index.rs
index 9fea690c3..e16969974 100644
--- a/crates/rustic_core/src/commands/repair/index.rs
+++ b/crates/rustic_core/src/commands/repair/index.rs
@@ -12,7 +12,8 @@ use crate::{
error::CommandErrorKind,
index::indexer::Indexer,
repofile::{IndexFile, IndexPack, PackHeader, PackHeaderRef},
- Open, Progress, ProgressBars, Repository, RusticResult,
+ repository::Open,
+ Progress, ProgressBars, Repository, RusticResult,
};
#[cfg_attr(feature = "clap", derive(clap::Parser))]
diff --git a/crates/rustic_core/src/commands/repair/snapshots.rs b/crates/rustic_core/src/commands/repair/snapshots.rs
index e5849e7bc..ca3be11ec 100644
--- a/crates/rustic_core/src/commands/repair/snapshots.rs
+++ b/crates/rustic_core/src/commands/repair/snapshots.rs
@@ -10,7 +10,7 @@ use crate::{
index::{indexer::Indexer, IndexedBackend, ReadIndex},
repofile::SnapshotFile,
repository::{IndexedFull, IndexedTree},
- Id, Open, ProgressBars, Repository, RusticResult, StringList,
+ Id, ProgressBars, Repository, RusticResult, StringList,
};
#[cfg_attr(feature = "clap", derive(clap::Parser))]
diff --git a/crates/rustic_core/src/commands/restore.rs b/crates/rustic_core/src/commands/restore.rs
index b4db6f166..82a5f2a96 100644
--- a/crates/rustic_core/src/commands/restore.rs
+++ b/crates/rustic_core/src/commands/restore.rs
@@ -24,8 +24,8 @@ use crate::{
},
blob::BlobType,
error::CommandErrorKind,
- repository::{IndexedFull, IndexedTree},
- Id, LocalDestination, Open, Progress, ProgressBars, Repository, RusticResult,
+ repository::{IndexedFull, IndexedTree, Open},
+ Id, LocalDestination, Progress, ProgressBars, Repository, RusticResult,
};
pub(crate) mod constants {
diff --git a/crates/rustic_core/src/lib.rs b/crates/rustic_core/src/lib.rs
index 02e6f6f26..05c8af7bf 100644
--- a/crates/rustic_core/src/lib.rs
+++ b/crates/rustic_core/src/lib.rs
@@ -128,5 +128,5 @@ pub use crate::{
repofile::snapshotfile::{
PathList, SnapshotGroup, SnapshotGroupCriterion, SnapshotOptions, StringList,
},
- repository::{IndexedFull, Open, OpenStatus, Repository, RepositoryOptions},
+ repository::{IndexedFull, OpenStatus, Repository, RepositoryOptions},
};
diff --git a/crates/rustic_core/src/repofile/snapshotfile.rs b/crates/rustic_core/src/repofile/snapshotfile.rs
index 7e5d1faaf..e5ff67570 100644
--- a/crates/rustic_core/src/repofile/snapshotfile.rs
+++ b/crates/rustic_core/src/repofile/snapshotfile.rs
@@ -756,6 +756,7 @@ impl StringList {
self.0.join("\n")
}
+ /// Turn StringList into an Iterator
pub fn iter(&self) -> std::slice::Iter<'_, String> {
self.0.iter()
}
diff --git a/crates/rustic_core/src/repository.rs b/crates/rustic_core/src/repository.rs
index a74e31531..9f53e1960 100644
--- a/crates/rustic_core/src/repository.rs
+++ b/crates/rustic_core/src/repository.rs
@@ -65,6 +65,7 @@ use warm_up::{warm_up, warm_up_wait};
#[derive(Clone, Default, Debug, serde::Deserialize, Setters)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[setters(into, strip_option)]
+/// Options for using and opening a [`Repository`]
pub struct RepositoryOptions {
/// Repository to use
#[cfg_attr(
@@ -141,13 +142,19 @@ pub struct RepositoryOptions {
#[serde_as(as = "Option")]
pub warm_up_wait: Option,
+ /// Other options for this repository
#[cfg_attr(feature = "clap", clap(skip))]
#[cfg_attr(feature = "merge", merge(strategy = overwrite))]
pub options: HashMap,
}
-// TODO: Unused function
-#[allow(dead_code)]
+impl RepositoryOptions {
+ /// Create a [`Repository`] using the given repository options
+ pub fn to_repository(&self) -> RusticResult> {
+ Repository::new(self)
+ }
+}
+
pub(crate) fn overwrite(left: &mut T, right: T) {
*left = right;
}
@@ -188,22 +195,28 @@ pub fn read_password_from_reader(file: &mut impl BufRead) -> RusticResult {
+ /// The name of the repository
pub name: String,
- pub be: HotColdBackend,
- pub be_hot: Option,
+ pub(crate) be: HotColdBackend,
+ pub(crate) be_hot: Option,
opts: RepositoryOptions,
pub(crate) pb: P,
status: S,
}
impl Repository {
+ /// Create a new repository from the given [`RepositoryOptions`] (without progress bars)
pub fn new(opts: &RepositoryOptions) -> RusticResult {
Self::new_with_progress(opts, NoProgressBars {})
}
}
impl Repository
{
+ /// Create a new repository from the given [`RepositoryOptions`] with given progress bars
pub fn new_with_progress(opts: &RepositoryOptions, pb: P) -> RusticResult {
let be = match &opts.repository {
Some(repo) => ChooseBackend::from_url(repo)?,
@@ -244,6 +257,7 @@ impl Repository
{
}
}
impl
Repository
{
+ /// Evaluates the password given by the repository options
pub fn password(&self) -> RusticResult> {
match (
&self.opts.password,
@@ -291,6 +305,7 @@ impl Repository
{
}
}
+ /// Gives the id of the config file
pub fn config_id(&self) -> RusticResult> {
let config_ids = self
.be
@@ -304,6 +319,9 @@ impl Repository
{
}
}
+ /// Open the repository.
+ ///
+ /// This gets the decryption key and reads the config file
pub fn open(self) -> RusticResult> {
let password = self
.password()?
@@ -311,6 +329,9 @@ impl Repository
{
self.open_with_password(&password)
}
+ /// Open the repository with a given password.
+ ///
+ /// This gets the decryption key and reads the config file
pub fn open_with_password(self, password: &str) -> RusticResult> {
let config_id = self
.config_id()?
@@ -342,6 +363,9 @@ impl Repository
{
self.open_raw(key, config)
}
+ /// Initialize a new repository with given options using the password defined in `RepositoryOptions`
+ ///
+ /// This returns an open repository which can be directly used.
pub fn init(
self,
key_opts: &KeyOptions,
@@ -353,6 +377,9 @@ impl
Repository
{
self.init_with_password(&password, key_opts, config_opts)
}
+ /// Initialize a new repository with given password and options.
+ ///
+ /// This returns an open repository which can be directly used.
pub fn init_with_password(
self,
pass: &str,
@@ -366,13 +393,16 @@ impl
Repository
{
self.open_raw(key, config)
}
+ /// Initialize a new repository with given password and a ready [`ConfigFile`].
+ ///
+ /// This returns an open repository which can be directly used.
pub fn init_with_config(
self,
- pass: &str,
+ password: &str,
key_opts: &KeyOptions,
config: ConfigFile,
) -> RusticResult> {
- let key = commands::init::init_with_config(&self, pass, key_opts, &config)?;
+ let key = commands::init::init_with_config(&self, password, key_opts, &config)?;
info!("repository {} successfully created.", config.id);
self.open_raw(key, config)
}
@@ -412,19 +442,24 @@ impl Repository
{
})
}
+ /// List all file [`Id`]s of the given [`FileType`] which are present in the repository
pub fn list(&self, tpe: FileType) -> RusticResult> {
Ok(self.be.list(tpe)?.into_iter())
}
}
impl Repository {
+ /// Collect information about repository files
pub fn infos_files(&self) -> RusticResult {
commands::repoinfo::collect_file_infos(self)
}
+
+ /// Warm up the given pack files without waiting.
pub fn warm_up(&self, packs: impl ExactSizeIterator- ) -> RusticResult<()> {
warm_up(self, packs)
}
+ /// Warm up the given pack files and wait the configured waiting time.
pub fn warm_up_wait(&self, packs: impl ExactSizeIterator
- ) -> RusticResult<()> {
warm_up_wait(self, packs)
}
@@ -455,6 +490,7 @@ impl
Open for Repository
{
}
#[derive(Debug)]
+/// Open Status: This repository is open, i.e. the password has been checked and the decryption key is available.
pub struct OpenStatus {
key: Key,
cache: Option,
@@ -480,20 +516,36 @@ impl Open for OpenStatus {
}
impl Repository
{
+ /// Get the content of the decrypted repository file given by id and [`FileType`]
pub fn cat_file(&self, tpe: FileType, id: &str) -> RusticResult {
commands::cat::cat_file(self, tpe, id)
}
+ /// Add a new key to the repository
pub fn add_key(&self, pass: &str, opts: &KeyOptions) -> RusticResult {
opts.add_key(self, pass)
}
+ /// Update the repository config by applying the given [`ConfigOptions`]
pub fn apply_config(&self, opts: &ConfigOptions) -> RusticResult {
commands::config::apply_config(self, opts)
}
+
+ /// Get the repository configuration
+ pub fn config(&self) -> &ConfigFile {
+ self.status.config()
+ }
+
+ pub(crate) fn dbe(&self) -> &S::DBE {
+ self.status.dbe()
+ }
}
impl Repository {
+ /// Get grouped snapshots.
+ ///
+ /// If `ids` are given, this will try to resolve the ids (or `latest` with respect to the given filter) and return a single group
+ /// If `ids` is empty, return and group all snapshots respecting the filter.
pub fn get_snapshot_group(
&self,
ids: &[String],
@@ -503,6 +555,10 @@ impl Repository {
commands::snapshots::get_snapshot_group(self, ids, group_by, filter)
}
+ /// Get a single snapshot
+ ///
+ /// If `id` is (part of) an `Id`, return this snapshot.
+ /// If `id` is "latest", return the latest snapshot respecting the giving filter.
pub fn get_snapshot_from_str(
&self,
id: &str,
@@ -513,15 +569,21 @@ impl Repository {
Ok(snap)
}
+ /// Get the given snapshots.
+ ///
+ /// `ids` may contain part of snapshots id which will be resolved. However, "latest" is not supported in
+ /// this function.
pub fn get_snapshots>(&self, ids: &[T]) -> RusticResult> {
let p = self.pb.progress_counter("getting snapshots...");
SnapshotFile::from_ids(self.dbe(), ids, &p)
}
+ /// Get all snapshots from the repository
pub fn get_all_snapshots(&self) -> RusticResult> {
self.get_matching_snapshots(|_| true)
}
+ /// Get all snapshots from the repository respecting the given `filter`
pub fn get_matching_snapshots(
&self,
filter: impl FnMut(&SnapshotFile) -> bool,
@@ -530,6 +592,7 @@ impl Repository {
SnapshotFile::all_from_backend(self.dbe(), filter, &p)
}
+ /// Get snapshots to forget depending on the given [`KeepOptions`]
pub fn get_forget_snapshots(
&self,
keep: &KeepOptions,
@@ -539,6 +602,9 @@ impl Repository {
commands::forget::get_forget_snapshots(self, keep, group_by, filter)
}
+ /// Get snapshots which are not already present and should be present.
+ ///
+ /// Note: This method should be called on the *destination repository*
pub fn relevant_copy_snapshots(
&self,
filter: impl FnMut(&SnapshotFile) -> bool,
@@ -549,6 +615,7 @@ impl Repository {
// TODO: Maybe only offer a method to remove &[Snapshotfile] and check if they must be kept.
// See e.g. the merge command of the CLI
+ /// Remove the given snapshots from the repository
pub fn delete_snapshots(&self, ids: &[Id]) -> RusticResult<()> {
let p = self.pb.progress_counter("removing snapshots...");
self.dbe()
@@ -556,6 +623,7 @@ impl Repository {
Ok(())
}
+ /// Save the given snapshots to the repository.
pub fn save_snapshots(&self, mut snaps: Vec) -> RusticResult<()> {
for snap in &mut snaps {
snap.id = Id::default();
@@ -565,14 +633,19 @@ impl Repository {
Ok(())
}
+ /// Check the repository for errors or inconsistencies
pub fn check(&self, opts: CheckOptions) -> RusticResult<()> {
opts.run(self)
}
+ /// Get the plan about what should be pruned and/or repacked.
pub fn prune_plan(&self, opts: &PruneOptions) -> RusticResult {
opts.get_plan(self)
}
+ /// Turn the repository into the `IndexedFull` state by reading and storing the index
+ ///
+ /// This saves the full index in memory which can be quite memory-consuming!
pub fn to_indexed(self) -> RusticResult>> {
let index = IndexBackend::new(self.dbe(), &self.pb.progress_counter(""))?;
let status = IndexedStatus {
@@ -590,6 +663,10 @@ impl Repository {
})
}
+ /// Turn the repository into the `IndexedIds` state by reading and storing a size-optimized index
+ ///
+ /// This saves only the `Id`s for data blobs. Therefore, not all operations are possible on the repository.
+ /// However, operations which add data are fully functional.
pub fn to_indexed_ids(self) -> RusticResult>> {
let index = IndexBackend::only_full_trees(self.dbe(), &self.pb.progress_counter(""))?;
let status = IndexedStatus {
@@ -607,10 +684,14 @@ impl Repository {
})
}
+ /// Get statistical information from the index
+ ///
+ /// This method reads all index files, even if an index is already available in memory.
pub fn infos_index(&self) -> RusticResult {
commands::repoinfo::collect_index_infos(self)
}
+ /// Read all files of a given [`RepoFile`]
pub fn stream_files(
&self,
) -> RusticResult>> {
@@ -620,6 +701,10 @@ impl Repository {
.into_iter())
}
+ /// Repair the index
+ ///
+ /// This compares the index with existing pack files and reads packfile headers to ensure the index
+ /// correctly represents the pack files.
pub fn repair_index(&self, opts: &RepairIndexOptions, dry_run: bool) -> RusticResult<()> {
opts.repair(self, dry_run)
}
@@ -630,7 +715,9 @@ pub trait IndexedTree: Open {
fn index(&self) -> &Self::I;
}
+/// Repository is fully indexed
pub trait IndexedIds: IndexedTree {}
+/// Repository is fully indexed
pub trait IndexedFull: IndexedIds {}
impl
IndexedTree for Repository
{
@@ -682,6 +769,7 @@ impl Open for IndexedStatus {
}
impl Repository
{
+ /// Get the index entry of the given blob
pub fn get_index_entry(&self, tpe: BlobType, id: &Id) -> RusticResult {
let ie = self
.index()
@@ -692,6 +780,9 @@ impl Repository
{
}
impl Repository {
+ /// Get a [`Node`] from a "SNAP\[:PATH\]" syntax
+ ///
+ /// This parses for a snapshot (using the filter when "latest" is used) and then traverses into the path to get the node.
pub fn node_from_snapshot_path(
&self,
snap_path: &str,
@@ -705,6 +796,9 @@ impl Repository {
Tree::node_from_path(self.index(), snap.tree, Path::new(path))
}
+ /// Get a [`Node`] from a [`SnapshotFile`] and a `path`
+ ///
+ /// This traverses into the path to get the node.
pub fn node_from_snapshot_and_path(
&self,
snap: &SnapshotFile,
@@ -713,6 +807,9 @@ impl Repository {
Tree::node_from_path(self.index(), snap.tree, Path::new(path))
}
+ /// Reads a raw tree from a "SNAP\[:PATH\]" syntax
+ ///
+ /// This parses for a snapshot (using the filter when "latest" is used) and then traverses into the path to get the tree.
pub fn cat_tree(
&self,
snap: &str,
@@ -721,6 +818,11 @@ impl Repository {
commands::cat::cat_tree(self, snap, sn_filter)
}
+ /// List the contents of a given [`Node`]
+ ///
+ /// If `node` is a tree node, this will list the content of that tree.
+ /// If `node` is a file node, this will only return one element.
+ /// Note that the `PathBuf` returned will be relative to the given 'node`.
pub fn ls(
&self,
node: &Node,
@@ -729,6 +831,7 @@ impl Repository {
NodeStreamer::new_with_glob(self.index().clone(), node, ls_opts)
}
+ /// Restore a given [`RestorePlan`] to a local destination
pub fn restore(
&self,
restore_infos: RestorePlan,
@@ -739,6 +842,11 @@ impl Repository {
opts.restore(restore_infos, self, node_streamer, dest)
}
+ /// Merge the given trees.
+ ///
+ /// This method creates needed tree blobs within the repository.
+ /// Merge conflicts (identical filenames which do not match) will be resolved using the ordering given by `cmp`.
+ /// This method returns the blob [`Id`] of the merged tree.
pub fn merge_trees(
&self,
trees: &[Id],
@@ -748,6 +856,11 @@ impl Repository {
commands::merge::merge_trees(self, trees, cmp, summary)
}
+ /// Merge the given snapshots.
+ ///
+ /// This method will create needed tree blobs within the repository.
+ /// Merge conflicts (identical filenames which do not match) will be resolved using the ordering given by `cmp`.
+ /// This method returns the modified and already saved [`SnapshotFile`].
pub fn merge_snapshots(
&self,
snaps: &[SnapshotFile],
@@ -759,6 +872,10 @@ impl Repository {
}
impl Repository {
+ /// Run a backup of `source` using the given options.
+ ///
+ /// You have to give a preflled [`SnapshotFile`] which is modified and saved.
+ /// Returns the saved snapshot.
pub fn backup(
&self,
opts: &BackupOptions,
@@ -770,10 +887,14 @@ impl Repository {
}
impl Repository {
+ /// Read a raw blob
pub fn cat_blob(&self, tpe: BlobType, id: &str) -> RusticResult {
commands::cat::cat_blob(self, tpe, id)
}
+ /// Dump a [`Node`] using the given writer.
+ ///
+ /// Currently, only regular file nodes are supported.
pub fn dump(&self, node: &Node, w: &mut impl Write) -> RusticResult<()> {
commands::dump::dump(self, node, w)
}
@@ -804,6 +925,10 @@ impl Repository {
commands::copy::copy(self, repo_dest, snapshots)
}
+ /// Repair snapshots.
+ ///
+ /// This traverses all trees of all snapshots and repairs defect trees.
+ /// WARNING: If you remove the original snapshots, you may loose data!
pub fn repair_snapshots(
&self,
opts: &RepairSnapshotsOptions,
diff --git a/src/commands/copy.rs b/src/commands/copy.rs
index 6c421d7bd..fc6b1fc86 100644
--- a/src/commands/copy.rs
+++ b/src/commands/copy.rs
@@ -12,7 +12,7 @@ use log::{error, info};
use merge::Merge;
use serde::Deserialize;
-use rustic_core::{CopySnapshot, Id, KeyOptions, Open, Repository, RepositoryOptions};
+use rustic_core::{CopySnapshot, Id, KeyOptions, Repository, RepositoryOptions};
/// `copy` subcommand
#[derive(clap::Parser, Command, Debug)]