Skip to content

Commit

Permalink
Move package_name_validations module into new_project module
Browse files Browse the repository at this point in the history
  • Loading branch information
messense committed Feb 27, 2024
1 parent dd81231 commit 148612f
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 144 deletions.
94 changes: 68 additions & 26 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@ name = "maturin"
version = "1.4.0"
description = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages"
exclude = [
"test-crates/**/*",
"sysconfig/*",
"test-data/*",
"ci/*",
"tests/*",
"guide/*",
".github/*",
".devcontainer/*",
"Dockerfile",
".dockerignore",
"deny.toml",
"noxfile.py",
"test-dockerfile.sh",
"Code-of-Conduct.md",
"test-crates/**/*",
"sysconfig/*",
"test-data/*",
"ci/*",
"tests/*",
"guide/*",
".github/*",
".devcontainer/*",
"Dockerfile",
".dockerignore",
"deny.toml",
"noxfile.py",
"test-dockerfile.sh",
"Code-of-Conduct.md",
]
homepage = "https://github.com/pyo3/maturin"
readme = "README.md"
repository = "https://github.com/pyo3/maturin"
license = "MIT OR Apache-2.0"
keywords = ["python", "cffi", "packaging", "pypi", "pyo3"]
categories = ["api-bindings", "development-tools::ffi", "command-line-utilities"]
categories = [
"api-bindings",
"development-tools::ffi",
"command-line-utilities",
]
edition = "2021"
rust-version = "1.70"

Expand Down Expand Up @@ -53,7 +57,11 @@ tar = "0.4.38"
tempfile = "3.2.0"
toml = "0.8.8"
toml_edit = "0.21.0"
zip = { version = "0.6.1", default-features = false, features = ["bzip2", "deflate", "time"] }
zip = { version = "0.6.1", default-features = false, features = [
"bzip2",
"deflate",
"time",
] }
thiserror = "1.0.37"
fs-err = "2.11.0"
fat-macho = { version = "0.4.8", default-features = false }
Expand All @@ -75,10 +83,15 @@ path-slash = "0.2.1"
pep440_rs = { version = "0.5.0", features = ["serde", "tracing"] }
pep508_rs = { version = "0.4.2", features = ["serde", "tracing"] }
time = "0.3.17"
unicode-xid = "0.2.4"
unicode-xid = { version = "0.2.4", optional = true }

# cli
clap = { version = "4.0.0", features = ["derive", "env", "wrap_help", "unstable-styles"] }
clap = { version = "4.0.0", features = [
"derive",
"env",
"wrap_help",
"unstable-styles",
] }
clap_complete_command = { version = "0.5.1", optional = true }

# cross compile
Expand All @@ -87,7 +100,9 @@ cargo-xwin = { version = "0.16.4", default-features = false, optional = true }

# log
tracing = "0.1.36"
tracing-subscriber = { version = "0.3.15", features = ["env-filter"], optional = true }
tracing-subscriber = { version = "0.3.15", features = [
"env-filter",
], optional = true }

# project scaffolding, maturin new/init/generate-ci
dialoguer = { version = "0.11.0", default-features = false, optional = true }
Expand All @@ -98,12 +113,20 @@ minijinja = { version = "1.0.7", optional = true }
bytesize = { version = "1.0.1", optional = true }
configparser = { version = "3.0.3", optional = true }
dirs = { version = "5.0.0", optional = true }
multipart = { version = "0.18.0", features = ["client"], default-features = false, optional = true }
ureq = { version = "2.9.4", features = ["gzip", "json", "socks-proxy"], default-features = false, optional = true }
multipart = { version = "0.18.0", features = [
"client",
], default-features = false, optional = true }
ureq = { version = "2.9.4", features = [
"gzip",
"json",
"socks-proxy",
], default-features = false, optional = true }
native-tls = { version = "0.2.8", optional = true }
rustls = { version = "0.22.2", optional = true }
rustls-pemfile = { version = "2.0.0", optional = true }
keyring = { version = "2.0.0", default-features = false, features = ["linux-no-secret-service"], optional = true }
keyring = { version = "2.0.0", default-features = false, features = [
"linux-no-secret-service",
], optional = true }
wild = { version = "2.1.0", optional = true }
url = { version = "2.3.0", optional = true }

Expand All @@ -125,20 +148,39 @@ log = ["tracing-subscriber"]

cli-completion = ["dep:clap_complete_command"]

upload = ["ureq", "multipart", "configparser", "bytesize", "dialoguer/password", "url", "wild", "dep:dirs"]
upload = [
"ureq",
"multipart",
"configparser",
"bytesize",
"dialoguer/password",
"url",
"wild",
"dep:dirs",
]
# keyring doesn't support *BSD so it's not enabled in `full` by default
password-storage = ["upload", "keyring"]

rustls = ["dep:rustls", "ureq?/tls", "cargo-xwin?/rustls-tls", "dep:rustls-pemfile"]
native-tls = ["dep:native-tls", "ureq?/native-tls", "cargo-xwin?/native-tls", "dep:rustls-pemfile"]
rustls = [
"dep:rustls",
"ureq?/tls",
"cargo-xwin?/rustls-tls",
"dep:rustls-pemfile",
]
native-tls = [
"dep:native-tls",
"ureq?/native-tls",
"cargo-xwin?/native-tls",
"dep:rustls-pemfile",
]

# cross compile using zig or xwin
cross-compile = ["zig", "xwin"]
zig = ["cargo-zigbuild"]
xwin = ["cargo-xwin"]

# project scaffolding
scaffolding = ["dialoguer", "console", "minijinja"]
scaffolding = ["dialoguer", "console", "minijinja", "unicode-xid"]

# Internal feature to speed up the tests significantly
faster-tests = []
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ mod metadata;
mod module_writer;
#[cfg(feature = "scaffolding")]
mod new_project;
mod package_name_validations;
mod project_layout;
pub mod pyproject_toml;
mod python_interpreter;
Expand Down
122 changes: 121 additions & 1 deletion src/new_project.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use self::package_name_validations::cargo_check_name;
use crate::ci::GenerateCI;
use crate::package_name_validations::cargo_check_name;
use crate::BridgeModel;
use anyhow::{bail, Context, Result};
use console::style;
Expand Down Expand Up @@ -256,3 +256,123 @@ fn generate_project(
let generator = ProjectGenerator::new(name, layout, bindings, overwrite)?;
generator.generate(project_path)
}

mod package_name_validations {
// Based on: https://github.com/rust-lang/cargo/blob/e975158c1b542aa3833fd8584746538c17a6ae55/src/cargo/ops/cargo_new.rs#L169
pub fn cargo_check_name(name: &str) -> anyhow::Result<()> {
// Instead of `PackageName::new` which performs these checks in the original cargo code
validate_package_name(name)?;

if is_keyword(name) {
anyhow::bail!(
"the name `{}` cannot be used as a package name, it is a Rust keyword",
name,
);
}
if is_conflicting_artifact_name(name) {
anyhow::bail!(
"the name `{}` cannot be used as a package name, \
it conflicts with cargo's build directory names",
name,
);
}
if name == "test" {
anyhow::bail!(
"the name `test` cannot be used as a package name, \
it conflicts with Rust's built-in test library",
);
}
if ["core", "std", "alloc", "proc_macro", "proc-macro"].contains(&name) {
eprintln!(
"⚠️ Warning: the name `{}` is part of Rust's standard library\n\
It is recommended to use a different name to avoid problems.",
name,
);
}
if is_windows_reserved(name) {
eprintln!(
"⚠️ Warning: the name `{}` is a reserved Windows filename\n\
This package will not work on Windows platforms.",
name
);
}
if is_non_ascii_name(name) {
eprintln!(
"⚠️ Warning: the name `{}` contains non-ASCII characters\n\
Non-ASCII crate names are not supported by Rust.",
name
);
}
let name_in_lowercase = name.to_lowercase();
if name != name_in_lowercase {
eprintln!(
"⚠️ Warning: the name `{name}` is not snake_case or kebab-case which is recommended for package names, consider `{name_in_lowercase}`"
);
}

Ok(())
}

// Based on: https://github.com/rust-lang/cargo/blob/7b7af3077bff8d60b7f124189bc9de227d3063a9/crates/cargo-util-schemas/src/restricted_names.rs#L42
fn validate_package_name(name: &str) -> anyhow::Result<()> {
if name.is_empty() {
anyhow::bail!("Package names cannot be empty");
}

let mut chars = name.chars();
if let Some(ch) = chars.next() {
if ch.is_ascii_digit() {
// A specific error for a potentially common case.
anyhow::bail!("Package names cannot start with a digit");
}
if !(unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_') {
anyhow::bail!(
"the first character must be a Unicode XID start character (most letters or `_`)"
);
}
}
for ch in chars {
if !(unicode_xid::UnicodeXID::is_xid_continue(ch) || ch == '-') {
anyhow::bail!(
"characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)"
);
}
}
Ok(())
}

// The following functions are based on https://github.com/rust-lang/cargo/blob/e975158c1b542aa3833fd8584746538c17a6ae55/src/cargo/util/restricted_names.rs

/// Returns `true` if the name contains non-ASCII characters.
pub fn is_non_ascii_name(name: &str) -> bool {
name.chars().any(|ch| ch > '\x7f')
}

/// A Rust keyword.
pub fn is_keyword(name: &str) -> bool {
// See https://doc.rust-lang.org/reference/keywords.html
[
"Self", "abstract", "as", "async", "await", "become", "box", "break", "const",
"continue", "crate", "do", "dyn", "else", "enum", "extern", "false", "final", "fn",
"for", "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
"override", "priv", "pub", "ref", "return", "self", "static", "struct", "super",
"trait", "true", "try", "type", "typeof", "unsafe", "unsized", "use", "virtual",
"where", "while", "yield",
]
.contains(&name)
}

/// These names cannot be used on Windows, even with an extension.
pub fn is_windows_reserved(name: &str) -> bool {
[
"con", "prn", "aux", "nul", "com1", "com2", "com3", "com4", "com5", "com6", "com7",
"com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
]
.contains(&name.to_ascii_lowercase().as_str())
}

/// An artifact with this name will conflict with one of Cargo's build directories.
pub fn is_conflicting_artifact_name(name: &str) -> bool {
["deps", "examples", "build", "incremental"].contains(&name)
}
}
Loading

0 comments on commit 148612f

Please sign in to comment.