Auto merge of #13626 - linyihai:pre-update, r=weihanglo

Allow precise update to prerelease.

### What does this PR try to resolve?

This is a feature that attempts to support updates to pre-release versions via `cargo update --precise`.

when `precise-pre-release` used, the prerelase version will be taking consider as compatible version.  That said, we can update to any compatible pre-release version. The logic of checking the compatibility of pre-release versions is currently tentative and does not take many conditions into account, this part of the logic makes more sense when implemented in semver.

Use `-Zunstable-options`  instead of  `-Zprecise-pre-release`.

### How should we test and review this PR?

### Additional information
Part of https://github.com/rust-lang/cargo/issues/13290
This commit is contained in:
bors 2024-04-03 15:44:08 +00:00
commit 6774b8503c
11 changed files with 124 additions and 29 deletions

View File

@ -402,6 +402,14 @@ impl Dependency {
self.matches_id(sum.package_id())
}
pub fn matches_prerelease(&self, sum: &Summary) -> bool {
let id = sum.package_id();
self.inner.name == id.name()
&& (self.inner.only_match_name
|| (self.inner.req.matches_prerelease(id.version())
&& self.inner.source_id == id.source_id()))
}
/// Returns `true` if the package (`id`) can fulfill this dependency request.
pub fn matches_ignoring_source(&self, id: PackageId) -> bool {
self.package_name() == id.name() && self.version_req().matches(id.version())

View File

@ -768,7 +768,6 @@ unstable_cli_options!(
next_lockfile_bump: bool,
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
precise_pre_release: bool = ("Enable pre-release versions to be selected with `update --precise`"),
profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"),
public_dependency: bool = ("Respect a dependency's `public` field in Cargo.toml to control public/private dependencies"),
publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"),
@ -1158,7 +1157,6 @@ impl CliUnstable {
"panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
"public-dependency" => self.public_dependency = parse_empty(k, v)?,
"profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?,
"precise-pre-release" => self.precise_pre_release = parse_empty(k, v)?,
"trim-paths" => self.trim_paths = parse_empty(k, v)?,
"publish-timeout" => self.publish_timeout = parse_empty(k, v)?,
"rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,

View File

@ -208,9 +208,9 @@ use crate::sources::source::QueryKind;
use crate::sources::source::Source;
use crate::sources::PathSource;
use crate::util::cache_lock::CacheLockMode;
use crate::util::hex;
use crate::util::interning::InternedString;
use crate::util::network::PollExt;
use crate::util::{hex, VersionExt};
use crate::util::{restricted_names, CargoResult, Filesystem, GlobalContext, LimitErrorReader};
/// The `.cargo-ok` file is used to track if the source is already unpacked.
@ -752,7 +752,13 @@ impl<'gctx> Source for RegistrySource<'gctx> {
if let Some((_, requested)) = self
.source_id
.precise_registry_version(dep.package_name().as_str())
.filter(|(c, _)| req.matches(c))
.filter(|(c, to)| {
if to.is_prerelease() && self.gctx.cli_unstable().unstable_options {
req.matches_prerelease(c)
} else {
req.matches(c)
}
})
{
req.precise_to(&requested);
}
@ -790,7 +796,13 @@ impl<'gctx> Source for RegistrySource<'gctx> {
.index
.query_inner(dep.package_name(), &req, &mut *self.ops, &mut |s| {
let matched = match kind {
QueryKind::Exact => dep.matches(s.as_summary()),
QueryKind::Exact => {
if req.is_precise() && self.gctx.cli_unstable().unstable_options {
dep.matches_prerelease(s.as_summary())
} else {
dep.matches(s.as_summary())
}
}
QueryKind::Alternatives => true,
QueryKind::Normalized => true,
};

View File

@ -111,6 +111,19 @@ impl OptVersionReq {
}
}
/// Since Semver does not support prerelease versions,
/// the simplest implementation is taken here without comparing the prerelease section.
/// The logic here is temporary, we'll have to consider more boundary conditions later,
/// and we're not sure if this part of the functionality should be implemented in semver or cargo.
pub fn matches_prerelease(&self, version: &Version) -> bool {
if version.is_prerelease() {
let mut version = version.clone();
version.pre = semver::Prerelease::EMPTY;
return self.matches(&version);
}
self.matches(version)
}
pub fn matches(&self, version: &Version) -> bool {
match self {
OptVersionReq::Any => true,

View File

@ -46,6 +46,8 @@ revision (such as a SHA hash or tag).
While not recommended, you can specify a yanked version of a package (nightly only).
When possible, try other non-yanked SemVer-compatible versions or seek help
from the maintainers of the package.
A compatible `pre-release` version can also be specified even when the version requirement in `Cargo.toml` doesn't contain any pre-release identifer (nightly only).
{{/option}}
{{#option "`-w`" "`--workspace`" }}

View File

@ -40,6 +40,10 @@ OPTIONS
SemVer-compatible versions or seek help from the maintainers of the
package.
A compatible pre-release version can also be specified even when the
version requirement in Cargo.toml doesnt contain any pre-release
identifer (nightly only).
-w, --workspace
Attempt to update only packages defined in the workspace. Other
packages are updated only if they dont already exist in the

View File

@ -42,7 +42,8 @@ the package to. If the package comes from a git repository, this can be a git
revision (such as a SHA hash or tag).</p>
<p>While not recommended, you can specify a yanked version of a package (nightly only).
When possible, try other non-yanked SemVer-compatible versions or seek help
from the maintainers of the package.</dd>
from the maintainers of the package.</p>
<p>A compatible <code>pre-release</code> version can also be specified even when the version requirement in <code>Cargo.toml</code> doesnt contain any pre-release identifer (nightly only).</dd>
<dt class="option-term" id="option-cargo-update--w"><a class="option-anchor" href="#option-cargo-update--w"></a><code>-w</code></dt>

View File

@ -347,7 +347,7 @@ Take for example this `Cargo.toml`.
my-dependency = "0.1.1"
```
It's possible to update `my-dependancy` to a pre-release with `update -Zprecise-pre-release -p my-dependency --precise 0.1.2-pre.0`.
It's possible to update `my-dependancy` to a pre-release with `update -Zunstable-options my-dependency --precise 0.1.2-pre.0`.
This is because `0.1.2-pre.0` is considered compatible with `0.1.1`.
It would not be possible to upgrade to `0.2.0-pre.0` from `0.1.1` in the same way.

View File

@ -43,6 +43,8 @@ revision (such as a SHA hash or tag).
While not recommended, you can specify a yanked version of a package (nightly only).
When possible, try other non\-yanked SemVer\-compatible versions or seek help
from the maintainers of the package.
.sp
A compatible \fBpre\-release\fR version can also be specified even when the version requirement in \fBCargo.toml\fR doesn\[cq]t contain any pre\-release identifer (nightly only).
.RE
.sp
\fB\-w\fR,

View File

@ -1,4 +1,4 @@
<svg width="1230px" height="740px" xmlns="http://www.w3.org/2000/svg">
<svg width="1230px" height="722px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
@ -69,35 +69,33 @@
</tspan>
<tspan x="10px" y="460px"><tspan> </tspan><tspan class="fg-cyan bold">-Z panic-abort-tests </tspan><tspan> Enable support to run tests with -Cpanic=abort</tspan>
</tspan>
<tspan x="10px" y="478px"><tspan> </tspan><tspan class="fg-cyan bold">-Z precise-pre-release </tspan><tspan> Enable pre-release versions to be selected with `update --precise`</tspan>
<tspan x="10px" y="478px"><tspan> </tspan><tspan class="fg-cyan bold">-Z profile-rustflags </tspan><tspan> Enable the `rustflags` option in profiles in .cargo/config.toml file</tspan>
</tspan>
<tspan x="10px" y="496px"><tspan> </tspan><tspan class="fg-cyan bold">-Z profile-rustflags </tspan><tspan> Enable the `rustflags` option in profiles in .cargo/config.toml file</tspan>
<tspan x="10px" y="496px"><tspan> </tspan><tspan class="fg-cyan bold">-Z public-dependency </tspan><tspan> Respect a dependency's `public` field in Cargo.toml to control public/private dependencies</tspan>
</tspan>
<tspan x="10px" y="514px"><tspan> </tspan><tspan class="fg-cyan bold">-Z public-dependency </tspan><tspan> Respect a dependency's `public` field in Cargo.toml to control public/private dependencies</tspan>
<tspan x="10px" y="514px"><tspan> </tspan><tspan class="fg-cyan bold">-Z publish-timeout </tspan><tspan> Enable the `publish.timeout` key in .cargo/config.toml file</tspan>
</tspan>
<tspan x="10px" y="532px"><tspan> </tspan><tspan class="fg-cyan bold">-Z publish-timeout </tspan><tspan> Enable the `publish.timeout` key in .cargo/config.toml file</tspan>
<tspan x="10px" y="532px"><tspan> </tspan><tspan class="fg-cyan bold">-Z rustdoc-map </tspan><tspan> Allow passing external documentation mappings to rustdoc</tspan>
</tspan>
<tspan x="10px" y="550px"><tspan> </tspan><tspan class="fg-cyan bold">-Z rustdoc-map </tspan><tspan> Allow passing external documentation mappings to rustdoc</tspan>
<tspan x="10px" y="550px"><tspan> </tspan><tspan class="fg-cyan bold">-Z rustdoc-scrape-examples</tspan><tspan> Allows Rustdoc to scrape code examples from reverse-dependencies</tspan>
</tspan>
<tspan x="10px" y="568px"><tspan> </tspan><tspan class="fg-cyan bold">-Z rustdoc-scrape-examples</tspan><tspan> Allows Rustdoc to scrape code examples from reverse-dependencies</tspan>
<tspan x="10px" y="568px"><tspan> </tspan><tspan class="fg-cyan bold">-Z script </tspan><tspan> Enable support for single-file, `.rs` packages</tspan>
</tspan>
<tspan x="10px" y="586px"><tspan> </tspan><tspan class="fg-cyan bold">-Z script </tspan><tspan> Enable support for single-file, `.rs` packages</tspan>
<tspan x="10px" y="586px"><tspan> </tspan><tspan class="fg-cyan bold">-Z target-applies-to-host </tspan><tspan> Enable the `target-applies-to-host` key in the .cargo/config.toml file</tspan>
</tspan>
<tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-cyan bold">-Z target-applies-to-host </tspan><tspan> Enable the `target-applies-to-host` key in the .cargo/config.toml file</tspan>
<tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-cyan bold">-Z trim-paths </tspan><tspan> Enable the `trim-paths` option in profiles</tspan>
</tspan>
<tspan x="10px" y="622px"><tspan> </tspan><tspan class="fg-cyan bold">-Z trim-paths </tspan><tspan> Enable the `trim-paths` option in profiles</tspan>
<tspan x="10px" y="622px"><tspan> </tspan><tspan class="fg-cyan bold">-Z unstable-options </tspan><tspan> Allow the usage of unstable options</tspan>
</tspan>
<tspan x="10px" y="640px"><tspan> </tspan><tspan class="fg-cyan bold">-Z unstable-options </tspan><tspan> Allow the usage of unstable options</tspan>
<tspan x="10px" y="640px">
</tspan>
<tspan x="10px" y="658px">
<tspan x="10px" y="658px"><tspan>Run with `</tspan><tspan class="fg-cyan bold">cargo -Z</tspan><tspan> </tspan><tspan class="fg-cyan">[FLAG] [COMMAND]</tspan><tspan>`</tspan>
</tspan>
<tspan x="10px" y="676px"><tspan>Run with `</tspan><tspan class="fg-cyan bold">cargo -Z</tspan><tspan> </tspan><tspan class="fg-cyan">[FLAG] [COMMAND]</tspan><tspan>`</tspan>
<tspan x="10px" y="676px">
</tspan>
<tspan x="10px" y="694px">
<tspan x="10px" y="694px"><tspan>See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags.</tspan>
</tspan>
<tspan x="10px" y="712px"><tspan>See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags.</tspan>
</tspan>
<tspan x="10px" y="730px">
<tspan x="10px" y="712px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -23,7 +23,7 @@ fn requires_nightly_cargo() {
.file("src/lib.rs", "")
.build();
p.cargo("update -p my-dependency --precise 0.1.2-pre.0")
p.cargo("update my-dependency --precise 0.1.2-pre.0")
.with_status(101)
// This error is suffering from #12579 but still demonstrates that updating to
// a pre-release does not work on stable
@ -41,20 +41,77 @@ perhaps a crate was updated and forgotten to be re-vendored?"#,
}
#[cargo_test]
fn feature_exists() {
fn update_pre_release() {
cargo_test_support::registry::init();
for version in ["0.1.1", "0.1.2-pre.0"] {
cargo_test_support::registry::Package::new("my-dependency", version).publish();
}
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "package"
[dependencies]
my-dependency = "0.1.1"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("-Zprecise-pre-release update")
p.cargo("update my-dependency --precise 0.1.2-pre.0 -Zunstable-options")
.masquerade_as_nightly_cargo(&["precise-pre-release"])
.with_stderr("")
.run()
.with_stderr(
r#"[UPDATING] `dummy-registry` index
[UPDATING] my-dependency v0.1.1 -> v0.1.2-pre.0
"#,
)
.run();
let lockfile = p.read_lockfile();
assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.2-pre.0\""));
}
#[cargo_test]
fn update_pre_release_differ() {
cargo_test_support::registry::init();
for version in ["0.1.2", "0.1.2-pre.0", "0.1.2-pre.1"] {
cargo_test_support::registry::Package::new("my-dependency", version).publish();
}
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "package"
[dependencies]
my-dependency = "0.1.2"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("update -p my-dependency --precise 0.1.2-pre.0 -Zunstable-options")
.masquerade_as_nightly_cargo(&["precise-pre-release"])
.with_stderr(
r#"[UPDATING] `dummy-registry` index
[DOWNGRADING] my-dependency v0.1.2 -> v0.1.2-pre.0
"#,
)
.run();
p.cargo("update -p my-dependency --precise 0.1.2-pre.1 -Zunstable-options")
.masquerade_as_nightly_cargo(&["precise-pre-release"])
.with_stderr(
r#"[UPDATING] `dummy-registry` index
[UPDATING] my-dependency v0.1.2-pre.0 -> v0.1.2-pre.1
"#,
)
.run();
let lockfile = p.read_lockfile();
assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.2-pre.1\""));
}