gitweb/daemon now work for wild repos also
(thanks to Kevin Fleming for the need/use case) TODO: tests TODO: proper documentation; meanwhile, just read this: - you can give gitweb and daemon read rights to wild card repos also, and it'll all just work -- when a new repo is 'C'reated, it'll pick up those rights etc - you can assign descriptions (and owners) to individual repos as before, except now you can assign them to repos that actually were created from wild card patterns. So for example, you can define rules for repo foo/..* and then assign descriptions like foo/repo1 = "repo one" foo/repo2 = "repo two" foo/dil "scott" = "scott's dilbert repo" However, this only works for repos that already exist, and only when you push the admin repo. Thumb rule: have the user create his wild repo, *then* add and push the admin config file with the description. Not the other way around. implementation notes: - wildcard support for git config revamped, refactored... it's not just git config that needs wildcard support. daemon and gitweb access also will be needing it soon, so we start by factoring out the part that finds the "pattern" given a "real" repo name. - GL_NO_DAEMON_NO_GITWEB now gates more than just those two things; see doc/big-config.mkd for details - we trawl through $GL_REPO_BASE_ABS *once* only, collecting repo names and tying them to either the same name or to a wild pattern that the repo name was created from - nice little subs to setup gitweb, daemon, and git config - god bless $GL_REPOPATT and the day I decided to set that env var whenever a user hits a wild repo in any way :-) - the code in gl-compile-conf is very simple now. Much nicer than before
This commit is contained in:
parent
61802045d9
commit
509c73b888
119
src/gitolite.pm
119
src/gitolite.pm
|
@ -115,6 +115,43 @@ 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
|
||||||
|
{
|
||||||
|
my $repos_p = shift;
|
||||||
|
my %repo_patts = ();
|
||||||
|
|
||||||
|
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return %repo_patts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# where is the rc file hiding?
|
# where is the rc file hiding?
|
||||||
|
@ -243,38 +280,17 @@ sub get_set_desc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# IMPORTANT NOTE: next 3 subs (setup_*) assume $PWD is the bare repo itself
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# set/unset repo configs
|
# set/unset repo configs
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
sub setup_repo_configs
|
sub setup_repo_configs
|
||||||
{
|
{
|
||||||
my ($repo_config_p, $repo, $wild) = @_;
|
my ($repo, $repo_patt, $repo_config_p) = @_;
|
||||||
|
|
||||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git");
|
|
||||||
|
|
||||||
# prep for wild and non-wild cases separately
|
|
||||||
my $repo_patt = ''; # actually "repo or repo_pattern"
|
|
||||||
if ($wild) {
|
|
||||||
chomp (my $creator = `cat gl-creater`);
|
|
||||||
|
|
||||||
# loop each key of %repo_config and make a copy
|
|
||||||
for my $key (keys %$repo_config_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$/) {
|
|
||||||
# if it matches, proceed
|
|
||||||
$repo_patt = $key;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$repo_patt ||= $repo; # just use the repo itself...
|
|
||||||
# XXX TODO there is a remote possibility of errors if you have a
|
|
||||||
# normal repo that fits a wild pattern; needs some digging into...
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( my ($key, $value) = each(%{ $repo_config_p->{$repo_patt} }) ) {
|
while ( my ($key, $value) = each(%{ $repo_config_p->{$repo_patt} }) ) {
|
||||||
if ($value) {
|
if ($value) {
|
||||||
|
@ -286,6 +302,57 @@ sub setup_repo_configs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# set/unset daemon access
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
my $export_ok = "git-daemon-export-ok";
|
||||||
|
sub setup_daemon_access
|
||||||
|
{
|
||||||
|
my ($repo, $allowed) = @_;
|
||||||
|
|
||||||
|
if ($allowed) {
|
||||||
|
system("touch $export_ok");
|
||||||
|
} else {
|
||||||
|
unlink($export_ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# set/unset gitweb access
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
my $desc_file = "description";
|
||||||
|
sub setup_gitweb_access
|
||||||
|
# this also sets "owner" for gitweb, by the way
|
||||||
|
{
|
||||||
|
my ($repo, $allowed, $desc, $owner) = @_;
|
||||||
|
|
||||||
|
if ($allowed) {
|
||||||
|
if ($desc) {
|
||||||
|
open(DESC, ">", $desc_file);
|
||||||
|
print DESC $desc . "\n";
|
||||||
|
close DESC;
|
||||||
|
}
|
||||||
|
if ($owner) {
|
||||||
|
# set the repository owner
|
||||||
|
system("git", "config", "gitweb.owner", $owner);
|
||||||
|
} else {
|
||||||
|
# remove the repository owner setting
|
||||||
|
system("git config --unset-all gitweb.owner 2>/dev/null");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unlink $desc_file;
|
||||||
|
system("git config --unset-all gitweb.owner 2>/dev/null");
|
||||||
|
}
|
||||||
|
|
||||||
|
# if there are no gitweb.* keys set, remove the section to keep the config file clean
|
||||||
|
my $keys = `git config --get-regexp '^gitweb\\.' 2>/dev/null`;
|
||||||
|
if (length($keys) == 0) {
|
||||||
|
system("git config --remove-section gitweb 2>/dev/null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# parse the compiled acl
|
# parse the compiled acl
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
|
@ -23,7 +23,7 @@ use warnings;
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
# these are set by the "rc" file
|
# these are set by the "rc" file
|
||||||
our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMINDIR, $RSYNC_BASE, $HTPASSWD_FILE, $GL_WILDREPOS, $GL_WILDREPOS_DEFPERMS, $GL_ADC_PATH, $SVNSERVE, $GL_SLAVE_MODE);
|
our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMINDIR, $RSYNC_BASE, $HTPASSWD_FILE, $GL_WILDREPOS, $GL_WILDREPOS_DEFPERMS, $GL_ADC_PATH, $SVNSERVE, $PROJECTS_LIST, $GL_SLAVE_MODE);
|
||||||
# and these are set by gitolite.pm
|
# and these are set by gitolite.pm
|
||||||
our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT, $REPOPATT_PATT);
|
our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT, $REPOPATT_PATT);
|
||||||
our %repos;
|
our %repos;
|
||||||
|
@ -207,7 +207,10 @@ if ($perm =~ /C/) {
|
||||||
# it was missing, and you have create perms
|
# it was missing, and you have create perms
|
||||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
||||||
new_repo($repo, "$GL_ADMINDIR/hooks/common", $user);
|
new_repo($repo, "$GL_ADMINDIR/hooks/common", $user);
|
||||||
&setup_repo_configs(\%repo_config, $repo, 1);
|
&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");
|
||||||
wrap_chdir($ENV{HOME});
|
wrap_chdir($ENV{HOME});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -470,94 +470,82 @@ unless ($GL_NO_CREATE_REPOS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# update repo configurations
|
# collect repo_patt for each actual repo
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
# no gating required for this. If you don't have any "config" lines it won't
|
# go through each actual repo on disk, and match it to either its own name in
|
||||||
# run anyway. An example of a config line could be:
|
# the config (non-wild) or a wild pattern that matches it. Lots of things
|
||||||
# config hooks.emailprefix = "[foo]"
|
# later will need this correspondence so we may as well snarf it in one shot
|
||||||
|
|
||||||
for my $repo (keys %repo_config) {
|
|
||||||
&setup_repo_configs(\%repo_config, $repo) if $repo =~ $REPONAME_PATT;
|
|
||||||
}
|
|
||||||
|
|
||||||
# wild
|
my %repo_patts = ();
|
||||||
if (%repo_config and $GL_WILDREPOS and $GL_GITCONFIG_WILD) {
|
%repo_patts = &collect_repo_patts(\%repos) unless $GL_NO_DAEMON_NO_GITWEB;
|
||||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
|
||||||
for my $repo (`find . -type d -name "*.git"`) {
|
|
||||||
chomp ($repo);
|
|
||||||
next unless -f "$ENV{GL_REPO_BASE_ABS}/$repo/gl-creater"; # all/only wild repos have this file
|
|
||||||
|
|
||||||
# $repo will look like "./foo/bar.git", make it "foo/bar" before
|
# NOTE: we're overloading GL_NO_DAEMON_NO_GITWEB to mean "no git config" also.
|
||||||
# calling the repo config setup sub
|
# In fact anything that requires trawling through the existing repos doing
|
||||||
$repo =~ s(\./(.*)\.git$)($1);
|
# stuff to all of them is skipped if this variable is set. This is primarily
|
||||||
&setup_repo_configs(\%repo_config, $repo, 1);
|
# for the Fedora folks, but it should be useful for anyone who has a huge set
|
||||||
}
|
# of repos and wants to manage gitweb/daemon/etc access via other means (they
|
||||||
}
|
# typically have the whole thing controlled by a web-app and a database
|
||||||
|
# anyway, and gitolite is only doing the access control and nothing more).
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# handle gitweb and daemon
|
# various updates to all real repos
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
# I just assume you'll never have any *real* users called "gitweb" or "daemon"
|
# ----------------------------------------------------------------------------
|
||||||
# :-) These are now "pseduo users" -- giving them "R" access to a repo is all
|
# update repo configurations, gitweb description, daemon export-ok, etc
|
||||||
# you have to do
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
# all these require a "chdir" to the repo, so we club them for efficiency
|
||||||
|
|
||||||
unless ($GL_NO_DAEMON_NO_GITWEB) {
|
|
||||||
# daemons first...
|
|
||||||
for my $repo (sort keys %repos) {
|
|
||||||
next unless $repo =~ $REPONAME_PATT;
|
|
||||||
next if $repo =~ m(^\@|EXTCMD/); # these are not real repos
|
|
||||||
my $export_ok = "$repo.git/git-daemon-export-ok";
|
|
||||||
if ($repos{$repo}{'R'}{'daemon'}) {
|
|
||||||
system("touch $export_ok");
|
|
||||||
} else {
|
|
||||||
unlink($export_ok);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my %projlist = ();
|
my %projlist = ();
|
||||||
# ...then gitwebs
|
|
||||||
for my $repo (sort keys %repos) {
|
# for each real repo (and remember this will be empty, thus skipping all this,
|
||||||
next unless $repo =~ $REPONAME_PATT;
|
# if $GL_NO_DAEMON_NO_GITWEB is on!)
|
||||||
next if $repo =~ m(^\@|EXTCMD/); # these are not real repos
|
for my $repo (keys %repo_patts) {
|
||||||
my $desc_file = "$repo.git/description";
|
my $repo_patt = $repo_patts{$repo}; # if non-wild, $repo_patt will be eq $repo anyway
|
||||||
# note: having a description also counts as enabling gitweb
|
|
||||||
if ($repos{$repo}{'R'}{'gitweb'} or $desc{"$repo.git"}) {
|
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'} || '');
|
||||||
|
|
||||||
|
# gitweb is a little more complicated. Here're some notes:
|
||||||
|
# - "setup_gitweb_access" also sets "owner", despite the name
|
||||||
|
# - specifying a description also counts as enabling gitweb
|
||||||
|
# - description and owner are not specified for wildrepos; they're
|
||||||
|
# specified for *actual* repos, even if the repo was created by a
|
||||||
|
# wild card spec and "C" permissions. If you see the
|
||||||
|
# conf/example.conf file, you will see that repo owner/desc don't go
|
||||||
|
# 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;
|
$projlist{"$repo.git"} = 1;
|
||||||
# add the description file; no messages to user or error checking :)
|
&setup_gitweb_access($repo, 1, $desc{"$repo.git"} || '', $owner{"$repo.git"} || '');
|
||||||
$desc{"$repo.git"} and open(DESC, ">", $desc_file) and print DESC $desc{"$repo.git"} . "\n" and close DESC;
|
|
||||||
if ($owner{"$repo.git"}) {
|
|
||||||
# set the repository owner
|
|
||||||
system("git", "--git-dir=$repo.git", "config", "gitweb.owner", $owner{"$repo.git"});
|
|
||||||
} else {
|
} else {
|
||||||
# remove the repository owner setting
|
&setup_gitweb_access($repo, 0, '', '');
|
||||||
system("git --git-dir=$repo.git config --unset-all gitweb.owner 2>/dev/null");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# delete the description file; no messages to user or error checking :)
|
|
||||||
unlink $desc_file;
|
|
||||||
# remove the repository owner setting
|
|
||||||
system("git --git-dir=$repo.git config --unset-all gitweb.owner 2>/dev/null");
|
|
||||||
}
|
|
||||||
|
|
||||||
# unless there are other gitweb.* keys set, remove the section to keep the
|
|
||||||
# config file clean
|
|
||||||
my $keys = `git --git-dir=$repo.git config --get-regexp '^gitweb\\.' 2>/dev/null`;
|
|
||||||
if (length($keys) == 0) {
|
|
||||||
system("git --git-dir=$repo.git config --remove-section gitweb 2>/dev/null");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# update the project list
|
# write out the project list
|
||||||
my $projlist_fh = wrap_open( ">", $PROJECTS_LIST);
|
my $projlist_fh = wrap_open( ">", $PROJECTS_LIST);
|
||||||
for my $proj (sort keys %projlist) {
|
for my $proj (sort keys %projlist) {
|
||||||
print $projlist_fh "$proj\n";
|
print $projlist_fh "$proj\n";
|
||||||
}
|
}
|
||||||
close $projlist_fh;
|
close $projlist_fh;
|
||||||
}
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# "compile" ssh authorized_keys
|
# "compile" ssh authorized_keys
|
||||||
|
|
Loading…
Reference in a new issue