Skip to content

Commit 66ad3f3

Browse files
committed
Add include filter
It can be inserted in workspace files, to allow for composition
1 parent 6e4be0e commit 66ad3f3

File tree

3 files changed

+166
-8
lines changed

3 files changed

+166
-8
lines changed

src/filter/mod.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ enum Op {
7272
Prefix(std::path::PathBuf),
7373
Subdir(std::path::PathBuf),
7474
Workspace(std::path::PathBuf),
75+
Include(std::path::PathBuf),
7576

7677
Glob(String),
7778

@@ -169,6 +170,9 @@ fn spec2(op: &Op) -> String {
169170
Op::Workspace(path) => {
170171
format!(":workspace={}", path.to_string_lossy())
171172
}
173+
Op::Include(path) => {
174+
format!(":include={}", path.to_string_lossy())
175+
}
172176

173177
Op::Chain(a, b) => match (to_op(*a), to_op(*b)) {
174178
(Op::Subdir(p1), Op::Prefix(p2)) if p1 == p2 => {
@@ -354,6 +358,54 @@ fn apply_to_commit2(
354358
))
355359
.transpose();
356360
}
361+
Op::Include(include_path) => {
362+
let normal_parents = commit
363+
.parent_ids()
364+
.map(|parent| transaction.get(filter, parent))
365+
.collect::<Option<Vec<git2::Oid>>>();
366+
367+
let normal_parents = some_or!(normal_parents, { return Ok(None) });
368+
369+
let cw = parse::parse(&tree::get_blob(repo, &commit.tree()?, &include_path))
370+
.unwrap_or(to_filter(Op::Empty));
371+
372+
let extra_parents = commit
373+
.parents()
374+
.map(|parent| {
375+
rs_tracing::trace_scoped!("parent", "id": parent.id().to_string());
376+
let pcw = parse::parse(&tree::get_blob(
377+
repo,
378+
&parent.tree().unwrap_or(tree::empty(repo)),
379+
&include_path,
380+
))
381+
.unwrap_or(to_filter(Op::Empty));
382+
383+
apply_to_commit2(
384+
&to_op(opt::optimize(to_filter(Op::Subtract(cw, pcw)))),
385+
&parent,
386+
transaction,
387+
)
388+
})
389+
.collect::<JoshResult<Option<Vec<_>>>>()?;
390+
391+
let extra_parents = some_or!(extra_parents, { return Ok(None) });
392+
393+
let filtered_parent_ids = normal_parents
394+
.into_iter()
395+
.chain(extra_parents.into_iter())
396+
.collect();
397+
398+
let filtered_tree = apply(transaction, filter, commit.tree()?)?;
399+
400+
return Some(history::create_filtered_commit(
401+
commit,
402+
filtered_parent_ids,
403+
filtered_tree,
404+
transaction,
405+
filter,
406+
))
407+
.transpose();
408+
}
357409
Op::Fold => {
358410
let filtered_parent_ids = commit
359411
.parents()
@@ -521,6 +573,15 @@ fn apply2<'a>(
521573
}
522574
}
523575

576+
Op::Include(path) => {
577+
let file = to_filter(Op::File(path.to_owned()));
578+
if let Ok(cw) = parse::parse(&tree::get_blob(repo, &tree, &path)) {
579+
apply(transaction, compose(file, cw), tree)
580+
} else {
581+
apply(transaction, file, tree)
582+
}
583+
}
584+
524585
Op::Compose(filters) => {
525586
let filtered: Vec<_> = filters
526587
.iter()
@@ -626,6 +687,71 @@ fn unapply2<'a>(
626687

627688
return Ok(r);
628689
}
690+
Op::Include(path) => {
691+
let root = to_filter(Op::File(path.to_owned()));
692+
let mapped = &tree::get_blob(transaction.repo(), &tree, path);
693+
let parsed = parse(mapped)?;
694+
695+
let mut blob = String::new();
696+
if let Ok(c) = get_comments(mapped) {
697+
if !c.is_empty() {
698+
blob = c;
699+
}
700+
}
701+
let blob = &format!("{}{}\n", &blob, pretty(parsed, 0));
702+
703+
// TODO: is this still necessary?
704+
// Remove filters file from the tree to prevent it from being parsed again
705+
// further down the callstack leading to endless recursion.
706+
let tree = tree::insert(
707+
transaction.repo(),
708+
&tree,
709+
path,
710+
git2::Oid::zero(),
711+
0o0100644,
712+
)?;
713+
714+
// Insert a dummy file to prevent the directory from dissappearing through becoming
715+
// empty.
716+
let tree = tree::insert(
717+
transaction.repo(),
718+
&tree,
719+
Path::new("DUMMY-df97a89d-b11f-4e1c-8400-345f895f0d40"),
720+
transaction.repo().blob("".as_bytes())?,
721+
0o0100644,
722+
)?;
723+
724+
let r = unapply(
725+
transaction,
726+
compose(root, parsed),
727+
tree.clone(),
728+
parent_tree,
729+
)?;
730+
731+
// Remove the dummy file inserted above
732+
let r = tree::insert(
733+
transaction.repo(),
734+
&r,
735+
&path.join("DUMMY-df97a89d-b11f-4e1c-8400-345f895f0d40"),
736+
git2::Oid::zero(),
737+
0o0100644,
738+
)?;
739+
740+
// Put the filters file back to it's target location.
741+
let r = if !mapped.is_empty() {
742+
tree::insert(
743+
transaction.repo(),
744+
&r,
745+
&path,
746+
transaction.repo().blob(blob.as_bytes())?,
747+
0o0100644, // Should this handle filemode?
748+
)?
749+
} else {
750+
r
751+
};
752+
753+
return Ok(r);
754+
}
629755
Op::Compose(filters) => {
630756
let mut remaining = tree.clone();
631757
let mut result = parent_tree.clone();
@@ -748,6 +874,16 @@ pub fn compute_warnings<'a>(
748874
}
749875
}
750876

877+
if let Op::Include(path) = to_op(filter) {
878+
let full_filter = &tree::get_blob(transaction.repo(), &tree, &path);
879+
if let Ok(res) = parse(full_filter) {
880+
filter = res;
881+
} else {
882+
warnings.push("couldn't parse include file\n".to_string());
883+
return warnings;
884+
}
885+
}
886+
751887
let filter = opt::flatten(filter);
752888
if let Op::Compose(filters) = to_op(filter) {
753889
for f in filters {

src/filter/parse.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ fn make_op(args: &[&str]) -> JoshResult<Op> {
77
["empty"] => Ok(Op::Empty),
88
["prefix", arg] => Ok(Op::Prefix(Path::new(arg).to_owned())),
99
["workspace", arg] => Ok(Op::Workspace(Path::new(arg).to_owned())),
10+
["include", arg] => Ok(Op::Include(Path::new(arg).to_owned())),
1011
["prefix"] => Err(josh_error(indoc!(
1112
r#"
1213
Filter ":prefix" requires an argument.
@@ -15,7 +16,7 @@ fn make_op(args: &[&str]) -> JoshResult<Op> {
1516
1617
:prefix=path
1718
18-
Where `path` is path to be used as a prefix
19+
Where `path` is the path to be used as a prefix
1920
"#
2021
))),
2122
["workspace"] => Err(josh_error(indoc!(
@@ -26,7 +27,18 @@ fn make_op(args: &[&str]) -> JoshResult<Op> {
2627
2728
:workspace=path
2829
29-
Where `path` is path to the directory where workspace.josh file is located
30+
Where `path` is the path to the directory where workspace.josh file is located
31+
"#
32+
))),
33+
["include"] => Err(josh_error(indoc!(
34+
r#"
35+
Filter ":include" requires an argument.
36+
37+
Note: use "=" to provide the argument value:
38+
39+
:include=path/to/include.josh
40+
41+
Where `path/to/include.josh` is the path to the include file
3042
"#
3143
))),
3244
["SQUASH"] => Ok(Op::Squash),

tests/filter/workspace_unique.t

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
$ git commit -m "add file2" 1> /dev/null
1717

1818
$ mkdir ws
19+
$ echo contents5 > ws/file5
20+
$ git add ws
21+
$ git commit -m "add file5" 1> /dev/null
1922
$ cat > ws/workspace.josh <<EOF
23+
> ::ws/file5
2024
> :/sub1::file1
2125
> ::sub2/subsub/
2226
> a = :/sub1
@@ -36,29 +40,35 @@
3640
[1] :prefix=sub2
3741
[1] :prefix=subsub
3842
[2] :/sub2
39-
[2] :[
43+
[2] ::ws/file5
44+
[3] :[
4045
:/sub1:[
4146
::file1
4247
:prefix=a
4348
]
4449
::sub2/subsub/
50+
::ws/file5
4551
]
46-
[2] :workspace=ws
52+
[3] :workspace=ws
4753

4854
$ git log --graph --pretty=%s refs/josh/master
49-
* add ws
50-
* add file2
51-
* add file1
55+
* add ws
56+
|\
57+
| * add file5
58+
| * add file2
59+
| * add file1
60+
* add file5
5261

5362
$ git checkout refs/josh/master 2> /dev/null
5463
$ tree
5564
.
5665
|-- a
5766
| `-- file4
5867
|-- file1
68+
|-- file5
5969
|-- sub2
6070
| `-- subsub
6171
| `-- file2
6272
`-- workspace.josh
6373

64-
3 directories, 4 files
74+
3 directories, 5 files

0 commit comments

Comments
 (0)