summaryrefslogtreecommitdiffstats
path: root/contrib/commands/compile-1
blob: a5b535662da68fe2628fb5315ae7b6bb97be36c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/perl -s
use strict;
use warnings;

# DESCRIPTION:

#   This program is meant to re-compile the access rules (and 'config' or
#   'option' lines) of exactly ONE actual repo (i.e., not a repo group or a
#   repo pattern).

# MOTIVATION:

#   Fedora has a huge number of repos, as well as lot of churn in permissions.
#   The combination of having a large conf *and* frequent compiles were not
#   working out, hence this solution.  Not sure if any others have such a
#   situation, so it's a standalone program, separate from "core" gitolite,
#   shipped in "contrib" instead of "src".

# SETUP:

#   It expects to run as a gitolite sub-command, which means you will need to
#   copy it from contrib to src/commands, or the equivalent location inside
#   LOCAL_CODE; see non-core.html in the docs for details.

# INVOCATION:

#   It takes one argument: the name of a file that contains the new ruleset
#   you want to use.  (This cannot be STDIN or "-" or something).

#   example:
#
#       gitolite compile-1 <file-containing-rules-for-exactly-one-repo>

# WARNING:

#   If the main gitolite.conf changes significantly (specifically, if the
#   number of effective rules in it increase quite a bit), you may have to run
#   this command on ALL repos to update their individual gl-conf files.
#
#   (TBD: explain this in more concrete terms)

# ----------------------------------------------------------------------
# THERE IS NO ERROR CHECKING ON THE WARNING ABOVE, NOR ON THE ASSUMPTIONS AND
# REQUIREMENTS BELOW.  PLEASE USE CAREFULLY!
# ----------------------------------------------------------------------

# ASSUMPTIONS/REQUIREMENTS:

#   The file given must contain exactly one 'repo' line, with exactly one repo
#   name, followed by the rules, configs, and options for that repo in the
#   normal gitolite.conf syntax.

#   The file must not have any group definitions, though it may use group
#   definitions already setup in the main gitolite.conf file.

#   Rules for this repo need not be already defined in the main gitolite.conf.
#   If they are, they will cease to have any effect once you run this command
#   - only the rules you supply in the file passed to this command will apply,
#   and they will be considered to be placed at the end of gitolite.conf.

#   If the repo does not exist, it must be first created using:
#
#       GL_USER=admin gitolite create <reponame>
#
#   where <reponame> is the gitolite-style name (i.e., "foo", not "foo.git" or
#   "~/repositories/foo" or "~/repositories/foo.git")
#
#   This, of course, requires the main gitolite.conf to have the following
#   lines at the top:
#
#       repo [A-Za-z].*
#           C   =   admin

#   Any change to the main gitolite.conf is followed by a full 'gitolite
#   compile'; i.e., ~/.gitolite/conf/gitolite.conf-compiled.pm, the main
#   "compiled" conf file, is consistent with the latest gitolite.conf.

use 5.10.0;
use Data::Dumper;

use lib $ENV{GL_LIBDIR};
use Gitolite::Rc;
use Gitolite::Common;
use Gitolite::Conf;
use Gitolite::Conf::Store;
use Gitolite::Conf::Sugar;

my ($cf, $repo) = args();       # conffile from @ARGV, repo from first line of conffile
my $startseq = getseq();        # get the starting sequence number by looking in the (common) compiled conf file
parse_and_store($cf, $repo);    # parse the ruleset and write out just the gl-conf file
                                # (this is the only part that uses core gitolite functions)
update_seq($repo, $startseq);   # update gl-conf with adjusted sequence numbers

exit 0;

# ----------------------------------------------------------------------

sub args {
    my $cf = shift @ARGV or _die "need conffile";
    $cf = $ENV{PWD} . "/" . $cf unless $cf =~ m(^/);

    my $t = slurp($cf);
    _die "bad conf file" unless $t =~ /^\s*repo\s+(\S+)\s*$/m;
    my $repo = $1;

    return ($cf, $repo);
}

sub getseq {
    my @main_cc = slurp "$rc{GL_ADMIN_BASE}/conf/gitolite.conf-compiled.pm";
    my $max = 0;
    for (@main_cc) {
        $max = $1 if m/^ +(\d+),$/ and $max < $1;
    }

    return $max;
}

sub parse_and_store {
    my ($cf, $repo) = @_;

    parse(sugar($cf));
    _chdir( $rc{GL_REPO_BASE} );
    Gitolite::Conf::Store::store_1($repo);
}

sub update_seq {
    my ($repo, $startseq) = @_;

    _chdir("$rc{GL_REPO_BASE}/$repo.git");
    my $text = slurp("gl-conf");

    $startseq+=1000;
    # just for safety, in case someone adds a few rules to the main conf later, but neglects to update repo confs

    $text =~ s/^( +)(\d+),$/"$1" . ($2+$startseq) . ","/gme;

    _print("gl-conf", $text);
}