1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-02 14:07:46 +00:00

backup_control: Implement custom error type

Implements an error type based on `UError` that replaces the previously used
error strings. The errors are currently returned when determining the backup
mode, but extensions for future uses are already in place as comments.
This commit is contained in:
Andreas Hartmann 2021-07-21 09:17:57 +02:00 committed by Michael Debertol
parent 2c6410f4d8
commit 54086ef4c5
2 changed files with 143 additions and 0 deletions

View file

@ -16,6 +16,7 @@ edition = "2018"
path="src/lib/lib.rs" path="src/lib/lib.rs"
[dependencies] [dependencies]
clap = "2.33.3"
dns-lookup = { version="1.0.5", optional=true } dns-lookup = { version="1.0.5", optional=true }
dunce = "1.0.0" dunce = "1.0.0"
getopts = "<= 0.2.21" getopts = "<= 0.2.21"

View file

@ -1,5 +1,89 @@
//! Implement GNU-style backup functionality.
//!
//! This module implements the backup functionality as described in the [GNU
//! manual][1]. It provides
//!
//! - pre-defined [`clap`-Arguments][2] for inclusion in utilities that
//! implement backups
//! - determination of the [backup mode][3]
//! - determination of the [backup suffix][4]
//! - [backup target path construction][5]
//! - [Error types][6] for backup-related errors
//! - GNU-compliant [help texts][7] for backup-related errors
//!
//! Backup-functionality is implemented by the following utilities:
//!
//! - `cp`
//! - `install`
//! - `ln`
//! - `mv`
//!
//!
//! [1]: https://www.gnu.org/software/coreutils/manual/html_node/Backup-options.html
//! [2]: arguments
//! [3]: `determine_backup_mode()`
//! [4]: `determine_backup_suffix()`
//! [5]: `get_backup_path()`
//! [6]: `BackupError`
//! [7]: `BACKUP_CONTROL_LONG_HELP`
//!
//!
//! # Usage example
//!
//! ```
//! #[macro_use]
//! extern crate uucore;
//!
//! use clap::{App, Arg, ArgMatches};
//! use std::path::{Path, PathBuf};
//! use uucore::backup_control::{self, BackupMode};
//! use uucore::error::{UError, UResult};
//!
//! fn main() {
//! let usage = String::from("app [OPTION]... ARG");
//! let long_usage = String::from("And here's a detailed explanation");
//!
//! let matches = App::new("app")
//! .arg(backup_control::arguments::backup())
//! .arg(backup_control::arguments::backup_no_args())
//! .arg(backup_control::arguments::suffix())
//! .usage(&usage[..])
//! .after_help(&*format!(
//! "{}\n{}",
//! long_usage,
//! backup_control::BACKUP_CONTROL_LONG_HELP
//! ))
//! .get_matches_from(vec![
//! "app", "--backup=t", "--suffix=bak~"
//! ]);
//!
//! let backup_mode = match backup_control::determine_backup_mode(&matches) {
//! Err(e) => {
//! show!(e);
//! return;
//! },
//! Ok(mode) => mode,
//! };
//! let backup_suffix = backup_control::determine_backup_suffix(&matches);
//! let target_path = Path::new("/tmp/example");
//!
//! let backup_path = backup_control::get_backup_path(
//! backup_mode, target_path, &backup_suffix
//! );
//!
//! // Perform your backups here.
//!
//! }
//! ```
// spell-checker:ignore backupopt
use crate::error::{UError, UResult};
use clap::ArgMatches;
use std::{ use std::{
env, env,
error::Error,
fmt::{Debug, Display},
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@ -17,6 +101,12 @@ the VERSION_CONTROL environment variable. Here are the values:
existing, nil numbered if numbered backups exist, simple otherwise existing, nil numbered if numbered backups exist, simple otherwise
simple, never always make simple backups"; simple, never always make simple backups";
static VALID_ARGS_HELP: &str = "Valid arguments are:
- none, off
- simple, never
- existing, nil
- numbered, t";
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum BackupMode { pub enum BackupMode {
NoBackup, NoBackup,
@ -25,6 +115,58 @@ pub enum BackupMode {
ExistingBackup, ExistingBackup,
} }
#[derive(Debug, Eq, PartialEq)]
pub enum BackupError {
InvalidArgument(String, String),
AmbiguousArgument(String, String),
BackupImpossible(),
// BackupFailed(PathBuf, PathBuf, std::io::Error),
}
impl UError for BackupError {
fn code(&self) -> i32 {
match self {
BackupError::BackupImpossible() => 2,
_ => 1,
}
}
fn usage(&self) -> bool {
// Suggested by clippy.
matches!(
self,
BackupError::InvalidArgument(_, _) | BackupError::AmbiguousArgument(_, _)
)
}
}
impl Error for BackupError {}
impl Display for BackupError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use BackupError as BE;
match self {
BE::InvalidArgument(arg, origin) => write!(
f,
"invalid argument {} for {}\n{}",
arg, origin, VALID_ARGS_HELP
),
BE::AmbiguousArgument(arg, origin) => write!(
f,
"ambiguous argument {} for {}\n{}",
arg, origin, VALID_ARGS_HELP
),
BE::BackupImpossible() => write!(f, "cannot create backup"),
// Placeholder for later
// BE::BackupFailed(from, to, e) => Display::fmt(
// &uio_error!(e, "failed to backup '{}' to '{}'", from.display(), to.display()),
// f
// ),
}
}
}
/// Arguments for backup-related functionality
pub mod arguments { pub mod arguments {
extern crate clap; extern crate clap;