##// END OF EJS Templates
ui: make readsections() abort when configuration cannot be read.
Patrick Mezard -
r4517:5371a213 default
parent child Browse files
Show More
@@ -1,450 +1,458
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from i18n import _
9 9 import errno, getpass, os, re, socket, sys, tempfile
10 10 import ConfigParser, traceback, util
11 11
12 12 def dupconfig(orig):
13 13 new = util.configparser(orig.defaults())
14 14 updateconfig(orig, new)
15 15 return new
16 16
17 17 def updateconfig(source, dest, sections=None):
18 18 if not sections:
19 19 sections = source.sections()
20 20 for section in sections:
21 21 if not dest.has_section(section):
22 22 dest.add_section(section)
23 23 for name, value in source.items(section, raw=True):
24 24 dest.set(section, name, value)
25 25
26 26 class ui(object):
27 27 def __init__(self, verbose=False, debug=False, quiet=False,
28 28 interactive=True, traceback=False, report_untrusted=True,
29 29 parentui=None):
30 30 self.overlay = None
31 31 self.buffers = []
32 32 if parentui is None:
33 33 # this is the parent of all ui children
34 34 self.parentui = None
35 35 self.readhooks = []
36 36 self.quiet = quiet
37 37 self.verbose = verbose
38 38 self.debugflag = debug
39 39 self.interactive = interactive
40 40 self.traceback = traceback
41 41 self.report_untrusted = report_untrusted
42 42 self.trusted_users = {}
43 43 self.trusted_groups = {}
44 44 # if ucdata is not None, its keys must be a superset of cdata's
45 45 self.cdata = util.configparser()
46 46 self.ucdata = None
47 47 # we always trust global config files
48 48 self.check_trusted = False
49 49 self.readconfig(util.rcpath())
50 50 self.check_trusted = True
51 51 self.updateopts(verbose, debug, quiet, interactive)
52 52 else:
53 53 # parentui may point to an ui object which is already a child
54 54 self.parentui = parentui.parentui or parentui
55 55 self.readhooks = self.parentui.readhooks[:]
56 56 self.trusted_users = parentui.trusted_users.copy()
57 57 self.trusted_groups = parentui.trusted_groups.copy()
58 58 self.cdata = dupconfig(self.parentui.cdata)
59 59 if self.parentui.ucdata:
60 60 self.ucdata = dupconfig(self.parentui.ucdata)
61 61 if self.parentui.overlay:
62 62 self.overlay = dupconfig(self.parentui.overlay)
63 63
64 64 def __getattr__(self, key):
65 65 return getattr(self.parentui, key)
66 66
67 67 def updateopts(self, verbose=False, debug=False, quiet=False,
68 68 interactive=True, traceback=False, config=[]):
69 69 for section, name, value in config:
70 70 self.setconfig(section, name, value)
71 71
72 72 if quiet or verbose or debug:
73 73 self.setconfig('ui', 'quiet', str(bool(quiet)))
74 74 self.setconfig('ui', 'verbose', str(bool(verbose)))
75 75 self.setconfig('ui', 'debug', str(bool(debug)))
76 76
77 77 self.verbosity_constraints()
78 78
79 79 if not interactive:
80 80 self.setconfig('ui', 'interactive', 'False')
81 81 self.interactive = False
82 82
83 83 self.traceback = self.traceback or traceback
84 84
85 85 def verbosity_constraints(self):
86 86 self.quiet = self.configbool('ui', 'quiet')
87 87 self.verbose = self.configbool('ui', 'verbose')
88 88 self.debugflag = self.configbool('ui', 'debug')
89 89
90 90 if self.debugflag:
91 91 self.verbose = True
92 92 self.quiet = False
93 93 elif self.verbose and self.quiet:
94 94 self.quiet = self.verbose = False
95 95
96 96 def _is_trusted(self, fp, f, warn=True):
97 97 if not self.check_trusted:
98 98 return True
99 99 st = util.fstat(fp)
100 100 if util.isowner(fp, st):
101 101 return True
102 102 tusers = self.trusted_users
103 103 tgroups = self.trusted_groups
104 104 if not tusers:
105 105 user = util.username()
106 106 if user is not None:
107 107 self.trusted_users[user] = 1
108 108 self.fixconfig(section='trusted')
109 109 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
110 110 user = util.username(st.st_uid)
111 111 group = util.groupname(st.st_gid)
112 112 if user not in tusers and group not in tgroups:
113 113 if warn and self.report_untrusted:
114 114 self.warn(_('Not trusting file %s from untrusted '
115 115 'user %s, group %s\n') % (f, user, group))
116 116 return False
117 117 return True
118 118
119 119 def readconfig(self, fn, root=None):
120 120 if isinstance(fn, basestring):
121 121 fn = [fn]
122 122 for f in fn:
123 123 try:
124 124 fp = open(f)
125 125 except IOError:
126 126 continue
127 127 cdata = self.cdata
128 128 trusted = self._is_trusted(fp, f)
129 129 if not trusted:
130 130 if self.ucdata is None:
131 131 self.ucdata = dupconfig(self.cdata)
132 132 cdata = self.ucdata
133 133 elif self.ucdata is not None:
134 134 # use a separate configparser, so that we don't accidentally
135 135 # override ucdata settings later on.
136 136 cdata = util.configparser()
137 137
138 138 try:
139 139 cdata.readfp(fp, f)
140 140 except ConfigParser.ParsingError, inst:
141 141 msg = _("Failed to parse %s\n%s") % (f, inst)
142 142 if trusted:
143 143 raise util.Abort(msg)
144 144 self.warn(_("Ignored: %s\n") % msg)
145 145
146 146 if trusted:
147 147 if cdata != self.cdata:
148 148 updateconfig(cdata, self.cdata)
149 149 if self.ucdata is not None:
150 150 updateconfig(cdata, self.ucdata)
151 151 # override data from config files with data set with ui.setconfig
152 152 if self.overlay:
153 153 updateconfig(self.overlay, self.cdata)
154 154 if root is None:
155 155 root = os.path.expanduser('~')
156 156 self.fixconfig(root=root)
157 157 for hook in self.readhooks:
158 158 hook(self)
159 159
160 160 def addreadhook(self, hook):
161 161 self.readhooks.append(hook)
162 162
163 163 def readsections(self, filename, *sections):
164 164 """Read filename and add only the specified sections to the config data
165 165
166 166 The settings are added to the trusted config data.
167 167 """
168 168 if not sections:
169 169 return
170 170
171 171 cdata = util.configparser()
172 172 try:
173 cdata.read(filename)
173 try:
174 fp = open(filename)
175 except IOError, inst:
176 raise util.Abort(_("unable to open %s: %s") % (filename,
177 getattr(inst, "strerror", inst)))
178 try:
179 cdata.readfp(fp, filename)
180 finally:
181 fp.close()
174 182 except ConfigParser.ParsingError, inst:
175 183 raise util.Abort(_("failed to parse %s\n%s") % (filename,
176 184 inst))
177 185
178 186 for section in sections:
179 187 if not cdata.has_section(section):
180 188 cdata.add_section(section)
181 189
182 190 updateconfig(cdata, self.cdata, sections)
183 191 if self.ucdata:
184 192 updateconfig(cdata, self.ucdata, sections)
185 193
186 194 def fixconfig(self, section=None, name=None, value=None, root=None):
187 195 # translate paths relative to root (or home) into absolute paths
188 196 if section is None or section == 'paths':
189 197 if root is None:
190 198 root = os.getcwd()
191 199 items = section and [(name, value)] or []
192 200 for cdata in self.cdata, self.ucdata, self.overlay:
193 201 if not cdata: continue
194 202 if not items and cdata.has_section('paths'):
195 203 pathsitems = cdata.items('paths')
196 204 else:
197 205 pathsitems = items
198 206 for n, path in pathsitems:
199 207 if path and "://" not in path and not os.path.isabs(path):
200 208 cdata.set("paths", n, os.path.join(root, path))
201 209
202 210 # update quiet/verbose/debug and interactive status
203 211 if section is None or section == 'ui':
204 212 if name is None or name in ('quiet', 'verbose', 'debug'):
205 213 self.verbosity_constraints()
206 214
207 215 if name is None or name == 'interactive':
208 216 self.interactive = self.configbool("ui", "interactive", True)
209 217
210 218 # update trust information
211 219 if (section is None or section == 'trusted') and self.trusted_users:
212 220 for user in self.configlist('trusted', 'users'):
213 221 self.trusted_users[user] = 1
214 222 for group in self.configlist('trusted', 'groups'):
215 223 self.trusted_groups[group] = 1
216 224
217 225 def setconfig(self, section, name, value):
218 226 if not self.overlay:
219 227 self.overlay = util.configparser()
220 228 for cdata in (self.overlay, self.cdata, self.ucdata):
221 229 if not cdata: continue
222 230 if not cdata.has_section(section):
223 231 cdata.add_section(section)
224 232 cdata.set(section, name, value)
225 233 self.fixconfig(section, name, value)
226 234
227 235 def _get_cdata(self, untrusted):
228 236 if untrusted and self.ucdata:
229 237 return self.ucdata
230 238 return self.cdata
231 239
232 240 def _config(self, section, name, default, funcname, untrusted, abort):
233 241 cdata = self._get_cdata(untrusted)
234 242 if cdata.has_option(section, name):
235 243 try:
236 244 func = getattr(cdata, funcname)
237 245 return func(section, name)
238 246 except ConfigParser.InterpolationError, inst:
239 247 msg = _("Error in configuration section [%s] "
240 248 "parameter '%s':\n%s") % (section, name, inst)
241 249 if abort:
242 250 raise util.Abort(msg)
243 251 self.warn(_("Ignored: %s\n") % msg)
244 252 return default
245 253
246 254 def _configcommon(self, section, name, default, funcname, untrusted):
247 255 value = self._config(section, name, default, funcname,
248 256 untrusted, abort=True)
249 257 if self.debugflag and not untrusted and self.ucdata:
250 258 uvalue = self._config(section, name, None, funcname,
251 259 untrusted=True, abort=False)
252 260 if uvalue is not None and uvalue != value:
253 261 self.warn(_("Ignoring untrusted configuration option "
254 262 "%s.%s = %s\n") % (section, name, uvalue))
255 263 return value
256 264
257 265 def config(self, section, name, default=None, untrusted=False):
258 266 return self._configcommon(section, name, default, 'get', untrusted)
259 267
260 268 def configbool(self, section, name, default=False, untrusted=False):
261 269 return self._configcommon(section, name, default, 'getboolean',
262 270 untrusted)
263 271
264 272 def configlist(self, section, name, default=None, untrusted=False):
265 273 """Return a list of comma/space separated strings"""
266 274 result = self.config(section, name, untrusted=untrusted)
267 275 if result is None:
268 276 result = default or []
269 277 if isinstance(result, basestring):
270 278 result = result.replace(",", " ").split()
271 279 return result
272 280
273 281 def has_section(self, section, untrusted=False):
274 282 '''tell whether section exists in config.'''
275 283 cdata = self._get_cdata(untrusted)
276 284 return cdata.has_section(section)
277 285
278 286 def _configitems(self, section, untrusted, abort):
279 287 items = {}
280 288 cdata = self._get_cdata(untrusted)
281 289 if cdata.has_section(section):
282 290 try:
283 291 items.update(dict(cdata.items(section)))
284 292 except ConfigParser.InterpolationError, inst:
285 293 msg = _("Error in configuration section [%s]:\n"
286 294 "%s") % (section, inst)
287 295 if abort:
288 296 raise util.Abort(msg)
289 297 self.warn(_("Ignored: %s\n") % msg)
290 298 return items
291 299
292 300 def configitems(self, section, untrusted=False):
293 301 items = self._configitems(section, untrusted=untrusted, abort=True)
294 302 if self.debugflag and not untrusted and self.ucdata:
295 303 uitems = self._configitems(section, untrusted=True, abort=False)
296 304 keys = uitems.keys()
297 305 keys.sort()
298 306 for k in keys:
299 307 if uitems[k] != items.get(k):
300 308 self.warn(_("Ignoring untrusted configuration option "
301 309 "%s.%s = %s\n") % (section, k, uitems[k]))
302 310 x = items.items()
303 311 x.sort()
304 312 return x
305 313
306 314 def walkconfig(self, untrusted=False):
307 315 cdata = self._get_cdata(untrusted)
308 316 sections = cdata.sections()
309 317 sections.sort()
310 318 for section in sections:
311 319 for name, value in self.configitems(section, untrusted):
312 320 yield section, name, str(value).replace('\n', '\\n')
313 321
314 322 def extensions(self):
315 323 result = self.configitems("extensions")
316 324 for i, (key, value) in enumerate(result):
317 325 if value:
318 326 result[i] = (key, os.path.expanduser(value))
319 327 return result
320 328
321 329 def hgignorefiles(self):
322 330 result = []
323 331 for key, value in self.configitems("ui"):
324 332 if key == 'ignore' or key.startswith('ignore.'):
325 333 result.append(os.path.expanduser(value))
326 334 return result
327 335
328 336 def username(self):
329 337 """Return default username to be used in commits.
330 338
331 339 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
332 340 and stop searching if one of these is set.
333 341 If not found, use ($LOGNAME or $USER or $LNAME or
334 342 $USERNAME) +"@full.hostname".
335 343 """
336 344 user = os.environ.get("HGUSER")
337 345 if user is None:
338 346 user = self.config("ui", "username")
339 347 if user is None:
340 348 user = os.environ.get("EMAIL")
341 349 if user is None:
342 350 try:
343 351 user = '%s@%s' % (util.getuser(), socket.getfqdn())
344 352 self.warn(_("No username found, using '%s' instead\n") % user)
345 353 except KeyError:
346 354 pass
347 355 if not user:
348 356 raise util.Abort(_("Please specify a username."))
349 357 return user
350 358
351 359 def shortuser(self, user):
352 360 """Return a short representation of a user name or email address."""
353 361 if not self.verbose: user = util.shortuser(user)
354 362 return user
355 363
356 364 def expandpath(self, loc, default=None):
357 365 """Return repository location relative to cwd or from [paths]"""
358 366 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
359 367 return loc
360 368
361 369 path = self.config("paths", loc)
362 370 if not path and default is not None:
363 371 path = self.config("paths", default)
364 372 return path or loc
365 373
366 374 def pushbuffer(self):
367 375 self.buffers.append([])
368 376
369 377 def popbuffer(self):
370 378 return "".join(self.buffers.pop())
371 379
372 380 def write(self, *args):
373 381 if self.buffers:
374 382 self.buffers[-1].extend([str(a) for a in args])
375 383 else:
376 384 for a in args:
377 385 sys.stdout.write(str(a))
378 386
379 387 def write_err(self, *args):
380 388 try:
381 389 if not sys.stdout.closed: sys.stdout.flush()
382 390 for a in args:
383 391 sys.stderr.write(str(a))
384 392 # stderr may be buffered under win32 when redirected to files,
385 393 # including stdout.
386 394 if not sys.stderr.closed: sys.stderr.flush()
387 395 except IOError, inst:
388 396 if inst.errno != errno.EPIPE:
389 397 raise
390 398
391 399 def flush(self):
392 400 try: sys.stdout.flush()
393 401 except: pass
394 402 try: sys.stderr.flush()
395 403 except: pass
396 404
397 405 def readline(self):
398 406 return sys.stdin.readline()[:-1]
399 407 def prompt(self, msg, pat=None, default="y"):
400 408 if not self.interactive: return default
401 409 while 1:
402 410 self.write(msg, " ")
403 411 r = self.readline()
404 412 if not pat or re.match(pat, r):
405 413 return r
406 414 else:
407 415 self.write(_("unrecognized response\n"))
408 416 def getpass(self, prompt=None, default=None):
409 417 if not self.interactive: return default
410 418 return getpass.getpass(prompt or _('password: '))
411 419 def status(self, *msg):
412 420 if not self.quiet: self.write(*msg)
413 421 def warn(self, *msg):
414 422 self.write_err(*msg)
415 423 def note(self, *msg):
416 424 if self.verbose: self.write(*msg)
417 425 def debug(self, *msg):
418 426 if self.debugflag: self.write(*msg)
419 427 def edit(self, text, user):
420 428 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
421 429 text=True)
422 430 try:
423 431 f = os.fdopen(fd, "w")
424 432 f.write(text)
425 433 f.close()
426 434
427 435 editor = (os.environ.get("HGEDITOR") or
428 436 self.config("ui", "editor") or
429 437 os.environ.get("EDITOR", "vi"))
430 438
431 439 util.system("%s \"%s\"" % (editor, name),
432 440 environ={'HGUSER': user},
433 441 onerr=util.Abort, errprefix=_("edit failed"))
434 442
435 443 f = open(name)
436 444 t = f.read()
437 445 f.close()
438 446 t = re.sub("(?m)^HG:.*\n", "", t)
439 447 finally:
440 448 os.unlink(name)
441 449
442 450 return t
443 451
444 452 def print_exc(self):
445 453 '''print exception traceback if traceback printing enabled.
446 454 only to call in exception handler. returns true if traceback
447 455 printed.'''
448 456 if self.traceback:
449 457 traceback.print_exc()
450 458 return self.traceback
@@ -1,584 +1,583
1 1 3:911600dab2ae
2 2 requesting all changes
3 3 adding changesets
4 4 adding manifests
5 5 adding file changes
6 6 added 1 changesets with 3 changes to 3 files
7 7 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
8 8
9 9 Extension disabled for lack of a hook
10 10 Pushing as user fred
11 11 hgrc = """
12 12 """
13 13 pushing to ../b
14 14 searching for changes
15 15 common changesets up to 6675d58eff77
16 16 3 changesets found
17 17 List of changesets:
18 18 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
19 19 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
20 20 911600dab2ae7a9baff75958b84fe606851ce955
21 21 adding changesets
22 22 add changeset ef1ea85a6374
23 23 add changeset f9cafe1212c8
24 24 add changeset 911600dab2ae
25 25 adding manifests
26 26 adding file changes
27 27 adding foo/Bar/file.txt revisions
28 28 adding foo/file.txt revisions
29 29 adding quux/file.py revisions
30 30 added 3 changesets with 3 changes to 3 files
31 31 rolling back last transaction
32 32 0:6675d58eff77
33 33
34 34 Extension disabled for lack of acl.sources
35 35 Pushing as user fred
36 36 hgrc = """
37 37 [hooks]
38 38 pretxnchangegroup.acl = python:hgext.acl.hook
39 39 """
40 40 pushing to ../b
41 41 searching for changes
42 42 common changesets up to 6675d58eff77
43 43 3 changesets found
44 44 List of changesets:
45 45 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
46 46 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
47 47 911600dab2ae7a9baff75958b84fe606851ce955
48 48 adding changesets
49 49 add changeset ef1ea85a6374
50 50 add changeset f9cafe1212c8
51 51 add changeset 911600dab2ae
52 52 adding manifests
53 53 adding file changes
54 54 adding foo/Bar/file.txt revisions
55 55 adding foo/file.txt revisions
56 56 adding quux/file.py revisions
57 57 added 3 changesets with 3 changes to 3 files
58 58 calling hook pretxnchangegroup.acl: hgext.acl.hook
59 59 acl: acl.allow not enabled
60 60 acl: acl.deny not enabled
61 61 acl: changes have source "push" - skipping
62 62 rolling back last transaction
63 63 0:6675d58eff77
64 64
65 65 No [acl.allow]/[acl.deny]
66 66 Pushing as user fred
67 67 hgrc = """
68 68 [hooks]
69 69 pretxnchangegroup.acl = python:hgext.acl.hook
70 70 [acl]
71 71 sources = push
72 72 """
73 73 pushing to ../b
74 74 searching for changes
75 75 common changesets up to 6675d58eff77
76 76 3 changesets found
77 77 List of changesets:
78 78 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
79 79 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
80 80 911600dab2ae7a9baff75958b84fe606851ce955
81 81 adding changesets
82 82 add changeset ef1ea85a6374
83 83 add changeset f9cafe1212c8
84 84 add changeset 911600dab2ae
85 85 adding manifests
86 86 adding file changes
87 87 adding foo/Bar/file.txt revisions
88 88 adding foo/file.txt revisions
89 89 adding quux/file.py revisions
90 90 added 3 changesets with 3 changes to 3 files
91 91 calling hook pretxnchangegroup.acl: hgext.acl.hook
92 92 acl: acl.allow not enabled
93 93 acl: acl.deny not enabled
94 94 acl: allowing changeset ef1ea85a6374
95 95 acl: allowing changeset f9cafe1212c8
96 96 acl: allowing changeset 911600dab2ae
97 97 rolling back last transaction
98 98 0:6675d58eff77
99 99
100 100 Empty [acl.allow]
101 101 Pushing as user fred
102 102 hgrc = """
103 103 [hooks]
104 104 pretxnchangegroup.acl = python:hgext.acl.hook
105 105 [acl]
106 106 sources = push
107 107 [acl.allow]
108 108 """
109 109 pushing to ../b
110 110 searching for changes
111 111 common changesets up to 6675d58eff77
112 112 3 changesets found
113 113 List of changesets:
114 114 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
115 115 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
116 116 911600dab2ae7a9baff75958b84fe606851ce955
117 117 adding changesets
118 118 add changeset ef1ea85a6374
119 119 add changeset f9cafe1212c8
120 120 add changeset 911600dab2ae
121 121 adding manifests
122 122 adding file changes
123 123 adding foo/Bar/file.txt revisions
124 124 adding foo/file.txt revisions
125 125 adding quux/file.py revisions
126 126 added 3 changesets with 3 changes to 3 files
127 127 calling hook pretxnchangegroup.acl: hgext.acl.hook
128 128 acl: acl.allow enabled, 0 entries for user fred
129 129 acl: acl.deny not enabled
130 130 acl: user fred not allowed on foo/file.txt
131 131 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
132 132 abort: acl: access denied for changeset ef1ea85a6374
133 133 transaction abort!
134 134 rollback completed
135 135 no rollback information available
136 136 0:6675d58eff77
137 137
138 138 fred is allowed inside foo/
139 139 Pushing as user fred
140 140 hgrc = """
141 141 [hooks]
142 142 pretxnchangegroup.acl = python:hgext.acl.hook
143 143 [acl]
144 144 sources = push
145 145 [acl.allow]
146 146 foo/** = fred
147 147 """
148 148 pushing to ../b
149 149 searching for changes
150 150 common changesets up to 6675d58eff77
151 151 3 changesets found
152 152 List of changesets:
153 153 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
154 154 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
155 155 911600dab2ae7a9baff75958b84fe606851ce955
156 156 adding changesets
157 157 add changeset ef1ea85a6374
158 158 add changeset f9cafe1212c8
159 159 add changeset 911600dab2ae
160 160 adding manifests
161 161 adding file changes
162 162 adding foo/Bar/file.txt revisions
163 163 adding foo/file.txt revisions
164 164 adding quux/file.py revisions
165 165 added 3 changesets with 3 changes to 3 files
166 166 calling hook pretxnchangegroup.acl: hgext.acl.hook
167 167 acl: acl.allow enabled, 1 entries for user fred
168 168 acl: acl.deny not enabled
169 169 acl: allowing changeset ef1ea85a6374
170 170 acl: allowing changeset f9cafe1212c8
171 171 acl: user fred not allowed on quux/file.py
172 172 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
173 173 abort: acl: access denied for changeset 911600dab2ae
174 174 transaction abort!
175 175 rollback completed
176 176 no rollback information available
177 177 0:6675d58eff77
178 178
179 179 Empty [acl.deny]
180 180 Pushing as user barney
181 181 hgrc = """
182 182 [hooks]
183 183 pretxnchangegroup.acl = python:hgext.acl.hook
184 184 [acl]
185 185 sources = push
186 186 [acl.allow]
187 187 foo/** = fred
188 188 [acl.deny]
189 189 """
190 190 pushing to ../b
191 191 searching for changes
192 192 common changesets up to 6675d58eff77
193 193 3 changesets found
194 194 List of changesets:
195 195 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
196 196 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
197 197 911600dab2ae7a9baff75958b84fe606851ce955
198 198 adding changesets
199 199 add changeset ef1ea85a6374
200 200 add changeset f9cafe1212c8
201 201 add changeset 911600dab2ae
202 202 adding manifests
203 203 adding file changes
204 204 adding foo/Bar/file.txt revisions
205 205 adding foo/file.txt revisions
206 206 adding quux/file.py revisions
207 207 added 3 changesets with 3 changes to 3 files
208 208 calling hook pretxnchangegroup.acl: hgext.acl.hook
209 209 acl: acl.allow enabled, 0 entries for user barney
210 210 acl: acl.deny enabled, 0 entries for user barney
211 211 acl: user barney not allowed on foo/file.txt
212 212 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
213 213 abort: acl: access denied for changeset ef1ea85a6374
214 214 transaction abort!
215 215 rollback completed
216 216 no rollback information available
217 217 0:6675d58eff77
218 218
219 219 fred is allowed inside foo/, but not foo/bar/ (case matters)
220 220 Pushing as user fred
221 221 hgrc = """
222 222 [hooks]
223 223 pretxnchangegroup.acl = python:hgext.acl.hook
224 224 [acl]
225 225 sources = push
226 226 [acl.allow]
227 227 foo/** = fred
228 228 [acl.deny]
229 229 foo/bar/** = fred
230 230 """
231 231 pushing to ../b
232 232 searching for changes
233 233 common changesets up to 6675d58eff77
234 234 3 changesets found
235 235 List of changesets:
236 236 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
237 237 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
238 238 911600dab2ae7a9baff75958b84fe606851ce955
239 239 adding changesets
240 240 add changeset ef1ea85a6374
241 241 add changeset f9cafe1212c8
242 242 add changeset 911600dab2ae
243 243 adding manifests
244 244 adding file changes
245 245 adding foo/Bar/file.txt revisions
246 246 adding foo/file.txt revisions
247 247 adding quux/file.py revisions
248 248 added 3 changesets with 3 changes to 3 files
249 249 calling hook pretxnchangegroup.acl: hgext.acl.hook
250 250 acl: acl.allow enabled, 1 entries for user fred
251 251 acl: acl.deny enabled, 1 entries for user fred
252 252 acl: allowing changeset ef1ea85a6374
253 253 acl: allowing changeset f9cafe1212c8
254 254 acl: user fred not allowed on quux/file.py
255 255 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
256 256 abort: acl: access denied for changeset 911600dab2ae
257 257 transaction abort!
258 258 rollback completed
259 259 no rollback information available
260 260 0:6675d58eff77
261 261
262 262 fred is allowed inside foo/, but not foo/Bar/
263 263 Pushing as user fred
264 264 hgrc = """
265 265 [hooks]
266 266 pretxnchangegroup.acl = python:hgext.acl.hook
267 267 [acl]
268 268 sources = push
269 269 [acl.allow]
270 270 foo/** = fred
271 271 [acl.deny]
272 272 foo/bar/** = fred
273 273 foo/Bar/** = fred
274 274 """
275 275 pushing to ../b
276 276 searching for changes
277 277 common changesets up to 6675d58eff77
278 278 3 changesets found
279 279 List of changesets:
280 280 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
281 281 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
282 282 911600dab2ae7a9baff75958b84fe606851ce955
283 283 adding changesets
284 284 add changeset ef1ea85a6374
285 285 add changeset f9cafe1212c8
286 286 add changeset 911600dab2ae
287 287 adding manifests
288 288 adding file changes
289 289 adding foo/Bar/file.txt revisions
290 290 adding foo/file.txt revisions
291 291 adding quux/file.py revisions
292 292 added 3 changesets with 3 changes to 3 files
293 293 calling hook pretxnchangegroup.acl: hgext.acl.hook
294 294 acl: acl.allow enabled, 1 entries for user fred
295 295 acl: acl.deny enabled, 2 entries for user fred
296 296 acl: allowing changeset ef1ea85a6374
297 297 acl: user fred denied on foo/Bar/file.txt
298 298 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
299 299 abort: acl: access denied for changeset f9cafe1212c8
300 300 transaction abort!
301 301 rollback completed
302 302 no rollback information available
303 303 0:6675d58eff77
304 304
305 305 barney is not mentioned => not allowed anywhere
306 306 Pushing as user barney
307 307 hgrc = """
308 308 [hooks]
309 309 pretxnchangegroup.acl = python:hgext.acl.hook
310 310 [acl]
311 311 sources = push
312 312 [acl.allow]
313 313 foo/** = fred
314 314 [acl.deny]
315 315 foo/bar/** = fred
316 316 foo/Bar/** = fred
317 317 """
318 318 pushing to ../b
319 319 searching for changes
320 320 common changesets up to 6675d58eff77
321 321 3 changesets found
322 322 List of changesets:
323 323 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
324 324 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
325 325 911600dab2ae7a9baff75958b84fe606851ce955
326 326 adding changesets
327 327 add changeset ef1ea85a6374
328 328 add changeset f9cafe1212c8
329 329 add changeset 911600dab2ae
330 330 adding manifests
331 331 adding file changes
332 332 adding foo/Bar/file.txt revisions
333 333 adding foo/file.txt revisions
334 334 adding quux/file.py revisions
335 335 added 3 changesets with 3 changes to 3 files
336 336 calling hook pretxnchangegroup.acl: hgext.acl.hook
337 337 acl: acl.allow enabled, 0 entries for user barney
338 338 acl: acl.deny enabled, 0 entries for user barney
339 339 acl: user barney not allowed on foo/file.txt
340 340 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
341 341 abort: acl: access denied for changeset ef1ea85a6374
342 342 transaction abort!
343 343 rollback completed
344 344 no rollback information available
345 345 0:6675d58eff77
346 346
347 347 barney is allowed everywhere
348 348 Pushing as user barney
349 349 hgrc = """
350 350 [hooks]
351 351 pretxnchangegroup.acl = python:hgext.acl.hook
352 352 [acl]
353 353 sources = push
354 354 [acl.allow]
355 355 foo/** = fred
356 356 [acl.deny]
357 357 foo/bar/** = fred
358 358 foo/Bar/** = fred
359 359 [acl.allow]
360 360 ** = barney
361 361 """
362 362 pushing to ../b
363 363 searching for changes
364 364 common changesets up to 6675d58eff77
365 365 3 changesets found
366 366 List of changesets:
367 367 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
368 368 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
369 369 911600dab2ae7a9baff75958b84fe606851ce955
370 370 adding changesets
371 371 add changeset ef1ea85a6374
372 372 add changeset f9cafe1212c8
373 373 add changeset 911600dab2ae
374 374 adding manifests
375 375 adding file changes
376 376 adding foo/Bar/file.txt revisions
377 377 adding foo/file.txt revisions
378 378 adding quux/file.py revisions
379 379 added 3 changesets with 3 changes to 3 files
380 380 calling hook pretxnchangegroup.acl: hgext.acl.hook
381 381 acl: acl.allow enabled, 1 entries for user barney
382 382 acl: acl.deny enabled, 0 entries for user barney
383 383 acl: allowing changeset ef1ea85a6374
384 384 acl: allowing changeset f9cafe1212c8
385 385 acl: allowing changeset 911600dab2ae
386 386 rolling back last transaction
387 387 0:6675d58eff77
388 388
389 389 wilma can change files with a .txt extension
390 390 Pushing as user wilma
391 391 hgrc = """
392 392 [hooks]
393 393 pretxnchangegroup.acl = python:hgext.acl.hook
394 394 [acl]
395 395 sources = push
396 396 [acl.allow]
397 397 foo/** = fred
398 398 [acl.deny]
399 399 foo/bar/** = fred
400 400 foo/Bar/** = fred
401 401 [acl.allow]
402 402 ** = barney
403 403 **/*.txt = wilma
404 404 """
405 405 pushing to ../b
406 406 searching for changes
407 407 common changesets up to 6675d58eff77
408 408 3 changesets found
409 409 List of changesets:
410 410 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
411 411 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
412 412 911600dab2ae7a9baff75958b84fe606851ce955
413 413 adding changesets
414 414 add changeset ef1ea85a6374
415 415 add changeset f9cafe1212c8
416 416 add changeset 911600dab2ae
417 417 adding manifests
418 418 adding file changes
419 419 adding foo/Bar/file.txt revisions
420 420 adding foo/file.txt revisions
421 421 adding quux/file.py revisions
422 422 added 3 changesets with 3 changes to 3 files
423 423 calling hook pretxnchangegroup.acl: hgext.acl.hook
424 424 acl: acl.allow enabled, 1 entries for user wilma
425 425 acl: acl.deny enabled, 0 entries for user wilma
426 426 acl: allowing changeset ef1ea85a6374
427 427 acl: allowing changeset f9cafe1212c8
428 428 acl: user wilma not allowed on quux/file.py
429 429 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
430 430 abort: acl: access denied for changeset 911600dab2ae
431 431 transaction abort!
432 432 rollback completed
433 433 no rollback information available
434 434 0:6675d58eff77
435 435
436 436 file specified by acl.config does not exist
437 437 Pushing as user barney
438 438 hgrc = """
439 439 [hooks]
440 440 pretxnchangegroup.acl = python:hgext.acl.hook
441 441 [acl]
442 442 sources = push
443 443 [acl.allow]
444 444 foo/** = fred
445 445 [acl.deny]
446 446 foo/bar/** = fred
447 447 foo/Bar/** = fred
448 448 [acl.allow]
449 449 ** = barney
450 450 **/*.txt = wilma
451 451 [acl]
452 452 config = ../acl.config
453 453 """
454 454 pushing to ../b
455 455 searching for changes
456 456 common changesets up to 6675d58eff77
457 457 3 changesets found
458 458 List of changesets:
459 459 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
460 460 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
461 461 911600dab2ae7a9baff75958b84fe606851ce955
462 462 adding changesets
463 463 add changeset ef1ea85a6374
464 464 add changeset f9cafe1212c8
465 465 add changeset 911600dab2ae
466 466 adding manifests
467 467 adding file changes
468 468 adding foo/Bar/file.txt revisions
469 469 adding foo/file.txt revisions
470 470 adding quux/file.py revisions
471 471 added 3 changesets with 3 changes to 3 files
472 472 calling hook pretxnchangegroup.acl: hgext.acl.hook
473 acl: acl.allow enabled, 1 entries for user barney
474 acl: acl.deny enabled, 0 entries for user barney
475 acl: allowing changeset ef1ea85a6374
476 acl: allowing changeset f9cafe1212c8
477 acl: allowing changeset 911600dab2ae
478 rolling back last transaction
473 error: pretxnchangegroup.acl hook failed: unable to open ../acl.config: No such file or directory
474 abort: unable to open ../acl.config: No such file or directory
475 transaction abort!
476 rollback completed
477 no rollback information available
479 478 0:6675d58eff77
480 479
481 480 betty is allowed inside foo/ by a acl.config file
482 481 Pushing as user betty
483 482 hgrc = """
484 483 [hooks]
485 484 pretxnchangegroup.acl = python:hgext.acl.hook
486 485 [acl]
487 486 sources = push
488 487 [acl.allow]
489 488 foo/** = fred
490 489 [acl.deny]
491 490 foo/bar/** = fred
492 491 foo/Bar/** = fred
493 492 [acl.allow]
494 493 ** = barney
495 494 **/*.txt = wilma
496 495 [acl]
497 496 config = ../acl.config
498 497 """
499 498 acl.config = """
500 499 [acl.allow]
501 500 foo/** = betty
502 501 """
503 502 pushing to ../b
504 503 searching for changes
505 504 common changesets up to 6675d58eff77
506 505 3 changesets found
507 506 List of changesets:
508 507 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
509 508 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
510 509 911600dab2ae7a9baff75958b84fe606851ce955
511 510 adding changesets
512 511 add changeset ef1ea85a6374
513 512 add changeset f9cafe1212c8
514 513 add changeset 911600dab2ae
515 514 adding manifests
516 515 adding file changes
517 516 adding foo/Bar/file.txt revisions
518 517 adding foo/file.txt revisions
519 518 adding quux/file.py revisions
520 519 added 3 changesets with 3 changes to 3 files
521 520 calling hook pretxnchangegroup.acl: hgext.acl.hook
522 521 acl: acl.allow enabled, 1 entries for user betty
523 522 acl: acl.deny enabled, 0 entries for user betty
524 523 acl: allowing changeset ef1ea85a6374
525 524 acl: allowing changeset f9cafe1212c8
526 525 acl: user betty not allowed on quux/file.py
527 526 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
528 527 abort: acl: access denied for changeset 911600dab2ae
529 528 transaction abort!
530 529 rollback completed
531 530 no rollback information available
532 531 0:6675d58eff77
533 532
534 533 acl.config can set only [acl.allow]/[acl.deny]
535 534 Pushing as user barney
536 535 hgrc = """
537 536 [hooks]
538 537 pretxnchangegroup.acl = python:hgext.acl.hook
539 538 [acl]
540 539 sources = push
541 540 [acl.allow]
542 541 foo/** = fred
543 542 [acl.deny]
544 543 foo/bar/** = fred
545 544 foo/Bar/** = fred
546 545 [acl.allow]
547 546 ** = barney
548 547 **/*.txt = wilma
549 548 [acl]
550 549 config = ../acl.config
551 550 """
552 551 acl.config = """
553 552 [acl.allow]
554 553 foo/** = betty
555 554 [hooks]
556 555 changegroup.acl = false
557 556 """
558 557 pushing to ../b
559 558 searching for changes
560 559 common changesets up to 6675d58eff77
561 560 3 changesets found
562 561 List of changesets:
563 562 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
564 563 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
565 564 911600dab2ae7a9baff75958b84fe606851ce955
566 565 adding changesets
567 566 add changeset ef1ea85a6374
568 567 add changeset f9cafe1212c8
569 568 add changeset 911600dab2ae
570 569 adding manifests
571 570 adding file changes
572 571 adding foo/Bar/file.txt revisions
573 572 adding foo/file.txt revisions
574 573 adding quux/file.py revisions
575 574 added 3 changesets with 3 changes to 3 files
576 575 calling hook pretxnchangegroup.acl: hgext.acl.hook
577 576 acl: acl.allow enabled, 1 entries for user barney
578 577 acl: acl.deny enabled, 0 entries for user barney
579 578 acl: allowing changeset ef1ea85a6374
580 579 acl: allowing changeset f9cafe1212c8
581 580 acl: allowing changeset 911600dab2ae
582 581 rolling back last transaction
583 582 0:6675d58eff77
584 583
@@ -1,56 +1,62
1 1 #!/bin/sh
2 2
3 3 cat <<EOF >> $HGRCPATH
4 4 [extensions]
5 5 notify=
6 6
7 7 [hooks]
8 8 incoming.notify = python:hgext.notify.hook
9 9
10 10 [notify]
11 11 sources = pull
12 12 diffstat = False
13 13
14 14 [usersubs]
15 15 foo@bar = *
16 16
17 17 [reposubs]
18 18 * = baz
19 19 EOF
20 20
21 21 hg help notify
22 22 hg init a
23 23 echo a > a/a
24 24 echo % commit
25 25 hg --traceback --cwd a commit -Ama -d '0 0'
26 26
27 27 echo % clone
28 28 hg --traceback clone a b
29 29
30 30 echo a >> a/a
31 31 echo % commit
32 32 hg --traceback --cwd a commit -Amb -d '1 0'
33 33
34 34 echo '% pull (minimal config)'
35 35 hg --traceback --cwd b pull ../a 2>&1 | sed -e 's/\(Message-Id:\).*/\1/' \
36 36 -e 's/changeset \([0-9a-f]* *\)in .*test-notif/changeset \1in test-notif/' \
37 37 -e 's/^details: .*test-notify/details: test-notify/' \
38 38 -e 's/^Date:.*/Date:/'
39 39
40 40 cat <<EOF >> $HGRCPATH
41 41 [notify]
42 42 config = $HGTMP/.notify.conf
43 43 domain = test.com
44 44 strip = 3
45 45 template = Subject: {desc|firstline|strip}\nFrom: {author}\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
46 46
47 47 [web]
48 48 baseurl = http://test/
49 49 EOF
50 50
51 echo % fail for config file is missing
52 hg --cwd b rollback
53 hg --cwd b pull ../a 2>&1 | grep 'unable to open.*\.notify\.conf' > /dev/null && echo pull failed
54
55 touch "$HGTMP/.notify.conf"
56
51 57 echo % pull
52 58 hg --cwd b rollback
53 59 hg --traceback --cwd b pull ../a 2>&1 | sed -e 's/\(Message-Id:\).*/\1/' \
54 60 -e 's/changeset \([0-9a-f]*\) in .*/changeset \1/' \
55 61 -e 's/^Date:.*/Date:/'
56 62
@@ -1,63 +1,66
1 1 notify extension - No help text available
2 2
3 3 no commands defined
4 4 % commit
5 5 adding a
6 6 % clone
7 7 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
8 8 % commit
9 9 % pull (minimal config)
10 10 pulling from ../a
11 11 searching for changes
12 12 adding changesets
13 13 adding manifests
14 14 adding file changes
15 15 added 1 changesets with 1 changes to 1 files
16 16 Date:
17 17 Subject: changeset in test-notify/b: b
18 18 From: test
19 19 X-Hg-Notification: changeset 0647d048b600
20 20 Message-Id:
21 21 To: baz, foo@bar
22 22
23 23 changeset 0647d048b600 in test-notify/b
24 24 details: test-notify/b?cmd=changeset;node=0647d048b600
25 25 description:
26 26 b
27 27
28 28 diffs (6 lines):
29 29
30 30 diff -r cb9a9f314b8b -r 0647d048b600 a
31 31 --- a/a Thu Jan 01 00:00:00 1970 +0000
32 32 +++ b/a Thu Jan 01 00:00:01 1970 +0000
33 33 @@ -1,1 +1,2 @@ a
34 34 a
35 35 +a
36 36 (run 'hg update' to get a working copy)
37 % fail for config file is missing
38 rolling back last transaction
39 pull failed
37 40 % pull
38 41 rolling back last transaction
39 42 pulling from ../a
40 43 searching for changes
41 44 adding changesets
42 45 adding manifests
43 46 adding file changes
44 47 added 1 changesets with 1 changes to 1 files
45 48 Date:
46 49 Subject: b
47 50 From: test@test.com
48 51 X-Hg-Notification: changeset 0647d048b600
49 52 Message-Id:
50 53 To: baz@test.com, foo@bar
51 54
52 55 changeset 0647d048b600
53 56 description:
54 57 b
55 58 diffs (6 lines):
56 59
57 60 diff -r cb9a9f314b8b -r 0647d048b600 a
58 61 --- a/a Thu Jan 01 00:00:00 1970 +0000
59 62 +++ b/a Thu Jan 01 00:00:01 1970 +0000
60 63 @@ -1,1 +1,2 @@ a
61 64 a
62 65 +a
63 66 (run 'hg update' to get a working copy)
General Comments 0
You need to be logged in to leave comments. Login now