use core::fmt; use std::{path::PathBuf, process::Command}; use anyhow::{Context, Result}; use clap::Parser; #[derive(Parser)] struct Cli { /// The file to pull the patch to rollup from. patch_file: PathBuf, } struct Diff { files: Vec, } struct FileDiff { from: PathBuf, to: PathBuf, diff: String, index: String, } impl fmt::Display for FileDiff { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!( f, "diff --git a/{} b/{}", self.from.display(), self.to.display() )?; writeln!(f, "--- a/{}", self.from.display())?; writeln!(f, "+++ b/{}", self.to.display())?; writeln!(f, "index {}", self.index)?; writeln!(f, "{}", self.diff)?; Ok(()) } } macro_rules! take { ($line:expr, $prefix:literal) => { $line.strip_prefix($prefix).unwrap().trim() }; } fn main() -> Result<()> { let args = Cli::parse(); let data = Command::new("filterdiff") .arg(&args.patch_file) .output() .context("Failed to run `filterdiff` for patch analysis")?; let stdout = String::from_utf8(data.stdout).unwrap(); let mut diff = Diff { files: vec![] }; let mut file_diff_from = None; let mut file_diff_to = None; let mut file_diff_diff: Option = None; let mut file_diff_index: Option = None; for (idx, line) in stdout.lines().enumerate() { eprintln!("{}", line); if line.starts_with("---") { file_diff_from = Some(PathBuf::from(take!(line, "--- a/"))); } else if line.starts_with("+++") { file_diff_to = Some(PathBuf::from(take!(line, "+++ b/"))); } else if line.starts_with("index") { file_diff_index = Some(take!(line, "index").to_owned()); } else if line.starts_with("diff --git") { if idx != 0 { diff.files.push(FileDiff { from: file_diff_from.take().unwrap(), to: file_diff_to.take().unwrap(), diff: file_diff_diff.take().unwrap(), index: file_diff_index.take().unwrap(), }); } } else { match file_diff_diff.as_mut() { Some(str) => { str.push_str(line); str.push('\n'); } None => { let mut base = line.to_owned(); base.push('\n'); file_diff_diff = Some(base); } } } } diff.files.push(FileDiff { from: file_diff_from.unwrap(), to: file_diff_to.unwrap(), diff: file_diff_diff.unwrap(), index: file_diff_index.unwrap(), }); for file in diff.files { eprintln!("{}", file) } Ok(()) }