Skip to content

Commit 6774b85

Browse files
committed
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 #13290
2 parents 09d5e96 + 179f2f1 commit 6774b85

File tree

11 files changed

+124
-29
lines changed

11 files changed

+124
-29
lines changed

src/cargo/core/dependency.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,14 @@ impl Dependency {
402402
self.matches_id(sum.package_id())
403403
}
404404

405+
pub fn matches_prerelease(&self, sum: &Summary) -> bool {
406+
let id = sum.package_id();
407+
self.inner.name == id.name()
408+
&& (self.inner.only_match_name
409+
|| (self.inner.req.matches_prerelease(id.version())
410+
&& self.inner.source_id == id.source_id()))
411+
}
412+
405413
/// Returns `true` if the package (`id`) can fulfill this dependency request.
406414
pub fn matches_ignoring_source(&self, id: PackageId) -> bool {
407415
self.package_name() == id.name() && self.version_req().matches(id.version())

src/cargo/core/features.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,6 @@ unstable_cli_options!(
768768
next_lockfile_bump: bool,
769769
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
770770
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
771-
precise_pre_release: bool = ("Enable pre-release versions to be selected with `update --precise`"),
772771
profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"),
773772
public_dependency: bool = ("Respect a dependency's `public` field in Cargo.toml to control public/private dependencies"),
774773
publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"),
@@ -1158,7 +1157,6 @@ impl CliUnstable {
11581157
"panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
11591158
"public-dependency" => self.public_dependency = parse_empty(k, v)?,
11601159
"profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?,
1161-
"precise-pre-release" => self.precise_pre_release = parse_empty(k, v)?,
11621160
"trim-paths" => self.trim_paths = parse_empty(k, v)?,
11631161
"publish-timeout" => self.publish_timeout = parse_empty(k, v)?,
11641162
"rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,

src/cargo/sources/registry/mod.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ use crate::sources::source::QueryKind;
208208
use crate::sources::source::Source;
209209
use crate::sources::PathSource;
210210
use crate::util::cache_lock::CacheLockMode;
211-
use crate::util::hex;
212211
use crate::util::interning::InternedString;
213212
use crate::util::network::PollExt;
213+
use crate::util::{hex, VersionExt};
214214
use crate::util::{restricted_names, CargoResult, Filesystem, GlobalContext, LimitErrorReader};
215215

216216
/// The `.cargo-ok` file is used to track if the source is already unpacked.
@@ -752,7 +752,13 @@ impl<'gctx> Source for RegistrySource<'gctx> {
752752
if let Some((_, requested)) = self
753753
.source_id
754754
.precise_registry_version(dep.package_name().as_str())
755-
.filter(|(c, _)| req.matches(c))
755+
.filter(|(c, to)| {
756+
if to.is_prerelease() && self.gctx.cli_unstable().unstable_options {
757+
req.matches_prerelease(c)
758+
} else {
759+
req.matches(c)
760+
}
761+
})
756762
{
757763
req.precise_to(&requested);
758764
}
@@ -790,7 +796,13 @@ impl<'gctx> Source for RegistrySource<'gctx> {
790796
.index
791797
.query_inner(dep.package_name(), &req, &mut *self.ops, &mut |s| {
792798
let matched = match kind {
793-
QueryKind::Exact => dep.matches(s.as_summary()),
799+
QueryKind::Exact => {
800+
if req.is_precise() && self.gctx.cli_unstable().unstable_options {
801+
dep.matches_prerelease(s.as_summary())
802+
} else {
803+
dep.matches(s.as_summary())
804+
}
805+
}
794806
QueryKind::Alternatives => true,
795807
QueryKind::Normalized => true,
796808
};

src/cargo/util/semver_ext.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ impl OptVersionReq {
111111
}
112112
}
113113

114+
/// Since Semver does not support prerelease versions,
115+
/// the simplest implementation is taken here without comparing the prerelease section.
116+
/// The logic here is temporary, we'll have to consider more boundary conditions later,
117+
/// and we're not sure if this part of the functionality should be implemented in semver or cargo.
118+
pub fn matches_prerelease(&self, version: &Version) -> bool {
119+
if version.is_prerelease() {
120+
let mut version = version.clone();
121+
version.pre = semver::Prerelease::EMPTY;
122+
return self.matches(&version);
123+
}
124+
self.matches(version)
125+
}
126+
114127
pub fn matches(&self, version: &Version) -> bool {
115128
match self {
116129
OptVersionReq::Any => true,

src/doc/man/cargo-update.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ revision (such as a SHA hash or tag).
4646
While not recommended, you can specify a yanked version of a package (nightly only).
4747
When possible, try other non-yanked SemVer-compatible versions or seek help
4848
from the maintainers of the package.
49+
50+
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).
4951
{{/option}}
5052

5153
{{#option "`-w`" "`--workspace`" }}

src/doc/man/generated_txt/cargo-update.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ OPTIONS
4040
SemVer-compatible versions or seek help from the maintainers of the
4141
package.
4242

43+
A compatible pre-release version can also be specified even when the
44+
version requirement in Cargo.toml doesn’t contain any pre-release
45+
identifer (nightly only).
46+
4347
-w, --workspace
4448
Attempt to update only packages defined in the workspace. Other
4549
packages are updated only if they don’t already exist in the

src/doc/src/commands/cargo-update.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ the package to. If the package comes from a git repository, this can be a git
4242
revision (such as a SHA hash or tag).</p>
4343
<p>While not recommended, you can specify a yanked version of a package (nightly only).
4444
When possible, try other non-yanked SemVer-compatible versions or seek help
45-
from the maintainers of the package.</dd>
45+
from the maintainers of the package.</p>
46+
<p>A compatible <code>pre-release</code> version can also be specified even when the version requirement in <code>Cargo.toml</code> doesn’t contain any pre-release identifer (nightly only).</dd>
4647

4748

4849
<dt class="option-term" id="option-cargo-update--w"><a class="option-anchor" href="#option-cargo-update--w"></a><code>-w</code></dt>

src/doc/src/reference/unstable.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ Take for example this `Cargo.toml`.
347347
my-dependency = "0.1.1"
348348
```
349349

350-
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`.
350+
It's possible to update `my-dependancy` to a pre-release with `update -Zunstable-options my-dependency --precise 0.1.2-pre.0`.
351351
This is because `0.1.2-pre.0` is considered compatible with `0.1.1`.
352352
It would not be possible to upgrade to `0.2.0-pre.0` from `0.1.1` in the same way.
353353

src/etc/man/cargo-update.1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ revision (such as a SHA hash or tag).
4343
While not recommended, you can specify a yanked version of a package (nightly only).
4444
When possible, try other non\-yanked SemVer\-compatible versions or seek help
4545
from the maintainers of the package.
46+
.sp
47+
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).
4648
.RE
4749
.sp
4850
\fB\-w\fR,

tests/testsuite/cargo/z_help/stdout.term.svg

Lines changed: 15 additions & 17 deletions
Loading

tests/testsuite/precise_pre_release.rs

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn requires_nightly_cargo() {
2323
.file("src/lib.rs", "")
2424
.build();
2525

26-
p.cargo("update -p my-dependency --precise 0.1.2-pre.0")
26+
p.cargo("update my-dependency --precise 0.1.2-pre.0")
2727
.with_status(101)
2828
// This error is suffering from #12579 but still demonstrates that updating to
2929
// a pre-release does not work on stable
@@ -41,20 +41,77 @@ perhaps a crate was updated and forgotten to be re-vendored?"#,
4141
}
4242

4343
#[cargo_test]
44-
fn feature_exists() {
44+
fn update_pre_release() {
45+
cargo_test_support::registry::init();
46+
47+
for version in ["0.1.1", "0.1.2-pre.0"] {
48+
cargo_test_support::registry::Package::new("my-dependency", version).publish();
49+
}
50+
4551
let p = project()
4652
.file(
4753
"Cargo.toml",
4854
r#"
4955
[package]
5056
name = "package"
57+
[dependencies]
58+
my-dependency = "0.1.1"
5159
"#,
5260
)
5361
.file("src/lib.rs", "")
5462
.build();
5563

56-
p.cargo("-Zprecise-pre-release update")
64+
p.cargo("update my-dependency --precise 0.1.2-pre.0 -Zunstable-options")
5765
.masquerade_as_nightly_cargo(&["precise-pre-release"])
58-
.with_stderr("")
59-
.run()
66+
.with_stderr(
67+
r#"[UPDATING] `dummy-registry` index
68+
[UPDATING] my-dependency v0.1.1 -> v0.1.2-pre.0
69+
"#,
70+
)
71+
.run();
72+
let lockfile = p.read_lockfile();
73+
assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.2-pre.0\""));
74+
}
75+
76+
#[cargo_test]
77+
fn update_pre_release_differ() {
78+
cargo_test_support::registry::init();
79+
80+
for version in ["0.1.2", "0.1.2-pre.0", "0.1.2-pre.1"] {
81+
cargo_test_support::registry::Package::new("my-dependency", version).publish();
82+
}
83+
84+
let p = project()
85+
.file(
86+
"Cargo.toml",
87+
r#"
88+
[package]
89+
name = "package"
90+
[dependencies]
91+
my-dependency = "0.1.2"
92+
"#,
93+
)
94+
.file("src/lib.rs", "")
95+
.build();
96+
97+
p.cargo("update -p my-dependency --precise 0.1.2-pre.0 -Zunstable-options")
98+
.masquerade_as_nightly_cargo(&["precise-pre-release"])
99+
.with_stderr(
100+
r#"[UPDATING] `dummy-registry` index
101+
[DOWNGRADING] my-dependency v0.1.2 -> v0.1.2-pre.0
102+
"#,
103+
)
104+
.run();
105+
106+
p.cargo("update -p my-dependency --precise 0.1.2-pre.1 -Zunstable-options")
107+
.masquerade_as_nightly_cargo(&["precise-pre-release"])
108+
.with_stderr(
109+
r#"[UPDATING] `dummy-registry` index
110+
[UPDATING] my-dependency v0.1.2-pre.0 -> v0.1.2-pre.1
111+
"#,
112+
)
113+
.run();
114+
115+
let lockfile = p.read_lockfile();
116+
assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.2-pre.1\""));
60117
}

0 commit comments

Comments
 (0)