diff --git a/docs/src/reference/filters.md b/docs/src/reference/filters.md index 19e0db2ae..3b0a3a786 100644 --- a/docs/src/reference/filters.md +++ b/docs/src/reference/filters.md @@ -168,11 +168,6 @@ for all further ancestors (and so on). This special value `0000000000000000000000000000000000000000` can be used as a `` to filter commits that don't match any of the other shas. -### Join multiple histories into one **:join(:filter_0,...,:filter_N)** - -Produce the history that would be the result of pushing the passed branches with the -passed filters into the upstream. - ### Start filtering from a specific commit **:from(:filter)** Produce a history that keeps the original history up to and including the specified commit `` unchanged, diff --git a/josh-core/src/filter/grammar.pest b/josh-core/src/filter/grammar.pest index 1e99fb8b1..23d69c4e7 100644 --- a/josh-core/src/filter/grammar.pest +++ b/josh-core/src/filter/grammar.pest @@ -26,7 +26,7 @@ filter_spec = { ( | filter_rev | filter_from | filter_concat - | filter_join + | filter_unapply | filter_replace | filter_squash | filter_presub @@ -74,8 +74,8 @@ filter_concat = { ~ ")" } -filter_join = { - CMD_START ~ "join" ~ "(" +filter_unapply = { + CMD_START ~ "unapply" ~ "(" ~ NEWLINE* ~ (rev ~ filter_spec)? ~ (CMD_SEP+ ~ (rev ~ filter_spec))* @@ -83,6 +83,7 @@ filter_join = { ~ ")" } + filter_replace = { CMD_START ~ "replace" ~ "(" ~ NEWLINE* diff --git a/josh-core/src/filter/mod.rs b/josh-core/src/filter/mod.rs index 08d798c5f..799880986 100644 --- a/josh-core/src/filter/mod.rs +++ b/josh-core/src/filter/mod.rs @@ -296,7 +296,6 @@ enum Op { // We use BTreeMap rather than HashMap to guarantee deterministic results when // converting to Filter Rev(std::collections::BTreeMap), - Join(std::collections::BTreeMap), Linear, Prune, Unsign, @@ -463,17 +462,6 @@ fn lazy_refs2(op: &Op) -> Vec { lr.append(&mut lazy_refs(*f)); lr } - Op::Join(filters) => { - let mut lr = lazy_refs2(&Op::Compose(filters.values().copied().collect())); - lr.extend(filters.keys().filter_map(|x| { - if let LazyRef::Lazy(s) = x { - Some(s.to_owned()) - } else { - None - } - })); - lr - } Op::Squash(Some(revs)) => { let mut lr = vec![]; lr.extend(revs.keys().filter_map(|x| { @@ -536,24 +524,6 @@ fn resolve_refs2(refs: &std::collections::HashMap, op: &Op) - }; Op::HistoryConcat(resolved_ref, f) } - Op::Join(filters) => { - let lr = filters - .iter() - .map(|(r, f)| { - let f = resolve_refs(refs, *f); - if let LazyRef::Lazy(s) = r { - if let Some(res) = refs.get(s) { - (LazyRef::Resolved(*res), f) - } else { - (r.clone(), f) - } - } else { - (r.clone(), f) - } - }) - .collect(); - Op::Join(lr) - } Op::Squash(Some(filters)) => { let lr = filters .iter() @@ -614,14 +584,6 @@ fn spec2(op: &Op) -> String { v.sort(); format!(":rev({})", v.join(",")) } - Op::Join(filters) => { - let mut v = filters - .iter() - .map(|(k, v)| format!("{}{}", k.to_string(), spec(*v))) - .collect::>(); - v.sort(); - format!(":join({})", v.join(",")) - } Op::Workspace(path) => { format!(":workspace={}", parse::quote_if(&path.to_string_lossy())) } @@ -864,34 +826,6 @@ fn apply_to_commit2( )) .transpose(); } - Op::Join(refs) => { - // First loop to populate missing list - for (&_, f) in refs.iter() { - transaction.get(*f, commit.id()); - } - let mut result = commit.id(); - for (combine_tip, f) in refs.iter() { - if let LazyRef::Resolved(combine_tip) = combine_tip { - let old = some_or!(transaction.get(*f, commit.id()), { - return Ok(None); - }); - result = history::unapply_filter( - transaction, - *f, - result, - old, - *combine_tip, - history::OrphansMode::Keep, - None, - &mut None, - )?; - } else { - return Err(josh_error("unresolved lazy ref")); - } - } - transaction.insert(filter, commit.id(), result, true); - return Ok(Some(result)); - } _ => { if let Some(oid) = transaction.get(filter, commit.id()) { return Ok(Some(oid)); @@ -1221,7 +1155,6 @@ fn apply2<'a>(transaction: &'a cache::Transaction, op: &Op, x: Apply<'a>) -> Jos Op::Prune => Ok(x), Op::Unsign => Ok(x), Op::Rev(_) => Err(josh_error("not applicable to tree")), - Op::Join(_) => Err(josh_error("not applicable to tree")), Op::RegexReplace(replacements) => { let mut t = x.tree().clone(); for (regex, replacement) in replacements { diff --git a/josh-core/src/filter/parse.rs b/josh-core/src/filter/parse.rs index e12a7e460..bfe797175 100644 --- a/josh-core/src/filter/parse.rs +++ b/josh-core/src/filter/parse.rs @@ -160,17 +160,6 @@ fn parse_item(pair: pest::iterators::Pair) -> JoshResult { _ => Err(josh_error("parse_item: no match {:?}")), } } - Rule::filter_join => { - let v: Vec<_> = pair.into_inner().map(|x| x.as_str()).collect(); - - let hm = v - .iter() - .tuples() - .map(|(oid, filter)| Ok((LazyRef::parse(oid)?, parse(filter)?))) - .collect::>()?; - - Ok(Op::Join(hm)) - } Rule::filter_rev => { let v: Vec<_> = pair.into_inner().map(|x| x.as_str()).collect(); diff --git a/josh-core/src/filter/persist.rs b/josh-core/src/filter/persist.rs index f34f46d85..e4c95cd5f 100644 --- a/josh-core/src/filter/persist.rs +++ b/josh-core/src/filter/persist.rs @@ -281,15 +281,6 @@ impl InMemoryBuilder { let params_tree = self.build_rev_params(&v)?; push_tree_entries(&mut entries, [("rev", params_tree)]); } - Op::Join(filters) => { - let mut v = filters - .iter() - .map(|(k, v)| (k.to_string(), *v)) - .collect::>(); - v.sort(); - let params_tree = self.build_rev_params(&v)?; - push_tree_entries(&mut entries, [("join", params_tree)]); - } Op::HistoryConcat(lr, f) => { let params_tree = self.build_rev_params(&[(lr.to_string(), *f)])?; push_tree_entries(&mut entries, [("concat", params_tree)]); @@ -613,32 +604,6 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult { } Ok(Op::Rev(filters)) } - "join" => { - let join_tree = repo.find_tree(entry.id())?; - let mut filters = std::collections::BTreeMap::new(); - for i in 0..join_tree.len() { - let entry = join_tree - .get(i) - .ok_or_else(|| josh_error("join: missing entry"))?; - let inner_tree = repo.find_tree(entry.id())?; - let key_blob = repo.find_blob( - inner_tree - .get_name("o") - .ok_or_else(|| josh_error("join: missing key"))? - .id(), - )?; - let filter_tree = repo.find_tree( - inner_tree - .get_name("f") - .ok_or_else(|| josh_error("join: missing filter"))? - .id(), - )?; - let key = std::str::from_utf8(key_blob.content())?.to_string(); - let filter = from_tree2(repo, filter_tree.id())?; - filters.insert(LazyRef::parse(&key)?, to_filter(filter)); - } - Ok(Op::Join(filters)) - } "concat" => { let concat_tree = repo.find_tree(entry.id())?; let entry = concat_tree diff --git a/tests/filter/filter_id.t b/tests/filter/filter_id.t index e7c85059c..dba9fc59a 100644 --- a/tests/filter/filter_id.t +++ b/tests/filter/filter_id.t @@ -598,3 +598,239 @@ Test ::*.txt=*.txt (pattern with pattern in source should be error) $ josh-filter -i ::*.txt=*.txt ERROR: Pattern filters cannot use destination=source syntax: *.txt [1] + +Test :FOLD + $ FILTER_HASH=$(josh-filter -i ':FOLD') + $ josh-filter -p ${FILTER_HASH} + :FOLD + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- fold + + 1 directory, 1 file + +Test :PATHS + $ FILTER_HASH=$(josh-filter -i ':PATHS') + $ josh-filter -p ${FILTER_HASH} + :PATHS + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- paths + + 1 directory, 1 file + +Test :INDEX + $ FILTER_HASH=$(josh-filter -i ':INDEX') + $ josh-filter -p ${FILTER_HASH} + :INDEX + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- index + + 1 directory, 1 file + +Test :INVERT + $ FILTER_HASH=$(josh-filter -i ':INVERT') + $ josh-filter -p ${FILTER_HASH} + :INVERT + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- invert + + 1 directory, 1 file + +Test :linear + $ FILTER_HASH=$(josh-filter -i ':linear') + $ josh-filter -p ${FILTER_HASH} + :linear + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- linear + + 1 directory, 1 file + +Test :prune=trivial-merge + $ FILTER_HASH=$(josh-filter -i ':prune=trivial-merge') + $ josh-filter -p ${FILTER_HASH} + :prune=trivial-merge + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- prune + + 1 directory, 1 file + +Test :unsign + $ FILTER_HASH=$(josh-filter -i ':unsign') + $ josh-filter -p ${FILTER_HASH} + :unsign + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- unsign + + 1 directory, 1 file + +Test :workspace=path/to/workspace + $ FILTER_HASH=$(josh-filter -i ':workspace=path/to/workspace') + $ josh-filter -p ${FILTER_HASH} + :workspace=path/to/workspace + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- workspace + + 1 directory, 1 file + +Test :+path/to/stored + $ FILTER_HASH=$(josh-filter -i ':+path/to/stored') + $ josh-filter -p ${FILTER_HASH} + :+path/to/stored + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- stored + + 1 directory, 1 file + +Test :hook=hookname + $ FILTER_HASH=$(josh-filter -i ':hook=hookname') + $ josh-filter -p ${FILTER_HASH} + :hook="hookname" + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- hook + + 1 directory, 1 file + +Test :author=Name;email@example.com + $ FILTER_HASH=$(josh-filter -i ':author="Name";"email@example.com"') + $ josh-filter -p ${FILTER_HASH} + :author="Name";"email@example.com" + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- author + |-- 0 + `-- 1 + + 2 directories, 2 files + +Test :committer=Name;email@example.com + $ FILTER_HASH=$(josh-filter -i ':committer="Name";"email@example.com"') + $ josh-filter -p ${FILTER_HASH} + :committer="Name";"email@example.com" + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- committer + |-- 0 + `-- 1 + + 2 directories, 2 files + +Test :"commit message" + $ FILTER_HASH=$(josh-filter -i ':"commit message"') + $ josh-filter -p ${FILTER_HASH} + :"commit message" + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- message + |-- 0 + `-- 1 + + 2 directories, 2 files + +Test :"commit message";".*" + $ FILTER_HASH=$(josh-filter -i ':"commit message";".*"') + $ josh-filter -p ${FILTER_HASH} + :"commit message";".*" + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- message + |-- 0 + `-- 1 + + 2 directories, 2 files + +Test :pin[:/a] + $ FILTER_HASH=$(josh-filter -i ':pin[:/a]') + $ josh-filter -p ${FILTER_HASH} + :pin[:/a] + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- pin + `-- subdir + + 2 directories, 1 file + +Test :SQUASH + $ FILTER_HASH=$(josh-filter -i ':SQUASH') + $ josh-filter -p ${FILTER_HASH} + :SQUASH + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- squash + + 1 directory, 1 file + +Test :replace("pattern":"replacement") + $ FILTER_HASH=$(josh-filter -i ':replace("pattern":"replacement")') + $ josh-filter -p ${FILTER_HASH} + :replace( + "pattern":"replacement" + ) + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- regex_replace + `-- 0 + |-- p + `-- r + + 3 directories, 2 files + +Test :rev(0000000000000000000000000000000000000000:/a) + $ FILTER_HASH=$(josh-filter -i ':rev(0000000000000000000000000000000000000000:/a)') + $ josh-filter -p ${FILTER_HASH} + :rev(0000000000000000000000000000000000000000:/a) + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- rev + `-- 0 + |-- f + | `-- subdir + `-- o + + 4 directories, 2 files + +Test :from(0000000000000000000000000000000000000000:/a) + $ FILTER_HASH=$(josh-filter -i ':from(0000000000000000000000000000000000000000:/a)') + $ josh-filter -p ${FILTER_HASH} + :/a:concat(0000000000000000000000000000000000000000:/a) + $ git read-tree --reset -u ${FILTER_HASH} + $ tree + . + `-- chain + |-- 0 + | `-- subdir + `-- 1 + `-- concat + `-- 0 + |-- f + | `-- subdir + `-- o + + 7 directories, 3 files + diff --git a/tests/filter/join.t b/tests/filter/join.t deleted file mode 100644 index a08cfdd2f..000000000 --- a/tests/filter/join.t +++ /dev/null @@ -1,34 +0,0 @@ - $ git init -q 1> /dev/null - -Initial commit - $ echo contents1 > file1 - $ git add . - $ git commit -m "add file1" 1> /dev/null - -Apply prefix filter - $ josh-filter -s :prefix=subtree refs/heads/master --update refs/heads/filtered - [1] :prefix=subtree - [1] sequence_number - - $ git log --graph --pretty=%s refs/heads/filtered - * add file1 - - $ git show refs/heads/filtered - commit f5ea0c2feb26f846b28627cf6275682eba3f3f3a - Author: Josh - Date: Thu Apr 7 22:13:13 2005 +0000 - - add file1 - - diff --git a/subtree/file1 b/subtree/file1 - new file mode 100644 - index 0000000..a024003 - --- /dev/null - +++ b/subtree/file1 - @@ -0,0 +1 @@ - +contents1 - - $ git ls-tree --name-only -r refs/heads/filtered - subtree/file1 - - $ josh-filter ":join(f5ea0c2feb26f846b28627cf6275682eba3f3f3a:prefix=subtree)" \ No newline at end of file diff --git a/tests/proxy/join_subtree.t b/tests/proxy/join_subtree.t deleted file mode 100644 index ded6d0ccc..000000000 --- a/tests/proxy/join_subtree.t +++ /dev/null @@ -1,208 +0,0 @@ - $ . ${TESTDIR}/setup_test_env.sh - $ cd ${TESTTMP} - - $ git clone -q http://localhost:8001/real_repo.git 1> /dev/null - warning: You appear to have cloned an empty repository. - $ cd real_repo - - $ mkdir sub1 - $ echo contents1 > sub1/file1 - $ git add sub1 - $ git commit -m "add file1" 1> /dev/null - $ git push 1> /dev/null - To http://localhost:8001/real_repo.git - * [new branch] master -> master - - $ cd ${TESTTMP} - - $ git clone -q http://localhost:8002/real_repo.git:/sub1.git - $ cd sub1 - - $ echo contents2 > file2 - $ git add file2 - $ git commit -m "add file2" 1> /dev/null - $ git show - commit d8388f5880393d255b371f1ed9b801d35620017e - Author: Josh - Date: Thu Apr 7 22:13:13 2005 +0000 - - add file2 - - diff --git a/file2 b/file2 - new file mode 100644 - index 0000000..6b46faa - --- /dev/null - +++ b/file2 - @@ -0,0 +1 @@ - +contents2 - $ git push http://localhost:8001/real/repo2.git HEAD:refs/heads/master 2>&1 >/dev/null | sed -e 's/[ ]*$//g' - To http://localhost:8001/real/repo2.git - * [new branch] HEAD -> master - - $ git fetch "http://localhost:8002/real_repo.git@refs/heads/master:join('/real/repo2.git@refs/heads/master':/sub1).git" - From http://localhost:8002/real_repo.git@refs/heads/master:join('/real/repo2.git@refs/heads/master':/sub1) - * branch HEAD -> FETCH_HEAD - - $ git fetch "http://localhost:8002/real_repo.git@refs/heads/master:join(%22/real/repo2.git@refs/heads/master%22:/sub1).git" - From http://localhost:8002/real_repo.git@refs/heads/master:join(%22/real/repo2.git@refs/heads/master%22:/sub1) - * branch HEAD -> FETCH_HEAD - $ git log --graph --pretty=%s-%H FETCH_HEAD - * add file2-81b10fb4984d20142cd275b89c91c346e536876a - * add file1-bb282e9cdc1b972fffd08fd21eead43bc0c83cb8 - $ git fetch "http://localhost:8002/real_repo.git@refs/heads/master:join(d8388f5880393d255b371f1ed9b801d35620017e:/sub1).git" - From http://localhost:8002/real_repo.git@refs/heads/master:join(d8388f5880393d255b371f1ed9b801d35620017e:/sub1) - * branch HEAD -> FETCH_HEAD - - $ git log --graph --pretty=%s-%H FETCH_HEAD - * add file2-81b10fb4984d20142cd275b89c91c346e536876a - * add file1-bb282e9cdc1b972fffd08fd21eead43bc0c83cb8 - - $ git diff ${EMPTY_TREE}..FETCH_HEAD - diff --git a/sub1/file1 b/sub1/file1 - new file mode 100644 - index 0000000..a024003 - --- /dev/null - +++ b/sub1/file1 - @@ -0,0 +1 @@ - +contents1 - diff --git a/sub1/file2 b/sub1/file2 - new file mode 100644 - index 0000000..6b46faa - --- /dev/null - +++ b/sub1/file2 - @@ -0,0 +1 @@ - +contents2 - - - $ git push -o base=refs/heads/master origin HEAD:refs/heads/new_branch 2>&1 >/dev/null | sed -e 's/[ ]*$//g' - remote: josh-proxy: pre-receive hook - remote: upstream: response status: 200 OK - remote: upstream: response body: - remote: - remote: To http://localhost:8001/real_repo.git - remote: * [new branch] JOSH_PUSH -> new_branch - To http://localhost:8002/real_repo.git:/sub1.git - * [new branch] HEAD -> new_branch - -$ curl -s http://localhost:8002/flush -Flushed credential cache - $ git push - remote: josh-proxy: pre-receive hook - remote: upstream: response status: 200 OK - remote: upstream: response body: - remote: - remote: To http://localhost:8001/real_repo.git - remote: bb282e9..81b10fb JOSH_PUSH -> master - To http://localhost:8002/real_repo.git:/sub1.git - 0b4cf6c..d8388f5 master -> master - - $ cd ${TESTTMP}/real_repo - $ git pull --rebase - From http://localhost:8001/real_repo - bb282e9..81b10fb master -> origin/master - * [new branch] new_branch -> origin/new_branch - Updating bb282e9..81b10fb - Fast-forward - sub1/file2 | 1 + - 1 file changed, 1 insertion(+) - create mode 100644 sub1/file2 - - $ tree - . - `-- sub1 - |-- file1 - `-- file2 - - 2 directories, 2 files - - $ cat sub1/file2 - contents2 - -Make sure all temporary namespace got removed - $ tree ${TESTTMP}/remote/scratch/real_repo.git/refs/ | grep request_ - [1] - - $ bash ${TESTDIR}/destroy_test_env.sh - "real/repo2.git" = [] - "real_repo.git" = [ - ":/sub1", - "::sub1/", - ':join("/real/repo2.git@refs/heads/master":/sub1)', - ":join(d8388f5880393d255b371f1ed9b801d35620017e:/sub1)", - ] - . - |-- josh - | `-- 24 - | `-- sled - | |-- blobs - | |-- conf - | `-- db - |-- mirror - | |-- FETCH_HEAD - | |-- HEAD - | |-- config - | |-- description - | |-- info - | | `-- exclude - | |-- objects - | | |-- 0b - | | | `-- 4cf6c9efbbda1eada39fa9c1d21d2525b027bb - | | |-- 3d - | | | `-- 77ff51363c9825cc2a221fc0ba5a883a1a2c72 - | | |-- 6b - | | | `-- 46faacade805991bcaea19382c9d941828ce80 - | | |-- 81 - | | | `-- b10fb4984d20142cd275b89c91c346e536876a - | | |-- a0 - | | | `-- 24003ee1acc6bf70318a46e7b6df651b9dc246 - | | |-- ba - | | | `-- 7e17233d9f79c96cb694959eb065302acd96a6 - | | |-- bb - | | | `-- 282e9cdc1b972fffd08fd21eead43bc0c83cb8 - | | |-- c6 - | | | `-- 27a2e3a6bfbb7307f522ad94fdfc8c20b92967 - | | |-- c8 - | | | `-- 2fc150c43f13cc56c0e9caeba01b58ec612022 - | | |-- d8 - | | | `-- 388f5880393d255b371f1ed9b801d35620017e - | | |-- info - | | `-- pack - | `-- refs - | |-- heads - | |-- josh - | | `-- upstream - | | |-- real%2Frepo2.git - | | | |-- HEAD - | | | `-- refs - | | | `-- heads - | | | `-- master - | | `-- real_repo.git - | | |-- HEAD - | | `-- refs - | | `-- heads - | | |-- master - | | `-- new_branch - | `-- tags - `-- overlay - |-- HEAD - |-- config - |-- description - |-- info - | `-- exclude - |-- objects - | |-- 0b - | | `-- 4cf6c9efbbda1eada39fa9c1d21d2525b027bb - | |-- 81 - | | `-- b10fb4984d20142cd275b89c91c346e536876a - | |-- ba - | | `-- 7e17233d9f79c96cb694959eb065302acd96a6 - | |-- info - | `-- pack - `-- refs - |-- heads - |-- namespaces - `-- tags - - 43 directories, 29 files - -$ cat ${TESTTMP}/josh-proxy.out diff --git a/tests/proxy/workspace_errors.t b/tests/proxy/workspace_errors.t index 4e9c38617..922b73c8b 100644 --- a/tests/proxy/workspace_errors.t +++ b/tests/proxy/workspace_errors.t @@ -106,7 +106,7 @@ Error in filter remote: 1 | a/b = :b/sub2 remote: | ^--- remote: | - remote: = expected EOI, filter_group, filter_subdir, filter_stored, filter_nop, filter_presub, filter, filter_noarg, filter_message, filter_rev, filter_from, filter_concat, filter_join, filter_replace, filter_squash, or filter_scope + remote: = expected EOI, filter_group, filter_subdir, filter_stored, filter_nop, filter_presub, filter, filter_noarg, filter_message, filter_rev, filter_from, filter_concat, filter_unapply, filter_replace, filter_squash, or filter_scope remote: remote: a/b = :b/sub2 remote: c = :/sub1