Skip to content

Commit 174e49a

Browse files
Introduce commit message filter
This changes the `:squash()` filter to take an additional filter per commit instead of special handling for the commit message. Change: message-filter
1 parent a4188e5 commit 174e49a

File tree

11 files changed

+171
-83
lines changed

11 files changed

+171
-83
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

josh-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pest_derive = "2.7.10"
2626
rayon = "1.10.0"
2727
regex = { workspace = true }
2828
rs_tracing = { workspace = true }
29+
strfmt = "0.2.4"
2930
serde = { workspace = true }
3031
serde_json = { workspace = true }
3132
serde_yaml = { workspace = true }

josh-core/src/filter/grammar.pest

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ char = {
2222

2323
filter_spec = { (
2424
filter_group
25+
| filter_message
2526
| filter_rev
2627
| filter_join
2728
| filter_replace
@@ -39,6 +40,7 @@ filter_nop = { CMD_START ~ "/" }
3940
filter_presub = { CMD_START ~ ":" ~ argument }
4041
filter = { CMD_START ~ cmd ~ "=" ~ (argument ~ (";" ~ argument)*)? }
4142
filter_noarg = { CMD_START ~ cmd }
43+
filter_message = { CMD_START ~ string }
4244

4345
filter_rev = {
4446
CMD_START ~ "rev" ~ "("
@@ -71,8 +73,8 @@ filter_replace = {
7173
filter_squash = {
7274
CMD_START ~ "squash" ~ "("
7375
~ NEWLINE*
74-
~ (rev ~ ":" ~ string)?
75-
~ (CMD_SEP+ ~ (rev ~ ":" ~ string))*
76+
~ (rev ~ filter_spec)?
77+
~ (CMD_SEP+ ~ (rev ~ filter_spec))*
7678
~ NEWLINE*
7779
~ ")"
7880
}

josh-core/src/filter/mod.rs

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::*;
2+
use history::RewriteData;
23
use pest::Parser;
34
use std::path::Path;
45
mod opt;
@@ -65,7 +66,11 @@ pub fn empty() -> Filter {
6566
to_filter(Op::Empty)
6667
}
6768

68-
pub fn squash(ids: Option<&[(git2::Oid, String)]>) -> Filter {
69+
pub fn message(m: &str) -> Filter {
70+
to_filter(Op::Message(m.to_string()))
71+
}
72+
73+
pub fn squash(ids: Option<&[(git2::Oid, Filter)]>) -> Filter {
6974
if let Some(ids) = ids {
7075
to_filter(Op::Squash(Some(
7176
ids.iter()
@@ -130,7 +135,7 @@ enum Op {
130135

131136
// We use BTreeMap rather than HashMap to guarantee deterministic results when
132137
// converting to Filter
133-
Squash(Option<std::collections::BTreeMap<LazyRef, String>>),
138+
Squash(Option<std::collections::BTreeMap<LazyRef, Filter>>),
134139
Author(String, String),
135140

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

153158
Glob(String),
159+
Message(String),
154160

155161
Compose(Vec<Filter>),
156162
Chain(Filter, Filter),
@@ -235,14 +241,7 @@ fn pretty2(op: &Op, indent: usize, compose: bool) -> String {
235241
Op::Squash(Some(ids)) => {
236242
let mut v = ids
237243
.iter()
238-
.map(|(oid, msg)| {
239-
format!(
240-
"{}{}:{}",
241-
" ".repeat(indent),
242-
&oid.to_string(),
243-
parse::quote(msg)
244-
)
245-
})
244+
.map(|(oid, f)| format!("{}{}{}", " ".repeat(indent), &oid.to_string(), spec(*f)))
246245
.collect::<Vec<_>>();
247246
v.sort();
248247
format!(":squash(\n{}\n)", v.join("\n"))
@@ -479,7 +478,7 @@ fn spec2(op: &Op) -> String {
479478
Op::Squash(Some(ids)) => {
480479
let mut v = ids
481480
.iter()
482-
.map(|(oid, msg)| format!("{}:{}", oid.to_string(), parse::quote(msg)))
481+
.map(|(oid, f)| format!("{}{}", oid.to_string(), spec(*f)))
483482
.collect::<Vec<_>>();
484483
v.sort();
485484
format!(":squash({})", v.join(","))
@@ -493,6 +492,9 @@ fn spec2(op: &Op) -> String {
493492
Op::Author(author, email) => {
494493
format!(":author={};{}", parse::quote(author), parse::quote(email))
495494
}
495+
Op::Message(m) => {
496+
format!(":{}", parse::quote(m))
497+
}
496498
}
497499
}
498500

@@ -635,9 +637,12 @@ fn apply_to_commit2(
635637
repo,
636638
commit,
637639
&[],
638-
&commit.tree()?,
639-
None,
640-
None,
640+
RewriteData {
641+
tree: commit.tree()?,
642+
author: None,
643+
committer: None,
644+
message: None,
645+
},
641646
true,
642647
))
643648
.transpose()
@@ -679,7 +684,7 @@ fn apply_to_commit2(
679684

680685
rs_tracing::trace_scoped!("apply_to_commit", "spec": spec(filter), "commit": commit.id().to_string());
681686

682-
let filtered_tree = match &to_op(filter) {
687+
let rewrite_data = match &to_op(filter) {
683688
Op::Rev(filters) => {
684689
let nf = *filters
685690
.get(&LazyRef::Resolved(git2::Oid::zero()))
@@ -721,11 +726,41 @@ fn apply_to_commit2(
721726
}
722727
}
723728

724-
apply(transaction, nf, commit.tree()?)?
729+
RewriteData {
730+
tree: apply(transaction, nf, commit.tree()?)?,
731+
message: None,
732+
author: None,
733+
committer: None,
734+
}
725735
}
726736
Op::Squash(Some(ids)) => {
727-
if ids.get(&LazyRef::Resolved(commit.id())).is_some() {
728-
commit.tree()?
737+
if let Some(sq) = ids.get(&LazyRef::Resolved(commit.id())) {
738+
let oid = if let Some(oid) =
739+
apply_to_commit2(&Op::Chain(filter::squash(None), *sq), commit, transaction)?
740+
{
741+
oid
742+
} else {
743+
return Ok(None);
744+
};
745+
746+
let rc = transaction.repo().find_commit(oid)?;
747+
let author = rc
748+
.author()
749+
.name()
750+
.map(|x| x.to_owned())
751+
.zip(rc.author().email().map(|x| x.to_owned()));
752+
let committer = rc
753+
.committer()
754+
.name()
755+
.map(|x| x.to_owned())
756+
.zip(rc.committer().email().map(|x| x.to_owned()));
757+
RewriteData {
758+
tree: rc.tree()?,
759+
message: rc.message_raw().map(|x| x.to_owned()),
760+
author: author,
761+
committer: committer,
762+
}
763+
//commit.tree()?
729764
} else {
730765
if let Some(parent) = commit.parents().next() {
731766
return Ok(
@@ -762,11 +797,14 @@ fn apply_to_commit2(
762797
return Some(history::create_filtered_commit(
763798
commit,
764799
vec![parent],
765-
commit.tree()?,
800+
RewriteData {
801+
tree: commit.tree()?,
802+
author: None,
803+
committer: None,
804+
message: None,
805+
},
766806
transaction,
767807
filter,
768-
None,
769-
None,
770808
))
771809
.transpose();
772810
}
@@ -847,11 +885,14 @@ fn apply_to_commit2(
847885
return Some(history::create_filtered_commit(
848886
commit,
849887
filtered_parent_ids,
850-
filtered_tree,
888+
RewriteData {
889+
tree: filtered_tree,
890+
author: None,
891+
committer: None,
892+
message: None,
893+
},
851894
transaction,
852895
filter,
853-
None,
854-
None,
855896
))
856897
.transpose();
857898
}
@@ -874,9 +915,36 @@ fn apply_to_commit2(
874915
filtered_tree = tree::overlay(transaction, filtered_tree, t)?;
875916
}
876917

877-
repo.find_tree(filtered_tree)?
918+
let filtered_tree = repo.find_tree(filtered_tree)?;
919+
RewriteData {
920+
tree: filtered_tree,
921+
author: None,
922+
committer: None,
923+
message: None,
924+
}
878925
}
879-
_ => apply(transaction, filter, commit.tree()?)?,
926+
Op::Author(author, email) => RewriteData {
927+
tree: commit.tree()?,
928+
author: Some((author.clone(), email.clone())),
929+
committer: Some((author.clone(), email.clone())),
930+
message: None,
931+
},
932+
Op::Message(m) => RewriteData {
933+
tree: commit.tree()?,
934+
author: None,
935+
committer: None,
936+
// Pass the message through `strfmt` to enable future extensions
937+
message: Some(strfmt::strfmt(
938+
m,
939+
&std::collections::HashMap::<String, &dyn strfmt::DisplayStr>::new(),
940+
)?),
941+
},
942+
_ => RewriteData {
943+
tree: apply(transaction, filter, commit.tree()?)?,
944+
message: None,
945+
author: None,
946+
committer: None,
947+
},
880948
};
881949

882950
let filtered_parent_ids = {
@@ -889,24 +957,12 @@ fn apply_to_commit2(
889957

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

892-
let author = match to_op(filter) {
893-
Op::Author(author, email) => Some((author, email)),
894-
_ => None,
895-
};
896-
897-
let message = match to_op(filter) {
898-
Op::Squash(Some(ids)) => ids.get(&LazyRef::Resolved(commit.id())).cloned(),
899-
_ => None,
900-
};
901-
902960
Some(history::create_filtered_commit(
903961
commit,
904962
filtered_parent_ids,
905-
filtered_tree,
963+
rewrite_data,
906964
transaction,
907965
filter,
908-
author,
909-
message,
910966
))
911967
.transpose()
912968
}
@@ -931,6 +987,7 @@ fn apply2<'a>(
931987
Op::Empty => return Ok(tree::empty(repo)),
932988
Op::Fold => Ok(tree),
933989
Op::Squash(None) => Ok(tree),
990+
Op::Message(_) => Ok(tree),
934991
Op::Author(_, _) => Ok(tree),
935992
Op::Squash(Some(_)) => Err(josh_error("not applicable to tree")),
936993
Op::Linear => Ok(tree),

josh-core/src/filter/parse.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ fn parse_item(pair: pest::iterators::Pair<Rule>) -> JoshResult<Op> {
8585
let mut inner = pair.into_inner();
8686
make_op(&[inner.next().unwrap().as_str()])
8787
}
88+
Rule::filter_message => {
89+
let mut inner = pair.into_inner();
90+
Ok(Op::Message(unquote(inner.next().unwrap().as_str())))
91+
}
8892
Rule::filter_group => {
8993
let v: Vec<_> = pair.into_inner().map(|x| unquote(x.as_str())).collect();
9094

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

145147
Ok(Op::Squash(Some(ids)))

0 commit comments

Comments
 (0)