Skip to content

Commit 1ea7352

Browse files
committed
use url::Url for parsing the Cargo Package ID Spc URL format
instead of manual disecting the string
1 parent db87bed commit 1ea7352

File tree

1 file changed

+83
-80
lines changed

1 file changed

+83
-80
lines changed

src/crates/mod.rs

Lines changed: 83 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -120,30 +120,24 @@ impl TryFrom<&'_ PackageId> for Crate {
120120
pkgid.repr
121121
),
122122
}
123-
} else if let Some((kind_proto, host_path_query_anchor)) = pkgid.repr.split_once("://") {
124-
let (kind, proto) = if let Some((kind, proto)) = kind_proto.split_once('+') {
123+
} else if pkgid.repr.contains("://") {
124+
// Cargo Package Id Spec URL format
125+
// <https://doc.rust-lang.org/cargo/reference/pkgid-spec.html>
126+
127+
let pkg_url = url::Url::parse(&pkgid.repr)?;
128+
129+
let (kind, proto) = if let Some((kind, proto)) = pkg_url.scheme().split_once('+') {
125130
(Some(kind), proto)
126131
} else {
127-
(None, kind_proto)
132+
(None, pkg_url.scheme())
128133
};
129134

130-
let (host_path_query, anchor) =
131-
if let Some((host_path_query, anchor)) = host_path_query_anchor.split_once('#') {
132-
(host_path_query, Some(anchor))
133-
} else {
134-
(host_path_query_anchor, None)
135-
};
135+
let anchor = pkg_url.fragment();
136+
let query = pkg_url.query();
136137

137-
let (host_path, query) =
138-
if let Some((host_path, query)) = host_path_query.split_once('?') {
139-
(host_path, Some(query))
140-
} else {
141-
(host_path_query, None)
142-
};
143-
144-
match (kind, proto, query) {
145-
(Some("path") | None, "file", None) => Ok(Crate::Path(host_path.to_string())),
146-
(Some("registry"), _, None) => {
138+
match (kind, proto) {
139+
(Some("path") | None, "file") => Ok(Crate::Path(pkg_url.path().to_string())),
140+
(Some("registry"), _) => {
147141
if let Some(anchor) = anchor {
148142
if let Some((package_name, version)) = anchor.split_once(['@', ':']) {
149143
Ok(Crate::Registry(RegistryCrate {
@@ -175,7 +169,9 @@ impl TryFrom<&'_ PackageId> for Crate {
175169
)
176170
}
177171

178-
let Some(package_name) = host_path.split('/').last() else {
172+
let Some(package_name) =
173+
pkg_url.path_segments().and_then(|segments| segments.last())
174+
else {
179175
bail!(
180176
"malformed pkgid format: {}\n maybe the representation has changed?",
181177
pkgid.repr
@@ -194,73 +190,68 @@ impl TryFrom<&'_ PackageId> for Crate {
194190
)
195191
}
196192
}
197-
(None, "http" | "https", _) | (Some("git"), _, _)
198-
if host_path.starts_with("github.com/") =>
199-
{
200-
let mut parts = host_path.split('/').skip(1);
201-
let Some(org) = parts.next() else {
202-
bail!(
193+
(Some("git"), _) | (None, "ssh" | "git" | "http" | "https") => {
194+
let sha = if let Some(query) = query {
195+
let Some((query_kind, rev)) = query.split_once('=') else {
196+
bail!(
197+
"malformed pkgid format: {}\n maybe the representation has changed?",
198+
pkgid.repr
199+
)
200+
};
201+
match query_kind {
202+
"branch" | "tag" | "rev" => Some(rev.to_string()),
203+
_ => {
204+
bail!(
203205
"malformed pkgid format: {}\n maybe the representation has changed?",
204206
pkgid.repr
205207
)
208+
}
209+
}
210+
} else {
211+
None
206212
};
207213

208-
let name = if let Some((package_name, _version)) =
209-
anchor.and_then(|anchor| anchor.split_once(['@', ':']))
210-
{
211-
package_name
212-
} else if let Some(name) = parts.next() {
213-
name
214-
} else {
215-
bail!(
214+
if pkg_url.domain() == Some("github.com") {
215+
let Some(org) = pkg_url
216+
.path_segments()
217+
.and_then(|mut segments| segments.next())
218+
else {
219+
bail!(
216220
"malformed pkgid format: {}\n maybe the representation has changed?",
217221
pkgid.repr
218222
)
219-
};
220-
221-
Ok(Crate::GitHub(GitHubRepo {
222-
org: org.to_string(),
223-
name: name.to_string(),
224-
sha: None,
225-
}))
226-
}
223+
};
227224

228-
(Some("git"), _, None) | (None, "ssh" | "git" | "http" | "https", None) => {
229-
let kind = if let Some(kind) = kind {
230-
format! {"{kind}+"}
231-
} else {
232-
String::new()
233-
};
234-
Ok(Crate::Git(GitRepo {
235-
url: format!("{kind}{proto}://{host_path}"),
236-
sha: None,
237-
}))
238-
}
239-
(Some("git"), _, Some(query))
240-
| (None, "ssh" | "git" | "http" | "https", Some(query)) => {
241-
let Some((query_kind, rev)) = query.split_once('=') else {
242-
bail!(
225+
let name = if let Some((package_name, _version)) =
226+
anchor.and_then(|anchor| anchor.split_once(['@', ':']))
227+
{
228+
package_name
229+
} else if let Some(name) = pkg_url
230+
.path_segments()
231+
.and_then(|mut segments| segments.nth(1))
232+
{
233+
name
234+
} else {
235+
bail!(
243236
"malformed pkgid format: {}\n maybe the representation has changed?",
244237
pkgid.repr
245238
)
246-
};
239+
};
247240

248-
let kind = if let Some(kind) = kind {
249-
format! {"{kind}+"}
241+
Ok(Crate::GitHub(GitHubRepo {
242+
org: org.to_string(),
243+
name: name.to_string(),
244+
sha,
245+
}))
250246
} else {
251-
String::new()
252-
};
253-
match query_kind {
254-
"branch" | "tag" | "rev" => Ok(Crate::Git(GitRepo {
255-
url: format!("{kind}{proto}://{host_path}"),
256-
sha: Some(rev.to_string()),
257-
})),
258-
_ => {
259-
bail!(
260-
"malformed pkgid format: {}\n maybe the representation has changed?",
261-
pkgid.repr
262-
)
263-
}
247+
let mut repo_url = pkg_url.clone();
248+
repo_url.set_fragment(None);
249+
repo_url.set_query(None);
250+
251+
Ok(Crate::Git(GitRepo {
252+
url: repo_url.to_string(),
253+
sha,
254+
}))
264255
}
265256
}
266257
_ => bail!(
@@ -269,11 +260,15 @@ impl TryFrom<&'_ PackageId> for Crate {
269260
),
270261
}
271262
} else if let Some((package_name, version)) = pkgid.repr.split_once(['@', ':']) {
263+
// Cargo Package Id Spec
264+
// name ("@"|":") semver
272265
Ok(Crate::Registry(RegistryCrate {
273266
name: package_name.to_string(),
274267
version: version.to_string(),
275268
}))
276269
} else {
270+
// Cargo Package Id Spec
271+
// name only
277272
Ok(Crate::Registry(RegistryCrate {
278273
name: pkgid.repr.clone(),
279274
version: "unknown".to_string(),
@@ -434,20 +429,28 @@ mod tests {
434429
name: "cargo-platform".to_string(),
435430
sha: None
436431
}),
437-
438-
"ssh://git@github.com/rust-lang/regex.git#regex@1.4.3" => Crate::Git(GitRepo {
439-
url: "ssh://git@github.com/rust-lang/regex.git".to_string(),
432+
"ssh://git@github.com/rust-lang/regex.git#regex@1.4.3" => Crate::GitHub(GitHubRepo {
433+
org: "rust-lang".to_string(),
434+
name: "regex".to_string(),
440435
sha: None
441436
}),
442-
"git+ssh://git@github.com/rust-lang/regex.git#regex@1.4.3" => Crate::Git(GitRepo {
443-
url: "git+ssh://git@github.com/rust-lang/regex.git".to_string(),
437+
"git+ssh://git@github.com/rust-lang/regex.git#regex@1.4.3" => Crate::GitHub(GitHubRepo {
438+
org: "rust-lang".to_string(),
439+
name: "regex".to_string(),
444440
sha: None
445441
}),
446-
"git+ssh://git@github.com/rust-lang/regex.git?branch=dev#regex@1.4.3" => Crate::Git(GitRepo {
447-
url: "git+ssh://git@github.com/rust-lang/regex.git".to_string(),
442+
"git+ssh://git@github.com/rust-lang/regex.git?branch=dev#regex@1.4.3" => Crate::GitHub(GitHubRepo {
443+
org: "rust-lang".to_string(),
444+
name: "regex".to_string(),
448445
sha: Some("dev".to_string())
449446
}),
450447

448+
"git+https://gitlab.com/dummy_org/dummy?rev=9823f01cf4948a41279f6a3febcf793130cab4f6" => Crate::Git(GitRepo {
449+
url: "git+https://gitlab.com/dummy_org/dummy"
450+
.to_string(),
451+
sha: Some("9823f01cf4948a41279f6a3febcf793130cab4f6".to_string())
452+
}),
453+
451454
"file:///path/to/my/project/foo" => Crate::Path("/path/to/my/project/foo".to_string()),
452455
"file:///path/to/my/project/foo#1.1.8" => Crate::Path("/path/to/my/project/foo".to_string()),
453456
"path+file:///path/to/my/project/foo#1.1.8" => Crate::Path("/path/to/my/project/foo".to_string()),

0 commit comments

Comments
 (0)