Skip to content

Commit 2b5ec99

Browse files
christian-schillingLMG
authored andcommitted
Fix :exclude[] implementation and documentation
It was not clear before that the excluded paths are the output of the filter rather than the matching input.
1 parent 7c9cca5 commit 2b5ec99

File tree

11 files changed

+147
-88
lines changed

11 files changed

+147
-88
lines changed

docs/src/reference/filters.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ Inside of a composition ``x=:filter`` can be used as an alternative spelling for
4545
``:filter:prefix=x``.
4646

4747
### Exclusion **`:exclude[:filter]`**
48-
Remove all paths matching ``:filter`` from the input tree.
48+
Remove all paths present in the *output* of ``:filter`` from the input tree.
49+
It should generally be avoided to use any filters that change paths and instead only
50+
use filters that select paths without altering them.
4951

5052
### Workspace **`:workspace=a`**
5153
Similar to ``:/a`` but also looks for a ``workspace.josh`` file inside the

src/cache.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::*;
22
use std::collections::HashMap;
33

4-
const VERSION: u64 = 6;
4+
const VERSION: u64 = 8;
55

66
lazy_static! {
77
static ref DB: std::sync::Mutex<Option<sled::Db>> = std::sync::Mutex::new(None);

src/filter/mod.rs

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ enum Op {
7373
Compose(Vec<Filter>),
7474
Chain(Filter, Filter),
7575
Subtract(Filter, Filter),
76+
Exclude(Filter),
7677
}
7778

7879
/// Pretty print the filter on multiple lines with initial indentation level.
@@ -113,10 +114,10 @@ fn pretty2(op: &Op, indent: usize, compose: bool) -> String {
113114
};
114115
match op {
115116
Op::Compose(filters) => ff(filters, "", indent),
116-
Op::Subtract(af, bf) => match (to_op(*af), to_op(*bf)) {
117-
(Op::Nop, Op::Compose(filters)) => ff(&filters, "exclude", indent),
118-
(Op::Nop, b) => format!(":exclude[{}]", pretty2(&b, indent, false)),
119-
_ => ff(&vec![*af, *bf], "subtract", indent + 4),
117+
Op::Subtract(af, bf) => ff(&vec![*af, *bf], "subtract", indent + 4),
118+
Op::Exclude(bf) => match to_op(*bf) {
119+
Op::Compose(filters) => ff(&filters, "exclude", indent),
120+
b => format!(":exclude[{}]", pretty2(&b, indent, false)),
120121
},
121122
Op::Chain(a, b) => match (to_op(*a), to_op(*b)) {
122123
(Op::Subdir(p1), Op::Prefix(p2)) if p1 == p2 => {
@@ -157,6 +158,9 @@ fn spec2(op: &Op) -> String {
157158
Op::Subtract(a, b) => {
158159
format!(":subtract[{},{}]", spec(*a), spec(*b))
159160
}
161+
Op::Exclude(b) => {
162+
format!(":exclude[{}]", spec(*b))
163+
}
160164
Op::Workspace(path) => {
161165
format!(":workspace={}", path.to_string_lossy())
162166
}
@@ -389,9 +393,21 @@ fn apply_to_commit2(
389393
};
390394
let bf = repo.find_tree(bf)?;
391395
let bu = unapply(transaction, *b, bf, tree::empty(repo))?;
392-
let ba = apply(transaction, *a, bu)?;
393-
394-
repo.find_tree(tree::subtract(repo, af, ba.id())?)?
396+
let ba = apply(transaction, *a, bu)?.id();
397+
repo.find_tree(tree::subtract(repo, af, ba)?)?
398+
}
399+
Op::Exclude(b) => {
400+
let bf = {
401+
transaction
402+
.repo()
403+
.find_commit(some_or!(
404+
apply_to_commit2(&to_op(*b), commit, transaction)?,
405+
{ return Ok(None) }
406+
))
407+
.map(|x| x.tree_id())
408+
.unwrap_or(tree::empty_id())
409+
};
410+
repo.find_tree(tree::subtract(repo, commit.tree_id(), bf)?)?
395411
}
396412
_ => apply(transaction, filter, commit.tree()?)?,
397413
};
@@ -476,8 +492,12 @@ fn apply2<'a>(
476492
let af = apply(transaction, *a, tree.clone())?;
477493
let bf = apply(transaction, *b, tree.clone())?;
478494
let bu = unapply(transaction, *b, bf, tree::empty(repo))?;
479-
let ba = apply(transaction, *a, bu)?;
480-
Ok(repo.find_tree(tree::subtract(repo, af.id(), ba.id())?)?)
495+
let ba = apply(transaction, *a, bu)?.id();
496+
Ok(repo.find_tree(tree::subtract(repo, af.id(), ba)?)?)
497+
}
498+
Op::Exclude(b) => {
499+
let bf = apply(transaction, *b, tree.clone())?.id();
500+
Ok(repo.find_tree(tree::subtract(repo, tree.id(), bf)?)?)
481501
}
482502

483503
Op::Paths => tree::pathstree("", tree.id(), transaction),
@@ -640,21 +660,19 @@ fn unapply2<'a>(
640660
}
641661
}
642662

643-
Op::Subtract(a, b) => match (to_op(*a), to_op(*b)) {
644-
(Op::Nop, b) => {
645-
let subtracted = tree::subtract(
646-
transaction.repo(),
647-
tree.id(),
648-
unapply2(transaction, &b, tree, tree::empty(transaction.repo()))?.id(),
649-
)?;
650-
Ok(transaction.repo().find_tree(tree::overlay(
651-
transaction.repo(),
652-
parent_tree.id(),
653-
subtracted,
654-
)?)?)
655-
}
656-
_ => return Err(josh_error("filter not reversible")),
657-
},
663+
Op::Subtract(_, _) => return Err(josh_error("filter not reversible")),
664+
Op::Exclude(b) => {
665+
let subtracted = tree::subtract(
666+
transaction.repo(),
667+
tree.id(),
668+
unapply(transaction, *b, tree, tree::empty(transaction.repo()))?.id(),
669+
)?;
670+
Ok(transaction.repo().find_tree(tree::overlay(
671+
transaction.repo(),
672+
parent_tree.id(),
673+
subtracted,
674+
)?)?)
675+
}
658676
Op::Glob(pattern) => {
659677
let pattern = glob::Pattern::new(pattern)?;
660678
let options = glob::MatchOptions {

src/filter/opt.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ pub fn simplify(filter: Filter) -> Filter {
7575
Op::Subtract(a, b) => match (to_op(a), to_op(b)) {
7676
(a, b) => Op::Subtract(simplify(to_filter(a)), simplify(to_filter(b))),
7777
},
78+
Op::Exclude(b) => Op::Exclude(simplify(b)),
7879
_ => to_op(filter),
7980
});
8081

@@ -128,6 +129,7 @@ pub fn flatten(filter: Filter) -> Filter {
128129
Op::Subtract(a, b) => match (to_op(a), to_op(b)) {
129130
(a, b) => Op::Subtract(flatten(to_filter(a)), flatten(to_filter(b))),
130131
},
132+
Op::Exclude(b) => Op::Exclude(flatten(b)),
131133
_ => to_op(filter),
132134
});
133135

@@ -339,6 +341,9 @@ fn step(filter: Filter) -> Filter {
339341
(_, Op::Empty) => Op::Empty,
340342
(a, b) => Op::Chain(step(to_filter(a)), step(to_filter(b))),
341343
},
344+
Op::Exclude(b) if b == to_filter(Op::Nop) => Op::Empty,
345+
Op::Exclude(b) if b == to_filter(Op::Empty) => Op::Nop,
346+
Op::Exclude(b) => Op::Exclude(step(b)),
342347
Op::Subtract(a, b) if a == b => Op::Empty,
343348
Op::Subtract(af, bf) => match (to_op(af), to_op(bf)) {
344349
(Op::Empty, _) => Op::Empty,

src/filter/parse.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ fn parse_item(pair: pest::iterators::Pair<Rule>) -> JoshResult<Op> {
5353
[cmd, args] => {
5454
let g = parse_group(args)?;
5555
match *cmd {
56-
"exclude" => {
57-
Ok(Op::Subtract(to_filter(Op::Nop), to_filter(Op::Compose(g))))
58-
}
56+
"exclude" => Ok(Op::Exclude(to_filter(Op::Compose(g)))),
5957
"subtract" if g.len() == 2 => Ok(Op::Subtract(g[0], g[1])),
6058
_ => Err(josh_error("parse_item: no match")),
6159
}

tests/filter/empty_orphan.t

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@ Empty root commits from unrelated parts of the tree should not be included
100100
c/file2
101101
c/file3
102102

103-
$ josh-filter -s c=:exclude[:/sub1] master
103+
$ josh-filter -s c=:exclude[::sub1/] master
104+
[4] :prefix=sub1
104105
[5] :/sub1
105-
[5] :exclude[:/sub1]
106+
[5] :exclude[::sub1/]
106107
[6] :prefix=c
107108

108109
$ git log FILTERED_HEAD --graph --pretty=%s
@@ -116,8 +117,9 @@ Empty root commits from unrelated parts of the tree should not be included
116117

117118
$ josh-filter -s :prefix=x FILTERED_HEAD
118119
[3] :prefix=x
120+
[4] :prefix=sub1
119121
[5] :/sub1
120-
[5] :exclude[:/sub1]
122+
[5] :exclude[::sub1/]
121123
[6] :prefix=c
122124

123125
$ git ls-tree --name-only -r FILTERED_HEAD

tests/filter/exclude_compose.t

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,59 +14,78 @@
1414
$ git add sub2
1515
$ git commit -m "add file2" 1> /dev/null
1616

17-
$ josh-filter -s :exclude[:/sub2] master --update refs/heads/hidden
18-
[1] :exclude[:/sub2]
17+
$ mkdir sub3
18+
$ echo contents1 > sub3/file1
19+
$ git add sub3
20+
$ git commit -m "add file3" 1> /dev/null
21+
22+
$ josh-filter -s :exclude[::sub2/] master --update refs/heads/hidden
23+
[1] :prefix=sub2
1924
[2] :/sub2
20-
$ git checkout hidden 1> /dev/null
21-
Switched to branch 'hidden'
25+
[2] :exclude[::sub2/]
26+
$ git checkout -q hidden 1> /dev/null
2227
$ tree
2328
.
24-
`-- sub1
29+
|-- sub1
30+
| `-- file1
31+
`-- sub3
2532
`-- file1
2633

27-
1 directory, 1 file
34+
2 directories, 2 files
2835
$ git log --graph --pretty=%s
36+
* add file3
2937
* add file1
3038

3139
$ echo contents3 > sub1/file3
3240
$ git add sub1/file3
3341
$ git commit -m "add sub1/file3" 1> /dev/null
3442

35-
$ josh-filter -s :exclude[:/sub1,:/sub2] master --update refs/josh/filtered
43+
$ josh-filter -s :exclude[::sub1/,::sub2/] master --update refs/josh/filtered
3644
[1] :/sub1
37-
[1] :exclude[
38-
:/sub1
39-
:/sub2
40-
]
41-
[1] :exclude[:/sub2]
45+
[1] :prefix=sub1
46+
[1] :prefix=sub2
4247
[2] :/sub2
4348
[2] :[
44-
:/sub1
45-
:/sub2
49+
::sub1/
50+
::sub2/
4651
]
52+
[2] :exclude[
53+
::sub1/
54+
::sub2/
55+
]
56+
[2] :exclude[::sub2/]
4757

48-
$ git checkout refs/josh/filtered
49-
Note: switching to 'refs/josh/filtered'.
50-
51-
You are in 'detached HEAD' state. You can look around, make experimental
52-
changes and commit them, and you can discard any commits you make in this
53-
state without impacting any branches by switching back to a branch.
54-
55-
If you want to create a new branch to retain commits you create, you may
56-
do so (now or later) by using -c with the switch command. Example:
57-
58-
git switch -c <new-branch-name>
59-
60-
Or undo this operation with:
61-
62-
git switch -
63-
64-
Turn off this advice by setting config variable advice.detachedHead to false
65-
66-
HEAD is now at bb282e9 add file1
58+
$ git checkout -q refs/josh/filtered
6759
$ tree
6860
.
69-
`-- sub1
61+
`-- sub3
7062
`-- file1
7163

7264
1 directory, 1 file
65+
66+
$ josh-filter -s :exclude[sub1=:/sub3] master --update refs/josh/filtered
67+
[1] :/sub1
68+
[1] :prefix=sub2
69+
[2] :/sub2
70+
[2] :/sub3
71+
[2] :[
72+
::sub1/
73+
::sub2/
74+
]
75+
[2] :exclude[
76+
::sub1/
77+
::sub2/
78+
]
79+
[2] :exclude[::sub2/]
80+
[2] :prefix=sub1
81+
[3] :exclude[:/sub3:prefix=sub1]
82+
83+
$ git checkout -q refs/josh/filtered
84+
$ tree
85+
.
86+
|-- sub2
87+
| `-- file2
88+
`-- sub3
89+
`-- file1
90+
91+
2 directories, 2 files

tests/filter/hide_view.t

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@
3333

3434
2 directories, 3 files
3535

36-
$ josh-filter -s c=:exclude[:/sub1] master --update refs/josh/filter/master
36+
$ josh-filter -s c=:exclude[::sub1/] master --update refs/josh/filter/master
3737
[1] :prefix=c
3838
[2] :/sub1
39-
[2] :exclude[:/sub1]
39+
[2] :exclude[::sub1/]
40+
[2] :prefix=sub1
4041
$ git checkout josh/filter/master 2> /dev/null
4142
$ git log --graph --pretty=%s
4243
* add file3
@@ -51,8 +52,9 @@
5152
$ josh-filter -s c=:exclude[::sub1/file2] master --update refs/josh/filter/master
5253
[2] :/sub1
5354
[2] ::sub1/file2
54-
[2] :exclude[:/sub1]
55+
[2] :exclude[::sub1/]
5556
[2] :exclude[::sub1/file2]
57+
[2] :prefix=sub1
5658
[3] :prefix=c
5759
$ git checkout josh/filter/master 2> /dev/null
5860
$ git log --graph --pretty=%s
@@ -72,9 +74,10 @@
7274
[2] :/sub1
7375
[2] ::sub1/file2
7476
[2] ::sub2/file3
75-
[2] :exclude[:/sub1]
77+
[2] :exclude[::sub1/]
7678
[2] :exclude[::sub1/file2]
7779
[2] :exclude[::sub2/file3]
80+
[2] :prefix=sub1
7881
[4] :prefix=c
7982
$ git checkout josh/filter/master 2> /dev/null
8083
$ git log --graph --pretty=%s

0 commit comments

Comments
 (0)