-
Notifications
You must be signed in to change notification settings - Fork 0
/
mkconfrepo
executable file
·280 lines (249 loc) · 8.96 KB
/
mkconfrepo
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#! /usr/bin/env python
import sys, os, re
conffiles = {}
conffiles["keys/README"] = """This is the keys directory.
For each user, place a subdirectory here, which is named like the user.
All files in this subdirectory are treated as if they contain ssh keys.
Normal files and subdirectories not named like users are ignored.
You may remove this README-file (if you have a user named README ;) )
"""
conffiles["access"] = """# Access configuration file.
# This file also has ini file syntax.
#
# The section names are names of repositories, or patterns matching
# multiple repositories. Each section name must start with a "/".
# Names of repositories are interpreted relative to the directory
# where all managed repositories are placed. A pattern ends with
# exactly one or two '*' characters. If ending with only one '*', it
# will match all repositories located exactly in the directory pointed
# to by the rest of the pattern, without descending into
# subdirectories. If ending with two '*', it will match all
# repositories located in the directory or in any of its
# subdirectories.
#
# Directories or patterns names may not contain a ']' character. They
# may also not refer to hidden directories, files or repositories
# (whose name starts with a dot ('.')).
#
# It is also not possible to use a '*' character anywhere in a
# repository name. A pattern may only contain exactly one or two '*'
# characters, which must be the last characters of the pattern.
#
#
#
# The options in a section are interpreted as group names if they
# start with an '@' character (i.e. "@group1" refers to the group
# named "group1"), else as user names. The option values may contain
# the characters "r", "w" and "C". "r" denotes that the user has read
# access, "w" denotes that the user has read access and write access
# and "C" denotes that the user has read and write access and may
# create new repositories.
#
# Examples:
# [/**]
# user1 = r
# user2 = r w
# user3 = rwC
# @group1 = r
#
# "/**" matches every repository. user1, user2, user3 and every user
# in group1 therefore are allowed to read every
# repository. Additionally, user2 may write to every repository and
# user3 may write to every repository and create new repositories
# everywhere.
#
# [/**]
# user1 = rw
# user2 = rw
# [/sandbox/*]
# user1 = rw
# user3 = rw
# [/sandbox/foo]
# user1 = rw
# user4 = rw
#
# user1 may write everywhere. user2 may write everywhere except
# immediately below the "sandbox" - directory. user2 may however write
# to sandbox/dings/bums, if that repository exists. user3 may write
# to every repository immediately below sandbox (p.ex. "sandbox/bar"
# or "sandbox/test", but neither to "sandbox" itself nor to
# "sandbox/foo". user4 may only write to "sandbox/foo".
#
# The following section names are illegal:
# [invalid1] # does not start with '/'
# [/invalid2/*/reallyinvalid/**] # contains a non-trailing '*'
# [/foo_$$]}&??/*] # contains a ']'
#
"""
conffiles["config"] = """# Example configuration file. This file has
# ini file syntax (as understood by pythons ConfigFileParser
#
# There are three sections; [paths], [groups] and [users]
[paths]
# Here, you can configure paths referring to important files and
# directories. The configurable paths and their default values are
# listed below.
#
# repopath = ~/repos
# This path refers to the directory where the repositories to manage
# are located.
#
# htpasswdpath = ~/repos/htpasswd
# This path refers to the htpasswd file. If this repository contains a
# file named "htpasswd", hgadmin will overwrite the file pointed to by
# "htpasswdpath" with the contents of the file in this repository
# named "htpasswd".
#
# hg-ssh = ~/hgadmin/hg-ssh
# This path points to the hg-ssh script.
#
# sshauthkeyspath = ~/.ssh/authorized_keys
# This path refers to the authorized_keys file used by ssh to
# determine access authorization. This file will be replaced by an
# autogenerated list of allowed keys, restricted to only executing the
# "hg-ssh" command, as listed above.
#
[groups]
# This section contains group definitions.
# Example definitions are listed below.
#
# group1 = user1, user2
# group2 = user3, user5, user6
# group3 =
# user1, # comment
# # another comment
# user2, user3, user4
[users]
# This section contains exactly one option, named "users".
# Its value is a list of the users.
#
# users = user1, user2,
# # strange user with own description:
# user3,
# # another user description
# another_user,
# # and another user description
# user4
#
"""
conffiles["hook-examples"] = """# example hook configurations
#
# This file contains some examples for how to add hooks to the
# configuration repository. Please add a path to the hgadmin script if
# necessary.
#
# If this repository is a clone of the real configuration repository, consider
# adding this hook:
#
# [hooks]
# precommit.hgadmin = hgadmin verify
#
# It will check your configuration for obvious errors and abort the
# commit if some are found
#
#
# If this repository is the real repository, consider adding these hooks:
#
# [hooks]
# changegroup.hgadmin = hg up
# update.hgadmin = hgadmin updateauth
# commit.hgadmin = hgadmin updateauth
#
# They will attempt to recreate the authentication information every
# time you commit locally or something gets pushed into the repository.
"""
conffiles["hgrc"] = """# sample hgrc to be included in every managed repo
"""
conffiles["README"] = """This is a hg repository containing configuration information for hgadmin.
hgadmin expects a number of special files in this configuration directory.
"config" -- contains general configuration for hgadmin
"access" -- contains access configuraiton for hgadmin
"hgrc" -- a sample hgrc inserted into every managed repository
"keys/$USER/keyfile" -- keyfiles containing ssh keys. Refer to keys/README
"htpasswd" -- file containing password hashes for users (for use with httpd - authentication)
You may want to add hooks to .hg/hgrc; please refer to "hook-examples"
for examples and help.
If you want to know more, read the contents of the other files in this
repo, or learn python and read the hgadmin and hg-ssh scripts ;)
"""
def fail(msg):
print(msg)
sys.exit(1)
def createconfrepo(path):
r = os.system("hg init " + path)
if r!= 0:
fail("unable to create config repository")
oldcwd = os.getcwd()
try:
os.chdir(path)
except OSError as e:
fail("unable to enter newly created config repository??!?")
try:
os.mkdir("keys")
for k in conffiles:
conffd = open(k, "w")
conffd.write(conffiles[k])
conffd.close()
r = os.system("hg add " + k)
if r != 0:
fail("unable to add file %s in config repository to hg" % k)
except OSError as e:
fail("unable to create config repository default files??")
r = os.system("hg commit -m 'automatically generated hgadmin configuration repository'")
if r != 0:
fail("unable to commit config repository")
try:
os.chdir(oldcwd)
except OSError as e:
fail("unable to get back to previous directory??")
def checkforhooksection(path):
x = re.compile(r"^\s*\[\s*hooks\s*\]", re.MULTILINE)
fn = path+"/.hg/hgrc"
if os.access(fn, os.R_OK):
confstring = open(fn, "r").read()
if x.search(confstring):
fail("configuration part contains [hooks]-section, aborting")
owndir = os.path.abspath(os.path.dirname(__file__))
hgadmin_path = owndir + "/hgadmin"
def addclienthooks(path):
checkforhooksection(path)
apath = os.path.abspath(path)
fd = open(path+"/.hg/hgrc", "a")
fd.write("\n[hooks]\n")
fd.write("precommit.hgadmin = %s --confdir %s verify\n" % (hgadmin_path, path))
fd.close()
def addserverhooks(path):
checkforhooksection(path)
apath = os.path.abspath(path)
fd = open(path+"/.hg/hgrc", "a")
fd.write("\n[hooks]\n")
fd.write("changegroup.hgadmin = hg up\n")
fd.write("update.hgadmin = %s --confdir %s updateauth\n" % (hgadmin_path, apath))
fd.write("commit.hgadmin = %s --confdir %s updateauth\n" % (hgadmin_path, apath))
fd.close()
def usage():
x = """usage:
{name} REPO -- creates REPO
{name} --addclienthooks REPO -- creates repo if it doesn't exist, then adds client hooks
{name} --addserverhooks REPO -- creates repo if it doesn't exist, then adds server hooks
"""
print(x.format(name=sys.argv[0]))
sys.exit(1)
def main():
if len(sys.argv) == 3:
if sys.argv[1] == '--addclienthooks':
if not os.access(sys.argv[2], os.F_OK):
createconfrepo(sys.argv[2])
addclienthooks(sys.argv[2])
elif sys.argv[1] == '--addserverhooks':
if not os.access(sys.argv[2], os.F_OK):
createconfrepo(sys.argv[2])
addserverhooks(sys.argv[2])
else:
usage()
elif len(sys.argv) == 2:
createconfrepo(sys.argv[1])
else:
usage()
if __name__ == "__main__":
main()