diff --git a/docs/reference/dependencies.mdx b/docs/reference/dependencies.mdx index 72ded57..cdc04f0 100644 --- a/docs/reference/dependencies.mdx +++ b/docs/reference/dependencies.mdx @@ -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 diff --git a/examples/dcr-math b/examples/dcr-math deleted file mode 160000 index 737d962..0000000 --- a/examples/dcr-math +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 737d9629c5d56d4e6d11405858dc7e63cd80745d diff --git a/man/man1/dcr.1 b/man/man1/dcr.1 index 5514ef5..4cd34c8 100644 --- a/man/man1/dcr.1 +++ b/man/man1/dcr.1 @@ -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 diff --git a/src/core/build_config.rs b/src/core/build_config.rs index f8e3e5e..e8ccd6b 100644 --- a/src/core/build_config.rs +++ b/src/core/build_config.rs @@ -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 { 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");