From 2b17ebe70766ad57dc6c29d04b1c401cfe129a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Fri, 24 Jul 2026 01:23:38 -0700 Subject: [PATCH] chore(cargo): disable debug info in generated profiles ### Summary Default development and CI Cargo profiles to `debug = false` in Flakebox itself, the default project template, and the Cargo profile lint fixer. Retain explicit dependency package overrides so projects can later enable workspace-only line tables without paying for dependency debug information. ### Details Generate `[profile.dev.package."*"]` and `[profile.ci.package."*"]` overrides with comments explaining the workspace `line-tables-only` option. Normalize valid inline TOML tables before updating them so the fixer preserves existing settings, and add focused coverage for generated values, serialization, comments, and inline-table preservation. Update the best-practices example; release-profile behavior remains unchanged. ### Verification `cargo test -p flakebox`, Cargo metadata validation, treefmt, and `selfci check` pass. ### Reviews Focused correctness and maintainability review found malformed inline serialization/comment placement, then uncovered preservation bugs for nested and root inline tables. The implementation now emits explicit override sections, places comments before `debug`, normalizes every table level, and preserves existing inline settings. Final re-review passed with no issues. ### Summary of the original prompt Apply the Cargo debug-profile defaults documented by dpc-public-skills change `myutwysq`, keeping the scope to Flakebox generated/default Cargo configuration and directly related tests/docs. --- Cargo.toml | 13 +++- docs/best-practices.md | 20 +++++- flakebox-bin/src/main.rs | 119 ++++++++++++++++++++++++++++++++++- templates/default/Cargo.toml | 13 +++- 4 files changed, 159 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 855e40c..fa85296 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,13 +19,24 @@ literal_string_with_formatting_args = "deny" dbg_macro = "deny" [profile.dev] +debug = false + +[profile.dev.package."*"] +# Keep dependencies without debug information if the workspace profile is +# changed to "line-tables-only" for more useful workspace panic traces. +debug = false [profile.ci] -debug = "line-tables-only" +debug = false inherits = "dev" incremental = false lto = "off" +[profile.ci.package."*"] +# Keep dependencies without debug information if the workspace profile is +# changed to "line-tables-only" for more useful workspace panic traces. +debug = false + [profile.release] debug = "line-tables-only" diff --git a/docs/best-practices.md b/docs/best-practices.md index 66599cf..ff6ea71 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -38,12 +38,30 @@ and use them in the Nix-based CI to improve the CI times. Example: ```toml +[profile.dev] +debug = false + +[profile.dev.package."*"] +# Keep dependencies without debug information if the workspace profile is +# changed to "line-tables-only" for more useful workspace panic traces. +debug = false + [profile.ci] +debug = false inherits = "dev" -debug = 1 incremental = false + +[profile.ci.package."*"] +# Keep dependencies without debug information if the workspace profile is +# changed to "line-tables-only" for more useful workspace panic traces. +debug = false ``` +The package overrides intentionally repeat the profile defaults. If more useful +workspace panic traces become worth the artifact size, this lets the workspace +profile switch to `debug = "line-tables-only"` without enabling dependency +debug information. + This can be combined with building the most performance-relevant dependencies with optimizations, either manually: diff --git a/flakebox-bin/src/main.rs b/flakebox-bin/src/main.rs index 6401086..05c0fdd 100644 --- a/flakebox-bin/src/main.rs +++ b/flakebox-bin/src/main.rs @@ -107,19 +107,80 @@ fn lint_cargo_toml_fix_resolver_v2(opts: &Opts) -> AppResult<()> { fn lint_cargo_toml_fix_ci_build_profile(opts: &Opts) -> AppResult<()> { let (path, mut cargo_toml) = load_root_cargo_toml(opts)?; + set_cargo_profile_defaults(&mut cargo_toml); + + fs::write(path, cargo_toml.to_string()).change_context(AppError::IO)?; + + Ok(()) +} + +fn set_cargo_profile_defaults(cargo_toml: &mut toml_edit::DocumentMut) { if cargo_toml.get("profile").is_none() { cargo_toml["profile"] = toml_edit::Item::Table(toml_edit::Table::new()); } + let profiles = item_as_table_mut(&mut cargo_toml["profile"], "Cargo profiles must be a table"); + if !profiles.contains_key("dev") { + profiles["dev"] = toml_edit::Item::Table(toml_edit::Table::new()); + } + profiles["dev"]["debug"] = value(false); + set_dependency_debug_override(cargo_toml, "dev"); + cargo_toml["profile"]["ci"] = toml_edit::Item::Table(toml_edit::Table::new()); + cargo_toml["profile"]["ci"]["debug"] = value(false); cargo_toml["profile"]["ci"]["inherits"] = value("dev"); cargo_toml["profile"]["ci"]["incremental"] = value(false); - cargo_toml["profile"]["ci"]["debug"] = value("line-tables-only"); cargo_toml["profile"]["ci"]["lto"] = value("off"); + set_dependency_debug_override(cargo_toml, "ci"); +} - fs::write(path, cargo_toml.to_string()).change_context(AppError::IO)?; +fn set_dependency_debug_override(cargo_toml: &mut toml_edit::DocumentMut, profile: &str) { + let profile = item_as_table_mut( + &mut cargo_toml["profile"][profile], + "Cargo profile must be a table", + ); + if !profile.contains_key("package") { + profile["package"] = toml_edit::Item::Table(toml_edit::Table::new()); + } - Ok(()) + let package = item_as_table_mut( + &mut profile["package"], + "Cargo profile package overrides must be a table", + ); + if !package.contains_key("*") { + package["*"] = toml_edit::Item::Table(toml_edit::Table::new()); + } + + let dependency_override = item_as_table_mut( + &mut package["*"], + "Cargo dependency profile override must be a table", + ); + dependency_override["debug"] = value(false); + dependency_override + .key_mut("debug") + .expect("debug was just inserted") + .leaf_decor_mut() + .set_prefix( + "# Keep dependencies without debug information if the workspace profile is\n\ + # changed to \"line-tables-only\" for more useful workspace panic traces.\n", + ); +} + +fn item_as_table_mut<'item>( + item: &'item mut toml_edit::Item, + invalid_message: &str, +) -> &'item mut toml_edit::Table { + if !item.is_table() { + let owned = std::mem::take(item); + *item = toml_edit::Item::Table( + owned + .into_table() + .unwrap_or_else(|_| panic!("{invalid_message}")), + ); + } + + item.as_table_mut() + .expect("item was already a table or was converted to one") } fn lint_cargo_toml(opts: &Opts, problems: &mut Vec) -> AppResult<()> { @@ -309,3 +370,55 @@ fn init_logging() { tracing::subscriber::set_global_default(subscriber).expect("Failed to set tracing subscriber"); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn cargo_profile_defaults_disable_debug_info_and_preserve_inline_dev_settings() { + let mut cargo_toml = "profile = { dev = { package = { \"*\" = { opt-level = 1 } } } }\n" + .parse::() + .expect("valid test manifest"); + + set_cargo_profile_defaults(&mut cargo_toml); + + assert_eq!(cargo_toml["profile"]["dev"]["debug"].as_bool(), Some(false)); + assert_eq!( + cargo_toml["profile"]["dev"]["package"]["*"]["debug"].as_bool(), + Some(false) + ); + assert_eq!( + cargo_toml["profile"]["dev"]["package"]["*"]["opt-level"].as_integer(), + Some(1) + ); + assert_eq!(cargo_toml["profile"]["ci"]["debug"].as_bool(), Some(false)); + assert_eq!( + cargo_toml["profile"]["ci"]["package"]["*"]["debug"].as_bool(), + Some(false) + ); + + let cargo_toml = cargo_toml.to_string(); + assert!(cargo_toml.contains( + "[profile.dev.package.\"*\"]\n\ + opt-level = 1\n\ + # Keep dependencies without debug information if the workspace profile is\n\ + # changed to \"line-tables-only\" for more useful workspace panic traces.\n\ + debug = false" + )); + assert!(cargo_toml.contains( + "[profile.ci.package.\"*\"]\n\ + # Keep dependencies without debug information if the workspace profile is\n\ + # changed to \"line-tables-only\" for more useful workspace panic traces.\n\ + debug = false" + )); + assert_eq!( + cargo_toml + .matches( + "# changed to \"line-tables-only\" for more useful workspace panic traces." + ) + .count(), + 2 + ); + } +} diff --git a/templates/default/Cargo.toml b/templates/default/Cargo.toml index d52d08d..df326b6 100644 --- a/templates/default/Cargo.toml +++ b/templates/default/Cargo.toml @@ -9,13 +9,24 @@ license = "MIT" [dependencies] [profile.dev] -debug = "line-tables-only" +debug = false lto = "off" +[profile.dev.package."*"] +# Keep dependencies without debug information if the workspace profile is +# changed to "line-tables-only" for more useful workspace panic traces. +debug = false + [profile.ci] +debug = false inherits = "dev" incremental = false +[profile.ci.package."*"] +# Keep dependencies without debug information if the workspace profile is +# changed to "line-tables-only" for more useful workspace panic traces. +debug = false + [profile.release] debug = "line-tables-only" lto = "fat"