Merge branch 'master' into wildrepos

lots of conflicts, esp in gl-auth-command, due to refactoring the
"special commands" stuff on master

Conflicts:
	doc/3-faq-tips-etc.mkd
	src/gitolite.pm
	src/gl-auth-command
	src/gl-compile-conf
This commit is contained in:
Sitaram Chamarty 2010-02-04 14:42:10 +05:30
commit c43560d2ef
7 changed files with 279 additions and 75 deletions

View file

@ -99,6 +99,11 @@ or in Unix, perl, shell, etc.)... well I can't afford 1000 USD rewards like
djb, so you'll have to settle for 1000 INR (Indian Rupees) as a "token" prize djb, so you'll have to settle for 1000 INR (Indian Rupees) as a "token" prize
:-) :-)
Update 2010-01-31: this security promise does not apply if you enable any of
the external command helpers (like rsync). It's probably quite secure, but I
just haven't thought about it enough to be able to make such promises, like I
can for the rest of "master".
---- ----
### contact and license ### contact and license

View file

@ -147,10 +147,18 @@ repo git
# DENY/EXCLUDE RULES # DENY/EXCLUDE RULES
# ***IMPORTANT NOTE: if you use deny rules, the order of the rules also makes # ***IMPORTANT NOTES ABOUT "DENY" RULES***:
# a difference, where earlier it did not. Please review your ruleset
# carefully or test it. In particular, do not use `@all` in a deny rule -- it # - deny rules do NOT affect read access. They only apply to `W` and `+`.
# won't work as you might expect***. #
# - when using deny rules, the order of your rules starts to matter, where
# earlier it did not. The first matching rule applies, where "matching" is
# defined as either permitting the operation you're attempting (`W` or `+`),
# which results in success, or a "deny" (`-`), which results in failure.
# (As before, a fallthrough also results in failure).
#
# - do not use `@all` when your config has any deny rules; it won't work as
# you probably expect it to!
# in the example above, you cannot easily say "anyone can write any tag, # in the example above, you cannot easily say "anyone can write any tag,
# except version tags can only be written by junio". The following might look # except version tags can only be written by junio". The following might look
@ -166,10 +174,6 @@ repo git
- refs/tags/v[0-9] = linus pasky @others - refs/tags/v[0-9] = linus pasky @others
RW refs/tags/ = junio linus pasky @others RW refs/tags/ = junio linus pasky @others
# Briefly, the rule is: the first matching refex that has the operation you're
# looking for (`W` or `+`), or a minus (`-`), results in success, or failure,
# respectively. A fallthrough also results in failure
# FILE/DIR NAME BASED RESTRICTIONS # FILE/DIR NAME BASED RESTRICTIONS
# -------------------------------- # --------------------------------
@ -264,3 +268,21 @@ repo gitolite
# security reasons. # security reasons.
# - you can also use an absolute path if you like, although in the interests # - you can also use an absolute path if you like, although in the interests
# of cloning the admin-repo sanely you should avoid doing this! # of cloning the admin-repo sanely you should avoid doing this!
# EXTERNAL COMMAND HELPERS -- RSYNC
# ---------------------------------
# If $RSYNC_BASE is non-empty, the following config entries come into play
# (otherwise they are ignored):
# a "fake" git repository to collect rsync rules. Gitolite does not
# auto-create any repo whose name starts with EXTCMD/
repo EXTCMD/rsync
# grant permissions to files/dirs within the $RSYNC_BASE tree. A leading
# NAME/ is required as a prefix; the actual path starts after that. Matching
# follows the same rules as elsewhere in gitolite.
RW NAME/ = sitaram
RW NAME/foo/ = user1
R NAME/bar/ = user2
# just to remind you that these are perl regexes, not shell globs
RW NAME/baz/.*/*.c = user3

View file

@ -106,6 +106,26 @@ $GIT_PATH="";
# syntax: space separated list of gitolite usernames in *one* string variable. # syntax: space separated list of gitolite usernames in *one* string variable.
# $SHELL_USERS = "alice bob"; # $SHELL_USERS = "alice bob";
# --------------------------------------
# if you want to enable the "htpasswd" command, give this the absolute path to
# whatever file apache (etc) expect to find the passwords in.
$HTPASSWD_FILE = "";
# Look in doc/3 ("easier to link gitweb authorisation with gitolite" section)
# for more details on using this feature.
# --------------------------------------
# EXTERNAL COMMAND HELPER -- RSYNC
#
# base path of all the files that are accessible via rsync. Must be an
# absolute path. Leave it undefined or set to the empty string to disable the
# rsync helper.
$RSYNC_BASE = "";
# $RSYNC_BASE = "/home/git/up-down";
# $RSYNC_BASE = "/tmp/up-down";
# -------------------------------------- # --------------------------------------
# per perl rules, this should be the last line in such a file: # per perl rules, this should be the last line in such a file:
1; 1;

View file

@ -27,6 +27,7 @@ In this document:
* "personal" branches * "personal" branches
* custom hooks and custom git config * custom hooks and custom git config
* repos named with wildcards * repos named with wildcards
* access control for external commands
* design choices * design choices
* keeping the parser and the access control separate * keeping the parser and the access control separate
@ -331,9 +332,25 @@ This requires that:
* the HTTP auth should use the same username (like "sitaram") as used in the * the HTTP auth should use the same username (like "sitaram") as used in the
gitolite config (for the corresponding user) gitolite config (for the corresponding user)
Once that is done, it's easy. Gitweb allows you to specify a subroutine to Normally a superuser sets up passwords for users using the "htpasswd" command,
decide on access. We use that feature and tie it to gitolite. Sample code but this is an administrative chore.
(untested, munged from something I saw [here][leho]) is given below.
Robin Smidsrød had the *great* idea that, since each user already has pubkey
access to `git@server`, this gives us a very neat way of using gitolite to let
the users *manage their own HTTP passwords*. Here's how:
* setup apache so that the htaccess file it looks for is owned by the "git"
user
* in the `~/.gitolite.rc` file, look for the variable `$HTPASSWD_FILE` and
point it to this file
* tell your users to type in `ssh git@server htpasswd` to set or change
their HTTP passwords
Here's the rest of how it hangs together.
Gitweb allows you to specify a subroutine to decide on access. We use that
feature and tie it to gitolite. Sample code (untested by me, but others do
use it, munged from something I saw [here][leho]) is given below.
Note the **utter simplicity** of the actual check (just 1 line!). This is an Note the **utter simplicity** of the actual check (just 1 line!). This is an
unexpected piece of luck coming from the decision to keep the config parse unexpected piece of luck coming from the decision to keep the config parse
@ -349,7 +366,7 @@ already done and we just use it!
$projectroot = '/home/git/repositories/'; $projectroot = '/home/git/repositories/';
my $gl_conf_compiled = '/home/git/.gitolite/conf/gitolite.conf-compiled.pm'; my $gl_conf_compiled = '/home/git/.gitolite/conf/gitolite.conf-compiled.pm';
# I assume this gives us the HTTP auth username # I am told this gives us the HTTP auth username
my $username = $cgi->remote_user; my $username = $cgi->remote_user;
# ---------- # ----------
@ -359,10 +376,11 @@ already done and we just use it!
die "parse $gl_conf_compiled failed: " . ($! or $@) unless do $gl_conf_compiled; die "parse $gl_conf_compiled failed: " . ($! or $@) unless do $gl_conf_compiled;
# this is gitweb's mechanism; it calls whatever sub is pointed at by this # this is gitweb's mechanism; it calls whatever sub is pointed at by this
# variable to decide access yes/no # variable to decide access yes/no. Gitweb calls it with one argument
# containing the full path of the repo being accessed
$export_auth_hook = sub { $export_auth_hook = sub {
my $reponame = shift; my $reponame = shift;
# gitweb passes us the full repo path; so we strip the beginning... # take the full path provided, strip the beginning...
$reponame =~ s/\Q$projectroot\E\/?//; $reponame =~ s/\Q$projectroot\E\/?//;
# ...and the end, to get the repo name as it is specified in gitolite conf # ...and the end, to get the repo name as it is specified in gitolite conf
$reponame =~ s/\.git$//; $reponame =~ s/\.git$//;
@ -499,12 +517,9 @@ that code path to better use :-)
#### "exclude" (or "deny") rules #### "exclude" (or "deny") rules
***IMPORTANT CAVEAT: if you use deny rules, the order of the rules also makes Here is an illustrative explanation of "deny" rules. However, please be sure
a difference, where earlier it did not. Please review your ruleset carefully to read the "DENY/EXCLUDE RULES" section in `conf/example.conf` for important
or test it. In particular, do not use `@all` in a deny rule -- it won't work notes/caveats before using "deny" rules.
as you might expect***. Also, deny rules are only processed in the second
level checks (see "two levels of access rights checking" above), which means
they only apply to write operations.
Take a look at the following snippet, which *seems* to say that "bruce" can Take a look at the following snippet, which *seems* to say that "bruce" can
write versioned tags (anything containing `refs/tags/v[0-9]`), but the other write versioned tags (anything containing `refs/tags/v[0-9]`), but the other
@ -614,6 +629,20 @@ per-repo "gitconfig" settings. Please see `doc/2-admin.mkd` and
**This feature only exists in the "wildrepos" branch!** Please see **This feature only exists in the "wildrepos" branch!** Please see
`doc/4-wildcard-repositories.mkd` for all the details. `doc/4-wildcard-repositories.mkd` for all the details.
#### access control for external commands
Gitolite now has a mechanism for allowing access control for arbitrary
external commands, as long as they are invoked via ssh and present a
server-side command that contains enough information to make an access control
decision. The first (and only, so far) such command implemented is rsync.
Note that this is incompatible with giving people shell access as described in
`doc/6-ssh-troubleshooting.mkd` -- people who have shell access are not
subject to this mechanism (it wouldn't make sense to try and control someone
who has shell access anyway).
Please see the config files (both of them) for examples and usage.
### design choices ### design choices
#### keeping the parser and the access control separate #### keeping the parser and the access control separate

View file

@ -292,4 +292,118 @@ sub expand_wild
} }
} }
# ----------------------------------------------------------------------------
# S P E C I A L C O M M A N D S
# ----------------------------------------------------------------------------
sub special_cmd
{
my ($GL_ADMINDIR, $GL_CONF_COMPILED, $RSYNC_BASE, $HTPASSWD_FILE) = @_;
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
my $user = $ENV{GL_USER};
# check each special command we know about and call it if enabled
if ($cmd eq 'info') {
&report_basic($GL_ADMINDIR, $GL_CONF_COMPILED, $user);
print "you also have shell access\n\r" if $shell_allowed;
} elsif ($HTPASSWD_FILE and $cmd eq 'htpasswd') {
&ext_cmd_htpasswd($HTPASSWD_FILE);
} elsif ($RSYNC_BASE and $cmd =~ /^rsync /) {
&ext_cmd_rsync($GL_CONF_COMPILED, $RSYNC_BASE, $cmd);
} else {
# if the user is allowed a shell, just run the command
exec $ENV{SHELL}, "-c", $cmd if $shell_allowed;
die "bad command: $cmd\n";
}
}
# ----------------------------------------------------------------------------
# generic check access routine
# ----------------------------------------------------------------------------
sub check_access
{
my ($GL_CONF_COMPILED, $repo, $path, $perm) = @_;
my $ref = "NAME/$path";
&parse_acl($GL_CONF_COMPILED);
# until I do some major refactoring (which will bloat the update hook a
# bit, sadly), this code duplicates stuff in the current update hook.
my @allowed_refs;
# we want specific perms to override @all, so they come first
push @allowed_refs, @ { $repos{$repo}{$ENV{GL_USER}} || [] };
push @allowed_refs, @ { $repos{$repo}{'@all'} || [] };
for my $ar (@allowed_refs) {
my $refex = (keys %$ar)[0];
next unless $ref =~ /^$refex/;
die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->{$refex} eq '-';
return if ($ar->{$refex} =~ /\Q$perm/);
}
die "$perm $ref $ENV{GL_REPO} $ENV{GL_USER} DENIED by fallthru\n";
}
# ----------------------------------------------------------------------------
# external command helper: rsync
# ----------------------------------------------------------------------------
sub ext_cmd_rsync
{
my ($GL_CONF_COMPILED, $RSYNC_BASE, $cmd) = @_;
# test the command patterns; reject if they don't fit. Rsync sends
# commands that looks like one of these to the server (the first one is
# for a read, the second for a write)
# rsync --server --sender -some.flags . some/path
# rsync --server -some.flags . some/path
die "bad rsync command: $cmd"
unless $cmd =~ /^rsync --server( --sender)? -[\w.]+(?: --(?:delete|partial))* \. (\S+)$/;
my $perm = "W";
$perm = "R" if $1;
my $path = $2;
die "I dont like absolute paths in $cmd\n" if $path =~ /^\//;
die "I dont like '..' paths in $cmd\n" if $path =~ /\.\./;
# ok now check if we're permitted to execute a $perm action on $path
# (taken as a refex) using rsync.
&check_access($GL_CONF_COMPILED, 'EXTCMD/rsync', $path, $perm);
# that should "die" if there's a problem
wrap_chdir($RSYNC_BASE);
&log_it("$ENV{GL_TS}\t$ENV{SSH_ORIGINAL_COMMAND}\t$ENV{USER}\n");
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND};
}
# ----------------------------------------------------------------------------
# external command helper: htpasswd
# ----------------------------------------------------------------------------
sub ext_cmd_htpasswd
{
my $HTPASSWD_FILE = shift;
die "$HTPASSWD_FILE doesn't exist or is not writable\n" unless -w $HTPASSWD_FILE;
$|++;
print <<EOFhtp;
Please type in your new htpasswd at the prompt. You only have to type it once.
NOTE THAT THE PASSWORD WILL BE ECHOED, so please make sure no one is
shoulder-surfing, and make sure you clear your screen as well as scrollback
history after you're done (or close your terminal instance).
EOFhtp
print "new htpasswd:";
my $password = <>;
$password =~ s/[\n\r]*$//;
my $rc = system("htpasswd", "-b", $HTPASSWD_FILE, $ENV{GL_USER}, $password);
die "htpasswd command seems to have failed with $rc return code...\n" if $rc;
}
1; 1;

View file

@ -24,7 +24,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); our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMINDIR, $RSYNC_BASE, $HTPASSWD_FILE);
# 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;
@ -48,6 +48,8 @@ $ENV{PATH} .= ":$GIT_PATH" if $GIT_PATH;
# set the umask before creating any files # set the umask before creating any files
umask($REPO_UMASK); umask($REPO_UMASK);
my $repo_base_abs = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# start... # start...
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
@ -63,25 +65,40 @@ if ($ARGV[0] eq '-s') {
# first, fix the biggest gripe I have with gitosis, a 1-line change # first, fix the biggest gripe I have with gitosis, a 1-line change
my $user=$ENV{GL_USER}=shift; # there; now that's available everywhere! my $user=$ENV{GL_USER}=shift; # there; now that's available everywhere!
# ----------------------------------------------------------------------------
# logging, timestamp env vars
# ----------------------------------------------------------------------------
# timestamp
my ($s, $min, $h, $d, $m, $y) = (localtime)[0..5];
$y += 1900; $m++; # usual adjustments
for ($s, $min, $h, $d, $m) {
$_ = "0$_" if $_ < 10;
}
$ENV{GL_TS} = "$y-$m-$d.$h:$min:$s";
# substitute template parameters and set the logfile name
$GL_LOGT =~ s/%y/$y/g;
$GL_LOGT =~ s/%m/$m/g;
$GL_LOGT =~ s/%d/$d/g;
$ENV{GL_LOG} = $GL_LOGT;
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# sanity checks on SSH_ORIGINAL_COMMAND # sanity checks on SSH_ORIGINAL_COMMAND
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# print basic access info if SSH_ORIGINAL_COMMAND does not exist # no SSH_ORIGINAL_COMMAND given...
unless ($ENV{SSH_ORIGINAL_COMMAND}) { unless ($ENV{SSH_ORIGINAL_COMMAND}) {
# unless the user is allowed to use a shell # if the user is allowed to use a shell, give him one
if ($shell_allowed) { if ($shell_allowed) {
my $shell = $ENV{SHELL}; my $shell = $ENV{SHELL};
$shell =~ s/.*\//-/; # change "/bin/bash" to "-bash" $shell =~ s/.*\//-/; # change "/bin/bash" to "-bash"
exec { $ENV{SHELL} } $shell; exec { $ENV{SHELL} } $shell;
} }
&report_basic($GL_ADMINDIR, $GL_CONF_COMPILED, $user); # otherwise, pretend he typed in "info" and carry on...
exit 1; $ENV{SSH_ORIGINAL_COMMAND} = 'info';
} }
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
my $repo_base_abs = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# get and set perms for actual repo created by wildcard-autoviv # get and set perms for actual repo created by wildcard-autoviv
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
@ -92,7 +109,8 @@ my $CUSTOM_COMMANDS=qr/^\s*(expand|getperms|setperms)\s/;
# back; they all blithely take advantage of the fact that processing custom # back; they all blithely take advantage of the fact that processing custom
# commands is sort of a dead end for normal (git) processing # commands is sort of a dead end for normal (git) processing
if ($cmd =~ $CUSTOM_COMMANDS) { if ($ENV{SSH_ORIGINAL_COMMAND} =~ $CUSTOM_COMMANDS) {
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
my ($verb, $repo) = ($cmd =~ /^\s*(\S+)\s+\/?(.*?)(?:.git)?$/); my ($verb, $repo) = ($cmd =~ /^\s*(\S+)\s+\/?(.*?)(?:.git)?$/);
if ($repo =~ $REPONAME_PATT and $verb =~ /getperms|setperms/) { if ($repo =~ $REPONAME_PATT and $verb =~ /getperms|setperms/) {
# with an actual reponame, you can "getperms" or "setperms" # with an actual reponame, you can "getperms" or "setperms"
@ -108,35 +126,36 @@ if ($cmd =~ $CUSTOM_COMMANDS) {
exit 0; exit 0;
} }
# people allowed to get a shell can get basic access info by asking nicely
if ($cmd eq 'info') {
&report_basic($GL_ADMINDIR, $GL_CONF_COMPILED, $user);
print "you also have shell access\n\r" if $shell_allowed;
exit 0;
}
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# normal (git) processing # non-git commands
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# split into command and arguments; the pattern allows old style as well as # if the command does NOT fit the pattern of a normal git command, send it off
# new style: "git-subcommand arg" or "git subcommand arg", just like gitosis # somewhere else...
# does, although I'm not sure how necessary that is
#
# keep in mind this is how git sends across the command:
# git-receive-pack 'reponame.git'
# including the single quotes
my ($verb, $repo) = ($cmd =~ /^\s*(git\s+\S+|\S+)\s+'\/?(.*?)(?:\.git)?'/); # side notes on detecting a normal git command: the pattern we check allows
# old style as well as new style ("git-subcommand arg" or "git subcommand
# arg"), just like gitosis does, although I'm not sure how necessary that is.
# Currently, this is how git sends across the command (including the single
# quotes):
# git-receive-pack 'reponame.git'
my ($verb, $repo) = ($ENV{SSH_ORIGINAL_COMMAND} =~ /^\s*(git\s+\S+|\S+)\s+'\/?(.*?)(?:\.git)?'/);
unless ( $verb and ( $verb =~ $R_COMMANDS or $verb =~ $W_COMMANDS ) and $repo and $repo =~ $REPONAME_PATT ) { unless ( $verb and ( $verb =~ $R_COMMANDS or $verb =~ $W_COMMANDS ) and $repo and $repo =~ $REPONAME_PATT ) {
# if the user is allowed a shell, just run the command # ok, it's not a normal git command; call the special command helper
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND} if $shell_allowed; &special_cmd ($GL_ADMINDIR, $GL_CONF_COMPILED, $RSYNC_BASE, $HTPASSWD_FILE);
# otherwise, whine exit;
die "bad command: $cmd\n";
} }
die "$repo ends with a slash; I don't like that\n" if $repo =~ /\/$/; die "$repo ends with a slash; I don't like that\n" if $repo =~ /\/$/;
die "$repo has two consecutive periods; I don't like that\n" if $repo =~ /\.\./; die "$repo has two consecutive periods; I don't like that\n" if $repo =~ /\.\./;
# reponame
$ENV{GL_REPO}=$repo;
# ----------------------------------------------------------------------------
# the real git commands (git-receive-pack, etc...)
# ----------------------------------------------------------------------------
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# first level permissions check # first level permissions check
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
@ -163,32 +182,11 @@ die "$perm access for $repo DENIED to $user\n"
unless $repos{$repo}{$perm}{$user} unless $repos{$repo}{$perm}{$user}
or $repos{$repo}{$perm}{'@all'}; or $repos{$repo}{$perm}{'@all'};
# ----------------------------------------------------------------------------
# logging, timestamp. also setup env vars for later
# ----------------------------------------------------------------------------
# reponame
$ENV{GL_REPO}=$repo;
# timestamp
my ($s, $min, $h, $d, $m, $y) = (localtime)[0..5];
$y += 1900; $m++; # usual adjustments
for ($s, $min, $h, $d, $m) {
$_ = "0$_" if $_ < 10;
}
$ENV{GL_TS} = "$y-$m-$d.$h:$min:$s";
# substitute template parameters and set the logfile name
$GL_LOGT =~ s/%y/$y/g;
$GL_LOGT =~ s/%m/$m/g;
$GL_LOGT =~ s/%d/$d/g;
$ENV{GL_LOG} = $GL_LOGT;
&log_it("$ENV{GL_TS}\t$ENV{SSH_ORIGINAL_COMMAND}\t$user\n");
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# over to git now # over to git now
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
&log_it("$ENV{GL_TS}\t$ENV{SSH_ORIGINAL_COMMAND}\t$user\n");
$repo = "'$REPO_BASE/$repo.git'"; $repo = "'$REPO_BASE/$repo.git'";
exec("git", "shell", "-c", "$verb $repo"); exec("git", "shell", "-c", "$verb $repo");

View file

@ -312,7 +312,6 @@ sub parse_conf_file
die "$WARN $fragment attempting to set description for $repo\n" if die "$WARN $fragment attempting to set description for $repo\n" if
$fragment ne 'master' and $fragment ne $repo and ($groups{"\@$fragment"}{$repo} || '') ne 'master'; $fragment ne 'master' and $fragment ne $repo and ($groups{"\@$fragment"}{$repo} || '') ne 'master';
$desc{"$repo.git"} = $desc; $desc{"$repo.git"} = $desc;
$owner =~ s/ /+/g if $owner; # gitweb/INSTALL wants more, but meh...!
$owner{"$repo.git"} = $owner || ''; $owner{"$repo.git"} = $owner || '';
} }
else else
@ -389,8 +388,9 @@ wrap_chdir("$repo_base_abs");
for my $repo (sort keys %repos) { for my $repo (sort keys %repos) {
next unless $repo =~ $REPONAME_PATT; next unless $repo =~ $REPONAME_PATT;
print STDERR "creating $repo...\n"; next if $repo =~ m(^EXTCMD/); # these are not real repos
unless (-d "$repo.git") { unless (-d "$repo.git") {
print STDERR "creating $repo...\n";
new_repo($repo, "$GL_ADMINDIR/src/hooks"); new_repo($repo, "$GL_ADMINDIR/src/hooks");
# new_repo would have chdir'd us away; come back # new_repo would have chdir'd us away; come back
wrap_chdir("$repo_base_abs"); wrap_chdir("$repo_base_abs");
@ -451,16 +451,32 @@ for my $repo (sort keys %repos) {
$projlist{"$repo.git"} = 1; $projlist{"$repo.git"} = 1;
# add the description file; no messages to user or error checking :) # add the description file; no messages to user or error checking :)
$desc{"$repo.git"} and open(DESC, ">", $desc_file) and print DESC $desc{"$repo.git"} . "\n" and close DESC; $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 {
# remove the repository owner setting
system("git --git-dir=$repo.git config --unset-all gitweb.owner 2>/dev/null");
}
} else { } else {
# delete the description file; no messages to user or error checking :) # delete the description file; no messages to user or error checking :)
unlink $desc_file; 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 # update 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" . ( $owner{$proj} ? " $owner{$proj}" : "" ) . "\n"; print $projlist_fh "$proj\n";
} }
close $projlist_fh; close $projlist_fh;