diff --git a/doc/big-config.mkd b/doc/big-config.mkd index 440288b..69b5e46 100644 --- a/doc/big-config.mkd +++ b/doc/big-config.mkd @@ -4,6 +4,8 @@ In this document: * when/why do we need it? * how do we use it? + * access rules for groups + * access rules for individual repos (split config) * other optimisations * disabling various defaults * optimising the authkeys file @@ -18,10 +20,10 @@ In this document: ### when/why do we need it? A "big config" is anything that has a few thousand users and a few thousand -repos, organised into groups that are much smaller in number (like maybe a few -hundreds of repogroups and a few dozens of usergroups). +repos, resulting in a very large 'compiled' config file. -So let's say you have +To understand the problem, consider what happens if you have something like +this in your gitolite conf file: @wbr = lynx firefox @devs = alice bob @@ -30,15 +32,15 @@ So let's say you have RW+ next = @devs RW master = @devs -Gitolite internally translates this to +Without the 'big config' setting, gitolite internally translates this to: repo lynx firefox RW+ next = alice bob RW master = alice bob -Not just that -- it now generates the actual config rules once for each -user-repo-ref combination (there are 8 combinations above; the compiled config -file looks partly like this: +and then generates the actual config rules once for each user-repo-ref +combination (there are 8 combinations above); the compiled config file looks +somewhat like this: %repos = ( 'firefox' => { @@ -51,20 +53,28 @@ file looks partly like this: 'bob' => 1 }, 'alice' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 0, + 'refs/heads/next', + 'RW+' + ], + [ + 4, + 'refs/heads/master', + 'RW' + ] ], 'bob' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 1, + 'refs/heads/next', + 'RW+' + ], + [ + 5, + 'refs/heads/master', + 'RW' + ] ] }, 'lynx' => { @@ -77,54 +87,73 @@ file looks partly like this: 'bob' => 1 }, 'alice' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 2, + 'refs/heads/next', + 'RW+' + ], + [ + 6, + 'refs/heads/master', + 'RW' + ] ], 'bob' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 3, + 'refs/heads/next', + 'RW+' + ], + [ + 7, + 'refs/heads/master', + 'RW' + ] ] } ); Phew! -You can imagine what that does when you have 10,000 users and 10,000 repos. -Let's just say it's not pretty :) +Of course, the output is the same whether you used groups (like `@wbr` and +`@devs` in the example above) or listed the repos directly on the 'repo' +lines. + +Anyway, you can imagine what that does when you have 10,000 users and 10,000 +repos. Let's just say it's not pretty :) ### how do we use it? -Now, if you had all those 10,000 users and repos explicitly listed (no -groups), then there is no help. But if, like the above example, you had -groups like we used above, there is hope. - Just set $GL_BIG_CONFIG = 1; in the `~/.gitolite.rc` file on the server (see next section for more -variables). When you do that, and push this configuration, the compiled file -looks like this: +variables). When you do that, and push this configuration, one of two things +happens. + + + +#### access rules for groups + +If you used group names in the 'repo' lines (as in `repo @wbr`), then the +compiled config looks like this: %repos = ( '@wbr' => { '@devs' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 0, + 'refs/heads/next', + 'RW+' + ], + [ + 1, + 'refs/heads/master', + 'RW' + ] ], 'R' => { '@devs' => 1 @@ -132,7 +161,7 @@ looks like this: 'W' => { '@devs' => 1 } - }, + } ); %groups = ( '@devs' => { @@ -148,6 +177,62 @@ looks like this: That's a lot smaller, and allows orders of magintude more repos and groups to be supported. + + +#### access rules for individual repos (split config) + +If, on the other hand, you had the repos listed individually, (as in `repo +lynx firefox`), then the main config file would now look like this: + + %repos = (); + %split_conf = ( + 'firefox' => 1, + 'lynx' => 1 + ); + +And each individual repo's configuration would go its own directory. For +instance, `~/repositories/lynx.git/gl-conf` would look like this: + + %one_repo = ( + 'lynx' => { + 'R' => { + 'alice' => 1, + 'bob' => 1 + }, + 'W' => { + 'alice' => 1, + 'bob' => 1 + }, + 'alice' => [ + [ + 0, + 'refs/heads/next', + 'RW+' + ], + [ + 4, + 'refs/heads/master', + 'RW' + ] + ], + 'bob' => [ + [ + 1, + 'refs/heads/next', + 'RW+' + ], + [ + 5, + 'refs/heads/master', + 'RW' + ] + ] + } + ); + +That does not reduce the overall size of the repo config (because you did not +group the repos), but the main repo config is now even smaller! + ### other optimisations @@ -169,22 +254,18 @@ if you *do* have a large number of repositories, and do *not* use gitolite's support for gitweb or git-daemon access (see "[easier to specify gitweb description and gitweb/daemon access][gwd]" for details). This will save a lot of time when you push the gitolite-admin repo with changes. This variable -also control whether "git config" lines (such as `config hooks.emailprefix = +also controls whether "git config" lines (such as `config hooks.emailprefix = "[gitolite]"`) will be processed or not. -Setting this is relatively harmless to a normal installation, unlike the next -two variables :-) `GL_NO_CREATE_REPOS` and `GL_NO_SETUP_AUTHKEYS` are meant -for installations where some backend system already exists that does all the -actual repo creation, and all the authentication setup (ssh auth keys), -respectively. +You should be a lot more careful with `GL_NO_CREATE_REPOS` and +`GL_NO_SETUP_AUTHKEYS`. These are meant for installations where some backend +system already exists that does all the actual repo creation, (including +setting up the proper hooks -- very important for access control), and all the +authentication setup (ssh auth keys), respectively. Summary: Please **leave those two variables alone** unless you're initials are "JK" ;-) -Also note that using all 3 of the `GL_NO_*` variables will result in -*everything* after the config compile being skipped. In other words, gitolite -is being used **only** for its access control language. - #### optimising the authkeys file @@ -228,15 +309,29 @@ this (note the clever date command that always gets you last months log file!) ### what are the downsides? -There is one minor issue. +There are some downsides. The first one applies in all cases: -If you use the delegation feature, you can no longer define or extend -@groups in a fragment, for security reasons. It will also not let you use any -group other than the @fragname itself (specifically, groups which contained a -subset of the allowed @fragname, which would work normally, do not work now). + * If you use the delegation feature, you can no longer define or extend + @groups in a fragment, for security reasons. It will also not let you use + any group other than the @fragname itself (specifically, groups which + contained a subset of the allowed @fragname, which would work normally, do + not work now). -(If you didn't understand all that, you're probably not using delegation, so -feel free to ignore it!) + (If you didn't understand all that, you're probably not using delegation, + so feel free to ignore it!) + +The following apply if individual ("split") conf files are written, which in +turn only happens if you used repo names instead of group names on the `repo` +lines: + + * the compile (gitolite-admin push) is now slower, because it potentially + has to write a few thousand small files instead of one large one. Since + the compile should be relatively infrequent compared to developer access, + this is ok -- the main config file is parsed much faster now, so every hit + to the server will benefit. + + * we can no longer distinguish 'repo not found on disk' from 'you dont have + access'. They both now look like 'you dont have access'. @@ -298,10 +393,10 @@ path to this program, set `$GL_BIG_CONFIG` to 1, and that will be that. ### implementation notes -To understand how big-config works, we'll first look at how it works without -this setting. Think back to the example at the top, and assume 'alice' is -accessing the 'lynx' repo. The various rights are governed by the following -hash elements: +To understand how big-config works (at least when you're using grouped repos), +we'll first look at how it works without this setting. Think back to the +example at the top, and assume 'alice' is accessing the 'lynx' repo. The +various rights are governed by the following hash elements: # for the first level checks $repos{'lynx'}{'R'}{'alice'} = 1 diff --git a/src/gitolite.pm b/src/gitolite.pm index b6794e4..38dd13a 100644 --- a/src/gitolite.pm +++ b/src/gitolite.pm @@ -44,9 +44,14 @@ our ($REPO_UMASK, $GL_WILDREPOS, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $REPO_BASE our %repos; our %groups; our %git_configs; +our %split_conf;; our $data_version; our $current_data_version = '1.7'; +# the following are read in from individual repo's gl-conf files, if present +our %one_repo; +our %one_git_config; + # ---------------------------------------------------------------------------- # convenience subs # ---------------------------------------------------------------------------- @@ -180,33 +185,19 @@ sub ln_sf } } -# collect repo patterns for all %repos - -# for each repo passed (actual repos only please!), use either its own name if -# it exists as is in the repos hash, or find and use the pattern that matches - -sub collect_repo_patts +# list physical repos +sub list_phy_repos { - my $repos_p = shift; - my %repo_patts = (); + my @phy_repos; wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); for my $repo (`find . -type d -name "*.git"`) { chomp ($repo); $repo =~ s(\./(.*)\.git$)($1); - # the key has to be in the list, since the repo physically exists - # -- my($perm, $creator, $wild) = &repo_rights($repo); - # -- $repo_patts{$repo} = $wild || $repo; - # turns out we're not using the value anywhere, so no point wasting - # all those cycles getting all repos' rights, at least until a real - # use for it comes along. But when it does come along, remember that - # $wild is now a space separated list of matching patterns (or empty - # if no wild patterns matched $repo). It is NOT a single value - # anymore! - $repo_patts{$repo} = 1; + push @phy_repos, $repo; } - return %repo_patts; + return @phy_repos; } @@ -337,6 +328,7 @@ sub new_repo # really care; we just pull it in once and save it for the rest of # the run do $GL_CONF_COMPILED; + add_repo_conf($repo) if $repo; %cached_groups = %groups; $cache_filled++; } @@ -559,8 +551,6 @@ sub parse_acl %repos = %saved_repos; %groups = %saved_groups; } else { die "parse $GL_CONF_COMPILED failed: " . ($! or $@) unless do $GL_CONF_COMPILED; - $saved_crwu = "$creator,$perm_cats_sig,$gl_user"; - %saved_repos = %repos; %saved_groups = %groups; } unless (defined($data_version) and $data_version eq $current_data_version) { # this cannot happen for 'easy-install' cases, by the way... @@ -569,6 +559,9 @@ sub parse_acl die "parse $GL_CONF_COMPILED failed: " . ($! or $@) unless do $GL_CONF_COMPILED; } + $saved_crwu = "$creator,$perm_cats_sig,$gl_user"; + %saved_repos = %repos; %saved_groups = %groups; + add_repo_conf($repo) if $repo; # basic access reporting doesn't send $repo, and doesn't need to; you just # want the config dumped as is, really @@ -607,6 +600,17 @@ sub parse_acl return ($wild); } +# add repo conf from repo.git/gl-conf +sub add_repo_conf +{ + my ($repo) = shift; + return unless $split_conf{$repo}; + do "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-conf" or return; + $repos{$repo} = $one_repo{$repo}; + $git_configs{$repo} = $one_git_config{$repo}; +} + + # ---------------------------------------------------------------------------- # print a report of $user's basic permissions # ---------------------------------------------------------------------------- @@ -643,6 +647,8 @@ sub report_basic local $ENV{GL_USER} = $user; &parse_acl($GL_CONF_COMPILED, "", "CREATOR"); + # all we need is for 'keys %repos' to come up with all the names, so: + @repos{ keys %split_conf } = values %split_conf if %split_conf; # send back some useful info if no command was given &report_version($GL_ADMINDIR, $user); diff --git a/src/gl-auth-command b/src/gl-auth-command index e176d56..1af4232 100755 --- a/src/gl-auth-command +++ b/src/gl-auth-command @@ -38,6 +38,7 @@ our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT, $REPOPATT_PATT, $ADC_CMD_ARGS_PAT our %repos; our %groups; our %git_configs; +our %split_conf;; # the common setup module is in the same directory as this running program is my $bindir = $0; diff --git a/src/gl-compile-conf b/src/gl-compile-conf index 24e703c..3930b38 100755 --- a/src/gl-compile-conf +++ b/src/gl-compile-conf @@ -92,6 +92,9 @@ our %groups = (); # in between :) my %repos = (); +# repos whose ACLs don't make it into the main compiled config file +my %split_conf = (); + # rule sequence number my $rule_seq = 0; @@ -398,26 +401,31 @@ for my $fragment_file (glob("conf/fragments/*.conf")) parse_conf_file($fragment_file, $fragment); } -my $compiled_fh = wrap_open( ">", "$GL_CONF_COMPILED.new" ); -my $data_version = $current_data_version; -print $compiled_fh Data::Dumper->Dump([$data_version], [qw(*data_version)]); -my $dumped_data = Data::Dumper->Dump([\%repos], [qw(*repos)]); -$dumped_data .= Data::Dumper->Dump([\%git_configs], [qw(*git_configs)]) if %git_configs; -# the dump uses single quotes, but we convert any strings containing $creator -# and $gl_user to double quoted strings. A bit sneaky, but not too much... -$dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g; -print $compiled_fh $dumped_data; -if (%groups) { - $dumped_data = Data::Dumper->Dump([\%groups], [qw(*groups)]); - $dumped_data =~ s/\bCREAT[EO]R\b/\$creator/g; +sub write_compiled_conf +{ + my $compiled_fh = wrap_open( ">", "$GL_CONF_COMPILED.new" ); + my $data_version = $current_data_version; + print $compiled_fh Data::Dumper->Dump([$data_version], [qw(*data_version)]); + my $dumped_data = Data::Dumper->Dump([\%repos], [qw(*repos)]); + $dumped_data .= Data::Dumper->Dump([\%git_configs], [qw(*git_configs)]) if %git_configs; + # the dump uses single quotes, but we convert any strings containing $creator + # and $gl_user to double quoted strings. A bit sneaky, but not too much... $dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g; print $compiled_fh $dumped_data; + if (%groups) { + $dumped_data = Data::Dumper->Dump([\%groups], [qw(*groups)]); + $dumped_data =~ s/\bCREAT[EO]R\b/\$creator/g; + $dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g; + print $compiled_fh $dumped_data; + } + print $compiled_fh Data::Dumper->Dump([\%split_conf], [qw(*split_conf)]) if %split_conf; + close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n"; + rename "$GL_CONF_COMPILED.new", "$GL_CONF_COMPILED"; } -close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n"; -rename "$GL_CONF_COMPILED.new", "$GL_CONF_COMPILED"; # ---------------------------------------------------------------------------- -# (that ends the config file compiler and write) +# (that ends the config file compiler, though we postpone the writing +# for now to deal with the latest GL_BIG_CONFIG innovation!) # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- @@ -443,25 +451,31 @@ die "\n\t\t***** AAARGH! *****\n" . "\tthe newer features, please upgrade.\n" if $git_version < 10602; # that's 1.6.2 to you - - # ---------------------------------------------------------------------------- -# the rest of this program can be "switched off"; see doc/big-config.mkd for -# details. +# most of the rest of this program can be "switched off"; see +# doc/big-config.mkd for details. # ---------------------------------------------------------------------------- -# ---------------------------------------------------------------------------- -# any new repos to be created? -# ---------------------------------------------------------------------------- - -# repo-base needs to be an absolute path for this loop to work right +# repo-base needs to be an absolute path due to all the jumping around we do, # so if it was not already absolute, prefix $HOME. $ENV{GL_REPO_BASE_ABS} = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" ); -unless ($GL_NO_CREATE_REPOS) { +# process the normal repos in %repos. This includes creating them if needed +# (and GL_NO_CREATE_REPOS is not set), checking hooks, and finally, if +# GL_BIG_CONFIG is set, writing out the one-repo config file for directly +# specified repos (i.e., "repo foo", not "@grp = foo" + "repo @grp") +do_normal_repos(); +write_compiled_conf(); # write out the final compiled config + +# ---------------------------------------------------------------------------- +# process the normal repos in %repos (create, hook, one_repo config...) +# ---------------------------------------------------------------------------- + +sub do_normal_repos +{ wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); - # autocreate repos. Start with the ones that are normal repos in %repos + # start with the ones that are normal repos in %repos my @repos = grep { $_ =~ $REPONAME_PATT and not /^@/ } sort keys %repos; # then, for each repogroup, find the members of the group and add them in map { push @repos, keys %{ $groups{$_} } } grep { /^@/ } keys %repos; @@ -470,39 +484,67 @@ unless ($GL_NO_CREATE_REPOS) { @repos = sort keys %seen; for my $repo (sort @repos) { - next unless $repo =~ $REPONAME_PATT; - next if $repo =~ m(^\@|EXTCMD/); # these are not real repos - unless (-d "$repo.git") { - print STDERR "creating $repo...\n"; - new_repo($repo, "$GL_ADMINDIR/hooks/common"); - # new_repo would have chdir'd us away; come back - wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); + next unless $repo =~ $REPONAME_PATT; # skip repo patterns + next if $repo =~ m(^\@|EXTCMD/); # skip groups and fake repos + + unless ($GL_NO_CREATE_REPOS) { + unless (-d "$repo.git") { + print STDERR "creating $repo...\n"; + new_repo($repo, "$GL_ADMINDIR/hooks/common"); + # new_repo would have chdir'd us away; come back + wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); + } + + # when repos are copied over from elsewhere, one had to run easy install + # once again to make the new (OS-copied) repo contain the proper update + # hook. Perhaps we can make this easier now, and eliminate the easy + # install, with a quick check (and a new, empty, "hook" as a sentinel) + unless (-l "$repo.git/hooks/gitolite-hooked") { + ln_sf("$GL_ADMINDIR/hooks/common", "*", "$repo.git/hooks"); + # in case of package install, GL_ADMINDIR is no longer the top cop; + # override with the package hooks + ln_sf("$GL_PACKAGE_HOOKS/common", "*", "$repo.git/hooks") if $GL_PACKAGE_HOOKS; + } } - # when repos are copied over from elsewhere, one had to run easy install - # once again to make the new (OS-copied) repo contain the proper update - # hook. Perhaps we can make this easier now, and eliminate the easy - # install, with a quick check (and a new, empty, "hook" as a sentinel) - unless (-l "$repo.git/hooks/gitolite-hooked") { - ln_sf("$GL_ADMINDIR/hooks/common", "*", "$repo.git/hooks"); - # in case of package install, GL_ADMINDIR is no longer the top cop; - # override with the package hooks - ln_sf("$GL_PACKAGE_HOOKS/common", "*", "$repo.git/hooks") if $GL_PACKAGE_HOOKS; - } + # write a one_repo config for normal repos declared directly (not just via a group) + write_1_compiled_conf($repo) if $GL_BIG_CONFIG and $repos{$repo} and -d "$repo.git"; } } +sub write_1_compiled_conf +{ + # warning: writes and *deletes* it from %repos and %git_configs + my ($repo) = shift; + my (%one_repo, %one_git_config); + + open(my $compiled_fh, ">", "$repo.git/gl-conf") or return; + + $one_repo{$repo} = $repos{$repo}; + delete $repos{$repo}; + my $dumped_data = Data::Dumper->Dump([\%one_repo], [qw(*one_repo)]); + + if ($git_configs{$repo}) { + $one_git_config{$repo} = $git_configs{$repo}; + delete $git_configs{$repo}; + $dumped_data .= Data::Dumper->Dump([\%one_git_config], [qw(*one_git_config)]); + } + + # the dump uses single quotes, but we convert any strings containing $creator + # and $gl_user to double quoted strings. A bit sneaky, but not too much... + $dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g; + print $compiled_fh $dumped_data; + close $compiled_fh; + + $split_conf{$repo} = 1; +} + # ---------------------------------------------------------------------------- -# collect repo_patt for each actual repo +# get a list of physical repos for later # ---------------------------------------------------------------------------- -# go through each actual repo on disk, and match it to either its own name in -# the config (non-wild) or a wild pattern that matches it. Lots of things -# later will need this correspondence so we may as well snarf it in one shot - - -my %repo_patts = (); -%repo_patts = &collect_repo_patts(\%repos) unless $GL_NO_DAEMON_NO_GITWEB; +my @phy_repos = (); +@phy_repos = &list_phy_repos() unless $GL_NO_DAEMON_NO_GITWEB; # NOTE: we're overloading GL_NO_DAEMON_NO_GITWEB to mean "no git config" also. # In fact anything that requires trawling through the existing repos doing @@ -520,8 +562,6 @@ my %repo_patts = (); # update repo configurations, gitweb description, daemon export-ok, etc # ---------------------------------------------------------------------------- -# all these require a "chdir" to the repo, so we club them for efficiency - my %projlist = (); # for each real repo (and remember this will be empty, thus skipping all this, @@ -530,13 +570,13 @@ my %projlist = (); # note: we do them in 2 separate loops to avoid breaking the optimisation in # sub parse_acl (look for variable $saved_crwu) -for my $repo (keys %repo_patts) { +for my $repo (@phy_repos) { wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git"); # daemon is easy &setup_daemon_access($repo); } -for my $repo (keys %repo_patts) { +for my $repo (@phy_repos) { wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git"); # gitweb is a little more complicated. Here're some notes: # - "setup_gitweb_access" also sets "owner", despite the name diff --git a/t/out/t01-repo-groups.2 b/t/out/t01-repo-groups.2 index 4275510..5b6a9aa 100644 --- a/t/out/t01-repo-groups.2 +++ b/t/out/t01-repo-groups.2 @@ -23,7 +23,21 @@ $data_version = '1.7'; '@g1' => 1, '@g2' => 1 } - }, + } +); +%groups = ( + '@g1' => { + 'aa' => 'master', + 'bb' => 'master' + } +); +%split_conf = ( + 'gitolite-admin' => 1, + 'testing' => 1 +); +repositories/gitolite-admin.git/gl-conf +repositories/testing.git/gl-conf +%one_repo = ( 'gitolite-admin' => { 'R' => { 'tester' => 1 @@ -38,7 +52,9 @@ $data_version = '1.7'; 'RW+' ] ] - }, + } +); +%one_repo = ( 'testing' => { '@all' => [ [ @@ -55,9 +71,3 @@ $data_version = '1.7'; } } ); -%groups = ( - '@g1' => { - 'aa' => 'master', - 'bb' => 'master' - } -); diff --git a/t/t01-repo-groups b/t/t01-repo-groups index 367e29d..86c7231 100644 --- a/t/t01-repo-groups +++ b/t/t01-repo-groups @@ -39,8 +39,8 @@ echo " RW = u2 u3 " | ugc -catconf -expect_filesame $TESTDIR/out/t01-repo-groups.1 +catconfs +expect_filesame $TESTDIR/out/t01-repo-groups.1bs # ---------- $TESTDIR/rollback || die "rollback failed" @@ -54,7 +54,7 @@ echo " RW = @g2 " | ugc -catconf +catconfs expect_filesame $TESTDIR/out/t01-repo-groups.2 name INTERNAL diff --git a/t/t02-user-groups b/t/t02-user-groups index 7b673cc..3fabcbd 100644 --- a/t/t02-user-groups +++ b/t/t02-user-groups @@ -42,8 +42,8 @@ echo " RW = u2 u3 " | ugc -catconf -expect_filesame $TESTDIR/out/t02-user-groups.1 +catconfs +expect_filesame $TESTDIR/out/t02-user-groups.1bs # ---------- $TESTDIR/rollback || die "rollback failed" @@ -60,7 +60,7 @@ echo " RW = @g2 " | ugc -catconf -expect_filesame $TESTDIR/out/t02-user-groups.2 +catconfs +expect_filesame $TESTDIR/out/t02-user-groups.2bs name INTERNAL diff --git a/t/t59-repo-not-on-disk b/t/t59-repo-not-on-disk index 2873763..9f246f6 100644 --- a/t/t59-repo-not-on-disk +++ b/t/t59-repo-not-on-disk @@ -76,15 +76,21 @@ do cd ~/td name "repo on disk missing: u1" runlocal git clone u1:aa - expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "0" ] && expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "1" ] && expect "R access for aa DENIED to u1" + [ "$bc" = "1" ] && expect "Or there may be no repository at the given path. Did you spell it correctly?" name "repo on disk missing: tester" runlocal git clone gitolite:aa - expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "0" ] && expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "1" ] && expect "R access for aa DENIED to tester" + [ "$bc" = "1" ] && expect "Or there may be no repository at the given path. Did you spell it correctly?" name "repo on disk missing: u4" runlocal git clone u4:aa - expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "0" ] && expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "1" ] && expect "R access for aa DENIED to u4" + [ "$bc" = "1" ] && expect "Or there may be no repository at the given path. Did you spell it correctly?" name "repo on disk missing: u6" runlocal git clone u6:aa diff --git a/t/test-driver.sh b/t/test-driver.sh index 5d03753..78ba786 100755 --- a/t/test-driver.sh +++ b/t/test-driver.sh @@ -14,6 +14,13 @@ runremote() { ssh gitolite-test@localhost "$@" > ~/1 2> ~/2; } listrepos() { ssh gitolite-test@localhost find repositories -type d -name "*.git" | sort > ~/1 2> ~/2; } # remote cat compiled pm catconf() { ssh gitolite-test@localhost cat .gitolite/conf/gitolite.conf-compiled.pm > ~/1 2> ~/2; } +catconfs() { + ( + ssh gitolite-test@localhost cat .gitolite/conf/gitolite.conf-compiled.pm + ssh gitolite-test@localhost find repositories -name gl-conf \| sort + ssh gitolite-test@localhost find repositories -name gl-conf \| sort \| xargs cat + ) > ~/1 2> ~/2 +} # remote cat ~/.gitolite.rc catrc() { ssh gitolite-test@localhost cat .gitolite.rc > ~/1 2> ~/2; } # tail gitolite logfile