Skip to content

Commit 0b4aadb

Browse files
Implement :from filter
Change: from-filter
1 parent f861282 commit 0b4aadb

File tree

6 files changed

+140
-4
lines changed

6 files changed

+140
-4
lines changed

docs/src/reference/filters.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ commits that don't match any of the other shas.
114114
Produce the history that would be the result of pushing the passed branches with the
115115
passed filters into the upstream.
116116

117+
### Start filtering from a specific commit **:from(<sha>:filter)**
118+
119+
Produce a history that keeps the original history leading up to the specified commit `<sha>` unchanged,
120+
but applies the given `:filter` to all commits from that commit onwards.
121+
117122
### Prune trivial merge commits **:prune=trivial-merge**
118123

119124
Produce a history that skips all merge commits whose tree is identical to the first parents

josh-core/src/filter/grammar.pest

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ filter_spec = { (
2424
filter_group
2525
| filter_message
2626
| filter_rev
27+
| filter_from
28+
| filter_concat
2729
| filter_join
2830
| filter_replace
2931
| filter_squash
@@ -51,6 +53,24 @@ filter_rev = {
5153
~ ")"
5254
}
5355

56+
filter_from = {
57+
CMD_START ~ "from" ~ "("
58+
~ NEWLINE*
59+
~ (rev ~ filter_spec)?
60+
~ (CMD_SEP+ ~ (rev ~ filter_spec))*
61+
~ NEWLINE*
62+
~ ")"
63+
}
64+
65+
filter_concat = {
66+
CMD_START ~ "from" ~ "("
67+
~ NEWLINE*
68+
~ (rev ~ filter_spec)?
69+
~ (CMD_SEP+ ~ (rev ~ filter_spec))*
70+
~ NEWLINE*
71+
~ ")"
72+
}
73+
5474
filter_join = {
5575
CMD_START ~ "join" ~ "("
5676
~ NEWLINE*
@@ -60,7 +80,6 @@ filter_join = {
6080
~ ")"
6181
}
6282

63-
6483
filter_replace = {
6584
CMD_START ~ "replace" ~ "("
6685
~ NEWLINE*

josh-core/src/filter/mod.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ enum Op {
301301
Pattern(String),
302302
Message(String),
303303

304+
HistoryConcat(LazyRef, Filter),
305+
304306
Compose(Vec<Filter>),
305307
Chain(Filter, Filter),
306308
Subtract(Filter, Filter),
@@ -425,6 +427,13 @@ fn lazy_refs2(op: &Op) -> Vec<String> {
425427
av
426428
}
427429
Op::Rev(filters) => lazy_refs2(&Op::Join(filters.clone())),
430+
Op::HistoryConcat(r, _) => {
431+
let mut lr = Vec::new();
432+
if let LazyRef::Lazy(s) = r {
433+
lr.push(s.to_owned());
434+
}
435+
lr
436+
}
428437
Op::Join(filters) => {
429438
let mut lr = lazy_refs2(&Op::Compose(filters.values().copied().collect()));
430439
lr.extend(filters.keys().filter_map(|x| {
@@ -485,6 +494,19 @@ fn resolve_refs2(refs: &std::collections::HashMap<String, git2::Oid>, op: &Op) -
485494
.collect();
486495
Op::Rev(lr)
487496
}
497+
Op::HistoryConcat(r, filter) => {
498+
let f = resolve_refs(refs, *filter);
499+
let resolved_ref = if let LazyRef::Lazy(s) = r {
500+
if let Some(res) = refs.get(s) {
501+
LazyRef::Resolved(*res)
502+
} else {
503+
r.clone()
504+
}
505+
} else {
506+
r.clone()
507+
};
508+
Op::HistoryConcat(resolved_ref, f)
509+
}
488510
Op::Join(filters) => {
489511
let lr = filters
490512
.iter()
@@ -626,6 +648,9 @@ fn spec2(op: &Op) -> String {
626648
Op::Message(m) => {
627649
format!(":{}", parse::quote(m))
628650
}
651+
Op::HistoryConcat(r, filter) => {
652+
format!(":concat({}{})", r.to_string(), spec(*filter))
653+
}
629654
Op::Hook(hook) => {
630655
format!(":hook={}", parse::quote(hook))
631656
}
@@ -821,6 +846,13 @@ fn as_tree2(repo: &git2::Repository, op: &Op) -> JoshResult<git2::Oid> {
821846
v.sort();
822847
builder.insert("rev", rev_params(repo, &v)?, git2::FileMode::Tree.into())?;
823848
}
849+
Op::HistoryConcat(r, f) => {
850+
builder.insert(
851+
"historyconcat",
852+
rev_params(repo, &vec![(r.to_string(), *f)])?,
853+
git2::FileMode::Tree.into(),
854+
)?;
855+
}
824856
Op::Join(filters) => {
825857
let mut v = filters
826858
.iter()
@@ -1626,6 +1658,19 @@ fn apply_to_commit2(
16261658
parent_filters,
16271659
);
16281660
}
1661+
Op::HistoryConcat(r, f) => {
1662+
if let LazyRef::Resolved(c) = r {
1663+
let a = apply_to_commit2(&to_op(*f), &repo.find_commit(*c)?, transaction)?;
1664+
let a = some_or!(a, { return Ok(None) });
1665+
if commit.id() == a {
1666+
transaction.insert(filter, commit.id(), *c, true);
1667+
return Ok(Some(*c));
1668+
}
1669+
} else {
1670+
return Err(josh_error("unresolved lazy ref"));
1671+
}
1672+
Apply::from_commit(commit)?
1673+
}
16291674
_ => {
16301675
let filtered_parent_ids = commit
16311676
.parent_ids()
@@ -1677,7 +1722,7 @@ fn apply2<'a>(transaction: &'a cache::Transaction, op: &Op, x: Apply<'a>) -> Jos
16771722
Op::Nop => Ok(x),
16781723
Op::Empty => Ok(x.with_tree(tree::empty(repo))),
16791724
Op::Fold => Ok(x),
1680-
Op::Squash(None) => Ok(x),
1725+
Op::Squash(..) => Ok(x),
16811726
Op::Author(author, email) => Ok(x.with_author((author.clone(), email.clone()))),
16821727
Op::Committer(author, email) => Ok(x.with_committer((author.clone(), email.clone()))),
16831728
Op::Message(m) => Ok(x.with_message(
@@ -1687,7 +1732,7 @@ fn apply2<'a>(transaction: &'a cache::Transaction, op: &Op, x: Apply<'a>) -> Jos
16871732
&std::collections::HashMap::<String, &dyn strfmt::DisplayStr>::new(),
16881733
)?,
16891734
)),
1690-
Op::Squash(Some(_)) => Err(josh_error("not applicable to tree")),
1735+
Op::HistoryConcat(..) => Ok(x),
16911736
Op::Linear => Ok(x),
16921737
Op::Prune => Ok(x),
16931738
Op::Unsign => Ok(x),

josh-core/src/filter/parse.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,31 @@ fn parse_item(pair: pest::iterators::Pair<Rule>) -> JoshResult<Op> {
146146

147147
Ok(Op::Rev(hm))
148148
}
149+
Rule::filter_from => {
150+
let v: Vec<_> = pair.into_inner().map(|x| x.as_str()).collect();
151+
152+
if v.len() == 2 {
153+
let oid = LazyRef::parse(v[0])?;
154+
let filter = parse(v[1])?;
155+
Ok(Op::Chain(
156+
filter,
157+
filter::to_filter(Op::HistoryConcat(oid, filter)),
158+
))
159+
} else {
160+
Err(josh_error("wrong argument count for :from"))
161+
}
162+
}
163+
Rule::filter_concat => {
164+
let v: Vec<_> = pair.into_inner().map(|x| x.as_str()).collect();
165+
166+
if v.len() == 2 {
167+
let oid = LazyRef::parse(v[0])?;
168+
let filter = parse(v[1])?;
169+
Ok(Op::HistoryConcat(oid, filter))
170+
} else {
171+
Err(josh_error("wrong argument count for :concat"))
172+
}
173+
}
149174
Rule::filter_replace => {
150175
let replacements = pair
151176
.into_inner()

tests/filter/concat.t

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
$ export TESTTMP=${PWD}
2+
3+
$ cd ${TESTTMP}
4+
$ git init -q libs 1> /dev/null
5+
$ cd libs
6+
7+
$ mkdir sub1
8+
$ echo contents1 > sub1/file1
9+
$ git add sub1
10+
$ git commit -m "add file1" 1> /dev/null
11+
12+
$ echo contents2 > sub1/file2
13+
$ git add sub1
14+
$ git commit -m "add file2" 1> /dev/null
15+
$ git update-ref refs/heads/from_here HEAD
16+
17+
18+
$ mkdir sub2
19+
$ echo contents1 > sub2/file3
20+
$ git add sub2
21+
$ git commit -m "add file3" 1> /dev/null
22+
23+
$ josh-filter ":\"x\""
24+
25+
$ git log --graph --pretty=%s:%H HEAD
26+
* add file3:667a912db7482f3c8023082c9b4c7b267792633a
27+
* add file2:81b10fb4984d20142cd275b89c91c346e536876a
28+
* add file1:bb282e9cdc1b972fffd08fd21eead43bc0c83cb8
29+
30+
$ git log --graph --pretty=%s:%H FILTERED_HEAD
31+
* x:9d117d96dfdba145df43ebe37d9e526acac4b17c
32+
* x:b232aa8eefaadfb5e38b3ad7355118aa59fb651e
33+
* x:6b4d1f87c2be08f7d0f9d40b6679aab612e259b1
34+
35+
$ josh-filter -p ":from(81b10fb4984d20142cd275b89c91c346e536876a:\"x\")"
36+
:"x":concat(81b10fb4984d20142cd275b89c91c346e536876a:"x")
37+
$ josh-filter ":from(81b10fb4984d20142cd275b89c91c346e536876a:\"x\")"
38+
39+
$ git log --graph --pretty=%s FILTERED_HEAD
40+
* x
41+
* add file2
42+
* add file1

tests/proxy/workspace_errors.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ Error in filter
106106
remote: 1 | a/b = :b/sub2
107107
remote: | ^---
108108
remote: |
109-
remote: = expected EOI, filter_group, filter_subdir, filter_nop, filter_presub, filter, filter_noarg, filter_message, filter_rev, filter_join, filter_replace, or filter_squash
109+
remote: = expected EOI, filter_group, filter_subdir, filter_nop, filter_presub, filter, filter_noarg, filter_message, filter_rev, filter_from, filter_concat, filter_join, filter_replace, or filter_squash
110110
remote:
111111
remote: a/b = :b/sub2
112112
remote: c = :/sub1

0 commit comments

Comments
 (0)