4b1cc44
#!/usr/bin/perl -s
4b1cc44
use strict;
4b1cc44
use warnings;
4b1cc44
4b1cc44
# DESCRIPTION:
4b1cc44
4b1cc44
#   This program is meant to re-compile the access rules (and 'config' or
4b1cc44
#   'option' lines) of exactly ONE actual repo (i.e., not a repo group or a
4b1cc44
#   repo pattern).
4b1cc44
4b1cc44
# MOTIVATION:
4b1cc44
4b1cc44
#   Fedora has a huge number of repos, as well as lot of churn in permissions.
4b1cc44
#   The combination of having a large conf *and* frequent compiles were not
4b1cc44
#   working out, hence this solution.  Not sure if any others have such a
4b1cc44
#   situation, so it's a standalone program, separate from "core" gitolite,
4b1cc44
#   shipped in "contrib" instead of "src".
4b1cc44
4b1cc44
# SETUP:
4b1cc44
4b1cc44
#   It expects to run as a gitolite sub-command, which means you will need to
4b1cc44
#   copy it from contrib to src/commands, or the equivalent location inside
4b1cc44
#   LOCAL_CODE; see non-core.html in the docs for details.
4b1cc44
4b1cc44
# INVOCATION:
4b1cc44
4b1cc44
#   It takes one argument: the name of a file that contains the new ruleset
4b1cc44
#   you want to use.  (This cannot be STDIN or "-" or something).
4b1cc44
4b1cc44
#   example:
4b1cc44
#
4b1cc44
#       gitolite compile-1 <file-containing-rules-for-exactly-one-repo>
4b1cc44
4b1cc44
# WARNING:
4b1cc44
4b1cc44
#   If the main gitolite.conf changes significantly (specifically, if the
4b1cc44
#   number of effective rules in it increase quite a bit), you may have to run
4b1cc44
#   this command on ALL repos to update their individual gl-conf files.
4b1cc44
#
4b1cc44
#   (TBD: explain this in more concrete terms)
4b1cc44
4b1cc44
# ----------------------------------------------------------------------
4b1cc44
# THERE IS NO ERROR CHECKING ON THE WARNING ABOVE, NOR ON THE ASSUMPTIONS AND
4b1cc44
# REQUIREMENTS BELOW.  PLEASE USE CAREFULLY!
4b1cc44
# ----------------------------------------------------------------------
4b1cc44
4b1cc44
# ASSUMPTIONS/REQUIREMENTS:
4b1cc44
4b1cc44
#   The file given must contain exactly one 'repo' line, with exactly one repo
4b1cc44
#   name, followed by the rules, configs, and options for that repo in the
4b1cc44
#   normal gitolite.conf syntax.
4b1cc44
4b1cc44
#   The file must not have any group definitions, though it may use group
4b1cc44
#   definitions already setup in the main gitolite.conf file.
4b1cc44
4b1cc44
#   Rules for this repo need not be already defined in the main gitolite.conf.
4b1cc44
#   If they are, they will cease to have any effect once you run this command
4b1cc44
#   - only the rules you supply in the file passed to this command will apply,
4b1cc44
#   and they will be considered to be placed at the end of gitolite.conf.
4b1cc44
4b1cc44
#   If the repo does not exist, it must be first created using:
4b1cc44
#
4b1cc44
#       GL_USER=admin gitolite create <reponame>
4b1cc44
#
4b1cc44
#   where <reponame> is the gitolite-style name (i.e., "foo", not "foo.git" or
4b1cc44
#   "~/repositories/foo" or "~/repositories/foo.git")
4b1cc44
#
4b1cc44
#   This, of course, requires the main gitolite.conf to have the following
4b1cc44
#   lines at the top:
4b1cc44
#
4b1cc44
#       repo [A-Za-z].*
4b1cc44
#           C   =   admin
4b1cc44
4b1cc44
#   Any change to the main gitolite.conf is followed by a full 'gitolite
4b1cc44
#   compile'; i.e., ~/.gitolite/conf/gitolite.conf-compiled.pm, the main
4b1cc44
#   "compiled" conf file, is consistent with the latest gitolite.conf.
4b1cc44
4b1cc44
use 5.10.0;
4b1cc44
use Data::Dumper;
4b1cc44
4b1cc44
use lib $ENV{GL_LIBDIR};
4b1cc44
use Gitolite::Rc;
4b1cc44
use Gitolite::Common;
4b1cc44
use Gitolite::Conf;
4b1cc44
use Gitolite::Conf::Store;
4b1cc44
use Gitolite::Conf::Sugar;
4b1cc44
4b1cc44
my ($cf, $repo) = args();       # conffile from @ARGV, repo from first line of conffile
4b1cc44
my $startseq = getseq();        # get the starting sequence number by looking in the (common) compiled conf file
4b1cc44
parse_and_store($cf, $repo);    # parse the ruleset and write out just the gl-conf file
4b1cc44
                                # (this is the only part that uses core gitolite functions)
4b1cc44
update_seq($repo, $startseq);   # update gl-conf with adjusted sequence numbers
4b1cc44
4b1cc44
exit 0;
4b1cc44
4b1cc44
# ----------------------------------------------------------------------
4b1cc44
4b1cc44
sub args {
4b1cc44
    my $cf = shift @ARGV or _die "need conffile";
4b1cc44
    $cf = $ENV{PWD} . "/" . $cf unless $cf =~ m(^/);
4b1cc44
4b1cc44
    my $t = slurp($cf);
4b1cc44
    _die "bad conf file" unless $t =~ /^\s*repo\s+(\S+)\s*$/m;
4b1cc44
    my $repo = $1;
4b1cc44
4b1cc44
    return ($cf, $repo);
4b1cc44
}
4b1cc44
4b1cc44
sub getseq {
4b1cc44
    my @main_cc = slurp "$rc{GL_ADMIN_BASE}/conf/gitolite.conf-compiled.pm";
4b1cc44
    my $max = 0;
4b1cc44
    for (@main_cc) {
4b1cc44
        $max = $1 if m/^ +(\d+),$/ and $max < $1;
4b1cc44
    }
4b1cc44
4b1cc44
    return $max;
4b1cc44
}
4b1cc44
4b1cc44
sub parse_and_store {
4b1cc44
    my ($cf, $repo) = @_;
4b1cc44
4b1cc44
    parse(sugar($cf));
4b1cc44
    _chdir( $rc{GL_REPO_BASE} );
4b1cc44
    Gitolite::Conf::Store::store_1($repo);
4b1cc44
}
4b1cc44
4b1cc44
sub update_seq {
4b1cc44
    my ($repo, $startseq) = @_;
4b1cc44
4b1cc44
    _chdir("$rc{GL_REPO_BASE}/$repo.git");
4b1cc44
    my $text = slurp("gl-conf");
4b1cc44
4b1cc44
    $startseq+=1000;
4b1cc44
    # just for safety, in case someone adds a few rules to the main conf later, but neglects to update repo confs
4b1cc44
4b1cc44
    $text =~ s/^( +)(\d+),$/"$1" . ($2+$startseq) . ","/gme;
4b1cc44
4b1cc44
    _print("gl-conf", $text);
4b1cc44
}