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
|
#!/usr/bin/perl
# ----------------------------------------------------------------------
# gitolite command to allow repo "owners" to set "options" on repos
# This command can be run by a user to set "options" for any repo that she
# owns.
#
# However, gitolite does *not* have the concept of an incremental "compile",
# and options are only designed to be specified in the gitolite.conf file
# (which a user should not be able to even see!). Therefore, we allow one
# specific file (conf/options.conf) to be manipulated by a remote user in a
# *controlled* fashion, and this file is "include"d in the main gitolite.conf
# file.
# WARNINGS:
# 1. Runs "gitolite compile" at the end. On really huge systems (where the
# sum total of the conf files is in the order of tens of thousands of
# lines) this may take a second or two :)
# 2. Since "options.conf" is not part of the admin repo, you may need to
# back it up separately, just like you currently back up gl-creator and
# gl-perms files from individual repos.
# 3. "options.conf" is formatted very strictly because it's not meant to be
# human edited. If you edit it directly on the server, be careful.
# Relevant gitolite doc links:
# "wild" repos and "owners"
# http://gitolite.com/gitolite/wild.html
# http://gitolite.com/gitolite/wild.html#specifying-owners
# http://gitolite.com/gitolite/wild.html#appendix-1-owner-and-creator
# gitolite "options"
# http://gitolite.com/gitolite/options.html
# the "include" statement
# http://gitolite.com/gitolite/conf.html#include
# setup:
# 1. Enable the command by adding it to the ENABLE list in the rc file.
#
# 2. Make sure your gitolite.conf has this line at the end:
#
# include "options.conf"
#
# then add/commit/push.
#
# Do NOT add a file called "options.conf" to your gitolite-admin repo!
# This means every time you compile (push the admin repo) you will get a
# warning about the missing file.
#
# You can either "touch ~/.gitolite/conf/options.conf" on the server, or
# take *any* wild repo and add *any* option to create it.
#
# 3. Specify options allowed to be changed by the user. For example:
#
# repo foo/..*
# C = blah blah
# ...other rules...
# option user-options = hook\..* foo bar[0-9].*
#
# Users can then set any of these options, but no others.
# ----------------------------------------------------------------------
use strict;
use warnings;
use lib $ENV{GL_LIBDIR};
use Gitolite::Easy;
use Gitolite::Common;
# ----------------------------------------------------------------------
# usage and arg checks
=for usage
Usage: ssh git@host option <repo> add <key> <val>
ssh git@host option <repo> del <key>
ssh git@host option <repo> list
Add, delete, or list options for wild repos. Keys must match one of the
allowed patterns; your system administrator will tell you what they are.
Doesn't check things like adding a key that already exists (simply overwrites
without warning), deleting a key that doesn't, etc.
=cut
usage() if not @ARGV or $ARGV[0] eq '-h';
my $OPTIONS = "$ENV{HOME}/.gitolite/conf/options.conf";
my $repo = shift;
die "sorry, you are not authorised\n" unless owns($repo);
my $op = shift; usage() unless $op =~ /^(add|del|list)$/;
my $key = shift; usage() if not $key and $op ne 'list';
my $val = shift; usage() if not $val and $op eq 'add';
_print( $OPTIONS, "" ) unless -f $OPTIONS; # avoid error on first run
my $options = slurp($OPTIONS);
# ----------------------------------------------------------------------
# get 'list' out of the way first
if ( $op eq 'list' ) {
print "$1\t$2\n" while $options =~ /^repo $repo\n option (\S+) = (.*)/mg;
exit 0;
}
# ----------------------------------------------------------------------
# that leaves 'add' or 'del'
# NOTE: sanity check on characters in key and val not needed;
# REMOTE_COMMAND_PATT is more restrictive than UNSAFE_PATT anyway!
# check if the key is allowed
my $user_options = option( $repo, 'user-options' );
# this is a space separated list of allowed option keys
my @validkeys = split( ' ', ( $user_options || '' ) );
my @matched = grep { $key =~ /^$_$/i } @validkeys;
_die "option '$key' not allowed\n" if ( @matched < 1 );
# delete anyway
$options =~ s/^repo $repo\n option $key = .*\n//m;
# then re-add if needed
$options .= "repo $repo\n option $key = $val\n" if $op eq 'add';
# ----------------------------------------------------------------------
# save and compile
_print( $OPTIONS, $options );
system("gitolite compile");
|