1
1
use std:: fmt;
2
2
3
- use anyhow:: bail;
4
- use anyhow:: Result ;
5
3
use semver:: Version ;
6
4
use serde:: { de, ser} ;
7
5
use url:: Url ;
@@ -11,6 +9,8 @@ use crate::core::PartialVersion;
11
9
use crate :: core:: SourceKind ;
12
10
use crate :: manifest:: PackageName ;
13
11
12
+ type Result < T > = std:: result:: Result < T , PackageIdSpecError > ;
13
+
14
14
/// Some or all of the data required to identify a package:
15
15
///
16
16
/// 1. the package name (a `String`, required)
@@ -83,12 +83,10 @@ impl PackageIdSpec {
83
83
if abs. exists ( ) {
84
84
let maybe_url = Url :: from_file_path ( abs)
85
85
. map_or_else ( |_| "a file:// URL" . to_string ( ) , |url| url. to_string ( ) ) ;
86
- bail ! (
87
- "package ID specification `{}` looks like a file path, \
88
- maybe try {}",
89
- spec,
90
- maybe_url
91
- ) ;
86
+ return Err ( PackageIdSpecError :: MaybeFilePath {
87
+ spec : spec. into ( ) ,
88
+ maybe_url,
89
+ } ) ;
92
90
}
93
91
}
94
92
let mut parts = spec. splitn ( 2 , [ ':' , '@' ] ) ;
@@ -119,51 +117,44 @@ impl PackageIdSpec {
119
117
}
120
118
"registry" => {
121
119
if url. query ( ) . is_some ( ) {
122
- bail ! ( "cannot have a query string in a pkgid: { url}" )
120
+ return Err ( PackageIdSpecError :: UnexpectedQueryString ( url) ) ;
123
121
}
124
122
kind = Some ( SourceKind :: Registry ) ;
125
123
url = strip_url_protocol ( & url) ;
126
124
}
127
125
"sparse" => {
128
126
if url. query ( ) . is_some ( ) {
129
- bail ! ( "cannot have a query string in a pkgid: { url}" )
127
+ return Err ( PackageIdSpecError :: UnexpectedQueryString ( url) ) ;
130
128
}
131
129
kind = Some ( SourceKind :: SparseRegistry ) ;
132
130
// Leave `sparse` as part of URL, see `SourceId::new`
133
131
// url = strip_url_protocol(&url);
134
132
}
135
133
"path" => {
136
134
if url. query ( ) . is_some ( ) {
137
- bail ! ( "cannot have a query string in a pkgid: { url}" )
135
+ return Err ( PackageIdSpecError :: UnexpectedQueryString ( url) ) ;
138
136
}
139
137
if scheme != "file" {
140
- anyhow :: bail! ( "`path+{ scheme}` is unsupported; `path+file` and `file` schemes are supported" ) ;
138
+ return Err ( PackageIdSpecError :: UnsupportedPathPlusScheme ( scheme. into ( ) ) ) ;
141
139
}
142
140
kind = Some ( SourceKind :: Path ) ;
143
141
url = strip_url_protocol ( & url) ;
144
142
}
145
- kind => anyhow :: bail! ( "unsupported source protocol: { kind}" ) ,
143
+ kind => return Err ( PackageIdSpecError :: UnsupportedProtocol ( kind. into ( ) ) ) ,
146
144
}
147
145
} else {
148
146
if url. query ( ) . is_some ( ) {
149
- bail ! ( "cannot have a query string in a pkgid: { url}" )
147
+ return Err ( PackageIdSpecError :: UnexpectedQueryString ( url) ) ;
150
148
}
151
149
}
152
150
153
151
let frag = url. fragment ( ) . map ( |s| s. to_owned ( ) ) ;
154
152
url. set_fragment ( None ) ;
155
153
156
154
let ( name, version) = {
157
- let mut path = url
158
- . path_segments ( )
159
- . ok_or_else ( || anyhow:: format_err!( "pkgid urls must have a path: {}" , url) ) ?;
160
- let path_name = path. next_back ( ) . ok_or_else ( || {
161
- anyhow:: format_err!(
162
- "pkgid urls must have at least one path \
163
- component: {}",
164
- url
165
- )
166
- } ) ?;
155
+ let Some ( path_name) = url. path_segments ( ) . and_then ( |mut p| p. next_back ( ) ) else {
156
+ return Err ( PackageIdSpecError :: MissingUrlPath ( url) ) ;
157
+ } ;
167
158
match frag {
168
159
Some ( fragment) => match fragment. split_once ( [ ':' , '@' ] ) {
169
160
Some ( ( name, part) ) => {
@@ -259,7 +250,7 @@ impl fmt::Display for PackageIdSpec {
259
250
}
260
251
261
252
impl ser:: Serialize for PackageIdSpec {
262
- fn serialize < S > ( & self , s : S ) -> Result < S :: Ok , S :: Error >
253
+ fn serialize < S > ( & self , s : S ) -> std :: result :: Result < S :: Ok , S :: Error >
263
254
where
264
255
S : ser:: Serializer ,
265
256
{
@@ -268,7 +259,7 @@ impl ser::Serialize for PackageIdSpec {
268
259
}
269
260
270
261
impl < ' de > de:: Deserialize < ' de > for PackageIdSpec {
271
- fn deserialize < D > ( d : D ) -> Result < PackageIdSpec , D :: Error >
262
+ fn deserialize < D > ( d : D ) -> std :: result :: Result < PackageIdSpec , D :: Error >
272
263
where
273
264
D : de:: Deserializer < ' de > ,
274
265
{
@@ -277,6 +268,32 @@ impl<'de> de::Deserialize<'de> for PackageIdSpec {
277
268
}
278
269
}
279
270
271
+ /// Error parsing a [`PackageIdSpec`].
272
+ #[ non_exhaustive]
273
+ #[ derive( Debug , thiserror:: Error ) ]
274
+ pub enum PackageIdSpecError {
275
+ #[ error( "unsupported source protocol: {0}" ) ]
276
+ UnsupportedProtocol ( String ) ,
277
+
278
+ #[ error( "`path+{0}` is unsupported; `path+file` and `file` schemes are supported" ) ]
279
+ UnsupportedPathPlusScheme ( String ) ,
280
+
281
+ #[ error( "cannot have a query string in a pkgid: {0}" ) ]
282
+ UnexpectedQueryString ( Url ) ,
283
+
284
+ #[ error( "pkgid urls must have at least one path component: {0}" ) ]
285
+ MissingUrlPath ( Url ) ,
286
+
287
+ #[ error( "package ID specification `{spec}` looks like a file path, maybe try {maybe_url}" ) ]
288
+ MaybeFilePath { spec : String , maybe_url : String } ,
289
+
290
+ #[ error( transparent) ]
291
+ NameValidation ( #[ from] crate :: restricted_names:: NameValidationError ) ,
292
+
293
+ #[ error( transparent) ]
294
+ PartialVersion ( #[ from] crate :: core:: PartialVersionError ) ,
295
+ }
296
+
280
297
#[ cfg( test) ]
281
298
mod tests {
282
299
use super :: PackageIdSpec ;
0 commit comments