use super::display::EscapedDisplayText;
use std::{
fmt::{Display, Formatter},
io,
path::PathBuf,
};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FilesystemConfigError {
CurrentDir {
source: io::Error,
},
CanonicalizeRoot {
source: io::Error,
},
RootIsNotDirectory {
workspace_root: PathBuf,
},
}
impl Display for FilesystemConfigError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::CurrentDir { source } => {
write!(formatter, "failed to read current directory: {source}")
}
Self::CanonicalizeRoot { source } => {
write!(formatter, "failed to canonicalize workspace root: {source}")
}
Self::RootIsNotDirectory { workspace_root } => {
write!(
formatter,
"{} is not a directory",
display_path(workspace_root)
)
}
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum PathPolicyError {
CurrentDir {
source: io::Error,
},
MissingParent {
path: PathBuf,
},
Parent {
path: PathBuf,
source: io::Error,
},
Unresolvable {
path: PathBuf,
source: io::Error,
},
OutsideWorkspace {
path: PathBuf,
workspace_root: PathBuf,
},
}
impl Display for PathPolicyError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::CurrentDir { source } => {
write!(formatter, "failed to read current directory: {source}")
}
Self::MissingParent { path } => {
write!(formatter, "{} has no parent directory", display_path(path))
}
Self::Parent { path, source } => {
write!(
formatter,
"failed to resolve parent for {}: {source}",
display_path(path)
)
}
Self::Unresolvable { path, source } => {
write!(
formatter,
"failed to safely resolve {}: {source}",
display_path(path)
)
}
Self::OutsideWorkspace {
path,
workspace_root,
} => write!(
formatter,
"{} is outside workspace root {}",
display_path(path),
display_path(workspace_root)
),
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FileReadError {
Policy(#[source] PathPolicyError),
Missing {
path: PathBuf,
},
Metadata {
path: PathBuf,
source: io::Error,
},
UnsupportedFileType {
path: PathBuf,
},
TooLarge {
path: PathBuf,
size: u64,
max_size: u64,
},
Open {
path: PathBuf,
source: io::Error,
},
Read {
path: PathBuf,
source: io::Error,
},
}
impl Display for FileReadError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Policy(error) => error.fmt(formatter),
Self::Missing { path } => {
write!(formatter, "{} does not exist", display_path(path))
}
Self::Metadata { path, source } => {
write!(
formatter,
"failed to read metadata for {}: {source}",
display_path(path)
)
}
Self::UnsupportedFileType { path } => {
write!(formatter, "{} is not a regular file", display_path(path))
}
Self::TooLarge {
path,
size,
max_size,
} => write!(
formatter,
"{} is {size} bytes, exceeding the {max_size} byte limit",
display_path(path)
),
Self::Open { path, source } => {
write!(formatter, "failed to open {}: {source}", display_path(path))
}
Self::Read { path, source } => {
write!(formatter, "failed to read {}: {source}", display_path(path))
}
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FileWriteError {
Policy(#[source] PathPolicyError),
Metadata {
path: PathBuf,
source: io::Error,
},
UnsupportedFileType {
path: PathBuf,
},
MissingParent {
path: PathBuf,
},
CreateTemp {
path: PathBuf,
source: io::Error,
},
WriteTemp {
path: PathBuf,
source: io::Error,
},
SyncTemp {
path: PathBuf,
source: io::Error,
},
SetTempPermissions {
path: PathBuf,
source: io::Error,
},
Rename {
temp_path: PathBuf,
target_path: PathBuf,
source: io::Error,
},
}
impl Display for FileWriteError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Policy(error) => error.fmt(formatter),
Self::Metadata { path, source } => {
write!(
formatter,
"failed to read metadata for {}: {source}",
display_path(path)
)
}
Self::UnsupportedFileType { path } => {
write!(formatter, "{} is not a regular file", display_path(path))
}
Self::MissingParent { path } => {
write!(formatter, "{} has no parent directory", display_path(path))
}
Self::CreateTemp { path, source } => {
write!(
formatter,
"failed to create temporary file {}: {source}",
display_path(path)
)
}
Self::WriteTemp { path, source } => {
write!(
formatter,
"failed to write temporary file {}: {source}",
display_path(path)
)
}
Self::SyncTemp { path, source } => {
write!(
formatter,
"failed to sync temporary file {}: {source}",
display_path(path)
)
}
Self::SetTempPermissions { path, source } => {
write!(
formatter,
"failed to set permissions on temporary file {}: {source}",
display_path(path)
)
}
Self::Rename {
temp_path,
target_path,
source,
} => write!(
formatter,
"failed to rename {} to {}: {source}",
display_path(temp_path),
display_path(target_path)
),
}
}
}
fn display_path(path: &std::path::Path) -> String {
EscapedDisplayText::from_path(path).as_str().to_owned()
}