Skip to content

Commit

Permalink
Introduce commit message filter (#1351)
Browse files Browse the repository at this point in the history
This changes the `:squash()` filter to take an additional
filter per commit instead of special handling for the commit
message.

Change: message-filter
  • Loading branch information
christian-schilling authored Aug 8, 2024
1 parent a4188e5 commit 4ef5d2c
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 83 deletions.
1 change: 1 addition & 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 josh-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pest_derive = "2.7.10"
rayon = "1.10.0"
regex = { workspace = true }
rs_tracing = { workspace = true }
strfmt = "0.2.4"
serde = { workspace = true }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
Expand Down
6 changes: 4 additions & 2 deletions josh-core/src/filter/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ char = {

filter_spec = { (
filter_group
| filter_message
| filter_rev
| filter_join
| filter_replace
Expand All @@ -39,6 +40,7 @@ filter_nop = { CMD_START ~ "/" }
filter_presub = { CMD_START ~ ":" ~ argument }
filter = { CMD_START ~ cmd ~ "=" ~ (argument ~ (";" ~ argument)*)? }
filter_noarg = { CMD_START ~ cmd }
filter_message = { CMD_START ~ string }

filter_rev = {
CMD_START ~ "rev" ~ "("
Expand Down Expand Up @@ -71,8 +73,8 @@ filter_replace = {
filter_squash = {
CMD_START ~ "squash" ~ "("
~ NEWLINE*
~ (rev ~ ":" ~ string)?
~ (CMD_SEP+ ~ (rev ~ ":" ~ string))*
~ (rev ~ filter_spec)?
~ (CMD_SEP+ ~ (rev ~ filter_spec))*
~ NEWLINE*
~ ")"
}
Expand Down
135 changes: 96 additions & 39 deletions josh-core/src/filter/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use history::RewriteData;
use pest::Parser;
use std::path::Path;
mod opt;
Expand Down Expand Up @@ -65,7 +66,11 @@ pub fn empty() -> Filter {
to_filter(Op::Empty)
}

pub fn squash(ids: Option<&[(git2::Oid, String)]>) -> Filter {
pub fn message(m: &str) -> Filter {
to_filter(Op::Message(m.to_string()))
}

pub fn squash(ids: Option<&[(git2::Oid, Filter)]>) -> Filter {
if let Some(ids) = ids {
to_filter(Op::Squash(Some(
ids.iter()
Expand Down Expand Up @@ -130,7 +135,7 @@ enum Op {

// We use BTreeMap rather than HashMap to guarantee deterministic results when
// converting to Filter
Squash(Option<std::collections::BTreeMap<LazyRef, String>>),
Squash(Option<std::collections::BTreeMap<LazyRef, Filter>>),
Author(String, String),

// We use BTreeMap rather than HashMap to guarantee deterministic results when
Expand All @@ -151,6 +156,7 @@ enum Op {
Workspace(std::path::PathBuf),

Glob(String),
Message(String),

Compose(Vec<Filter>),
Chain(Filter, Filter),
Expand Down Expand Up @@ -235,14 +241,7 @@ fn pretty2(op: &Op, indent: usize, compose: bool) -> String {
Op::Squash(Some(ids)) => {
let mut v = ids
.iter()
.map(|(oid, msg)| {
format!(
"{}{}:{}",
" ".repeat(indent),
&oid.to_string(),
parse::quote(msg)
)
})
.map(|(oid, f)| format!("{}{}{}", " ".repeat(indent), &oid.to_string(), spec(*f)))
.collect::<Vec<_>>();
v.sort();
format!(":squash(\n{}\n)", v.join("\n"))
Expand Down Expand Up @@ -479,7 +478,7 @@ fn spec2(op: &Op) -> String {
Op::Squash(Some(ids)) => {
let mut v = ids
.iter()
.map(|(oid, msg)| format!("{}:{}", oid.to_string(), parse::quote(msg)))
.map(|(oid, f)| format!("{}{}", oid.to_string(), spec(*f)))
.collect::<Vec<_>>();
v.sort();
format!(":squash({})", v.join(","))
Expand All @@ -493,6 +492,9 @@ fn spec2(op: &Op) -> String {
Op::Author(author, email) => {
format!(":author={};{}", parse::quote(author), parse::quote(email))
}
Op::Message(m) => {
format!(":{}", parse::quote(m))
}
}
}

Expand Down Expand Up @@ -635,9 +637,12 @@ fn apply_to_commit2(
repo,
commit,
&[],
&commit.tree()?,
None,
None,
RewriteData {
tree: commit.tree()?,
author: None,
committer: None,
message: None,
},
true,
))
.transpose()
Expand Down Expand Up @@ -679,7 +684,7 @@ 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) {
let rewrite_data = match &to_op(filter) {
Op::Rev(filters) => {
let nf = *filters
.get(&LazyRef::Resolved(git2::Oid::zero()))
Expand Down Expand Up @@ -721,11 +726,41 @@ fn apply_to_commit2(
}
}

apply(transaction, nf, commit.tree()?)?
RewriteData {
tree: apply(transaction, nf, commit.tree()?)?,
message: None,
author: None,
committer: None,
}
}
Op::Squash(Some(ids)) => {
if ids.get(&LazyRef::Resolved(commit.id())).is_some() {
commit.tree()?
if let Some(sq) = ids.get(&LazyRef::Resolved(commit.id())) {
let oid = if let Some(oid) =
apply_to_commit2(&Op::Chain(filter::squash(None), *sq), commit, transaction)?
{
oid
} else {
return Ok(None);
};

let rc = transaction.repo().find_commit(oid)?;
let author = rc
.author()
.name()
.map(|x| x.to_owned())
.zip(rc.author().email().map(|x| x.to_owned()));
let committer = rc
.committer()
.name()
.map(|x| x.to_owned())
.zip(rc.committer().email().map(|x| x.to_owned()));
RewriteData {
tree: rc.tree()?,
message: rc.message_raw().map(|x| x.to_owned()),
author: author,
committer: committer,
}
//commit.tree()?
} else {
if let Some(parent) = commit.parents().next() {
return Ok(
Expand Down Expand Up @@ -762,11 +797,14 @@ fn apply_to_commit2(
return Some(history::create_filtered_commit(
commit,
vec![parent],
commit.tree()?,
RewriteData {
tree: commit.tree()?,
author: None,
committer: None,
message: None,
},
transaction,
filter,
None,
None,
))
.transpose();
}
Expand Down Expand Up @@ -847,11 +885,14 @@ fn apply_to_commit2(
return Some(history::create_filtered_commit(
commit,
filtered_parent_ids,
filtered_tree,
RewriteData {
tree: filtered_tree,
author: None,
committer: None,
message: None,
},
transaction,
filter,
None,
None,
))
.transpose();
}
Expand All @@ -874,9 +915,36 @@ fn apply_to_commit2(
filtered_tree = tree::overlay(transaction, filtered_tree, t)?;
}

repo.find_tree(filtered_tree)?
let filtered_tree = repo.find_tree(filtered_tree)?;
RewriteData {
tree: filtered_tree,
author: None,
committer: None,
message: None,
}
}
_ => apply(transaction, filter, commit.tree()?)?,
Op::Author(author, email) => RewriteData {
tree: commit.tree()?,
author: Some((author.clone(), email.clone())),
committer: Some((author.clone(), email.clone())),
message: None,
},
Op::Message(m) => RewriteData {
tree: commit.tree()?,
author: None,
committer: None,
// Pass the message through `strfmt` to enable future extensions
message: Some(strfmt::strfmt(
m,
&std::collections::HashMap::<String, &dyn strfmt::DisplayStr>::new(),
)?),
},
_ => RewriteData {
tree: apply(transaction, filter, commit.tree()?)?,
message: None,
author: None,
committer: None,
},
};

let filtered_parent_ids = {
Expand All @@ -889,24 +957,12 @@ fn apply_to_commit2(

let filtered_parent_ids = some_or!(filtered_parent_ids, { return Ok(None) });

let author = match to_op(filter) {
Op::Author(author, email) => Some((author, email)),
_ => None,
};

let message = match to_op(filter) {
Op::Squash(Some(ids)) => ids.get(&LazyRef::Resolved(commit.id())).cloned(),
_ => None,
};

Some(history::create_filtered_commit(
commit,
filtered_parent_ids,
filtered_tree,
rewrite_data,
transaction,
filter,
author,
message,
))
.transpose()
}
Expand All @@ -931,6 +987,7 @@ fn apply2<'a>(
Op::Empty => return Ok(tree::empty(repo)),
Op::Fold => Ok(tree),
Op::Squash(None) => Ok(tree),
Op::Message(_) => Ok(tree),
Op::Author(_, _) => Ok(tree),
Op::Squash(Some(_)) => Err(josh_error("not applicable to tree")),
Op::Linear => Ok(tree),
Expand Down
8 changes: 5 additions & 3 deletions josh-core/src/filter/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ fn parse_item(pair: pest::iterators::Pair<Rule>) -> JoshResult<Op> {
let mut inner = pair.into_inner();
make_op(&[inner.next().unwrap().as_str()])
}
Rule::filter_message => {
let mut inner = pair.into_inner();
Ok(Op::Message(unquote(inner.next().unwrap().as_str())))
}
Rule::filter_group => {
let v: Vec<_> = pair.into_inner().map(|x| unquote(x.as_str())).collect();

Expand Down Expand Up @@ -137,9 +141,7 @@ fn parse_item(pair: pest::iterators::Pair<Rule>) -> JoshResult<Op> {
let ids = pair
.into_inner()
.tuples()
.map(|(oid, message)| {
Ok((LazyRef::parse(oid.as_str())?, unquote(message.as_str())))
})
.map(|(oid, filter)| Ok((LazyRef::parse(oid.as_str())?, parse(filter.as_str())?)))
.collect::<JoshResult<_>>()?;

Ok(Op::Squash(Some(ids)))
Expand Down
Loading

0 comments on commit 4ef5d2c

Please sign in to comment.