-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(spec): Allow partial versions when unambigious
This was proposed in #12425 to help improve usability of the existing `cargo update` when dealing with the added workflows.
- Loading branch information
Showing
10 changed files
with
111 additions
and
55 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
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 |
---|---|---|
|
@@ -10,7 +10,8 @@ use crate::core::PackageId; | |
use crate::util::edit_distance; | ||
use crate::util::errors::CargoResult; | ||
use crate::util::interning::InternedString; | ||
use crate::util::{validate_package_name, IntoUrl, ToSemver}; | ||
use crate::util::PartialVersion; | ||
use crate::util::{validate_package_name, IntoUrl}; | ||
|
||
/// Some or all of the data required to identify a package: | ||
/// | ||
|
@@ -24,7 +25,7 @@ use crate::util::{validate_package_name, IntoUrl, ToSemver}; | |
#[derive(Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)] | ||
pub struct PackageIdSpec { | ||
name: InternedString, | ||
version: Option<Version>, | ||
version: Option<PartialVersion>, | ||
url: Option<Url>, | ||
} | ||
|
||
|
@@ -70,7 +71,7 @@ impl PackageIdSpec { | |
let mut parts = spec.splitn(2, [':', '@']); | ||
let name = parts.next().unwrap(); | ||
let version = match parts.next() { | ||
Some(version) => Some(version.to_semver()?), | ||
Some(version) => Some(version.parse::<PartialVersion>()?), | ||
None => None, | ||
}; | ||
validate_package_name(name, "pkgid", "")?; | ||
|
@@ -94,12 +95,12 @@ impl PackageIdSpec { | |
spec.query(i) | ||
} | ||
|
||
/// Convert a `PackageId` to a `PackageIdSpec`, which will have both the `Version` and `Url` | ||
/// Convert a `PackageId` to a `PackageIdSpec`, which will have both the `PartialVersion` and `Url` | ||
/// fields filled in. | ||
pub fn from_package_id(package_id: PackageId) -> PackageIdSpec { | ||
PackageIdSpec { | ||
name: package_id.name(), | ||
version: Some(package_id.version().clone()), | ||
version: Some(package_id.version().clone().into()), | ||
url: Some(package_id.source_id().url().clone()), | ||
} | ||
} | ||
|
@@ -128,14 +129,14 @@ impl PackageIdSpec { | |
let name_or_version = parts.next().unwrap(); | ||
match parts.next() { | ||
Some(part) => { | ||
let version = part.to_semver()?; | ||
let version = part.parse::<PartialVersion>()?; | ||
(InternedString::new(name_or_version), Some(version)) | ||
} | ||
None => { | ||
if name_or_version.chars().next().unwrap().is_alphabetic() { | ||
(InternedString::new(name_or_version), None) | ||
} else { | ||
let version = name_or_version.to_semver()?; | ||
let version = name_or_version.parse::<PartialVersion>()?; | ||
(InternedString::new(path_name), Some(version)) | ||
} | ||
} | ||
|
@@ -155,7 +156,12 @@ impl PackageIdSpec { | |
self.name | ||
} | ||
|
||
pub fn version(&self) -> Option<&Version> { | ||
/// Full `semver::Version`, if present | ||
pub fn version(&self) -> Option<Version> { | ||
self.version.as_ref().and_then(|v| v.version()) | ||
} | ||
|
||
pub fn partial_version(&self) -> Option<&PartialVersion> { | ||
self.version.as_ref() | ||
} | ||
|
||
|
@@ -174,7 +180,8 @@ impl PackageIdSpec { | |
} | ||
|
||
if let Some(ref v) = self.version { | ||
if v != package_id.version() { | ||
let req = v.exact_req(); | ||
if !req.matches(package_id.version()) { | ||
return false; | ||
} | ||
} | ||
|
@@ -326,7 +333,6 @@ mod tests { | |
use super::PackageIdSpec; | ||
use crate::core::{PackageId, SourceId}; | ||
use crate::util::interning::InternedString; | ||
use crate::util::ToSemver; | ||
use url::Url; | ||
|
||
#[test] | ||
|
@@ -351,16 +357,25 @@ mod tests { | |
"https://crates.io/foo#1.2.3", | ||
PackageIdSpec { | ||
name: InternedString::new("foo"), | ||
version: Some("1.2.3".to_semver().unwrap()), | ||
version: Some("1.2.3".parse().unwrap()), | ||
url: Some(Url::parse("https://crates.io/foo").unwrap()), | ||
}, | ||
"https://crates.io/foo#1.2.3", | ||
); | ||
ok( | ||
"https://crates.io/foo#1.2", | ||
PackageIdSpec { | ||
name: InternedString::new("foo"), | ||
version: Some("1.2".parse().unwrap()), | ||
url: Some(Url::parse("https://crates.io/foo").unwrap()), | ||
}, | ||
"https://crates.io/foo#1.2", | ||
); | ||
ok( | ||
"https://crates.io/foo#bar:1.2.3", | ||
PackageIdSpec { | ||
name: InternedString::new("bar"), | ||
version: Some("1.2.3".to_semver().unwrap()), | ||
version: Some("1.2.3".parse().unwrap()), | ||
url: Some(Url::parse("https://crates.io/foo").unwrap()), | ||
}, | ||
"https://crates.io/foo#[email protected]", | ||
|
@@ -369,11 +384,20 @@ mod tests { | |
"https://crates.io/foo#[email protected]", | ||
PackageIdSpec { | ||
name: InternedString::new("bar"), | ||
version: Some("1.2.3".to_semver().unwrap()), | ||
version: Some("1.2.3".parse().unwrap()), | ||
url: Some(Url::parse("https://crates.io/foo").unwrap()), | ||
}, | ||
"https://crates.io/foo#[email protected]", | ||
); | ||
ok( | ||
"https://crates.io/foo#[email protected]", | ||
PackageIdSpec { | ||
name: InternedString::new("bar"), | ||
version: Some("1.2".parse().unwrap()), | ||
url: Some(Url::parse("https://crates.io/foo").unwrap()), | ||
}, | ||
"https://crates.io/foo#[email protected]", | ||
); | ||
ok( | ||
"foo", | ||
PackageIdSpec { | ||
|
@@ -387,7 +411,7 @@ mod tests { | |
"foo:1.2.3", | ||
PackageIdSpec { | ||
name: InternedString::new("foo"), | ||
version: Some("1.2.3".to_semver().unwrap()), | ||
version: Some("1.2.3".parse().unwrap()), | ||
url: None, | ||
}, | ||
"[email protected]", | ||
|
@@ -396,21 +420,29 @@ mod tests { | |
"[email protected]", | ||
PackageIdSpec { | ||
name: InternedString::new("foo"), | ||
version: Some("1.2.3".to_semver().unwrap()), | ||
version: Some("1.2.3".parse().unwrap()), | ||
url: None, | ||
}, | ||
"[email protected]", | ||
); | ||
ok( | ||
"[email protected]", | ||
PackageIdSpec { | ||
name: InternedString::new("foo"), | ||
version: Some("1.2".parse().unwrap()), | ||
url: None, | ||
}, | ||
"[email protected]", | ||
); | ||
} | ||
|
||
#[test] | ||
fn bad_parsing() { | ||
assert!(PackageIdSpec::parse("baz:").is_err()); | ||
assert!(PackageIdSpec::parse("baz:*").is_err()); | ||
assert!(PackageIdSpec::parse("baz:1.0").is_err()); | ||
assert!(PackageIdSpec::parse("baz@").is_err()); | ||
assert!(PackageIdSpec::parse("baz@*").is_err()); | ||
assert!(PackageIdSpec::parse("[email protected]").is_err()); | ||
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()); | ||
} | ||
|
@@ -428,5 +460,6 @@ mod tests { | |
assert!(!PackageIdSpec::parse("foo:1.2.2").unwrap().matches(foo)); | ||
assert!(PackageIdSpec::parse("[email protected]").unwrap().matches(foo)); | ||
assert!(!PackageIdSpec::parse("[email protected]").unwrap().matches(foo)); | ||
assert!(PackageIdSpec::parse("[email protected]").unwrap().matches(foo)); | ||
} | ||
} |
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
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
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 |
---|---|---|
|
@@ -24,6 +24,7 @@ The formal grammar for a Package Id Specification is: | |
spec := pkgname | ||
| proto "://" hostname-and-path [ "#" ( pkgname | semver ) ] | ||
pkgname := name [ ("@" | ":" ) semver ] | ||
semver := digits [ "." digits [ "." digits [ "-" prerelease ] [ "+" build ]]] | ||
proto := "http" | "git" | ... | ||
``` | ||
|
@@ -40,6 +41,7 @@ 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` | | ||
|
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 |
---|---|---|
|
@@ -151,25 +151,20 @@ fn multiple_versions() { | |
.with_status(101) | ||
.with_stderr( | ||
"\ | ||
error: invalid package ID specification: `two-ver@0` | ||
<tab>Did you mean `two-ver`? | ||
Caused by: | ||
cannot parse '0' as a SemVer version | ||
error: There are multiple `two-ver` packages in your project, and the specification `two-ver@0` is ambiguous. | ||
Please re-run this command with `-p <spec>` where `<spec>` is one of the following: | ||
[email protected] | ||
[email protected] | ||
", | ||
) | ||
.run(); | ||
|
||
// Incomplete version. | ||
p.cargo("pkgid [email protected]") | ||
.with_status(101) | ||
.with_stderr( | ||
.with_status(0) | ||
.with_stdout( | ||
"\ | ||
error: invalid package ID specification: `[email protected]` | ||
Caused by: | ||
cannot parse '0.2' as a SemVer version | ||
https://github.com/rust-lang/crates.io-index#[email protected] | ||
", | ||
) | ||
.run(); | ||
|
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