Skip to content

Commit de5ac27

Browse files
committed
feat(toml): Add support for open namespaces
1 parent 489dde1 commit de5ac27

File tree

4 files changed

+197
-57
lines changed

4 files changed

+197
-57
lines changed

crates/cargo-util-schemas/src/restricted_names.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ enum ErrorKind {
3434
}
3535

3636
pub(crate) fn validate_package_name(name: &str) -> Result<()> {
37-
validate_name(name, "package name")
37+
for part in name.split("::") {
38+
validate_name(part, "package name")?;
39+
}
40+
Ok(())
3841
}
3942

4043
pub(crate) fn validate_registry_name(name: &str) -> Result<()> {
@@ -86,6 +89,17 @@ pub(crate) fn validate_name(name: &str, what: &'static str) -> Result<()> {
8689

8790
/// Ensure a package name is [valid][validate_package_name]
8891
pub(crate) fn sanitize_package_name(name: &str, placeholder: char) -> String {
92+
let mut slug = String::new();
93+
for part in name.split("::") {
94+
if !slug.is_empty() {
95+
slug.push_str("::");
96+
}
97+
slug.push_str(&sanitize_name(part, placeholder));
98+
}
99+
slug
100+
}
101+
102+
pub(crate) fn sanitize_name(name: &str, placeholder: char) -> String {
89103
let mut slug = String::new();
90104
let mut chars = name.chars();
91105
while let Some(ch) = chars.next() {

src/cargo/util/toml/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,16 @@ pub fn prepare_for_publish(
247247
package_root: &Path,
248248
) -> CargoResult<manifest::TomlManifest> {
249249
let gctx = ws.gctx();
250+
251+
if me
252+
.cargo_features
253+
.iter()
254+
.flat_map(|f| f.iter())
255+
.any(|f| f == "open-namespaces")
256+
{
257+
anyhow::bail!("cannot publish with `open-namespaces`")
258+
}
259+
250260
let mut package = me.package().unwrap().clone();
251261
package.workspace = None;
252262
let current_resolver = package
@@ -587,6 +597,9 @@ pub fn to_real_manifest(
587597
};
588598

589599
let package_name = package.name.trim();
600+
if package_name.contains(':') {
601+
features.require(Feature::open_namespaces())?;
602+
}
590603

591604
let resolved_path = package_root.join("Cargo.toml");
592605

tests/testsuite/build.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -467,18 +467,18 @@ fn cargo_compile_with_empty_package_name() {
467467
#[cargo_test]
468468
fn cargo_compile_with_invalid_package_name() {
469469
let p = project()
470-
.file("Cargo.toml", &basic_manifest("foo::bar", "0.0.0"))
470+
.file("Cargo.toml", &basic_manifest("foo@bar", "0.0.0"))
471471
.build();
472472

473473
p.cargo("build")
474474
.with_status(101)
475475
.with_stderr(
476476
"\
477-
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
477+
[ERROR] invalid character `@` in package name: `foo@bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
478478
--> Cargo.toml:3:16
479479
|
480-
3 | name = \"foo::bar\"
481-
| ^^^^^^^^^^
480+
3 | name = \"foo@bar\"
481+
| ^^^^^^^^^
482482
|
483483
",
484484
)

tests/testsuite/open_namespaces.rs

Lines changed: 165 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ fn within_namespace_requires_feature() {
2020
.masquerade_as_nightly_cargo(&["open-namespaces"])
2121
.with_status(101)
2222
.with_stderr(
23-
"\
24-
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
25-
--> Cargo.toml:3:24
26-
|
27-
3 | name = \"foo::bar\"
28-
| ^^^^^^^^^^
29-
|
30-
",
23+
r#"error: failed to parse manifest at `[CWD]/Cargo.toml`
24+
25+
Caused by:
26+
feature `open-namespaces` is required
27+
28+
The package requires the Cargo feature called `open-namespaces`, but that feature is not stabilized in this version of Cargo ([..]).
29+
Consider adding `cargo-features = ["open-namespaces"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature.
30+
See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#open-namespaces for more information about the status of this feature.
31+
"#,
3132
)
3233
.run()
3334
}
@@ -51,17 +52,50 @@ fn implicit_lib_within_namespace() {
5152

5253
p.cargo("read-manifest")
5354
.masquerade_as_nightly_cargo(&["open-namespaces"])
54-
.with_status(101)
55-
.with_stderr(
56-
"\
57-
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
58-
--> Cargo.toml:5:24
59-
|
60-
5 | name = \"foo::bar\"
61-
| ^^^^^^^^^^
62-
|
63-
",
55+
.with_json(
56+
r#"{
57+
"authors": [],
58+
"categories": [],
59+
"default_run": null,
60+
"dependencies": [],
61+
"description": null,
62+
"documentation": null,
63+
"edition": "2015",
64+
"features": {},
65+
"homepage": null,
66+
"id": "path+file://[..]#foo::[email protected]",
67+
"keywords": [],
68+
"license": null,
69+
"license_file": null,
70+
"links": null,
71+
"manifest_path": "[CWD]/Cargo.toml",
72+
"metadata": null,
73+
"name": "foo::bar",
74+
"publish": null,
75+
"readme": null,
76+
"repository": null,
77+
"rust_version": null,
78+
"source": null,
79+
"targets": [
80+
{
81+
"crate_types": [
82+
"lib"
83+
],
84+
"doc": true,
85+
"doctest": true,
86+
"edition": "2015",
87+
"kind": [
88+
"lib"
89+
],
90+
"name": "foo::bar",
91+
"src_path": "[CWD]/src/lib.rs",
92+
"test": true
93+
}
94+
],
95+
"version": "0.0.1"
96+
}"#,
6497
)
98+
.with_stderr("")
6599
.run()
66100
}
67101

@@ -84,17 +118,50 @@ fn implicit_bin_within_namespace() {
84118

85119
p.cargo("read-manifest")
86120
.masquerade_as_nightly_cargo(&["open-namespaces"])
87-
.with_status(101)
88-
.with_stderr(
89-
"\
90-
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
91-
--> Cargo.toml:5:24
92-
|
93-
5 | name = \"foo::bar\"
94-
| ^^^^^^^^^^
95-
|
96-
",
121+
.with_json(
122+
r#"{
123+
"authors": [],
124+
"categories": [],
125+
"default_run": null,
126+
"dependencies": [],
127+
"description": null,
128+
"documentation": null,
129+
"edition": "2015",
130+
"features": {},
131+
"homepage": null,
132+
"id": "path+file://[..]#foo::[email protected]",
133+
"keywords": [],
134+
"license": null,
135+
"license_file": null,
136+
"links": null,
137+
"manifest_path": "[CWD]/Cargo.toml",
138+
"metadata": null,
139+
"name": "foo::bar",
140+
"publish": null,
141+
"readme": null,
142+
"repository": null,
143+
"rust_version": null,
144+
"source": null,
145+
"targets": [
146+
{
147+
"crate_types": [
148+
"bin"
149+
],
150+
"doc": true,
151+
"doctest": false,
152+
"edition": "2015",
153+
"kind": [
154+
"bin"
155+
],
156+
"name": "foo::bar",
157+
"src_path": "[CWD]/src/main.rs",
158+
"test": true
159+
}
160+
],
161+
"version": "0.0.1"
162+
}"#,
97163
)
164+
.with_stderr("")
98165
.run()
99166
}
100167

@@ -116,22 +183,69 @@ fn explicit_bin_within_namespace() {
116183
"#,
117184
)
118185
.file("src/lib.rs", "")
119-
.file("src/foo-bar/main.rs", "fn main() {}")
186+
.file("src/bin/foo-bar/main.rs", "fn main() {}")
120187
.build();
121188

122189
p.cargo("read-manifest")
123190
.masquerade_as_nightly_cargo(&["open-namespaces"])
124-
.with_status(101)
125-
.with_stderr(
126-
"\
127-
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
128-
--> Cargo.toml:5:24
129-
|
130-
5 | name = \"foo::bar\"
131-
| ^^^^^^^^^^
132-
|
133-
",
191+
.with_json(
192+
r#"{
193+
"authors": [],
194+
"categories": [],
195+
"default_run": null,
196+
"dependencies": [],
197+
"description": null,
198+
"documentation": null,
199+
"edition": "2015",
200+
"features": {},
201+
"homepage": null,
202+
"id": "path+file://[..]#foo::[email protected]",
203+
"keywords": [],
204+
"license": null,
205+
"license_file": null,
206+
"links": null,
207+
"manifest_path": "[CWD]/Cargo.toml",
208+
"metadata": null,
209+
"name": "foo::bar",
210+
"publish": null,
211+
"readme": null,
212+
"repository": null,
213+
"rust_version": null,
214+
"source": null,
215+
"targets": [
216+
{
217+
"crate_types": [
218+
"lib"
219+
],
220+
"doc": true,
221+
"doctest": true,
222+
"edition": "2015",
223+
"kind": [
224+
"lib"
225+
],
226+
"name": "foo::bar",
227+
"src_path": "[CWD]/src/lib.rs",
228+
"test": true
229+
},
230+
{
231+
"crate_types": [
232+
"bin"
233+
],
234+
"doc": true,
235+
"doctest": false,
236+
"edition": "2015",
237+
"kind": [
238+
"bin"
239+
],
240+
"name": "foo-bar",
241+
"src_path": "[CWD]/src/bin/foo-bar/main.rs",
242+
"test": true
243+
}
244+
],
245+
"version": "0.0.1"
246+
}"#,
134247
)
248+
.with_stderr("")
135249
.run()
136250
}
137251

@@ -164,14 +278,14 @@ fn main() {}
164278
"edition": "2021",
165279
"features": {},
166280
"homepage": null,
167-
"id": "path+file://[..]#foo--[email protected]",
281+
"id": "path+file://[..]#foo::[email protected]",
168282
"keywords": [],
169283
"license": null,
170284
"license_file": null,
171285
"links": null,
172286
"manifest_path": "[CWD]/foo::bar.rs",
173287
"metadata": null,
174-
"name": "foo--bar",
288+
"name": "foo::bar",
175289
"publish": [],
176290
"readme": null,
177291
"repository": null,
@@ -188,7 +302,7 @@ fn main() {}
188302
"kind": [
189303
"bin"
190304
],
191-
"name": "foo--bar",
305+
"name": "foo::bar",
192306
"src_path": "[..]/foo::bar.rs",
193307
"test": true
194308
}
@@ -197,10 +311,7 @@ fn main() {}
197311
}
198312
"#,
199313
)
200-
.with_stderr(
201-
"\
202-
",
203-
)
314+
.with_stderr("")
204315
.run();
205316
}
206317

@@ -232,12 +343,14 @@ fn publish_namespaced() {
232343
.with_status(101)
233344
.with_stderr(
234345
"\
235-
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
236-
--> Cargo.toml:5:24
237-
|
238-
5 | name = \"foo::bar\"
239-
| ^^^^^^^^^^
240-
|
346+
[UPDATING] crates.io index
347+
[WARNING] manifest has no documentation, homepage or repository.
348+
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
349+
Packaging foo::bar v0.0.1 ([CWD])
350+
[ERROR] failed to prepare local package for uploading
351+
352+
Caused by:
353+
cannot publish with `open-namespaces`
241354
",
242355
)
243356
.run();

0 commit comments

Comments
 (0)