Skip to content

Commit

Permalink
feat(errors): better docs and url(docsrs) for all errors
Browse files Browse the repository at this point in the history
Fixes: #248
  • Loading branch information
zkat committed Apr 18, 2023
1 parent 1c73345 commit 0629a08
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 62 deletions.
80 changes: 61 additions & 19 deletions crates/nassun/src/error.rs
Expand Up @@ -9,79 +9,106 @@ use thiserror::Error;
/// Error type returned by all API calls.
#[derive(Error, Debug, Diagnostic)]
pub enum NassunError {
/// Something went wrong while fetching a package.
/// A given package exists, but the version that the specifier resolved to
/// does not.
///
/// Check that the version or range you're requesting actually exists and
/// try again.
#[error("Package for `{0}` was found, but resolved version `{1}` does not exist.")]
#[diagnostic(
code(nassun::missing_version),
url(docsrs),
help("Try using `oro view` to see what versions are available")
)]
MissingVersion(PackageSpec, Version),

/// Something went wrong while trying to parse a PackageArg
/// Something went wrong while trying to parse a PackageSpec.
#[error(transparent)]
#[diagnostic(transparent)]
PackageSpecError(#[from] oro_package_spec::PackageSpecError),

/// Failed to read a directory dependency. Refer to the error message for
/// more details.
#[error("{0}")]
#[diagnostic(code(nassun::dir::read))]
#[diagnostic(code(nassun::dir::read), url(docsrs))]
DirReadError(#[source] std::io::Error, PathBuf),

/// An io-related error occurred while executing git.
#[error("Failed to execute git subprocess. {0}")]
#[diagnostic(code(nassun::git::clone::io))]
#[diagnostic(code(nassun::git::clone::io), url(docsrs))]
GitIoError(#[source] std::io::Error),

/// An error occurred while trying to clone a repository.
#[error("Failed to clone repository at `{0}`")]
#[diagnostic(code(nassun::git::clone::repo))]
#[diagnostic(code(nassun::git::clone::repo), url(docsrs))]
GitCloneError(String),

/// An error occurred while trying to checkout a repository.
#[error("Failed to check out `{0}#{1}`")]
#[diagnostic(code(nassun::git::checkout::repo))]
#[diagnostic(code(nassun::git::checkout::repo), url(docsrs))]
GitCheckoutError(String, String),

/// Failed to extract a tarball while doing a certain IO operation. Refer
/// to the error message for more details.
#[error("Failed to extract tarball while {2}{}", if let Some(path) = .1 {
format!(" (file: {})", path.to_string_lossy())
} else {
"".to_string()
})]
#[diagnostic(code(nassun::io::extract))]
#[diagnostic(code(nassun::io::extract), url(docsrs))]
ExtractIoError(#[source] std::io::Error, Option<PathBuf>, String),

/// Failed to extract a tarball to the cache. Refer to the error message
/// for more details.
#[cfg(not(target_arch = "wasm32"))]
#[error("Failed to extract tarball to cache. {0}{}", if let Some(path) = .1 {
format!(" (file: {})", path.to_string_lossy())
} else {
"".to_string()
})]
#[diagnostic(code(nassun::cache::extract))]
#[diagnostic(code(nassun::cache::extract), url(docsrs))]
ExtractCacheError(#[source] cacache::Error, Option<PathBuf>),

/// A generic IO error occurred. Refer tot he error message for more
/// details.
#[error(transparent)]
#[diagnostic(code(nassun::io::generic))]
#[diagnostic(code(nassun::io::generic), url(docsrs))]
IoError(#[from] std::io::Error),

/// A generic oro-client error.
#[error(transparent)]
#[diagnostic(transparent)]
OroClientError(#[from] oro_client::OroClientError),

/// A generic serde error.
#[error(transparent)]
#[diagnostic(code(nassun::serde))]
#[diagnostic(code(nassun::serde), url(docsrs))]
SerdeError(#[from] serde_json::Error),

/// Failed to parse a URL.
#[error(transparent)]
#[diagnostic(code(nassun::bad_url))]
#[diagnostic(code(nassun::bad_url), url(docsrs))]
UrlError(#[from] url::ParseError),

/// Failed to parse a package integrity string.
#[error(transparent)]
#[diagnostic(code(nassun::integrity_parse_error))]
#[diagnostic(code(nassun::integrity_parse_error), url(docsrs))]
IntegrityError(#[from] ssri::Error),

/// There's no tarball specified as part of the package metadata for a
/// given package. This is likely a bug in the registry.
#[error("Package metadata for {0} is missing a package tarball URL.")]
#[diagnostic(code(nassun::no_tarball))]
#[diagnostic(code(nassun::no_tarball), url(docsrs))]
NoTarball(String, PackageSpec, Box<CorgiVersionMetadata>),

/// No matching version could be found for a given specifier. Make sure
/// that the version, range, or dist-tag you requested actually exists.
///
/// Using `oro view` can help.
#[error("No matching `{name}` version found for spec `{spec}`.")]
#[diagnostic(
code(resolver::no_matching_version),
url(docsrs),
// TODO: format help string using variables?
help("Try using `oro view` to see what versions are available")
)]
Expand All @@ -91,36 +118,51 @@ pub enum NassunError {
versions: Vec<String>,
},

/// Generic serde-wasm-bindgen error.
#[cfg(target_arch = "wasm32")]
#[error(transparent)]
#[diagnostic(code(node_maintainer::serde_wasm_bindgen::error))]
#[diagnostic(code(node_maintainer::serde_wasm_bindgen::error), url(docsrs))]
SerdeWasmBindgenError(#[from] serde_wasm_bindgen::Error),

/// Failed to find git in the user's `$PATH`.
///
/// Make sure git is installed and visible from the executing shell's `$PATH`.
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
#[diagnostic(
code(nassun::which_git_failure),
url(docsrs),
help("Are you sure git is installed and available in your $PATH?")
)]
WhichGit(#[from] which::Error),

#[error("Only Version, Tag, Range, and Alias package args are supported, but got `{0}`.")]
#[diagnostic(code(nassun::invalid_package_spec))]
/// The version resolver ran into an unexpected package spec. This is
/// almost definitely a bug.
#[error("Only Version, Tag, Range, and Alias package specs are supported, but got `{0}`.")]
#[diagnostic(code(nassun::invalid_package_spec), url(docsrs))]
InvalidPackageSpec(PackageSpec),

/// Some unsupported operation happened while working with a dummy
/// package. This is an internal detail and almost definitely a bug worth
/// reporting.
#[error("Unsupported dummy package operation: {0}")]
#[diagnostic(code(nassun::unsupported_dummy_operation))]
#[diagnostic(code(nassun::unsupported_dummy_operation), url(docsrs))]
UnsupportedDummyOperation(String),

/// A dummy package was missing a name. This is an internal detail and
/// almost definitely a bug worth reporting.
#[error("Dummy package does not have a name.")]
#[diagnostic(code(nassun::dummy_no_name))]
#[diagnostic(code(nassun::dummy_no_name), url(docsrs))]
DummyNoName,

/// A miscellaneous, usually internal error. This is used mainly to wrap
/// either manual InternalErrors, or those using external errors that
/// don't implement std::error::Error.
///
/// If you see this error, please file a bug report so that a better error
/// can take its place.
#[error("{0}")]
#[diagnostic(code(nassun::misc))]
#[diagnostic(code(nassun::misc), url(docsrs))]
MiscError(String),
}

Expand Down
60 changes: 36 additions & 24 deletions crates/node-maintainer/src/error.rs
Expand Up @@ -10,82 +10,85 @@ use crate::{NpmPackageLock, NpmPackageLockEntry};
pub enum NodeMaintainerError {
/// Unsupported resolved URL scheme
#[error("Unsupported resolved URL scheme")]
#[diagnostic(code(node_maintainer::kdl::unsupported_url_scheme))]
#[diagnostic(code(node_maintainer::kdl::unsupported_url_scheme), url(docsrs))]
UnsupportedScheme(String),

/// Failed to parse a resolved URL while parsing lockfile
#[error("Failed to parse a resolved URL while parsing lockfile: {0}")]
#[diagnostic(code(node_maintainer::kdl::url_parse_error))]
#[diagnostic(code(node_maintainer::kdl::url_parse_error), url(docsrs))]
UrlParseError(String, #[source] url::ParseError),

/// Failed to parse a Semver string.
#[error("Failed to parse a Semver string.")]
#[diagnostic(code(node_maintainer::kdl::semver_parse_error))]
#[diagnostic(code(node_maintainer::kdl::semver_parse_error), url(docsrs))]
SemverParseError(#[from] node_semver::SemverError),

/// Missing version for NPM package entry in lockfile.
#[error("Missing version for NPM package entry in lockfile.")]
#[diagnostic(code(node_maintainer::kdl::missing_version))]
#[diagnostic(code(node_maintainer::kdl::missing_version), url(docsrs))]
MissingVersion,

/// Missing resolution for package entry in lockfile.
#[error("Missing version for NPM package entry in lockfile.")]
#[diagnostic(code(node_maintainer::kdl::missing_version))]
#[diagnostic(code(node_maintainer::kdl::missing_version), url(docsrs))]
MissingResolution,

/// Failed to parse an integrity value.
#[error(transparent)]
#[diagnostic(code(node_maintainer::kdl::integrity_parse_error))]
#[diagnostic(code(node_maintainer::kdl::integrity_parse_error), url(docsrs))]
IntegrityParseError(#[from] ssri::Error),

/// Failed to parse an integrity value while loading lockfile.
#[error("Failed to parse an integrity value while loading lockfile node:\n{0}")]
#[diagnostic(code(node_maintainer::kdl::integrity_parse_error))]
#[diagnostic(code(node_maintainer::kdl::integrity_parse_error), url(docsrs))]
KdlLockfileIntegrityParseError(KdlNode, #[source] ssri::Error),

/// Missing package node name.
#[error("Missing package node name:\n{0}")]
#[diagnostic(code(node_maintainer::kdl::missing_node_name))]
#[diagnostic(code(node_maintainer::kdl::missing_node_name), url(docsrs))]
KdlLockMissingName(KdlNode),

/// Missing package node name.
#[error("Missing package name:\n{0:#?}")]
#[diagnostic(code(node_maintainer::npm::missing_name))]
#[diagnostic(code(node_maintainer::npm::missing_name), url(docsrs))]
NpmLockMissingName(Box<NpmPackageLockEntry>),

/// Failed to parse an integrity value while loading NPM lockfile.
#[error("Failed to parse an integrity value while loading lockfile node:\n{0:#?}")]
#[diagnostic(code(node_maintainer::npm::integrity_parse_error))]
#[diagnostic(code(node_maintainer::npm::integrity_parse_error), url(docsrs))]
NpmLockfileIntegrityParseError(Box<NpmPackageLockEntry>, #[source] ssri::Error),

/// Unsupported NPM Package Lock version.
#[error("Unsupported NPM Package Lock version: {0}")]
#[diagnostic(code(node_maintainer::npm::unsupported_package_lock_Version))]
#[diagnostic(
code(node_maintainer::npm::unsupported_package_lock_Version),
url(docsrs)
)]
NpmUnsupportedPackageLockVersion(u64),

/// No root node in KDL lockfile.
#[error("No root node in KDL lockfile.")]
#[diagnostic(code(node_maintainer::kdl::missing_root))]
#[diagnostic(code(node_maintainer::kdl::missing_root), url(docsrs))]
KdlLockMissingRoot(KdlDocument),

/// No root node in NPM lockfile.
#[error("No root package in NPM lockfile.")]
#[diagnostic(code(node_maintainer::npm::missing_root))]
#[diagnostic(code(node_maintainer::npm::missing_root), url(docsrs))]
NpmLockMissingRoot(NpmPackageLock),

/// Error parsing lockfile.
#[error(transparent)]
#[diagnostic(code(node_maintainer::kdl::parse_error))]
#[diagnostic(code(node_maintainer::kdl::parse_error), url(docsrs))]
KdlParseError(#[from] kdl::KdlError),

#[error("Invalid lockfile version format.")]
#[diagnostic(code(node_maintainer::kdl::invalid_lockfile_version))]
#[diagnostic(code(node_maintainer::kdl::invalid_lockfile_version), url(docsrs))]
InvalidLockfileVersion,

/// Error from serde_wasm_bindgen
#[cfg(target_arch = "wasm32")]
#[error(transparent)]
#[diagnostic(code(node_maintainer::serde_wasm_bindgen::error))]
#[diagnostic(code(node_maintainer::serde_wasm_bindgen::error), url(docsrs))]
SerdeWasmBindgenError(#[from] serde_wasm_bindgen::Error),

/// Generic package spec error.
Expand All @@ -95,7 +98,7 @@ pub enum NodeMaintainerError {

/// Generic IO Error.
#[error(transparent)]
#[diagnostic(code(node_maintainer::io_error))]
#[diagnostic(code(node_maintainer::io_error), url(docsrs))]
IoError(#[from] std::io::Error),

/// Generic error returned from Nassun.
Expand All @@ -105,32 +108,41 @@ pub enum NodeMaintainerError {

/// Generic serde_json error.
#[error(transparent)]
#[diagnostic(code(node_maintainer::serde_json_error))]
#[diagnostic(code(node_maintainer::serde_json_error), url(docsrs))]
SerdeJsonError(#[from] serde_json::Error),

/// Generic error
/// Generic error. Refer to the error message for more details.
#[error("{0}")]
#[diagnostic(code(node_maintainer::miscellaneous_error))]
#[diagnostic(code(node_maintainer::miscellaneous_error), url(docsrs))]
MiscError(String),

/// Failed to send data through mpsc channel. This is likely an internal
/// error of some sort.
#[error("Failed to send data through mpsc channel.")]
#[diagnostic(code(node_maintainer::mpsc_error))]
#[diagnostic(code(node_maintainer::mpsc_error), url(docsrs))]
TrySendError,

/// Failed to validate a graph. Refer to the error message for more details.
#[error("{0}")]
#[diagnostic(code(node_maintainer::graph_error))]
#[diagnostic(code(node_maintainer::graph_error), url(docsrs))]
GraphValidationError(String),

/// Got an error while walking `node_modules`. Refer to the error message
/// for specific details.
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
#[diagnostic(code(node_maintainer::walkdir_error))]
#[diagnostic(code(node_maintainer::walkdir_error), url(docsrs))]
WalkDirError(#[from] walkdir::Error),

/// Failed to read `package.json` during the build step. Refer to the
/// error message for more details.
#[cfg(not(target_arch = "wasm32"))]
#[error("Failed to read manifest during build step, at {}", .0.display())]
#[diagnostic(code(node_maintainer::build_manifest_read_error))]
#[diagnostic(code(node_maintainer::build_manifest_read_error), url(docsrs))]
BuildManifestReadError(std::path::PathBuf, #[source] std::io::Error),

/// Some error occurred while running a script. Refer to the error message
/// for more details.
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
#[diagnostic(transparent)]
Expand Down
19 changes: 14 additions & 5 deletions crates/oro-client/src/error.rs
Expand Up @@ -4,17 +4,22 @@ use thiserror::Error;

#[derive(Debug, Error, Diagnostic)]
pub enum OroClientError {
/// An invalid URL was provided.
#[error(transparent)]
#[diagnostic(code(oro_client::url_parse_error))]
#[diagnostic(code(oro_client::url_parse_error), url(docsrs))]
UrlParseError(#[from] url::ParseError),

/// The package was not found in the registry.
///
/// Make sure the package name is spelled correctly and that you've
/// configured the right registry to fetch it from.
#[error("Package `{1}` was not found in registry {0}.")]
#[diagnostic(code(oro_client::package_not_found))]
#[diagnostic(code(oro_client::package_not_found), url(docsrs))]
PackageNotFound(Url, String),

/// Got some bad JSON we couldn't parse.
#[error("Received some unexpected JSON. Unable to parse.")]
#[diagnostic(code(oro_client::bad_json))]
#[diagnostic(code(oro_client::bad_json), url(docsrs))]
BadJson {
source: serde_json::Error,
url: String,
Expand All @@ -24,13 +29,17 @@ pub enum OroClientError {
err_loc: (usize, usize),
},

/// A generic request error happened while making a request. Refer to the
/// error message for more details.
#[error(transparent)]
#[diagnostic(code(oro_client::request_error))]
#[diagnostic(code(oro_client::request_error), url(docsrs))]
RequestError(#[from] reqwest::Error),

/// A generic request middleware error happened while making a request.
/// Refer to the error message for more details.
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
#[diagnostic(code(oro_client::request_middleware_error))]
#[diagnostic(code(oro_client::request_middleware_error), url(docsrs))]
RequestMiddlewareError(#[from] reqwest_middleware::Error),
}

Expand Down

0 comments on commit 0629a08

Please sign in to comment.