Merge branch 'pu-big-config' into pu
This commit is contained in:
commit
c3d23f8734
6 changed files with 488 additions and 138 deletions
|
@ -82,7 +82,13 @@ $GIT_PATH="";
|
||||||
|
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# BIG CONFIG SETTINGS
|
||||||
|
|
||||||
|
# Please read doc/big-config.mkd for details
|
||||||
|
|
||||||
|
$GL_BIG_CONFIG = 0;
|
||||||
|
$GL_NO_DAEMON_NO_GITWEB = 0;
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# SECURITY SENSITIVE SETTINGS
|
# SECURITY SENSITIVE SETTINGS
|
||||||
|
|
219
doc/big-config.mkd
Normal file
219
doc/big-config.mkd
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
# what is a "big-config"
|
||||||
|
|
||||||
|
In this document:
|
||||||
|
|
||||||
|
* when/why do we need it?
|
||||||
|
* how do we use it?
|
||||||
|
* summary of settings in RC file
|
||||||
|
* what are the downsides?
|
||||||
|
* (extra coolness) usergroups and LDAP/similar tools
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
|
||||||
|
So let's say you have
|
||||||
|
|
||||||
|
@wbr = lynx firefox
|
||||||
|
@devs = alice bob
|
||||||
|
|
||||||
|
repo @wbr
|
||||||
|
RW+ next = @devs
|
||||||
|
RW master = @devs
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
%repos = (
|
||||||
|
'firefox' => {
|
||||||
|
'R' => {
|
||||||
|
'alice' => 1,
|
||||||
|
'bob' => 1
|
||||||
|
},
|
||||||
|
'W' => {
|
||||||
|
'alice' => 1,
|
||||||
|
'bob' => 1
|
||||||
|
},
|
||||||
|
'alice' => [
|
||||||
|
{
|
||||||
|
'refs/heads/next' => 'RW+'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'refs/heads/master' => 'RW'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'bob' => [
|
||||||
|
{
|
||||||
|
'refs/heads/next' => 'RW+'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'refs/heads/master' => 'RW'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'lynx' => {
|
||||||
|
'R' => {
|
||||||
|
'alice' => 1,
|
||||||
|
'bob' => 1
|
||||||
|
},
|
||||||
|
'W' => {
|
||||||
|
'alice' => 1,
|
||||||
|
'bob' => 1
|
||||||
|
},
|
||||||
|
'alice' => [
|
||||||
|
{
|
||||||
|
'refs/heads/next' => 'RW+'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'refs/heads/master' => 'RW'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'bob' => [
|
||||||
|
{
|
||||||
|
'refs/heads/next' => 'RW+'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'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 :)
|
||||||
|
|
||||||
|
### 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. When you do that, and push this
|
||||||
|
configuration, the compiled file looks like this:
|
||||||
|
|
||||||
|
%repos = (
|
||||||
|
'@wbr' => {
|
||||||
|
'@devs' => [
|
||||||
|
{
|
||||||
|
'refs/heads/next' => 'RW+'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'refs/heads/master' => 'RW'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'R' => {
|
||||||
|
'@devs' => 1
|
||||||
|
},
|
||||||
|
'W' => {
|
||||||
|
'@devs' => 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
%groups = (
|
||||||
|
'@devs' => {
|
||||||
|
'alice' => 'master',
|
||||||
|
'bob' => 'master'
|
||||||
|
},
|
||||||
|
'@wbr' => {
|
||||||
|
'firefox' => 'master',
|
||||||
|
'lynx' => 'master'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
That's a lot smaller, and allows orders of magintude more repos and groups to
|
||||||
|
be supported.
|
||||||
|
|
||||||
|
### summary of settings in RC file
|
||||||
|
|
||||||
|
The default RC file contains the following lines:
|
||||||
|
|
||||||
|
$GL_BIG_CONFIG = 0;
|
||||||
|
$GL_NO_DAEMON_NO_GITWEB = 0;
|
||||||
|
|
||||||
|
The first setting means that by default, big-config is off; you can change it
|
||||||
|
to 1 to enable it.
|
||||||
|
|
||||||
|
The second is a very useful optimisation that you *must* enable 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][gw]" for details). This will save a lot of time when
|
||||||
|
you push the gitolite-admin repo with changes.
|
||||||
|
|
||||||
|
[gw]: http://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#gitweb
|
||||||
|
|
||||||
|
### what are the downsides?
|
||||||
|
|
||||||
|
There are a few minor issues.
|
||||||
|
|
||||||
|
First, "deny" rules (rules whose "permission" is a "-" sign), will not work
|
||||||
|
exactly the same as before.
|
||||||
|
|
||||||
|
[TODO: add a nice example etc...]
|
||||||
|
|
||||||
|
Second, 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!)
|
||||||
|
|
||||||
|
### (extra coolness) usergroups and LDAP/similar tools
|
||||||
|
|
||||||
|
[Please NOTE: this is all about *user* groups, not *repo* groups]
|
||||||
|
|
||||||
|
Gitolite now allows usergroup information to be passed in from outside. The
|
||||||
|
`gl-auth-commmand` can now take an optional list of usergroup names after the
|
||||||
|
first argument (which is the username).
|
||||||
|
|
||||||
|
To understand why this is useful, consider the following:
|
||||||
|
|
||||||
|
Some people have an LDAP-backed ssh daemon (or some other similar mechanism
|
||||||
|
that can speak "ssh" to the client), with pubkeys stored in LDAP, etc., and
|
||||||
|
some way (not using `~/.ssh/authorized_keys`) of invoking gitolite.
|
||||||
|
|
||||||
|
Such setups also have "usergroups", and a way to tell, for each user, what
|
||||||
|
groups he/she is a member of. So let's say "alice" works on projects "foo"
|
||||||
|
and "bar", while "bob" is works on project "bar" and is a member of the
|
||||||
|
`L3_support` team.
|
||||||
|
|
||||||
|
You can use those group names in the gitolite config file for access control
|
||||||
|
as "@foo", "@bar", `@L3_support`, etc.; please note the "@" prefix because
|
||||||
|
gitolite requires it.
|
||||||
|
|
||||||
|
However, that still leaves a wee little inconvenience. You still have to add
|
||||||
|
lines like this to the gitolite config file:
|
||||||
|
|
||||||
|
@foo = alice
|
||||||
|
@bar = alice bob
|
||||||
|
@L3_support = bob
|
||||||
|
|
||||||
|
You don't need to do that anymore now. Tell your authentication system that,
|
||||||
|
after authenticating alice, instead of running:
|
||||||
|
|
||||||
|
/some/path/to/gl-auth-command alice
|
||||||
|
|
||||||
|
it should first find the groups that alice is a member of, and then run:
|
||||||
|
|
||||||
|
/some/path/to/gl-auth-command alice foo bar
|
||||||
|
|
||||||
|
That's it. Internally, gitolite will behave as if the config file had also
|
||||||
|
specified:
|
||||||
|
|
||||||
|
@foo = alice
|
||||||
|
@bar = alice
|
|
@ -34,27 +34,12 @@ exit 0 if exists $ENV{GL_BYPASS_UPDATE_HOOK};
|
||||||
|
|
||||||
# we should already have the GL_RC env var set when we enter this hook
|
# we should already have the GL_RC env var set when we enter this hook
|
||||||
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
||||||
# then "do" the compiled config file, whose name we now know. Before doing
|
|
||||||
# that we setup the creator etc from environment variables so that the parse
|
|
||||||
# interpolates them. We've minimised the duplication but this *does*
|
|
||||||
# duplicate a bit of parse_acl from gitolite.pm; we don't want to include that
|
|
||||||
# file here just for that little bit
|
|
||||||
{
|
|
||||||
our $creator = $ENV{GL_CREATOR};
|
|
||||||
our $readers = $ENV{GL_READERS};
|
|
||||||
our $writers = $ENV{GL_WRITERS};
|
|
||||||
our $gl_user = $ENV{GL_USER};
|
|
||||||
|
|
||||||
die "parse $GL_CONF_COMPILED failed: " . ($! or $@) unless do $GL_CONF_COMPILED;
|
|
||||||
|
|
||||||
$repos{$ENV{GL_REPO}} = $repos{$ENV{GL_REPOPATT}} if ( $ENV{GL_REPOPATT} );
|
|
||||||
}
|
|
||||||
my $reported_repo = $ENV{GL_REPO} . ( $ENV{GL_REPOPATT} ? " ($ENV{GL_REPOPATT})" : "" );
|
|
||||||
|
|
||||||
# we've started to need some common subs in what used to be a small, cute,
|
|
||||||
# little script that barely spanned a few lines :(
|
|
||||||
require "$ENV{GL_BINDIR}/gitolite.pm";
|
require "$ENV{GL_BINDIR}/gitolite.pm";
|
||||||
|
|
||||||
|
my ($perm, $creator, $wild) = &repo_rights($ENV{GL_REPO});
|
||||||
|
my $reported_repo = $ENV{GL_REPO} . ( $ENV{GL_REPOPATT} ? " ($ENV{GL_REPOPATT})" : "" );
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# start...
|
# start...
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
@ -71,17 +56,17 @@ chomp($merge_base = `git merge-base $oldsha $newsha`)
|
||||||
unless $oldsha eq '0' x 40
|
unless $oldsha eq '0' x 40
|
||||||
or $newsha eq '0' x 40;
|
or $newsha eq '0' x 40;
|
||||||
|
|
||||||
# what are you trying to do? (is it 'W' or '+'?)
|
# att_acc == attempted access -- what are you trying to do? (is it 'W' or '+'?)
|
||||||
my $perm = 'W';
|
my $att_acc = 'W';
|
||||||
# rewriting a tag is considered a rewind, in terms of permissions
|
# rewriting a tag is considered a rewind, in terms of permissions
|
||||||
$perm = '+' if $ref =~ m(refs/tags/) and $oldsha ne ('0' x 40);
|
$att_acc = '+' if $ref =~ m(refs/tags/) and $oldsha ne ('0' x 40);
|
||||||
# non-ff push to ref
|
# non-ff push to ref
|
||||||
# notice that ref delete looks like a rewind, as it should
|
# notice that ref delete looks like a rewind, as it should
|
||||||
$perm = '+' if $oldsha ne $merge_base;
|
$att_acc = '+' if $oldsha ne $merge_base;
|
||||||
|
|
||||||
# were any 'D' perms specified? If they were, it means we have to separate
|
# were any 'D' perms specified? If they were, it means we have to separate
|
||||||
# deletes from rewinds, so if the new sha is all 0's, change the '+' to a 'D'
|
# deletes from rewinds, so if the new sha is all 0's, change the '+' to a 'D'
|
||||||
$perm = 'D' if ( $repos{$ENV{GL_REPO}}{DELETE_IS_D} or $repos{'@all'}{DELETE_IS_D} ) and $newsha eq '0' x 40;
|
$att_acc = 'D' if ( $repos{$ENV{GL_REPO}}{DELETE_IS_D} or $repos{'@all'}{DELETE_IS_D} ) and $newsha eq '0' x 40;
|
||||||
|
|
||||||
my @allowed_refs;
|
my @allowed_refs;
|
||||||
# @all repos: see comments in similar code in check_access
|
# @all repos: see comments in similar code in check_access
|
||||||
|
@ -113,12 +98,12 @@ if (exists $repos{$ENV{GL_REPO}}{NAME_LIMITS}) {
|
||||||
# log is the *first* one (which is a *real* ref, like refs/heads/master),
|
# log is the *first* one (which is a *real* ref, like refs/heads/master),
|
||||||
# while all the rest (if they exist) are like NAME/something. So we do the
|
# while all the rest (if they exist) are like NAME/something. So we do the
|
||||||
# first one separately to capture it, then run the rest (if any)
|
# first one separately to capture it, then run the rest (if any)
|
||||||
my $log_refex = check_ref(\@allowed_refs, $ENV{GL_REPO}, (shift @refs), $perm);
|
my $log_refex = check_ref(\@allowed_refs, $ENV{GL_REPO}, (shift @refs), $att_acc);
|
||||||
&check_ref (\@allowed_refs, $ENV{GL_REPO}, $_ , $perm) for @refs;
|
&check_ref (\@allowed_refs, $ENV{GL_REPO}, $_ , $att_acc) for @refs;
|
||||||
|
|
||||||
# if we returned at all, all the checks succeeded, so we log the action and exit 0
|
# if we returned at all, all the checks succeeded, so we log the action and exit 0
|
||||||
|
|
||||||
&log_it("$ENV{GL_TS} $perm\t" .
|
&log_it("$ENV{GL_TS} $att_acc\t" .
|
||||||
substr($oldsha, 0, 14) . "\t" . substr($newsha, 0, 14) .
|
substr($oldsha, 0, 14) . "\t" . substr($newsha, 0, 14) .
|
||||||
"\t$reported_repo\t$ref\t$ENV{GL_USER}\t$log_refex\n");
|
"\t$reported_repo\t$ref\t$ENV{GL_USER}\t$log_refex\n");
|
||||||
|
|
||||||
|
|
191
src/gitolite.pm
191
src/gitolite.pm
|
@ -1,4 +1,7 @@
|
||||||
use strict;
|
use strict;
|
||||||
|
use Data::Dumper;
|
||||||
|
$Data::Dumper::Deepcopy = 1;
|
||||||
|
|
||||||
# this file is commonly used using "require". It is not required to use "use"
|
# this file is commonly used using "require". It is not required to use "use"
|
||||||
# (because it doesn't live in a different package)
|
# (because it doesn't live in a different package)
|
||||||
|
|
||||||
|
@ -34,8 +37,9 @@ our $USERNAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$); # very simple patter
|
||||||
our $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$);
|
our $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$);
|
||||||
|
|
||||||
# these come from the RC file
|
# these come from the RC file
|
||||||
our ($REPO_UMASK, $GL_WILDREPOS, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $REPO_BASE, $GL_CONF_COMPILED);
|
our ($REPO_UMASK, $GL_WILDREPOS, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $REPO_BASE, $GL_CONF_COMPILED, $GL_BIG_CONFIG);
|
||||||
our %repos;
|
our %repos;
|
||||||
|
our %groups;
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# convenience subs
|
# convenience subs
|
||||||
|
@ -253,24 +257,39 @@ sub parse_acl
|
||||||
# want the config dumped as is, really
|
# want the config dumped as is, really
|
||||||
return unless $repo;
|
return unless $repo;
|
||||||
|
|
||||||
# return with "no wildcard match" status if you found the actual repo in
|
my ($wild, @repo_plus, @user_plus);
|
||||||
# the config or if wild is unset
|
# expand $repo and $gl_user into all possible matching values
|
||||||
return $ENV{GL_REPOPATT} = "" if $repos{$repo} or not $GL_WILDREPOS;
|
($wild, @repo_plus) = &get_memberships($repo, 1);
|
||||||
|
( @user_plus) = &get_memberships($gl_user, 0);
|
||||||
|
# XXX testing notes: the above should return just one entry during
|
||||||
|
# non-BC usage, whether wild or not
|
||||||
|
die "assert 1 failed" if (@repo_plus > 1 and $repo_plus[-1] ne '@all'
|
||||||
|
or @repo_plus > 2) and not $GL_BIG_CONFIG;
|
||||||
|
|
||||||
# didn't find actual repo in %repos, and wild is set, so find the repo
|
# the old "convenience copy" thing. Now on steroids :)
|
||||||
# pattern that matches the actual repo
|
|
||||||
my @matched = grep { $repo =~ /^$_$/ } sort keys %repos;
|
|
||||||
|
|
||||||
# didn't find a match? avoid leaking info to user about repo existence;
|
# note that when copying the @all entry, we retain the destination name as
|
||||||
# as before, pretend "no wildcard match" status
|
# @all; we dont change it to $repo or $gl_user
|
||||||
return $ENV{GL_REPOPATT} = "" unless @matched;
|
for my $r ('@all', @repo_plus) {
|
||||||
|
my $dr = $repo; $dr = '@all' if $r eq '@all';
|
||||||
|
$repos{$dr}{DELETE_IS_D} = 1 if $repos{$r}{DELETE_IS_D};
|
||||||
|
$repos{$dr}{NAME_LIMITS} = 1 if $repos{$r}{NAME_LIMITS};
|
||||||
|
|
||||||
die "$repo has multiple matches\n@matched\n" if @matched > 1;
|
for my $u ('@all', @user_plus) {
|
||||||
|
my $du = $gl_user; $du = '@all' if $u eq '@all';
|
||||||
|
$repos{$dr}{C}{$du} = 1 if $repos{$r}{C}{$u};
|
||||||
|
$repos{$dr}{R}{$du} = 1 if $repos{$r}{R}{$u};
|
||||||
|
$repos{$dr}{W}{$du} = 1 if $repos{$r}{W}{$u};
|
||||||
|
|
||||||
# found exactly one pattern that matched, copy its ACL for convenience
|
next if $r eq $dr and $u eq $du; # no point duplicating those refexes
|
||||||
$repos{$repo} = $repos{$matched[0]};
|
push @{ $repos{$dr}{$du} }, @{ $repos{$r}{$u} }
|
||||||
# and return the pattern
|
if exists $repos{$r}{$u} and ref($repos{$r}{$u}) eq 'ARRAY';
|
||||||
return $ENV{GL_REPOPATT} = $matched[0];
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ENV{GL_REPOPATT} = "";
|
||||||
|
$ENV{GL_REPOPATT} = $wild if $wild and $GL_WILDREPOS;
|
||||||
|
return ($wild);
|
||||||
}
|
}
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
@ -295,6 +314,11 @@ sub report_basic
|
||||||
&report_version($GL_ADMINDIR, $user);
|
&report_version($GL_ADMINDIR, $user);
|
||||||
print "\rthe gitolite config gives you the following access:\r\n";
|
print "\rthe gitolite config gives you the following access:\r\n";
|
||||||
for my $r (sort keys %repos) {
|
for my $r (sort keys %repos) {
|
||||||
|
if ($r =~ $REPONAME_PATT) {
|
||||||
|
&parse_acl($GL_CONF_COMPILED, $r, "NOBODY", "NOBODY", "NOBODY");
|
||||||
|
} else {
|
||||||
|
&parse_acl($GL_CONF_COMPILED, $r, $ENV{GL_USER}, "NOBODY", "NOBODY");
|
||||||
|
}
|
||||||
# @all repos; meaning of read/write flags:
|
# @all repos; meaning of read/write flags:
|
||||||
# @R => @all users are allowed access to this repo
|
# @R => @all users are allowed access to this repo
|
||||||
# #R => you're a super user and can see @all repos
|
# #R => you're a super user and can see @all repos
|
||||||
|
@ -331,7 +355,7 @@ sub expand_wild
|
||||||
# actual_repo has to match the pattern being expanded
|
# actual_repo has to match the pattern being expanded
|
||||||
next unless $actual_repo =~ /$repo/;
|
next unless $actual_repo =~ /$repo/;
|
||||||
|
|
||||||
my($perm, $creator) = &repo_rights($actual_repo);
|
my($perm, $creator, $wild) = &repo_rights($actual_repo);
|
||||||
next unless $perm =~ /\S/;
|
next unless $perm =~ /\S/;
|
||||||
print "$perm\t$creator\t$actual_repo\n";
|
print "$perm\t$creator\t$actual_repo\n";
|
||||||
}
|
}
|
||||||
|
@ -342,64 +366,67 @@ sub expand_wild
|
||||||
# how/why). Regardless of how we're called, we assume $ENV{GL_USER} is
|
# how/why). Regardless of how we're called, we assume $ENV{GL_USER} is
|
||||||
# already defined
|
# already defined
|
||||||
{
|
{
|
||||||
my %normal_repos;
|
my $last_repo = '';
|
||||||
|
|
||||||
sub repo_rights {
|
sub repo_rights {
|
||||||
my $repo = shift;
|
my $repo = shift;
|
||||||
$repo =~ s/^\.\///;
|
$repo =~ s/^\.\///;
|
||||||
$repo =~ s/\.git$//;
|
$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
|
# 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
|
# (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"
|
# a wildrepo, it may or may not exist. If it doesn't exist, the "C"
|
||||||
# perms are also filled in, else that column is left blank
|
# perms are also filled in, else that column is left blank
|
||||||
|
|
||||||
unless (%normal_repos) {
|
unless ($REPO_BASE) {
|
||||||
unless ($REPO_BASE) {
|
# means we've been called from outside; see doc/admin-defined-commands.mkd
|
||||||
# means we've been called from outside
|
&where_is_rc();
|
||||||
&where_is_rc();
|
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
||||||
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
|
||||||
}
|
|
||||||
|
|
||||||
&parse_acl($GL_CONF_COMPILED, "", "NOBODY", "NOBODY", "NOBODY");
|
|
||||||
%normal_repos = %repos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
my $creator;
|
|
||||||
my $perm = ' ';
|
my $perm = ' ';
|
||||||
|
my $creator;
|
||||||
|
|
||||||
# if repo is present "as is" in the config, those permissions will
|
# get basic info about the repo and fill %repos
|
||||||
# override anything inherited from a wildcard that may have matched
|
my $wild = '';
|
||||||
if ($normal_repos{$repo}) {
|
my $exists = -d "$ENV{GL_REPO_BASE_ABS}/$repo.git";
|
||||||
%repos = %normal_repos;
|
if ($exists) {
|
||||||
$creator = '<gitolite>';
|
# these will be empty if it's not a wildcard repo anyway
|
||||||
} elsif ( -d "$ENV{GL_REPO_BASE_ABS}/$repo.git" ) {
|
|
||||||
# must be a wildrepo, and it has already been created; find the
|
|
||||||
# creator and subsitute in repos
|
|
||||||
my ($read, $write);
|
my ($read, $write);
|
||||||
($creator, $read, $write) = &wild_repo_rights($ENV{GL_REPO_BASE_ABS}, $repo, $ENV{GL_USER});
|
($creator, $read, $write) = &wild_repo_rights($ENV{GL_REPO_BASE_ABS}, $repo, $ENV{GL_USER});
|
||||||
# get access list with these substitutions
|
# get access list with these substitutions
|
||||||
&parse_acl($GL_CONF_COMPILED, $repo, $creator || "NOBODY", $read || "NOBODY", $write || "NOBODY");
|
$wild = &parse_acl($GL_CONF_COMPILED, $repo, $creator || "NOBODY", $read || "NOBODY", $write || "NOBODY");
|
||||||
|
} else {
|
||||||
|
$wild = &parse_acl($GL_CONF_COMPILED, $repo, $ENV{GL_USER}, "NOBODY", "NOBODY");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exists and not $wild) {
|
||||||
|
$creator = '<gitolite>';
|
||||||
|
} elsif ($exists) {
|
||||||
|
# is a wildrepo, and it has already been created
|
||||||
$creator = "($creator)";
|
$creator = "($creator)";
|
||||||
} else {
|
} else {
|
||||||
# repo didn't exist; C perms also need to be filled in after
|
# repo didn't exist; C perms need to be filled in
|
||||||
# getting access list with only creator filled in
|
|
||||||
&parse_acl($GL_CONF_COMPILED, $repo, $ENV{GL_USER}, "NOBODY", "NOBODY");
|
|
||||||
$perm = ( $repos{$repo}{C}{'@all'} ? ' @C' : ( $repos{$repo}{C}{$ENV{GL_USER}} ? ' =C' : ' ' )) if $GL_WILDREPOS;
|
$perm = ( $repos{$repo}{C}{'@all'} ? ' @C' : ( $repos{$repo}{C}{$ENV{GL_USER}} ? ' =C' : ' ' )) if $GL_WILDREPOS;
|
||||||
# if you didn't have perms to create it, delete the "convenience"
|
# if you didn't have perms to create it, delete the "convenience"
|
||||||
# copy of the ACL that parse_acl makes
|
# copy of the ACL that parse_acl makes
|
||||||
delete $repos{$repo} unless $perm =~ /C/;
|
delete $repos{$repo} unless $perm =~ /C/;
|
||||||
$creator = "<repo_not_found>";
|
$creator = "<notfound>";
|
||||||
}
|
}
|
||||||
$perm .= ( $repos{$repo}{R}{'@all'} ? ' @R' : ( $repos{'@all'}{R}{$ENV{GL_USER}} ? ' #R' : ( $repos{$repo}{R}{$ENV{GL_USER}} ? ' R' : ' ' )));
|
$perm .= ( $repos{$repo}{R}{'@all'} ? ' @R' : ( $repos{'@all'}{R}{$ENV{GL_USER}} ? ' #R' : ( $repos{$repo}{R}{$ENV{GL_USER}} ? ' R' : ' ' )));
|
||||||
$perm .= ( $repos{$repo}{W}{'@all'} ? ' @W' : ( $repos{'@all'}{W}{$ENV{GL_USER}} ? ' #W' : ( $repos{$repo}{W}{$ENV{GL_USER}} ? ' W' : ' ' )));
|
$perm .= ( $repos{$repo}{W}{'@all'} ? ' @W' : ( $repos{'@all'}{W}{$ENV{GL_USER}} ? ' #W' : ( $repos{$repo}{W}{$ENV{GL_USER}} ? ' W' : ' ' )));
|
||||||
return($perm, $creator);
|
|
||||||
|
# set up for caching %repos
|
||||||
|
$last_repo = $repo;
|
||||||
|
|
||||||
|
return($perm, $creator, $wild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# helper/convenience routine to get rights and ownership from a shell command
|
# helper/convenience routine to get rights and ownership from a shell command
|
||||||
sub cli_repo_rights {
|
sub cli_repo_rights {
|
||||||
my ($perm, $creator) = &repo_rights($_[0]);
|
my ($perm, $creator, $wild) = &repo_rights($_[0]);
|
||||||
$perm =~ s/ /_/g;
|
$perm =~ s/ /_/g;
|
||||||
$creator =~ s/^\(|\)$//g;
|
$creator =~ s/^\(|\)$//g;
|
||||||
print "$perm $creator\n";
|
print "$perm $creator\n";
|
||||||
|
@ -443,6 +470,84 @@ sub special_cmd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# get memberships
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# given a plain reponame or username, return:
|
||||||
|
# - the name itself, plus all the groups it belongs to if $GL_BIG_CONFIG is
|
||||||
|
# set
|
||||||
|
# OR
|
||||||
|
# - (for repos) if the name itself doesn't exist in the config, a wildcard
|
||||||
|
# matching it, plus all the groups that wildcard belongs to (again if
|
||||||
|
# $GL_BIG_CONFIG is set)
|
||||||
|
|
||||||
|
# A name can normally appear (repo example) (user example)
|
||||||
|
# - directly (repo foo) (RW = bar)
|
||||||
|
# - (only for repos) as a direct wildcard (repo foo/.*)
|
||||||
|
# but if $GL_BIG_CONFIG is set, it can also appear:
|
||||||
|
# - indirectly (@g = foo; repo @g) (@ug = bar; RW = @ug))
|
||||||
|
# - (only for repos) as an indirect wildcard (@g = foo/.*; repo @g).
|
||||||
|
# things that may not be obvious from the above:
|
||||||
|
# - the wildcard stuff does not apply to username memberships
|
||||||
|
# - for repos, wildcard appearances are TOTALLY ignored if a non-wild
|
||||||
|
# appearance (direct or indirect) exists
|
||||||
|
|
||||||
|
sub get_memberships {
|
||||||
|
my $base = shift; # reponame or username
|
||||||
|
my $is_repo = shift; # some true value means a repo name has been passed
|
||||||
|
|
||||||
|
my $wild = '';
|
||||||
|
my (@ret, @ret_w); # maintain wild matches separately from non-wild
|
||||||
|
|
||||||
|
# direct
|
||||||
|
push @ret, $base if not $is_repo or exists $repos{$base};
|
||||||
|
if ($is_repo and $GL_WILDREPOS and not @ret) {
|
||||||
|
for my $i (sort keys %repos) {
|
||||||
|
if ($base =~ /^$i$/) {
|
||||||
|
die "$ABRT $base matches $wild AND $i\n" if $wild and $wild ne $i;
|
||||||
|
$wild = $i;
|
||||||
|
# direct wildcard
|
||||||
|
push @ret_w, $i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($GL_BIG_CONFIG) {
|
||||||
|
for my $g (sort keys %groups) {
|
||||||
|
for my $i (sort keys %{ $groups{$g} }) {
|
||||||
|
if ($base eq $i) {
|
||||||
|
# indirect
|
||||||
|
push @ret, $g;
|
||||||
|
} elsif ($is_repo and $GL_WILDREPOS and not @ret and $base =~ /^$i$/) {
|
||||||
|
die "$ABRT $base matches $wild AND $i\n" if $wild and $wild ne $i;
|
||||||
|
$wild = $i;
|
||||||
|
# indirect wildcard
|
||||||
|
push @ret_w, $g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# deal with returning user info first
|
||||||
|
unless ($is_repo) {
|
||||||
|
# add in group membership info sent in via second and subsequent
|
||||||
|
# arguments to gl-auth-command; be sure to prefix the "@" sign to each
|
||||||
|
# of them!
|
||||||
|
push @ret, map { s/^/@/; $_; } split(' ', $ENV{GL_GROUP_LIST}) if $ENV{GL_GROUP_LIST};
|
||||||
|
return (@ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
# enforce the rule about ignoring all wildcard matches if a non-wild match
|
||||||
|
# exists while returning. (The @ret gating above does not adequately
|
||||||
|
# ensure this, it is only an optimisation).
|
||||||
|
#
|
||||||
|
# Also note that there is an extra return value when called for repos
|
||||||
|
# (compared to usernames)
|
||||||
|
|
||||||
|
return ((@ret ? '' : $wild), (@ret ? @ret : @ret_w));
|
||||||
|
}
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# generic check access routine
|
# generic check access routine
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
|
@ -28,6 +28,7 @@ our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMIND
|
||||||
# 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;
|
||||||
|
our %groups;
|
||||||
|
|
||||||
# the common setup module is in the same directory as this running program is
|
# the common setup module is in the same directory as this running program is
|
||||||
my $bindir = $0;
|
my $bindir = $0;
|
||||||
|
@ -55,6 +56,10 @@ my $repo_base_abs = $ENV{GL_REPO_BASE_ABS} = ( $REPO_BASE =~ m(^/) ? $REPO_BASE
|
||||||
# start...
|
# start...
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# no arguments given? default user is $USER (fedorahosted works like this,
|
||||||
|
# and it is harmless for others)
|
||||||
|
@ARGV = ($ENV{USER}) unless @ARGV;
|
||||||
|
|
||||||
# if the first argument is a "-s", this user is allowed to get a shell using
|
# if the first argument is a "-s", this user is allowed to get a shell using
|
||||||
# this key
|
# this key
|
||||||
my $shell_allowed = 0;
|
my $shell_allowed = 0;
|
||||||
|
@ -66,6 +71,10 @@ 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!
|
||||||
|
|
||||||
|
# if there are any more arguments, they're a list of group names that the user
|
||||||
|
# is a member of
|
||||||
|
$ENV{GL_GROUP_LIST} = join(" ", @ARGV) if @ARGV;
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# logging, timestamp env vars
|
# logging, timestamp env vars
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
@ -184,7 +193,7 @@ $ENV{GL_REPO}=$repo;
|
||||||
# first level permissions check
|
# first level permissions check
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
my ($perm, $creator) = &repo_rights($repo);
|
my ($perm, $creator, $wild) = &repo_rights($repo);
|
||||||
if ($perm =~ /C/) {
|
if ($perm =~ /C/) {
|
||||||
# it was missing, and you have create perms
|
# it was missing, and you have create perms
|
||||||
wrap_chdir("$repo_base_abs");
|
wrap_chdir("$repo_base_abs");
|
||||||
|
|
|
@ -52,7 +52,7 @@ $Data::Dumper::Sortkeys = 1;
|
||||||
open STDOUT, ">", "/dev/null" if (@ARGV and shift eq '-q');
|
open STDOUT, ">", "/dev/null" if (@ARGV and shift eq '-q');
|
||||||
|
|
||||||
# these are set by the "rc" file
|
# these are set by the "rc" file
|
||||||
our ($GL_ADMINDIR, $GL_CONF, $GL_KEYDIR, $GL_CONF_COMPILED, $REPO_BASE, $REPO_UMASK, $PROJECTS_LIST, $GIT_PATH, $GL_WILDREPOS, $GL_GITCONFIG_KEYS, $GL_PACKAGE_HOOKS, $GL_SETPERMS_OVERRIDES_CONFIG);
|
our ($GL_ADMINDIR, $GL_CONF, $GL_KEYDIR, $GL_CONF_COMPILED, $REPO_BASE, $REPO_UMASK, $PROJECTS_LIST, $GIT_PATH, $GL_WILDREPOS, $GL_GITCONFIG_KEYS, $GL_PACKAGE_HOOKS, $GL_SETPERMS_OVERRIDES_CONFIG, $GL_BIG_CONFIG, $GL_NO_DAEMON_NO_GITWEB);
|
||||||
# and these are set by gitolite.pm
|
# and these are set by gitolite.pm
|
||||||
our ($REPONAME_PATT, $REPOPATT_PATT, $USERNAME_PATT, $AUTH_COMMAND, $AUTH_OPTIONS, $ABRT, $WARN);
|
our ($REPONAME_PATT, $REPOPATT_PATT, $USERNAME_PATT, $AUTH_COMMAND, $AUTH_OPTIONS, $ABRT, $WARN);
|
||||||
|
|
||||||
|
@ -173,6 +173,8 @@ sub parse_conf_file
|
||||||
# user or repo groups
|
# user or repo groups
|
||||||
if (/^(@\S+) = (.*)/)
|
if (/^(@\S+) = (.*)/)
|
||||||
{
|
{
|
||||||
|
die "$ABRT defining groups is not allowed inside fragments\n"
|
||||||
|
if $GL_BIG_CONFIG and $fragment ne 'master';
|
||||||
# store the members of each group as hash key. Keep track of when
|
# store the members of each group as hash key. Keep track of when
|
||||||
# the group was *first* created by using $fragment as the *value*
|
# the group was *first* created by using $fragment as the *value*
|
||||||
do { $groups{$1}{$_} ||= $fragment } for ( expand_list( split(' ', $2) ) );
|
do { $groups{$1}{$_} ||= $fragment } for ( expand_list( split(' ', $2) ) );
|
||||||
|
@ -181,10 +183,12 @@ sub parse_conf_file
|
||||||
# repo(s)
|
# repo(s)
|
||||||
elsif (/^repo (.*)/)
|
elsif (/^repo (.*)/)
|
||||||
{
|
{
|
||||||
# grab the list and expand any @stuff in it
|
# grab the list...
|
||||||
@repos = split ' ', $1;
|
@repos = split ' ', $1;
|
||||||
unless (@repos == 1 and $repos[0] eq '@all') {
|
unless (@repos == 1 and $repos[0] eq '@all') {
|
||||||
@repos = expand_list ( @repos );
|
# ...expand groups in the default case
|
||||||
|
@repos = expand_list ( @repos ) unless $GL_BIG_CONFIG;
|
||||||
|
# ...sanity check
|
||||||
for (@repos) {
|
for (@repos) {
|
||||||
die "$ABRT bad reponame $_\n"
|
die "$ABRT bad reponame $_\n"
|
||||||
if ($GL_WILDREPOS and $_ !~ $REPOPATT_PATT);
|
if ($GL_WILDREPOS and $_ !~ $REPOPATT_PATT);
|
||||||
|
@ -214,7 +218,7 @@ sub parse_conf_file
|
||||||
|
|
||||||
# expand the user list, unless it is just "@all"
|
# expand the user list, unless it is just "@all"
|
||||||
@users = expand_list ( @users )
|
@users = expand_list ( @users )
|
||||||
unless (@users == 1 and $users[0] eq '@all');
|
unless ($GL_BIG_CONFIG or (@users == 1 and $users[0] eq '@all'));
|
||||||
do { die "$ABRT bad username $_\n" unless $_ =~ $USERNAME_PATT } for @users;
|
do { die "$ABRT bad username $_\n" unless $_ =~ $USERNAME_PATT } for @users;
|
||||||
|
|
||||||
s/\bCREAT[EO]R\b/~\$creator/g for @users;
|
s/\bCREAT[EO]R\b/~\$creator/g for @users;
|
||||||
|
@ -237,6 +241,8 @@ sub parse_conf_file
|
||||||
# fragment is also called 'foo' (you're allowed to have a
|
# fragment is also called 'foo' (you're allowed to have a
|
||||||
# fragment that is only concerned with one repo)
|
# fragment that is only concerned with one repo)
|
||||||
( $fragment eq $repo ) or
|
( $fragment eq $repo ) or
|
||||||
|
# same thing in big-config-land; foo is just @foo now
|
||||||
|
( $GL_BIG_CONFIG and "\@$fragment" eq $repo ) or
|
||||||
# fragment is called "bar" and "@bar = foo" has been
|
# fragment is called "bar" and "@bar = foo" has been
|
||||||
# defined in the master config
|
# defined in the master config
|
||||||
( ($groups{"\@$fragment"}{$repo} || '') eq 'master' )
|
( ($groups{"\@$fragment"}{$repo} || '') eq 'master' )
|
||||||
|
@ -370,6 +376,7 @@ my $dumped_data = Data::Dumper->Dump([\%repos], [qw(*repos)]);
|
||||||
# much...
|
# much...
|
||||||
$dumped_data =~ s/'(?=[^']*\$(?:creator|readers|writers|gl_user))~*(.*?)'/"$1"/g;
|
$dumped_data =~ s/'(?=[^']*\$(?:creator|readers|writers|gl_user))~*(.*?)'/"$1"/g;
|
||||||
print $compiled_fh $dumped_data;
|
print $compiled_fh $dumped_data;
|
||||||
|
print $compiled_fh Data::Dumper->Dump([\%groups], [qw(*groups)]) if $GL_BIG_CONFIG and %groups;
|
||||||
close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n";
|
close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n";
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
@ -402,28 +409,37 @@ die "\n\t\t***** AAARGH! *****\n" .
|
||||||
# so if it was not already absolute, prefix $HOME.
|
# so if it was not already absolute, prefix $HOME.
|
||||||
my $repo_base_abs = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
|
my $repo_base_abs = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
|
||||||
|
|
||||||
wrap_chdir("$repo_base_abs");
|
{
|
||||||
|
wrap_chdir("$repo_base_abs");
|
||||||
|
|
||||||
for my $repo (sort keys %repos) {
|
# autocreate repos. Start with the ones that are normal repos in %repos
|
||||||
next unless $repo =~ $REPONAME_PATT;
|
my @repos = grep { $_ =~ $REPONAME_PATT and not /^@/ } sort keys %repos;
|
||||||
next if $repo =~ m(^EXTCMD/); # these are not real repos
|
# then, for each repogroup, find the members of the group and add them in
|
||||||
next if $repo eq '@all';
|
map { push @repos, keys %{ $groups{$_} } } grep { /^@/ } keys %repos;
|
||||||
unless (-d "$repo.git") {
|
# weed out duplicates (the code in the loop below is disk activity!)
|
||||||
print STDERR "creating $repo...\n";
|
my %seen = map { $_ => 1 } @repos;
|
||||||
new_repo($repo, "$GL_ADMINDIR/hooks/common");
|
@repos = sort keys %seen;
|
||||||
# new_repo would have chdir'd us away; come back
|
|
||||||
wrap_chdir("$repo_base_abs");
|
|
||||||
}
|
|
||||||
|
|
||||||
# when repos are copied over from elsewhere, one had to run easy install
|
for my $repo (sort @repos) {
|
||||||
# once again to make the new (OS-copied) repo contain the proper update
|
next unless $repo =~ $REPONAME_PATT;
|
||||||
# hook. Perhaps we can make this easier now, and eliminate the easy
|
next if $repo =~ m(^\@|EXTCMD/); # these are not real repos
|
||||||
# install, with a quick check (and a new, empty, "hook" as a sentinel)
|
unless (-d "$repo.git") {
|
||||||
unless (-l "$repo.git/hooks/gitolite-hooked") {
|
print STDERR "creating $repo...\n";
|
||||||
ln_sf("$GL_ADMINDIR/hooks/common", "*", "$repo.git/hooks");
|
new_repo($repo, "$GL_ADMINDIR/hooks/common");
|
||||||
# in case of package install, GL_ADMINDIR is no longer the top cop;
|
# new_repo would have chdir'd us away; come back
|
||||||
# override with the package hooks
|
wrap_chdir("$repo_base_abs");
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,56 +470,60 @@ for my $repo (keys %repo_config) {
|
||||||
|
|
||||||
wrap_chdir("$repo_base_abs");
|
wrap_chdir("$repo_base_abs");
|
||||||
|
|
||||||
# daemons first...
|
unless ($GL_NO_DAEMON_NO_GITWEB) {
|
||||||
for my $repo (sort keys %repos) {
|
# daemons first...
|
||||||
next unless $repo =~ $REPONAME_PATT;
|
for my $repo (sort keys %repos) {
|
||||||
my $export_ok = "$repo.git/git-daemon-export-ok";
|
next unless $repo =~ $REPONAME_PATT;
|
||||||
if ($repos{$repo}{'R'}{'daemon'}) {
|
next if $repo =~ m(^\@|EXTCMD/); # these are not real repos
|
||||||
system("touch $export_ok");
|
my $export_ok = "$repo.git/git-daemon-export-ok";
|
||||||
} else {
|
if ($repos{$repo}{'R'}{'daemon'}) {
|
||||||
unlink($export_ok);
|
system("touch $export_ok");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my %projlist = ();
|
|
||||||
# ...then gitwebs
|
|
||||||
for my $repo (sort keys %repos) {
|
|
||||||
next unless $repo =~ $REPONAME_PATT;
|
|
||||||
my $desc_file = "$repo.git/description";
|
|
||||||
# note: having a description also counts as enabling gitweb
|
|
||||||
if ($repos{$repo}{'R'}{'gitweb'} or $desc{"$repo.git"}) {
|
|
||||||
$projlist{"$repo.git"} = 1;
|
|
||||||
# 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;
|
|
||||||
if ($owner{"$repo.git"}) {
|
|
||||||
# set the repository owner
|
|
||||||
system("git", "--git-dir=$repo.git", "config", "gitweb.owner", $owner{"$repo.git"});
|
|
||||||
} else {
|
} else {
|
||||||
|
unlink($export_ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my %projlist = ();
|
||||||
|
# ...then gitwebs
|
||||||
|
for my $repo (sort keys %repos) {
|
||||||
|
next unless $repo =~ $REPONAME_PATT;
|
||||||
|
next if $repo =~ m(^\@|EXTCMD/); # these are not real repos
|
||||||
|
my $desc_file = "$repo.git/description";
|
||||||
|
# note: having a description also counts as enabling gitweb
|
||||||
|
if ($repos{$repo}{'R'}{'gitweb'} or $desc{"$repo.git"}) {
|
||||||
|
$projlist{"$repo.git"} = 1;
|
||||||
|
# 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;
|
||||||
|
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 {
|
||||||
|
# delete the description file; no messages to user or error checking :)
|
||||||
|
unlink $desc_file;
|
||||||
# remove the repository owner setting
|
# remove the repository owner setting
|
||||||
system("git --git-dir=$repo.git config --unset-all gitweb.owner 2>/dev/null");
|
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 :)
|
# unless there are other gitweb.* keys set, remove the section to keep the
|
||||||
unlink $desc_file;
|
# config file clean
|
||||||
# remove the repository owner setting
|
my $keys = `git --git-dir=$repo.git config --get-regexp '^gitweb\\.' 2>/dev/null`;
|
||||||
system("git --git-dir=$repo.git config --unset-all gitweb.owner 2>/dev/null");
|
if (length($keys) == 0) {
|
||||||
|
system("git --git-dir=$repo.git config --remove-section gitweb 2>/dev/null");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# unless there are other gitweb.* keys set, remove the section to keep the
|
# update the project list
|
||||||
# config file clean
|
my $projlist_fh = wrap_open( ">", $PROJECTS_LIST);
|
||||||
my $keys = `git --git-dir=$repo.git config --get-regexp '^gitweb\\.' 2>/dev/null`;
|
for my $proj (sort keys %projlist) {
|
||||||
if (length($keys) == 0) {
|
print $projlist_fh "$proj\n";
|
||||||
system("git --git-dir=$repo.git config --remove-section gitweb 2>/dev/null");
|
|
||||||
}
|
}
|
||||||
|
close $projlist_fh;
|
||||||
}
|
}
|
||||||
|
|
||||||
# update the project list
|
|
||||||
my $projlist_fh = wrap_open( ">", $PROJECTS_LIST);
|
|
||||||
for my $proj (sort keys %projlist) {
|
|
||||||
print $projlist_fh "$proj\n";
|
|
||||||
}
|
|
||||||
close $projlist_fh;
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# "compile" ssh authorized_keys
|
# "compile" ssh authorized_keys
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
@ -560,10 +580,16 @@ for my $pubkey (`find . -type f`)
|
||||||
print $newkeys_fh $pubkey_content;
|
print $newkeys_fh $pubkey_content;
|
||||||
}
|
}
|
||||||
# lint check 3; a little more severe than the first two I guess...
|
# lint check 3; a little more severe than the first two I guess...
|
||||||
for my $user (sort keys %user_list)
|
|
||||||
{
|
{
|
||||||
next if $user =~ /^(gitweb|daemon|\@all|~\$creator|\$readers|\$writers)$/ or $user_list{$user} eq 'has pubkey';
|
my @no_pubkey =
|
||||||
print STDERR "$WARN user $user in config, but has no pubkey!\n";
|
grep { $_ !~ /^(gitweb|daemon|\@.*|~\$creator|\$readers|\$writers)$/ }
|
||||||
|
grep { $user_list{$_} ne 'has pubkey' }
|
||||||
|
keys %user_list;
|
||||||
|
if (@no_pubkey > 10) {
|
||||||
|
print STDERR "$WARN You have " . scalar(@no_pubkey) . " users WITHOUT pubkeys...!\n";
|
||||||
|
} elsif (@no_pubkey) {
|
||||||
|
print STDERR "$WARN the following users have no pubkeys:\n", join(",", sort @no_pubkey), "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print $newkeys_fh "# gitolite end\n";
|
print $newkeys_fh "# gitolite end\n";
|
||||||
|
|
Loading…
Add table
Reference in a new issue