feat(toml): Add support for open namespaces

This commit is contained in:
Ed Page 2024-03-15 11:52:41 -05:00
parent 489dde1114
commit 9ea3f260a8
4 changed files with 198 additions and 57 deletions

View file

@ -34,7 +34,10 @@ enum ErrorKind {
} }
pub(crate) fn validate_package_name(name: &str) -> Result<()> { pub(crate) fn validate_package_name(name: &str) -> Result<()> {
validate_name(name, "package name") for part in name.split("::") {
validate_name(part, "package name")?;
}
Ok(())
} }
pub(crate) fn validate_registry_name(name: &str) -> Result<()> { pub(crate) fn validate_registry_name(name: &str) -> Result<()> {
@ -86,6 +89,17 @@ pub(crate) fn validate_name(name: &str, what: &'static str) -> Result<()> {
/// Ensure a package name is [valid][validate_package_name] /// Ensure a package name is [valid][validate_package_name]
pub(crate) fn sanitize_package_name(name: &str, placeholder: char) -> String { pub(crate) fn sanitize_package_name(name: &str, placeholder: char) -> String {
let mut slug = String::new();
for part in name.split("::") {
if !slug.is_empty() {
slug.push_str("::");
}
slug.push_str(&sanitize_name(part, placeholder));
}
slug
}
pub(crate) fn sanitize_name(name: &str, placeholder: char) -> String {
let mut slug = String::new(); let mut slug = String::new();
let mut chars = name.chars(); let mut chars = name.chars();
while let Some(ch) = chars.next() { while let Some(ch) = chars.next() {

View file

@ -247,6 +247,16 @@ pub fn prepare_for_publish(
package_root: &Path, package_root: &Path,
) -> CargoResult<manifest::TomlManifest> { ) -> CargoResult<manifest::TomlManifest> {
let gctx = ws.gctx(); let gctx = ws.gctx();
if me
.cargo_features
.iter()
.flat_map(|f| f.iter())
.any(|f| f == "open-namespaces")
{
anyhow::bail!("cannot publish with `open-namespaces`")
}
let mut package = me.package().unwrap().clone(); let mut package = me.package().unwrap().clone();
package.workspace = None; package.workspace = None;
let current_resolver = package let current_resolver = package
@ -587,6 +597,9 @@ pub fn to_real_manifest(
}; };
let package_name = package.name.trim(); let package_name = package.name.trim();
if package_name.contains(':') {
features.require(Feature::open_namespaces())?;
}
let resolved_path = package_root.join("Cargo.toml"); let resolved_path = package_root.join("Cargo.toml");

View file

@ -467,18 +467,18 @@ fn cargo_compile_with_empty_package_name() {
#[cargo_test] #[cargo_test]
fn cargo_compile_with_invalid_package_name() { fn cargo_compile_with_invalid_package_name() {
let p = project() let p = project()
.file("Cargo.toml", &basic_manifest("foo::bar", "0.0.0")) .file("Cargo.toml", &basic_manifest("foo@bar", "0.0.0"))
.build(); .build();
p.cargo("build") p.cargo("build")
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) [ERROR] invalid character `@` in package name: `foo@bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
--> Cargo.toml:3:16 --> Cargo.toml:3:16
| |
3 | name = \"foo::bar\" 3 | name = \"foo@bar\"
| ^^^^^^^^^^ | ^^^^^^^^^
| |
", ",
) )

View file

@ -20,14 +20,15 @@ fn within_namespace_requires_feature() {
.masquerade_as_nightly_cargo(&["open-namespaces"]) .masquerade_as_nightly_cargo(&["open-namespaces"])
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ r#"error: failed to parse manifest at `[CWD]/Cargo.toml`
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)
--> Cargo.toml:3:24 Caused by:
| feature `open-namespaces` is required
3 | name = \"foo::bar\"
| ^^^^^^^^^^ The package requires the Cargo feature called `open-namespaces`, but that feature is not stabilized in this version of Cargo ([..]).
| 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.
", See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#open-namespaces for more information about the status of this feature.
"#,
) )
.run() .run()
} }
@ -51,17 +52,50 @@ fn implicit_lib_within_namespace() {
p.cargo("read-manifest") p.cargo("read-manifest")
.masquerade_as_nightly_cargo(&["open-namespaces"]) .masquerade_as_nightly_cargo(&["open-namespaces"])
.with_status(101) .with_json(
.with_stderr( r#"{
"\ "authors": [],
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) "categories": [],
--> Cargo.toml:5:24 "default_run": null,
| "dependencies": [],
5 | name = \"foo::bar\" "description": null,
| ^^^^^^^^^^ "documentation": null,
| "edition": "2015",
", "features": {},
"homepage": null,
"id": "path+file://[..]#foo::bar@0.0.1",
"keywords": [],
"license": null,
"license_file": null,
"links": null,
"manifest_path": "[CWD]/Cargo.toml",
"metadata": null,
"name": "foo::bar",
"publish": null,
"readme": null,
"repository": null,
"rust_version": null,
"source": null,
"targets": [
{
"crate_types": [
"lib"
],
"doc": true,
"doctest": true,
"edition": "2015",
"kind": [
"lib"
],
"name": "foo::bar",
"src_path": "[CWD]/src/lib.rs",
"test": true
}
],
"version": "0.0.1"
}"#,
) )
.with_stderr("")
.run() .run()
} }
@ -84,17 +118,50 @@ fn implicit_bin_within_namespace() {
p.cargo("read-manifest") p.cargo("read-manifest")
.masquerade_as_nightly_cargo(&["open-namespaces"]) .masquerade_as_nightly_cargo(&["open-namespaces"])
.with_status(101) .with_json(
.with_stderr( r#"{
"\ "authors": [],
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) "categories": [],
--> Cargo.toml:5:24 "default_run": null,
| "dependencies": [],
5 | name = \"foo::bar\" "description": null,
| ^^^^^^^^^^ "documentation": null,
| "edition": "2015",
", "features": {},
"homepage": null,
"id": "path+file://[..]#foo::bar@0.0.1",
"keywords": [],
"license": null,
"license_file": null,
"links": null,
"manifest_path": "[CWD]/Cargo.toml",
"metadata": null,
"name": "foo::bar",
"publish": null,
"readme": null,
"repository": null,
"rust_version": null,
"source": null,
"targets": [
{
"crate_types": [
"bin"
],
"doc": true,
"doctest": false,
"edition": "2015",
"kind": [
"bin"
],
"name": "foo::bar",
"src_path": "[CWD]/src/main.rs",
"test": true
}
],
"version": "0.0.1"
}"#,
) )
.with_stderr("")
.run() .run()
} }
@ -116,22 +183,69 @@ fn explicit_bin_within_namespace() {
"#, "#,
) )
.file("src/lib.rs", "") .file("src/lib.rs", "")
.file("src/foo-bar/main.rs", "fn main() {}") .file("src/bin/foo-bar/main.rs", "fn main() {}")
.build(); .build();
p.cargo("read-manifest") p.cargo("read-manifest")
.masquerade_as_nightly_cargo(&["open-namespaces"]) .masquerade_as_nightly_cargo(&["open-namespaces"])
.with_status(101) .with_json(
.with_stderr( r#"{
"\ "authors": [],
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) "categories": [],
--> Cargo.toml:5:24 "default_run": null,
| "dependencies": [],
5 | name = \"foo::bar\" "description": null,
| ^^^^^^^^^^ "documentation": null,
| "edition": "2015",
", "features": {},
"homepage": null,
"id": "path+file://[..]#foo::bar@0.0.1",
"keywords": [],
"license": null,
"license_file": null,
"links": null,
"manifest_path": "[CWD]/Cargo.toml",
"metadata": null,
"name": "foo::bar",
"publish": null,
"readme": null,
"repository": null,
"rust_version": null,
"source": null,
"targets": [
{
"crate_types": [
"lib"
],
"doc": true,
"doctest": true,
"edition": "2015",
"kind": [
"lib"
],
"name": "foo::bar",
"src_path": "[CWD]/src/lib.rs",
"test": true
},
{
"crate_types": [
"bin"
],
"doc": true,
"doctest": false,
"edition": "2015",
"kind": [
"bin"
],
"name": "foo-bar",
"src_path": "[CWD]/src/bin/foo-bar/main.rs",
"test": true
}
],
"version": "0.0.1"
}"#,
) )
.with_stderr("")
.run() .run()
} }
@ -164,14 +278,14 @@ fn main() {}
"edition": "2021", "edition": "2021",
"features": {}, "features": {},
"homepage": null, "homepage": null,
"id": "path+file://[..]#foo--bar@0.0.0", "id": "path+file://[..]#foo::bar@0.0.0",
"keywords": [], "keywords": [],
"license": null, "license": null,
"license_file": null, "license_file": null,
"links": null, "links": null,
"manifest_path": "[CWD]/foo::bar.rs", "manifest_path": "[CWD]/foo::bar.rs",
"metadata": null, "metadata": null,
"name": "foo--bar", "name": "foo::bar",
"publish": [], "publish": [],
"readme": null, "readme": null,
"repository": null, "repository": null,
@ -188,7 +302,7 @@ fn main() {}
"kind": [ "kind": [
"bin" "bin"
], ],
"name": "foo--bar", "name": "foo::bar",
"src_path": "[..]/foo::bar.rs", "src_path": "[..]/foo::bar.rs",
"test": true "test": true
} }
@ -197,14 +311,12 @@ fn main() {}
} }
"#, "#,
) )
.with_stderr( .with_stderr("")
"\
",
)
.run(); .run();
} }
#[cargo_test] #[cargo_test]
#[cfg(unix)] // until we get proper packaging support
fn publish_namespaced() { fn publish_namespaced() {
let registry = RegistryBuilder::new().http_api().http_index().build(); let registry = RegistryBuilder::new().http_api().http_index().build();
@ -232,12 +344,14 @@ fn publish_namespaced() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] invalid character `:` in package name: `foo::bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) [UPDATING] crates.io index
--> Cargo.toml:5:24 [WARNING] manifest has no documentation, homepage or repository.
| See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
5 | name = \"foo::bar\" Packaging foo::bar v0.0.1 ([CWD])
| ^^^^^^^^^^ [ERROR] failed to prepare local package for uploading
|
Caused by:
cannot publish with `open-namespaces`
", ",
) )
.run(); .run();