Skip to content

Commit

Permalink
Add :rev(...) filter
Browse files Browse the repository at this point in the history
Change: start-filter
  • Loading branch information
christian-schilling committed Nov 14, 2022
1 parent e084d74 commit e48826e
Show file tree
Hide file tree
Showing 10 changed files with 418 additions and 5 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ handlebars = "4.3.5"
hex = "0.4.3"
hyper-reverse-proxy = "0.5.1"
indoc = "1.0.7"
itertools = "0.9"
juniper = "0.15.10"
lazy_static = "1.4.0"
log = "0.4.17"
Expand Down
7 changes: 7 additions & 0 deletions docs/src/reference/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ These filter do not modify git trees, but instead only operate on the commit gra
Produce a filtered history that does not contain any merge commits. This is done by
simply dropping all parents except the first on every commit.

### Filter specific part of the history **:at_commit=<sha>[:filter]**
Produce a history where the commit specified by `<sha>` is replaced by the result of applying
`:filter` to it.
This means also all parents of this specific commit appear filtered with `:filter` and all
descendent commits will be left unchanged. However all commits hashes will still be different
due to the filtered parents.

Filter order matters
--------------------

Expand Down
10 changes: 10 additions & 0 deletions src/filter/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ char = {

filter_spec = { (
filter_group
| filter_rev
| filter_presub
| filter_subdir
| filter_nop
Expand All @@ -32,6 +33,15 @@ filter_presub = { CMD_START ~ ":" ~ argument }
filter = { CMD_START ~ cmd ~ "=" ~ (argument ~ (";" ~ argument)*)? }
filter_noarg = { CMD_START ~ cmd }

filter_rev = {
CMD_START ~ "rev" ~ "("
~ NEWLINE*
~ (argument ~ filter_spec)?
~ (CMD_SEP+ ~ (argument ~ filter_spec))*
~ NEWLINE*
~ ")"
}

argument = { string | PATH }

cmd = { ALNUM+ }
Expand Down
50 changes: 46 additions & 4 deletions src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ enum Op {
Fold,
Paths,
Squash(Option<std::collections::HashMap<git2::Oid, (String, String, String)>>),
Rev(std::collections::HashMap<git2::Oid, Filter>),
Linear,

RegexReplace(regex::Regex, String),
Expand Down Expand Up @@ -194,6 +195,13 @@ fn nesting2(op: &Op) -> usize {
Op::Workspace(_) => usize::MAX,
Op::Chain(a, b) => 1 + nesting(*a).max(nesting(*b)),
Op::Subtract(a, b) => 1 + nesting(*a).max(nesting(*b)),
Op::Rev(filters) => {
1 + filters
.values()
.map(|filter| nesting(*filter))
.max()
.unwrap_or(0)
}
_ => 0,
}
}
Expand Down Expand Up @@ -223,12 +231,20 @@ fn spec2(op: &Op) -> String {
Op::Exclude(b) => {
format!(":exclude[{}]", spec(*b))
}
Op::Rev(filters) => {
let mut v = filters
.iter()
.map(|(k, v)| format!("{}{}", k, spec(*v)))
.collect::<Vec<_>>();
v.sort();
format!(":rev({})", v.join(","))
}
Op::Workspace(path) => {
format!(":workspace={}", parse::quote(&path.to_string_lossy()))
}
Op::RegexReplace(regex, replacement) => {
format!(
":replace={},{}",
":replace={};{}",
parse::quote(&regex.to_string()),
parse::quote(&replacement)
)
Expand Down Expand Up @@ -384,6 +400,27 @@ fn apply_to_commit2(
rs_tracing::trace_scoped!("apply_to_commit", "spec": spec(filter), "commit": commit.id().to_string());

let filtered_tree = match &to_op(filter) {
Op::Rev(filters) => {
let nf = *filters
.get(&git2::Oid::zero())
.unwrap_or(&to_filter(Op::Nop));

for (id, startfilter) in filters {
if *id == commit.id() {
let mut f2 = filters.clone();
f2.remove(id);
f2.insert(git2::Oid::zero(), *startfilter);
if let Some(start) = apply_to_commit2(&Op::Rev(f2), &commit, transaction)? {
transaction.insert(filter, commit.id(), start, true);
return Ok(Some(start));
} else {
return Ok(None);
}
}
}

apply(transaction, nf, commit.tree()?)?
}
Op::Squash(Some(ids)) => {
if let Some(_) = ids.get(&commit.id()) {
commit.tree()?
Expand Down Expand Up @@ -619,7 +656,7 @@ fn apply2<'a>(
Op::Squash(None) => Ok(tree),
Op::Squash(Some(_)) => Err(josh_error("not applicable to tree")),
Op::Linear => Ok(tree),

Op::Rev(_) => Err(josh_error("not applicable to tree")),
Op::RegexReplace(regex, replacement) => {
tree::regex_replace(tree.id(), &regex, &replacement, transaction)
}
Expand Down Expand Up @@ -712,7 +749,11 @@ pub fn unapply<'a>(
parent_tree: git2::Tree<'a>,
) -> JoshResult<git2::Tree<'a>> {
if let Ok(inverted) = invert(filter) {
let matching = apply(transaction, chain(filter, inverted), parent_tree.clone())?;
let matching = apply(
transaction,
chain(invert(inverted)?, inverted),
parent_tree.clone(),
)?;
let stripped = tree::subtract(transaction, parent_tree.id(), matching.id())?;
let new_tree = apply(transaction, inverted, tree)?;

Expand All @@ -733,7 +774,8 @@ pub fn unapply<'a>(
}

if let Op::Chain(a, b) = to_op(filter) {
let p = apply(transaction, a, parent_tree.clone())?;
let i = if let Ok(i) = invert(a) { invert(i)? } else { a };
let p = apply(transaction, i, parent_tree.clone())?;
return unapply(
transaction,
a,
Expand Down
2 changes: 2 additions & 0 deletions src/filter/opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ fn step(filter: Filter) -> Filter {
Op::Prefix(path)
}
}
//Op::Rev(id, filter) => Op::Rev(id, step(filter)),
Op::Compose(filters) if filters.is_empty() => Op::Empty,
Op::Compose(filters) if filters.len() == 1 => to_op(filters[0]),
Op::Compose(mut filters) => {
Expand Down Expand Up @@ -426,6 +427,7 @@ pub fn invert(filter: Filter) -> JoshResult<Filter> {
Op::File(path) => Some(Op::File(path)),
Op::Prefix(path) => Some(Op::Subdir(path)),
Op::Glob(pattern) => Some(Op::Glob(pattern)),
Op::Rev(_) => Some(Op::Nop),
_ => None,
};

Expand Down
12 changes: 12 additions & 0 deletions src/filter/parse.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use indoc::{formatdoc, indoc};
use itertools::Itertools;

fn make_op(args: &[&str]) -> JoshResult<Op> {
match args {
Expand Down Expand Up @@ -103,6 +104,17 @@ fn parse_item(pair: pest::iterators::Pair<Rule>) -> JoshResult<Op> {
_ => Err(josh_error("parse_item: no match {:?}")),
}
}
Rule::filter_rev => {
let v: Vec<_> = pair.into_inner().map(|x| unquote(x.as_str())).collect();

let hm = v
.iter()
.tuples()
.map(|(oid, filter)| Ok((git2::Oid::from_str(oid)?, parse(filter)?)))
.collect::<JoshResult<_>>()?;

Ok(Op::Rev(hm))
}
_ => Err(josh_error("parse_item: no match")),
}
}
Expand Down
Loading

0 comments on commit e48826e

Please sign in to comment.