Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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\""));
}