diff --git a/src/gitolite.pm b/src/gitolite.pm index bf70db6..1a3bfb6 100644 --- a/src/gitolite.pm +++ b/src/gitolite.pm @@ -40,6 +40,7 @@ our $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z[][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$); our ($REPO_UMASK, $GL_WILDREPOS, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $REPO_BASE, $GL_CONF_COMPILED, $GL_BIG_CONFIG); our %repos; our %groups; +our %repo_config; our $data_version; our $current_data_version = '1.5'; @@ -129,24 +130,9 @@ sub collect_repo_patts for my $repo (`find . -type d -name "*.git"`) { chomp ($repo); $repo =~ s(\./(.*)\.git$)($1); - # if its non-wild that's all you need - if ($repos_p->{$repo}) { - $repo_patts{$repo} = $repo; - } else { - # otherwise it gets a wee bit complicated ;-) - chomp (my $creator = `cat $repo.git/gl-creater`); - for my $key (keys %$repos_p) { - my $key2 = $key; - # subst $creator in the copy with the creator name - $key2 =~ s/\$creator/$creator/g; - # match the new key against $repo - if ($repo =~ /^$key2$/) { - # and if it matched you're done for this $repo - $repo_patts{$repo} = $key; - last; - } - } - } + # 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; } return %repo_patts; @@ -290,9 +276,9 @@ sub get_set_desc sub setup_repo_configs { - my ($repo, $repo_patt, $repo_config_p) = @_; + my ($repo, $repo_config_p) = @_; - while ( my ($key, $value) = each(%{ $repo_config_p->{$repo_patt} }) ) { + while ( my ($key, $value) = each(%{ $repo_config_p->{$repo} }) ) { if ($value) { $value =~ s/^"(.*)"$/$1/; system("git", "config", $key, $value); @@ -306,12 +292,13 @@ sub setup_repo_configs # set/unset daemon access # ---------------------------------------------------------------------------- +# does not return anything; just touch/unlink the appropriate file my $export_ok = "git-daemon-export-ok"; sub setup_daemon_access { - my ($repo, $allowed) = @_; + my $repo = shift; - if ($allowed) { + if (&can_read($repo, 'daemon')) { system("touch $export_ok"); } else { unlink($export_ok); @@ -322,13 +309,18 @@ sub setup_daemon_access # set/unset gitweb access # ---------------------------------------------------------------------------- +# returns 1 if gitweb access has happened; this is to allow the caller to add +# an entry to the projects.list file my $desc_file = "description"; sub setup_gitweb_access # this also sets "owner" for gitweb, by the way { - my ($repo, $allowed, $desc, $owner) = @_; + my ($repo, $desc, $owner) = @_; + my $ret = 0; - if ($allowed) { + # passing in a descr implies 'R = gitweb' + if ($desc or &can_read($repo, 'gitweb')) { + $ret = 1; if ($desc) { open(DESC, ">", $desc_file); print DESC $desc . "\n"; @@ -351,6 +343,8 @@ sub setup_gitweb_access if (length($keys) == 0) { system("git config --remove-section gitweb 2>/dev/null"); } + + return $ret; } # ---------------------------------------------------------------------------- @@ -409,6 +403,7 @@ sub parse_acl $repos{$dr}{DELETE_IS_D} = 1 if $repos{$r}{DELETE_IS_D}; $repos{$dr}{CREATE_IS_C} = 1 if $repos{$r}{CREATE_IS_C}; $repos{$dr}{NAME_LIMITS} = 1 if $repos{$r}{NAME_LIMITS}; + $repo_config{$dr} = $repo_config{$r} if $repo_config{$r}; for my $u ('@all', "$gl_user - wild", @user_plus) { my $du = $gl_user; $du = '@all' if $u eq '@all'; @@ -522,8 +517,6 @@ sub expand_wild $repo =~ s/^\.\///; $repo =~ s/\.git$//; - return if $last_repo eq $repo; # a wee bit o' caching, though not yet needed - # we get passed an actual repo name. It may be a normal # (non-wildcard) repo, in which case it is assumed to exist. If it's # a wildrepo, it may or may not exist. If it doesn't exist, the "C" @@ -582,6 +575,14 @@ sub cli_repo_rights { print "$perm $creator\n"; } +sub can_read { + my $repo = shift; + my $user = shift || $ENV{GL_USER}; + local $ENV{GL_USER} = $user; + my ($perm, $creator, $wild) = &repo_rights($repo); + return $perm =~ /R/; +} + # ---------------------------------------------------------------------------- # setup the ~/.ssh/authorized_keys file # ---------------------------------------------------------------------------- diff --git a/src/gl-auth-command b/src/gl-auth-command index bd7737a..9a1e0dc 100755 --- a/src/gl-auth-command +++ b/src/gl-auth-command @@ -207,10 +207,9 @@ if ($perm =~ /C/) { # it was missing, and you have create perms wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); new_repo($repo, "$GL_ADMINDIR/hooks/common", $user); - &setup_repo_configs($repo, $ENV{GL_REPOPATT}, \%repo_config); - &setup_daemon_access($repo, $repos{$ENV{GL_REPOPATT}}{'R'}{'daemon'} || ''); - &setup_gitweb_access($repo, $repos{$ENV{GL_REPOPATT}}{'R'}{'gitweb'} || '', '', ''); - system("echo $repo.git >> $PROJECTS_LIST"); + &setup_repo_configs($repo, \%repo_config); + &setup_daemon_access($repo); + system("echo $repo.git >> $PROJECTS_LIST") if &setup_gitweb_access($repo, '', ''); wrap_chdir($ENV{HOME}); } diff --git a/src/gl-compile-conf b/src/gl-compile-conf index 8926a91..0a93465 100755 --- a/src/gl-compile-conf +++ b/src/gl-compile-conf @@ -105,7 +105,7 @@ our $current_data_version; # this comes from gitolite.pm my %user_list = (); # repo configurations -my %repo_config = (); +our %repo_config = (); # gitweb descriptions and owners; plain text, keyed by "$repo.git" my %desc = (); @@ -311,7 +311,15 @@ sub parse_conf_file for my $repo (@repos) # each repo in the current stanza { $repo_config{$repo}{$key} = $value; - print STDERR "$WARN git config set for $repo but \$GL_GITCONFIG_WILD not set\n" unless $repo =~ $REPONAME_PATT or $GL_GITCONFIG_WILD; + # no problem if it's a plain repo (non-pattern, non-groupname) + # OR wild configs are allowed + unless ( ($repo =~ $REPONAME_PATT and $repo !~ /^@/) or $GL_GITCONFIG_WILD) { + my @r = ($repo); # single wildpatt + @r = sort keys %{ $groups{$repo} } if $groups{$repo}; # or a group; get its members + do { + print STDERR "$WARN git config set for $_ but \$GL_GITCONFIG_WILD not set\n" unless $_ =~ $REPONAME_PATT + } for @r; + } } } # include @@ -389,7 +397,12 @@ $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; -print $compiled_fh Data::Dumper->Dump([\%groups], [qw(*groups)]) if $GL_BIG_CONFIG and %groups; +if ($GL_BIG_CONFIG and %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; + print $compiled_fh $dumped_data; +} close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n"; rename "$GL_CONF_COMPILED.new", "$GL_CONF_COMPILED"; @@ -504,23 +517,12 @@ my %projlist = (); # for each real repo (and remember this will be empty, thus skipping all this, # if $GL_NO_DAEMON_NO_GITWEB is on!) for my $repo (keys %repo_patts) { - my $repo_patt = $repo_patts{$repo}; # if non-wild, $repo_patt will be eq $repo anyway + my $repo_patt = $repo_patts{$repo}; wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git"); - # git config - if ($repo_patt eq $repo or $GL_GITCONFIG_WILD) { - # erm, what that means is that it's either a non-wild repo being - # config'd or a wild one but gitconfig is allowed on wilds. - # XXX do we really need GL_GITCONFIG_WILD now? It was meant to be - # only an efficiency thing, but that was before this whole revamp; - # we already trawl through $REPO_BASE exactly once now anyway! - # ...need to think about this - &setup_repo_configs($repo, $repo_patt, \%repo_config) if $repo_config{$repo_patt}; - } - # daemon is easy - &setup_daemon_access($repo, $repos{$repo_patt}{'R'}{'daemon'} || ''); + &setup_daemon_access($repo); # gitweb is a little more complicated. Here're some notes: # - "setup_gitweb_access" also sets "owner", despite the name @@ -532,12 +534,16 @@ for my $repo (keys %repo_patts) { # into the "repo foo" section; they're essentialy independent. # Anyway, I believe it doesn't make sense to have all wild repos # (for some pattern) to have the same description and owner. - if ($repos{$repo_patt}{'R'}{'gitweb'} or $desc{"$repo.git"}) { - $projlist{"$repo.git"} = 1; - &setup_gitweb_access($repo, 1, $desc{"$repo.git"} || '', $owner{"$repo.git"} || ''); - } else { - &setup_gitweb_access($repo, 0, '', ''); - } + $projlist{"$repo.git"} = 1 if &setup_gitweb_access($repo, $desc{"$repo.git"} || '', $owner{"$repo.git"} || ''); + + # git config + # implementation note: this must happen *after* one of the previous 2 + # calls (setup daemon or gitweb). The reason is that they call + # "can_read", which eventually calls parse_acl with the right "creator" + # set for the *current* repo, which in turn stores translated values fr + # $creator in the repo_config hash, which, (phew!) is needed for a match + # that eventually gets you a valid $repo_config{} below + &setup_repo_configs($repo, \%repo_config) if $repo_config{$repo}; } # write out the project list