diff --git a/hacking/cargo-manifest-management/.gitignore b/hacking/cargo-manifest-management/.gitignore index 3846a5860..92abaa828 100644 --- a/hacking/cargo-manifest-management/.gitignore +++ b/hacking/cargo-manifest-management/.gitignore @@ -5,3 +5,4 @@ # /target/ +blueprint.json diff --git a/hacking/cargo-manifest-management/Cargo.lock b/hacking/cargo-manifest-management/Cargo.lock index 504612d37..f1905d022 100644 --- a/hacking/cargo-manifest-management/Cargo.lock +++ b/hacking/cargo-manifest-management/Cargo.lock @@ -388,6 +388,7 @@ dependencies = [ "serde_json", "similar", "toml", + "toml-normalize", ] [[package]] diff --git a/hacking/cargo-manifest-management/Makefile b/hacking/cargo-manifest-management/Makefile index ac8cd5cde..eeda5c320 100644 --- a/hacking/cargo-manifest-management/Makefile +++ b/hacking/cargo-manifest-management/Makefile @@ -4,29 +4,25 @@ # SPDX-License-Identifier: BSD-2-Clause # -blueprint := $$(nix-build -A blueprintJSON --no-out-link) +blueprint := blueprint.json -target_dir := target - -bin_dir := $(target_dir)/debug - -run := PATH=$(bin_dir):$$PATH $(bin_dir)/manage-cargo-manifests --blueprint $(blueprint) +run := cargo run -p manage-cargo-manifests -- .PHONY: none none: .PHONY: clean clean: - rm -rf $(target_dir) + rm -rf $(target_dir) $(blueprint) -.INTERMEDIATE: bins -bins: - cargo build +.PHONY: $(blueprint) +$(blueprint): + nix-build -A blueprintJSON --out-link $@ .PHONY: update -update: bins - $(run) +update: $(blueprint) + $(run) --blueprint $< .PHONY: check -check: bins - $(run) --just-check +check: $(blueprint) + $(run) --blueprint $< --just-check diff --git a/hacking/cargo-manifest-management/crates/manage-cargo-manifests/Cargo.toml b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/Cargo.toml index 64dcbd261..553986fd3 100644 --- a/hacking/cargo-manifest-management/crates/manage-cargo-manifests/Cargo.toml +++ b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/Cargo.toml @@ -15,5 +15,6 @@ license = "BSD-2-Clause" clap = { version = "4.4.6", features = [ "derive" ] } serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" -toml = "0.8.6" similar = "2.3" +toml = "0.8.6" +toml-normalize = { path = "../toml-normalize" } diff --git a/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/main.rs b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/main.rs index 484a8a9da..9278ad8fd 100644 --- a/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/main.rs +++ b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/main.rs @@ -5,17 +5,17 @@ // use std::fs::{self, File}; -use std::io::Write; use std::path::PathBuf; -use std::process::{self, Command, Stdio}; +use std::process; use std::str; use clap::Parser; use serde::Deserialize; -use serde_json::Value as JsonValue; use similar::{ChangeTag, TextDiff}; use toml::Table as TomlTable; +use toml_normalize::{builtin_policies, Error as TomlNormalizeError, Formatter, Policy}; + #[derive(Debug, Parser)] struct Args { #[arg(long)] @@ -47,7 +47,7 @@ pub struct Entry { #[serde(rename = "frontmatter")] pub frontmatter: Option, #[serde(rename = "formatPolicyOverrides")] - pub format_policy_overrides: Vec, + pub format_policy_overrides: Vec, #[serde(rename = "justEnsureEquivalence")] pub just_ensure_equivalence: bool, } @@ -63,12 +63,26 @@ impl Blueprint { impl Entry { fn execute(&self, just_check: bool) { let manifest_path = self.absolute_path.join("Cargo.toml"); - let rendered = self.render(&format!("{}", self.manifest_value)); + let rendered = self.render(&self.manifest_value).unwrap_or_else(|err| { + eprintln!( + "error normalizing structured value for {}: {}", + manifest_path.display(), + err + ); + die(); + }); let mut write = true; if manifest_path.is_file() { let existing = fs::read_to_string(&manifest_path).unwrap(); if self.just_ensure_equivalence { - let existing_rendered = self.render(&existing); + let existing_toml = toml::from_str(&existing).unwrap_or_else(|err| { + eprintln!("error parsing {} as TOML: {}", manifest_path.display(), err); + die(); + }); + let existing_rendered = self.render(&existing_toml).unwrap_or_else(|err| { + eprintln!("error normalizing {}: {}", manifest_path.display(), err); + die(); + }); if existing_rendered != rendered { eprintln!( "error: {} is out of date (note that this is a structural comparison):", @@ -77,49 +91,38 @@ impl Entry { eprintln!("{}", format_diff(&rendered, &existing_rendered)); die(); } - } else { - if existing == rendered { - write = false; - } else if just_check { - eprintln!("error: {} is out of date:", manifest_path.display()); - eprintln!("{}", format_diff(&rendered, &existing)); - die(); - } + } else if existing == rendered { + write = false; + } else if just_check { + eprintln!("error: {} is out of date:", manifest_path.display()); + eprintln!("{}", format_diff(&rendered, &existing)); + die(); } } else if just_check || self.just_ensure_equivalence { eprintln!("error: {} does not exist", manifest_path.display()); die(); } if write { + assert!(!just_check); eprintln!("writing {}", manifest_path.display()); fs::write(manifest_path, rendered).unwrap(); } } - fn render(&self, unformatted_toml: &str) -> String { - let mut cmd = Command::new("toml-normalize"); - cmd.stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .arg("--builtin-policy=cargo-manifest"); + fn render(&self, unformatted_toml: &TomlTable) -> Result { + let mut composite_policy = builtin_policies::cargo_manifest_policy(); for policy in self.format_policy_overrides.iter() { - cmd.arg(format!("--inline-policy={}", policy)); + composite_policy = composite_policy.override_with(policy); } - let mut child = cmd.spawn().unwrap(); - child - .stdin - .take() - .unwrap() - .write_all(unformatted_toml.as_bytes()) - .unwrap(); - let output = child.wait_with_output().unwrap(); - assert!(output.status.success()); + let formatter = Formatter::new(composite_policy); + let doc = formatter.format(unformatted_toml)?; let mut s = String::new(); if let Some(frontmatter) = self.frontmatter.as_ref() { s.push_str(frontmatter); s.push('\n'); } - s.push_str(str::from_utf8(&output.stdout).unwrap()); - s + s.push_str(&doc.to_string()); + Ok(s) } } diff --git a/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs index dffc773ea..6a05a925c 100644 --- a/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs @@ -9,5 +9,5 @@ mod policy; pub mod builtin_policies; -pub use format::{AbstractPolicy, Formatter}; +pub use format::{AbstractPolicy, Error, Formatter}; pub use policy::{KeyOrdering, Policy, TableRule}; diff --git a/hacking/cargo-manifest-management/default.nix b/hacking/cargo-manifest-management/default.nix index 19f41fde2..01d61659e 100644 --- a/hacking/cargo-manifest-management/default.nix +++ b/hacking/cargo-manifest-management/default.nix @@ -27,11 +27,7 @@ rec { inherit (workspace) blueprint debug; - prettyJSON = name: value: with pkgs; runCommand name { - nativeBuildInputs = [ jq ]; - } '' - jq < ${builtins.toFile name (builtins.toJSON value)} > $out - ''; + prettyJSON = (pkgs.formats.json {}).generate; blueprintJSON = prettyJSON "blueprint.json" blueprint; }