diff --git a/CHANGELOG-rust.md b/CHANGELOG-rust.md index e71107b..ebca234 100644 --- a/CHANGELOG-rust.md +++ b/CHANGELOG-rust.md @@ -5,6 +5,8 @@ This changelog tracks the Rust `svdtools` project. See ## [Unreleased] +* Add `expand-patch` tool to show full patch rule with all includes + ## [v0.3.14] 2024-04-04 * If there is no path to interpolate, show unmodified `description`. diff --git a/src/cli.rs b/src/cli.rs index e39ec3c..88f3e94 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,6 @@ -use anyhow::Result; +use anyhow::{Ok, Result}; use clap::Parser; -use std::path::PathBuf; +use std::{fs::File, io::Write, path::PathBuf}; use svdtools::{ convert::convert_cli, @@ -41,6 +41,13 @@ enum Command { #[clap(long)] enum_derive: Option, }, + ExpandPatch { + /// Path to input YAML file + yaml_file: PathBuf, + + /// Path to output file. By default it prints to stdout + out_path: Option, + }, /// Generate Make dependency file listing dependencies for a YAML file. Makedeps { /// Input yaml file @@ -148,6 +155,18 @@ impl Command { &config, )? } + Self::ExpandPatch { + yaml_file, + out_path, + } => { + let yml = patch_cli::expand_patch(yaml_file)?; + if let Some(out_path) = out_path.as_ref() { + let mut f = File::create(out_path)?; + f.write_all(yml.as_bytes())?; + } else { + println!("{yml}"); + } + } Self::Makedeps { yaml_file, deps_file, diff --git a/src/patch/mod.rs b/src/patch/mod.rs index 3056b23..b4a3a4d 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -66,19 +66,29 @@ impl Default for Config { } } +fn load_patch(yaml_file: &Path) -> Result { + // Load the specified YAML root file + let f = File::open(yaml_file)?; + let mut contents = String::new(); + (&f).read_to_string(&mut contents)?; + let docs = YamlLoader::load_from_str(&contents)?; + let mut doc = docs.into_iter().next().unwrap(); // select the first document + let root = doc.hash_mut()?; + root.insert("_path".to_yaml(), yaml_file.to_str().unwrap().to_yaml()); + + // Load all included YAML files + yaml_includes(root)?; + Ok(doc) +} + pub fn process_file( yaml_file: &Path, out_path: Option<&Path>, format_config: Option<&Path>, config: &Config, ) -> Result<()> { - // Load the specified YAML root file - let f = File::open(yaml_file)?; - let mut contents = String::new(); - (&f).read_to_string(&mut contents)?; - let mut docs = YamlLoader::load_from_str(&contents)?; - let root = docs[0].hash_mut()?; // select the first document - root.insert("_path".to_yaml(), yaml_file.to_str().unwrap().to_yaml()); + let mut doc = load_patch(yaml_file)?; + let root = doc.hash_mut()?; // Load the specified SVD file let svdpath = abspath( @@ -102,15 +112,12 @@ pub fn process_file( parser_config.validate_level = ValidateLevel::Disabled; let mut svd = svd_parser::parse_with_config(&contents, &parser_config)?; - // Load all included YAML files - yaml_includes(root)?; - // Process device svd.process(root, config).with_context(|| { let name = &svd.name; let mut out_str = String::new(); let mut emitter = yaml_rust::YamlEmitter::new(&mut out_str); - emitter.dump(&Yaml::Hash(root.clone())).unwrap(); + emitter.dump(&doc).unwrap(); if config.show_patch_on_error { format!("Processing device `{name}`. Patches looks like:\n{out_str}") } else { @@ -189,6 +196,7 @@ pub fn yaml_includes(parent: &mut Hash) -> Result> { included.extend(yaml_includes(child)?); update_dict(parent, child)?; } + parent.remove(&"_include".to_yaml()); Ok(included) } diff --git a/src/patch/patch_cli.rs b/src/patch/patch_cli.rs index aa206d5..a6f3d0f 100644 --- a/src/patch/patch_cli.rs +++ b/src/patch/patch_cli.rs @@ -11,3 +11,11 @@ pub fn patch( super::process_file(yaml_file, out_path, format_config, config)?; Ok(()) } + +pub fn expand_patch(yaml_file: &Path) -> Result { + let doc = super::load_patch(yaml_file)?; + let mut out_str = String::new(); + let mut emitter = yaml_rust::YamlEmitter::new(&mut out_str); + emitter.dump(&doc).unwrap(); + Ok(out_str) +}