forked from rust-lang/cargo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
152 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ use semver::Version; | |
use serde::{de, ser}; | ||
use url::Url; | ||
|
||
use crate::core::GitReference; | ||
use crate::core::PackageId; | ||
use crate::core::SourceKind; | ||
use crate::util::edit_distance; | ||
|
@@ -104,17 +105,47 @@ impl PackageIdSpec { | |
name: String::from(package_id.name().as_str()), | ||
version: Some(package_id.version().clone().into()), | ||
url: Some(package_id.source_id().url().clone()), | ||
kind: None, | ||
kind: Some(package_id.source_id().kind().clone()), | ||
} | ||
} | ||
|
||
/// Tries to convert a valid `Url` to a `PackageIdSpec`. | ||
fn from_url(mut url: Url) -> CargoResult<PackageIdSpec> { | ||
let mut kind = None; | ||
if let Some((kind_str, scheme)) = url.scheme().split_once('+') { | ||
match kind_str { | ||
"git" => { | ||
let git_ref = GitReference::DefaultBranch; | ||
kind = Some(SourceKind::Git(git_ref)); | ||
url = strip_url_protocol(&url); | ||
} | ||
"registry" => { | ||
kind = Some(SourceKind::Registry); | ||
url = strip_url_protocol(&url); | ||
} | ||
"sparse" => { | ||
kind = Some(SourceKind::SparseRegistry); | ||
// Leave `sparse` as part of URL | ||
// url = strip_url_protocol(&url); | ||
} | ||
"path" => { | ||
if scheme != "file" { | ||
anyhow::bail!("`path+{scheme}` is unsupported; `path+file` and `file` schemes are supported"); | ||
} | ||
kind = Some(SourceKind::Path); | ||
url = strip_url_protocol(&url); | ||
} | ||
kind => anyhow::bail!("unsupported source protocol: {kind}"), | ||
} | ||
} | ||
|
||
if url.query().is_some() { | ||
bail!("cannot have a query string in a pkgid: {}", url) | ||
} | ||
|
||
let frag = url.fragment().map(|s| s.to_owned()); | ||
url.set_fragment(None); | ||
|
||
let (name, version) = { | ||
let mut path = url | ||
.path_segments() | ||
|
@@ -148,7 +179,7 @@ impl PackageIdSpec { | |
name, | ||
version, | ||
url: Some(url), | ||
kind: None, | ||
kind, | ||
}) | ||
} | ||
|
||
|
@@ -173,6 +204,14 @@ impl PackageIdSpec { | |
self.url = Some(url); | ||
} | ||
|
||
pub fn kind(&self) -> Option<&SourceKind> { | ||
self.kind.as_ref() | ||
} | ||
|
||
pub fn set_kind(&mut self, kind: SourceKind) { | ||
self.kind = Some(kind); | ||
} | ||
|
||
/// Checks whether the given `PackageId` matches the `PackageIdSpec`. | ||
pub fn matches(&self, package_id: PackageId) -> bool { | ||
if self.name() != package_id.name().as_str() { | ||
|
@@ -191,6 +230,12 @@ impl PackageIdSpec { | |
} | ||
} | ||
|
||
if let Some(k) = &self.kind { | ||
if k != package_id.source_id().kind() { | ||
return false; | ||
} | ||
} | ||
|
||
true | ||
} | ||
|
||
|
@@ -287,11 +332,20 @@ impl PackageIdSpec { | |
} | ||
} | ||
|
||
fn strip_url_protocol(url: &Url) -> Url { | ||
// Ridiculous hoop because `Url::set_scheme` errors when changing to http/https | ||
let raw = url.to_string(); | ||
raw.split_once('+').unwrap().1.parse().unwrap() | ||
} | ||
|
||
impl fmt::Display for PackageIdSpec { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
let mut printed_name = false; | ||
match self.url { | ||
Some(ref url) => { | ||
if let Some(protocol) = self.kind.as_ref().and_then(|k| k.protocol()) { | ||
write!(f, "{protocol}+")?; | ||
} | ||
write!(f, "{}", url)?; | ||
if url.path_segments().unwrap().next_back().unwrap() != &*self.name { | ||
printed_name = true; | ||
|
@@ -332,7 +386,7 @@ impl<'de> de::Deserialize<'de> for PackageIdSpec { | |
#[cfg(test)] | ||
mod tests { | ||
use super::PackageIdSpec; | ||
use crate::core::{PackageId, SourceId}; | ||
use crate::core::{GitReference, PackageId, SourceId, SourceKind}; | ||
use url::Url; | ||
|
||
#[test] | ||
|
@@ -407,6 +461,26 @@ mod tests { | |
}, | ||
"https://crates.io/foo#[email protected]", | ||
); | ||
ok( | ||
"registry+https://crates.io/foo#[email protected]", | ||
PackageIdSpec { | ||
name: String::from("bar"), | ||
version: Some("1.2".parse().unwrap()), | ||
url: Some(Url::parse("https://crates.io/foo").unwrap()), | ||
kind: Some(SourceKind::Registry), | ||
}, | ||
"registry+https://crates.io/foo#[email protected]", | ||
); | ||
ok( | ||
"sparse+https://crates.io/foo#[email protected]", | ||
PackageIdSpec { | ||
name: String::from("bar"), | ||
version: Some("1.2".parse().unwrap()), | ||
url: Some(Url::parse("sparse+https://crates.io/foo").unwrap()), | ||
kind: Some(SourceKind::SparseRegistry), | ||
}, | ||
"sparse+https://crates.io/foo#[email protected]", | ||
); | ||
ok( | ||
"foo", | ||
PackageIdSpec { | ||
|
@@ -499,6 +573,18 @@ mod tests { | |
}, | ||
"https://github.com/rust-lang/crates.io-index#[email protected]", | ||
); | ||
ok( | ||
"sparse+https://github.com/rust-lang/crates.io-index#[email protected]", | ||
PackageIdSpec { | ||
name: String::from("regex"), | ||
version: Some("1.4.3".parse().unwrap()), | ||
url: Some( | ||
Url::parse("sparse+https://github.com/rust-lang/crates.io-index").unwrap(), | ||
), | ||
kind: Some(SourceKind::SparseRegistry), | ||
}, | ||
"sparse+https://github.com/rust-lang/crates.io-index#[email protected]", | ||
); | ||
ok( | ||
"https://github.com/rust-lang/cargo#0.52.0", | ||
PackageIdSpec { | ||
|
@@ -529,6 +615,16 @@ mod tests { | |
}, | ||
"ssh://[email protected]/rust-lang/regex.git#[email protected]", | ||
); | ||
ok( | ||
"git+ssh://[email protected]/rust-lang/regex.git#[email protected]", | ||
PackageIdSpec { | ||
name: String::from("regex"), | ||
version: Some("1.4.3".parse().unwrap()), | ||
url: Some(Url::parse("ssh://[email protected]/rust-lang/regex.git").unwrap()), | ||
kind: Some(SourceKind::Git(GitReference::DefaultBranch)), | ||
}, | ||
"git+ssh://[email protected]/rust-lang/regex.git#[email protected]", | ||
); | ||
ok( | ||
"file:///path/to/my/project/foo", | ||
PackageIdSpec { | ||
|
@@ -549,6 +645,16 @@ mod tests { | |
}, | ||
"file:///path/to/my/project/foo#1.1.8", | ||
); | ||
ok( | ||
"path+file:///path/to/my/project/foo#1.1.8", | ||
PackageIdSpec { | ||
name: String::from("foo"), | ||
version: Some("1.1.8".parse().unwrap()), | ||
url: Some(Url::parse("file:///path/to/my/project/foo").unwrap()), | ||
kind: Some(SourceKind::Path), | ||
}, | ||
"path+file:///path/to/my/project/foo#1.1.8", | ||
); | ||
} | ||
|
||
#[test] | ||
|
@@ -560,6 +666,10 @@ mod tests { | |
assert!(PackageIdSpec::parse("baz@^1.0").is_err()); | ||
assert!(PackageIdSpec::parse("https://baz:1.0").is_err()); | ||
assert!(PackageIdSpec::parse("https://#baz:1.0").is_err()); | ||
assert!( | ||
PackageIdSpec::parse("foobar+https://github.com/rust-lang/crates.io-index").is_err() | ||
); | ||
assert!(PackageIdSpec::parse("path+https://github.com/rust-lang/crates.io-index").is_err()); | ||
} | ||
|
||
#[test] | ||
|
@@ -581,6 +691,12 @@ mod tests { | |
assert!(!PackageIdSpec::parse("https://bob.com#[email protected]") | ||
.unwrap() | ||
.matches(foo)); | ||
assert!(PackageIdSpec::parse("registry+https://example.com#[email protected]") | ||
.unwrap() | ||
.matches(foo)); | ||
assert!(!PackageIdSpec::parse("git+https://example.com#[email protected]") | ||
.unwrap() | ||
.matches(foo)); | ||
|
||
let meta = PackageId::new("meta", "1.2.3+hello", sid).unwrap(); | ||
assert!(PackageIdSpec::parse("meta").unwrap().matches(meta)); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,11 +21,12 @@ qualified with a version to make it unique, such as `[email protected]`. | |
The formal grammar for a Package Id Specification is: | ||
|
||
```notrust | ||
spec := pkgname | ||
| proto "://" hostname-and-path [ "#" ( pkgname | semver ) ] | ||
spec := pkgname | | ||
[ kind "+" ] proto "://" hostname-and-path [ "#" ( pkgname | semver ) ] | ||
pkgname := name [ ("@" | ":" ) semver ] | ||
semver := digits [ "." digits [ "." digits [ "-" prerelease ] [ "+" build ]]] | ||
kind = "sparse" | "registry" | "git" | "file" | ||
proto := "http" | "git" | ... | ||
``` | ||
|
||
|
@@ -38,28 +39,31 @@ that come from different sources such as different registries. | |
|
||
The following are references to the `regex` package on `crates.io`: | ||
|
||
| Spec | Name | Version | | ||
|:------------------------------------------------------------|:-------:|:-------:| | ||
| `regex` | `regex` | `*` | | ||
| `[email protected]` | `regex` | `1.4.*` | | ||
| `[email protected]` | `regex` | `1.4.3` | | ||
| `https://github.com/rust-lang/crates.io-index#regex` | `regex` | `*` | | ||
| `https://github.com/rust-lang/crates.io-index#[email protected]` | `regex` | `1.4.3` | | ||
| Spec | Name | Version | | ||
|:------------------------------------------------------------------|:-------:|:-------:| | ||
| `regex` | `regex` | `*` | | ||
| `[email protected]` | `regex` | `1.4.*` | | ||
| `[email protected]` | `regex` | `1.4.3` | | ||
| `https://github.com/rust-lang/crates.io-index#regex` | `regex` | `*` | | ||
| `https://github.com/rust-lang/crates.io-index#[email protected]` | `regex` | `1.4.3` | | ||
| `sparse+https://github.com/rust-lang/crates.io-index#[email protected]` | `regex` | `1.4.3` | | ||
|
||
The following are some examples of specs for several different git dependencies: | ||
|
||
| Spec | Name | Version | | ||
|:----------------------------------------------------------|:----------------:|:--------:| | ||
| `https://github.com/rust-lang/cargo#0.52.0` | `cargo` | `0.52.0` | | ||
| `https://github.com/rust-lang/cargo#[email protected]` | <nobr>`cargo-platform`</nobr> | `0.1.2` | | ||
| `ssh://[email protected]/rust-lang/regex.git#[email protected]` | `regex` | `1.4.3` | | ||
| Spec | Name | Version | | ||
|:-----------------------------------------------------------|:----------------:|:--------:| | ||
| `https://github.com/rust-lang/cargo#0.52.0` | `cargo` | `0.52.0` | | ||
| `https://github.com/rust-lang/cargo#[email protected]` | <nobr>`cargo-platform`</nobr> | `0.1.2` | | ||
| `ssh://[email protected]/rust-lang/regex.git#[email protected]` | `regex` | `1.4.3` | | ||
| `git+ssh://[email protected]/rust-lang/regex.git#[email protected]` | `regex` | `1.4.3` | | ||
|
||
Local packages on the filesystem can use `file://` URLs to reference them: | ||
|
||
| Spec | Name | Version | | ||
|:---------------------------------------|:-----:|:-------:| | ||
| `file:///path/to/my/project/foo` | `foo` | `*` | | ||
| `file:///path/to/my/project/foo#1.1.8` | `foo` | `1.1.8` | | ||
| Spec | Name | Version | | ||
|:--------------------------------------------|:-----:|:-------:| | ||
| `file:///path/to/my/project/foo` | `foo` | `*` | | ||
| `file:///path/to/my/project/foo#1.1.8` | `foo` | `1.1.8` | | ||
| `path+file:///path/to/my/project/foo#1.1.8` | `foo` | `1.1.8` | | ||
|
||
### Brevity of specifications | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,10 @@ fn local() { | |
p.cargo("generate-lockfile").run(); | ||
|
||
p.cargo("pkgid foo") | ||
.with_stdout(format!("file://[..]{}#0.1.0", p.root().to_str().unwrap())) | ||
.with_stdout(format!( | ||
"path+file://[..]{}#0.1.0", | ||
p.root().to_str().unwrap() | ||
)) | ||
.run(); | ||
|
||
// Bad file URL. | ||
|
@@ -89,7 +92,7 @@ fn registry() { | |
p.cargo("generate-lockfile").run(); | ||
|
||
p.cargo("pkgid crates-io") | ||
.with_stdout("https://github.com/rust-lang/crates.io-index#[email protected]") | ||
.with_stdout("registry+https://github.com/rust-lang/crates.io-index#[email protected]") | ||
.run(); | ||
|
||
// Bad URL. | ||
|
@@ -143,7 +146,7 @@ fn multiple_versions() { | |
p.cargo("generate-lockfile").run(); | ||
|
||
p.cargo("pkgid two-ver:0.2.0") | ||
.with_stdout("https://github.com/rust-lang/crates.io-index#[email protected]") | ||
.with_stdout("registry+https://github.com/rust-lang/crates.io-index#[email protected]") | ||
.run(); | ||
|
||
// Incomplete version. | ||
|
@@ -163,7 +166,7 @@ Please re-run this command with one of the following specifications: | |
p.cargo("pkgid [email protected]") | ||
.with_stdout( | ||
"\ | ||
https://github.com/rust-lang/crates.io-index#[email protected] | ||
registry+https://github.com/rust-lang/crates.io-index#[email protected] | ||
", | ||
) | ||
.run(); | ||
|