mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Improved error message for versions prefixed with v
(#15484)
### What does this PR try to resolve? - Added an error message when version in `CRATE[@<VER>]` or `--version <VER>` starts with 'v' for `install`, `add`, `yank` and `update --precise <VER>` - Check if version is valid in `cargo yank` Fixes #12331 ### How should we test and review this PR? Added tests for each subcommand
This commit is contained in:
commit
6cba807e2c
@ -286,6 +286,12 @@ fn parse_semver_flag(v: &str) -> CargoResult<VersionReq> {
|
|||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| format_err!("no version provided for the `--version` flag"))?;
|
.ok_or_else(|| format_err!("no version provided for the `--version` flag"))?;
|
||||||
|
|
||||||
|
if let Some(stripped) = v.strip_prefix("v") {
|
||||||
|
bail!(
|
||||||
|
"the version provided, `{v}` is not a valid SemVer requirement\n\n\
|
||||||
|
help: try changing the version to `{stripped}`",
|
||||||
|
)
|
||||||
|
}
|
||||||
let is_req = "<>=^~".contains(first) || v.contains('*');
|
let is_req = "<>=^~".contains(first) || v.contains('*');
|
||||||
if is_req {
|
if is_req {
|
||||||
match v.parse::<VersionReq>() {
|
match v.parse::<VersionReq>() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::command_prelude::*;
|
use crate::command_prelude::*;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
use cargo::ops;
|
use cargo::ops;
|
||||||
use cargo_credential::Secret;
|
use cargo_credential::Secret;
|
||||||
|
|
||||||
@ -60,5 +61,19 @@ fn resolve_crate<'k>(
|
|||||||
krate = Some(k);
|
krate = Some(k);
|
||||||
version = Some(v);
|
version = Some(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(version) = version {
|
||||||
|
semver::Version::parse(version).with_context(|| {
|
||||||
|
if let Some(stripped) = version.strip_prefix("v") {
|
||||||
|
return format!(
|
||||||
|
"the version provided, `{version}` is not a \
|
||||||
|
valid SemVer version\n\n\
|
||||||
|
help: try changing the version to `{stripped}`",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
format!("invalid version `{version}`")
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok((krate, version))
|
Ok((krate, version))
|
||||||
}
|
}
|
||||||
|
@ -523,8 +523,16 @@ impl SourceId {
|
|||||||
version: semver::Version,
|
version: semver::Version,
|
||||||
precise: &str,
|
precise: &str,
|
||||||
) -> CargoResult<SourceId> {
|
) -> CargoResult<SourceId> {
|
||||||
let precise = semver::Version::parse(precise)
|
let precise = semver::Version::parse(precise).with_context(|| {
|
||||||
.with_context(|| format!("invalid version format for precise version `{precise}`"))?;
|
if let Some(stripped) = precise.strip_prefix("v") {
|
||||||
|
return format!(
|
||||||
|
"the version provided, `{precise}` is not a \
|
||||||
|
valid SemVer version\n\n\
|
||||||
|
help: try changing the version to `{stripped}`",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
format!("invalid version format for precise version `{precise}`")
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(SourceId::wrap(SourceIdInner {
|
Ok(SourceId::wrap(SourceIdInner {
|
||||||
precise: Some(Precise::Updated {
|
precise: Some(Precise::Updated {
|
||||||
|
@ -47,8 +47,16 @@ impl CrateSpec {
|
|||||||
package_name?;
|
package_name?;
|
||||||
|
|
||||||
if let Some(version) = version {
|
if let Some(version) = version {
|
||||||
semver::VersionReq::parse(version)
|
semver::VersionReq::parse(version).with_context(|| {
|
||||||
.with_context(|| format!("invalid version requirement `{version}`"))?;
|
if let Some(stripped) = version.strip_prefix("v") {
|
||||||
|
return format!(
|
||||||
|
"the version provided, `{version}` is not a \
|
||||||
|
valid SemVer requirement\n\n\
|
||||||
|
help: changing the package to `{name}@{stripped}`",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
format!("invalid version requirement `{version}`")
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = Self {
|
let id = Self {
|
||||||
|
@ -126,6 +126,7 @@ mod path_base_unstable;
|
|||||||
mod path_dev;
|
mod path_dev;
|
||||||
mod path_inferred_name;
|
mod path_inferred_name;
|
||||||
mod path_inferred_name_conflicts_full_feature;
|
mod path_inferred_name_conflicts_full_feature;
|
||||||
|
mod prefixed_v_in_version;
|
||||||
mod preserve_dep_std_table;
|
mod preserve_dep_std_table;
|
||||||
mod preserve_features_sorted;
|
mod preserve_features_sorted;
|
||||||
mod preserve_features_table;
|
mod preserve_features_table;
|
||||||
|
1
tests/testsuite/cargo_add/prefixed_v_in_version/in
Symbolic link
1
tests/testsuite/cargo_add/prefixed_v_in_version/in
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../add-basic.in
|
26
tests/testsuite/cargo_add/prefixed_v_in_version/mod.rs
Normal file
26
tests/testsuite/cargo_add/prefixed_v_in_version/mod.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use cargo_test_support::compare::assert_ui;
|
||||||
|
use cargo_test_support::current_dir;
|
||||||
|
use cargo_test_support::file;
|
||||||
|
use cargo_test_support::prelude::*;
|
||||||
|
use cargo_test_support::str;
|
||||||
|
use cargo_test_support::Project;
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn case() {
|
||||||
|
cargo_test_support::registry::init();
|
||||||
|
|
||||||
|
let project = Project::from_template(current_dir!().join("in"));
|
||||||
|
let project_root = project.root();
|
||||||
|
let cwd = &project_root;
|
||||||
|
|
||||||
|
snapbox::cmd::Command::cargo_ui()
|
||||||
|
.arg("add")
|
||||||
|
.arg_line("foo@v0.0.1")
|
||||||
|
.current_dir(cwd)
|
||||||
|
.assert()
|
||||||
|
.code(101)
|
||||||
|
.stdout_eq(str![""])
|
||||||
|
.stderr_eq(file!["stderr.term.svg"]);
|
||||||
|
|
||||||
|
assert_ui().subset_matches(current_dir!().join("out"), &project_root);
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
[workspace]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "cargo-list-test-fixture"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2015"
|
@ -0,0 +1,37 @@
|
|||||||
|
<svg width="740px" height="146px" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<style>
|
||||||
|
.fg { fill: #AAAAAA }
|
||||||
|
.bg { background: #000000 }
|
||||||
|
.fg-red { fill: #AA0000 }
|
||||||
|
.container {
|
||||||
|
padding: 0 10px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
.bold { font-weight: bold; }
|
||||||
|
tspan {
|
||||||
|
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||||
|
white-space: pre;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
|
||||||
|
|
||||||
|
<text xml:space="preserve" class="container fg">
|
||||||
|
<tspan x="10px" y="28px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> the version provided, `v0.0.1` is not a valid SemVer requirement</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="46px">
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="64px"><tspan>help: changing the package to `foo@0.0.1`</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="82px">
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="100px"><tspan>Caused by:</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="118px"><tspan> unexpected character 'v' while parsing major version number</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="136px">
|
||||||
|
</tspan>
|
||||||
|
</text>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -2899,3 +2899,19 @@ fn dry_run_remove_orphan() {
|
|||||||
// Ensure server is still installed after the dry run
|
// Ensure server is still installed after the dry run
|
||||||
assert_has_installed_exe(paths::cargo_home(), "server");
|
assert_has_installed_exe(paths::cargo_home(), "server");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn prefixed_v_in_version() {
|
||||||
|
pkg("foo", "0.0.1");
|
||||||
|
cargo_process("install foo@v0.0.1")
|
||||||
|
.with_status(1)
|
||||||
|
.with_stderr_data(str![[r#"
|
||||||
|
[ERROR] invalid value 'foo@v0.0.1' for '[CRATE[@<VER>]]...': the version provided, `v0.0.1` is not a valid SemVer requirement
|
||||||
|
|
||||||
|
[HELP] try changing the version to `0.0.1`
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
|
||||||
|
"#]])
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
@ -2709,3 +2709,41 @@ fn update_breaking_pre_release_upgrade() {
|
|||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn prefixed_v_in_version() {
|
||||||
|
Package::new("bar", "1.0.0").publish();
|
||||||
|
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2015"
|
||||||
|
authors = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bar = "1.0.0"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("generate-lockfile").run();
|
||||||
|
|
||||||
|
Package::new("bar", "1.0.1").publish();
|
||||||
|
p.cargo("update bar --precise v1.0.1")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr_data(str![[r#"
|
||||||
|
[ERROR] the version provided, `v1.0.1` is not a valid SemVer version
|
||||||
|
|
||||||
|
[HELP] try changing the version to `1.0.1`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
unexpected character 'v' while parsing major version number
|
||||||
|
|
||||||
|
"#]])
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
@ -212,3 +212,71 @@ fn inline_and_explicit_version() {
|
|||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn bad_version() {
|
||||||
|
let registry = registry::init();
|
||||||
|
setup("foo", "0.0.1");
|
||||||
|
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
license = "MIT"
|
||||||
|
description = "foo"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/main.rs", "fn main() {}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("yank foo@bar")
|
||||||
|
.replace_crates_io(registry.index_url())
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr_data(str![[r#"
|
||||||
|
[ERROR] invalid version `bar`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
unexpected character 'b' while parsing major version number
|
||||||
|
|
||||||
|
"#]])
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn prefixed_v_in_version() {
|
||||||
|
let registry = registry::init();
|
||||||
|
setup("foo", "0.0.1");
|
||||||
|
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
license = "MIT"
|
||||||
|
description = "foo"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/main.rs", "fn main() {}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("yank bar@v0.0.1")
|
||||||
|
.replace_crates_io(registry.index_url())
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr_data(str![[r#"
|
||||||
|
[ERROR] the version provided, `v0.0.1` is not a valid SemVer version
|
||||||
|
|
||||||
|
[HELP] try changing the version to `0.0.1`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
unexpected character 'v' while parsing major version number
|
||||||
|
|
||||||
|
"#]])
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user