Skip to content

Commit

Permalink
Allow precise update to prerelease.
Browse files Browse the repository at this point in the history
  • Loading branch information
linyihai committed Apr 3, 2024
1 parent 6972630 commit 179f2f1
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 29 deletions.
8 changes: 8 additions & 0 deletions src/cargo/core/dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
2 changes: 0 additions & 2 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,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"),
Expand Down Expand Up @@ -1154,7 +1153,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)?,
Expand Down
18 changes: 15 additions & 3 deletions src/cargo/sources/registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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,
};
Expand Down
13 changes: 13 additions & 0 deletions src/cargo/util/semver_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions src/doc/man/cargo-update.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`" }}
Expand Down
4 changes: 4 additions & 0 deletions src/doc/man/generated_txt/cargo-update.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 doesn’t 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 don’t already exist in the
Expand Down
3 changes: 2 additions & 1 deletion src/doc/src/commands/cargo-update.md
Original file line number Diff line number Diff line change
Expand Up @@ -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> doesn’t 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>
Expand Down
2 changes: 1 addition & 1 deletion src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 2 additions & 0 deletions src/etc/man/cargo-update.1
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
32 changes: 15 additions & 17 deletions tests/testsuite/cargo/z_help/stdout.term.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 62 additions & 5 deletions tests/testsuite/precise_pre_release.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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\""));
}

0 comments on commit 179f2f1

Please sign in to comment.