summaryrefslogtreecommitdiffstats
path: root/src/lib/Gitolite/Setup.pm
blob: 8ad5d3470a4de7b60c1b90bc1bcaea927fc829fd (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package Gitolite::Setup;

# implements 'gitolite setup'
# ----------------------------------------------------------------------

=for args
Usage:  gitolite setup [<option>]

Setup gitolite, compile conf, run the POST_COMPILE trigger (see rc file) and
propagate hooks.

    -a, --admin <name>          admin name
    -pk, --pubkey <file>        pubkey file name
    -ho, --hooks-only           skip other steps and just propagate hooks
    -m, --message               set setup commit message

First run: either the pubkey or the admin name is *required*, depending on
whether you're using ssh mode or http mode.

Subsequent runs:

  - Without options, 'gitolite setup' is a general "fix up everything" command
    (for example, if you brought in repos from outside, or someone messed
    around with the hooks, or you made an rc file change that affects access
    rules, etc.)

  - '-pk' can be used to replace the admin key; useful if you lost the admin's
    private key but do have shell access to the server.

  - '-ho' is mainly for scripting use.  Do not combine with other options.

  - '-a' is ignored

  - '-m' can be used to replace default commit message "gitolite setup $argv"
    with a custom message (e.g. "Setting up your repository mgmt").

=cut

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

@EXPORT = qw(
  setup
);

use Exporter 'import';

use Gitolite::Rc;
use Gitolite::Common;
use Gitolite::Conf::Store;

use strict;
use warnings;

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

sub setup {
    my ( $admin, $pubkey, $h_only, $message ) = args();

    unless ($h_only) {
        setup_glrc();
        setup_gladmin( $admin, $pubkey, $message );

        _system("gitolite compile");
        _system("gitolite trigger POST_COMPILE");
    }

    hook_repos();    # all of them, just to be sure
}

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

sub args {
    my $admin   = '';
    my $pubkey  = '';
    my $message = '';
    my $h_only  = 0;
    my $help    = 0;
    my $argv    = join( " ", @ARGV );

    require Getopt::Long;
    Getopt::Long::GetOptions(
        'admin|a=s'     => \$admin,
        'pubkey|pk=s'   => \$pubkey,
        'message|m=s'   => \$message,
        'hooks-only|ho' => \$h_only,
        'help|h'        => \$help,
    ) or usage();

    usage() if $help or ( $pubkey and $admin );
    usage() if $h_only and ( $admin or $pubkey );

    if ($pubkey) {
        $pubkey =~ /\.pub$/                 or _die "'$pubkey' name does not end in .pub";
        tsh_try("cat $pubkey")              or _die "'$pubkey' not a readable file";
        tsh_lines() == 1                    or _die "'$pubkey' must have exactly one line";
        tsh_try("ssh-keygen -l -f $pubkey") or _die "'$pubkey' does not seem to be a valid ssh pubkey file";

        $admin = $pubkey;
        # next 2 lines duplicated from args() in ssh-authkeys
        $admin =~ s(.*/)();                # foo/bar/baz.pub -> baz.pub
        $admin =~ s/(\@[^.]+)?\.pub$//;    # baz.pub, baz@home.pub -> baz
        $pubkey =~ /\@/ and print STDERR "NOTE: the admin username is '$admin'\n";

    }

    return ( $admin || '', $pubkey || '', $h_only || 0, $message || "gitolite setup $argv");
}

sub setup_glrc {
    _print( glrc('default-filename'), glrc('default-text') ) if not glrc('filename');
}

sub setup_gladmin {
    my ( $admin, $pubkey, $message ) = @_;
    _die "'-pk' or '-a' required; see 'gitolite setup -h' for more"
      if not $admin and not -f "$rc{GL_ADMIN_BASE}/conf/gitolite.conf";

    # reminder: 'admin files' are in ~/.gitolite, 'admin repo' is
    # $rc{GL_REPO_BASE}/gitolite-admin.git

    # grab the pubkey content before we chdir() away
    my $pubkey_content = '';
    $pubkey_content = slurp($pubkey) if $pubkey;

    # set up the admin files in admin-base

    _mkdir( $rc{GL_ADMIN_BASE} );
    _chdir( $rc{GL_ADMIN_BASE} );

    _mkdir("conf");
    _mkdir("logs");
    my $conf;
    {
        local $/ = undef;
        $conf = <DATA>;
    }
    $conf =~ s/%ADMIN/$admin/g;

    _print( "conf/gitolite.conf", $conf ) if not -f "conf/gitolite.conf";

    if ($pubkey) {
        _mkdir("keydir");
        _print( "keydir/$admin.pub", $pubkey_content );
    }

    # set up the admin repo in repo-base

    _chdir();
    _mkdir( $rc{GL_REPO_BASE} );
    _chdir( $rc{GL_REPO_BASE} );

    new_repo("gitolite-admin") if not -d "gitolite-admin.git";

    # commit the admin files to the admin repo

    $ENV{GIT_WORK_TREE} = $rc{GL_ADMIN_BASE};
    _chdir("$rc{GL_REPO_BASE}/gitolite-admin.git");
    _system("git add conf/gitolite.conf");
    _system("git add keydir") if $pubkey;
    tsh_try("git config --get user.email") or tsh_run( "git config user.email $ENV{USER}\@" . `hostname` );
    tsh_try("git config --get user.name")  or tsh_run( "git config user.name '$ENV{USER} on '" . `hostname` );
    tsh_try("git diff --cached --quiet")
      or tsh_try("git commit -am '$message'")
      or _die "setup failed to commit to the admin repo";
    delete $ENV{GIT_WORK_TREE};
}

1;

__DATA__
repo gitolite-admin
    RW+     =   %ADMIN

repo testing
    RW+     =   @all