diff --git a/Cargo.lock b/Cargo.lock index 1ac7f76..29ffb86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.6.13" @@ -126,6 +135,7 @@ dependencies = [ name = "gerrit-filter-branch" version = "0.1.0" dependencies = [ + "aho-corasick", "clap", "git2", ] @@ -222,6 +232,12 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + [[package]] name = "once_cell" version = "1.19.0" diff --git a/Cargo.toml b/Cargo.toml index 0244b84..9afbfe8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +aho-corasick = "1.1.3" clap = { version = "4.5.4", features = ["derive"] } git2 = "0.18.3" diff --git a/src/main.rs b/src/main.rs index 713048f..d621004 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,9 @@ -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + io::{stdin, stdout}, +}; +use aho_corasick::AhoCorasick; use clap::Parser; use git2::{Oid, Repository, Signature, Time}; @@ -25,6 +29,10 @@ struct Args { #[arg(short, long)] /// A timestamp (in seconds since the epoch) at which point commits should be considered unchanged, even if it or its parents have aforementioned email. cutoff: String, + + #[arg(short, long)] + /// If the list of rewritten OIDs should be rewritten in the stdin stream, rather than the Git repo. + rewrite_stdin: bool, } struct State { @@ -232,33 +240,51 @@ fn main() { let refoid = state.repo.find_reference(&gref).unwrap().target().unwrap(); let newoid = state.rewrite(refoid); - if refoid != newoid { - println!("{:?}: {:?} -> {:?}", gref, refoid, newoid); - state - .repo - .reference(&gref, newoid, true, "filter-branch rewrite") - .unwrap(); - } else { - println!("{:?}: {:?} (unchanged)", gref, refoid); + + if !state.args.rewrite_stdin { + if refoid != newoid { + println!("{:?}: {:?} -> {:?}", gref, refoid, newoid); + state + .repo + .reference(&gref, newoid, true, "filter-branch rewrite") + .unwrap(); + } else { + println!("{:?}: {:?} (unchanged)", gref, refoid); + } } } - for gref in &refs { - if !gref.ends_with("/meta") { - continue; - } + if state.args.rewrite_stdin { + let data: Vec<_> = state + .rewritten + .iter() + .map(|f| (f.0.to_string(), f.1.to_string())) + .collect(); - let refoid = state.repo.find_reference(&gref).unwrap().target().unwrap(); - let newoid = state.rewrite_meta(refoid); + let to_replace: Vec<&[u8]> = data.iter().map(|f| f.1.as_bytes()).collect(); + let matcher = AhoCorasick::new(data.iter().map(|f| f.0.as_bytes())).unwrap(); - if refoid != newoid { - println!("{:?}: {:?} -> {:?}", gref, refoid, newoid); - state - .repo - .reference(&gref, newoid, true, "filter-branch rewrite") - .unwrap(); - } else { - println!("{:?}: {:?} (unchanged)", gref, refoid); + matcher + .try_stream_replace_all(stdin().lock(), stdout().lock(), &to_replace[..]) + .unwrap(); + } else { + for gref in &refs { + if !gref.ends_with("/meta") { + continue; + } + + let refoid = state.repo.find_reference(&gref).unwrap().target().unwrap(); + let newoid = state.rewrite_meta(refoid); + + if refoid != newoid { + println!("{:?}: {:?} -> {:?}", gref, refoid, newoid); + state + .repo + .reference(&gref, newoid, true, "filter-branch rewrite") + .unwrap(); + } else { + println!("{:?}: {:?} (unchanged)", gref, refoid); + } } } }