### Initialize a new repository with rustic_core Source: https://github.com/rustic-rs/rustic_core/blob/main/crates/core/README.md This example demonstrates how to initialize a new backup repository using rustic_core. It sets up logging, defines backend options, and configures repository, key, and configuration options before creating the repository. Ensure you have the necessary dependencies and features enabled. ```rust use rustic_backend::BackendOptions; use rustic_core::{ConfigOptions, KeyOptions, Repository, RepositoryOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; fn main() -> Result<(), Box> { // Display info logs let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); // Initialize Backends let backends = BackendOptions::default() .repository("/tmp/repo") .to_backends()?; // Init repository let repo_opts = RepositoryOptions::default().password("test"); let key_opts = KeyOptions::default(); let config_opts = ConfigOptions::default(); let _repo = Repository::new(&repo_opts, backends)?.init(&key_opts, &config_opts)?; // -> use _repo for any operation on an open repository Ok(()) } ``` -------------------------------- ### Check Repository Integrity Source: https://github.com/rustic-rs/rustic_core/blob/main/crates/core/README.md Initializes backends, opens a repository, and performs a check operation. This example specifically enables trust cache checks. ```rust use rustic_backend::BackendOptions; use rustic_core::{CheckOptions, Repository, RepositoryOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; fn main() -> Result<(), Box> { // Display info logs let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); // Initialize Backends let backends = BackendOptions::default() .repository("/tmp/repo") .to_backends()?; // Open repository let repo_opts = RepositoryOptions::default().password("test"); let repo = Repository::new(&repo_opts, backends)?.open()?; // Check repository with standard options but omitting cache checks let opts = CheckOptions::default().trust_cache(true); repo.check(opts)?; Ok(()) } ``` -------------------------------- ### Initialize a new repository Source: https://github.com/rustic-rs/rustic_core/blob/main/README.md Demonstrates how to initialize a new repository using BackendOptions and Repository configuration. ```rust use rustic_backend::BackendOptions; use rustic_core::{ConfigOptions, KeyOptions, Repository, RepositoryOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; fn main() -> Result<(), Box> { // Display info logs let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); // Initialize Backends let backends = BackendOptions::default() .repository("/tmp/repo") .to_backends()?; // Init repository let repo_opts = RepositoryOptions::default().password("test"); let key_opts = KeyOptions::default(); let config_opts = ConfigOptions::default(); let _repo = Repository::new(&repo_opts, &backends)?.init(&key_opts, &config_opts)?; // -> use _repo for any operation on an open repository Ok(()) } ``` -------------------------------- ### Create a New Snapshot Source: https://github.com/rustic-rs/rustic_core/blob/main/crates/core/README.md Initializes backends, opens a repository, and creates a new snapshot with specified tags. Ensure the repository path and password are set correctly. ```rust use rustic_backend::BackendOptions; use rustic_core::{BackupOptions, PathList, Repository, RepositoryOptions, SnapshotOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; fn main() -> Result<(), Box> { // Display info logs let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); // Initialize Backends let backends = BackendOptions::default() .repository("/tmp/repo") .repo_hot("/tmp/repo2") .to_backends()?; // Open repository let repo_opts = RepositoryOptions::default().password("test"); let repo = Repository::new(&repo_opts, backends)? .open()?; .to_indexed_ids()?; let backup_opts = BackupOptions::default(); let source = PathList::from_string(".")?.sanitize()?; let snap = SnapshotOptions::default() .add_tags("tag1,tag2")?; .to_snapshot()?; // Create snapshot let snap = repo.backup(&backup_opts, &source, snap)?; println!("successfully created snapshot:\n{snap:#?}"); Ok(()) } ``` -------------------------------- ### Initialize New Repository Source: https://context7.com/rustic-rs/rustic_core/llms.txt Creates a new encrypted backup repository. Ensure the master key is saved securely for recovery. Requires backend configuration and options for encryption and compression. ```rust use rustic_backend::BackendOptions; use rustic_core::{ repofile::MasterKey, ConfigOptions, Credentials, KeyOptions, Repository, RepositoryOptions, }; fn main() -> Result<(), Box> { // Initialize backends pointing to local directory let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; // Create repository options (can configure caching, warm-up, etc.) let repo_opts = RepositoryOptions::default(); // Key options for encryption (cost parameters, etc.) let key_opts = KeyOptions::default(); // Config options (compression level, version, pack sizes) let config_opts = ConfigOptions::default(); // Initialize repository with a new master key // IMPORTANT: Save this master key securely - it's needed for recovery! let repo = Repository::new(&repo_opts, &backends)?.init( &Credentials::Masterkey(MasterKey::new()), &key_opts, &config_opts, )?; println!("Repository initialized with ID: {}", repo.config().id); Ok(()) } ``` -------------------------------- ### Create a new snapshot in Rust Source: https://github.com/rustic-rs/rustic_core/blob/main/README.md Initializes a repository backend and performs a backup of a specified path with custom tags. ```rust use rustic_backend::BackendOptions; use rustic_core::{BackupOptions, PathList, Repository, RepositoryOptions, SnapshotOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; fn main() -> Result<(), Box> { // Display info logs let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); // Initialize Backends let backends = BackendOptions::default() .repository("/tmp/repo") .repo_hot("/tmp/repo2") .to_backends()?; // Open repository let repo_opts = RepositoryOptions::default().password("test"); let repo = Repository::new(&repo_opts, &backends)? .open()? .to_indexed_ids()?; let backup_opts = BackupOptions::default(); let source = PathList::from_string(".")?.sanitize()?; let snap = SnapshotOptions::default() .add_tags("tag1,tag2")? .to_snapshot()?; // Create snapshot let snap = repo.backup(&backup_opts, &source, snap)?; println!("successfully created snapshot:\n{snap:#?}"); Ok(()) } ``` -------------------------------- ### Open Existing Repository Source: https://context7.com/rustic-rs/rustic_core/llms.txt Opens an existing repository using password-based authentication. The repository must be transitioned to an indexed state before performing backup or restore operations. ```rust use rustic_backend::BackendOptions; use rustic_core::{Credentials, Repository, RepositoryOptions}; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo_opts = RepositoryOptions::default(); let credentials = Credentials::password("my_secret_password"); // Open repository - returns Repository let repo = Repository::new(&repo_opts, &backends)?.open(&credentials)?; // Get repository configuration println!("Repository ID: {}", repo.config().id); println!("Repository version: {}", repo.config().version); // For backup operations, transition to IndexedIds state (memory efficient) let indexed_repo = repo.to_indexed_ids()?; // For restore/read operations, transition to IndexedFull state // let indexed_repo = repo.to_indexed()?; Ok(()) } ``` -------------------------------- ### Create Backup Snapshot Source: https://context7.com/rustic-rs/rustic_core/llms.txt Creates a new snapshot by backing up specified source paths. Supports tags, hostname filtering, and parent snapshot detection for incremental backups. Requires the repository to be in the IndexedIds state. ```rust use rustic_backend::BackendOptions; use rustic_core::{ BackupOptions, Credentials, PathList, Repository, RepositoryOptions, SnapshotOptions, }; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))? .to_indexed_ids()?; // IndexedIds state required for backup // Configure backup options let backup_opts = BackupOptions::default(); // Define source paths to backup let source = PathList::from_string("/home/user/documents")?.sanitize()?; // Create snapshot with metadata let snap = SnapshotOptions::default() .add_tags("daily,important")? // Comma-separated tags .host("my-laptop".to_string()) // Override hostname .to_snapshot()?; // Run the backup let snapshot = repo.backup(&backup_opts, &source, snap)?; println!("Backup complete!"); println!("Snapshot ID: {}", snapshot.id); println!("Files new: {}", snapshot.summary.as_ref().unwrap().files_new); println!("Data added: {} bytes", snapshot.summary.as_ref().unwrap().data_added); Ok(()) } ``` -------------------------------- ### Restore a Snapshot Source: https://github.com/rustic-rs/rustic_core/blob/main/crates/core/README.md Opens a repository, selects the latest snapshot, lists its contents, and restores them to a specified local directory. The destination directory will be created if it does not exist. ```rust use rustic_backend::BackendOptions; use rustic_core::{LocalDestination, LsOptions, Repository, RepositoryOptions, RestoreOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; fn main() -> Result<(), Box> { // Display info logs let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); // Initialize Backends let backends = BackendOptions::default() .repository("/tmp/repo") .to_backends()?; // Open repository let repo_opts = RepositoryOptions::default().password("test"); let repo = Repository::new(&repo_opts, backends)? .open()?; .to_indexed()?; // use latest snapshot without filtering snapshots let node = repo.node_from_snapshot_path("latest", |_| true)?; // use list of the snapshot contents using no additional filtering let streamer_opts = LsOptions::default(); let ls = repo.ls(&node, &streamer_opts)?; let destination = "./restore/"; // restore to this destination dir let create = true; // create destination dir, if it doesn't exist let dest = LocalDestination::new(destination, create, !node.is_dir())?; let opts = RestoreOptions::default(); let dry_run = false; // create restore infos. Note: this also already creates needed dirs in the destination let restore_infos = repo.prepare_restore(&opts, ls.clone(), &dest, dry_run)?; repo.restore(restore_infos, &opts, ls, &dest)?; Ok(()) } ``` -------------------------------- ### Add rustic_backend to Cargo.toml Source: https://github.com/rustic-rs/rustic_core/blob/main/crates/backend/README.md Include this dependency in your Cargo.toml file to use the rustic_backend crate. ```toml [dependencies] rustic_backend = "*" ``` -------------------------------- ### Configure Storage Backends in Rust Source: https://context7.com/rustic-rs/rustic_core/llms.txt Configure various storage backends including local, REST, rclone, and OpenDAL. Supports hot/cold storage separation for metadata and data. ```rust use rustic_backend::BackendOptions; use rustic_core::{Credentials, Repository, RepositoryOptions}; use std::collections::BTreeMap; fn main() -> Result<(), Box> { // Local backend let local_backends = BackendOptions::default() .repository("/path/to/local/repo") .to_backends()?; // REST backend (restic REST server) let rest_backends = BackendOptions::default() .repository("rest:https://user:pass@backup.example.com/repo") .to_backends()?; // Rclone backend (uses rclone remote configuration) let rclone_backends = BackendOptions::default() .repository("rclone:myremote:backup/repo") .to_backends()?; // OpenDAL backend with options (S3 example) let mut s3_options = BTreeMap::new(); s3_options.insert("access_key_id".to_string(), "YOUR_ACCESS_KEY".to_string()); s3_options.insert("secret_access_key".to_string(), "YOUR_SECRET_KEY".to_string()); let s3_backends = BackendOptions::default() .repository("opendal:s3:bucket_name/path/to/repo") .options(s3_options) .to_backends()?; // Hot/Cold repository setup (hot for metadata, cold for data) let hotcold_backends = BackendOptions::default() .repository("/path/to/cold/storage") // Cold: main data storage .repo_hot("/path/to/hot/storage") // Hot: frequently accessed metadata .to_backends()?; // Use any backend with Repository let repo = Repository::new(&RepositoryOptions::default(), &local_backends)? .open(&Credentials::password("test"))?; Ok(()) } ``` -------------------------------- ### Configure Repository Settings in Rust Source: https://context7.com/rustic-rs/rustic_core/llms.txt Use ConfigOptions to modify repository parameters like compression levels. The apply_config method returns a boolean indicating if changes were actually applied. ```rust use rustic_backend::BackendOptions; use rustic_core::{ max_compression_level, ConfigOptions, Credentials, Repository, RepositoryOptions, }; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let mut repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))?; // Display current config println!("Current compression: {:?}", repo.config().compression); // Update configuration let config_opts = ConfigOptions::default() .set_compression(max_compression_level()); // Maximum zstd compression let changed = repo.apply_config(&config_opts)?; if changed { println!("Configuration updated!"); println!("New compression level: {:?}", repo.config().compression); } else { println!("No configuration changes needed"); } Ok(()) } ``` -------------------------------- ### Retrieve Repository Statistics in Rust Source: https://context7.com/rustic-rs/rustic_core/llms.txt Access repository file information and index statistics using infos_files and infos_index methods. ```rust use rustic_backend::BackendOptions; use rustic_core::{Credentials, Repository, RepositoryOptions}; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))?; // Get file information (pack files, keys, snapshots, index files) let file_infos = repo.infos_files()?; for info in file_infos.files { println!("{:?}: {} files, {} bytes", info.file_type, info.count, info.size); } // Get index information (blob statistics) let index_infos = repo.infos_index()?; println!("\nIndex Statistics:"); println!(" Tree blobs: {} ({} bytes)", index_infos.tree.count, index_infos.tree.size); println!(" Data blobs: {} ({} bytes)", index_infos.data.count, index_infos.data.size); println!(" Total packs: {}", index_infos.packs); Ok(()) } ``` -------------------------------- ### Add rustic_core to Cargo.toml Source: https://github.com/rustic-rs/rustic_core/blob/main/crates/core/README.md Include the rustic_core crate as a dependency in your project's Cargo.toml file. ```toml [ dependencies] rustic_core = "*" ``` -------------------------------- ### List Snapshot Contents in Rust Source: https://context7.com/rustic-rs/rustic_core/llms.txt Lists files and directories within a snapshot, requiring an indexed repository state. ```rust use rustic_backend::BackendOptions; use rustic_core::{Credentials, LsOptions, Repository, RepositoryOptions}; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))? .to_indexed()?; // IndexedFull state required for ls // Get node from snapshot path (supports "latest" or snapshot ID) // Can also specify subpath: "latest:/subdir/path" let node = repo.node_from_snapshot_path("latest", |_| true)?; // List contents with default options (recursive) let ls_opts = LsOptions::default(); for item in repo.ls(&node, &ls_opts)? { let (path, node) = item?; let node_type = if node.is_dir() { "DIR " } else { "FILE" }; let size = node.meta.size; println!("{} {:>10} {}", node_type, size, path.display()); } Ok(()) } ``` -------------------------------- ### Copy Snapshots Between Repositories Source: https://context7.com/rustic-rs/rustic_core/llms.txt Copies snapshots from a source repository to a destination repository. Useful for offsite backups or migrating repository data. Ensure both repositories are opened with appropriate credentials and options. ```rust use rustic_backend::BackendOptions; use rustic_core::{CopySnapshot, Credentials, Repository, RepositoryOptions}; fn main() -> Result<(), Box> { // Source repository let src_backends = BackendOptions::default() .repository("/tmp/source_repo") .to_backends()?; let credentials = Credentials::password("test"); let src_repo = Repository::new(&RepositoryOptions::default(), &src_backends)? .open(&credentials)? .to_indexed()?; // IndexedFull for reading // Destination repository let dst_backends = BackendOptions::default() .repository("/tmp/dest_repo") .to_backends()?; let dst_repo = Repository::new(&RepositoryOptions::default(), &dst_backends)? .open(&credentials)? .to_indexed_ids()?; // IndexedIds for writing // Get all snapshots from source let snapshots = src_repo.get_all_snapshots()?; // Find which snapshots need to be copied (not already in dest) let copy_snapshots = dst_repo.relevant_copy_snapshots(|_| true, &snapshots)?; let to_copy: Vec<_> = copy_snapshots .iter() .filter_map(|CopySnapshot { relevant, sn }| relevant.then_some(sn)) .collect(); println!("Copying {} snapshots", to_copy.len()); // Perform the copy src_repo.copy(&dst_repo, to_copy)?; println!("Copy complete!"); Ok(()) } ``` -------------------------------- ### Add dependency to Cargo.toml Source: https://github.com/rustic-rs/rustic_core/blob/main/README.md Include the rustic_core crate in your project dependencies. ```toml [dependencies] rustic_core = "0" ``` -------------------------------- ### Search for files in snapshots Source: https://context7.com/rustic-rs/rustic_core/llms.txt Uses glob patterns to locate specific files across all repository snapshots. Requires an indexed repository to perform the search. ```rust use globset::Glob; use rustic_backend::BackendOptions; use rustic_core::{Credentials, FindMatches, Repository, RepositoryOptions}; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))? .to_indexed()?; // Get all snapshots sorted by time let mut snapshots = repo.get_all_snapshots()?; snapshots.sort_unstable(); // Get tree IDs from snapshots let tree_ids = snapshots.iter().map(|sn| sn.tree); // Create a glob pattern matcher let glob = Glob::new("**/*.rs")?.compile_matcher(); // Find matching nodes across all snapshots let FindMatches { paths, nodes, matches } = repo.find_matching_nodes(tree_ids, &|path, _node| glob.is_match(path))?; // Print results grouped by snapshot for (snap, match_indices) in snapshots.iter().zip(matches) { if !match_indices.is_empty() { println!("\nSnapshot {} ({}):", snap.id, snap.time); for (path_idx, node_idx) in match_indices { println!(" {} ({} bytes)", paths[path_idx].display(), nodes[node_idx].meta.size); } } } Ok(()) } ``` -------------------------------- ### List and Filter Snapshots in Rust Source: https://context7.com/rustic-rs/rustic_core/llms.txt Retrieves snapshots from a repository using various filtering criteria like hostnames, tags, or specific identifiers. ```rust use rustic_backend::BackendOptions; use rustic_core::{Credentials, Repository, RepositoryOptions}; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))?; // Get all snapshots let all_snapshots = repo.get_all_snapshots()?; println!("Total snapshots: {}", all_snapshots.len()); // Get snapshots matching a filter let filtered = repo.get_matching_snapshots(|snap| { snap.hostname == "my-laptop" && snap.tags.contains(&"important".to_string()) })?; for snap in &filtered { println!("ID: {} | Time: {} | Host: {} | Tags: {:?}", snap.id, snap.time, snap.hostname, snap.tags); } // Get specific snapshot by ID or "latest" let latest = repo.get_snapshot_from_str("latest", |_| true)?; println!("Latest snapshot: {} at {}", latest.id, latest.time); // Get Nth latest snapshot using "latest~N" syntax let second_latest = repo.get_snapshot_from_str("latest~1", |_| true)?; Ok(()) } ``` -------------------------------- ### Restore a snapshot in Rust Source: https://github.com/rustic-rs/rustic_core/blob/main/README.md Restores data from the latest snapshot to a local directory using a prepared restore configuration. ```rust use rustic_backend::BackendOptions; use rustic_core::{LocalDestination, LsOptions, Repository, RepositoryOptions, RestoreOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; fn main() -> Result<(), Box> { // Display info logs let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); // Initialize Backends let backends = BackendOptions::default() .repository("/tmp/repo") .to_backends()?; // Open repository let repo_opts = RepositoryOptions::default().password("test"); let repo = Repository::new(&repo_opts, &backends)? .open()? .to_indexed()?; // use latest snapshot without filtering snapshots let node = repo.node_from_snapshot_path("latest", |_| true)?; // use list of the snapshot contents using no additional filtering let streamer_opts = LsOptions::default(); let ls = repo.ls(&node, &streamer_opts)?; let destination = "./restore/"; // restore to this destination dir let create = true; // create destination dir, if it doesn't exist let dest = LocalDestination::new(destination, create, !node.is_dir())?; let opts = RestoreOptions::default(); let dry_run = false; // create restore infos. Note: this also already creates needed dirs in the destination let restore_infos = repo.prepare_restore(&opts, ls.clone(), &dest, dry_run)?; repo.restore(restore_infos, &opts, ls, &dest)?; Ok(()) } ``` -------------------------------- ### Manage Repository Encryption Keys Source: https://context7.com/rustic-rs/rustic_core/llms.txt Adds or removes encryption keys for a repository, allowing for shared access. Note that the currently used key cannot be deleted. ```rust use rustic_backend::BackendOptions; use rustic_core::{Credentials, KeyOptions, Repository, RepositoryOptions}; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("current_password"))?; // Add a new key with a different password let key_opts = KeyOptions::default(); let new_key_id = repo.add_key("new_user_password", &key_opts)?; println!("Added new key with ID: {}", new_key_id); // List all keys in the repository let keys: Vec<_> = repo.list::()?.collect(); println!("Repository has {} keys", keys.len()); // Delete a key (cannot delete the currently used key) // repo.delete_key(&key_id_to_delete)?; Ok(()) } ``` -------------------------------- ### Check a repository in Rust Source: https://github.com/rustic-rs/rustic_core/blob/main/README.md Performs an integrity check on the repository, optionally trusting the local cache. ```rust use rustic_backend::BackendOptions; use rustic_core::{CheckOptions, Repository, RepositoryOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; fn main() -> Result<(), Box> { // Display info logs let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); // Initialize Backends let backends = BackendOptions::default() .repository("/tmp/repo") .to_backends()?; // Open repository let repo_opts = RepositoryOptions::default().password("test"); let repo = Repository::new(&repo_opts, &backends)?.open()?; // Check repository with standard options but omitting cache checks let opts = CheckOptions::default().trust_cache(true); repo.check(opts)?; Ok(()) } ``` -------------------------------- ### Check repository integrity Source: https://context7.com/rustic-rs/rustic_core/llms.txt Validates the consistency of index files, pack files, and snapshot trees. Setting read_data to true will verify all pack data, which is significantly slower. ```rust use rustic_backend::BackendOptions; use rustic_core::{CheckOptions, Credentials, Repository, RepositoryOptions}; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))?; // Configure check options let opts = CheckOptions::default() .trust_cache(true) // Skip cache validation .read_data(false); // Set to true to verify all pack data (slow) // Run repository check let results = repo.check(opts)?; println!("Check completed!"); println!("Index packs: {}", results.index_packs); println!("Index blobs: {}", results.index_blobs); if results.errors.is_empty() { println!("No errors found!"); } else { println!("Errors found:"); for error in &results.errors { println!(" - {}", error); } } Ok(()) } ``` -------------------------------- ### Restore Files from Snapshot in Rust Source: https://context7.com/rustic-rs/rustic_core/llms.txt Restores data from a snapshot to a local destination, supporting dry-run modes and metadata preservation. ```rust use rustic_backend::BackendOptions; use rustic_core::{ Credentials, LocalDestination, LsOptions, Repository, RepositoryOptions, RestoreOptions, }; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))? .to_indexed()?; // IndexedFull state required for restore // Get the snapshot/node to restore // Can use "snapshot_id:/path/to/subdir" to restore specific directory let node = repo.node_from_snapshot_path("latest", |_| true)?; // Configure listing options let ls_opts = LsOptions::default(); let ls = repo.ls(&node, &ls_opts)?; // Setup destination let destination = "/tmp/restored_files/"; let create_destination = true; let dest = LocalDestination::new(destination, create_destination, !node.is_dir())?; // Configure restore options let opts = RestoreOptions::default(); let dry_run = false; // Prepare restore (creates directories, calculates what to restore) let restore_plan = repo.prepare_restore(&opts, ls.clone(), &dest, dry_run)?; println!("Files to restore: {}", restore_plan.stats.files_total); println!("Total size: {} bytes", restore_plan.stats.total_file_size); // Execute the restore repo.restore(restore_plan, &opts, ls, &dest)?; println!("Restore complete!"); Ok(()) } ``` -------------------------------- ### Forget and prune snapshots Source: https://context7.com/rustic-rs/rustic_core/llms.txt Applies retention policies to identify snapshots for removal and reclaims storage by pruning unreferenced data. Note that deletion and pruning operations are commented out by default. ```rust use jiff::Zoned; use rustic_backend::BackendOptions; use rustic_core::{ Credentials, ForgetGroups, Grouped, KeepOptions, PruneOptions, Repository, RepositoryOptions, SnapshotGroupCriterion, }; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))?; // Define retention policy let keep = KeepOptions::default() .keep_last(5) // Keep last 5 snapshots .keep_daily(7) // Keep daily for 7 days .keep_weekly(4) // Keep weekly for 4 weeks .keep_monthly(12) // Keep monthly for 12 months .keep_yearly(3); // Keep yearly for 3 years // Group snapshots (by host, paths, tags) let group_by = SnapshotGroupCriterion::default(); let snaps = repo.get_all_snapshots()?; let grouped = Grouped::from_items(snaps, group_by); // Calculate which snapshots to forget let forget_groups = ForgetGroups::from_grouped_snapshots_with_retention( grouped, &keep, &Zoned::now() )?; // Display what would be forgotten for group in forget_groups.groups() { println!("Group: {:?}", group.group); println!(" Keep: {} snapshots", group.keep.len()); println!(" Forget: {} snapshots", group.forget.len()); } // Actually delete the snapshots (uncomment to execute) // repo.delete_snapshots(&forget_groups.into_forget_ids())?; // After forgetting snapshots, prune unused data let prune_opts = PruneOptions::default(); let prune_plan = repo.prune_plan(&prune_opts)?; println!("\nPrune statistics:"); println!(" Packs to delete: {:?}", prune_plan.stats); // Execute pruning (uncomment to execute) // prune_plan.do_prune(&repo, &prune_opts)?; Ok(()) } ``` -------------------------------- ### Modify Snapshot Tags Source: https://context7.com/rustic-rs/rustic_core/llms.txt Adds, removes, or sets tags on existing snapshots for improved organization and filtering. This operation involves saving new snapshot versions and then deleting the old ones. ```rust use rustic_backend::BackendOptions; use rustic_core::{Credentials, Repository, RepositoryOptions, StringList}; use std::str::FromStr; fn main() -> Result<(), Box> { let backends = BackendOptions::default() .repository("/tmp/my_backup_repo") .to_backends()?; let repo = Repository::new(&RepositoryOptions::default(), &backends)? .open(&Credentials::password("test"))?; // Get all snapshots let snaps = repo.get_all_snapshots()?; // Define tags to add let new_tags = vec![StringList::from_str("verified")?]; // Filter and modify snapshots that need tag updates let modified_snaps: Vec<_> = snaps .into_iter() .filter_map(|mut sn| { // add_tags returns true if tags were actually added // Can also use: sn.set_tags() or sn.remove_tags() sn.add_tags(new_tags.clone()).then_some(sn) }) .collect(); if modified_snaps.is_empty() { println!("No snapshots needed tag updates"); return Ok(()) } // Get IDs of original snapshots to delete after saving new versions let old_ids: Vec<_> = modified_snaps.iter().map(|sn| sn.id).collect(); // Save modified snapshots (creates new snapshot files) repo.save_snapshots(modified_snaps)?; // Remove old snapshot files repo.delete_snapshots(&old_ids)?; println!("Updated tags on {} snapshots", old_ids.len()); Ok(()) } ```