From 6e2db1230211697091d724cf2483384e9e3a2234 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 21 Aug 2010 09:56:11 +0530 Subject: [PATCH] allow @groups in setperms command also This should hopefully be the final step in making wildrepos as close to normal repos as possible. You can now do pretty much anything with them that you can do with normal repos [1] Implementation notes: - compile puts out %groups into the compiled config file regardless of GL_BIG_CONFIG because this feature needs it - wild_repo_rights caches %groups because the part of the %groups hash we care about will not change between calls in the same run ---- [1] **except** use the full-blown config file syntax within the gl-perms file :-) I don't plan to do that; it's too complicated! [2] [2] yeah yeah I know -- famous last words! --- src/gitolite.pm | 65 ++++++++++++++++-------- src/gl-compile-conf | 2 +- t/out/t01-repo-groups.1b | 105 +++++++++++++++++++++++++++++++++++++++ t/out/t02-user-groups.1b | 80 +++++++++++++++++++++++++++++ t/t01-repo-groups | 2 +- t/t02-user-groups | 2 +- t/t61-setperms-wild | 72 +++++++++++++++++++++++++++ 7 files changed, 305 insertions(+), 23 deletions(-) create mode 100644 t/out/t01-repo-groups.1b create mode 100644 t/out/t02-user-groups.1b create mode 100644 t/t61-setperms-wild diff --git a/src/gitolite.pm b/src/gitolite.pm index e0c2af4..e78c882 100644 --- a/src/gitolite.pm +++ b/src/gitolite.pm @@ -255,28 +255,53 @@ sub new_repo # metaphysics (like, "is there a god?", "who created me?", etc) # ---------------------------------------------------------------------------- -# "who created this repo", "am I on the R list", and "am I on the RW list"? -sub wild_repo_rights { - my ($repo, $user) = @_; - # creator - my $c = ''; - if ( -f "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-creater") { - my $fh = wrap_open("<", "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-creater"); - chomp($c = <$fh>); - } - # $user's R and W rights - my ($r, $w); $r = ''; $w = ''; - if ($user and -f "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-perms") { - my $fh = wrap_open("<", "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-perms"); - my $perms = join ("", <$fh>); - if ($perms) { - $r = $user if $perms =~ /^\s*R(?=\s).*\s(\@all|$user)(\s|$)/m; - $w = $user if $perms =~ /^\s*RW(?=\s).*\s(\@all|$user)(\s|$)/m; - } - } + # the following sub needs some persistent data, so we make a closure + my $cache_filled = 0; + my %cached_groups; - return ($c, $r, $w); + # "who created this repo", "am I on the R list", and "am I on the RW list"? + sub wild_repo_rights + { + my ($repo, $user) = @_; + # pull in basic group info + unless ($cache_filled) { + local(%repos, %groups); + # read group info from compiled config. At the time we're called + # this info has not yet been pulled in by the rest of the code, so + # we need to do this specially here. However, the info we're + # looking for is not subject to variable substitutions so we don't + # really care; we just pull it in once and save it for the rest of + # the run + do $GL_CONF_COMPILED; + %cached_groups = %groups; + $cache_filled++; + } + # creator + my $c = ''; + if ( -f "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-creater") { + my $fh = wrap_open("<", "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-creater"); + chomp($c = <$fh>); + } + # $user's R and W rights + my ($r, $w); $r = ''; $w = ''; + if ($user and -f "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-perms") { + my $fh = wrap_open("<", "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-perms"); + my $perms = join ("", <$fh>); + # $perms is say "R alice @foo @bar\nRW bob @baz" (the entire gl-perms + # file). We replace each @foo with $user if $cached_groups{'@foo'}{$user} + # exists (i.e., $user is a member of @foo) + for my $g ($perms =~ /\s(\@\S+)/g) { + $perms =~ s/ $g(?!\S)/ $user/ if $cached_groups{$g}{$user}; + } + if ($perms) { + $r = $user if $perms =~ /^\s*R(?=\s).*\s(\@all|$user)(\s|$)/m; + $w = $user if $perms =~ /^\s*RW(?=\s).*\s(\@all|$user)(\s|$)/m; + } + } + + return ($c, $r, $w); + } } # ---------------------------------------------------------------------------- diff --git a/src/gl-compile-conf b/src/gl-compile-conf index a128dc8..0ccd7d5 100755 --- a/src/gl-compile-conf +++ b/src/gl-compile-conf @@ -393,7 +393,7 @@ $dumped_data .= Data::Dumper->Dump([\%repo_config], [qw(*repo_config)]) if %repo # much... $dumped_data =~ s/'(?=[^']*\$(?:creator|readers|writers|gl_user))~?(.*?)'/"$1"/g; print $compiled_fh $dumped_data; -if ($GL_BIG_CONFIG and %groups) { +if (%groups) { $dumped_data = Data::Dumper->Dump([\%groups], [qw(*groups)]); $dumped_data =~ s/\bCREAT[EO]R\b/\$creator/g; $dumped_data =~ s/'(?=[^']*\$(?:creator|readers|writers|gl_user))~?(.*?)'/"$1"/g; diff --git a/t/out/t01-repo-groups.1b b/t/out/t01-repo-groups.1b new file mode 100644 index 0000000..dac62f2 --- /dev/null +++ b/t/out/t01-repo-groups.1b @@ -0,0 +1,105 @@ +$data_version = '1.5'; +%repos = ( + 'aa' => { + 'R' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'W' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'u1' => [ + [ + 2, + 'refs/.*', + 'RW+' + ] + ], + 'u2' => [ + [ + 4, + 'refs/.*', + 'RW' + ] + ], + 'u3' => [ + [ + 5, + 'refs/.*', + 'RW' + ] + ] + }, + 'bb' => { + 'R' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'W' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'u1' => [ + [ + 3, + 'refs/.*', + 'RW+' + ] + ], + 'u2' => [ + [ + 6, + 'refs/.*', + 'RW' + ] + ], + 'u3' => [ + [ + 7, + 'refs/.*', + 'RW' + ] + ] + }, + 'gitolite-admin' => { + 'R' => { + 'tester' => 1 + }, + 'W' => { + 'tester' => 1 + }, + 'tester' => [ + [ + 0, + 'refs/.*', + 'RW+' + ] + ] + }, + 'testing' => { + '@all' => [ + [ + 1, + 'refs/.*', + 'RW+' + ] + ], + 'R' => { + '@all' => 1 + }, + 'W' => { + '@all' => 1 + } + } +); +%groups = ( + '@g1' => { + 'aa' => 'master', + 'bb' => 'master' + } +); diff --git a/t/out/t02-user-groups.1b b/t/out/t02-user-groups.1b new file mode 100644 index 0000000..cfae71a --- /dev/null +++ b/t/out/t02-user-groups.1b @@ -0,0 +1,80 @@ +$data_version = '1.5'; +%repos = ( + 'aa' => { + 'R' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'W' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'u1' => [ + [ + 2, + 'refs/.*', + 'RW+' + ] + ], + 'u2' => [ + [ + 3, + 'refs/.*', + 'RW' + ] + ], + 'u3' => [ + [ + 4, + 'refs/.*', + 'RW' + ] + ] + }, + 'gitolite-admin' => { + 'R' => { + 'tester' => 1 + }, + 'W' => { + 'tester' => 1 + }, + 'tester' => [ + [ + 0, + 'refs/.*', + 'RW+' + ] + ] + }, + 'testing' => { + '@all' => [ + [ + 1, + 'refs/.*', + 'RW+' + ] + ], + 'R' => { + '@all' => 1 + }, + 'W' => { + '@all' => 1 + } + } +); +%groups = ( + '@g1' => { + 'u1' => 'master' + }, + '@g2' => { + 'u2' => 'master', + 'u3' => 'master' + }, + '@g3' => { + 'u4' => 'master', + 'u5' => 'master', + 'u6' => 'master' + } +); diff --git a/t/t01-repo-groups b/t/t01-repo-groups index d738def..367e29d 100644 --- a/t/t01-repo-groups +++ b/t/t01-repo-groups @@ -26,7 +26,7 @@ echo " " | ugc catconf -expect_filesame $TESTDIR/out/t01-repo-groups.1 +expect_filesame $TESTDIR/out/t01-repo-groups.1b # ---------- $TESTDIR/rollback || die "rollback failed" diff --git a/t/t02-user-groups b/t/t02-user-groups index bc17e17..7b673cc 100644 --- a/t/t02-user-groups +++ b/t/t02-user-groups @@ -29,7 +29,7 @@ echo " " | ugc catconf -expect_filesame $TESTDIR/out/t02-user-groups.1 +expect_filesame $TESTDIR/out/t02-user-groups.1b # ---------- $TESTDIR/rollback || die "rollback failed" diff --git a/t/t61-setperms-wild b/t/t61-setperms-wild new file mode 100644 index 0000000..aa4d8c7 --- /dev/null +++ b/t/t61-setperms-wild @@ -0,0 +1,72 @@ +# vim: syn=sh: +for bc in 0 1 +do + cd $TESTDIR + $TESTDIR/rollback || die "rollback failed" + editrc GL_WILDREPOS 1 + editrc GL_BIG_CONFIG $bc + + name "INTERNAL" + echo " + @leads = u1 u2 + @devs = u1 u2 u3 u4 + + @gbar = bar/CREATOR/..* + repo @gbar + C = @leads + RW+ = CREATOR + RW = WRITERS + R = READERS + " | ugc + name "nothing set yet" + expect_push_ok "master -> master" + + name "u1 auto-creates a repo" + runlocal git ls-remote u1:bar/u1/try1 + expect "Initialized empty Git repository in /home/gitolite-test/repositories/bar/u1/try1.git/" + name "default permissions for u2 and u4" + runlocal ssh u1 expand + expect R.*W.*u1.*bar/u1/try1 + runlocal ssh u2 expand + notexpect R.*W.*u1.*bar/u1/try1 + runlocal ssh u4 expand + notexpect R.*W.*u1.*bar/u1/try1 + + name "@leads can RW try1" + echo RW @leads | runlocal ssh u1 setperms bar/u1/try1 + expect "RW @leads" + runlocal ssh u1 expand + expect R.*W.*u1.*bar/u1/try1 + runlocal ssh u2 expand + expect R.*W.*u1.*bar/u1/try1 + runlocal ssh u4 expand + notexpect R.*W.*u1.*bar/u1/try1 + + name "@devs can R try1" + echo R @devs | runlocal ssh u1 setperms bar/u1/try1 + expect "R @devs" + notexpect "RW @leads" + runlocal ssh u1 expand + expect R.*W.*u1.*bar/u1/try1 + runlocal ssh u2 expand + notexpect R.*W.*u1.*bar/u1/try1 + expect R.*u1.*bar/u1/try1 + runlocal ssh u4 expand + notexpect R.*W.*u1.*bar/u1/try1 + expect R.*u1.*bar/u1/try1 + + name "combo of previous 2" + printf "R @devs\nRW @leads\n" | runlocal ssh u1 setperms bar/u1/try1 + expect "R @devs" + expect "RW @leads" + runlocal ssh u1 expand + expect R.*W.*u1.*bar/u1/try1 + runlocal ssh u2 expand + expect R.*W.*u1.*bar/u1/try1 + runlocal ssh u4 expand + notexpect R.*W.*u1.*bar/u1/try1 + expect R.*u1.*bar/u1/try1 + + name "INTERNAL" + +done