diff --git a/josh-proxy/src/bin/josh-proxy.rs b/josh-proxy/src/bin/josh-proxy.rs index c76f52ff6..803c7ac41 100644 --- a/josh-proxy/src/bin/josh-proxy.rs +++ b/josh-proxy/src/bin/josh-proxy.rs @@ -295,7 +295,7 @@ async fn do_filter( let mut headref = headref; - josh::filter_refs(&transaction, filter, &from_to)?; + josh::filter_refs(&transaction, filter, &from_to, josh::filter::empty())?; if headref == "HEAD" { headref = heads_map .read()? diff --git a/src/bin/josh-filter.rs b/src/bin/josh-filter.rs index 027df3cec..795704c19 100644 --- a/src/bin/josh-filter.rs +++ b/src/bin/josh-filter.rs @@ -101,7 +101,41 @@ fn run_filter(args: Vec) -> josh::JoshResult { .arg( clap::Arg::with_name("check-permission") .long("check-permission") - .short("c") + .short("c"), + ) + .arg(clap::Arg::with_name("missing-permission").long("missing-permission")) + .arg( + clap::Arg::with_name("whitelist") + .long("whitelist") + .short("w") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("blacklist") + .long("blacklist") + .short("b") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("users") + .long("users") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("groups") + .long("groups") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("user") + .long("user") + .short("u") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("repo") + .long("repo") + .short("r") .takes_value(true), ) .arg(clap::Arg::with_name("version").long("version").short("v")) @@ -183,6 +217,7 @@ fn run_filter(args: Vec) -> josh::JoshResult { josh::filter::parse(&i)?, input_ref, "refs/JOSH_TMP", + josh::filter::empty(), )?; } } @@ -193,12 +228,6 @@ fn run_filter(args: Vec) -> josh::JoshResult { let target = update_target; let reverse = args.is_present("reverse"); - let check_permissions = args.is_present("check-permission"); - - if check_permissions { - filterobj = josh::filter::chain(josh::filter::parse(":PATHS")?, filterobj); - filterobj = josh::filter::chain(filterobj, josh::filter::parse(":FOLD")?); - } let t = if reverse { "refs/JOSH_TMP".to_owned() @@ -213,21 +242,49 @@ fn run_filter(args: Vec) -> josh::JoshResult { .unwrap() .to_string(); - josh::filter_ref(&transaction, filterobj, &src, &t)?; - - let mut all_paths = vec![]; - + let check_permissions = args.is_present("check-permission"); + let mut permissions_filter = josh::filter::empty(); if check_permissions { - let result_tree = repo.find_reference(&t)?.peel_to_tree()?; + let whitelist; + let blacklist; + if args.is_present("users") + && args.is_present("groups") + && args.is_present("user") + && args.is_present("repo") + { + let users = args.value_of("users").unwrap(); + let groups = args.value_of("groups").unwrap(); + let user = args.value_of("user").unwrap(); + let repo = args.value_of("repo").unwrap(); + + let acl = josh::get_acl(users, groups, user, repo)?; + whitelist = acl.0; + blacklist = acl.1; + } else { + whitelist = match args.value_of("whitelist") { + Some(s) => josh::filter::parse(s)?, + _ => josh::filter::nop(), + }; + blacklist = match args.value_of("blacklist") { + Some(s) => josh::filter::parse(s)?, + _ => josh::filter::empty(), + }; + } + permissions_filter = josh::filter::make_permissions_filter(filterobj, whitelist, blacklist) + } - result_tree.walk(git2::TreeWalkMode::PreOrder, |_, entry| { - let name = entry.name().unwrap(); - if name.starts_with("JOSH_ORIG_PATH_") { - let pathname = josh::from_ns(&name.replacen("JOSH_ORIG_PATH_", "", 1)); - all_paths.push(pathname); - } - git2::TreeWalkResult::Ok - })?; + let missing_permissions = args.is_present("missing-permission"); + if missing_permissions { + filterobj = permissions_filter; + permissions_filter = josh::filter::empty(); + } + + let updated_refs = josh::filter_ref(&transaction, filterobj, &src, &t, permissions_filter)?; + if args.value_of("update") != Some("FILTERED_HEAD") && updated_refs == 0 { + println!( + "Warning: reference {} wasn't updated", + args.value_of("update").unwrap() + ); } #[cfg(feature = "search")] @@ -264,39 +321,6 @@ fn run_filter(args: Vec) -> josh::JoshResult { /* println!("\n Search took {:?}", duration); */ } - let mut dedup = vec![]; - - for w in all_paths.as_slice().windows(2) { - if let [a, b, ..] = w { - if !b.starts_with(a) { - dedup.push(a.to_owned()); - } - } - } - - let dedup = all_paths; - - let options = glob::MatchOptions { - case_sensitive: true, - require_literal_separator: true, - require_literal_leading_dot: true, - }; - - if let Some(cp) = args.value_of("check-permission") { - let pattern = glob::Pattern::new(cp)?; - - let mut allowed = !dedup.is_empty(); - for d in dedup.iter() { - let d = std::path::PathBuf::from(d); - let m = pattern.matches_path_with(&d, options); - if !m { - allowed = false; - println!("missing permission for: {:?}", &d); - } - } - println!("Allowed = {:?}", allowed); - } - if reverse { let new = repo.revparse_single(target).unwrap().id(); let old = repo.revparse_single("JOSH_TMP").unwrap().id(); diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 96c96202b..e8500f732 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -29,10 +29,15 @@ impl std::fmt::Debug for Filter { return to_op(*self).fmt(f); } } + pub fn nop() -> Filter { to_filter(Op::Nop) } +pub fn empty() -> Filter { + to_filter(Op::Empty) +} + fn to_filter(op: Op) -> Filter { let s = format!("{:?}", op); let f = Filter( @@ -767,6 +772,20 @@ fn compute_warnings2<'a>( warnings } +pub fn make_permissions_filter(filter: Filter, whitelist: Filter, blacklist: Filter) -> Filter { + rs_tracing::trace_scoped!("make_permissions_filter"); + + let filter = chain(to_filter(Op::Paths), filter); + let filter = chain(filter, to_filter(Op::Invert)); + let filter = chain( + filter, + compose(blacklist, to_filter(Op::Subtract(nop(), whitelist))), + ); + let filter = opt::optimize(filter); + + return filter; +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/housekeeping.rs b/src/housekeeping.rs index 6c98a56c4..b762a5eca 100644 --- a/src/housekeeping.rs +++ b/src/housekeeping.rs @@ -227,7 +227,7 @@ pub fn refresh_known_filters( upstream_repo, ); - updated_count += filter_refs(&t, filter::parse(filter_spec)?, &refs)?; + updated_count += filter_refs(&t, filter::parse(filter_spec)?, &refs, filter::empty())?; } info!("updated {} refs for {:?}", updated_count, upstream_repo); } diff --git a/src/lib.rs b/src/lib.rs index e4d0f44f4..b981f18f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,9 @@ extern crate pest_derive; #[macro_use] extern crate serde_json; +use std::collections::HashMap; +use tracing; + pub mod cache; pub mod filter; pub mod graphql; @@ -166,12 +169,34 @@ pub fn filter_ref( filterobj: filter::Filter, from_refsname: &str, to_refname: &str, + permissions: filter::Filter, ) -> JoshResult { let mut updated_count = 0; if let Ok(reference) = transaction.repo().revparse_single(from_refsname) { let original_commit = reference.peel_to_commit()?; let oid = original_commit.id(); + let perms_commit = if let Some(s) = transaction.get_ref(permissions, oid) { + s + } else { + tracing::trace!("apply_to_commit (permissions)"); + + filter::apply_to_commit(permissions, &original_commit, &transaction)? + }; + + if perms_commit != git2::Oid::zero() { + let perms_commit = transaction.repo().find_commit(perms_commit)?; + if !perms_commit.tree()?.is_empty() || perms_commit.parents().len() > 0 { + tracing::event!( + tracing::Level::WARN, + msg = "filter_refs: missing permissions for ref", + warn = true, + reference = from_refsname, + ); + return Err(josh_error("missing permissions for ref")); + } + } + let filter_commit = if let Some(s) = transaction.get_ref(filterobj, oid) { s } else { @@ -226,6 +251,7 @@ pub fn filter_refs( transaction: &cache::Transaction, filterobj: filter::Filter, refs: &[(String, String)], + permissions: filter::Filter, ) -> JoshResult { rs_tracing::trace_scoped!("filter_refs", "spec": filter::spec(filterobj)); let s = tracing::Span::current(); @@ -235,7 +261,7 @@ pub fn filter_refs( let mut updated_count = 0; for (k, v) in refs { - updated_count += ok_or!(filter_ref(transaction, filterobj, k, v), { + updated_count += ok_or!(filter_ref(&transaction, filterobj, &k, &v, permissions), { tracing::event!( tracing::Level::WARN, msg = "filter_refs: Can't filter reference", @@ -275,3 +301,64 @@ pub fn normalize_path(path: &std::path::Path) -> std::path::PathBuf { } ret } + +type Users = HashMap; + +#[derive(Debug, serde::Deserialize)] +struct User { + pub groups: toml::value::Array, +} + +type Groups = HashMap>; +#[derive(Debug, serde::Deserialize)] +struct Group { + pub whitelist: String, + pub blacklist: String, +} + +pub fn get_acl( + users: &str, + groups: &str, + user: &str, + repo: &str, +) -> JoshResult<(filter::Filter, filter::Filter)> { + let users = + std::fs::read_to_string(users).map_err(|_| josh_error("failed to read users file"))?; + let users: Users = serde_yaml::from_str(&users) + .map_err(|err| josh_error(format!("failed to parse users file: {}", err).as_str()))?; + let groups = + std::fs::read_to_string(groups).map_err(|_| josh_error("failed to read groups file"))?; + let groups: Groups = serde_yaml::from_str(&groups) + .map_err(|err| josh_error(format!("failed to parse groups file: {}", err).as_str()))?; + + return users + .get(user) + .and_then(|u| { + let mut whitelist = filter::empty(); + let mut blacklist = filter::empty(); + for g in &u.groups { + let lists = groups.get(repo).and_then(|repo| { + repo.get(g.as_str()?).and_then(|group| { + let w = filter::parse(&group.whitelist); + let b = filter::parse(&group.blacklist); + Some((w, b)) + }) + })?; + if let Err(e) = lists.0 { + return Some(Err(JoshError(format!("Error parsing whitelist: {}", e)))); + } + if let Err(e) = lists.1 { + return Some(Err(JoshError(format!("Error parsing blacklist: {}", e)))); + } + if let Ok(w) = lists.0 { + whitelist = filter::compose(whitelist, w); + } + if let Ok(b) = lists.1 { + blacklist = filter::compose(blacklist, b); + } + } + println!("w: {:?}, b: {:?}", whitelist, blacklist); + Some(Ok((whitelist, blacklist))) + }) + .unwrap_or(Ok((filter::empty(), filter::nop()))); +} diff --git a/tests/filter/empty_head.t b/tests/filter/empty_head.t index 35385debf..a139652cd 100644 --- a/tests/filter/empty_head.t +++ b/tests/filter/empty_head.t @@ -35,6 +35,7 @@ $ git commit -m "add file5" 1> /dev/null $ josh-filter -s :/sub2 master --update refs/josh/filter/master + Warning: reference refs/josh/filter/master wasn't updated [2] :/sub1 [2] :/sub2 $ git log --graph --pretty=%s josh/filter/master diff --git a/tests/filter/infofile.t b/tests/filter/infofile.t index cf3a99758..45c21ac84 100644 --- a/tests/filter/infofile.t +++ b/tests/filter/infofile.t @@ -30,6 +30,7 @@ * add file1 $ josh-filter -s c=:/sub1 master --update refs/josh/filter/master + Warning: reference refs/josh/filter/master wasn't updated [2] :/sub1 [2] :prefix=c $ git log --graph --pretty=%s josh/filter/master @@ -48,6 +49,7 @@ $ git commit -m "add file5" 1> /dev/null $ josh-filter -s c=:/sub2 master --update refs/josh/filter/master + Warning: reference refs/josh/filter/master wasn't updated [2] :/sub1 [2] :/sub2 [3] :prefix=c diff --git a/tests/filter/permissions/cli.t b/tests/filter/permissions/cli.t new file mode 100644 index 000000000..ec62c8a6f --- /dev/null +++ b/tests/filter/permissions/cli.t @@ -0,0 +1,122 @@ + $ export TESTTMP=${PWD} + + $ . ${TESTDIR}/setup_repo.sh + +# default permissions give everything + $ josh-filter -s :/ master --check-permission --update refs/josh/filtered + + $ git checkout refs/josh/filtered 2> /dev/null + $ tree + . + |-- a + | |-- file_a2 + | `-- workspace.josh + |-- b + | `-- file_b1 + `-- c + `-- d + |-- e + | `-- file_cd3 + |-- file_cd + `-- file_cd2 + + 5 directories, 6 files + + +# default same as this + $ josh-filter -s :/ master --check-permission -b :empty -w :nop --update refs/josh/filtered_2 + + $ git checkout refs/josh/filtered 2> /dev/null + $ tree + . + |-- a + | |-- file_a2 + | `-- workspace.josh + |-- b + | `-- file_b1 + `-- c + `-- d + |-- e + | `-- file_cd3 + |-- file_cd + `-- file_cd2 + + 5 directories, 6 files + + +# no permissions + $ josh-filter -s :/ master --check-permission -b :nop -w :empty --update refs/josh/filtered + [3] :INVERT + [3] :PATHS + [12] _invert + [16] _paths + ERROR: JoshError("missing permissions for ref") + [1] + $ josh-filter -s :/b master --check-permission -w ::a/ --update refs/josh/filtered + [1] :/a + [1] :/b + [1] :subtract[ + :/ + ::a/ + ] + [3] :PATHS + [4] :INVERT + [13] _invert + [16] _paths + ERROR: JoshError("missing permissions for ref") + [1] + + + $ josh-filter -s :/b master --check-permission -b ::b/ -w ::b/ --update refs/josh/filtered + [1] :/a + [1] :[ + ::b/ + :subtract[ + :/ + ::b/ + ] + ] + [1] :prefix=b + [1] :subtract[ + :/ + ::a/ + ] + [1] :subtract[ + :/ + ::b/ + ] + [2] :/b + [3] :PATHS + [4] :INVERT + [13] _invert + [16] _paths + ERROR: JoshError("missing permissions for ref") + [1] + + +# access granted + $ josh-filter -s :/b master --check-permission -w ::b/ --update refs/josh/filtered + [1] :/a + [1] :[ + ::b/ + :subtract[ + :/ + ::b/ + ] + ] + [1] :prefix=b + [1] :subtract[ + :/ + ::a/ + ] + [1] :subtract[ + :/ + ::b/ + ] + [3] :/b + [3] :PATHS + [4] :INVERT + [13] _invert + [16] _paths + + diff --git a/tests/filter/permissions.t b/tests/filter/permissions/filters.t similarity index 86% rename from tests/filter/permissions.t rename to tests/filter/permissions/filters.t index eb1ca2e9b..b9fedc392 100644 --- a/tests/filter/permissions.t +++ b/tests/filter/permissions/filters.t @@ -1,40 +1,6 @@ $ export TESTTMP=${PWD} - $ cd ${TESTTMP} - $ git init 1> /dev/null - - $ mkdir a - $ echo "cws = :/c" > a/workspace.josh - $ echo contents1 > a/file_a2 - $ git add a - - $ mkdir b - $ echo contents1 > b/file_b1 - $ git add b - - $ mkdir -p c/d - $ echo contents1 > c/d/file_cd - $ git add c - $ git commit -m "add dirs" 1> /dev/null - - $ echo contents2 > c/d/file_cd2 - $ git add c - $ git commit -m "add file_cd2" 1> /dev/null - - $ mkdir -p c/d/e - $ echo contents2 > c/d/e/file_cd3 - $ git add c - $ git commit -m "add file_cd3" 1> /dev/null - - $ echo contents3 >> c/d/e/file_cd3 - $ git add c - $ git commit -m "edit file_cd3" 1> /dev/null - - $ git log --graph --pretty=%s - * edit file_cd3 - * add file_cd3 - * add file_cd2 - * add dirs + $ . ${TESTDIR}/setup_repo.sh $ josh-filter -s :PATHS master --update refs/josh/filtered [3] :PATHS @@ -259,56 +225,10 @@ `-- file_cd2 5 directories, 6 files - - $ git diff $EMPTY_TREE HEAD - diff --git a/a/file_a2 b/a/file_a2 - new file mode 100644 - index 0000000..4b2f88e - --- /dev/null - +++ b/a/file_a2 - @@ -0,0 +1 @@ - +a/file_a2 - \ No newline at end of file - diff --git a/a/workspace.josh b/a/workspace.josh - new file mode 100644 - index 0000000..b5fbe37 - --- /dev/null - +++ b/a/workspace.josh - @@ -0,0 +1 @@ - +a/workspace.josh - \ No newline at end of file - diff --git a/b/file_b1 b/b/file_b1 - new file mode 100644 - index 0000000..413b4ca - --- /dev/null - +++ b/b/file_b1 - @@ -0,0 +1 @@ - +b/file_b1 - \ No newline at end of file - diff --git a/c/d/e/file_cd3 b/c/d/e/file_cd3 - new file mode 100644 - index 0000000..8719808 - --- /dev/null - +++ b/c/d/e/file_cd3 - @@ -0,0 +1 @@ - +c/d/e/file_cd3 - \ No newline at end of file - diff --git a/c/d/file_cd b/c/d/file_cd - new file mode 100644 - index 0000000..bb36c67 - --- /dev/null - +++ b/c/d/file_cd - @@ -0,0 +1 @@ - +c/d/file_cd - \ No newline at end of file - diff --git a/c/d/file_cd2 b/c/d/file_cd2 - new file mode 100644 - index 0000000..26318eb - --- /dev/null - +++ b/c/d/file_cd2 - @@ -0,0 +1 @@ - +c/d/file_cd2 - \ No newline at end of file + $ cat a/file_a2 + a/file_a2 (no-eol) + $ cat b/file_b1 + b/file_b1 (no-eol) $ josh-filter -s :PATHS:workspace=a:INVERT master --update refs/josh/filtered diff --git a/tests/filter/permissions/permissions.t b/tests/filter/permissions/permissions.t new file mode 100644 index 000000000..4a10d1686 --- /dev/null +++ b/tests/filter/permissions/permissions.t @@ -0,0 +1,713 @@ + $ export TESTTMP=${PWD} + + $ . ${TESTDIR}/setup_repo.sh + +# acl + $ cat << EOF > users.yaml + > LMG: + > groups: ["dev"] + > CSchilling: + > groups: ["dev2"] + > EOF + $ cat << EOF > groups.yaml + > test: + > dev: + > whitelist: ":/" + > blacklist: ":empty" + > dev2: + > blacklist: ":empty" + > whitelist: | + > :[ + > ::b/ + > ::a/ + > ] + > EOF + +# doesn't work + $ josh-filter -s :/ master --check-permission --users users.yaml --groups groups.yaml -u CSchilling -r test --update refs/josh/filtered + w: Compose([Chain(Subdir("a"), Prefix("a")), Chain(Subdir("b"), Prefix("b"))]), b: Empty + [1] :/a + [1] :/b + [1] :[ + ::a/ + ::b/ + ] + [1] :prefix=a + [1] :prefix=b + [3] :INVERT + [3] :PATHS + [3] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [12] _invert + [16] _paths + ERROR: JoshError("missing permissions for ref") + [1] + + $ josh-filter -s :/ master --check-permission --missing-permission --users users.yaml --groups groups.yaml -u CSchilling -r test --update refs/josh/filtered + w: Compose([Chain(Subdir("a"), Prefix("a")), Chain(Subdir("b"), Prefix("b"))]), b: Empty + [1] :/a + [1] :/b + [1] :[ + ::a/ + ::b/ + ] + [1] :prefix=a + [1] :prefix=b + [3] :INVERT + [3] :PATHS + [3] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [12] _invert + [16] _paths + $ git checkout refs/josh/filtered + Note: switching to 'refs/josh/filtered'. + + You are in 'detached HEAD' state. You can look around, make experimental + changes and commit them, and you can discard any commits you make in this + state without impacting any branches by switching back to a branch. + + If you want to create a new branch to retain commits you create, you may + do so (now or later) by using -c with the switch command. Example: + + git switch -c + + Or undo this operation with: + + git switch - + + Turn off this advice by setting config variable advice.detachedHead to false + + HEAD is now at c6749dc add file_cd3 + $ tree + . + |-- c + | `-- d + | |-- e + | | `-- file_cd3 + | |-- file_cd + | `-- file_cd2 + |-- groups.yaml + `-- users.yaml + + 3 directories, 5 files + $ cat b/file_b1 + cat: b/file_b1: No such file or directory + [1] + $ git log + commit c6749dc54b9f93d87e04e89900c0ca1e730c0ca4 + Author: Josh + Date: Thu Apr 7 22:13:13 2005 +0000 + + add file_cd3 + + commit 58bed947100bda96f7b2a90df2623e1cdee685e5 + Author: Josh + Date: Thu Apr 7 22:13:13 2005 +0000 + + add file_cd2 + + commit 838b5164aff95c891164bfc0ed8611dc008c39ea + Author: Josh + Date: Thu Apr 7 22:13:13 2005 +0000 + + add dirs + +# works + $ josh-filter -s :[::b/,::a/] master --check-permission --users users.yaml --groups groups.yaml -u CSchilling -r test --update refs/josh/filtered + w: Compose([Chain(Subdir("a"), Prefix("a")), Chain(Subdir("b"), Prefix("b"))]), b: Empty + [2] :prefix=b + [3] :PATHS + [3] :prefix=a + [4] :/a + [4] :/b + [4] :INVERT + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [13] _invert + [16] _paths + $ git checkout refs/josh/filtered + Warning: you are leaving 3 commits behind, not connected to + any of your branches: + + c6749dc add file_cd3 + 58bed94 add file_cd2 + 838b516 add dirs + + If you want to keep them by creating a new branch, this may be a good time + to do so with: + + git branch c6749dc + + HEAD is now at 3259647 add dirs + $ tree + . + |-- a + | |-- file_a2 + | `-- workspace.josh + |-- b + | `-- file_b1 + |-- groups.yaml + `-- users.yaml + + 2 directories, 5 files + $ cat b/file_b1 + contents1 + $ josh-filter -s :[::b/,::a/] master --check-permission --missing-permission --users users.yaml --groups groups.yaml -u CSchilling -r test --update refs/josh/filtered + w: Compose([Chain(Subdir("a"), Prefix("a")), Chain(Subdir("b"), Prefix("b"))]), b: Empty + [2] :prefix=b + [3] :PATHS + [3] :prefix=a + [4] :/a + [4] :/b + [4] :INVERT + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [13] _invert + [16] _paths + $ git checkout refs/josh/filtered + HEAD is now at 3259647 add dirs + $ tree + . + |-- a + | |-- file_a2 + | `-- workspace.josh + |-- b + | `-- file_b1 + |-- groups.yaml + `-- users.yaml + + 2 directories, 5 files + $ git log + commit 3259647798774e12c657ea4cb057c61b1233165a + Author: Josh + Date: Thu Apr 7 22:13:13 2005 +0000 + + add dirs + $ cat b/file_b1 + contents1 +# doesn't work + $ josh-filter -s :/ master --check-permission --users users.yaml --groups groups.yaml -u bob -r test --update refs/josh/filtered + [2] :prefix=b + [3] :PATHS + [3] :prefix=a + [4] :/a + [4] :/b + [4] :INVERT + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [13] _invert + [16] _paths + ERROR: JoshError("missing permissions for ref") + [1] +# works + $ josh-filter -s :/ master --check-permission --users users.yaml --groups groups.yaml -u LMG -r test --update refs/josh/filtered + w: Nop, b: Empty + [2] :prefix=b + [3] :PATHS + [3] :prefix=a + [4] :/a + [4] :/b + [4] :INVERT + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [13] _invert + [16] _paths + + $ git diff $EMPTY_TREE HEAD + diff --git a/a/file_a2 b/a/file_a2 + new file mode 100644 + index 0000000..a024003 + --- /dev/null + +++ b/a/file_a2 + @@ -0,0 +1 @@ + +contents1 + diff --git a/a/workspace.josh b/a/workspace.josh + new file mode 100644 + index 0000000..3af54d0 + --- /dev/null + +++ b/a/workspace.josh + @@ -0,0 +1 @@ + +cws = :/c + diff --git a/b/file_b1 b/b/file_b1 + new file mode 100644 + index 0000000..a024003 + --- /dev/null + +++ b/b/file_b1 + @@ -0,0 +1 @@ + +contents1 + + + $ josh-filter -s :PATHS:workspace=a:INVERT master --update refs/josh/filtered + [2] :prefix=b + [3] :PATHS + [3] :prefix=a + [3] :workspace=a + [4] :/a + [4] :/b + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [7] :INVERT + [16] _paths + [23] _invert + + $ git checkout refs/josh/filtered 2> /dev/null + $ tree + . + |-- a + | |-- file_a2 + | `-- workspace.josh + |-- c + | `-- d + | |-- e + | | `-- file_cd3 + | |-- file_cd + | `-- file_cd2 + |-- groups.yaml + `-- users.yaml + + 4 directories, 7 files + + $ git diff $EMPTY_TREE HEAD + diff --git a/a/file_a2 b/a/file_a2 + new file mode 100644 + index 0000000..ee73843 + --- /dev/null + +++ b/a/file_a2 + @@ -0,0 +1 @@ + +file_a2 + \ No newline at end of file + diff --git a/a/workspace.josh b/a/workspace.josh + new file mode 100644 + index 0000000..0ab7ce1 + --- /dev/null + +++ b/a/workspace.josh + @@ -0,0 +1 @@ + +workspace.josh + \ No newline at end of file + diff --git a/c/d/e/file_cd3 b/c/d/e/file_cd3 + new file mode 100644 + index 0000000..ed74419 + --- /dev/null + +++ b/c/d/e/file_cd3 + @@ -0,0 +1 @@ + +cws/d/e/file_cd3 + \ No newline at end of file + diff --git a/c/d/file_cd b/c/d/file_cd + new file mode 100644 + index 0000000..7afa8f7 + --- /dev/null + +++ b/c/d/file_cd + @@ -0,0 +1 @@ + +cws/d/file_cd + \ No newline at end of file + diff --git a/c/d/file_cd2 b/c/d/file_cd2 + new file mode 100644 + index 0000000..4fbc84d + --- /dev/null + +++ b/c/d/file_cd2 + @@ -0,0 +1 @@ + +cws/d/file_cd2 + \ No newline at end of file + + $ josh-filter -s :PATHS:FOLD master --update refs/josh/filtered + [2] :prefix=b + [3] :FOLD + [3] :PATHS + [3] :prefix=a + [3] :workspace=a + [4] :/a + [4] :/b + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [7] :INVERT + [16] _paths + [23] _invert + + + + $ git checkout master 2> /dev/null + $ git rm -r c/d + rm 'c/d/e/file_cd3' + rm 'c/d/file_cd' + rm 'c/d/file_cd2' + $ git commit -m "rm" 1> /dev/null + + $ echo contents2 > a/newfile + $ git add a + $ git commit -m "add newfile" 1> /dev/null + + $ josh-filter -s :PATHS master --update refs/josh/filtered + [2] :prefix=b + [3] :FOLD + [3] :prefix=a + [3] :workspace=a + [4] :/a + [4] :/b + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [5] :PATHS + [7] :INVERT + [19] _paths + [23] _invert + + $ git log --graph --pretty=%s master + * add newfile + * rm + * edit file_cd3 + * add file_cd3 + * add file_cd2 + * add dirs + + $ git log --graph --pretty=%s refs/josh/filtered + * add newfile + * rm + * add file_cd3 + * add file_cd2 + * add dirs + + $ git checkout refs/josh/filtered 2> /dev/null + $ tree + . + |-- a + | |-- file_a2 + | |-- newfile + | `-- workspace.josh + |-- b + | `-- file_b1 + |-- groups.yaml + `-- users.yaml + + 2 directories, 6 files + + $ git diff $EMPTY_TREE HEAD + diff --git a/a/file_a2 b/a/file_a2 + new file mode 100644 + index 0000000..4b2f88e + --- /dev/null + +++ b/a/file_a2 + @@ -0,0 +1 @@ + +a/file_a2 + \ No newline at end of file + diff --git a/a/newfile b/a/newfile + new file mode 100644 + index 0000000..17b95ba + --- /dev/null + +++ b/a/newfile + @@ -0,0 +1 @@ + +a/newfile + \ No newline at end of file + diff --git a/a/workspace.josh b/a/workspace.josh + new file mode 100644 + index 0000000..c9acb10 + --- /dev/null + +++ b/a/workspace.josh + @@ -0,0 +1,2 @@ + +#a/workspace.josh + +cws = :/c + diff --git a/b/file_b1 b/b/file_b1 + new file mode 100644 + index 0000000..413b4ca + --- /dev/null + +++ b/b/file_b1 + @@ -0,0 +1 @@ + +b/file_b1 + \ No newline at end of file + + + $ git log --graph --pretty=%s refs/josh/filtered + * add newfile + * rm + * add file_cd3 + * add file_cd2 + * add dirs + + $ git checkout refs/josh/filtered 2> /dev/null + $ tree + . + |-- a + | |-- file_a2 + | |-- newfile + | `-- workspace.josh + |-- b + | `-- file_b1 + |-- groups.yaml + `-- users.yaml + + 2 directories, 6 files + + $ git diff $EMPTY_TREE HEAD + diff --git a/a/file_a2 b/a/file_a2 + new file mode 100644 + index 0000000..4b2f88e + --- /dev/null + +++ b/a/file_a2 + @@ -0,0 +1 @@ + +a/file_a2 + \ No newline at end of file + diff --git a/a/newfile b/a/newfile + new file mode 100644 + index 0000000..17b95ba + --- /dev/null + +++ b/a/newfile + @@ -0,0 +1 @@ + +a/newfile + \ No newline at end of file + diff --git a/a/workspace.josh b/a/workspace.josh + new file mode 100644 + index 0000000..c9acb10 + --- /dev/null + +++ b/a/workspace.josh + @@ -0,0 +1,2 @@ + +#a/workspace.josh + +cws = :/c + diff --git a/b/file_b1 b/b/file_b1 + new file mode 100644 + index 0000000..413b4ca + --- /dev/null + +++ b/b/file_b1 + @@ -0,0 +1 @@ + +b/file_b1 + \ No newline at end of file + + + + $ josh-filter -s :PATHS:/c:FOLD master --update refs/josh/filtered + [2] :prefix=b + [3] :prefix=a + [3] :workspace=a + [4] :/a + [4] :/b + [4] :/c + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [5] :PATHS + [6] :FOLD + [7] :INVERT + [19] _paths + [23] _invert + + $ git log --graph --pretty=%s refs/josh/filtered + * add file_cd3 + * add file_cd2 + * add dirs + + $ git checkout refs/josh/filtered 2> /dev/null + $ tree + . + |-- d + | |-- e + | | `-- file_cd3 + | |-- file_cd + | `-- file_cd2 + |-- groups.yaml + `-- users.yaml + + 2 directories, 5 files + + $ git diff $EMPTY_TREE HEAD + diff --git a/d/e/file_cd3 b/d/e/file_cd3 + new file mode 100644 + index 0000000..8719808 + --- /dev/null + +++ b/d/e/file_cd3 + @@ -0,0 +1 @@ + +c/d/e/file_cd3 + \ No newline at end of file + diff --git a/d/file_cd b/d/file_cd + new file mode 100644 + index 0000000..bb36c67 + --- /dev/null + +++ b/d/file_cd + @@ -0,0 +1 @@ + +c/d/file_cd + \ No newline at end of file + diff --git a/d/file_cd2 b/d/file_cd2 + new file mode 100644 + index 0000000..26318eb + --- /dev/null + +++ b/d/file_cd2 + @@ -0,0 +1 @@ + +c/d/file_cd2 + \ No newline at end of file + + + + $ josh-filter -s :PATHS:workspace=a:FOLD master --update refs/josh/filtered + [2] :prefix=b + [3] :prefix=a + [4] :/a + [4] :/b + [4] :/c + [4] :[ + ::a/ + ::b/ + ] + [4] :subtract[ + :/ + :[ + ::a/ + ::b/ + ] + ] + [5] :PATHS + [5] :workspace=a + [7] :INVERT + [10] :FOLD + [19] _paths + [23] _invert + + $ git log --graph --pretty=%s refs/josh/filtered + * add newfile + * add file_cd3 + * add file_cd2 + * add dirs + + $ git checkout refs/josh/filtered 2> /dev/null + $ tree + . + |-- cws + | `-- d + | |-- e + | | `-- file_cd3 + | |-- file_cd + | `-- file_cd2 + |-- file_a2 + |-- groups.yaml + |-- newfile + |-- users.yaml + `-- workspace.josh + + 3 directories, 8 files + + $ git diff $EMPTY_TREE HEAD + diff --git a/cws/d/e/file_cd3 b/cws/d/e/file_cd3 + new file mode 100644 + index 0000000..8719808 + --- /dev/null + +++ b/cws/d/e/file_cd3 + @@ -0,0 +1 @@ + +c/d/e/file_cd3 + \ No newline at end of file + diff --git a/cws/d/file_cd b/cws/d/file_cd + new file mode 100644 + index 0000000..bb36c67 + --- /dev/null + +++ b/cws/d/file_cd + @@ -0,0 +1 @@ + +c/d/file_cd + \ No newline at end of file + diff --git a/cws/d/file_cd2 b/cws/d/file_cd2 + new file mode 100644 + index 0000000..26318eb + --- /dev/null + +++ b/cws/d/file_cd2 + @@ -0,0 +1 @@ + +c/d/file_cd2 + \ No newline at end of file + diff --git a/file_a2 b/file_a2 + new file mode 100644 + index 0000000..4b2f88e + --- /dev/null + +++ b/file_a2 + @@ -0,0 +1 @@ + +a/file_a2 + \ No newline at end of file + diff --git a/newfile b/newfile + new file mode 100644 + index 0000000..17b95ba + --- /dev/null + +++ b/newfile + @@ -0,0 +1 @@ + +a/newfile + \ No newline at end of file + diff --git a/workspace.josh b/workspace.josh + new file mode 100644 + index 0000000..c9acb10 + --- /dev/null + +++ b/workspace.josh + @@ -0,0 +1,2 @@ + +#a/workspace.josh + +cws = :/c + diff --git a/tests/filter/permissions/setup_repo.sh b/tests/filter/permissions/setup_repo.sh new file mode 100644 index 000000000..bd8e5d47d --- /dev/null +++ b/tests/filter/permissions/setup_repo.sh @@ -0,0 +1,29 @@ +cd ${TESTTMP} +git init 1> /dev/null + +mkdir a +echo "cws = :/c" > a/workspace.josh +echo contents1 > a/file_a2 +git add a + +mkdir b +echo contents1 > b/file_b1 +git add b + +mkdir -p c/d +echo contents1 > c/d/file_cd +git add c +git commit -m "add dirs" 1> /dev/null + +echo contents2 > c/d/file_cd2 +git add c +git commit -m "add file_cd2" 1> /dev/null + +mkdir -p c/d/e +echo contents2 > c/d/e/file_cd3 +git add c +git commit -m "add file_cd3" 1> /dev/null + +echo contents3 >> c/d/e/file_cd3 +git add c +git commit -m "edit file_cd3" 1> /dev/null diff --git a/tests/filter/submodule.t b/tests/filter/submodule.t index fda41c6f9..6f20c01ca 100644 --- a/tests/filter/submodule.t +++ b/tests/filter/submodule.t @@ -27,6 +27,7 @@ [1] :/libs $ git ls-tree --name-only -r refs/josh/filter/master $ josh-filter -s c=:/libs master --update refs/josh/filter/master + Warning: reference refs/josh/filter/master wasn't updated [1] :/libs [1] :prefix=c $ git ls-tree --name-only -r refs/josh/filter/master