BackupManager

Struct BackupManager 

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

Manages backup and restoration of AGPM binaries during upgrades.

BackupManager provides comprehensive backup functionality to protect against failed upgrades and enable rollback capabilities. It creates backups of the current binary before upgrades and can restore them if needed.

§Safety Features

  • Automatic Backup Creation: Creates backups before any binary modification
  • Permission Preservation: Maintains file permissions and metadata on Unix systems
  • Atomic Operations: Uses file copy operations for reliability
  • Retry Logic: Handles Windows file locking issues with automatic retries
  • Rollback Support: Enables quick restoration from backups

§Backup Strategy

The backup manager creates a copy of the original binary with a .backup suffix in the same directory. This approach:

  • Keeps backups close to the original for easy access
  • Preserves the same file system and permissions context
  • Allows for quick restoration without complex path management
  • Works consistently across different installation methods

§Cross-Platform Considerations

§Unix Systems (Linux, macOS)

  • Preserves executable permissions and ownership
  • Uses standard file copy operations
  • Handles symbolic links appropriately

§Windows

  • Implements retry logic for file locking issues
  • Handles executable files that might be in use
  • Works with Windows permission models

§Examples

§Basic Backup and Restore

use agpm_cli::upgrade::backup::BackupManager;
use std::path::PathBuf;

let exe_path = PathBuf::from("/usr/local/bin/agpm");
let backup_manager = BackupManager::new(exe_path);

// Create backup before upgrade
backup_manager.create_backup().await?;

// ... perform upgrade ...

// Restore if upgrade failed
let upgrade_failed = false; // Set based on upgrade result
if upgrade_failed {
    backup_manager.restore_backup().await?;
} else {
    backup_manager.cleanup_backup().await?;
}

§Check for Existing Backup

use agpm_cli::upgrade::backup::BackupManager;
use std::path::PathBuf;

let backup_manager = BackupManager::new(PathBuf::from("agpm"));

if backup_manager.backup_exists() {
    println!("Backup found at: {}", backup_manager.backup_path().display());
}

§Error Handling

All operations return Result<T, anyhow::Error> with detailed error context:

  • Permission errors when unable to read/write files
  • File system errors during copy operations
  • Platform-specific issues (Windows file locking, Unix permissions)

§Implementation Details

  • Uses tokio::fs for async file operations
  • Implements platform-specific permission handling
  • Provides detailed logging for debugging and monitoring
  • Handles edge cases like missing files and permission issues

Implementations§

Source§

impl BackupManager

Source

pub fn new(executable_path: PathBuf) -> Self

Create a new BackupManager for the specified executable.

Automatically determines the backup file path by appending .backup to the original executable name in the same directory.

§Arguments
  • executable_path - Full path to the executable binary to manage
§Examples
use agpm_cli::upgrade::backup::BackupManager;
use std::path::PathBuf;

// Unix-style path
let manager = BackupManager::new(PathBuf::from("/usr/local/bin/agpm"));
// Backup will be at /usr/local/bin/agpm.backup

// Windows-style path
let manager = BackupManager::new(PathBuf::from(r"C:\Program Files\agpm\agpm.exe"));
// Backup will be at C:\Program Files\agpm\agpm.exe.backup
Source

pub async fn create_backup(&self) -> Result<()>

Create a backup of the original binary.

Copies the current binary to the backup location, preserving permissions and metadata. If a backup already exists, it will be replaced.

§Process
  1. Validate that the original file exists
  2. Remove any existing backup file
  3. Copy the original file to the backup location
  4. Preserve file permissions on Unix systems
§Returns
  • Ok(()) - Backup created successfully
  • Err(error) - Backup creation failed
§Errors

This method can fail if:

  • The original file doesn’t exist or is not readable
  • Insufficient permissions to create the backup file
  • File system errors during the copy operation
  • Unable to set permissions on the backup file (Unix)
§Examples
use agpm_cli::upgrade::backup::BackupManager;
use std::path::PathBuf;

let manager = BackupManager::new(PathBuf::from("./agpm"));

match manager.create_backup().await {
    Ok(()) => println!("Backup created successfully"),
    Err(e) => eprintln!("Failed to create backup: {}", e),
}
Source

pub async fn restore_backup(&self) -> Result<()>

Restore the original binary from backup.

Replaces the current binary with the backup copy, effectively rolling back to the previous version. This operation includes retry logic for Windows systems where the binary might be locked.

§Process
  1. Validate that a backup file exists
  2. Remove the current (potentially corrupted) binary
  3. Copy the backup file back to the original location
  4. Restore file permissions on Unix systems
  5. Retry up to 3 times on Windows for file locking issues
§Returns
  • Ok(()) - Backup restored successfully
  • Err(error) - Restoration failed after all retries
§Errors

This method can fail if:

  • No backup file exists at the expected location
  • Insufficient permissions to replace the original file
  • File locking issues prevent replacement (Windows)
  • File system errors during the copy operation
  • Unable to restore permissions (Unix)
§Platform Behavior
§Windows
  • Implements retry logic with 1-second delays
  • Handles file locking from running processes
  • Attempts up to 3 times before giving up
§Unix
  • Preserves executable permissions and ownership
  • Single attempt (usually succeeds immediately)
§Examples
use agpm_cli::upgrade::backup::BackupManager;
use std::path::PathBuf;

let manager = BackupManager::new(PathBuf::from("./agpm"));

if manager.backup_exists() {
    match manager.restore_backup().await {
        Ok(()) => println!("Successfully restored from backup"),
        Err(e) => eprintln!("Failed to restore backup: {}", e),
    }
} else {
    eprintln!("No backup found to restore");
}
Source

pub async fn cleanup_backup(&self) -> Result<()>

Remove the backup file after a successful upgrade.

Cleans up the backup file once it’s no longer needed, typically after a successful upgrade has been completed and verified.

§Returns
  • Ok(()) - Backup cleaned up successfully or no backup existed
  • Err(error) - Failed to remove the backup file
§Errors

This method can fail if:

  • Insufficient permissions to delete the backup file
  • File system errors during deletion
  • File is locked or in use (rare on most systems)
§Examples
use agpm_cli::upgrade::backup::BackupManager;
use std::path::PathBuf;

let manager = BackupManager::new(PathBuf::from("./agpm"));

// After successful upgrade
manager.cleanup_backup().await?;
println!("Backup cleaned up");
§Note

This method silently succeeds if no backup file exists, making it safe to call unconditionally after upgrades.

Source

pub fn backup_exists(&self) -> bool

Check if a backup file currently exists.

This is a synchronous check that verifies whether a backup file is present at the expected location.

§Returns
  • true - A backup file exists and can potentially be restored
  • false - No backup file found at the expected location
§Examples
use agpm_cli::upgrade::backup::BackupManager;
use std::path::PathBuf;

let manager = BackupManager::new(PathBuf::from("./agpm"));

if manager.backup_exists() {
    println!("Backup available for rollback");
} else {
    println!("No backup found");
}
§Note

This method only checks for file existence, not validity or integrity of the backup file. Use restore_backup() to verify the backup can actually be used.

Source

pub fn backup_path(&self) -> &Path

Get the path where the backup file is stored.

Returns the full path to the backup file location, which is useful for logging, debugging, or manual backup management.

§Returns

A path reference to the backup file location.

§Examples
use agpm_cli::upgrade::backup::BackupManager;
use std::path::PathBuf;

let manager = BackupManager::new(PathBuf::from("/usr/local/bin/agpm"));
println!("Backup location: {}", manager.backup_path().display());
// Output: Backup location: /usr/local/bin/agpm.backup
§Use Cases
  • Logging: Include backup location in log messages
  • Debugging: Help users locate backup files manually
  • Error Messages: Show backup location when operations fail
  • Manual Recovery: Allow users to manually restore backups

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> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more