Obsidian Backup System
A Git-based backup library for Rust applications. Originally designed for the Obsidian Minecraft Server Panel, but generic enough to be used in any project requiring file backup management.
This library uses Git under the hood to provide efficient, version-controlled backups with diff capabilities.
Features
- 🔄 Create backups - Snapshot your files and directories using Git commits
- 📋 List backups - View all available backup points with timestamps and descriptions
- ⏮️ Restore backups - Safely roll back to any previous backup state with atomic operations
- 🔍 Diff backups - See exactly what changed between backup points, including nested directories
- 📦 Export backups - Create compressed archives (7z) from any backup (requires
zipfeature) - 🏷️ Backup descriptions - Add meaningful descriptions to track what each backup represents
- ⚡ Efficient storage - Leverages Git's delta compression for space-efficient storage
- 🗑️ Backup retention - Automatically purge old backups by count, age, or repository size
- 🔧 Optional features - Enable only the functionality you need
- 🛡️ Smart exclusions - Automatically excludes system files (.git, .DS_Store, temp files, etc.)
Requirements
- Rust Edition 2024 - This crate requires Rust edition 2024 or later
- Rust Version - Rust 1.82.0 or later (for edition 2024 support)
Installation
This crate is not yet published on crates.io. To use it, add the following to your Cargo.toml:
[]
= { = "https://github.com/Obsidian-Minecraft-Server-Portal/obsidian-backup-system.git" }
With Optional Features
[]
= { = "https://github.com/Obsidian-Minecraft-Server-Portal/obsidian-backup-system.git", = ["serde", "logging", "zip"] }
Available Features
| Feature | Description | Dependencies |
|---|---|---|
serde |
Enables serialization/deserialization support for backup items | serde |
logging |
Enables internal logging using the log crate |
log |
zip |
Enables exporting backups as 7z compressed archives | sevenz-rust2 |
cli |
Builds the command-line interface application | clap, serde_json, pretty_env_logger |
Basic Usage
Initialize BackupManager
use BackupManager;
// Create a backup manager
// store_directory: where backup metadata is stored (.git repository)
// working_directory: the directory you want to back up
let manager = new
.expect;
Create a Backup
// Create a backup without description
let backup_id = manager.backup
.expect;
println!;
// Create a backup with description
let backup_id = manager.backup
.expect;
Note: Backups automatically exclude common system and temporary files:
- Version control:
.git - System files:
.DS_Store,Thumbs.db,desktop.ini,$RECYCLE.BIN - Temporary files:
*.tmp,*.swp,~*, Office temp files (~$*) - Python cache:
__pycache__
List All Backups
let backups = manager.list
.expect;
for backup in backups
Get Most Recent Backup
if let Some = manager.last.expect else
Restore a Backup
// Restore using backup ID
manager.restore
.expect;
Safety Note: The restore operation uses a safe atomic approach:
- Files are first checked out to a temporary directory
- The working directory is backed up before being replaced
- If restoration fails, the original directory is automatically restored
- This prevents data loss from partial or failed restore operations
View Changes (Diff)
// Get differences between a backup and its parent
let modified_files = manager.diff
.expect;
for file in modified_files
Export Backup as Archive (requires zip feature)
Export to File
Export to Stream
For scenarios where you need to stream the archive directly (e.g., HTTP responses, in-memory processing):
Note:
- Compression levels are automatically validated and clamped to the valid range (0-9). Values below 0 become 0, and values above 9 become 9.
- The 7z format requires seeking, so the writer must implement both
WriteandSeektraits. - For streaming over network without seek capability, export to a buffer first, then send the bytes.
Purge Old Backups
The backup system provides three strategies for managing backup retention and preventing unlimited growth:
1. Purge by Count - Keep Only N Most Recent Backups
// Keep only the 10 most recent backups, remove all older ones
manager.purge_backups_over_count
.expect;
This method:
- Keeps the specified number of most recent backups
- Removes all older backups while maintaining Git repository integrity
- Consolidates the oldest kept backup into a new base commit
- Runs garbage collection to reclaim disk space
2. Purge by Age - Remove Backups Older Than a Time Period
use Duration;
// Remove backups older than 30 days
manager.purge_backups_older_than
.expect;
// Remove backups older than 7 days
manager.purge_backups_older_than
.expect;
// Remove backups older than 2 hours
manager.purge_backups_older_than
.expect;
This method:
- Removes all backups created before the specified time period
- Preserves all backups within the time window
- Creates a consolidated base commit from the oldest kept backup
- Automatically runs cleanup to free disk space
3. Purge by Size - Keep Repository Under a Size Limit
// Keep repository under 100MB
manager.purge_backups_over_size
.expect;
// Keep repository under 1GB
manager.purge_backups_over_size
.expect;
This method:
- Removes oldest backups until repository size is below the threshold
- Uses a binary search approach to efficiently find the right number of backups to keep
- Requires at least one backup to remain
- Returns an error if size cannot be reduced without removing all backups
Important Notes:
- All purge operations maintain repository integrity through Git's commit rewriting
- Purging is permanent and cannot be undone - removed backups are deleted
- At least one backup must remain after purging
- Automatic garbage collection runs after purging to reclaim disk space
- Purge operations may take time on large repositories due to rewriting commit history
Complete Example
use BackupManager;
use fs;
Backup Retention Example
use BackupManager;
use Duration;
use fs;
With Logging (requires logging feature)
use ;
Command Line Interface
The obackup command-line tool provides a convenient way to manage backups directly from the terminal without writing any code.
Building the CLI
The CLI requires the cli, serde, logging, and optionally zip features to be enabled. Build it using:
The binary will be located at ./target/release/obackup (or ./target/release/obackup.exe on Windows).
Installation
After building, you can copy the binary to a location in your PATH:
# Linux/macOS
# Windows (PowerShell, as administrator)
CLI Usage
obackup [OPTIONS] <COMMAND>
Global Options
-s, --store-directory <PATH>- Store directory for backup repository (default:./backup_store)-w, --working-directory <PATH>- Working directory to backup (default:.)-v, --verbose- Increase verbosity level (can be repeated:-v,-vv,-vvv)-h, --help- Print help information-V, --version- Print version information
Commands
init - Initialize a new backup repository
Initializes a new backup repository in the specified store directory.
backup - Create a new backup
Creates a new backup of the working directory.
Options:
-d, --description <TEXT>- Description for the backup
Examples:
# Create a backup without description
# Create a backup with description
list - List all backups
Lists all available backups with their IDs, timestamps, and descriptions.
Options:
-j, --json- Output in JSON format
Examples:
# List backups in human-readable format
# List backups in JSON format
last - Show the most recent backup
Displays information about the most recent backup.
Options:
-j, --json- Output in JSON format
Examples:
# Show last backup
# Show last backup in JSON format
restore - Restore a backup by ID
Restores the working directory to the state of the specified backup.
Arguments:
<BACKUP_ID>- The backup ID to restore (obtained fromlistorlast)
Example:
⚠️ Warning: This will replace all files in the working directory with the backup contents.
export - Export a backup to a 7z archive
Exports a backup as a compressed 7z archive. Requires the zip feature.
Arguments:
<BACKUP_ID>- The backup ID to export
Options:
-o, --output <PATH>- Output path for the archive-l, --level <0-9>- Compression level (default: 5)
Example:
# Export with default compression
# Export with maximum compression
diff - Show changes in a specific backup
Shows what files were added, modified, or deleted in a specific backup.
Arguments:
<BACKUP_ID>- The backup ID to diff
Options:
-j, --json- Output in JSON format-c, --show-content- Show file contents
Examples:
# Show changes summary
# Show changes with file contents
# Show changes in JSON format
CLI Workflow Examples
Basic Workflow
# Initialize backup repository
# Create first backup
# Make some changes to your project files...
# Create another backup
# View all backups
# Check what changed in the last backup
# Restore to a previous state if needed
Using Short Paths
If you're working from within your project directory, you can use relative paths:
# Initialize (stores backup data in ./backups, tracks current directory)
# Create backups
# List and inspect
Verbose Output
Use -v flags to see detailed logging:
# Info level logging
# Debug level logging
# Trace level logging (very detailed)
Archiving Backups
# Get the ID of the last backup
# Export it as a compressed archive
API Reference
BackupManager
The main struct for managing backups.
Methods
new(store_directory, working_directory) -> Result<Self>- Initialize a new backup managersetup_ignore_file(ignore_file: impl AsRef<Path>) -> Result<()>- Configure ignore patterns from a.gitignore-style filebackup(description: Option<String>) -> Result<String>- Create a new backup, returns backup IDlist() -> Result<Vec<BackupItem>>- List all available backupslast() -> Result<Option<BackupItem>>- Get the most recent backuprestore(backup_id: impl AsRef<str>) -> Result<()>- Restore a specific backupdiff(backup_id: impl AsRef<str>) -> Result<Vec<ModifiedFile>>- Get changes in a backupexport(backup_id, output_path, level: u8) -> Result<()>- Export backup as 7z archive to file (requireszipfeature)export_to_stream<W: Write + Seek>(backup_id, writer: W, level: u8) -> Result<()>- Export backup as 7z archive to a stream (requireszipfeature)purge_backups_over_count(count: usize) -> Result<()>- Keep only the N most recent backups, remove older onespurge_backups_older_than(period: chrono::Duration) -> Result<()>- Remove backups older than specified durationpurge_backups_over_size(size: usize) -> Result<()>- Remove old backups to keep repository under size limit (in bytes)
BackupItem
Represents a backup point with metadata.
ModifiedFile
Represents a file that changed in a backup.
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.