use crate::fs_primitive_error::PrimitiveError;
use std::fmt;
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum MigrateError {
Io {
action: String,
path: PathBuf,
reason: String,
},
Primitive(PrimitiveError),
UnreadableDirectory {
path: PathBuf,
reason: String,
},
Journal(String),
Interrupted(String),
}
impl MigrateError {
pub fn io(action: &str, path: &std::path::Path, error: &std::io::Error) -> MigrateError {
return MigrateError::Io { action: action.to_string(), path: path.to_path_buf(), reason: error.to_string() };
}
}
impl fmt::Display for MigrateError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MigrateError::Io { action, path, reason } => return write!(formatter, "cannot {action} {}: {reason}", path.display()),
MigrateError::Primitive(error) => return write!(formatter, "{error}"),
MigrateError::UnreadableDirectory { path, reason } => {
return write!(
formatter,
"the directory {} cannot be listed or searched by this user ({reason}); copying around it would leave its content out of the new checkout",
path.display()
);
}
MigrateError::Journal(message) => return write!(formatter, "{message}"),
MigrateError::Interrupted(point) => return write!(formatter, "stopped at the test point {point}"),
}
}
}
impl std::error::Error for MigrateError {}
impl From<PrimitiveError> for MigrateError {
fn from(error: PrimitiveError) -> MigrateError {
return MigrateError::Primitive(error);
}
}
#[derive(Debug)]
pub struct Interrupt {
target: Option<(String, u64)>,
hits: AtomicU64,
}
impl Interrupt {
pub fn never() -> Interrupt {
return Interrupt { target: None, hits: AtomicU64::new(0) };
}
pub fn at(point: &str, after: u64) -> Interrupt {
return Interrupt { target: Some((point.to_string(), after)), hits: AtomicU64::new(0) };
}
pub fn check(&self, point: &str) -> Result<(), MigrateError> {
let Some((name, after)) = &self.target else { return Ok(()) };
if name != point {
return Ok(());
}
let seen: u64 = self.hits.fetch_add(1, Ordering::SeqCst);
if seen == *after {
return Err(MigrateError::Interrupted(point.to_string()));
}
return Ok(());
}
}