Skip to content

Commit 07d0089

Browse files
Implement :lookup filter
Change: lookup
1 parent e22bb9e commit 07d0089

File tree

3 files changed

+206
-8
lines changed

3 files changed

+206
-8
lines changed

josh-core/src/filter/mod.rs

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ enum Op {
296296
Prefix(std::path::PathBuf),
297297
Subdir(std::path::PathBuf),
298298
Workspace(std::path::PathBuf),
299+
Lookup(std::path::PathBuf),
300+
Lookup2(git2::Oid),
299301

300302
Pattern(String),
301303
Message(String),
@@ -595,6 +597,12 @@ fn spec2(op: &Op) -> String {
595597
Op::Workspace(path) => {
596598
format!(":workspace={}", parse::quote_if(&path.to_string_lossy()))
597599
}
600+
Op::Lookup(path) => {
601+
format!(":lookup={}", parse::quote_if(&path.to_string_lossy()))
602+
}
603+
Op::Lookup2(oid) => {
604+
format!(":lookup2={}", oid.to_string())
605+
}
598606
Op::RegexReplace(replacements) => {
599607
let v = replacements
600608
.iter()
@@ -1303,8 +1311,8 @@ fn resolve_workspace_redirect<'a>(
13031311
}
13041312
}
13051313

1306-
fn get_workspace<'a>(repo: &'a git2::Repository, tree: &'a git2::Tree<'a>, path: &Path) -> Filter {
1307-
let ws_path = normalize_path(&path.join("workspace.josh"));
1314+
fn get_filter<'a>(repo: &'a git2::Repository, tree: &'a git2::Tree<'a>, path: &Path) -> Filter {
1315+
let ws_path = normalize_path(path);
13081316
let ws_id = ok_or!(tree.get_path(&ws_path), {
13091317
return to_filter(Op::Empty);
13101318
})
@@ -1456,6 +1464,69 @@ fn apply_to_commit2(
14561464
Apply::from_commit(commit)?.with_parents(filtered_parent_ids),
14571465
)?
14581466
}
1467+
Op::Lookup(lookup_path) => {
1468+
let lookup_commit = if let Some(lookup_commit) =
1469+
apply_to_commit2(&Op::Subdir(lookup_path.clone()), &commit, transaction)?
1470+
{
1471+
lookup_commit
1472+
} else {
1473+
return Ok(None);
1474+
};
1475+
1476+
let op = Op::Lookup2(lookup_commit);
1477+
1478+
if let Some(start) = transaction.get(to_filter(op), commit.id()) {
1479+
transaction.insert(filter, commit.id(), start, true);
1480+
return Ok(Some(start));
1481+
} else {
1482+
return Ok(None);
1483+
}
1484+
}
1485+
1486+
Op::Lookup2(lookup_commit_id) => {
1487+
let lookup_commit = repo.find_commit(*lookup_commit_id)?;
1488+
for parent in lookup_commit.parents() {
1489+
let lookup_tree = lookup_commit.tree_id();
1490+
let cw = get_filter(
1491+
repo,
1492+
&repo.find_tree(lookup_tree)?,
1493+
&std::path::PathBuf::new().join(commit.id().to_string()),
1494+
);
1495+
if cw != filter::empty() {
1496+
if let Some(start) =
1497+
apply_to_commit2(&Op::Lookup2(parent.id()), &commit, transaction)?
1498+
{
1499+
transaction.insert(filter, commit.id(), start, true);
1500+
return Ok(Some(start));
1501+
} else {
1502+
return Ok(None);
1503+
}
1504+
}
1505+
break;
1506+
}
1507+
let lookup_tree = lookup_commit.tree_id();
1508+
let cw = get_filter(
1509+
repo,
1510+
&repo.find_tree(lookup_tree)?,
1511+
&std::path::PathBuf::new().join(commit.id().to_string()),
1512+
);
1513+
1514+
if cw == filter::empty() {
1515+
// FIXME empty filter or no entry in table?
1516+
for parent in commit.parents() {
1517+
if let Some(start) = apply_to_commit2(&op, &parent, transaction)? {
1518+
transaction.insert(filter, commit.id(), start, true);
1519+
return Ok(Some(start));
1520+
} else {
1521+
return Ok(None);
1522+
}
1523+
}
1524+
return Ok(None);
1525+
}
1526+
1527+
Apply::from_commit(commit)?
1528+
.with_tree(apply(transaction, cw, Apply::from_commit(commit)?)?.into_tree())
1529+
}
14591530
Op::Squash(Some(ids)) => {
14601531
if let Some(sq) = ids.get(&LazyRef::Resolved(commit.id())) {
14611532
let oid = if let Some(oid) =
@@ -1582,7 +1653,7 @@ fn apply_to_commit2(
15821653

15831654
let commit_filter = filter;
15841655

1585-
let cw = get_workspace(repo, &commit.tree()?, ws_path);
1656+
let cw = get_filter(repo, &commit.tree()?, &ws_path.join("workspace.josh"));
15861657

15871658
let parent_filters = commit
15881659
.parents()
@@ -1597,10 +1668,10 @@ fn apply_to_commit2(
15971668
ws_path.clone()
15981669
};
15991670

1600-
let pcw = get_workspace(
1671+
let pcw = get_filter(
16011672
repo,
16021673
&parent.tree().unwrap_or_else(|_| tree::empty(repo)),
1603-
&p,
1674+
&p.join("workspace.josh"),
16041675
);
16051676
Ok((parent, pcw))
16061677
})
@@ -1737,6 +1808,8 @@ fn apply2<'a>(transaction: &'a cache::Transaction, op: &Op, x: Apply<'a>) -> Jos
17371808
Op::Prune => Ok(x),
17381809
Op::Unsign => Ok(x),
17391810
Op::Rev(_) => Err(josh_error("not applicable to tree")),
1811+
Op::Lookup(_) => Err(josh_error("not applicable to tree")),
1812+
Op::Lookup2(_) => Err(josh_error("not applicable to tree")),
17401813
Op::Join(_) => Err(josh_error("not applicable to tree")),
17411814
Op::RegexReplace(replacements) => {
17421815
let mut t = x.tree().clone();
@@ -1825,7 +1898,10 @@ fn apply2<'a>(transaction: &'a cache::Transaction, op: &Op, x: Apply<'a>) -> Jos
18251898
transaction,
18261899
compose(
18271900
wsj_file,
1828-
compose(get_workspace(repo, &x.tree(), path), base),
1901+
compose(
1902+
get_filter(repo, &x.tree(), &path.join("workspace.josh")),
1903+
base,
1904+
),
18291905
),
18301906
x,
18311907
)
@@ -1937,8 +2013,12 @@ fn unapply_workspace<'a>(
19372013
match op {
19382014
Op::Workspace(path) => {
19392015
let tree = pre_process_tree(transaction.repo(), tree)?;
1940-
let workspace = get_workspace(transaction.repo(), &tree, Path::new(""));
1941-
let original_workspace = get_workspace(transaction.repo(), &parent_tree, path);
2016+
let workspace = get_filter(transaction.repo(), &tree, Path::new("workspace.josh"));
2017+
let original_workspace = get_filter(
2018+
transaction.repo(),
2019+
&parent_tree,
2020+
&path.join("workspace.josh"),
2021+
);
19422022

19432023
let root = to_filter(Op::Subdir(path.to_owned()));
19442024
let wsj_file = to_filter(Op::File(Path::new("workspace.josh").to_owned()));

josh-core/src/filter/parse.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ fn make_op(args: &[&str]) -> JoshResult<Op> {
1010
["author", author, email] => Ok(Op::Author(author.to_string(), email.to_string())),
1111
["committer", author, email] => Ok(Op::Committer(author.to_string(), email.to_string())),
1212
["workspace", arg] => Ok(Op::Workspace(Path::new(arg).to_owned())),
13+
["lookup", arg] => Ok(Op::Lookup(Path::new(arg).to_owned())),
1314
["prefix"] => Err(josh_error(indoc!(
1415
r#"
1516
Filter ":prefix" requires an argument.

tests/filter/lookup.t

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
$ export TERM=dumb
2+
$ export RUST_LOG_STYLE=never
3+
4+
$ git init -q real_repo 1> /dev/null
5+
$ cd real_repo
6+
7+
$ mkdir sub1
8+
$ echo contents1 > sub1/file1
9+
$ git add sub1
10+
$ git commit -m "add file1" 1> /dev/null
11+
12+
$ mkdir sub1
13+
mkdir: cannot create directory 'sub1': File exists
14+
[1]
15+
$ echo contents2 > sub1/file2
16+
$ git add sub1
17+
$ git commit -m "add file2" 1> /dev/null
18+
19+
$ git log --graph --pretty=%H
20+
* 81b10fb4984d20142cd275b89c91c346e536876a
21+
* bb282e9cdc1b972fffd08fd21eead43bc0c83cb8
22+
23+
$ mkdir table
24+
$ echo ":prefix=x" > table/81b10fb4984d20142cd275b89c91c346e536876a
25+
$ echo ":prefix=y" > table/bb282e9cdc1b972fffd08fd21eead43bc0c83cb8
26+
$ git add table
27+
$ git commit -m "add lookup table" 1> /dev/null
28+
29+
30+
$ echo contents3 > sub1/file3
31+
$ git add sub1
32+
$ git commit -m "add file3" 1> /dev/null
33+
34+
$ git log --graph --pretty=%H
35+
* 26e4c43675b985689e280bc42264a9226af76943
36+
* 14c74c5eca73952b36d736034b388832748c49d6
37+
* 81b10fb4984d20142cd275b89c91c346e536876a
38+
* bb282e9cdc1b972fffd08fd21eead43bc0c83cb8
39+
40+
$ josh-filter -s ":lookup=table" --update refs/heads/filtered
41+
[1] :lookup=table
42+
[2] :/table
43+
[4] :lookup2=4880528e9d57aa5efc925e120a8077bfa37d778d
44+
45+
$ git log refs/heads/filtered --graph --pretty=%s
46+
* add file2
47+
* add file1
48+
$ git diff ${EMPTY_TREE}..refs/heads/filtered
49+
diff --git a/x/sub1/file1 b/x/sub1/file1
50+
new file mode 100644
51+
index 0000000..a024003
52+
--- /dev/null
53+
+++ b/x/sub1/file1
54+
@@ -0,0 +1 @@
55+
+contents1
56+
diff --git a/x/sub1/file2 b/x/sub1/file2
57+
new file mode 100644
58+
index 0000000..6b46faa
59+
--- /dev/null
60+
+++ b/x/sub1/file2
61+
@@ -0,0 +1 @@
62+
+contents2
63+
$ git diff ${EMPTY_TREE}..refs/heads/filtered~1
64+
diff --git a/y/sub1/file1 b/y/sub1/file1
65+
new file mode 100644
66+
index 0000000..a024003
67+
--- /dev/null
68+
+++ b/y/sub1/file1
69+
@@ -0,0 +1 @@
70+
+contents1
71+
72+
$ echo ":prefix=z" > table/14c74c5eca73952b36d736034b388832748c49d6
73+
$ echo ":prefix=z" > table/26e4c43675b985689e280bc42264a9226af76943
74+
$ git add table
75+
$ git commit -m "mod lookup table" 1> /dev/null
76+
$ tree table
77+
table
78+
|-- 14c74c5eca73952b36d736034b388832748c49d6
79+
|-- 26e4c43675b985689e280bc42264a9226af76943
80+
|-- 81b10fb4984d20142cd275b89c91c346e536876a
81+
`-- bb282e9cdc1b972fffd08fd21eead43bc0c83cb8
82+
83+
1 directory, 4 files
84+
85+
$ josh-filter -s ":lookup=table" --update refs/heads/filtered
86+
Warning: reference refs/heads/filtered wasn't updated
87+
[2] :lookup=table
88+
[3] :/table
89+
[4] :lookup2=4880528e9d57aa5efc925e120a8077bfa37d778d
90+
[5] :lookup2=ed934c124e28c83270d9cfbb011f3ceb46c0f69e
91+
$ git log refs/heads/filtered --graph --pretty=%s
92+
* add file2
93+
* add file1
94+
95+
$ git diff ${EMPTY_TREE}..refs/heads/filtered
96+
diff --git a/x/sub1/file1 b/x/sub1/file1
97+
new file mode 100644
98+
index 0000000..a024003
99+
--- /dev/null
100+
+++ b/x/sub1/file1
101+
@@ -0,0 +1 @@
102+
+contents1
103+
diff --git a/x/sub1/file2 b/x/sub1/file2
104+
new file mode 100644
105+
index 0000000..6b46faa
106+
--- /dev/null
107+
+++ b/x/sub1/file2
108+
@@ -0,0 +1 @@
109+
+contents2
110+
$ git diff ${EMPTY_TREE}..refs/heads/filtered~1
111+
diff --git a/y/sub1/file1 b/y/sub1/file1
112+
new file mode 100644
113+
index 0000000..a024003
114+
--- /dev/null
115+
+++ b/y/sub1/file1
116+
@@ -0,0 +1 @@
117+
+contents1

0 commit comments

Comments
 (0)