use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::path::PathBuf;
use crate::CheckResult;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
InvalidRustLibName(String),
InvalidRustLibPath {
path: String,
reason: &'static str,
},
RustLibAlreadyExists(String),
RustLibNotFound(String),
RustLibIsNotDirectory(String),
DuplicateWritePath(String),
NonUtf8Path(PathBuf),
NonUtf8File(PathBuf),
SymlinkNotAllowed(PathBuf),
UnsupportedFileType(PathBuf),
RootsOverlap {
rust_libs_root: PathBuf,
work_root: PathBuf,
},
MissingRequiredFile(&'static str),
InvalidVersion(String),
InvalidCargoManifest(String),
VersionMismatch {
version_file: String,
cargo_manifest: String,
},
InvalidRegistryToken,
CheckFailed(CheckResult),
Io {
action: &'static str,
path: PathBuf,
source: io::Error,
},
Sandbox {
stage: String,
message: String,
},
Publish(String),
}
impl Error {
pub(crate) fn io(action: &'static str, path: impl Into<PathBuf>, source: io::Error) -> Self {
Self::Io {
action,
path: path.into(),
source,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidRustLibName(name) => write!(
f,
"invalid Rust library name {name:?}; use ASCII letters, digits, '-' or '_'"
),
Self::InvalidRustLibPath { path, reason } => {
write!(f, "invalid Rust library path {path:?}: {reason}")
}
Self::RustLibAlreadyExists(name) => {
write!(f, "Rust library {name:?} already exists")
}
Self::RustLibNotFound(name) => write!(f, "Rust library {name:?} was not found"),
Self::RustLibIsNotDirectory(name) => {
write!(f, "Rust library {name:?} is not a directory")
}
Self::DuplicateWritePath(path) => {
write!(f, "write batch contains duplicate path {path:?}")
}
Self::NonUtf8Path(path) => {
write!(
f,
"Rust library contains a non-UTF-8 path: {}",
path.display()
)
}
Self::NonUtf8File(path) => {
write!(f, "Rust library file is not UTF-8: {}", path.display())
}
Self::SymlinkNotAllowed(path) => {
write!(
f,
"Rust library symlinks are not allowed: {}",
path.display()
)
}
Self::UnsupportedFileType(path) => write!(
f,
"Rust library entry is not a regular file or directory: {}",
path.display()
),
Self::RootsOverlap {
rust_libs_root,
work_root,
} => write!(
f,
"Rust libraries root ({}) and work root ({}) must not overlap",
rust_libs_root.display(),
work_root.display()
),
Self::MissingRequiredFile(path) => {
write!(f, "Rust library is missing required file {path}")
}
Self::InvalidVersion(value) => write!(
f,
"invalid Cargo.toml [package].version {value:?}; expected canonical major.minor.patch"
),
Self::InvalidCargoManifest(message) => {
write!(f, "invalid Cargo.toml: {message}")
}
Self::VersionMismatch {
version_file,
cargo_manifest,
} => write!(
f,
"version {version_file} does not match Cargo.toml package version {cargo_manifest}"
),
Self::InvalidRegistryToken => f.write_str("crates.io registry token is empty"),
Self::CheckFailed(result) => {
if let Some(stage) = result.failure() {
write!(
f,
"Rust library cannot be published because its {} check failed",
stage.stage
)
} else {
f.write_str(
"Rust library cannot be published because its full check did not pass",
)
}
}
Self::Io {
action,
path,
source,
} => write!(f, "failed to {action} {}: {source}", path.display()),
Self::Sandbox { stage, message } => {
write!(f, "Podman failed during {stage}: {message}")
}
Self::Publish(message) => write!(f, "crates.io publication failed: {message}"),
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::Io { source, .. } => Some(source),
_ => None,
}
}
}