refactor(util-schemas): error type for PackageIdSpec

This commit is contained in:
Weihang Lo 2023-12-19 13:25:49 -05:00
parent a3267bfa29
commit 1e577614c5
No known key found for this signature in database
GPG key ID: D7DBF189825E82E7
4 changed files with 47 additions and 29 deletions

View file

@ -3,6 +3,7 @@ mod partial_version;
mod source_kind;
pub use package_id_spec::PackageIdSpec;
pub use package_id_spec::PackageIdSpecError;
pub use partial_version::PartialVersion;
pub use partial_version::PartialVersionError;
pub use source_kind::GitReference;

View file

@ -1,7 +1,5 @@
use std::fmt;
use anyhow::bail;
use anyhow::Result;
use semver::Version;
use serde::{de, ser};
use url::Url;
@ -11,6 +9,8 @@ use crate::core::PartialVersion;
use crate::core::SourceKind;
use crate::manifest::PackageName;
type Result<T> = std::result::Result<T, PackageIdSpecError>;
/// Some or all of the data required to identify a package:
///
/// 1. the package name (a `String`, required)
@ -83,12 +83,10 @@ impl PackageIdSpec {
if abs.exists() {
let maybe_url = Url::from_file_path(abs)
.map_or_else(|_| "a file:// URL".to_string(), |url| url.to_string());
bail!(
"package ID specification `{}` looks like a file path, \
maybe try {}",
spec,
maybe_url
);
return Err(PackageIdSpecError::MaybeFilePath {
spec: spec.into(),
maybe_url,
});
}
}
let mut parts = spec.splitn(2, [':', '@']);
@ -119,14 +117,14 @@ impl PackageIdSpec {
}
"registry" => {
if url.query().is_some() {
bail!("cannot have a query string in a pkgid: {url}")
return Err(PackageIdSpecError::UnexpectedQueryString(url));
}
kind = Some(SourceKind::Registry);
url = strip_url_protocol(&url);
}
"sparse" => {
if url.query().is_some() {
bail!("cannot have a query string in a pkgid: {url}")
return Err(PackageIdSpecError::UnexpectedQueryString(url));
}
kind = Some(SourceKind::SparseRegistry);
// Leave `sparse` as part of URL, see `SourceId::new`
@ -134,19 +132,19 @@ impl PackageIdSpec {
}
"path" => {
if url.query().is_some() {
bail!("cannot have a query string in a pkgid: {url}")
return Err(PackageIdSpecError::UnexpectedQueryString(url));
}
if scheme != "file" {
anyhow::bail!("`path+{scheme}` is unsupported; `path+file` and `file` schemes are supported");
return Err(PackageIdSpecError::UnsupportedPathPlusScheme(scheme.into()));
}
kind = Some(SourceKind::Path);
url = strip_url_protocol(&url);
}
kind => anyhow::bail!("unsupported source protocol: {kind}"),
kind => return Err(PackageIdSpecError::UnsupportedProtocol(kind.into())),
}
} else {
if url.query().is_some() {
bail!("cannot have a query string in a pkgid: {url}")
return Err(PackageIdSpecError::UnexpectedQueryString(url));
}
}
@ -154,16 +152,9 @@ impl PackageIdSpec {
url.set_fragment(None);
let (name, version) = {
let mut path = url
.path_segments()
.ok_or_else(|| anyhow::format_err!("pkgid urls must have a path: {}", url))?;
let path_name = path.next_back().ok_or_else(|| {
anyhow::format_err!(
"pkgid urls must have at least one path \
component: {}",
url
)
})?;
let Some(path_name) = url.path_segments().and_then(|mut p| p.next_back()) else {
return Err(PackageIdSpecError::MissingUrlPath(url));
};
match frag {
Some(fragment) => match fragment.split_once([':', '@']) {
Some((name, part)) => {
@ -259,7 +250,7 @@ impl fmt::Display for PackageIdSpec {
}
impl ser::Serialize for PackageIdSpec {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
@ -268,7 +259,7 @@ impl ser::Serialize for PackageIdSpec {
}
impl<'de> de::Deserialize<'de> for PackageIdSpec {
fn deserialize<D>(d: D) -> Result<PackageIdSpec, D::Error>
fn deserialize<D>(d: D) -> std::result::Result<PackageIdSpec, D::Error>
where
D: de::Deserializer<'de>,
{
@ -277,6 +268,32 @@ impl<'de> de::Deserialize<'de> for PackageIdSpec {
}
}
/// Error parsing a [`PackageIdSpec`].
#[non_exhaustive]
#[derive(Debug, thiserror::Error)]
pub enum PackageIdSpecError {
#[error("unsupported source protocol: {0}")]
UnsupportedProtocol(String),
#[error("`path+{0}` is unsupported; `path+file` and `file` schemes are supported")]
UnsupportedPathPlusScheme(String),
#[error("cannot have a query string in a pkgid: {0}")]
UnexpectedQueryString(Url),
#[error("pkgid urls must have at least one path component: {0}")]
MissingUrlPath(Url),
#[error("package ID specification `{spec}` looks like a file path, maybe try {maybe_url}")]
MaybeFilePath { spec: String, maybe_url: String },
#[error(transparent)]
NameValidation(#[from] crate::restricted_names::NameValidationError),
#[error(transparent)]
PartialVersion(#[from] crate::core::PartialVersionError),
}
#[cfg(test)]
mod tests {
use super::PackageIdSpec;

View file

@ -72,7 +72,7 @@ impl Packages {
let mut specs = packages
.iter()
.map(|p| PackageIdSpec::parse(p))
.collect::<CargoResult<Vec<_>>>()?;
.collect::<Result<Vec<_>, _>>()?;
if !patterns.is_empty() {
let matched_pkgs = ws
.members()

View file

@ -186,7 +186,7 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
opts.invert
.iter()
.map(|p| PackageIdSpec::parse(p))
.collect::<CargoResult<Vec<PackageIdSpec>>>()?
.collect::<Result<Vec<PackageIdSpec>, _>>()?
};
let root_ids = ws_resolve.targeted_resolve.specs_to_ids(&root_specs)?;
let root_indexes = graph.indexes_from_ids(&root_ids);
@ -207,7 +207,7 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
let pkgs_to_prune = opts
.pkgs_to_prune
.iter()
.map(|p| PackageIdSpec::parse(p))
.map(|p| PackageIdSpec::parse(p).map_err(Into::into))
.map(|r| {
// Provide an error message if pkgid is not within the resolved
// dependencies graph.