From efd7e7afd373a3fb28cb959a7df7780b822584f7 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Tue, 31 Oct 2023 12:31:29 +0000 Subject: [PATCH 1/9] cmm: Improve implementation of format.rs Signed-off-by: Nick Spinale --- hacking/cargo-manifest-management/Cargo.lock | 38 +- hacking/cargo-manifest-management/Cargo.toml | 4 +- .../src/cargo_manifest_policy.rs | 25 +- hacking/cargo-manifest-management/src/diff.rs | 2 +- .../cargo-manifest-management/src/format.rs | 409 +++++++++--------- hacking/cargo-manifest-management/src/main.rs | 8 +- hacking/cargo-manifest-management/src/plan.rs | 14 +- 7 files changed, 252 insertions(+), 248 deletions(-) diff --git a/hacking/cargo-manifest-management/Cargo.lock b/hacking/cargo-manifest-management/Cargo.lock index 993844c84..544074c3f 100644 --- a/hacking/cargo-manifest-management/Cargo.lock +++ b/hacking/cargo-manifest-management/Cargo.lock @@ -55,10 +55,10 @@ name = "cargo-manifest-management" version = "0.1.0" dependencies = [ "clap", - "either", "serde", "serde_json", "similar", + "toml", "toml_edit", ] @@ -108,12 +108,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - [[package]] name = "equivalent" version = "1.0.1" @@ -209,6 +203,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + [[package]] name = "similar" version = "2.3.0" @@ -232,19 +235,36 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" -version = "0.20.4" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380f9e8120405471f7c9ad1860a713ef5ece6a670c7eae39225e477340f32fc4" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] diff --git a/hacking/cargo-manifest-management/Cargo.toml b/hacking/cargo-manifest-management/Cargo.toml index 0977582e4..51138820e 100644 --- a/hacking/cargo-manifest-management/Cargo.toml +++ b/hacking/cargo-manifest-management/Cargo.toml @@ -14,11 +14,11 @@ license = "BSD-2-Clause" [dependencies] clap = { version = "4.4.6", features = [ "derive" ] } -either = "1.9" serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" -similar = "2.3" +toml = "0.8.6" toml_edit = "0.20.4" +similar = "2.3" # exclude from top-level workspace [workspace] diff --git a/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs b/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs index 42e107453..1e806a00e 100644 --- a/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs +++ b/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs @@ -11,6 +11,21 @@ use crate::{PathSegment, Policy}; pub struct CargoManifestPolicy; impl Policy for CargoManifestPolicy { + fn max_width(&self) -> usize { + 100 + } + + fn indent_width(&self) -> usize { + 4 + } + + fn never_inline_table(&self, path: &[PathSegment]) -> bool { + path.len() <= 1 + || (path.len() <= 3 && path[0].is_table_key("target")) + || (path.len() <= 3 && path[0].is_table_key("profile")) + || (path.len() == 3 && path[1].is_table_key("bin")) + } + fn compare_keys(&self, path: &[PathSegment], a: &str, b: &str) -> Ordering { let ranking = if path.len() == 0 { Ranking { @@ -71,16 +86,6 @@ impl Policy for CargoManifestPolicy { }; ranking.compare(a, b) } - - fn is_always_table(&self, path: &[PathSegment]) -> bool { - path.len() <= 1 - || (path.len() <= 3 && path[0].is_table_key("target")) - || (path.len() <= 3 && path[0].is_table_key("profile")) - } - - fn is_always_array_of_tables(&self, path: &[PathSegment]) -> bool { - path.len() == 2 && path[1].is_table_key("bin") - } } struct Ranking<'a> { diff --git a/hacking/cargo-manifest-management/src/diff.rs b/hacking/cargo-manifest-management/src/diff.rs index a6abc76d4..86cf79b9c 100644 --- a/hacking/cargo-manifest-management/src/diff.rs +++ b/hacking/cargo-manifest-management/src/diff.rs @@ -6,7 +6,7 @@ use similar::{ChangeTag, TextDiff}; -pub fn diff(a: &str, b: &str) -> String { +pub fn display_diff(a: &str, b: &str) -> String { let mut s = String::new(); let d = TextDiff::from_lines(a, b); for change in d.iter_all_changes() { diff --git a/hacking/cargo-manifest-management/src/format.rs b/hacking/cargo-manifest-management/src/format.rs index 3a2f75a5b..530c8d4e4 100644 --- a/hacking/cargo-manifest-management/src/format.rs +++ b/hacking/cargo-manifest-management/src/format.rs @@ -5,23 +5,24 @@ // use std::cmp::Ordering; -use std::collections::BTreeMap; use std::mem; -use either::Either; -use serde_json::Value as JsonValue; -use toml_edit::{Array, ArrayOfTables, Document, Formatted, InlineTable, Item, Table, Value}; - -const MAX_WIDTH: usize = 100; +use toml::value::{ + Array as UnformattedArray, Table as UnformattedTable, Value as UnformattedValue, +}; +use toml_edit::{Array, ArrayOfTables, Document, Formatted, InlineTable, Item, Key, Table, Value}; pub trait Policy { - fn compare_keys(&self, path: &[PathSegment], a: &str, b: &str) -> Ordering; + fn max_width(&self) -> usize; + + fn indent_width(&self) -> usize; - fn is_always_table(&self, path: &[PathSegment]) -> bool; + fn never_inline_table(&self, path: &[PathSegment]) -> bool; - fn is_always_array_of_tables(&self, path: &[PathSegment]) -> bool; + fn compare_keys(&self, path: &[PathSegment], a: &str, b: &str) -> Ordering; } +#[derive(Debug, Clone)] pub enum PathSegment { TableKey(String), ArrayIndex(usize), @@ -49,15 +50,12 @@ impl Formatter

{ Self { policy } } - pub fn format(&self, manifest: &JsonValue) -> Document { + pub fn format(&self, table: &UnformattedTable) -> Result { let mut state = FormatterState { formatter: self, current_path: vec![], }; - let item = state.translate(manifest).into_item(); - let mut doc = Document::new(); - let _ = mem::replace(doc.as_item_mut(), item); - doc + state.format_top_level(table) } } @@ -66,109 +64,168 @@ struct FormatterState<'a, P> { current_path: Vec, } +#[derive(Debug, Clone)] +pub enum Error { + CannotInlineTable(CannotInlineTableError), +} + +#[derive(Debug, Clone)] +pub struct CannotInlineTableError { + path: Vec, +} + +impl CannotInlineTableError { + fn new(path: Vec) -> Self { + Self { path } + } +} + +impl From for Error { + fn from(err: CannotInlineTableError) -> Error { + Self::CannotInlineTable(err) + } +} + +struct FormattedTable { + table: Table, + inline_table: Result, +} + impl<'a, P: Policy> FormatterState<'a, P> { - fn translate(&mut self, v: &JsonValue) -> Translated { - match v { - JsonValue::Bool(w) => Value::Boolean(Formatted::new(*w)).into(), - JsonValue::Number(w) => if let Some(x) = w.as_i64() { - Value::Integer(Formatted::new(x)) - } else if let Some(x) = w.as_f64() { - Value::Float(Formatted::new(x)) - } else { - panic!() - } - .into(), - JsonValue::String(w) => Value::String(Formatted::new(w.clone())).into(), - JsonValue::Array(w) => { - let mut children = vec![]; - for (i, x) in w.iter().enumerate() { - self.push(PathSegment::ArrayIndex(i)); - children.push(self.translate(x)); - self.pop(); - } - let homogenous_children = - if self.policy().is_always_array_of_tables(self.current_path()) { - TranslatedArray::Tables(TranslatedArray::tables_from_translated(&children)) - } else { - TranslatedArray::homogenize(&children) - }; - match homogenous_children { - TranslatedArray::Values(values) => Translated::Value(Value::Array({ - let mut array = Array::new(); - for v in values.into_iter() { - array.push(v); - } - let wrap = self - .current_key() - .map(|k| is_kv_too_long(k, &Value::Array(array.clone()))) - .unwrap_or(false); - if wrap { - array.iter_mut().for_each(|e| { - e.decor_mut().set_prefix("\n "); - }); - array.iter_mut().last().map(|e| { - e.decor_mut().set_suffix("\n"); - }); - } - array - })), - TranslatedArray::Tables(tables) => Translated::Item(Item::ArrayOfTables({ - let mut array = ArrayOfTables::new(); - for v in tables.into_iter() { - array.push(v); - } - array - })), + fn format_top_level(&mut self, v: &UnformattedTable) -> Result { + let table = self.format_table_to_table(v)?; + let mut doc = Document::new(); + *doc.as_table_mut() = table; + Ok(doc) + } + + fn format_to_value(&mut self, v: &UnformattedValue) -> Result { + Ok(match v { + UnformattedValue::Boolean(w) => Value::Boolean(Formatted::new(*w)), + UnformattedValue::Integer(w) => Value::Integer(Formatted::new(*w)), + UnformattedValue::Float(w) => Value::Float(Formatted::new(*w)), + UnformattedValue::String(w) => Value::String(Formatted::new(w.clone())), + UnformattedValue::Datetime(w) => Value::Datetime(Formatted::new(w.clone())), + UnformattedValue::Array(w) => Value::Array(self.format_array_to_array(w)?), + UnformattedValue::Table(w) => Value::InlineTable(self.format_table_to_inline_table(w)?), + }) + } + + fn format_table_to_inline_table(&mut self, v: &UnformattedTable) -> Result { + if self.policy().never_inline_table(self.current_path()) { + return Err(CannotInlineTableError::new(self.current_path().to_vec()).into()); + } + let mut table = InlineTable::new(); + for (k, x) in v.iter() { + table.insert(k, self.with_table_key(k, |this| this.format_to_value(x))?); + } + table.sort_values_by(self.compare_values_at_current_path()); + Ok(table) + } + + fn format_array_to_array(&mut self, v: &UnformattedArray) -> Result { + let mut array = Array::new(); + for (i, x) in v.iter().enumerate() { + array.push(self.with_array_index(i, |this| this.format_to_value(x))?); + } + Ok(array) + } + + fn format_table_to_table(&mut self, v: &UnformattedTable) -> Result { + let mut table = Table::new(); + table.set_implicit(true); + for (k, x) in v.iter() { + table.insert(k, self.with_table_key(k, |this| this.format_to_item(x))?); + } + table.sort_values_by(self.compare_values_at_current_path()); + Ok(table) + } + + fn format_to_item(&mut self, v: &UnformattedValue) -> Result { + Ok(match v { + UnformattedValue::Array(w) => self.format_array_to_item(w)?, + UnformattedValue::Table(w) => self.format_table_to_item(w)?, + _ => Item::Value(self.format_to_value(v)?), + }) + } + + fn format_array_to_item(&mut self, v: &UnformattedArray) -> Result { + let just_tables = v.iter().all(UnformattedValue::is_table); + let mut array = if !just_tables { + Some(self.format_array_to_array(v)?) + } else { + let mut inline_tables = Some(vec![]); + for (i, x) in v + .iter() + .map(UnformattedValue::as_table) + .map(Option::unwrap) + .enumerate() + { + let inline_table = + self.with_array_index(i, |this| this.format_table_to_inline_table(x))?; + if self.is_inline_table_too_wide_for_array(&inline_table) { + inline_tables = None; + break; + } else { + inline_tables.as_mut().unwrap().push(inline_table); } } - JsonValue::Object(w) => { - let mut children = BTreeMap::new(); - for (k, x) in w.iter() { - self.push(PathSegment::TableKey(k.clone())); - children.insert(k.clone(), self.translate(x)); - self.pop(); - } - let homogenous_children = if self.policy().is_always_table(self.current_path()) { - TranslatedMap::Items(TranslatedMap::items_from_translated(&children)) + inline_tables.map(|inline_tables| { + let mut array = Array::new(); + array.extend(inline_tables); + array + }) + }; + if let Some(array) = &mut array { + let wrap = + self.is_kv_too_wide(self.current_key().unwrap(), &Value::Array(array.clone())); + if wrap { + array.iter_mut().for_each(|e| { + e.decor_mut().set_prefix("\n "); + }); + array.iter_mut().last().map(|e| { + e.decor_mut().set_suffix("\n"); + }); + } + } + Ok(if let Some(array) = array { + Item::Value(Value::Array(array)) + } else { + let mut array_of_tables = ArrayOfTables::new(); + for (i, x) in v + .iter() + .map(UnformattedValue::as_table) + .map(Option::unwrap) + .enumerate() + { + let table = self.with_array_index(i, |this| this.format_table_to_table(x))?; + array_of_tables.push(table); + } + Item::ArrayOfTables(array_of_tables) + }) + } + + fn format_table_to_item(&mut self, v: &UnformattedTable) -> Result { + let inline_table = match self.format_table_to_inline_table(v) { + Ok(inline_table) => { + let too_wide = self.is_kv_too_wide( + self.current_key().unwrap(), + &Value::InlineTable(inline_table.clone()), + ); + if !too_wide { + Some(inline_table) } else { - TranslatedMap::homogenize(&children) - }; - match homogenous_children { - TranslatedMap::Values(values) => { - let mut table = InlineTable::new(); - for (k, v) in values.clone().into_iter() { - table.insert(k, v); - } - table.sort_values_by(|k1, _v1, k2, _v2| { - self.policy().compare_keys(self.current_path(), k1, k2) - }); - if !self - .current_key() - .map(|k| is_kv_too_long(k, &Value::InlineTable(table.clone()))) - .unwrap_or(false) - { - Either::Left(Translated::Value(Value::InlineTable(table))) - } else { - Either::Right(TranslatedMap::items_from_values(values)) - } - } - TranslatedMap::Items(items) => Either::Right(items), + None } - .map_right(|items| { - let mut table = Table::new(); - table.set_implicit(true); - for (k, v) in items.into_iter() { - table.insert(&k, v); - } - table.sort_values_by(|k1, _v1, k2, _v2| { - self.policy().compare_keys(self.current_path(), k1, k2) - }); - Translated::Item(Item::Table(table)) - }) - .into_inner() } - _ => panic!(), - } + Err(Error::CannotInlineTable(_)) => None, + }; + Ok(if let Some(inline_table) = inline_table { + Item::Value(Value::InlineTable(inline_table)) + } else { + let table = self.format_table_to_table(v)?; + Item::Table(table) + }) } fn policy(&self) -> &P { @@ -189,120 +246,42 @@ impl<'a, P: Policy> FormatterState<'a, P> { fn pop(&mut self) { self.current_path.pop(); } -} - -#[derive(Clone)] -enum Translated { - Item(Item), - Value(Value), -} -impl From for Translated { - fn from(item: Item) -> Self { - Self::Item(item) + fn with_path_segment(&mut self, seg: PathSegment, f: impl FnOnce(&mut Self) -> R) -> R { + self.push(seg); + let r = f(self); + self.pop(); + r } -} -impl From for Translated { - fn from(value: Value) -> Self { - Self::Value(value) - } -} - -impl Translated { - fn as_value(&self) -> Option<&Value> { - match self { - Self::Value(v) => Some(v), - _ => None, - } + fn with_table_key(&mut self, k: &str, f: impl FnOnce(&mut Self) -> R) -> R { + self.with_path_segment(PathSegment::TableKey(k.to_owned()), f) } - fn is_value(&self) -> bool { - self.as_value().is_some() + fn with_array_index(&mut self, i: usize, f: impl FnOnce(&mut Self) -> R) -> R { + self.with_path_segment(PathSegment::ArrayIndex(i), f) } - fn into_item(self) -> Item { - match self { - Self::Value(value) => Item::Value(value), - Self::Item(item) => item, - } + fn compare_values_at_current_path( + &mut self, + ) -> impl '_ + FnMut(&Key, &T, &Key, &T) -> Ordering { + |k1, _v1, k2, _v2| self.policy().compare_keys(self.current_path(), k1, k2) } -} -enum TranslatedMap { - Items(BTreeMap), - Values(BTreeMap), -} - -impl TranslatedMap { - fn homogenize(heterogeneous: &BTreeMap) -> Self { - if heterogeneous.values().all(Translated::is_value) { - Self::Values( - heterogeneous - .iter() - .map(|(k, v)| (k.clone(), v.as_value().unwrap().clone())) - .collect(), - ) - } else { - Self::Items(Self::items_from_translated(heterogeneous)) - } - } - - fn items_from_translated(translated: &BTreeMap) -> BTreeMap { - translated - .iter() - .map(|(k, v)| (k.clone(), v.clone().into_item())) - .collect() - } - - fn items_from_values(values: BTreeMap) -> BTreeMap { - values - .into_iter() - .map(|(k, v)| (k, Item::Value(v))) - .collect() - } -} - -enum TranslatedArray { - Tables(Vec), - Values(Vec), -} - -impl TranslatedArray { - fn homogenize(heterogeneous: &[Translated]) -> Self { - if heterogeneous.iter().all(Translated::is_value) { - Self::Values( - heterogeneous - .iter() - .map(|v| v.as_value().unwrap().clone()) - .collect(), - ) - } else { - Self::Tables(Self::tables_from_translated(heterogeneous)) - } - } - - fn tables_from_translated(translated: &[Translated]) -> Vec
{ - translated - .iter() - .map(|v| v.clone().into_item().as_table().unwrap().clone()) - .collect() + fn is_kv_too_wide(&self, k: &str, v: &Value) -> bool { + let mut table = Table::new(); + table.insert(k, Item::Value(v.clone())); + let mut doc = Document::new(); + let _ = mem::replace(doc.as_item_mut(), Item::Table(table)); + let mut s = doc.to_string(); + assert_eq!(s.pop(), Some('\n')); + s.chars().count() > self.policy().max_width() } - fn tables_from_values(values: &[Value]) -> Vec
{ - values - .into_iter() - .map(|v| v.as_inline_table().unwrap().clone().into_table()) - .collect() + fn is_inline_table_too_wide_for_array(&self, v: &InlineTable) -> bool { + let value = format!("{}", v).len(); + let comma = 1; + let total = self.policy().indent_width() + value + comma; + total > self.policy().max_width() } } - -fn is_kv_too_long(k: &str, v: &Value) -> bool { - let mut table = Table::new(); - table.insert(k, Item::Value(v.clone())); - let mut doc = Document::new(); - let _ = mem::replace(doc.as_item_mut(), Item::Table(table)); - let mut s = doc.to_string(); - assert_eq!(s.pop(), Some('\n')); - s.chars().count() > MAX_WIDTH -} diff --git a/hacking/cargo-manifest-management/src/main.rs b/hacking/cargo-manifest-management/src/main.rs index da5a69ac7..6108fd6b7 100644 --- a/hacking/cargo-manifest-management/src/main.rs +++ b/hacking/cargo-manifest-management/src/main.rs @@ -18,7 +18,7 @@ mod format; mod plan; use cargo_manifest_policy::CargoManifestPolicy; -use diff::diff; +use diff::display_diff; use format::{Formatter, PathSegment, Policy}; use plan::Plan; @@ -41,7 +41,9 @@ fn main() { // for debugging: fn test_format() { - let json_value = serde_json::from_reader(io::stdin()).unwrap(); - let toml_doc = Formatter::new(CargoManifestPolicy).format(&json_value); + let root_table = serde_json::from_reader(io::stdin()).unwrap(); + let toml_doc = Formatter::new(CargoManifestPolicy) + .format(&root_table) + .unwrap(); print!("{}", toml_doc) } diff --git a/hacking/cargo-manifest-management/src/plan.rs b/hacking/cargo-manifest-management/src/plan.rs index 892680bf5..863c000dc 100644 --- a/hacking/cargo-manifest-management/src/plan.rs +++ b/hacking/cargo-manifest-management/src/plan.rs @@ -11,9 +11,9 @@ use std::process; use std::str; use serde::Deserialize; -use serde_json::Value as JsonValue; +use toml::Table as UnformattedTable; -use crate::{diff, Formatter, Policy}; +use crate::{display_diff, Formatter, Policy}; #[derive(Debug, Deserialize)] #[serde(transparent)] @@ -23,7 +23,7 @@ pub struct Plan { #[derive(Debug, Deserialize)] pub struct Entry { - pub manifest: JsonValue, + pub manifest: UnformattedTable, pub frontmatter: Option, pub just_ensure_equivalence: bool, } @@ -41,7 +41,7 @@ impl Plan { write = false; } else if just_check { eprintln!("error: {} is out of date:", path.display()); - eprintln!("{}", diff(&rendered, existing)); + eprintln!("{}", display_diff(&rendered, existing)); process::exit(1); } } else if just_check { @@ -67,10 +67,8 @@ impl Entry { pub fn get_package_name(&self) -> Option<&str> { Some( self.manifest - .as_object() - .unwrap() .get("package")? - .as_object() + .as_table() .unwrap() .get("name") .unwrap() @@ -80,7 +78,7 @@ impl Entry { } fn render(&self, formatter: &Formatter

) -> String { - let doc = formatter.format(&self.manifest); + let doc = formatter.format(&self.manifest).unwrap(); let mut s = String::new(); if let Some(frontmatter) = self.frontmatter.as_ref() { s.push_str(frontmatter); From b8b5c7c0c2c7e91945329163e8150cde959b482a Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Wed, 1 Nov 2023 10:21:10 +0000 Subject: [PATCH 2/9] cmm: Add path regexes Signed-off-by: Nick Spinale --- hacking/cargo-manifest-management/Cargo.lock | 208 ++++++++++++++++ hacking/cargo-manifest-management/Cargo.toml | 4 + .../src/cargo_manifest_policy.rs | 175 ++++++------- .../src/easy_policy.rs | 100 ++++++++ .../cargo-manifest-management/src/format.rs | 36 ++- hacking/cargo-manifest-management/src/main.rs | 11 +- .../src/path_regex/generic_regex.rs | 231 +++++++++++++++++ .../src/path_regex/grammar.pest | 77 ++++++ .../src/path_regex/mod.rs | 122 +++++++++ .../src/path_regex/parse.rs | 232 ++++++++++++++++++ .../src/path_regex/path_segment_predicate.rs | 59 +++++ 11 files changed, 1132 insertions(+), 123 deletions(-) create mode 100644 hacking/cargo-manifest-management/src/easy_policy.rs create mode 100644 hacking/cargo-manifest-management/src/path_regex/generic_regex.rs create mode 100644 hacking/cargo-manifest-management/src/path_regex/grammar.pest create mode 100644 hacking/cargo-manifest-management/src/path_regex/mod.rs create mode 100644 hacking/cargo-manifest-management/src/path_regex/parse.rs create mode 100644 hacking/cargo-manifest-management/src/path_regex/path_segment_predicate.rs diff --git a/hacking/cargo-manifest-management/Cargo.lock b/hacking/cargo-manifest-management/Cargo.lock index 544074c3f..4a322899b 100644 --- a/hacking/cargo-manifest-management/Cargo.lock +++ b/hacking/cargo-manifest-management/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.6.4" @@ -50,11 +59,24 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "cargo-manifest-management" version = "0.1.0" dependencies = [ "clap", + "pest", + "pest_derive", + "rangemap", + "regex", "serde", "serde_json", "similar", @@ -62,6 +84,12 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "clap" version = "4.4.6" @@ -108,12 +136,51 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "hashbrown" version = "0.14.2" @@ -142,12 +209,69 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "pest" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "proc-macro2" version = "1.0.69" @@ -166,6 +290,41 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rangemap" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977b1e897f9d764566891689e642653e5ed90c6895106acd005eb4c1d0203991" + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "ryu" version = "1.0.15" @@ -212,6 +371,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "similar" version = "2.3.0" @@ -235,6 +405,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "toml" version = "0.8.6" @@ -269,6 +459,18 @@ dependencies = [ "winnow", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -281,6 +483,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/hacking/cargo-manifest-management/Cargo.toml b/hacking/cargo-manifest-management/Cargo.toml index 51138820e..e90ed9ed3 100644 --- a/hacking/cargo-manifest-management/Cargo.toml +++ b/hacking/cargo-manifest-management/Cargo.toml @@ -19,6 +19,10 @@ serde_json = "1.0" toml = "0.8.6" toml_edit = "0.20.4" similar = "2.3" +regex = "1.10.2" +rangemap = "1.4.0" +pest = "2.7.5" +pest_derive = "2.7.5" # exclude from top-level workspace [workspace] diff --git a/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs b/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs index 1e806a00e..2b6c73324 100644 --- a/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs +++ b/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs @@ -4,105 +4,82 @@ // SPDX-License-Identifier: BSD-2-Clause // -use std::cmp::{Ordering, Reverse}; +use crate::{path_regex::PathRegex, EasyPolicy, Policy, TableRule, TableRuleOrdering}; -use crate::{PathSegment, Policy}; - -pub struct CargoManifestPolicy; - -impl Policy for CargoManifestPolicy { - fn max_width(&self) -> usize { - 100 - } - - fn indent_width(&self) -> usize { - 4 - } - - fn never_inline_table(&self, path: &[PathSegment]) -> bool { - path.len() <= 1 - || (path.len() <= 3 && path[0].is_table_key("target")) - || (path.len() <= 3 && path[0].is_table_key("profile")) - || (path.len() == 3 && path[1].is_table_key("bin")) - } - - fn compare_keys(&self, path: &[PathSegment], a: &str, b: &str) -> Ordering { - let ranking = if path.len() == 0 { - Ranking { - front: &[ - "package", - "lib", - "bin", - "features", - "dependencies", - "dev-dependencies", - "build-dependencies", - "workspace", - "profile", - ], - back: &[], - } - } else if path.len() == 1 && path[0].is_table_key("package") { - Ranking { - front: &["name", "version"], - back: &["description"], - } - } else if path.len() >= 2 - && path[path.len() - 2] - .as_table_key() - .map(|k| k.ends_with("dependencies")) - .unwrap_or(false) - { - Ranking { - front: &[ - "path", - "git", - "branch", - "tag", - "rev", - "version", - "registry", - "default-features", - "features", - "optional", - ], - back: &[], - } - } else if path.len() == 2 && path[0].is_table_key("target") { - Ranking { - front: &["dependencies", "dev-dependencies", "build-dependencies"], - back: &[], - } - } else if path.len() == 1 && path[0].is_table_key("workspace") { - Ranking { - front: &[], - back: &["members", "exclude"], - } - } else { - Ranking { - front: &[], - back: &[], - } - }; - ranking.compare(a, b) - } -} - -struct Ranking<'a> { - front: &'a [&'a str], - back: &'a [&'a str], -} - -impl<'a> Ranking<'a> { - fn order<'b>(&self, a: &'b str) -> (Reverse>>, Option, &'b str) { - ( - Reverse(self.front.iter().position(|s| s == &a).map(Reverse)), - self.back.iter().position(|s| s == &a), - a, - ) - } - - fn compare(&self, a: &str, b: &str) -> Ordering { - self.order(a).cmp(&self.order(b)) +pub fn cargo_manifest_policy() -> impl Policy { + EasyPolicy { + rules: vec![ + TableRule { + path_regex: PathRegex::new(r#".{,1}|["target|profile"].{,2}|["bin"][-]."#), + never_inline: true, + ..Default::default() + }, + TableRule { + path_regex: PathRegex::new(""), + sort: TableRuleOrdering { + front: vec![ + "package".to_owned(), + "lib".to_owned(), + "bin".to_owned(), + "features".to_owned(), + "dependencies".to_owned(), + "dev-dependencies".to_owned(), + "build-dependencies".to_owned(), + "workspace".to_owned(), + "profile".to_owned(), + ], + ..Default::default() + }, + ..Default::default() + }, + TableRule { + path_regex: PathRegex::new(r#"["package"]"#), + sort: TableRuleOrdering { + front: vec!["name".to_owned(), "version".to_owned()], + back: vec!["description".to_owned()], + }, + ..Default::default() + }, + TableRule { + path_regex: PathRegex::new(r#".*["(.*-)?dependencies"]."#), + sort: TableRuleOrdering { + front: vec![ + "path".to_owned(), + "git".to_owned(), + "branch".to_owned(), + "tag".to_owned(), + "rev".to_owned(), + "version".to_owned(), + "registry".to_owned(), + "default-features".to_owned(), + "features".to_owned(), + "optional".to_owned(), + ], + ..Default::default() + }, + ..Default::default() + }, + TableRule { + path_regex: PathRegex::new(r#"["target"]."#), + sort: TableRuleOrdering { + front: vec![ + "dependencies".to_owned(), + "dev-dependencies".to_owned(), + "build-dependencies".to_owned(), + ], + ..Default::default() + }, + ..Default::default() + }, + TableRule { + path_regex: PathRegex::new(r#"["workspace"]"#), + sort: TableRuleOrdering { + back: vec!["members".to_owned(), "exclude".to_owned()], + ..Default::default() + }, + ..Default::default() + }, + ], + ..Default::default() } } diff --git a/hacking/cargo-manifest-management/src/easy_policy.rs b/hacking/cargo-manifest-management/src/easy_policy.rs new file mode 100644 index 000000000..092bba2a9 --- /dev/null +++ b/hacking/cargo-manifest-management/src/easy_policy.rs @@ -0,0 +1,100 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use std::cmp::{Ordering, Reverse}; + +use crate::{ + path_regex::{PathRegex, PathSegment}, + Policy, +}; + +pub struct EasyPolicy { + pub max_width: usize, + pub indent_width: usize, + pub rules: Vec, +} + +impl EasyPolicy { + fn matching_rules<'a>( + &'a self, + path: &'a [PathSegment], + ) -> impl 'a + Iterator { + self.rules + .iter() + .rev() + .filter(|rule| rule.path_regex.is_match(path.iter())) + } +} + +pub struct TableRule { + pub path_regex: PathRegex, + pub never_inline: bool, + pub sort: TableRuleOrdering, +} + +#[derive(Default)] +pub struct TableRuleOrdering { + pub front: Vec, + pub back: Vec, +} + +impl Default for EasyPolicy { + fn default() -> Self { + Self { + max_width: 100, + indent_width: 4, + rules: Default::default(), + } + } +} + +impl Default for TableRule { + fn default() -> Self { + Self { + path_regex: PathRegex::new("!(.*)"), + never_inline: Default::default(), + sort: Default::default(), + } + } +} + +impl Policy for EasyPolicy { + fn max_width(&self) -> usize { + self.max_width + } + + fn indent_width(&self) -> usize { + self.indent_width + } + + fn never_inline_table(&self, path: &[PathSegment]) -> bool { + self.matching_rules(path).any(|rule| rule.never_inline) + } + + fn compare_keys(&self, path: &[PathSegment], a: &str, b: &str) -> Ordering { + for rule in self.matching_rules(path) { + let ordering = rule.sort.compare(a, b); + if ordering != Ordering::Equal { + return ordering; + } + } + a.cmp(b) + } +} + +impl TableRuleOrdering { + fn key<'a>(&self, a: &'a str) -> (Reverse>>, Option, &'a str) { + ( + Reverse(self.front.iter().position(|s| s == &a).map(Reverse)), + self.back.iter().position(|s| s == &a), + a, + ) + } + + fn compare(&self, a: &str, b: &str) -> Ordering { + self.key(a).cmp(&self.key(b)) + } +} diff --git a/hacking/cargo-manifest-management/src/format.rs b/hacking/cargo-manifest-management/src/format.rs index 530c8d4e4..4ca2530b9 100644 --- a/hacking/cargo-manifest-management/src/format.rs +++ b/hacking/cargo-manifest-management/src/format.rs @@ -12,6 +12,8 @@ use toml::value::{ }; use toml_edit::{Array, ArrayOfTables, Document, Formatted, InlineTable, Item, Key, Table, Value}; +use crate::path_regex::PathSegment; + pub trait Policy { fn max_width(&self) -> usize; @@ -22,22 +24,16 @@ pub trait Policy { fn compare_keys(&self, path: &[PathSegment], a: &str, b: &str) -> Ordering; } -#[derive(Debug, Clone)] -pub enum PathSegment { - TableKey(String), - ArrayIndex(usize), -} - impl PathSegment { - pub fn as_table_key(&self) -> Option<&str> { + pub fn as_key(&self) -> Option<&str> { match self { - Self::TableKey(k) => Some(k), + Self::Key(k) => Some(k), _ => None, } } - pub fn is_table_key(&self, key: &str) -> bool { - self.as_table_key().map(|k| k == key).unwrap_or(false) + pub fn is_key(&self, key: &str) -> bool { + self.as_key().map(|k| k == key).unwrap_or(false) } } @@ -117,7 +113,7 @@ impl<'a, P: Policy> FormatterState<'a, P> { } let mut table = InlineTable::new(); for (k, x) in v.iter() { - table.insert(k, self.with_table_key(k, |this| this.format_to_value(x))?); + table.insert(k, self.with_key(k, |this| this.format_to_value(x))?); } table.sort_values_by(self.compare_values_at_current_path()); Ok(table) @@ -126,7 +122,7 @@ impl<'a, P: Policy> FormatterState<'a, P> { fn format_array_to_array(&mut self, v: &UnformattedArray) -> Result { let mut array = Array::new(); for (i, x) in v.iter().enumerate() { - array.push(self.with_array_index(i, |this| this.format_to_value(x))?); + array.push(self.with_index(i, |this| this.format_to_value(x))?); } Ok(array) } @@ -135,7 +131,7 @@ impl<'a, P: Policy> FormatterState<'a, P> { let mut table = Table::new(); table.set_implicit(true); for (k, x) in v.iter() { - table.insert(k, self.with_table_key(k, |this| this.format_to_item(x))?); + table.insert(k, self.with_key(k, |this| this.format_to_item(x))?); } table.sort_values_by(self.compare_values_at_current_path()); Ok(table) @@ -162,7 +158,7 @@ impl<'a, P: Policy> FormatterState<'a, P> { .enumerate() { let inline_table = - self.with_array_index(i, |this| this.format_table_to_inline_table(x))?; + self.with_index(i, |this| this.format_table_to_inline_table(x))?; if self.is_inline_table_too_wide_for_array(&inline_table) { inline_tables = None; break; @@ -198,7 +194,7 @@ impl<'a, P: Policy> FormatterState<'a, P> { .map(Option::unwrap) .enumerate() { - let table = self.with_array_index(i, |this| this.format_table_to_table(x))?; + let table = self.with_index(i, |this| this.format_table_to_table(x))?; array_of_tables.push(table); } Item::ArrayOfTables(array_of_tables) @@ -237,7 +233,7 @@ impl<'a, P: Policy> FormatterState<'a, P> { } fn current_key(&self) -> Option<&str> { - self.current_path.last()?.as_table_key() + self.current_path.last()?.as_key() } fn push(&mut self, seg: PathSegment) { self.current_path.push(seg); @@ -254,12 +250,12 @@ impl<'a, P: Policy> FormatterState<'a, P> { r } - fn with_table_key(&mut self, k: &str, f: impl FnOnce(&mut Self) -> R) -> R { - self.with_path_segment(PathSegment::TableKey(k.to_owned()), f) + fn with_key(&mut self, k: &str, f: impl FnOnce(&mut Self) -> R) -> R { + self.with_path_segment(PathSegment::Key(k.to_owned()), f) } - fn with_array_index(&mut self, i: usize, f: impl FnOnce(&mut Self) -> R) -> R { - self.with_path_segment(PathSegment::ArrayIndex(i), f) + fn with_index(&mut self, i: usize, f: impl FnOnce(&mut Self) -> R) -> R { + self.with_path_segment(PathSegment::Index(i), f) } fn compare_values_at_current_path( diff --git a/hacking/cargo-manifest-management/src/main.rs b/hacking/cargo-manifest-management/src/main.rs index 6108fd6b7..ead7802a3 100644 --- a/hacking/cargo-manifest-management/src/main.rs +++ b/hacking/cargo-manifest-management/src/main.rs @@ -14,12 +14,15 @@ use clap::Parser; mod cargo_manifest_policy; mod diff; +mod easy_policy; mod format; +mod path_regex; mod plan; -use cargo_manifest_policy::CargoManifestPolicy; +use cargo_manifest_policy::cargo_manifest_policy; use diff::display_diff; -use format::{Formatter, PathSegment, Policy}; +use easy_policy::{EasyPolicy, TableRule, TableRuleOrdering}; +use format::{Formatter, Policy}; use plan::Plan; #[derive(Debug, Parser)] @@ -35,14 +38,14 @@ fn main() { let args = Args::parse(); let plan_file = File::open(&args.plan).unwrap(); let plan: Plan = serde_json::from_reader(plan_file).unwrap(); - plan.execute(&Formatter::new(CargoManifestPolicy), args.just_check); + plan.execute(&Formatter::new(cargo_manifest_policy()), args.just_check); } // for debugging: fn test_format() { let root_table = serde_json::from_reader(io::stdin()).unwrap(); - let toml_doc = Formatter::new(CargoManifestPolicy) + let toml_doc = Formatter::new(cargo_manifest_policy()) .format(&root_table) .unwrap(); print!("{}", toml_doc) diff --git a/hacking/cargo-manifest-management/src/path_regex/generic_regex.rs b/hacking/cargo-manifest-management/src/path_regex/generic_regex.rs new file mode 100644 index 000000000..87d74fe9e --- /dev/null +++ b/hacking/cargo-manifest-management/src/path_regex/generic_regex.rs @@ -0,0 +1,231 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use std::borrow::Borrow; +use std::rc::Rc; + +// TODO mitigate regex size explosions with smart constructors + +pub trait Predicate { + fn is_match(&self, c: &T) -> bool; +} + +pub struct GenericRegex

{ + inner: Rc>, +} + +impl

Clone for GenericRegex

{ + fn clone(&self) -> Self { + Self { + inner: self.inner().clone(), + } + } +} + +impl

GenericRegex

{ + fn new(inner: Rc>) -> Self { + Self { inner } + } + + fn inner(&self) -> &Rc> { + &self.inner + } + + fn into_inner(self) -> Rc> { + self.inner + } + + pub fn null() -> Self { + Self::new(Inner::null()) + } + + pub fn epsilon() -> Self { + Self::new(Inner::epsilon()) + } + + pub fn symbol(p: P) -> Self { + Self::new(Inner::symbol(p)) + } + + pub fn complement(self) -> Self { + Self::new(Inner::complement(self.into_inner())) + } + + pub fn star(self) -> Self { + Self::new(Inner::star(self.into_inner())) + } + + pub fn or(self, rhs: Self) -> Self { + Self::new(self.into_inner().or(rhs.into_inner())) + } + + pub fn and(self, rhs: Self) -> Self { + Self::new(self.into_inner().and(rhs.into_inner())) + } + + pub fn then(self, rhs: Self) -> Self { + Self::new(self.into_inner().then(rhs.into_inner())) + } + + pub fn traverse( + &self, + f: &mut impl FnMut(&P) -> Result, + ) -> Result, E> { + self.inner().traverse(f).map(GenericRegex::new) + } + + pub fn is_match(&self, s: impl Iterator>) -> bool + where + P: Predicate, + { + let mut r = self.inner().clone(); + for x in s { + r = r.derivative(x.borrow()); + } + r.nullable() + } + + // combinators + + pub fn plus(self) -> Self { + Self::then(self.clone(), self.star()) + } + + pub fn optional(self) -> Self { + Self::or(self, Self::epsilon()) + } + + pub fn repeat(self, min: Option, max: Option) -> Self { + let lhs = match min { + Some(n) => self.clone().repeat_at_least(n), + None => Self::null().complement(), + }; + let rhs = match max { + Some(n) => self.clone().repeat_at_most(n), + None => Self::null().complement(), + }; + lhs.and(rhs) + } + + pub fn repeat_exactly(self, n: usize) -> Self { + match n { + 0 => Self::epsilon(), + _ => Self::then(self.clone(), self.repeat_exactly(n - 1)), + } + } + + pub fn repeat_at_least(self, n: usize) -> Self { + self.clone().repeat_exactly(n).then(self.star()) + } + + pub fn repeat_at_most(self, n: usize) -> Self { + match n { + 0 => Self::epsilon(), + _ => Self::or( + Self::epsilon(), + Self::then(self.clone(), self.repeat_exactly(n - 1)), + ), + } + } +} + +#[derive(Debug, Clone)] +enum Inner

{ + Null, + Epsilon, + Symbol(P), + Complement(Rc), + Star(Rc), + Or(Rc, Rc), + And(Rc, Rc), + Then(Rc, Rc), +} + +impl

Inner

{ + fn null() -> Rc { + Rc::new(Self::Null) + } + + fn epsilon() -> Rc { + Rc::new(Self::Epsilon) + } + + fn symbol(p: P) -> Rc { + Rc::new(Self::Symbol(p)) + } + + fn complement(self: Rc) -> Rc { + Rc::new(Self::Complement(self)) + } + + fn star(self: Rc) -> Rc { + Rc::new(Self::Complement(self)) + } + + fn or(self: Rc, rhs: Rc) -> Rc { + Rc::new(Self::Or(self, rhs)) + } + + fn and(self: Rc, rhs: Rc) -> Rc { + Rc::new(Self::And(self, rhs)) + } + + fn then(self: Rc, rhs: Rc) -> Rc { + Rc::new(Self::Then(self, rhs)) + } + + fn traverse(&self, f: &mut impl FnMut(&P) -> Result) -> Result>, E> { + Ok(Rc::new(match self { + Self::Null => Inner::Null, + Self::Epsilon => Inner::Epsilon, + Self::Symbol(p) => Inner::Symbol(f(p)?), + Self::Complement(r) => Inner::Complement(r.traverse(f)?), + Self::Star(r) => Inner::Star(r.traverse(f)?), + Self::Or(lhs, rhs) => Inner::Or(lhs.traverse(f)?, rhs.traverse(f)?), + Self::And(lhs, rhs) => Inner::And(lhs.traverse(f)?, rhs.traverse(f)?), + Self::Then(lhs, rhs) => Inner::Then(lhs.traverse(f)?, rhs.traverse(f)?), + })) + } + + fn nullable(&self) -> bool { + match self { + Self::Null => false, + Self::Epsilon => true, + Self::Symbol(_) => false, + Self::Complement(r) => !r.nullable(), + Self::Star(_) => true, + Self::Or(lhs, rhs) => lhs.nullable() || rhs.nullable(), + Self::And(lhs, rhs) => lhs.nullable() && rhs.nullable(), + Self::Then(lhs, rhs) => lhs.nullable() && rhs.nullable(), + } + } + + fn derivative(&self, c: &T) -> Rc + where + P: Predicate, + { + match self { + Self::Null => Self::null(), + Self::Epsilon => Self::null(), + Self::Symbol(p) => { + if p.is_match(c) { + Self::epsilon() + } else { + Self::null() + } + } + Self::Complement(r) => Self::complement(r.derivative(c)), + Self::Star(r) => r.derivative(c).then(r.clone().star()), + Self::Or(lhs, rhs) => lhs.derivative(c).or(rhs.derivative(c)), + Self::And(lhs, rhs) => lhs.derivative(c).and(rhs.derivative(c)), + Self::Then(lhs, rhs) => lhs.derivative(c).then(rhs.clone()).or(if lhs.nullable() { + rhs.derivative(c) + } else { + Self::null() + }), + } + } +} diff --git a/hacking/cargo-manifest-management/src/path_regex/grammar.pest b/hacking/cargo-manifest-management/src/path_regex/grammar.pest new file mode 100644 index 000000000..771aeea2c --- /dev/null +++ b/hacking/cargo-manifest-management/src/path_regex/grammar.pest @@ -0,0 +1,77 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +path_regex = { + SOI ~ opt_expr ~ EOI +} + +opt_expr = { + expr? +} + +expr = { + prefix? ~ primary ~ postfix? ~ (infix ~ prefix? ~ primary ~ postfix? )* +} + +primary = _{ + dot | key_symbol | index_symbol | "(" ~ opt_expr ~ ")" +} + +prefix = _{ not } +postfix = _{ star | plus | optional | repeat } +infix = _{ or | and | concat } + +not = { "!" } + +star = { "*" } +plus = {"+" } +optional = { "?" } + +repeat = { "{" ~ repeat_inner ~ "}" } +repeat_inner = { repeat_inclusive_range | repeat_exactly } +repeat_inclusive_range = { repeat_inclusive_range_side ~ "," ~ repeat_inclusive_range_side } +repeat_inclusive_range_side = { intlit? } +repeat_exactly = { intlit } + +or = { "|" } +and = { "&" } +concat = { "" } + +dot = { "." } + +key_symbol = { + "[" ~ PUSH("\""+) ~ key_symbol_regex ~ POP ~ "]" +} + +key_symbol_regex = { + ( + !(PEEK ~ "]") ~ ANY + )* +} + +index_symbol = { + "[" ~ opt_index_symbol_ranges ~ "]" +} + +opt_index_symbol_ranges = { + index_symbol_ranges? +} + +index_symbol_ranges = { + index_symbol_range ~ ("," ~ index_symbol_range)* +} + +index_symbol_range = { + index_symbol_range_side ~ "-" ~ index_symbol_range_side +} + +index_symbol_range_side = { + intlit? +} + +intlit = @{ + "0" | ASCII_NONZERO_DIGIT ~ (ASCII_DIGIT)* +} diff --git a/hacking/cargo-manifest-management/src/path_regex/mod.rs b/hacking/cargo-manifest-management/src/path_regex/mod.rs new file mode 100644 index 000000000..c17729262 --- /dev/null +++ b/hacking/cargo-manifest-management/src/path_regex/mod.rs @@ -0,0 +1,122 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use std::borrow::Borrow; + +mod generic_regex; +mod parse; +mod path_segment_predicate; + +use generic_regex::GenericRegex; +use parse::{parse, Expr}; +use path_segment_predicate::PathSegmentPredicate; + +#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub enum PathSegment { + Key(String), + Index(usize), +} + +#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] +struct Path { + inner: Vec, +} + +impl Path { + pub fn new() -> Self { + Self::default() + } + + pub fn as_slice(&self) -> &[PathSegment] { + self.inner.as_slice() + } + + pub fn push(&mut self, path_segment: PathSegment) { + self.inner.push(path_segment) + } + + pub fn push_key(&mut self, key: String) { + self.push(PathSegment::Key(key)) + } + + pub fn push_index(&mut self, index: usize) { + self.push(PathSegment::Index(index)) + } + + pub fn pop(&mut self) -> Option { + self.inner.pop() + } +} + +pub struct PathRegex { + source: String, + inner: GenericRegex, +} + +impl PathRegex { + pub fn new(path_regex: &str) -> Self { + let expr = parse(path_regex); + Self { + source: path_regex.to_owned(), + inner: generic_regex_from_expr(&expr), + } + } + + pub fn is_match(&self, path: impl Iterator>) -> bool { + self.inner.is_match(path) + } + + pub fn source(&self) -> &str { + &self.source + } +} + +fn generic_regex_from_expr(expr: &Expr) -> GenericRegex { + match expr { + Expr::Epsilon => GenericRegex::epsilon(), + Expr::Not(r) => GenericRegex::complement(generic_regex_from_expr(r)), + Expr::Star(r) => GenericRegex::star(generic_regex_from_expr(r)), + Expr::Plus(r) => GenericRegex::plus(generic_regex_from_expr(r)), + Expr::Optional(r) => GenericRegex::optional(generic_regex_from_expr(r)), + Expr::Repeat(r, repetition) => { + GenericRegex::repeat(generic_regex_from_expr(r), repetition.min, repetition.max) + } + Expr::And(rhs, lhs) => { + GenericRegex::and(generic_regex_from_expr(rhs), generic_regex_from_expr(lhs)) + } + Expr::Or(rhs, lhs) => { + GenericRegex::or(generic_regex_from_expr(rhs), generic_regex_from_expr(lhs)) + } + Expr::Concat(rhs, lhs) => { + GenericRegex::then(generic_regex_from_expr(rhs), generic_regex_from_expr(lhs)) + } + Expr::Dot => GenericRegex::symbol(PathSegmentPredicate::any()), + Expr::KeySymbol(key_regex) => { + GenericRegex::symbol(PathSegmentPredicate::from_key_regex(key_regex)) + } + Expr::IndexSymbol(index_ranges) => { + GenericRegex::symbol(PathSegmentPredicate::from_index_ranges(index_ranges)) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn it_works() { + assert!(PathRegex::new(r#"["package"]"#) + .is_match([PathSegment::Key("package".to_owned())].iter())); + assert!(PathRegex::new(r#".*["(.*-)?dependencies"]."#).is_match( + [ + PathSegment::Key("dependencies".to_owned()), + PathSegment::Key("foo".to_owned()) + ] + .iter() + )); + } +} diff --git a/hacking/cargo-manifest-management/src/path_regex/parse.rs b/hacking/cargo-manifest-management/src/path_regex/parse.rs new file mode 100644 index 000000000..77a720b1a --- /dev/null +++ b/hacking/cargo-manifest-management/src/path_regex/parse.rs @@ -0,0 +1,232 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use pest::{ + iterators::Pair, + pratt_parser::{Assoc, Op, PrattParser}, + Parser, +}; +use pest_derive::Parser; + +#[derive(Parser)] +#[grammar = "path_regex/grammar.pest"] +struct PathRegexParser; + +#[derive(Debug, Clone)] +pub enum Expr { + Epsilon, + Not(Box), + Star(Box), + Plus(Box), + Optional(Box), + Repeat(Box, Repetition), + And(Box, Box), + Or(Box, Box), + Concat(Box, Box), + Dot, + KeySymbol(String), + IndexSymbol(Vec), +} + +#[derive(Debug, Clone)] +pub struct Repetition { + pub min: Option, + pub max: Option, +} + +#[derive(Debug, Clone)] +pub struct IndexRange { + pub start: Option, + pub end: Option, +} + +pub fn parse(s: &str) -> Expr { + let mut top_level_pairs = + PathRegexParser::parse(Rule::path_regex, &s).unwrap_or_else(|err| panic!("{}", err)); + assert_eq!(top_level_pairs.len(), 1); + let path_regex_pair = top_level_pairs.next().unwrap(); + assert_eq!(path_regex_pair.as_rule(), Rule::path_regex); + let expr_pair = path_regex_pair.into_inner().next().unwrap(); + *Expr::parse(expr_pair) +} + +impl Expr { + fn pratt() -> PrattParser { + PrattParser::new() + .op(Op::infix(Rule::or, Assoc::Right)) + .op(Op::infix(Rule::and, Assoc::Right)) + .op(Op::infix(Rule::concat, Assoc::Right)) + .op(Op::postfix(Rule::star)) + .op(Op::postfix(Rule::plus)) + .op(Op::postfix(Rule::optional)) + .op(Op::postfix(Rule::repeat)) + .op(Op::prefix(Rule::not)) + } + + fn parse(pair: Pair) -> Box { + Self::parse_inner(pair, &Self::pratt()) + } + + fn parse_inner(pair: Pair, pratt: &PrattParser) -> Box { + assert_eq!(pair.as_rule(), Rule::opt_expr); + + if let Some(expr_pair) = pair.into_inner().next() { + assert_eq!(expr_pair.as_rule(), Rule::expr); + pratt + .map_primary(|primary| match primary.as_rule() { + Rule::dot => Box::new(Self::Dot), + Rule::key_symbol => Box::new(Self::KeySymbol(Self::parse_key_symbol(primary))), + Rule::index_symbol => { + Box::new(Self::IndexSymbol(Self::parse_index_symbol(primary))) + } + Rule::opt_expr => Self::parse_inner(primary, pratt), + _ => unreachable!(), + }) + .map_prefix(|op, rhs| { + Box::new(match op.as_rule() { + Rule::not => Self::Not(rhs), + _ => unreachable!(), + }) + }) + .map_postfix(|lhs, op| { + Box::new(match op.as_rule() { + Rule::star => Self::Star(lhs), + Rule::plus => Self::Plus(lhs), + Rule::optional => Self::Optional(lhs), + Rule::repeat => Self::Repeat(lhs, Repetition::parse(op)), + _ => unreachable!(), + }) + }) + .map_infix(|lhs, op, rhs| { + Box::new(match op.as_rule() { + Rule::or => Self::Or(lhs, rhs), + Rule::and => Self::And(lhs, rhs), + Rule::concat => Self::Concat(lhs, rhs), + _ => unreachable!(), + }) + }) + .parse(expr_pair.into_inner()) + } else { + Box::new(Self::Epsilon) + } + } + + fn parse_key_symbol(pair: Pair) -> String { + assert_eq!(pair.as_rule(), Rule::key_symbol); + let key_symbol_regex_pair = pair.into_inner().next().unwrap(); + assert_eq!(key_symbol_regex_pair.as_rule(), Rule::key_symbol_regex); + key_symbol_regex_pair.as_str().to_owned() + } + + fn parse_index_symbol(pair: Pair) -> Vec { + assert_eq!(pair.as_rule(), Rule::index_symbol); + let opt_index_symbol_ranges_pair = pair.into_inner().next().unwrap(); + assert_eq!( + opt_index_symbol_ranges_pair.as_rule(), + Rule::opt_index_symbol_ranges + ); + opt_index_symbol_ranges_pair + .into_inner() + .next() + .map(|index_symbol_ranges_pair| { + assert_eq!( + index_symbol_ranges_pair.as_rule(), + Rule::index_symbol_ranges + ); + index_symbol_ranges_pair + .into_inner() + .map(|index_symbol_range_pair| { + assert_eq!(index_symbol_range_pair.as_rule(), Rule::index_symbol_range); + IndexRange::parse(index_symbol_range_pair) + }) + .collect::>() + }) + .unwrap_or_else(|| vec![]) + } +} + +impl Repetition { + fn parse(pair: Pair) -> Self { + assert_eq!(pair.as_rule(), Rule::repeat); + let repeat_inner_pair = pair.into_inner().next().unwrap(); + assert_eq!(repeat_inner_pair.as_rule(), Rule::repeat_inner); + let pair = repeat_inner_pair.into_inner().next().unwrap(); + match pair.as_rule() { + Rule::repeat_exactly => { + let intlit_pair = pair.into_inner().next().unwrap(); + assert_eq!(intlit_pair.as_rule(), Rule::intlit); + let n = intlit_pair.as_str().parse().unwrap(); + Self { + min: Some(n), + max: Some(n), + } + } + Rule::repeat_inclusive_range => { + assert_eq!(pair.as_rule(), Rule::repeat_inclusive_range); + let mut pairs = pair.into_inner(); + let min = Self::parse_side(pairs.next().unwrap()); + let max = Self::parse_side(pairs.next().unwrap()); + Self { min, max } + } + _ => unreachable!(), + } + } + + fn parse_side(pair: Pair) -> Option { + parse_range_side(pair, Rule::repeat_inclusive_range_side) + } +} + +impl IndexRange { + fn parse(pair: Pair) -> Self { + assert_eq!(pair.as_rule(), Rule::index_symbol_range); + let mut pairs = pair.into_inner(); + let start = Self::parse_side(pairs.next().unwrap()); + let end = Self::parse_side(pairs.next().unwrap()); + Self { start, end } + } + + fn parse_side(pair: Pair) -> Option { + parse_range_side(pair, Rule::index_symbol_range_side) + } +} + +fn parse_range_side(pair: Pair, rule: Rule) -> Option { + assert_eq!(pair.as_rule(), rule); + pair.into_inner().next().map(|intlit_pair| { + assert_eq!(intlit_pair.as_rule(), Rule::intlit); + intlit_pair.as_str().parse().unwrap() + }) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test() { + let ss = &[ + "(.)", + r#".*![""abc""](.|.&.)"#, + "[-]", + "[1-]", + "[-1]", + "[1-1]", + ".{,}", + ".{1}", + ".{,1}", + ".{1,}", + ".{1,1}", + "", + "()", + "()()", + ".().", + ]; + for s in ss { + parse(s); + } + } +} diff --git a/hacking/cargo-manifest-management/src/path_regex/path_segment_predicate.rs b/hacking/cargo-manifest-management/src/path_regex/path_segment_predicate.rs new file mode 100644 index 000000000..a02861931 --- /dev/null +++ b/hacking/cargo-manifest-management/src/path_regex/path_segment_predicate.rs @@ -0,0 +1,59 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use rangemap::inclusive_set::RangeInclusiveSet; +use regex::Regex; + +use super::generic_regex::Predicate; +use super::parse::IndexRange; +use super::PathSegment; + +pub struct PathSegmentPredicate { + inner: Inner, +} + +enum Inner { + Any, + Key(Regex), + Index(RangeInclusiveSet), +} + +impl PathSegmentPredicate { + fn new(inner: Inner) -> Self { + Self { inner } + } + + pub fn any() -> Self { + Self::new(Inner::Any) + } + + pub fn from_key_regex(re: &str) -> Self { + let anchored_re = format!("^{re}$"); // TODO is this sound? + let compiled = Regex::new(&anchored_re).unwrap(); + Self::new(Inner::Key(compiled)) + } + + pub fn from_index_ranges(ranges: &[IndexRange]) -> Self { + let mut set = RangeInclusiveSet::new(); + for range in ranges { + let start = range.start.unwrap_or(usize::MIN); + let end = range.end.unwrap_or(usize::MAX); + set.insert(start..=end); + } + Self::new(Inner::Index(set)) + } +} + +impl Predicate for PathSegmentPredicate { + fn is_match(&self, path_segment: &PathSegment) -> bool { + match (&self.inner, path_segment) { + (Inner::Any, _) => true, + (Inner::Key(re), PathSegment::Key(key)) => re.is_match(key), + (Inner::Index(set), PathSegment::Index(index)) => set.contains(index), + _ => false, + } + } +} From 7411e732d0b2e1ed49575fa5cc9a81923ca7ad3d Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Fri, 3 Nov 2023 08:02:52 +0000 Subject: [PATCH 3/9] cmm: Split crates Signed-off-by: Nick Spinale --- hacking/cargo-manifest-management/Cargo.lock | 49 +++++++++++++------ hacking/cargo-manifest-management/Cargo.toml | 26 +++------- hacking/cargo-manifest-management/Makefile | 2 +- .../crates/manage-cargo-manifests/Cargo.toml | 23 +++++++++ .../manage-cargo-manifests}/src/diff.rs | 0 .../manage-cargo-manifests}/src/main.rs | 9 +--- .../manage-cargo-manifests}/src/plan.rs | 4 +- .../crates/toml-normalize/Cargo.toml | 18 +++++++ .../src/cargo_manifest_policy.rs | 4 +- .../toml-normalize}/src/easy_policy.rs | 7 ++- .../{ => crates/toml-normalize}/src/format.rs | 24 ++------- .../crates/toml-normalize/src/lib.rs | 7 +++ .../crates/toml-path-regex/Cargo.toml | 19 +++++++ .../toml-path-regex/src}/generic_regex.rs | 3 +- .../toml-path-regex/src}/grammar.pest | 0 .../toml-path-regex/src/lib.rs} | 26 +++++++++- .../toml-path-regex/src}/parse.rs | 2 +- .../src}/path_segment_predicate.rs | 0 18 files changed, 151 insertions(+), 72 deletions(-) create mode 100644 hacking/cargo-manifest-management/crates/manage-cargo-manifests/Cargo.toml rename hacking/cargo-manifest-management/{ => crates/manage-cargo-manifests}/src/diff.rs (100%) rename hacking/cargo-manifest-management/{ => crates/manage-cargo-manifests}/src/main.rs (79%) rename hacking/cargo-manifest-management/{ => crates/manage-cargo-manifests}/src/plan.rs (97%) create mode 100644 hacking/cargo-manifest-management/crates/toml-normalize/Cargo.toml rename hacking/cargo-manifest-management/{ => crates/toml-normalize}/src/cargo_manifest_policy.rs (96%) rename hacking/cargo-manifest-management/{ => crates/toml-normalize}/src/easy_policy.rs (96%) rename hacking/cargo-manifest-management/{ => crates/toml-normalize}/src/format.rs (95%) create mode 100644 hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs create mode 100644 hacking/cargo-manifest-management/crates/toml-path-regex/Cargo.toml rename hacking/cargo-manifest-management/{src/path_regex => crates/toml-path-regex/src}/generic_regex.rs (99%) rename hacking/cargo-manifest-management/{src/path_regex => crates/toml-path-regex/src}/grammar.pest (100%) rename hacking/cargo-manifest-management/{src/path_regex/mod.rs => crates/toml-path-regex/src/lib.rs} (85%) rename hacking/cargo-manifest-management/{src/path_regex => crates/toml-path-regex/src}/parse.rs (99%) rename hacking/cargo-manifest-management/{src/path_regex => crates/toml-path-regex/src}/path_segment_predicate.rs (100%) diff --git a/hacking/cargo-manifest-management/Cargo.lock b/hacking/cargo-manifest-management/Cargo.lock index 4a322899b..0f7f76347 100644 --- a/hacking/cargo-manifest-management/Cargo.lock +++ b/hacking/cargo-manifest-management/Cargo.lock @@ -68,22 +68,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "cargo-manifest-management" -version = "0.1.0" -dependencies = [ - "clap", - "pest", - "pest_derive", - "rangemap", - "regex", - "serde", - "serde_json", - "similar", - "toml", - "toml_edit", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -215,6 +199,20 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "manage-cargo-manifests" +version = "0.1.0" +dependencies = [ + "clap", + "serde", + "serde_json", + "similar", + "toml", + "toml-normalize", + "toml-path-regex", + "toml_edit", +] + [[package]] name = "memchr" version = "2.6.4" @@ -437,6 +435,25 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "toml-normalize" +version = "0.1.0" +dependencies = [ + "toml", + "toml-path-regex", + "toml_edit", +] + +[[package]] +name = "toml-path-regex" +version = "0.1.0" +dependencies = [ + "pest", + "pest_derive", + "rangemap", + "regex", +] + [[package]] name = "toml_datetime" version = "0.6.5" diff --git a/hacking/cargo-manifest-management/Cargo.toml b/hacking/cargo-manifest-management/Cargo.toml index e90ed9ed3..52f7d4e82 100644 --- a/hacking/cargo-manifest-management/Cargo.toml +++ b/hacking/cargo-manifest-management/Cargo.toml @@ -5,24 +5,10 @@ # # -[package] -name = "cargo-manifest-management" -version = "0.1.0" -authors = ["Nick Spinale "] -edition = "2021" -license = "BSD-2-Clause" - -[dependencies] -clap = { version = "4.4.6", features = [ "derive" ] } -serde = { version = "1.0", features = [ "derive" ] } -serde_json = "1.0" -toml = "0.8.6" -toml_edit = "0.20.4" -similar = "2.3" -regex = "1.10.2" -rangemap = "1.4.0" -pest = "2.7.5" -pest_derive = "2.7.5" - -# exclude from top-level workspace [workspace] +resolver = "2" +members = [ + "crates/toml-path-regex", + "crates/toml-normalize", + "crates/manage-cargo-manifests", +] diff --git a/hacking/cargo-manifest-management/Makefile b/hacking/cargo-manifest-management/Makefile index cf70784fc..2b23d97d1 100644 --- a/hacking/cargo-manifest-management/Makefile +++ b/hacking/cargo-manifest-management/Makefile @@ -5,7 +5,7 @@ # plan := $$(nix-build -A planJSON --no-out-link) -run := cargo run -- --plan $(plan) +run := cargo run -p manage-cargo-manifests -- --plan $(plan) .PHONY: none none: diff --git a/hacking/cargo-manifest-management/crates/manage-cargo-manifests/Cargo.toml b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/Cargo.toml new file mode 100644 index 000000000..4fc608886 --- /dev/null +++ b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/Cargo.toml @@ -0,0 +1,23 @@ +# +# Copyright 2023, Colias Group, LLC +# +# SPDX-License-Identifier: BSD-2-Clause +# +# + +[package] +name = "manage-cargo-manifests" +version = "0.1.0" +authors = ["Nick Spinale "] +edition = "2021" +license = "BSD-2-Clause" + +[dependencies] +clap = { version = "4.4.6", features = [ "derive" ] } +serde = { version = "1.0", features = [ "derive" ] } +serde_json = "1.0" +toml = "0.8.6" +toml_edit = "0.20.4" +similar = "2.3" +toml-path-regex = { path = "../toml-path-regex" } +toml-normalize = { path = "../toml-normalize" } diff --git a/hacking/cargo-manifest-management/src/diff.rs b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/diff.rs similarity index 100% rename from hacking/cargo-manifest-management/src/diff.rs rename to hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/diff.rs diff --git a/hacking/cargo-manifest-management/src/main.rs b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/main.rs similarity index 79% rename from hacking/cargo-manifest-management/src/main.rs rename to hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/main.rs index ead7802a3..b7b60f5c7 100644 --- a/hacking/cargo-manifest-management/src/main.rs +++ b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/main.rs @@ -12,17 +12,12 @@ use std::path::PathBuf; use clap::Parser; -mod cargo_manifest_policy; +use toml_normalize::{cargo_manifest_policy, Formatter}; + mod diff; -mod easy_policy; -mod format; -mod path_regex; mod plan; -use cargo_manifest_policy::cargo_manifest_policy; use diff::display_diff; -use easy_policy::{EasyPolicy, TableRule, TableRuleOrdering}; -use format::{Formatter, Policy}; use plan::Plan; #[derive(Debug, Parser)] diff --git a/hacking/cargo-manifest-management/src/plan.rs b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/plan.rs similarity index 97% rename from hacking/cargo-manifest-management/src/plan.rs rename to hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/plan.rs index 863c000dc..695162448 100644 --- a/hacking/cargo-manifest-management/src/plan.rs +++ b/hacking/cargo-manifest-management/crates/manage-cargo-manifests/src/plan.rs @@ -13,7 +13,9 @@ use std::str; use serde::Deserialize; use toml::Table as UnformattedTable; -use crate::{display_diff, Formatter, Policy}; +use toml_normalize::{Formatter, Policy}; + +use crate::display_diff; #[derive(Debug, Deserialize)] #[serde(transparent)] diff --git a/hacking/cargo-manifest-management/crates/toml-normalize/Cargo.toml b/hacking/cargo-manifest-management/crates/toml-normalize/Cargo.toml new file mode 100644 index 000000000..3b1128191 --- /dev/null +++ b/hacking/cargo-manifest-management/crates/toml-normalize/Cargo.toml @@ -0,0 +1,18 @@ +# +# Copyright 2023, Colias Group, LLC +# +# SPDX-License-Identifier: BSD-2-Clause +# +# + +[package] +name = "toml-normalize" +version = "0.1.0" +authors = ["Nick Spinale "] +edition = "2021" +license = "BSD-2-Clause" + +[dependencies] +toml = "0.8.6" +toml_edit = "0.20.4" +toml-path-regex = { path = "../toml-path-regex" } diff --git a/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs similarity index 96% rename from hacking/cargo-manifest-management/src/cargo_manifest_policy.rs rename to hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs index 2b6c73324..0f6477814 100644 --- a/hacking/cargo-manifest-management/src/cargo_manifest_policy.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs @@ -4,7 +4,9 @@ // SPDX-License-Identifier: BSD-2-Clause // -use crate::{path_regex::PathRegex, EasyPolicy, Policy, TableRule, TableRuleOrdering}; +use toml_path_regex::PathRegex; + +use crate::{EasyPolicy, Policy, TableRule, TableRuleOrdering}; pub fn cargo_manifest_policy() -> impl Policy { EasyPolicy { diff --git a/hacking/cargo-manifest-management/src/easy_policy.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/easy_policy.rs similarity index 96% rename from hacking/cargo-manifest-management/src/easy_policy.rs rename to hacking/cargo-manifest-management/crates/toml-normalize/src/easy_policy.rs index 092bba2a9..7e912bc43 100644 --- a/hacking/cargo-manifest-management/src/easy_policy.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/easy_policy.rs @@ -6,10 +6,9 @@ use std::cmp::{Ordering, Reverse}; -use crate::{ - path_regex::{PathRegex, PathSegment}, - Policy, -}; +use toml_path_regex::{PathRegex, PathSegment}; + +use crate::Policy; pub struct EasyPolicy { pub max_width: usize, diff --git a/hacking/cargo-manifest-management/src/format.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs similarity index 95% rename from hacking/cargo-manifest-management/src/format.rs rename to hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs index 4ca2530b9..82206816c 100644 --- a/hacking/cargo-manifest-management/src/format.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs @@ -12,7 +12,7 @@ use toml::value::{ }; use toml_edit::{Array, ArrayOfTables, Document, Formatted, InlineTable, Item, Key, Table, Value}; -use crate::path_regex::PathSegment; +use toml_path_regex::PathSegment; pub trait Policy { fn max_width(&self) -> usize; @@ -24,19 +24,6 @@ pub trait Policy { fn compare_keys(&self, path: &[PathSegment], a: &str, b: &str) -> Ordering; } -impl PathSegment { - pub fn as_key(&self) -> Option<&str> { - match self { - Self::Key(k) => Some(k), - _ => None, - } - } - - pub fn is_key(&self, key: &str) -> bool { - self.as_key().map(|k| k == key).unwrap_or(false) - } -} - pub struct Formatter

{ policy: P, } @@ -74,6 +61,10 @@ impl CannotInlineTableError { fn new(path: Vec) -> Self { Self { path } } + + pub fn path(&self) -> &[PathSegment] { + &self.path + } } impl From for Error { @@ -82,11 +73,6 @@ impl From for Error { } } -struct FormattedTable { - table: Table, - inline_table: Result, -} - impl<'a, P: Policy> FormatterState<'a, P> { fn format_top_level(&mut self, v: &UnformattedTable) -> Result { let table = self.format_table_to_table(v)?; diff --git a/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs new file mode 100644 index 000000000..3172c9850 --- /dev/null +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs @@ -0,0 +1,7 @@ +mod cargo_manifest_policy; +mod easy_policy; +mod format; + +pub use cargo_manifest_policy::cargo_manifest_policy; +pub use easy_policy::{EasyPolicy, TableRule, TableRuleOrdering}; +pub use format::{Formatter, Policy}; diff --git a/hacking/cargo-manifest-management/crates/toml-path-regex/Cargo.toml b/hacking/cargo-manifest-management/crates/toml-path-regex/Cargo.toml new file mode 100644 index 000000000..fc0847efb --- /dev/null +++ b/hacking/cargo-manifest-management/crates/toml-path-regex/Cargo.toml @@ -0,0 +1,19 @@ +# +# Copyright 2023, Colias Group, LLC +# +# SPDX-License-Identifier: BSD-2-Clause +# +# + +[package] +name = "toml-path-regex" +version = "0.1.0" +authors = ["Nick Spinale "] +edition = "2021" +license = "BSD-2-Clause" + +[dependencies] +regex = "1.10.2" +rangemap = "1.4.0" +pest = "2.7.5" +pest_derive = "2.7.5" diff --git a/hacking/cargo-manifest-management/src/path_regex/generic_regex.rs b/hacking/cargo-manifest-management/crates/toml-path-regex/src/generic_regex.rs similarity index 99% rename from hacking/cargo-manifest-management/src/path_regex/generic_regex.rs rename to hacking/cargo-manifest-management/crates/toml-path-regex/src/generic_regex.rs index 87d74fe9e..f11637f5b 100644 --- a/hacking/cargo-manifest-management/src/path_regex/generic_regex.rs +++ b/hacking/cargo-manifest-management/crates/toml-path-regex/src/generic_regex.rs @@ -70,6 +70,7 @@ impl

GenericRegex

{ Self::new(self.into_inner().then(rhs.into_inner())) } + #[allow(dead_code)] pub fn traverse( &self, f: &mut impl FnMut(&P) -> Result, @@ -162,7 +163,7 @@ impl

Inner

{ } fn star(self: Rc) -> Rc { - Rc::new(Self::Complement(self)) + Rc::new(Self::Star(self)) } fn or(self: Rc, rhs: Rc) -> Rc { diff --git a/hacking/cargo-manifest-management/src/path_regex/grammar.pest b/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest similarity index 100% rename from hacking/cargo-manifest-management/src/path_regex/grammar.pest rename to hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest diff --git a/hacking/cargo-manifest-management/src/path_regex/mod.rs b/hacking/cargo-manifest-management/crates/toml-path-regex/src/lib.rs similarity index 85% rename from hacking/cargo-manifest-management/src/path_regex/mod.rs rename to hacking/cargo-manifest-management/crates/toml-path-regex/src/lib.rs index c17729262..d7b599d33 100644 --- a/hacking/cargo-manifest-management/src/path_regex/mod.rs +++ b/hacking/cargo-manifest-management/crates/toml-path-regex/src/lib.rs @@ -20,8 +20,32 @@ pub enum PathSegment { Index(usize), } +impl PathSegment { + pub fn as_key(&self) -> Option<&str> { + match self { + Self::Key(k) => Some(k), + _ => None, + } + } + + pub fn is_key(&self, key: &str) -> bool { + self.as_key().map(|k| k == key).unwrap_or(false) + } + + pub fn as_index(&self) -> Option { + match self { + Self::Index(i) => Some(*i), + _ => None, + } + } + + pub fn is_index(&self, index: usize) -> bool { + self.as_index().map(|i| i == index).unwrap_or(false) + } +} + #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] -struct Path { +pub struct Path { inner: Vec, } diff --git a/hacking/cargo-manifest-management/src/path_regex/parse.rs b/hacking/cargo-manifest-management/crates/toml-path-regex/src/parse.rs similarity index 99% rename from hacking/cargo-manifest-management/src/path_regex/parse.rs rename to hacking/cargo-manifest-management/crates/toml-path-regex/src/parse.rs index 77a720b1a..71d0930cf 100644 --- a/hacking/cargo-manifest-management/src/path_regex/parse.rs +++ b/hacking/cargo-manifest-management/crates/toml-path-regex/src/parse.rs @@ -12,7 +12,7 @@ use pest::{ use pest_derive::Parser; #[derive(Parser)] -#[grammar = "path_regex/grammar.pest"] +#[grammar = "grammar.pest"] struct PathRegexParser; #[derive(Debug, Clone)] diff --git a/hacking/cargo-manifest-management/src/path_regex/path_segment_predicate.rs b/hacking/cargo-manifest-management/crates/toml-path-regex/src/path_segment_predicate.rs similarity index 100% rename from hacking/cargo-manifest-management/src/path_regex/path_segment_predicate.rs rename to hacking/cargo-manifest-management/crates/toml-path-regex/src/path_segment_predicate.rs From b2478ffc342dd51031e2ed83ed106be20af7b7a0 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Fri, 3 Nov 2023 08:17:17 +0000 Subject: [PATCH 4/9] cmm: Run cargo update Signed-off-by: Nick Spinale --- hacking/cargo-manifest-management/Cargo.lock | 36 ++++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/hacking/cargo-manifest-management/Cargo.lock b/hacking/cargo-manifest-management/Cargo.lock index 0f7f76347..5f96bc5ba 100644 --- a/hacking/cargo-manifest-management/Cargo.lock +++ b/hacking/cargo-manifest-management/Cargo.lock @@ -76,9 +76,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -86,9 +86,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", @@ -98,9 +98,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" @@ -179,9 +179,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown", @@ -331,18 +331,18 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -574,9 +574,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32" dependencies = [ "memchr", ] From add8845fc3649a091309104e0c98dd09199922d0 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Fri, 3 Nov 2023 08:18:07 +0000 Subject: [PATCH 5/9] cmm: Add missing REUSE header Signed-off-by: Nick Spinale --- .../crates/toml-normalize/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) 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 3172c9850..60c19740a 100644 --- a/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/lib.rs @@ -1,3 +1,9 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + mod cargo_manifest_policy; mod easy_policy; mod format; From 8f646eae1a7fa1235272730a4e0616d25322b6dd Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Fri, 3 Nov 2023 08:20:18 +0000 Subject: [PATCH 6/9] cmm: Add support for single quotes Signed-off-by: Nick Spinale --- .../crates/toml-normalize/src/cargo_manifest_policy.rs | 2 +- .../crates/toml-path-regex/src/grammar.pest | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs index 0f6477814..6381eb032 100644 --- a/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs @@ -12,7 +12,7 @@ pub fn cargo_manifest_policy() -> impl Policy { EasyPolicy { rules: vec![ TableRule { - path_regex: PathRegex::new(r#".{,1}|["target|profile"].{,2}|["bin"][-]."#), + path_regex: PathRegex::new(".{,1}|['target|profile'].{,2}|['bin'][-]."), never_inline: true, ..Default::default() }, diff --git a/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest b/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest index 771aeea2c..47de6b787 100644 --- a/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest +++ b/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest @@ -43,7 +43,11 @@ concat = { "" } dot = { "." } key_symbol = { - "[" ~ PUSH("\""+) ~ key_symbol_regex ~ POP ~ "]" + "[" ~ PUSH(key_symbol_quotes) ~ key_symbol_regex ~ POP ~ "]" +} + +key_symbol_quotes = _{ + "\""+ | "'"+ } key_symbol_regex = { From 79ac7791041355f3c83b136ddee1f28e9553c6e3 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Fri, 3 Nov 2023 08:23:18 +0000 Subject: [PATCH 7/9] cmm: Add support for whitespace Signed-off-by: Nick Spinale --- .../crates/toml-normalize/src/cargo_manifest_policy.rs | 10 ++++++++-- .../crates/toml-path-regex/src/grammar.pest | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs index 6381eb032..9ab835539 100644 --- a/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/cargo_manifest_policy.rs @@ -12,7 +12,13 @@ pub fn cargo_manifest_policy() -> impl Policy { EasyPolicy { rules: vec![ TableRule { - path_regex: PathRegex::new(".{,1}|['target|profile'].{,2}|['bin'][-]."), + path_regex: PathRegex::new( + r#" + .{,1} + | ['target|profile'] .{,2} + | ['bin'] [-] . + "#, + ), never_inline: true, ..Default::default() }, @@ -35,7 +41,7 @@ pub fn cargo_manifest_policy() -> impl Policy { ..Default::default() }, TableRule { - path_regex: PathRegex::new(r#"["package"]"#), + path_regex: PathRegex::new("['package']"), sort: TableRuleOrdering { front: vec!["name".to_owned(), "version".to_owned()], back: vec!["description".to_owned()], diff --git a/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest b/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest index 47de6b787..04c9cf21c 100644 --- a/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest +++ b/hacking/cargo-manifest-management/crates/toml-path-regex/src/grammar.pest @@ -79,3 +79,5 @@ index_symbol_range_side = { intlit = @{ "0" | ASCII_NONZERO_DIGIT ~ (ASCII_DIGIT)* } + +WHITESPACE = _{ " " | "\t" | "\r" | "\n" } From 674d6f4b604df25099a018f4b1000b027cee9c5f Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Fri, 3 Nov 2023 08:27:42 +0000 Subject: [PATCH 8/9] cmm: Add trailing commas to wrapped arrays Signed-off-by: Nick Spinale --- Cargo.toml | 2 +- crates/private/support/sel4-simple-task/runtime/Cargo.toml | 2 +- crates/sel4-async/network/Cargo.toml | 2 +- crates/sel4-capdl-initializer/with-embedded-spec/Cargo.toml | 2 +- .../crates/toml-normalize/src/format.rs | 5 ++--- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4303c0f82..a649a769f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -127,5 +127,5 @@ members = [ "crates/sel4/config/generic/types", "crates/sel4/config/macros", "crates/sel4/sys", - "crates/sel4/sys/wrappers" + "crates/sel4/sys/wrappers", ] diff --git a/crates/private/support/sel4-simple-task/runtime/Cargo.toml b/crates/private/support/sel4-simple-task/runtime/Cargo.toml index e7befce35..163b5e7e7 100644 --- a/crates/private/support/sel4-simple-task/runtime/Cargo.toml +++ b/crates/private/support/sel4-simple-task/runtime/Cargo.toml @@ -21,7 +21,7 @@ alloc = [ "sel4-backtrace/alloc", "sel4-backtrace-simple/alloc", "sel4-simple-task-threading/alloc", - "serde_json?/alloc" + "serde_json?/alloc", ] default = ["serde_json", "alloc"] serde_json = ["dep:serde_json"] diff --git a/crates/sel4-async/network/Cargo.toml b/crates/sel4-async/network/Cargo.toml index d65b33807..a144a3aff 100644 --- a/crates/sel4-async/network/Cargo.toml +++ b/crates/sel4-async/network/Cargo.toml @@ -31,5 +31,5 @@ features = [ "socket-dns", "socket-tcp", "async", - "alloc" + "alloc", ] diff --git a/crates/sel4-capdl-initializer/with-embedded-spec/Cargo.toml b/crates/sel4-capdl-initializer/with-embedded-spec/Cargo.toml index 27e9ac60e..0bde3a1b7 100644 --- a/crates/sel4-capdl-initializer/with-embedded-spec/Cargo.toml +++ b/crates/sel4-capdl-initializer/with-embedded-spec/Cargo.toml @@ -19,7 +19,7 @@ license = "BSD-2-Clause" [features] deflate = [ "sel4-capdl-initializer-with-embedded-spec-embedded-spec/deflate", - "sel4-capdl-initializer-with-embedded-spec-embedded-spec-validate/deflate" + "sel4-capdl-initializer-with-embedded-spec-embedded-spec-validate/deflate", ] [dependencies] diff --git a/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs index 82206816c..34c3760d1 100644 --- a/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs @@ -165,9 +165,8 @@ impl<'a, P: Policy> FormatterState<'a, P> { array.iter_mut().for_each(|e| { e.decor_mut().set_prefix("\n "); }); - array.iter_mut().last().map(|e| { - e.decor_mut().set_suffix("\n"); - }); + array.set_trailing_comma(true); + array.set_trailing("\n"); } } Ok(if let Some(array) = array { From c69d2d76213adc492a9bf1de0e444e5e6b594c3d Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Fri, 3 Nov 2023 08:56:41 +0000 Subject: [PATCH 9/9] cmm: Clean up code Signed-off-by: Nick Spinale --- .../crates/toml-normalize/src/format.rs | 18 +++++++++--------- .../crates/toml-path-regex/src/lib.rs | 2 +- .../src/path_segment_predicate.rs | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs b/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs index 34c3760d1..afc9427d1 100644 --- a/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs +++ b/hacking/cargo-manifest-management/crates/toml-normalize/src/format.rs @@ -12,7 +12,7 @@ use toml::value::{ }; use toml_edit::{Array, ArrayOfTables, Document, Formatted, InlineTable, Item, Key, Table, Value}; -use toml_path_regex::PathSegment; +use toml_path_regex::{Path, PathSegment}; pub trait Policy { fn max_width(&self) -> usize; @@ -36,7 +36,7 @@ impl Formatter

{ pub fn format(&self, table: &UnformattedTable) -> Result { let mut state = FormatterState { formatter: self, - current_path: vec![], + current_path: Path::new(), }; state.format_top_level(table) } @@ -44,7 +44,7 @@ impl Formatter

{ struct FormatterState<'a, P> { formatter: &'a Formatter

, - current_path: Vec, + current_path: Path, } #[derive(Debug, Clone)] @@ -54,16 +54,16 @@ pub enum Error { #[derive(Debug, Clone)] pub struct CannotInlineTableError { - path: Vec, + path: Path, } impl CannotInlineTableError { - fn new(path: Vec) -> Self { + fn new(path: Path) -> Self { Self { path } } pub fn path(&self) -> &[PathSegment] { - &self.path + self.path.as_slice() } } @@ -95,7 +95,7 @@ impl<'a, P: Policy> FormatterState<'a, P> { fn format_table_to_inline_table(&mut self, v: &UnformattedTable) -> Result { if self.policy().never_inline_table(self.current_path()) { - return Err(CannotInlineTableError::new(self.current_path().to_vec()).into()); + return Err(CannotInlineTableError::new(self.current_path.clone()).into()); } let mut table = InlineTable::new(); for (k, x) in v.iter() { @@ -214,11 +214,11 @@ impl<'a, P: Policy> FormatterState<'a, P> { } fn current_path(&self) -> &[PathSegment] { - &self.current_path + self.current_path.as_slice() } fn current_key(&self) -> Option<&str> { - self.current_path.last()?.as_key() + self.current_path().last()?.as_key() } fn push(&mut self, seg: PathSegment) { self.current_path.push(seg); diff --git a/hacking/cargo-manifest-management/crates/toml-path-regex/src/lib.rs b/hacking/cargo-manifest-management/crates/toml-path-regex/src/lib.rs index d7b599d33..a6774c444 100644 --- a/hacking/cargo-manifest-management/crates/toml-path-regex/src/lib.rs +++ b/hacking/cargo-manifest-management/crates/toml-path-regex/src/lib.rs @@ -119,7 +119,7 @@ fn generic_regex_from_expr(expr: &Expr) -> GenericRegex { } Expr::Dot => GenericRegex::symbol(PathSegmentPredicate::any()), Expr::KeySymbol(key_regex) => { - GenericRegex::symbol(PathSegmentPredicate::from_key_regex(key_regex)) + GenericRegex::symbol(PathSegmentPredicate::from_key_regex(key_regex).unwrap()) } Expr::IndexSymbol(index_ranges) => { GenericRegex::symbol(PathSegmentPredicate::from_index_ranges(index_ranges)) diff --git a/hacking/cargo-manifest-management/crates/toml-path-regex/src/path_segment_predicate.rs b/hacking/cargo-manifest-management/crates/toml-path-regex/src/path_segment_predicate.rs index a02861931..7b5057530 100644 --- a/hacking/cargo-manifest-management/crates/toml-path-regex/src/path_segment_predicate.rs +++ b/hacking/cargo-manifest-management/crates/toml-path-regex/src/path_segment_predicate.rs @@ -5,7 +5,7 @@ // use rangemap::inclusive_set::RangeInclusiveSet; -use regex::Regex; +use regex::{Error as RegexError, Regex}; use super::generic_regex::Predicate; use super::parse::IndexRange; @@ -30,10 +30,10 @@ impl PathSegmentPredicate { Self::new(Inner::Any) } - pub fn from_key_regex(re: &str) -> Self { + pub fn from_key_regex(re: &str) -> Result { let anchored_re = format!("^{re}$"); // TODO is this sound? - let compiled = Regex::new(&anchored_re).unwrap(); - Self::new(Inner::Key(compiled)) + let compiled = Regex::new(&anchored_re)?; + Ok(Self::new(Inner::Key(compiled))) } pub fn from_index_ranges(ranges: &[IndexRange]) -> Self {