# HG changeset patch # User Dirkjan Ochtman # Date 1214983873 -7200 # Node ID c64f35a96448e2e69864207de2aaa1f17d0b9f24 # Parent b2c4be19d7b1458ce0cf78fe1319aa2639a5947a# Parent e81d2bd669088aa22e3437c610d216500ffeb02c merge with main diff -r b2c4be19d7b1 -r c64f35a96448 hgext/acl.py --- a/hgext/acl.py Wed Jul 02 09:21:57 2008 +0200 +++ b/hgext/acl.py Wed Jul 02 09:31:13 2008 +0200 @@ -46,77 +46,45 @@ # ** = user6 from mercurial.i18n import _ -from mercurial.node import bin, short from mercurial import util import getpass -class checker(object): - '''acl checker.''' - - def buildmatch(self, key): - '''return tuple of (match function, list enabled).''' - if not self.ui.has_section(key): - self.ui.debug(_('acl: %s not enabled\n') % key) - return None, False - - thisuser = self.getuser() - pats = [pat for pat, users in self.ui.configitems(key) - if thisuser in users.replace(',', ' ').split()] - self.ui.debug(_('acl: %s enabled, %d entries for user %s\n') % - (key, len(pats), thisuser)) - if pats: - match = util.matcher(self.repo.root, names=pats)[1] - else: - match = util.never - return match, True - - def getuser(self): - '''return name of authenticated user.''' - return self.user +def buildmatch(ui, repo, user, key): + '''return tuple of (match function, list enabled).''' + if not ui.has_section(key): + ui.debug(_('acl: %s not enabled\n') % key) + return None - def __init__(self, ui, repo): - self.ui = ui - self.repo = repo - self.user = getpass.getuser() - cfg = self.ui.config('acl', 'config') - if cfg: - self.ui.readsections(cfg, 'acl.allow', 'acl.deny') - self.allow, self.allowable = self.buildmatch('acl.allow') - self.deny, self.deniable = self.buildmatch('acl.deny') - - def skipsource(self, source): - '''true if incoming changes from this source should be skipped.''' - ok_sources = self.ui.config('acl', 'sources', 'serve').split() - return source not in ok_sources - - def check(self, node): - '''return if access allowed, raise exception if not.''' - files = self.repo[node].files() - if self.deniable: - for f in files: - if self.deny(f): - self.ui.debug(_('acl: user %s denied on %s\n') % - (self.getuser(), f)) - raise util.Abort(_('acl: access denied for changeset %s') % - short(node)) - if self.allowable: - for f in files: - if not self.allow(f): - self.ui.debug(_('acl: user %s not allowed on %s\n') % - (self.getuser(), f)) - raise util.Abort(_('acl: access denied for changeset %s') % - short(node)) - self.ui.debug(_('acl: allowing changeset %s\n') % short(node)) + pats = [pat for pat, users in ui.configitems(key) + if user in users.replace(',', ' ').split()] + ui.debug(_('acl: %s enabled, %d entries for user %s\n') % + (key, len(pats), user)) + if pats: + return util.matcher(repo.root, names=pats)[1] + return util.never def hook(ui, repo, hooktype, node=None, source=None, **kwargs): if hooktype != 'pretxnchangegroup': raise util.Abort(_('config error - hook type "%s" cannot stop ' 'incoming changesets') % hooktype) - - c = checker(ui, repo) - if c.skipsource(source): + if source not in ui.config('acl', 'sources', 'serve').split(): ui.debug(_('acl: changes have source "%s" - skipping\n') % source) return - for rev in xrange(repo[node].rev(), len(repo)): - c.check(repo.changelog.node(rev)) + user = getpass.getuser() + cfg = ui.config('acl', 'config') + if cfg: + ui.readsections(cfg, 'acl.allow', 'acl.deny') + allow = buildmatch(ui, repo, user, 'acl.allow') + deny = buildmatch(ui, repo, user, 'acl.deny') + + for rev in xrange(repo[node], len(repo)): + ctx = repo[rev] + for f in ctx.files(): + if deny and deny(f): + ui.debug(_('acl: user %s denied on %s\n') % (user, f)) + raise util.Abort(_('acl: access denied for changeset %s') % ctx) + if allow and not allow(f): + ui.debug(_('acl: user %s not allowed on %s\n') % (user, f)) + raise util.Abort(_('acl: access denied for changeset %s') % ctx) + ui.debug(_('acl: allowing changeset %s\n') % ctx) diff -r b2c4be19d7b1 -r c64f35a96448 mercurial/commands.py --- a/mercurial/commands.py Wed Jul 02 09:21:57 2008 +0200 +++ b/mercurial/commands.py Wed Jul 02 09:31:13 2008 +0200 @@ -110,8 +110,8 @@ ctx = repo[opts['rev']] m = cmdutil.match(repo, pats, opts) - for abs in repo.walk(m, ctx.node()): - fctx = ctx.filectx(abs) + for abs in ctx.walk(m): + fctx = ctx[abs] if not opts['text'] and util.binary(fctx.data()): ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs)) continue @@ -485,9 +485,9 @@ ctx = repo[opts['rev']] err = 1 m = cmdutil.match(repo, (file1,) + pats, opts) - for abs in repo.walk(m, ctx.node()): + for abs in ctx.walk(m): fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) - data = ctx.filectx(abs).data() + data = ctx[abs].data() if opts.get('decode'): data = repo.wwritedata(abs, data) fp.write(data) @@ -907,8 +907,8 @@ ctx = repo[opts.get('rev')] m = cmdutil.match(repo, (file1,) + pats, opts) - for abs in repo.walk(m, ctx.node()): - fctx = ctx.filectx(abs) + for abs in ctx.walk(m): + fctx = ctx[abs] o = fctx.filelog().renamed(fctx.filenode()) rel = m.rel(abs) if o: @@ -1693,17 +1693,13 @@ that contain white space as multiple filenames. """ end = opts['print0'] and '\0' or '\n' - rev = opts['rev'] - if rev: - node = repo.lookup(rev) - else: - node = None + rev = opts.get('rev') or None ret = 1 m = cmdutil.match(repo, pats, opts, default='relglob') m.bad = lambda x,y: False - for abs in repo.walk(m, node): - if not node and abs not in repo.dirstate: + for abs in repo[rev].walk(m): + if not rev and abs not in repo.dirstate: continue if opts['fullpath']: ui.write(os.path.join(repo.root, abs), end) @@ -2350,7 +2346,7 @@ m = cmdutil.match(repo, pats, opts) m.bad = badfn - for abs in repo.walk(m, node=node): + for abs in repo[node].walk(m): if abs not in names: names[abs] = m.rel(abs), m.exact(abs) diff -r b2c4be19d7b1 -r c64f35a96448 mercurial/context.py --- a/mercurial/context.py Wed Jul 02 09:21:57 2008 +0200 +++ b/mercurial/context.py Wed Jul 02 09:31:13 2008 +0200 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -from node import nullid, nullrev, short +from node import nullid, nullrev, short, hex from i18n import _ import ancestor, bdiff, revlog, util, os, errno @@ -23,6 +23,9 @@ def __str__(self): return short(self.node()) + def __int__(self): + return self.rev() + def __repr__(self): return "" % str(self) @@ -79,6 +82,7 @@ def rev(self): return self._rev def node(self): return self._node + def hex(self): return hex(self._node) def user(self): return self._changeset[1] def date(self): return self._changeset[2] def files(self): return self._changeset[3] @@ -142,6 +146,23 @@ n = self._repo.changelog.ancestor(self._node, c2._node) return changectx(self._repo, n) + def walk(self, match): + fdict = dict.fromkeys(match.files()) + # for dirstate.walk, files=['.'] means "walk the whole tree". + # follow that here, too + fdict.pop('.', None) + for fn in self: + for ffn in fdict: + # match if the file is the exact name or a directory + if ffn == fn or fn.startswith("%s/" % ffn): + del fdict[ffn] + break + if match(fn): + yield fn + for fn in util.sort(fdict): + if match.bad(fn, 'No such file in rev ' + str(self)) and match(fn): + yield fn + class filectx(object): """A filecontext object makes access to data related to a particular filerevision convenient.""" @@ -572,6 +593,10 @@ """return the ancestor context of self and c2""" return self._parents[0].ancestor(c2) # punt on two parents for now + def walk(self, match): + for src, fn, st in self._repo.dirstate.walk(match, True, False): + yield fn + class workingfilectx(filectx): """A workingfilectx object makes access to data related to a particular file in the working directory convenient.""" @@ -693,6 +718,9 @@ def __str__(self): return str(self._parents[0]) + "+" + def __int__(self): + return self._rev + def __nonzero__(self): return True diff -r b2c4be19d7b1 -r c64f35a96448 mercurial/localrepo.py --- a/mercurial/localrepo.py Wed Jul 02 09:21:57 2008 +0200 +++ b/mercurial/localrepo.py Wed Jul 02 09:31:13 2008 +0200 @@ -941,27 +941,7 @@ changeset, finding all files matched by the match function ''' - - if node: - fdict = dict.fromkeys(match.files()) - # for dirstate.walk, files=['.'] means "walk the whole tree". - # follow that here, too - fdict.pop('.', None) - for fn in self[node]: - for ffn in fdict: - # match if the file is the exact name or a directory - if ffn == fn or fn.startswith("%s/" % ffn): - del fdict[ffn] - break - if match(fn): - yield fn - for fn in util.sort(fdict): - if match.bad(fn, 'No such file in rev ' + short(node)) \ - and match(fn): - yield fn - else: - for src, fn, st in self.dirstate.walk(match, True, False): - yield fn + return self[node].walk(match) def status(self, node1=None, node2=None, match=None, ignored=False, clean=False, unknown=False): diff -r b2c4be19d7b1 -r c64f35a96448 mercurial/manifest.py --- a/mercurial/manifest.py Wed Jul 02 09:21:57 2008 +0200 +++ b/mercurial/manifest.py Wed Jul 02 09:31:13 2008 +0200 @@ -119,16 +119,16 @@ return "".join([struct.pack(">lll", d[0], d[1], len(d[2])) + d[2] for d in x ]) - def checkforbidden(f): - if '\n' in f or '\r' in f: - raise RevlogError(_("'\\n' and '\\r' disallowed in filenames")) + def checkforbidden(l): + for f in l: + if '\n' in f or '\r' in f: + raise RevlogError(_("'\\n' and '\\r' disallowed in filenames")) # if we're using the listcache, make sure it is valid and # parented by the same node we're diffing against if not (changed and self.listcache and p1 and self.mapcache[0] == p1): files = util.sort(map) - for f in files: - checkforbidden(f) + checkforbidden(files) # if this is changed to support newlines in filenames, # be sure to check the templates/ dir again (especially *-raw.tmpl) @@ -139,8 +139,7 @@ else: addlist = self.listcache - for f in changed[0]: - checkforbidden(f) + checkforbidden(changed[0]) # combine the changed lists into one list for sorting work = [[x, 0] for x in changed[0]] work[len(work):] = [[x, 1] for x in changed[1]] diff -r b2c4be19d7b1 -r c64f35a96448 tests/test-acl.out --- a/tests/test-acl.out Wed Jul 02 09:21:57 2008 +0200 +++ b/tests/test-acl.out Wed Jul 02 09:31:13 2008 +0200 @@ -58,8 +58,6 @@ adding quux/file.py revisions added 3 changesets with 3 changes to 3 files calling hook pretxnchangegroup.acl: hgext.acl.hook -acl: acl.allow not enabled -acl: acl.deny not enabled acl: changes have source "push" - skipping updating the branch cache rolling back last transaction