use std::{
io,
path::{Path, PathBuf},
process::ExitStatus,
};
use guppy::errors::Error as GuppyError;
use guppy::graph::PackageLink;
use thiserror::Error;
use toml_edit::TomlError as TomlEditError;
use url::ParseError;
use super::DependencyType;
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
WorkspaceError(WorkspaceError),
#[error("Workspace has at least one cycle that includes as least {crate1} and {crate2}")]
WorkspaceCycles {
crate1: String,
crate2: String,
},
#[error("Unable to write to the output")]
OutputError(#[source] io::Error),
#[error("Conditions for a release are not satisfied: {reason}")]
VerifyError {
reason: String,
},
#[error("{typ} of {from} on {to} prevents publication of {from}")]
BadDependency {
from: String,
to: String,
typ: DependencyType,
},
#[error("Unable to read file {}", path.display())]
FileReadError {
#[source]
inner: io::Error,
path: PathBuf,
},
#[error("Unable to write file {}", path.display())]
FileWriteError {
#[source]
inner: io::Error,
path: PathBuf,
},
#[error(transparent)]
TomlError(TomlError),
#[error("Unexpected contents of {manifest_path}")]
CargoTomlError {
#[source]
inner: CargoTomlError,
manifest_path: PathBuf,
},
#[error("Unable to run \"cargo publish\" for {manifest_path}")]
CargoPublish {
#[source]
inner: io::Error,
manifest_path: PathBuf,
},
#[error("\"cargo publish\" exited with a failure for {manifest_path}: {status}")]
CargoPublishStatus {
status: ExitStatus,
manifest_path: PathBuf,
},
#[error(transparent)]
UrlError(UrlError),
#[error(transparent)]
WriteReleaseError(WriteReleaseError),
#[error("Unable to update Cargo lockfile")]
CargoLockfileUpdate {
reason: String,
package_name: String,
},
}
pub type Result<T> = std::result::Result<T, anyhow::Error>;
#[derive(Debug, Error)]
#[error("Unable to parse the workspace structure starting at {manifest_path}")]
pub struct WorkspaceError {
#[source]
metadata_error: GuppyError,
manifest_path: PathBuf,
}
#[derive(Debug, Error)]
#[error("Unable to parse {} as a TOML file", path.display())]
pub struct TomlError {
#[source]
inner: TomlEditError,
path: PathBuf,
}
#[derive(Debug, Error)]
pub enum CargoTomlError {
#[error("Unable to locate expected table {table_name}")]
NoTable {
table_name: String,
},
#[error("Unable to located expected value {value_name}")]
NoValue {
value_name: String,
},
#[error("Unable to set the version for {name} to {version}")]
SetVersion {
name: String,
version: String,
},
}
#[derive(Debug, Error)]
#[error("Unable to parse url for displaying release record.")]
pub struct UrlError {
#[source]
inner: ParseError,
}
#[derive(Debug, Error)]
#[error("Unable to write the release record for {main_crate} as JSON.")]
pub struct WriteReleaseError {
#[source]
inner: serde_json::Error,
main_crate: String,
}
impl Error {
pub(crate) fn workspace_error(metadata_error: GuppyError, manifest_path: PathBuf) -> Error {
Error::WorkspaceError(WorkspaceError {
metadata_error,
manifest_path,
})
}
pub(crate) fn output_error(inner: io::Error) -> Error {
Error::OutputError(inner)
}
pub(crate) fn verify_error(reason: impl Into<String>) -> Error {
Error::VerifyError {
reason: reason.into(),
}
}
pub(crate) fn bad_dependency(link: &PackageLink, typ: DependencyType) -> Error {
Error::BadDependency {
from: link.from().name().to_string(),
to: link.to().name().to_string(),
typ,
}
}
pub(crate) fn file_read_error(inner: io::Error, path: impl AsRef<Path>) -> Error {
Error::FileReadError {
inner,
path: path.as_ref().to_owned(),
}
}
pub(crate) fn file_write_error(inner: io::Error, path: impl AsRef<Path>) -> Error {
Error::FileWriteError {
inner,
path: path.as_ref().to_owned(),
}
}
pub(crate) fn toml_error(inner: TomlEditError, path: impl AsRef<Path>) -> Error {
Error::TomlError(TomlError {
inner,
path: path.as_ref().to_owned(),
})
}
pub(crate) fn cargo_publish(inner: io::Error, manifest_path: &Path) -> Error {
Error::CargoPublish {
inner,
manifest_path: manifest_path.to_owned(),
}
}
pub(crate) fn cargo_publish_status(status: ExitStatus, manifest_path: &Path) -> Error {
Error::CargoPublishStatus {
status,
manifest_path: manifest_path.to_owned(),
}
}
pub(crate) fn url_parse_error(inner: ParseError) -> Error {
Error::UrlError(UrlError { inner })
}
pub(crate) fn write_release_error(inner: serde_json::Error, main_crate: &str) -> Error {
Error::WriteReleaseError(WriteReleaseError {
inner,
main_crate: main_crate.to_owned(),
})
}
}
impl CargoTomlError {
pub(crate) fn no_table(table: &str) -> Self {
Self::NoTable {
table_name: table.to_owned(),
}
}
pub(crate) fn no_value(value: &str) -> Self {
Self::NoValue {
value_name: value.to_owned(),
}
}
pub(crate) fn set_version(name: &str, version: &str) -> Self {
Self::SetVersion {
name: name.to_owned(),
version: version.to_owned(),
}
}
pub(crate) fn into_error(self, path: impl AsRef<Path>) -> Error {
Error::CargoTomlError {
inner: self,
manifest_path: path.as_ref().to_owned(),
}
}
}