Skip to main content

BackupManager

Struct BackupManager 

Source
pub struct BackupManager { /* private fields */ }
Expand description

BackupManager is a struct responsible for managing backup operations.

This struct serves as a core component for creating, storing, and retrieving backups in the system. It encapsulates the Repository where backup data is managed, providing an interface to interact with the underlying repository for backup-related tasks.

§Fields

  • repository: The repository where backup data is stored and managed.

§Example

use obsidian_backups::BackupManager;

let backup_manager = BackupManager::new("./backup_store", "./my_data")
    .expect("Failed to create BackupManager");

Implementations§

Source§

impl BackupManager

Source

pub fn new( store_directory: impl AsRef<Path>, working_directory: impl AsRef<Path>, ) -> Result<Self>

Creates a new instance of BackupManager.

This function initializes a BackupManager by setting up a new Git repository in the specified store_directory with the specified working_directory as the working directory for the repository.

§Arguments
  • store_directory - A reference to a path where the repository data will be stored.
  • working_directory - A reference to a path that will serve as the working directory for the repository.

Both arguments accept types that can be converted into a PathBuf.

§Returns

Returns Ok(Self) with the initialized BackupManager if successful, or an error if the Git repository initialization fails.

§Logging
  • Logs an informational message when starting and successfully completing the initialization process.
  • Logs debug messages showing the resolved paths and steps during initialization.
§Errors

Returns an error if repository initialization fails. This typically occurs due to invalid paths, insufficient permissions, or issues with the Git backend.

§Example
use obsidian_backup_system::BackupManager;

let manager = BackupManager::new("./backup_store", "./my_data")
    .expect("Failed to initialize BackupManager");

Note: Ensure that the provided paths are valid and writable for the process.

Source

pub fn setup_ignore_file(&mut self, ignore_file: impl AsRef<Path>) -> Result<()>

Sets up a .gitignore-style ignore file for the repository using the provided file path. This function configures an ignore matcher to exclude specified paths or patterns.

§Arguments
  • ignore_file - A path-like object referencing the ignore file to process. The file should follow .gitignore syntax.
§Returns
  • Result<()> - Returns Ok(()) if the ignore matcher is successfully built and configured. Returns an error if the ignore matcher cannot be built or if the ignore file causes an issue.
§Behavior
  1. Locates the working directory of the repository. Defaults to ./ if the repository has no working directory.
  2. Initializes a GitignoreBuilder using the repository’s working directory.
  3. Checks whether the provided ignore file exists:
    • If the file exists, attempts to add it to the builder. Logs a warning if there’s an issue while adding the file.
  4. Attempts to construct the ignore matcher from the builder:
    • If successful, stores the ignore matcher in self.ignore_matcher.
    • If unsuccessful, logs an error message and returns an error.
§Errors
  • Returns an error if:
    • The ignore file could not be properly parsed or added.
    • The ignore matcher fails to build successfully.
§Logging
  • Logs a warning message if the function fails to add the ignore file to the builder.
  • Logs an error message if the function fails to build the ignore matcher.
§Example Usage
use std::path::Path;
use obsidian_backup_system::BackupManager;

let mut backup_manager = BackupManager::new("./backup_store", "./my_data")?;
backup_manager.setup_ignore_file(".my_ignore_file")?;
Source

pub fn list(&self) -> Result<Vec<BackupItem>>

Lists all backup items available in the repository.

The method traverses the commit history of the repository, collects metadata for each commit, and returns a list of items representing the backup points. Each item includes the commit ID, timestamp, and commit message.

§Process
  • Logs an informational message indicating the start of the operation.
  • Initializes a revision walk over the repository to retrieve commit objects.
  • Iterates through each commit, retrieves its metadata, and constructs a BackupItem instance.
  • Each created BackupItem is logged at the trace level, and the total count is logged at the end.
§Returns

A Result containing a vector of BackupItem instances if the operation succeeds, or an error if any repository operation fails.

§Errors

Returns an error if:

  • The revision walk initialization fails.
  • Retrieving an individual commit in the history fails.
  • Any other repository-related operation encounters an error.
§Logging
  • Logs informational messages about the start and result of the operation.
  • Logs debug messages about processing individual commits.
  • Logs trace messages with details of each created BackupItem.
§Example
use obsidian_backup_system::BackupManager;

let manager = BackupManager::new("./backup_store", "./my_data")
    .expect("Failed to initialize BackupManager");

match manager.list() {
    Ok(backup_items) => {
        for item in backup_items {
            println!("Backup ID: {}, Timestamp: {}, Description: {}",
                     item.id, item.timestamp, item.description);
        }
    },
    Err(e) => eprintln!("Error listing backup items: {}", e),
}
§Note

The method assumes that commit messages are UTF-8 encoded. If a commit has no message, an empty string is used as the description.

§Dependencies
  • Requires the repository to be properly initialized and accessible.
  • Relies on the BackupItem struct to hold commit metadata.
Source

pub fn backup(&self, description: Option<String>) -> Result<String>

Creates a backup by committing the current state of the repository.

This method stages all changes, creates a commit with the given description, and returns the ID of the newly created commit. If no description is provided, a default description of “No description provided” is used. It also ensures proper handling for creating an initial commit if the repository does not have an existing HEAD.

§Arguments
  • description - An optional string containing a description for the backup commit.
§Returns

Returns a Result<String> which contains:

  • On success: The ID of the newly created commit as a string.
  • On failure: An error indicating the cause of the failure.
§Errors

This function will return an error if:

  • There is an issue accessing or writing the repository index.
  • There is an issue creating a new tree or finding the tree object in the repository.
  • The repository signature (user name and email) is invalid or not set.
  • The commit operation fails due to any Git-related error.
§Logging

This method emits the following log messages:

  • info logs for the overall operation (Creating backup, Backup created successfully).
  • debug logs for intermediate steps, such as getting the index, adding files, writing the tree, finding parents, creating signatures, and creating the commit.
§Example
use obsidian_backup_system::BackupManager;

let manager = BackupManager::new("./backup_store", "./my_data")
    .expect("Failed to initialize BackupManager");

let description = Some("Backup before deployment".to_string());
match manager.backup(description) {
    Ok(commit_id) => println!("Backup created with ID: {}", commit_id),
    Err(e) => eprintln!("Failed to create backup: {}", e),
}
§Notes
  • This method assumes that the caller has already initialized the repository (self.repository) and has proper permissions to write to it.
  • If no HEAD exists (e.g., for an empty repository), it creates an initial commit without parent commits.
Source

pub fn restore(&self, backup_id: impl AsRef<str>) -> Result<()>

Restores a backup by its ID and checks out the associated commit.

§Arguments
  • backup_id - A reference to a string that uniquely identifies the backup. This ID is parsed as a git object ID.
§Returns
  • Result<()> - Returns Ok(()) if the backup was successfully restored, or an error if the operation fails at any stage.
§Process
  1. The backup ID is parsed as a git object ID (OID).
  2. The associated git commit is retrieved using the OID.
  3. The commit’s tree is accessed, and its contents are checked out in the repository.
  4. If the repository is configured with a working directory:
    • The contents of the current working directory are removed.
    • A new working directory is created.
    • HEAD is checked out into the working directory.
  5. Logs are generated at various points to provide insights into the restoration process.
§Logs
  • Info logs are used to indicate the start and successful completion of the restore operation.
  • Debug logs provide detailed information about each step of the process, such as parsing the backup ID, working with git objects, and modifying the working directory.
  • Warning logs occur if no working directory is configured for the repository.
§Errors

Returns an error if any of the following occurs:

  • The backup ID cannot be parsed as a valid git OID.
  • The associated commit cannot be found in the repository.
  • The commit’s tree cannot be accessed.
  • Checking out the tree in the repository fails.
  • File system operations, such as removing or creating the working directory, encounter errors.
§Example Usage
use obsidian_backup_system::BackupManager;

let manager = BackupManager::new("./backup_store", "./my_data")
    .expect("Failed to initialize BackupManager");

let backup_id = "abcdef1234567890";
if let Err(err) = manager.restore(backup_id) {
    eprintln!("Failed to restore backup: {}", err);
} else {
    println!("Backup restored successfully!");
}
Source

pub fn diff(&self, backup_id: impl AsRef<str>) -> Result<Vec<ModifiedFile>>

Computes the list of files that were modified (added, updated, or deleted) in the specified backup/commit within the repository.

§Arguments
  • backup_id - A string-like identifier for the backup or commit to compute the modified files against its parent commit. The function expects this to be in the format of a valid Git object ID.
§Returns

A Result containing:

  • Ok(Vec<ModifiedFile>) - A vector of ModifiedFile objects, each representing a file that was added, updated, or deleted. Each ModifiedFile includes:
    • path: The path of the file.
    • content_before: The file’s content before modification (if applicable, Some if the file existed, otherwise None).
    • content_after: The file’s content after modification (if applicable, Some if the file exists, otherwise None for deletions).
  • Err(git2::Error) - In case of any error during Git repository or commit/tree operations.
§Details
  • The function computes the difference between the specified commit/tree and its immediate parent (if available). If there is no parent commit (e.g., for the first commit), only the newly added files will appear in the output list.
  • For each file in the current tree:
    • If a corresponding file exists in the parent tree, the function checks for modifications.
    • If the file does not exist in the parent tree, it is marked as newly added.
  • For files that existed in the parent tree but are absent in the current tree, the function marks them as deleted.
§Errors

This function can return an Err in the following situations:

  • If the provided backup_id is not a valid Git commit or tree object ID.
  • If the repository cannot find the commit or tree corresponding to backup_id.
  • If there are errors while retrieving or processing blobs within the trees.
§Example
use obsidian_backup_system::BackupManager;

let manager = BackupManager::new("./backup_store", "./my_data")
    .expect("Failed to initialize BackupManager");

let backup_id = "abcd1234";
let modified_files = manager.diff(backup_id)
    .expect("Failed to get diff");

for file in modified_files {
    println!("Path: {}", file.path);
    match (&file.content_before, &file.content_after) {
        (Some(before), Some(after)) => {
            println!("File was modified. Before size: {}, After size: {}", before.len(), after.len());
        }
        (None, Some(after)) => {
            println!("File was added. Size: {}", after.len());
        }
        (Some(before), None) => {
            println!("File was deleted. Previous size: {}", before.len());
        }
        _ => {}
    }
}
§Structs Used
  • ModifiedFile: A struct representing a modified file, with the following fields:
    • path: The file’s path as a String.
    • content_before: An optional Vec<u8> containing the file’s content in the parent revision (if it existed).
    • content_after: An optional Vec<u8> containing the file’s content in the current revision (if it exists).
§Note
  • This function assumes text or binary files are stored as blobs in the Git repository.
  • Files that are not blobs (e.g., submodules or symlinks) are ignored.
Source

pub fn last(&self) -> Result<Option<BackupItem>>

Source

pub fn purge_backups_over_count(&self, count: usize) -> Result<()>

Source

pub fn purge_backups_older_than(&self, period: Duration) -> Result<()>

Source

pub fn purge_backups_over_size(&self, size: usize) -> Result<()>

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.