# HG changeset patch # User Dirkjan Ochtman # Date 1214994477 -7200 # Node ID 8909070fd05e8b03f86d38e8d008113d2a2329e4 # Parent c228ae4bc89cc54d686e2ba8a22527c14f1c89f8# Parent 943f066c0d58763d3bffa6333e8da31988e02fa0 merge another backout diff -r 943f066c0d58 -r 8909070fd05e contrib/win32/mercurial.iss --- a/contrib/win32/mercurial.iss Wed Jul 02 12:02:33 2008 +0200 +++ b/contrib/win32/mercurial.iss Wed Jul 02 12:27:57 2008 +0200 @@ -2,7 +2,7 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! [Setup] -AppCopyright=Copyright 2005-2007 Matt Mackall and others +AppCopyright=Copyright 2005-2008 Matt Mackall and others AppName=Mercurial AppVerName=Mercurial snapshot InfoAfterFile=contrib/win32/postinstall.txt @@ -18,7 +18,7 @@ DefaultDirName={pf}\Mercurial SourceDir=..\.. VersionInfoDescription=Mercurial distributed SCM -VersionInfoCopyright=Copyright 2005-2007 Matt Mackall and others +VersionInfoCopyright=Copyright 2005-2008 Matt Mackall and others VersionInfoCompany=Matt Mackall and others InternalCompressLevel=max SolidCompression=true diff -r 943f066c0d58 -r 8909070fd05e hgext/acl.py --- a/hgext/acl.py Wed Jul 02 12:02:33 2008 +0200 +++ b/hgext/acl.py Wed Jul 02 12:27:57 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 943f066c0d58 -r 8909070fd05e mercurial/commands.py --- a/mercurial/commands.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/commands.py Wed Jul 02 12:27:57 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 943f066c0d58 -r 8909070fd05e mercurial/context.py --- a/mercurial/context.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/context.py Wed Jul 02 12:27:57 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 943f066c0d58 -r 8909070fd05e mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/hgweb/hgweb_mod.py Wed Jul 02 12:27:57 2008 +0200 @@ -169,7 +169,7 @@ req.write(content) del tmpl - return req + return [] except revlog.LookupError, err: req.respond(HTTP_NOT_FOUND, ctype) @@ -177,12 +177,15 @@ if 'manifest' not in msg: msg = 'revision not found: %s' % err.name req.write(tmpl('error', error=msg)) + return [] except (RepoError, revlog.RevlogError), inst: req.respond(HTTP_SERVER_ERROR, ctype) req.write(tmpl('error', error=str(inst))) + return [] except ErrorResponse, inst: req.respond(inst.code, ctype) req.write(tmpl('error', error=inst.message)) + return [] def templater(self, req): diff -r 943f066c0d58 -r 8909070fd05e mercurial/hgweb/hgwebdir_mod.py --- a/mercurial/hgweb/hgwebdir_mod.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/hgweb/hgwebdir_mod.py Wed Jul 02 12:27:57 2008 +0200 @@ -70,8 +70,7 @@ def __call__(self, env, respond): req = wsgirequest(env, respond) - self.run_wsgi(req) - return req + return self.run_wsgi(req) def run_wsgi(self, req): @@ -91,13 +90,13 @@ else: fname = req.form['static'][0] req.write(staticfile(static, fname, req)) - return + return [] # top-level index elif not virtual: req.respond(HTTP_OK, ctype) req.write(self.makeindex(req, tmpl)) - return + return [] # nested indexes and hgwebs @@ -108,8 +107,7 @@ req.env['REPO_NAME'] = virtual try: repo = hg.repository(self.parentui, real) - hgweb(repo).run_wsgi(req) - return + return hgweb(repo).run_wsgi(req) except IOError, inst: msg = inst.strerror raise ErrorResponse(HTTP_SERVER_ERROR, msg) @@ -121,7 +119,7 @@ if [r for r in repos if r.startswith(subdir)]: req.respond(HTTP_OK, ctype) req.write(self.makeindex(req, tmpl, subdir)) - return + return [] up = virtual.rfind('/') if up < 0: @@ -131,10 +129,12 @@ # prefixes not found req.respond(HTTP_NOT_FOUND, ctype) req.write(tmpl("notfound", repo=virtual)) + return [] except ErrorResponse, err: req.respond(err.code, ctype) req.write(tmpl('error', error=err.message or '')) + return [] finally: tmpl = None diff -r 943f066c0d58 -r 8909070fd05e mercurial/hgweb/protocol.py --- a/mercurial/hgweb/protocol.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/hgweb/protocol.py Wed Jul 02 12:27:57 2008 +0200 @@ -124,8 +124,7 @@ # response when run outside cgi script pass req.respond(HTTP_OK, HGTYPE) - yield errorfmt % 'unsynced changes' - return + return errorfmt % 'unsynced changes', req.respond(HTTP_OK, HGTYPE) @@ -143,8 +142,7 @@ lock = repo.lock() try: if not check_heads(): - yield errorfmt % 'unsynced changes' - return + return errorfmt % 'unsynced changes', fp.seek(0) header = fp.read(6) @@ -170,11 +168,11 @@ finally: val = sys.stdout.getvalue() sys.stdout, sys.stderr = oldio - yield '%d\n%s' % (ret, val) + return '%d\n%s' % (ret, val), finally: del lock except ValueError, inst: - yield errorfmt % inst + return errorfmt % inst, except (OSError, IOError), inst: filename = getattr(inst, 'filename', '') # Don't send our filesystem layout to the client @@ -188,11 +186,12 @@ else: code = HTTP_SERVER_ERROR req.respond(code) - yield '0\n%s: %s\n' % (error, filename) + return '0\n%s: %s\n' % (error, filename), finally: fp.close() os.unlink(tempname) def stream_out(repo, req): req.respond(HTTP_OK, HGTYPE) - return streamclone.stream_out(repo, untrusted=True) + streamclone.stream_out(repo, req, untrusted=True) + return [] diff -r 943f066c0d58 -r 8909070fd05e mercurial/httprepo.py --- a/mercurial/httprepo.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/httprepo.py Wed Jul 02 12:27:57 2008 +0200 @@ -268,6 +268,7 @@ # 1.0 here is the _protocol_ version opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] + opener.addheaders.append(('Accept', 'application/mercurial-0.1')) urllib2.install_opener(opener) def url(self): diff -r 943f066c0d58 -r 8909070fd05e mercurial/localrepo.py --- a/mercurial/localrepo.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/localrepo.py Wed Jul 02 12:27:57 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 943f066c0d58 -r 8909070fd05e mercurial/manifest.py --- a/mercurial/manifest.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/manifest.py Wed Jul 02 12:27:57 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 943f066c0d58 -r 8909070fd05e mercurial/patch.py diff -r 943f066c0d58 -r 8909070fd05e mercurial/sshserver.py --- a/mercurial/sshserver.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/sshserver.py Wed Jul 02 12:27:57 2008 +0200 @@ -204,6 +204,4 @@ os.unlink(tempname) def do_stream_out(self): - for chunk in streamclone.stream_out(self.repo): - self.fout.write(chunk) - self.fout.flush() + streamclone.stream_out(self.repo, self.fout) diff -r 943f066c0d58 -r 8909070fd05e mercurial/streamclone.py --- a/mercurial/streamclone.py Wed Jul 02 12:02:33 2008 +0200 +++ b/mercurial/streamclone.py Wed Jul 02 12:27:57 2008 +0200 @@ -51,12 +51,12 @@ # # server writes out raw file data. -def stream_out(repo, untrusted=False): +def stream_out(repo, fileobj, untrusted=False): '''stream out all metadata files in repository. writes to file-like object, must support write() and optional flush().''' if not repo.ui.configbool('server', 'uncompressed', untrusted=untrusted): - yield '1\n' + fileobj.write('1\n') return # get consistent snapshot of repo. lock during scan so lock not @@ -67,10 +67,10 @@ repolock = repo.lock() except (lock.LockHeld, lock.LockUnavailable), inst: repo.ui.warn('locking the repository failed: %s\n' % (inst,)) - yield '2\n' + fileobj.write('2\n') return - yield '0\n' + fileobj.write('0\n') repo.ui.debug('scanning\n') entries = [] total_bytes = 0 @@ -83,9 +83,11 @@ repo.ui.debug('%d files, %d bytes to transfer\n' % (len(entries), total_bytes)) - yield '%d %d\n' % (len(entries), total_bytes) + fileobj.write('%d %d\n' % (len(entries), total_bytes)) for name, size in entries: repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) - yield '%s\0%d\n' % (name, size) + fileobj.write('%s\0%d\n' % (name, size)) for chunk in util.filechunkiter(repo.sopener(name), limit=size): - yield chunk + fileobj.write(chunk) + flush = getattr(fileobj, 'flush', None) + if flush: flush() diff -r 943f066c0d58 -r 8909070fd05e setup.py --- a/setup.py Wed Jul 02 12:02:33 2008 +0200 +++ b/setup.py Wed Jul 02 12:27:57 2008 +0200 @@ -129,7 +129,7 @@ [os.path.join(root, file_) for file_ in files]) for root, dirs, files in os.walk('templates')], cmdclass=cmdclass, - options=dict(py2exe=dict(packages=['hgext']), + options=dict(py2exe=dict(packages=['hgext', 'email']), bdist_mpkg=dict(zipdist=True, license='COPYING', readme='contrib/macosx/Readme.html', diff -r 943f066c0d58 -r 8909070fd05e tests/test-acl.out --- a/tests/test-acl.out Wed Jul 02 12:02:33 2008 +0200 +++ b/tests/test-acl.out Wed Jul 02 12:27:57 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 diff -r 943f066c0d58 -r 8909070fd05e tests/test-hgweb-commands --- a/tests/test-hgweb-commands Wed Jul 02 12:02:33 2008 +0200 +++ b/tests/test-hgweb-commands Wed Jul 02 12:27:57 2008 +0200 @@ -34,6 +34,7 @@ echo % Overviews "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/tags/?style=atom' | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//" "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/summary/?style=gitweb' | sed "s/[0-9]* years ago/long ago/g" +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/graph/?style=gitweb' | sed "s/[0-9]* years/long/g" echo % capabilities "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities' diff -r 943f066c0d58 -r 8909070fd05e tests/test-hgweb-commands.out Binary file tests/test-hgweb-commands.out has changed