feat: add package name validation in default manifest generation; clarify pkg-config dependency requirements

This commit is contained in:
2026-09-13 14:46:57 +08:00
parent be14cfb8e2
commit 6c79340736
4 changed files with 27 additions and 9 deletions

View File

@@ -56,9 +56,10 @@ fmt = { pkg-config = "fmt" }
openssl = { pkg-config = ["openssl", "libcrypto"] }
```
The `pkg-config` executable and the named packages must be available in `PATH` and
`PKG_CONFIG_PATH`. These dependencies are not downloaded or built by DCR; they are
recorded in `dcr.lock` with a `pkg-config+...` source.
The `pkg-config` executable must be available in `PATH`. The named `.pc` files must
be available through pkg-config's standard search paths or via `PKG_CONFIG_PATH`.
These dependencies are not downloaded or built by DCR; they are recorded in
`dcr.lock` with a `pkg-config+...` source.
## Registry

Submodule examples/dcr-math deleted from 737d9629c5

View File

@@ -1,4 +1,4 @@
.TH DCR 1 "2026-06-02" "dcr 0.7.0" "DCR Manual"
.TH DCR 1 "2026-08-31" "dcr 0.9.1" "DCR Manual"
.SH NAME
dcr \- Cargo\-like build tool and package manager for C/C++ projects
.SH SYNOPSIS

View File

@@ -256,7 +256,7 @@ impl Config {
let (data, doc) = if path.exists() {
load_parts(&path)?
} else {
let content = default_toml_text(package_name);
let content = default_toml_text(package_name)?;
let doc: DocumentMut = content.parse().map_err(ConfigError::TomlEdit)?;
fs::write(&path, doc.to_string())?;
let data: Value = toml::from_str(&content)?;
@@ -836,7 +836,7 @@ fn load_parts(path: &Path) -> Result<(Value, DocumentMut), ConfigError> {
Ok((data, doc))
}
fn default_toml_text(package_name: Option<&str>) -> String {
fn default_toml_text(package_name: Option<&str>) -> Result<String, ConfigError> {
let name = package_name
.map(|s| s.to_string())
.or_else(|| {
@@ -845,9 +845,11 @@ fn default_toml_text(package_name: Option<&str>) -> String {
.and_then(|p| p.file_name().map(|v| v.to_string_lossy().to_string()))
})
.unwrap_or_else(|| "project".to_string());
validate_non_empty_string(&name, "package.name")?;
validate_package_name(&name)?;
let dcr_version = env!("CARGO_PKG_VERSION");
format!(
Ok(format!(
"[package]\n\
name = \"{name}\"\n\
version = \"{DEFAULT_VERSION}\"\n\
@@ -864,7 +866,7 @@ fn default_toml_text(package_name: Option<&str>) -> String {
kind = \"{DEFAULT_KIND}\"\n\
\n\
[dependencies]\n"
)
))
}
fn dcr_version_warn_once(path_key: &str) -> bool {
@@ -1295,6 +1297,22 @@ mod tests {
);
}
#[test]
fn create_rejects_invalid_name_without_writing_manifest() {
let dir = temp_dir("invalid_create_name");
let path = dir.join("dcr.toml");
for name in ["", "bad name", "../bad", "bad\"name", " bad", "bad."] {
let result = Config::create(&path.to_string_lossy(), Some(name));
assert!(matches!(result, Err(ConfigError::Invalid(_))), "{name:?}");
assert!(!path.exists(), "invalid name must not create a manifest");
}
let config = Config::create(&path.to_string_lossy(), Some("valid-name")).unwrap();
assert_eq!(
config.get("package.name").and_then(Value::as_str),
Some("valid-name")
);
}
#[test]
fn new_creates_default_config() {
let dir = temp_dir("new_default");