Skip to content

Commit dd53196

Browse files
committed
Auto merge of #10597 - epage:yank, r=ehuss
feat(yank): Support foo@version like cargo-add ### What does this PR try to resolve? In #10472, cargo-add was merged with support for an inline version syntax of `cargo add foo@version`. That also served as the change proposal for extending that syntax to `cargo yank` for convenience and consistency. ### How should we test and review this PR? Documentation updates are split into their own commit to not clog up browsing the code. The ops API is generic enough that this is implemented purely in the command. For now, the `foo@version` syntax parser is being left in the command, rather than being shared, as we see how the behavior of these different parsers diverge for their target needs to see what makes sense for refactoring. See also The Rule of Three - This doesn't use the full `pkgid` syntax (modified in #10582) because that allows syntax that is unsupported here. - This doesn't use `cargo-add`s parser because that is for version reqs. Tests were added for various combinations of flags and behavior. ### Additional information The major difference is that `cargo-add` is specifying a version-req while `cargo-yank` is specifying a version. This was originally discussed on [zulip](https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/Multiple.20ways.20of.20specifying.20versions) and there seemed to be a desire to have one syntax rather than the user thinking about a syntax per type of version (which users won't always think about). See also #10582 which extended the pkgid spec syntax and has some more discussion on this general trend. `cargo-install` will be updated in a subsequent PR.
2 parents f643459 + 790e4ce commit dd53196

File tree

6 files changed

+149
-9
lines changed

6 files changed

+149
-9
lines changed

src/bin/cargo/commands/yank.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ pub fn cli() -> App {
1010
.arg(
1111
opt("version", "The version to yank or un-yank")
1212
.alias("vers")
13-
.value_name("VERSION")
14-
.required(true),
13+
.value_name("VERSION"),
1514
)
1615
.arg(opt(
1716
"undo",
@@ -28,14 +27,37 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
2827

2928
let registry = args.registry(config)?;
3029

30+
let (krate, version) = resolve_crate(args.value_of("crate"), args.value_of("version"))?;
31+
if version.is_none() {
32+
return Err(anyhow::format_err!("`--version` is required").into());
33+
}
34+
3135
ops::yank(
3236
config,
33-
args.value_of("crate").map(|s| s.to_string()),
34-
args.value_of("version").map(|s| s.to_string()),
37+
krate.map(|s| s.to_string()),
38+
version.map(|s| s.to_string()),
3539
args.value_of("token").map(|s| s.to_string()),
3640
args.value_of("index").map(|s| s.to_string()),
3741
args.is_present("undo"),
3842
registry,
3943
)?;
4044
Ok(())
4145
}
46+
47+
fn resolve_crate<'k>(
48+
mut krate: Option<&'k str>,
49+
mut version: Option<&'k str>,
50+
) -> crate::CargoResult<(Option<&'k str>, Option<&'k str>)> {
51+
if let Some((k, v)) = krate.and_then(|k| k.split_once('@')) {
52+
if version.is_some() {
53+
anyhow::bail!("cannot specify both `@{v}` and `--version`");
54+
}
55+
if k.is_empty() {
56+
// by convention, arguments starting with `@` are response files
57+
anyhow::bail!("missing crate name for `@{v}`");
58+
}
59+
krate = Some(k);
60+
version = Some(v);
61+
}
62+
Ok((krate, version))
63+
}

src/doc/man/cargo-yank.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ cargo-yank - Remove a pushed crate from the index
66

77
## SYNOPSIS
88

9+
`cargo yank` [_options_] _crate_@_version_\
910
`cargo yank` [_options_] `--version` _version_ [_crate_]
1011

1112
## DESCRIPTION
@@ -64,7 +65,7 @@ Undo a yank, putting a version back into the index.
6465

6566
1. Yank a crate from the index:
6667

67-
cargo yank --version 1.0.7 foo
68+
cargo yank foo@1.0.7
6869

6970
## SEE ALSO
7071
{{man "cargo" 1}}, {{man "cargo-login" 1}}, {{man "cargo-publish" 1}}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ NAME
44
cargo-yank - Remove a pushed crate from the index
55

66
SYNOPSIS
7+
cargo yank [options] crate@version
78
cargo yank [options] --version version [crate]
89

910
DESCRIPTION
@@ -104,7 +105,7 @@ EXIT STATUS
104105
EXAMPLES
105106
1. Yank a crate from the index:
106107

107-
cargo yank --version 1.0.7 foo
108+
cargo yank foo@1.0.7
108109

109110
SEE ALSO
110111
cargo(1), cargo-login(1), cargo-publish(1)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ cargo-yank - Remove a pushed crate from the index
66

77
## SYNOPSIS
88

9+
`cargo yank` [_options_] _crate_@_version_\
910
`cargo yank` [_options_] `--version` _version_ [_crate_]
1011

1112
## DESCRIPTION
@@ -140,7 +141,7 @@ details on environment variables that Cargo reads.
140141

141142
1. Yank a crate from the index:
142143

143-
cargo yank --version 1.0.7 foo
144+
cargo yank foo@1.0.7
144145

145146
## SEE ALSO
146147
[cargo(1)](cargo.html), [cargo-login(1)](cargo-login.html), [cargo-publish(1)](cargo-publish.html)

src/etc/man/cargo-yank.1

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
.SH "NAME"
77
cargo\-yank \- Remove a pushed crate from the index
88
.SH "SYNOPSIS"
9+
\fBcargo yank\fR [\fIoptions\fR] \fIcrate\fR@\fIversion\fR
10+
.br
911
\fBcargo yank\fR [\fIoptions\fR] \fB\-\-version\fR \fIversion\fR [\fIcrate\fR]
1012
.SH "DESCRIPTION"
1113
The yank command removes a previously published crate's version from the
@@ -139,7 +141,7 @@ details on environment variables that Cargo reads.
139141
.sp
140142
.RS 4
141143
.nf
142-
cargo yank \-\-version 1.0.7 foo
144+
cargo yank foo@1.0.7
143145
.fi
144146
.RE
145147
.RE

tests/testsuite/yank.rs

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn setup(name: &str, version: &str) {
1313
}
1414

1515
#[cargo_test]
16-
fn simple() {
16+
fn explicit_version() {
1717
registry::init();
1818
setup("foo", "0.0.1");
1919

@@ -46,3 +46,116 @@ Caused by:
4646
)
4747
.run();
4848
}
49+
50+
#[cargo_test]
51+
fn inline_version() {
52+
registry::init();
53+
setup("foo", "0.0.1");
54+
55+
let p = project()
56+
.file(
57+
"Cargo.toml",
58+
r#"
59+
[project]
60+
name = "foo"
61+
version = "0.0.1"
62+
authors = []
63+
license = "MIT"
64+
description = "foo"
65+
"#,
66+
)
67+
.file("src/main.rs", "fn main() {}")
68+
.build();
69+
70+
p.cargo("yank foo@0.0.1 --token sekrit").run();
71+
72+
p.cargo("yank --undo foo@0.0.1 --token sekrit")
73+
.with_status(101)
74+
.with_stderr(
75+
" Updating `[..]` index
76+
Unyank foo@0.0.1
77+
error: failed to undo a yank from the registry at file:///[..]
78+
79+
Caused by:
80+
EOF while parsing a value at line 1 column 0",
81+
)
82+
.run();
83+
}
84+
85+
#[cargo_test]
86+
fn version_required() {
87+
registry::init();
88+
setup("foo", "0.0.1");
89+
90+
let p = project()
91+
.file(
92+
"Cargo.toml",
93+
r#"
94+
[project]
95+
name = "foo"
96+
version = "0.0.1"
97+
authors = []
98+
license = "MIT"
99+
description = "foo"
100+
"#,
101+
)
102+
.file("src/main.rs", "fn main() {}")
103+
.build();
104+
105+
p.cargo("yank foo --token sekrit")
106+
.with_status(101)
107+
.with_stderr("error: `--version` is required")
108+
.run();
109+
}
110+
111+
#[cargo_test]
112+
fn inline_version_without_name() {
113+
registry::init();
114+
setup("foo", "0.0.1");
115+
116+
let p = project()
117+
.file(
118+
"Cargo.toml",
119+
r#"
120+
[project]
121+
name = "foo"
122+
version = "0.0.1"
123+
authors = []
124+
license = "MIT"
125+
description = "foo"
126+
"#,
127+
)
128+
.file("src/main.rs", "fn main() {}")
129+
.build();
130+
131+
p.cargo("yank @0.0.1 --token sekrit")
132+
.with_status(101)
133+
.with_stderr("error: missing crate name for `@0.0.1`")
134+
.run();
135+
}
136+
137+
#[cargo_test]
138+
fn inline_and_explicit_version() {
139+
registry::init();
140+
setup("foo", "0.0.1");
141+
142+
let p = project()
143+
.file(
144+
"Cargo.toml",
145+
r#"
146+
[project]
147+
name = "foo"
148+
version = "0.0.1"
149+
authors = []
150+
license = "MIT"
151+
description = "foo"
152+
"#,
153+
)
154+
.file("src/main.rs", "fn main() {}")
155+
.build();
156+
157+
p.cargo("yank foo@0.0.1 --version 0.0.1 --token sekrit")
158+
.with_status(101)
159+
.with_stderr("error: cannot specify both `@0.0.1` and `--version`")
160+
.run();
161+
}

0 commit comments

Comments
 (0)