Mercurial > hg
changeset 14127:f45c8db21749
merge with nicdumz
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Sun, 01 May 2011 06:04:08 -0500 |
parents | a36e8c99d51c (diff) fbbe9239574a (current diff) |
children | 0386b51dd749 |
files | tests/darcs1.hg tests/legacy-encoding.hg tests/tampered.hg tests/test-bundle-r.t tests/test-issue322.t tests/test-issue433.t tests/test-issue436.t tests/test-keyword.hg tests/test-manifest.hg tests/test-merge-symlinks.hg tests/test-no-symlinks.hg tests/test-rebase-keep-branch.t |
diffstat | 66 files changed, 1160 insertions(+), 892 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/wix/guids.wxi Sun May 01 10:51:10 2011 +0200 +++ b/contrib/wix/guids.wxi Sun May 01 06:04:08 2011 -0500 @@ -33,7 +33,7 @@ <?define templates.raw.guid = {04DE03A2-FBFD-4c5f-8DEA-5436DDF4689D} ?> <?define templates.rss.guid = {A7D608DE-0CF6-44f4-AF1E-EE30CC237FDA} ?> <?define templates.spartan.guid = {80222625-FA8F-44b1-86CE-1781EF375D09} ?> - <?define templates.static.guid = {68C9F843-DE7E-480f-9DA2-D220B19D02C3} ?> + <?define templates.static.guid = {B27D7311-050A-4A96-9971-B674A0EA21D0} ?> <!-- mercurial.wxs --> <?define ProductUpgradeCode = {A1CC6134-E945-4399-BE36-EB0017FDF7CF} ?>
--- a/contrib/wix/templates.wxs Sun May 01 10:51:10 2011 +0200 +++ b/contrib/wix/templates.wxs Sun May 01 06:04:08 2011 -0500 @@ -195,7 +195,7 @@ <File Id="static.coal.file.png" Name="coal-file.png" /> <File Id="static.coal.folder.png" Name="coal-folder.png" /> <File Id="static.excanvas.js" Name="excanvas.js" /> - <File Id="static.graph.js" Name="graph.js" /> + <File Id="static.mercurial.js" Name="mercurial.js" /> <File Id="static.hgicon.png" Name="hgicon.png" /> <File Id="static.hglogo.png" Name="hglogo.png" /> <File Id="static.style.coal.css" Name="style-coal.css" />
--- a/doc/hgrc.5.txt Sun May 01 10:51:10 2011 +0200 +++ b/doc/hgrc.5.txt Sun May 01 06:04:08 2011 -0500 @@ -634,6 +634,10 @@ Run before starting a local commit. Exit status 0 allows the commit to proceed. Non-zero status will cause the commit to fail. Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``. +``prelistkeys`` + Run before listing pushkeys (like bookmarks) in the + repository. Non-zero status will cause failure. The key namespace is + in ``$HG_NAMESPACE``. ``preoutgoing`` Run before collecting changes to send from the local repository to another. Non-zero status will cause failure. This lets you prevent @@ -643,6 +647,12 @@ ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote SSH or HTTP repository. If "push", "pull" or "bundle", operation is happening on behalf of repository on same system. +``prepushkey`` + Run before a pushkey (like a bookmark) is added to the + repository. Non-zero status will cause the key to be rejected. The + key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``, + the old value (if any) is in ``$HG_OLD``, and the new value is in + ``$HG_NEW``. ``pretag`` Run before creating a tag. Exit status 0 allows the tag to be created. Non-zero status will cause the tag to fail. ID of @@ -669,6 +679,15 @@ the update to proceed. Non-zero status will prevent the update. Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is in ``$HG_PARENT2``. +``listkeys`` + Run after listing pushkeys (like bookmarks) in the repository. The + key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a + dictionary containing the keys and values. +``pushkey`` + Run after a pushkey (like a bookmark) is added to the + repository. The key namespace is in ``$HG_NAMESPACE``, the key is in + ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new + value is in ``$HG_NEW``. ``tag`` Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
--- a/hgext/color.py Sun May 01 10:51:10 2011 +0200 +++ b/hgext/color.py Sun May 01 06:04:08 2011 -0500 @@ -100,7 +100,7 @@ ''' -import os +import os, sys from mercurial import commands, dispatch, extensions, ui as uimod, util from mercurial.i18n import _ @@ -301,17 +301,22 @@ global _terminfo_params if ui.plain(): return + + formatted = (os.environ.get('TERM') != 'dumb' and ui.formatted()) mode = ui.config('color', 'mode', 'auto') if mode == 'auto': if os.name == 'nt' and 'TERM' not in os.environ: # looks line a cmd.exe console, use win32 API or nothing mode = w32effects and 'win32' or 'none' else: - _terminfosetup(ui) - if not _terminfo_params: - mode = 'ansi' + if not formatted: + _terminfo_params = False else: - mode = 'terminfo' + _terminfosetup(ui) + if not _terminfo_params: + mode = 'ansi' + else: + mode = 'terminfo' if mode == 'win32': if w32effects is None: # only warn if color.mode is explicitly set to win32 @@ -329,8 +334,7 @@ auto = coloropt == 'auto' always = util.parsebool(coloropt) if (always or - (always is None and - (auto and (os.environ.get('TERM') != 'dumb' and ui_.formatted())))): + (always is None and auto and formatted)): colorui._colormode = mode colorui.__bases__ = (ui_.__class__,) ui_.__class__ = colorui
--- a/hgext/fetch.py Sun May 01 10:51:10 2011 +0200 +++ b/hgext/fetch.py Sun May 01 06:04:08 2011 -0500 @@ -9,7 +9,7 @@ from mercurial.i18n import _ from mercurial.node import nullid, short -from mercurial import commands, cmdutil, hg, util, url, error +from mercurial import commands, cmdutil, hg, util, error from mercurial.lock import release def fetch(ui, repo, source='default', **opts): @@ -66,7 +66,7 @@ other = hg.repository(hg.remoteui(repo, opts), ui.expandpath(source)) ui.status(_('pulling from %s\n') % - url.hidepassword(ui.expandpath(source))) + util.hidepassword(ui.expandpath(source))) revs = None if opts['rev']: try: @@ -125,7 +125,7 @@ # we don't translate commit messages message = (cmdutil.logmessage(opts) or ('Automated merge with %s' % - url.removeauth(other.url()))) + util.removeauth(other.url()))) editor = cmdutil.commiteditor if opts.get('force_editor') or opts.get('edit'): editor = cmdutil.commitforceeditor
--- a/hgext/graphlog.py Sun May 01 10:51:10 2011 +0200 +++ b/hgext/graphlog.py Sun May 01 06:04:08 2011 -0500 @@ -214,36 +214,50 @@ else: return (len(repo) - 1, 0) -def check_unsupported_flags(opts): +def check_unsupported_flags(pats, opts): for op in ["follow_first", "copies", "newest_first"]: if op in opts and opts[op]: raise util.Abort(_("-G/--graph option is incompatible with --%s") % op.replace("_", "-")) + if pats and opts.get('follow'): + raise util.Abort(_("-G/--graph option is incompatible with --follow " + "with file argument")) def revset(pats, opts): """Return revset str built of revisions, log options and file patterns. """ - opt2revset = dict(only_merges='merge', - only_branch='branch', - no_merges='not merge', - include='file', - exclude='not file', - prune='not follow') + opt2revset = { + 'follow': (0, 'follow()'), + 'no_merges': (0, 'not merge()'), + 'only_merges': (0, 'merge()'), + 'removed': (0, 'removes("*")'), + 'date': (1, 'date($)'), + 'branch': (2, 'branch($)'), + 'exclude': (2, 'not file($)'), + 'include': (2, 'file($)'), + 'keyword': (2, 'keyword($)'), + 'only_branch': (2, 'branch($)'), + 'prune': (2, 'not ($ or ancestors($))'), + 'user': (2, 'user($)'), + } revset = [] for op, val in opts.iteritems(): if not val: continue - revop = opt2revset.get(op, op) - if op in ('follow', 'only_merges', 'no_merges'): - revset.append('%s()' % revop) - elif op in ("date", "keyword", "remove", "user", "branch", - "only_branch", "prune"): - revset.append('%s(%s)' % (op, val)) - elif op in ('include', 'exclude'): + if op == 'rev': + # Already a revset + revset.extend(val) + if op not in opt2revset: + continue + arity, revop = opt2revset[op] + revop = revop.replace('$', '%(val)r') + if arity == 0: + revset.append(revop) + elif arity == 1: + revset.append(revop % {'val': val}) + else: for f in val: - revset.append('%s(%r)' % (op, f)) - elif op == 'rev': - revset.extend(val) + revset.append(revop % {'val': f}) for path in pats: revset.append('file(%r)' % path) @@ -275,7 +289,7 @@ directory. """ - check_unsupported_flags(opts) + check_unsupported_flags(pats, opts) revs = revrange(repo, [revset(pats, opts)]) revdag = graphmod.dagwalker(repo, revs) @@ -301,7 +315,7 @@ directory. """ - check_unsupported_flags(opts) + check_unsupported_flags([], opts) o = hg._outgoing(ui, repo, dest, opts) if o is None: return @@ -323,7 +337,7 @@ def subreporecurse(): return 1 - check_unsupported_flags(opts) + check_unsupported_flags([], opts) def display(other, chlist, displayer): revdag = graphrevs(other, chlist, opts) showparents = [ctx.node() for ctx in repo[None].parents()]
--- a/hgext/parentrevspec.py Sun May 01 10:51:10 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -# Mercurial extension to make it easy to refer to the parent of a revision -# -# Copyright (C) 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br> -# -# This software may be used and distributed according to the terms of the -# GNU General Public License version 2 or any later version. - -'''interpret suffixes to refer to ancestor revisions - -This extension allows you to use git-style suffixes to refer to the -ancestors of a specific revision. - -For example, if you can refer to a revision as "foo", then:: - - foo^N = Nth parent of foo - foo^0 = foo - foo^1 = first parent of foo - foo^2 = second parent of foo - foo^ = foo^1 - - foo~N = Nth first grandparent of foo - foo~0 = foo - foo~1 = foo^1 = foo^ = first parent of foo - foo~2 = foo^1^1 = foo^^ = first parent of first parent of foo -''' -from mercurial import error - -def reposetup(ui, repo): - if not repo.local(): - return - - class parentrevspecrepo(repo.__class__): - def lookup(self, key): - try: - _super = super(parentrevspecrepo, self) - return _super.lookup(key) - except error.RepoError: - pass - - circ = key.find('^') - tilde = key.find('~') - if circ < 0 and tilde < 0: - raise - elif circ >= 0 and tilde >= 0: - end = min(circ, tilde) - else: - end = max(circ, tilde) - - cl = self.changelog - base = key[:end] - try: - node = _super.lookup(base) - except error.RepoError: - # eek - reraise the first error - return _super.lookup(key) - - rev = cl.rev(node) - suffix = key[end:] - i = 0 - while i < len(suffix): - # foo^N => Nth parent of foo - # foo^0 == foo - # foo^1 == foo^ == 1st parent of foo - # foo^2 == 2nd parent of foo - if suffix[i] == '^': - j = i + 1 - p = cl.parentrevs(rev) - if j < len(suffix) and suffix[j].isdigit(): - j += 1 - n = int(suffix[i + 1:j]) - if n > 2 or n == 2 and p[1] == -1: - raise - else: - n = 1 - if n: - rev = p[n - 1] - i = j - # foo~N => Nth first grandparent of foo - # foo~0 = foo - # foo~1 = foo^1 == foo^ == 1st parent of foo - # foo~2 = foo^1^1 == foo^^ == 1st parent of 1st parent of foo - elif suffix[i] == '~': - j = i + 1 - while j < len(suffix) and suffix[j].isdigit(): - j += 1 - if j == i + 1: - raise - n = int(suffix[i + 1:j]) - for k in xrange(n): - rev = cl.parentrevs(rev)[0] - i = j - else: - raise - return cl.node(rev) - - repo.__class__ = parentrevspecrepo
--- a/hgext/patchbomb.py Sun May 01 10:51:10 2011 +0200 +++ b/hgext/patchbomb.py Sun May 01 06:04:08 2011 -0500 @@ -48,7 +48,7 @@ import os, errno, socket, tempfile, cStringIO, time import email.MIMEMultipart, email.MIMEBase import email.Utils, email.Encoders, email.Generator -from mercurial import cmdutil, commands, hg, mail, patch, util, discovery, url +from mercurial import cmdutil, commands, hg, mail, patch, util, discovery from mercurial.i18n import _ from mercurial.node import bin @@ -238,15 +238,14 @@ dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest) revs, checkout = hg.addbranchrevs(repo, repo, branches, revs) - if revs: - revs = [repo.lookup(rev) for rev in revs] other = hg.repository(hg.remoteui(repo, opts), dest) - ui.status(_('comparing with %s\n') % url.hidepassword(dest)) - o = discovery.findoutgoing(repo, other) + ui.status(_('comparing with %s\n') % util.hidepassword(dest)) + common, _anyinc, _heads = discovery.findcommonincoming(repo, other) + nodes = revs and map(repo.lookup, revs) or revs + o = repo.changelog.findmissing(common, heads=nodes) if not o: ui.status(_("no changes found\n")) return [] - o = repo.changelog.nodesbetween(o, revs)[0] return [str(repo.changelog.rev(r)) for r in o] def getpatches(revs):
--- a/hgext/schemes.py Sun May 01 10:51:10 2011 +0200 +++ b/hgext/schemes.py Sun May 01 06:04:08 2011 -0500 @@ -41,7 +41,7 @@ """ import os, re -from mercurial import extensions, hg, templater, url as urlmod, util +from mercurial import extensions, hg, templater, util from mercurial.i18n import _ @@ -95,4 +95,4 @@ 'letter %s:\\\n') % (scheme, scheme.upper())) hg.schemes[scheme] = ShortRepository(url, scheme, t) - extensions.wrapfunction(urlmod, 'hasdriveletter', hasdriveletter) + extensions.wrapfunction(util, 'hasdriveletter', hasdriveletter)
--- a/hgext/transplant.py Sun May 01 10:51:10 2011 +0200 +++ b/hgext/transplant.py Sun May 01 06:04:08 2011 -0500 @@ -494,10 +494,10 @@ and then resume where you left off by calling :hg:`transplant --continue/-c`. ''' - def incwalk(repo, incoming, branches, match=util.always): + def incwalk(repo, commmon, branches, match=util.always): if not branches: branches = None - for node in repo.changelog.nodesbetween(incoming, branches)[0]: + for node in repo.changelog.findmissing(common, branches): if match(node): yield node @@ -552,8 +552,8 @@ if source: sourcerepo = ui.expandpath(source) source = hg.repository(ui, sourcerepo) - source, common, incoming, bundle = bundlerepo.getremotechanges(ui, repo, - source, force=True) + source, common, anyinc, bundle = bundlerepo.getremotechanges(ui, repo, + source, force=True) else: source = repo @@ -577,7 +577,7 @@ revmap[int(r)] = source.lookup(r) elif opts.get('all') or not merges: if source != repo: - alltransplants = incwalk(source, incoming, branches, + alltransplants = incwalk(source, common, branches, match=matchfn) else: alltransplants = transplantwalk(source, p1, branches,
--- a/hgext/zeroconf/Zeroconf.py Sun May 01 10:51:10 2011 +0200 +++ b/hgext/zeroconf/Zeroconf.py Sun May 01 06:04:08 2011 -0500 @@ -808,7 +808,7 @@ try: list = self.cache[entry.key] return list[list.index(entry)] - except KeyError: + except (KeyError, ValueError): return None def getByDetails(self, name, type, clazz):
--- a/mercurial/bookmarks.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/bookmarks.py Sun May 01 06:04:08 2011 -0500 @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. from mercurial.i18n import _ -from mercurial.node import nullid, nullrev, bin, hex, short +from mercurial.node import hex from mercurial import encoding, error, util import errno, os
--- a/mercurial/bundlerepo.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/bundlerepo.py Sun May 01 06:04:08 2011 -0500 @@ -15,7 +15,7 @@ from i18n import _ import os, struct, tempfile, shutil import changegroup, util, mdiff, discovery -import localrepo, changelog, manifest, filelog, revlog, error, url +import localrepo, changelog, manifest, filelog, revlog, error class bundlerevlog(revlog.revlog): def __init__(self, opener, indexfile, bundle, @@ -274,7 +274,7 @@ cwd = os.path.join(cwd,'') if parentpath.startswith(cwd): parentpath = parentpath[len(cwd):] - u = url.url(path) + u = util.url(path) path = u.localpath() if u.scheme == 'bundle': s = path.split("+", 1) @@ -287,9 +287,8 @@ return bundlerepository(ui, repopath, bundlename) def getremotechanges(ui, repo, other, revs=None, bundlename=None, - force=False, usecommon=False): - tmp = discovery.findcommonincoming(repo, other, heads=revs, force=force, - commononly=usecommon) + force=False): + tmp = discovery.findcommonincoming(repo, other, heads=revs, force=force) common, incoming, rheads = tmp if not incoming: try: @@ -305,7 +304,7 @@ if revs is None and other.capable('changegroupsubset'): revs = rheads - if usecommon: + if other.capable('getbundle'): cg = other.getbundle('incoming', common=common, heads=revs) elif revs is None: cg = other.changegroup(incoming, "incoming")
--- a/mercurial/changegroup.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/changegroup.py Sun May 01 06:04:08 2011 -0500 @@ -43,7 +43,9 @@ return "" bundletypes = { - "": ("", nocompress), + "": ("", nocompress), # only when using unbundle on ssh and old http servers + # since the unification ssh accepts a header but there + # is no capability signaling it. "HG10UN": ("HG10UN", nocompress), "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()), "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
--- a/mercurial/cmdutil.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/cmdutil.py Sun May 01 06:04:08 2011 -0500 @@ -8,7 +8,7 @@ from node import hex, nullid, nullrev, short from i18n import _ import os, sys, errno, re, glob, tempfile -import util, scmutil, templater, patch, error, encoding, templatekw +import util, scmutil, templater, patch, error, templatekw import match as matchmod import similar, revset, subrepo @@ -174,7 +174,7 @@ pass # fall through to new-style queries if old-style fails - m = revset.match(spec) + m = revset.match(repo.ui, spec) for r in m(repo, range(len(repo))): if r not in seen: l.append(r) @@ -1314,9 +1314,16 @@ match.bad = lambda x, y: bad.append(x) or oldbad(x, y) names = [] wctx = repo[None] + wctx.status(clean=True) + existing = None + if scmutil.showportabilityalert(ui): + existing = dict([(fn.lower(), fn) for fn in + wctx.added() + wctx.clean() + wctx.modified()]) for f in repo.walk(match): exact = match.exact(f) if exact or f not in repo.dirstate: + if existing: + scmutil.checkcasecollision(ui, f, existing) names.append(f) if ui.verbose or not exact: ui.status(_('adding %s\n') % match.rel(join(f)))
--- a/mercurial/commands.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/commands.py Sun May 01 06:04:08 2011 -0500 @@ -10,7 +10,7 @@ from i18n import _, gettext import os, re, sys, difflib, time, tempfile import hg, scmutil, util, revlog, extensions, copies, error, bookmarks -import patch, help, mdiff, url, encoding, templatekw, discovery +import patch, help, url, encoding, templatekw, discovery import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server import merge as mergemod import minirst, revset, templatefilters @@ -696,49 +696,21 @@ if dest: raise util.Abort(_("--base is incompatible with specifying " "a destination")) - base = [repo.lookup(rev) for rev in base] - # create the right base - # XXX: nodesbetween / changegroup* should be "fixed" instead - o = [] - has = set((nullid,)) - for n in base: - has.update(repo.changelog.reachable(n)) - if revs: - revs = [repo.lookup(rev) for rev in revs] - visit = revs[:] - has.difference_update(visit) - else: - visit = repo.changelog.heads() - seen = {} - while visit: - n = visit.pop(0) - parents = [p for p in repo.changelog.parents(n) if p not in has] - if len(parents) == 0: - if n not in has: - o.append(n) - else: - for p in parents: - if p not in seen: - seen[p] = 1 - visit.append(p) + common = [repo.lookup(rev) for rev in base] else: dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest, opts.get('branch')) other = hg.repository(hg.remoteui(repo, opts), dest) revs, checkout = hg.addbranchrevs(repo, other, branches, revs) - if revs: - revs = [repo.lookup(rev) for rev in revs] - o = discovery.findoutgoing(repo, other, force=opts.get('force')) - - if not o: + inc = discovery.findcommonincoming(repo, other, force=opts.get('force')) + common, _anyinc, _heads = inc + + nodes = revs and map(repo.lookup, revs) or revs + cg = repo.getbundle('bundle', common=common, heads=nodes) + if not cg: ui.status(_("no changes found\n")) return 1 - if revs: - cg = repo.changegroupsubset(o, revs, 'bundle') - else: - cg = repo.changegroup(o, 'bundle') - bundletype = opts.get('type', 'bzip2').lower() btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'} bundletype = btypes.get(bundletype) @@ -1324,7 +1296,10 @@ if ui.verbose: tree = revset.parse(expr)[0] ui.note(tree, "\n") - func = revset.match(expr) + newtree = revset.findaliases(ui, tree) + if newtree != tree: + ui.note(newtree, "\n") + func = revset.match(ui, expr) for c in func(repo, range(len(repo))): ui.write("%s\n" % c) @@ -2635,7 +2610,7 @@ if 'bookmarks' not in other.listkeys('namespaces'): ui.warn(_("remote doesn't support bookmarks\n")) return 0 - ui.status(_('comparing with %s\n') % url.hidepassword(source)) + ui.status(_('comparing with %s\n') % util.hidepassword(source)) return bookmarks.diff(ui, repo, other) ret = hg.incoming(ui, repo, source, opts) @@ -2922,7 +2897,7 @@ if 'bookmarks' not in other.listkeys('namespaces'): ui.warn(_("remote doesn't support bookmarks\n")) return 0 - ui.status(_('comparing with %s\n') % url.hidepassword(dest)) + ui.status(_('comparing with %s\n') % util.hidepassword(dest)) return bookmarks.diff(ui, other, repo) ret = hg.outgoing(ui, repo, dest, opts) @@ -2996,13 +2971,13 @@ if search: for name, path in ui.configitems("paths"): if name == search: - ui.write("%s\n" % url.hidepassword(path)) + ui.write("%s\n" % util.hidepassword(path)) return ui.warn(_("not found!\n")) return 1 else: for name, path in ui.configitems("paths"): - ui.write("%s = %s\n" % (name, url.hidepassword(path))) + ui.write("%s = %s\n" % (name, util.hidepassword(path))) def postincoming(ui, repo, modheads, optupdate, checkout): if modheads == 0: @@ -3045,7 +3020,7 @@ """ source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch')) other = hg.repository(hg.remoteui(repo, opts), source) - ui.status(_('pulling from %s\n') % url.hidepassword(source)) + ui.status(_('pulling from %s\n') % util.hidepassword(source)) revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev')) if opts.get('bookmark'): @@ -3128,7 +3103,7 @@ dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest, opts.get('branch')) - ui.status(_('pushing to %s\n') % url.hidepassword(dest)) + ui.status(_('pushing to %s\n') % util.hidepassword(dest)) revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev')) other = hg.repository(hg.remoteui(repo, opts), dest) if revs: @@ -3947,7 +3922,7 @@ source, branches = hg.parseurl(ui.expandpath('default')) other = hg.repository(hg.remoteui(repo, {}), source) revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev')) - ui.debug('comparing with %s\n' % url.hidepassword(source)) + ui.debug('comparing with %s\n' % util.hidepassword(source)) repo.ui.pushbuffer() common, incoming, rheads = discovery.findcommonincoming(repo, other) repo.ui.popbuffer() @@ -3957,11 +3932,11 @@ dest, branches = hg.parseurl(ui.expandpath('default-push', 'default')) revs, checkout = hg.addbranchrevs(repo, repo, branches, None) other = hg.repository(hg.remoteui(repo, {}), dest) - ui.debug('comparing with %s\n' % url.hidepassword(dest)) + ui.debug('comparing with %s\n' % util.hidepassword(dest)) repo.ui.pushbuffer() - o = discovery.findoutgoing(repo, other) + common, _anyinc, _heads = discovery.findcommonincoming(repo, other) repo.ui.popbuffer() - o = repo.changelog.nodesbetween(o, None)[0] + o = repo.changelog.findmissing(common=common) if o: t.append(_('%d outgoing') % len(o)) if 'bookmarks' in other.listkeys('namespaces'):
--- a/mercurial/discovery.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/discovery.py Sun May 01 06:04:08 2011 -0500 @@ -9,14 +9,19 @@ from i18n import _ import util, error -def findcommonincoming(repo, remote, heads=None, force=False, commononly=False): - """Return a tuple (common, missing, heads) used to identify missing nodes - from remote. "missing" is either a boolean indicating if any nodes are missing - (when commononly=True), or else a list of the root nodes of the missing set. +def findcommonincoming(repo, remote, heads=None, force=False): + """Return a tuple (common, anyincoming, heads) used to identify the common + subset of nodes between repo and remote. - If a list of heads is specified, return only nodes which are heads - or ancestors of these heads. + "common" is a list of (at least) the heads of the common subset. + "anyincoming" is testable as a boolean indicating if any nodes are missing + locally. If remote does not support getbundle, this actually is a list of + roots of the nodes that would be incoming, to be supplied to + changegroupsubset. No code except for pull should be relying on this fact + any longer. + "heads" is either the supplied heads, or else the remote's heads. """ + m = repo.changelog.nodemap search = [] fetch = set() @@ -37,7 +42,7 @@ # and start by examining the heads repo.ui.status(_("searching for changes\n")) - if commononly: + if remote.capable('getbundle'): myheads = repo.heads() known = remote.known(myheads) if util.all(known): @@ -155,45 +160,6 @@ return base, list(fetch), heads -def findoutgoing(repo, remote, base=None, remoteheads=None, force=False): - """Return list of nodes that are roots of subsets not in remote - - If base dict is specified, assume that these nodes and their parents - exist on the remote side. - If remotehead is specified, assume it is the list of the heads from - the remote repository. - """ - if base is None: - base = findcommonincoming(repo, remote, heads=remoteheads, - force=force)[0] - else: - base = list(base) - - repo.ui.debug("common changesets up to " - + " ".join(map(short, base)) + "\n") - - remain = set(repo.changelog.nodemap) - - # prune everything remote has from the tree - remain.remove(nullid) - remove = base - while remove: - n = remove.pop(0) - if n in remain: - remain.remove(n) - for p in repo.changelog.parents(n): - remove.append(p) - - # find every node whose parents have been pruned - subset = [] - # find every remote head that will get new children - for n in remain: - p1, p2 = repo.changelog.parents(n) - if p1 not in remain and p2 not in remain: - subset.append(n) - - return subset - def prepush(repo, remote, force, revs, newbranch): '''Analyze the local and remote repositories and determine which changesets need to be pushed to the remote. Return value depends @@ -209,14 +175,13 @@ successive changegroup chunks ready to be sent over the wire and remoteheads is the list of remote heads.''' remoteheads = remote.heads() - common, inc, rheads = findcommonincoming(repo, remote, heads=remoteheads, - force=force) + common, inc, _rheads = findcommonincoming(repo, remote, heads=remoteheads, + force=force) cl = repo.changelog - update = findoutgoing(repo, remote, common, remoteheads) - outg, bases, heads = cl.nodesbetween(update, revs) + outg = cl.findmissing(common, revs) - if not bases: + if not outg: repo.ui.status(_("no changes found\n")) return None, 1 @@ -317,8 +282,7 @@ if revs is None: # use the fast path, no race possible on push - nodes = repo.changelog.findmissing(common) - cg = repo._changegroup(nodes, 'push') + cg = repo._changegroup(outg, 'push') else: - cg = repo.changegroupsubset(update, revs, 'push') + cg = repo.getbundle('push', heads=revs, common=common) return cg, remoteheads
--- a/mercurial/dispatch.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/dispatch.py Sun May 01 06:04:08 2011 -0500 @@ -133,7 +133,8 @@ elif hasattr(inst, "reason"): try: # usually it is in the form (errno, strerror) reason = inst.reason.args[1] - except AttributeError: # it might be anything, for example a string + except (AttributeError, IndexError): + # it might be anything, for example a string reason = inst.reason ui.warn(_("abort: error: %s\n") % reason) elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
--- a/mercurial/encoding.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/encoding.py Sun May 01 06:04:08 2011 -0500 @@ -148,3 +148,17 @@ return sum([w(c) in wide and 2 or 1 for c in d]) return len(d) +def lower(s): + "best-effort encoding-aware case-folding of local string s" + try: + if isinstance(s, localstr): + u = s._utf8.decode("utf-8") + else: + u = s.decode(encoding, encodingmode) + + lu = u.lower() + if u == lu: + return s # preserve localstring + return lu.encode(encoding) + except UnicodeError: + return s.lower() # we don't know how to fold this except in ASCII
--- a/mercurial/extensions.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/extensions.py Sun May 01 06:04:08 2011 -0500 @@ -11,7 +11,7 @@ _extensions = {} _order = [] -_ignore = ['hbisect', 'bookmarks'] +_ignore = ['hbisect', 'bookmarks', 'parentrevspec'] def extensions(): for name in _order:
--- a/mercurial/filelog.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/filelog.py Sun May 01 06:04:08 2011 -0500 @@ -6,17 +6,28 @@ # GNU General Public License version 2 or any later version. import revlog +import re +_mdre = re.compile('\1\n') def _parsemeta(text): - if not text.startswith('\1\n'): - return {} - s = text.index('\1\n', 2) - mt = text[2:s] - m = {} - for l in mt.splitlines(): + """return (metadatadict, keylist, metadatasize)""" + # text can be buffer, so we can't use .startswith or .index + if text[:2] != '\1\n': + return None, None, None + s = _mdre.search(text, 2).start() + mtext = text[2:s] + meta = {} + keys = [] + for l in mtext.splitlines(): k, v = l.split(": ", 1) - m[k] = v - return m + meta[k] = v + keys.append(k) + return meta, keys, (s + 2) + +def _packmeta(meta, keys=None): + if not keys: + keys = sorted(meta.iterkeys()) + return "".join("%s: %s\n" % (k, meta[k]) for k in keys) class filelog(revlog.revlog): def __init__(self, opener, path): @@ -32,15 +43,14 @@ def add(self, text, meta, transaction, link, p1=None, p2=None): if meta or text.startswith('\1\n'): - mt = ["%s: %s\n" % (k, v) for k, v in sorted(meta.iteritems())] - text = "\1\n%s\1\n%s" % ("".join(mt), text) + text = "\1\n%s\1\n%s" % (_packmeta(meta), text) return self.addrevision(text, transaction, link, p1, p2) def renamed(self, node): if self.parents(node)[0] != revlog.nullid: return False t = self.revision(node) - m = _parsemeta(t) + m = _parsemeta(t)[0] if m and "copy" in m: return (m["copy"], revlog.bin(m["copyrev"])) return False
--- a/mercurial/graphmod.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/graphmod.py Sun May 01 06:04:08 2011 -0500 @@ -18,7 +18,6 @@ """ from mercurial.node import nullrev -from mercurial.cmdutil import revrange CHANGESET = 'C' @@ -31,39 +30,29 @@ returned. """ if not revs: - return [] - - ns = [repo[r].node() for r in revs] - revdag = list(nodes(repo, ns)) + return cl = repo.changelog lowestrev = min(revs) gpcache = {} - leafs = {} - for i, (id, c, ctx, parents) in enumerate(revdag): + knownrevs = set(revs) + for rev in revs: + ctx = repo[rev] + parents = sorted(set([p.rev() for p in ctx.parents() + if p.rev() in knownrevs])) mpars = [p.rev() for p in ctx.parents() if p.rev() != nullrev and p.rev() not in parents] - grandparents = [] for mpar in mpars: gp = gpcache.get(mpar) or grandparent(cl, lowestrev, revs, mpar) gpcache[mpar] = gp if gp is None: - leafs.setdefault(mpar, []).append((i, ctx)) - else: - grandparents.append(gp) + parents.append(mpar) + elif gp not in parents: + parents.append(gp) - if grandparents: - for gp in grandparents: - if gp not in revdag[i][3]: - revdag[i][3].append(gp) - - for parent, leafs in leafs.iteritems(): - for i, ctx in leafs: - revdag[i][3].append(parent) - - return revdag + yield (ctx.rev(), CHANGESET, ctx, parents) def nodes(repo, nodes): """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
--- a/mercurial/help/revsets.txt Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/help/revsets.txt Sun May 01 06:04:08 2011 -0500 @@ -42,11 +42,45 @@ ``x - y`` Changesets in x but not in y. + +``x^n`` + The nth parent of x, n == 0, 1, or 2. + For n == 0, x; for n == 1, the first parent of each changeset in x; + for n == 2, the second parent of changeset in x. + +``x~n`` + The nth first ancestor of x; ``x~0`` is x; ``x~3`` is ``x^^^``. + +There is a single postfix operator: + +``x^`` + Equivalent to ``x^1``, the first parent of each changeset in x. + The following predicates are supported: .. predicatesmarker +New predicates (known as "aliases") can be defined, using any combination of +existing predicates or other aliases. An alias definition looks like:: + + <alias> = <definition> + +in the ``revsetalias`` section of ``.hgrc``. Arguments of the form `$1`, `$2`, +etc. are substituted from the alias into the definition. + +For example, + +:: + + [revsetalias] + h = heads() + d($1) = sort($1, date) + rs($1, $2) = reverse(sort($1, $2)) + +defines three aliases, ``h``, ``d``, and ``rs``. ``rs(0:tip, author)`` is +exactly equivalent to ``reverse(sort(0:tip, author))``. + Command line equivalents for :hg:`log`:: -f -> ::.
--- a/mercurial/hg.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/hg.py Sun May 01 06:04:08 2011 -0500 @@ -8,16 +8,16 @@ from i18n import _ from lock import release -from node import hex, nullid, nullrev, short +from node import hex, nullid import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo, bookmarks -import lock, util, extensions, error, encoding, node -import cmdutil, discovery, url +import lock, util, extensions, error, node +import cmdutil, discovery import merge as mergemod import verify as verifymod import errno, os, shutil def _local(path): - path = util.expandpath(url.localpath(path)) + path = util.expandpath(util.localpath(path)) return (os.path.isfile(path) and bundlerepo or localrepo) def addbranchrevs(lrepo, repo, branches, revs): @@ -54,7 +54,7 @@ def parseurl(path, branches=None): '''parse url#branch, returning (url, (branch, branches))''' - u = url.url(path) + u = util.url(path) branch = None if u.fragment: branch = u.fragment @@ -71,7 +71,7 @@ } def _lookup(path): - u = url.url(path) + u = util.url(path) scheme = u.scheme or 'file' thing = schemes.get(scheme) or schemes['file'] try: @@ -221,8 +221,8 @@ else: dest = ui.expandpath(dest) - dest = url.localpath(dest) - source = url.localpath(source) + dest = util.localpath(dest) + source = util.localpath(source) if os.path.exists(dest): if not os.path.isdir(dest): @@ -248,7 +248,7 @@ abspath = origsource copy = False if src_repo.cancopy() and islocal(dest): - abspath = os.path.abspath(url.localpath(origsource)) + abspath = os.path.abspath(util.localpath(origsource)) copy = not pull and not rev if copy: @@ -421,24 +421,19 @@ """ source, branches = parseurl(ui.expandpath(source), opts.get('branch')) other = repository(remoteui(repo, opts), source) - ui.status(_('comparing with %s\n') % url.hidepassword(source)) + ui.status(_('comparing with %s\n') % util.hidepassword(source)) revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev')) if revs: revs = [other.lookup(rev) for rev in revs] - usecommon = other.capable('getbundle') - other, common, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other, - revs, opts["bundle"], opts["force"], - usecommon=usecommon) - if not incoming: + other, common, anyinc, bundle = bundlerepo.getremotechanges(ui, repo, other, + revs, opts["bundle"], opts["force"]) + if not anyinc: ui.status(_("no changes found\n")) return subreporecurse() try: - if usecommon: - chlist = other.changelog.findmissing(common, revs) - else: - chlist = other.changelog.nodesbetween(incoming, revs)[0] + chlist = other.changelog.findmissing(common, revs) displayer = cmdutil.show_changeset(ui, other, opts, buffered) # XXX once graphlog extension makes it into core, @@ -482,18 +477,19 @@ def _outgoing(ui, repo, dest, opts): dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = parseurl(dest, opts.get('branch')) - ui.status(_('comparing with %s\n') % url.hidepassword(dest)) + ui.status(_('comparing with %s\n') % util.hidepassword(dest)) revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev')) if revs: revs = [repo.lookup(rev) for rev in revs] other = repository(remoteui(repo, opts), dest) - o = discovery.findoutgoing(repo, other, force=opts.get('force')) + inc = discovery.findcommonincoming(repo, other, force=opts.get('force')) + common, _anyinc, _heads = inc + o = repo.changelog.findmissing(common, revs) if not o: ui.status(_("no changes found\n")) return None - - return repo.changelog.nodesbetween(o, revs)[0] + return o def outgoing(ui, repo, dest, opts): def recurse():
--- a/mercurial/hgweb/hgwebdir_mod.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/hgweb/hgwebdir_mod.py Sun May 01 06:04:08 2011 -0500 @@ -9,7 +9,7 @@ import os, re, time from mercurial.i18n import _ from mercurial import ui, hg, scmutil, util, templater -from mercurial import error, encoding, url +from mercurial import error, encoding from common import ErrorResponse, get_mtime, staticfile, paritygen, \ get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR from hgweb_mod import hgweb @@ -364,7 +364,7 @@ def updatereqenv(self, env): if self._baseurl is not None: - u = url.url(self._baseurl) + u = util.url(self._baseurl) env['SERVER_NAME'] = u.host if u.port: env['SERVER_PORT'] = u.port
--- a/mercurial/hgweb/protocol.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/hgweb/protocol.py Sun May 01 06:04:08 2011 -0500 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import cStringIO, zlib, sys, urllib +import cgi, cStringIO, zlib, sys, urllib from mercurial import util, wireproto from common import HTTP_OK @@ -16,18 +16,31 @@ self.req = req self.response = '' def getargs(self, args): + knownargs = self._args() data = {} keys = args.split() for k in keys: if k == '*': star = {} - for key in self.req.form.keys(): + for key in knownargs.keys(): if key != 'cmd' and key not in keys: - star[key] = self.req.form[key][0] + star[key] = knownargs[key][0] data['*'] = star else: - data[k] = self.req.form[k][0] + data[k] = knownargs[k][0] return [data[k] for k in keys] + def _args(self): + args = self.req.form.copy() + chunks = [] + i = 1 + while 1: + h = self.req.env.get('HTTP_X_HGARG_' + str(i)) + if h is None: + break + chunks += [h] + i += 1 + args.update(cgi.parse_qs(''.join(chunks), keep_blank_values=True)) + return args def getfile(self, fp): length = int(self.req.env['CONTENT_LENGTH']) for s in util.filechunkiter(self.req, limit=length):
--- a/mercurial/hgweb/server.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/hgweb/server.py Sun May 01 06:04:08 2011 -0500 @@ -59,6 +59,12 @@ def log_message(self, format, *args): self._log_any(self.server.accesslog, format, *args) + def log_request(self, code='-', size='-'): + xheaders = [h for h in self.headers.items() if h[0].startswith('x-')] + self.log_message('"%s" %s %s%s', + self.requestline, str(code), str(size), + ''.join([' %s:%s' % h for h in sorted(xheaders)])) + def do_write(self): try: self.do_hgweb()
--- a/mercurial/httprepo.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/httprepo.py Sun May 01 06:04:08 2011 -0500 @@ -28,7 +28,7 @@ self.path = path self.caps = None self.handler = None - u = url.url(path) + u = util.url(path) if u.query or u.fragment: raise util.Abort(_('unsupported URL component: "%s"') % (u.query or u.fragment)) @@ -76,7 +76,26 @@ data = args.pop('data', None) headers = args.pop('headers', {}) self.ui.debug("sending %s command\n" % cmd) - q = [('cmd', cmd)] + sorted(args.items()) + q = [('cmd', cmd)] + headersize = 0 + if len(args) > 0: + httpheader = self.capable('httpheader') + if httpheader: + headersize = int(httpheader.split(',')[0]) + if headersize > 0: + # The headers can typically carry more data than the URL. + encargs = urllib.urlencode(sorted(args.items())) + headerfmt = 'X-HgArg-%s' + contentlen = headersize - len(headerfmt % '000' + ': \r\n') + headernum = 0 + for i in xrange(0, len(encargs), contentlen): + headernum += 1 + header = headerfmt % str(headernum) + headers[header] = encargs[i:i + contentlen] + varyheaders = [headerfmt % str(h) for h in range(1, headernum + 1)] + headers['Vary'] = ','.join(varyheaders) + else: + q += sorted(args.items()) qs = '?%s' % urllib.urlencode(q) cu = "%s%s" % (self._url, qs) req = urllib2.Request(cu, data, headers) @@ -111,12 +130,12 @@ except AttributeError: proto = resp.headers['content-type'] - safeurl = url.hidepassword(self._url) + safeurl = util.hidepassword(self._url) # accept old "text/plain" and "application/hg-changegroup" for now if not (proto.startswith('application/mercurial-') or proto.startswith('text/plain') or proto.startswith('application/hg-changegroup')): - self.ui.debug("requested URL: '%s'\n" % url.hidepassword(cu)) + self.ui.debug("requested URL: '%s'\n" % util.hidepassword(cu)) raise error.RepoError( _("'%s' does not appear to be an hg repository:\n" "---%%<--- (%s)\n%s\n---%%<---\n") @@ -147,19 +166,18 @@ # have to stream bundle to a temp file because we do not have # http 1.1 chunked transfer. - type = "" types = self.capable('unbundle') - # servers older than d1b16a746db6 will send 'unbundle' as a - # boolean capability try: types = types.split(',') except AttributeError: + # servers older than d1b16a746db6 will send 'unbundle' as a + # boolean capability. They only support headerless/uncompressed + # bundles. types = [""] - if types: - for x in types: - if x in changegroup.bundletypes: - type = x - break + for x in types: + if x in changegroup.bundletypes: + type = x + break tempname = changegroup.writebundle(cg, None, type) fp = url.httpsendfile(self.ui, tempname, "rb")
--- a/mercurial/localrepo.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/localrepo.py Sun May 01 06:04:08 2011 -0500 @@ -14,7 +14,6 @@ import match as matchmod import merge as mergemod import tags as tagsmod -import url as urlmod from lock import release import weakref, errno, os, time, inspect propertycache = util.propertycache @@ -190,7 +189,7 @@ warned = [0] def validate(node): try: - r = self.changelog.rev(node) + self.changelog.rev(node) return node except error.LookupError: if not warned[0]: @@ -1327,9 +1326,8 @@ def pull(self, remote, heads=None, force=False): lock = self.lock() try: - usecommon = remote.capable('getbundle') tmp = discovery.findcommonincoming(self, remote, heads=heads, - force=force, commononly=usecommon) + force=force) common, fetch, rheads = tmp if not fetch: self.ui.status(_("no changes found\n")) @@ -1341,7 +1339,7 @@ # issue1320, avoid a race if remote changed after discovery heads = rheads - if usecommon: + if remote.capable('getbundle'): cg = remote.getbundle('pull', common=common, heads=heads or rheads) elif heads is None: @@ -1475,6 +1473,8 @@ if not heads: heads = cl.heads() common, missing = cl.findcommonmissing(common, heads) + if not missing: + return None return self._changegroupsubset(common, missing, heads, source) def _changegroupsubset(self, commonrevs, csets, heads, source): @@ -1694,7 +1694,7 @@ cl.delayupdate() oldheads = cl.heads() - tr = self.transaction("\n".join([srctype, urlmod.hidepassword(url)])) + tr = self.transaction("\n".join([srctype, util.hidepassword(url)])) try: trp = weakref.proxy(tr) # pull off the changeset group @@ -1918,10 +1918,18 @@ return self.pull(remote, heads) def pushkey(self, namespace, key, old, new): - return pushkey.push(self, namespace, key, old, new) + self.hook('prepushkey', throw=True, namespace=namespace, key=key, + old=old, new=new) + ret = pushkey.push(self, namespace, key, old, new) + self.hook('pushkey', namespace=namespace, key=key, old=old, new=new, + ret=ret) + return ret def listkeys(self, namespace): - return pushkey.list(self, namespace) + self.hook('prelistkeys', throw=True, namespace=namespace) + values = pushkey.list(self, namespace) + self.hook('listkeys', namespace=namespace, values=values) + return values def debugwireargs(self, one, two, three=None, four=None, five=None): '''used to test argument passing over the wire''' @@ -1936,7 +1944,7 @@ return a def instance(ui, path, create): - return localrepository(ui, urlmod.localpath(path), create) + return localrepository(ui, util.localpath(path), create) def islocal(path): return True
--- a/mercurial/merge.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/merge.py Sun May 01 06:04:08 2011 -0500 @@ -271,7 +271,6 @@ ms.reset(wctx.p1().node()) moves = [] action.sort(key=actionkey) - substate = wctx.substate # prime # prescan for merges u = repo.ui
--- a/mercurial/pure/bdiff.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/pure/bdiff.py Sun May 01 06:04:08 2011 -0500 @@ -19,6 +19,7 @@ def _normalizeblocks(a, b, blocks): prev = None + r = [] for curr in blocks: if prev is None: prev = curr @@ -40,9 +41,10 @@ while (b1end + shift < b2end and a[a1end + shift] == b[b1end + shift]): shift += 1 - yield a1, b1, l1 + shift + r.append((a1, b1, l1 + shift)) prev = a2 + shift, b2 + shift, l2 - shift - yield prev + r.append(prev) + return r def bdiff(a, b): a = str(a).splitlines(True)
--- a/mercurial/pure/mpatch.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/pure/mpatch.py Sun May 01 06:04:08 2011 -0500 @@ -56,9 +56,9 @@ def pull(dst, src, l): # pull l bytes from src while l: - f = src.pop(0) + f = src.pop() if f[0] > l: # do we need to split? - src.insert(0, (f[0] - l, f[1] + l)) + src.append((f[0] - l, f[1] + l)) dst.append((l, f[1])) return dst.append(f) @@ -66,7 +66,7 @@ def collect(buf, list): start = buf - for l, p in list: + for l, p in reversed(list): move(buf, p, l) buf += l return (buf - start, start) @@ -88,7 +88,7 @@ new.append((l, pos + 12)) # what got added pos += l + 12 last = p2 - frags = new + frags # what was left at the end + frags.extend(reversed(new)) # what was left at the end t = collect(b2, frags)
--- a/mercurial/pure/parsers.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/pure/parsers.py Sun May 01 06:04:08 2011 -0500 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -from mercurial.node import bin, nullid, nullrev +from mercurial.node import bin, nullid from mercurial import util import struct, zlib
--- a/mercurial/repair.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/repair.py Sun May 01 06:04:08 2011 -0500 @@ -6,9 +6,9 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import changegroup, bookmarks -from node import nullrev, short -from i18n import _ +from mercurial import changegroup, bookmarks +from mercurial.node import short +from mercurial.i18n import _ import os def _bundle(repo, bases, heads, node, suffix, compress=True):
--- a/mercurial/revlog.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/revlog.py Sun May 01 06:04:08 2011 -0500 @@ -14,7 +14,7 @@ # import stuff from node for others to import from revlog from node import bin, hex, nullid, nullrev, short #@UnusedImport from i18n import _ -import changegroup, ancestor, mdiff, parsers, error, util +import ancestor, mdiff, parsers, error, util import struct, zlib, errno _pack = struct.pack @@ -288,7 +288,7 @@ @util.propertycache def nodemap(self): - n = self.rev(self.node(0)) + self.rev(self.node(0)) return self._nodecache def rev(self, node): @@ -822,6 +822,9 @@ def _chunk(self, rev): return decompress(self._chunkraw(rev, rev)) + def _chunkbase(self, rev): + return self._chunk(rev) + def _chunkclear(self): self._chunkcache = (0, '') @@ -884,7 +887,7 @@ self._chunkraw(base, rev) if text is None: - text = self._chunk(base) + text = self._chunkbase(base) bins = [self._chunk(r) for r in chain] text = mdiff.patches(text, bins)
--- a/mercurial/revset.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/revset.py Sun May 01 06:04:08 2011 -0500 @@ -13,6 +13,8 @@ elements = { "(": (20, ("group", 1, ")"), ("func", 1, ")")), + "~": (18, None, ("ancestor", 18)), + "^": (18, None, ("parent", 18), ("parentpost", 18)), "-": (5, ("negate", 19), ("minus", 5)), "::": (17, ("dagrangepre", 17), ("dagrange", 17), ("dagrangepost", 17)), @@ -47,7 +49,7 @@ elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully yield ('..', None, pos) pos += 1 # skip ahead - elif c in "():,-|&+!": # handle simple operators + elif c in "():,-|&+!~^": # handle simple operators yield (c, None, pos) elif (c in '"\'' or c == 'r' and program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings @@ -209,6 +211,22 @@ s = set(repo.changelog.ancestors(*args)) | set(args) return [r for r in subset if r in s] +def ancestorspec(repo, subset, x, n): + """``set~n`` + Changesets that are the Nth ancestor (first parents only) of a changeset in set. + """ + try: + n = int(n[1]) + except ValueError: + raise error.ParseError(_("~ expects a number")) + ps = set() + cl = repo.changelog + for r in getset(repo, subset, x): + for i in range(n): + r = cl.parentrevs(r)[0] + ps.add(r) + return [r for r in subset if r in ps] + def author(repo, subset, x): """``author(string)`` Alias for ``user(string)``. @@ -452,6 +470,20 @@ raise error.ParseError(_("limit expects a number")) return getset(repo, subset, l[0])[:lim] +def last(repo, subset, x): + """``last(set, n)`` + Last n members of set. + """ + # i18n: "last" is a keyword + l = getargs(x, 2, 2, _("last requires two arguments")) + try: + # i18n: "last" is a keyword + lim = int(getstring(l[1], _("last requires a number"))) + except ValueError: + # i18n: "last" is a keyword + raise error.ParseError(_("last expects a number")) + return getset(repo, subset, l[0])[-lim:] + def maxrev(repo, subset, x): """``max(set)`` Changeset with highest revision number in set. @@ -522,10 +554,10 @@ revs = [repo.lookup(rev) for rev in revs] other = hg.repository(hg.remoteui(repo, {}), dest) repo.ui.pushbuffer() - o = discovery.findoutgoing(repo, other) + common, _anyinc, _heads = discovery.findcommonincoming(repo, other) repo.ui.popbuffer() cl = repo.changelog - o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]]) + o = set([cl.rev(r) for r in repo.changelog.findmissing(common, revs)]) return [r for r in subset if r in o] def p1(repo, subset, x): @@ -574,6 +606,31 @@ ps.update(cl.parentrevs(r)) return [r for r in subset if r in ps] +def parentspec(repo, subset, x, n): + """``set^0`` + The set. + ``set^1`` (or ``set^``), ``set^2`` + First or second parent, respectively, of all changesets in set. + """ + try: + n = int(n[1]) + if n not in (0, 1, 2): + raise ValueError + except ValueError: + raise error.ParseError(_("^ expects a number 0, 1, or 2")) + ps = set() + cl = repo.changelog + for r in getset(repo, subset, x): + if n == 0: + ps.add(r) + elif n == 1: + ps.add(cl.parentrevs(r)[0]) + elif n == 2: + parents = cl.parentrevs(r) + if len(parents) > 1: + ps.add(parents[1]) + return [r for r in subset if r in ps] + def present(repo, subset, x): """``present(set)`` An empty set, if any revision in set isn't found; otherwise, @@ -724,6 +781,7 @@ "head": head, "heads": heads, "keyword": keyword, + "last": last, "limit": limit, "max": maxrev, "min": minrev, @@ -754,6 +812,9 @@ "not": notset, "list": listset, "func": func, + "ancestor": ancestorspec, + "parent": parentspec, + "parentpost": p1, } def optimize(x, small): @@ -799,9 +860,12 @@ elif op == 'not': o = optimize(x[1], not small) return o[0], (op, o[1]) + elif op == 'parentpost': + o = optimize(x[1], small) + return o[0], (op, o[1]) elif op == 'group': return optimize(x[1], small) - elif op in 'range list': + elif op in 'range list parent ancestorspec': wa, ta = optimize(x[1], small) wb, tb = optimize(x[2], small) return wa + wb, (op, ta, tb) @@ -825,14 +889,89 @@ return w + wa, (op, x[1], ta) return 1, x +class revsetalias(object): + funcre = re.compile('^([^(]+)\(([^)]+)\)$') + args = () + + def __init__(self, token, value): + '''Aliases like: + + h = heads(default) + b($1) = ancestors($1) - ancestors(default) + ''' + if isinstance(token, tuple): + self.type, self.name = token + else: + m = self.funcre.search(token) + if m: + self.type = 'func' + self.name = m.group(1) + self.args = [x.strip() for x in m.group(2).split(',')] + else: + self.type = 'symbol' + self.name = token + + if isinstance(value, str): + for arg in self.args: + value = value.replace(arg, repr(arg)) + self.replacement, pos = parse(value) + if pos != len(value): + raise error.ParseError('invalid token', pos) + else: + self.replacement = value + + def match(self, tree): + if not tree: + return False + if tree == (self.type, self.name): + return True + if tree[0] != self.type: + return False + if len(tree) > 1 and tree[1] != ('symbol', self.name): + return False + # 'func' + funcname + args + if ((self.args and len(tree) != 3) or + (len(self.args) == 1 and tree[2][0] == 'list') or + (len(self.args) > 1 and (tree[2][0] != 'list' or + len(tree[2]) - 1 != len(self.args)))): + raise error.ParseError('invalid amount of arguments', len(tree) - 2) + return True + + def replace(self, tree): + if tree == (self.type, self.name): + return self.replacement + result = self.replacement + def getsubtree(i): + if tree[2][0] == 'list': + return tree[2][i + 1] + return tree[i + 2] + for i, v in enumerate(self.args): + valalias = revsetalias(('string', v), getsubtree(i)) + result = valalias.process(result) + return result + + def process(self, tree): + if self.match(tree): + return self.replace(tree) + if isinstance(tree, tuple): + return tuple(map(self.process, tree)) + return tree + +def findaliases(ui, tree): + for k, v in ui.configitems('revsetalias'): + alias = revsetalias(k, v) + tree = alias.process(tree) + return tree + parse = parser.parser(tokenize, elements).parse -def match(spec): +def match(ui, spec): if not spec: raise error.ParseError(_("empty query")) tree, pos = parse(spec) if (pos != len(spec)): raise error.ParseError("invalid token", pos) + tree = findaliases(ui, tree) weight, tree = optimize(tree, True) def mfunc(repo, subset): return getset(repo, subset, tree)
--- a/mercurial/scmutil.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/scmutil.py Sun May 01 06:04:08 2011 -0500 @@ -17,19 +17,42 @@ def checkportable(ui, f): '''Check if filename f is portable and warn or abort depending on config''' checkfilename(f) - val = ui.config('ui', 'portablefilenames', 'warn') - lval = val.lower() - abort = os.name == 'nt' or lval == 'abort' - bval = util.parsebool(val) - if abort or lval == 'warn' or bval: + if showportabilityalert(ui): msg = util.checkwinfilename(f) if msg: - if abort: - raise util.Abort("%s: %r" % (msg, f)) - ui.warn(_("warning: %s: %r\n") % (msg, f)) - elif bval is None and lval != 'ignore': + portabilityalert(ui, "%s: %r" % (msg, f)) + +def checkcasecollision(ui, f, files): + if f.lower() in files and files[f.lower()] != f: + portabilityalert(ui, _('possible case-folding collision for %s') % f) + files[f.lower()] = f + +def checkportabilityalert(ui): + '''check if the user's config requests nothing, a warning, or abort for + non-portable filenames''' + val = ui.config('ui', 'portablefilenames', 'warn') + lval = val.lower() + bval = util.parsebool(val) + abort = os.name == 'nt' or lval == 'abort' + warn = bval or lval == 'warn' + if bval is None and not (warn or abort or lval == 'ignore'): raise error.ConfigError( _("ui.portablefilenames value is invalid ('%s')") % val) + return abort, warn + +def showportabilityalert(ui): + '''check if the user wants any notification of portability problems''' + abort, warn = checkportabilityalert(ui) + return abort or warn + +def portabilityalert(ui, msg): + if not msg: + return + abort, warn = checkportabilityalert(ui) + if abort: + raise util.Abort("%s" % msg) + elif warn: + ui.warn(_("warning: %s\n") % msg) class path_auditor(object): '''ensure that a filesystem path contains no banned components. @@ -106,7 +129,28 @@ # want to add "foo/bar/baz" before checking if there's a "foo/.hg" self.auditeddir.update(prefixes) -class opener(object): +class abstractopener(object): + """Abstract base class; cannot be instantiated""" + + def __init__(self, *args, **kwargs): + '''Prevent instantiation; don't call this from subclasses.''' + raise NotImplementedError('attempted instantiating ' + str(type(self))) + + def read(self, *args, **kwargs): + fp = self(*args, **kwargs) + try: + return fp.read() + finally: + fp.close() + + def write(self, data, *args, **kwargs): + fp = self(*args, **kwargs) + try: + return fp.write(data) + finally: + fp.close() + +class opener(abstractopener): '''Open files relative to a base directory This class is used to hide the details of COW semantics and @@ -201,6 +245,16 @@ f.close() self._fixfilemode(dst) +class filteropener(abstractopener): + '''Wrapper opener for filtering filenames with a function.''' + + def __init__(self, opener, filter): + self._filter = filter + self._orig = opener + + def __call__(self, path, *args, **kwargs): + return self._orig(self._filter(path), *args, **kwargs) + def canonpath(root, cwd, myname, auditor=None): '''return the canonical path of myname, given cwd and root''' if util.endswithsep(root):
--- a/mercurial/sshrepo.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/sshrepo.py Sun May 01 06:04:08 2011 -0500 @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. from i18n import _ -import util, error, wireproto, url +import util, error, wireproto class remotelock(object): def __init__(self, repo): @@ -23,7 +23,7 @@ self._url = path self.ui = ui - u = url.url(path, parsequery=False, parsefragment=False) + u = util.url(path, parsequery=False, parsefragment=False) if u.scheme != 'ssh' or not u.host or u.path is None: self._abort(error.RepoError(_("couldn't parse location %s") % path))
--- a/mercurial/statichttprepo.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/statichttprepo.py Sun May 01 06:04:08 2011 -0500 @@ -9,7 +9,7 @@ from i18n import _ import changelog, byterange, url, error -import localrepo, manifest, util, store +import localrepo, manifest, util, scmutil, store import urllib, urllib2, errno class httprangereader(object): @@ -67,17 +67,17 @@ urlopener = url.opener(ui, authinfo) urlopener.add_handler(byterange.HTTPRangeHandler()) - def opener(base): - """return a function that opens files over http""" - p = base - def o(path, mode="r", atomictemp=None): + class statichttpopener(scmutil.abstractopener): + def __init__(self, base): + self.base = base + + def __call__(self, path, mode="r", atomictemp=None): if mode not in ('r', 'rb'): raise IOError('Permission denied') - f = "/".join((p, urllib.quote(path))) + f = "/".join((self.base, urllib.quote(path))) return httprangereader(f, urlopener) - return o - return opener + return statichttpopener class statichttprepository(localrepo.localrepository): def __init__(self, ui, path): @@ -85,7 +85,7 @@ self.ui = ui self.root = path - u = url.url(path.rstrip('/') + "/.hg") + u = util.url(path.rstrip('/') + "/.hg") self.path, authinfo = u.authinfo() opener = build_opener(ui, authinfo)
--- a/mercurial/store.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/store.py Sun May 01 06:04:08 2011 -0500 @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. from i18n import _ -import osutil, util +import osutil, scmutil, util import os, stat _sha = util.sha1 @@ -236,12 +236,12 @@ class basicstore(object): '''base class for local repository stores''' - def __init__(self, path, opener): + def __init__(self, path, openertype): self.path = path self.createmode = _calcmode(path) - op = opener(self.path) + op = openertype(self.path) op.createmode = self.createmode - self.opener = lambda f, *args, **kw: op(encodedir(f), *args, **kw) + self.opener = scmutil.filteropener(op, encodedir) def join(self, f): return self.path + '/' + encodedir(f) @@ -285,12 +285,12 @@ pass class encodedstore(basicstore): - def __init__(self, path, opener): + def __init__(self, path, openertype): self.path = path + '/store' self.createmode = _calcmode(self.path) - op = opener(self.path) + op = openertype(self.path) op.createmode = self.createmode - self.opener = lambda f, *args, **kw: op(encodefilename(f), *args, **kw) + self.opener = scmutil.filteropener(op, encodefilename) def datafiles(self): for a, b, size in self._walk('data', True): @@ -366,11 +366,11 @@ return iter(self.entries) class fncachestore(basicstore): - def __init__(self, path, opener, encode): + def __init__(self, path, openertype, encode): self.encode = encode self.path = path + '/store' self.createmode = _calcmode(self.path) - op = opener(self.path) + op = openertype(self.path) op.createmode = self.createmode fnc = fncache(op) self.fncache = fnc @@ -411,11 +411,11 @@ def write(self): self.fncache.write() -def store(requirements, path, opener): +def store(requirements, path, openertype): if 'store' in requirements: if 'fncache' in requirements: auxencode = lambda f: _auxencode(f, 'dotencode' in requirements) encode = lambda f: _hybridencode(f, auxencode) - return fncachestore(path, opener, encode) - return encodedstore(path, opener) - return basicstore(path, opener) + return fncachestore(path, openertype, encode) + return encodedstore(path, openertype) + return basicstore(path, openertype)
--- a/mercurial/subrepo.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/subrepo.py Sun May 01 06:04:08 2011 -0500 @@ -8,7 +8,7 @@ import errno, os, re, xml.dom.minidom, shutil, posixpath import stat, subprocess, tarfile from i18n import _ -import config, scmutil, util, node, error, cmdutil, url, bookmarks +import config, scmutil, util, node, error, cmdutil, bookmarks hg = None propertycache = util.propertycache @@ -194,13 +194,13 @@ """return pull/push path of repo - either based on parent repo .hgsub info or on the top repo config. Abort or return None if no source found.""" if hasattr(repo, '_subparent'): - source = url.url(repo._subsource) + source = util.url(repo._subsource) source.path = posixpath.normpath(source.path) if posixpath.isabs(source.path) or source.scheme: return str(source) parent = _abssource(repo._subparent, push, abort=False) if parent: - parent = url.url(parent) + parent = util.url(parent) parent.path = posixpath.join(parent.path, source.path) parent.path = posixpath.normpath(parent.path) return str(parent)
--- a/mercurial/templatekw.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/templatekw.py Sun May 01 06:04:08 2011 -0500 @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. from node import hex -import encoding, patch, util, error, help +import patch, util, error, help def showlist(name, values, plural=None, **args): '''expand set of values.
--- a/mercurial/ui.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/ui.py Sun May 01 06:04:08 2011 -0500 @@ -7,7 +7,7 @@ from i18n import _ import errno, getpass, os, socket, sys, tempfile, traceback -import config, scmutil, util, error, url +import config, scmutil, util, error class ui(object): def __init__(self, src=None): @@ -111,7 +111,7 @@ % (n, p, self.configsource('paths', n))) p = p.replace('%%', '%') p = util.expandpath(p) - if not url.hasscheme(p) and not os.path.isabs(p): + if not util.hasscheme(p) and not os.path.isabs(p): p = os.path.normpath(os.path.join(root, p)) c.set("paths", n, p) @@ -332,7 +332,7 @@ def expandpath(self, loc, default=None): """Return repository location relative to cwd or from [paths]""" - if url.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')): + if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')): return loc path = self.config('paths', loc)
--- a/mercurial/url.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/url.py Sun May 01 06:04:08 2011 -0500 @@ -7,309 +7,11 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import urllib, urllib2, httplib, os, socket, cStringIO, re +import urllib, urllib2, httplib, os, socket, cStringIO import __builtin__ from i18n import _ import keepalive, util -class url(object): - """Reliable URL parser. - - This parses URLs and provides attributes for the following - components: - - <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment> - - Missing components are set to None. The only exception is - fragment, which is set to '' if present but empty. - - If parsefragment is False, fragment is included in query. If - parsequery is False, query is included in path. If both are - False, both fragment and query are included in path. - - See http://www.ietf.org/rfc/rfc2396.txt for more information. - - Note that for backward compatibility reasons, bundle URLs do not - take host names. That means 'bundle://../' has a path of '../'. - - Examples: - - >>> url('http://www.ietf.org/rfc/rfc2396.txt') - <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'> - >>> url('ssh://[::1]:2200//home/joe/repo') - <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'> - >>> url('file:///home/joe/repo') - <url scheme: 'file', path: '/home/joe/repo'> - >>> url('bundle:foo') - <url scheme: 'bundle', path: 'foo'> - >>> url('bundle://../foo') - <url scheme: 'bundle', path: '../foo'> - >>> url('c:\\\\foo\\\\bar') - <url path: 'c:\\\\foo\\\\bar'> - - Authentication credentials: - - >>> url('ssh://joe:xyz@x/repo') - <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'> - >>> url('ssh://joe@x/repo') - <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'> - - Query strings and fragments: - - >>> url('http://host/a?b#c') - <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'> - >>> url('http://host/a?b#c', parsequery=False, parsefragment=False) - <url scheme: 'http', host: 'host', path: 'a?b#c'> - """ - - _safechars = "!~*'()+" - _safepchars = "/!~*'()+" - _matchscheme = re.compile(r'^[a-zA-Z0-9+.\-]+:').match - - def __init__(self, path, parsequery=True, parsefragment=True): - # We slowly chomp away at path until we have only the path left - self.scheme = self.user = self.passwd = self.host = None - self.port = self.path = self.query = self.fragment = None - self._localpath = True - self._hostport = '' - self._origpath = path - - # special case for Windows drive letters - if hasdriveletter(path): - self.path = path - return - - # For compatibility reasons, we can't handle bundle paths as - # normal URLS - if path.startswith('bundle:'): - self.scheme = 'bundle' - path = path[7:] - if path.startswith('//'): - path = path[2:] - self.path = path - return - - if self._matchscheme(path): - parts = path.split(':', 1) - if parts[0]: - self.scheme, path = parts - self._localpath = False - - if not path: - path = None - if self._localpath: - self.path = '' - return - else: - if parsefragment and '#' in path: - path, self.fragment = path.split('#', 1) - if not path: - path = None - if self._localpath: - self.path = path - return - - if parsequery and '?' in path: - path, self.query = path.split('?', 1) - if not path: - path = None - if not self.query: - self.query = None - - # // is required to specify a host/authority - if path and path.startswith('//'): - parts = path[2:].split('/', 1) - if len(parts) > 1: - self.host, path = parts - path = path - else: - self.host = parts[0] - path = None - if not self.host: - self.host = None - if path: - path = '/' + path - - if self.host and '@' in self.host: - self.user, self.host = self.host.rsplit('@', 1) - if ':' in self.user: - self.user, self.passwd = self.user.split(':', 1) - if not self.host: - self.host = None - - # Don't split on colons in IPv6 addresses without ports - if (self.host and ':' in self.host and - not (self.host.startswith('[') and self.host.endswith(']'))): - self._hostport = self.host - self.host, self.port = self.host.rsplit(':', 1) - if not self.host: - self.host = None - - if (self.host and self.scheme == 'file' and - self.host not in ('localhost', '127.0.0.1', '[::1]')): - raise util.Abort(_('file:// URLs can only refer to localhost')) - - self.path = path - - for a in ('user', 'passwd', 'host', 'port', - 'path', 'query', 'fragment'): - v = getattr(self, a) - if v is not None: - setattr(self, a, urllib.unquote(v)) - - def __repr__(self): - attrs = [] - for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path', - 'query', 'fragment'): - v = getattr(self, a) - if v is not None: - attrs.append('%s: %r' % (a, v)) - return '<url %s>' % ', '.join(attrs) - - def __str__(self): - """Join the URL's components back into a URL string. - - Examples: - - >>> str(url('http://user:pw@host:80/?foo#bar')) - 'http://user:pw@host:80/?foo#bar' - >>> str(url('ssh://user:pw@[::1]:2200//home/joe#')) - 'ssh://user:pw@[::1]:2200//home/joe#' - >>> str(url('http://localhost:80//')) - 'http://localhost:80//' - >>> str(url('http://localhost:80/')) - 'http://localhost:80/' - >>> str(url('http://localhost:80')) - 'http://localhost:80/' - >>> str(url('bundle:foo')) - 'bundle:foo' - >>> str(url('bundle://../foo')) - 'bundle:../foo' - >>> str(url('path')) - 'path' - """ - if self._localpath: - s = self.path - if self.scheme == 'bundle': - s = 'bundle:' + s - if self.fragment: - s += '#' + self.fragment - return s - - s = self.scheme + ':' - if (self.user or self.passwd or self.host or - self.scheme and not self.path): - s += '//' - if self.user: - s += urllib.quote(self.user, safe=self._safechars) - if self.passwd: - s += ':' + urllib.quote(self.passwd, safe=self._safechars) - if self.user or self.passwd: - s += '@' - if self.host: - if not (self.host.startswith('[') and self.host.endswith(']')): - s += urllib.quote(self.host) - else: - s += self.host - if self.port: - s += ':' + urllib.quote(self.port) - if self.host: - s += '/' - if self.path: - s += urllib.quote(self.path, safe=self._safepchars) - if self.query: - s += '?' + urllib.quote(self.query, safe=self._safepchars) - if self.fragment is not None: - s += '#' + urllib.quote(self.fragment, safe=self._safepchars) - return s - - def authinfo(self): - user, passwd = self.user, self.passwd - try: - self.user, self.passwd = None, None - s = str(self) - finally: - self.user, self.passwd = user, passwd - if not self.user: - return (s, None) - return (s, (None, (str(self), self.host), - self.user, self.passwd or '')) - - def localpath(self): - if self.scheme == 'file' or self.scheme == 'bundle': - path = self.path or '/' - # For Windows, we need to promote hosts containing drive - # letters to paths with drive letters. - if hasdriveletter(self._hostport): - path = self._hostport + '/' + self.path - elif self.host is not None and self.path: - path = '/' + path - # We also need to handle the case of file:///C:/, which - # should return C:/, not /C:/. - elif hasdriveletter(path): - # Strip leading slash from paths with drive names - return path[1:] - return path - return self._origpath - -def hasscheme(path): - return bool(url(path).scheme) - -def hasdriveletter(path): - return path[1:2] == ':' and path[0:1].isalpha() - -def localpath(path): - return url(path, parsequery=False, parsefragment=False).localpath() - -def hidepassword(u): - '''hide user credential in a url string''' - u = url(u) - if u.passwd: - u.passwd = '***' - return str(u) - -def removeauth(u): - '''remove all authentication information from a url string''' - u = url(u) - u.user = u.passwd = None - return str(u) - -def netlocsplit(netloc): - '''split [user[:passwd]@]host[:port] into 4-tuple.''' - - a = netloc.find('@') - if a == -1: - user, passwd = None, None - else: - userpass, netloc = netloc[:a], netloc[a + 1:] - c = userpass.find(':') - if c == -1: - user, passwd = urllib.unquote(userpass), None - else: - user = urllib.unquote(userpass[:c]) - passwd = urllib.unquote(userpass[c + 1:]) - c = netloc.find(':') - if c == -1: - host, port = netloc, None - else: - host, port = netloc[:c], netloc[c + 1:] - return host, port, user, passwd - -def netlocunsplit(host, port, user=None, passwd=None): - '''turn host, port, user, passwd into [user[:passwd]@]host[:port].''' - if port: - hostport = host + ':' + port - else: - hostport = host - if user: - quote = lambda s: urllib.quote(s, safe='') - if passwd: - userpass = quote(user) + ':' + quote(passwd) - else: - userpass = quote(user) - return userpass + '@' + hostport - return hostport - def readauthforuri(ui, uri): # Read configuration config = dict() @@ -342,44 +44,6 @@ bestauth = group, auth return bestauth -_safe = ('abcdefghijklmnopqrstuvwxyz' - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - '0123456789' '_.-/') -_safeset = None -_hex = None -def quotepath(path): - '''quote the path part of a URL - - This is similar to urllib.quote, but it also tries to avoid - quoting things twice (inspired by wget): - - >>> quotepath('abc def') - 'abc%20def' - >>> quotepath('abc%20def') - 'abc%20def' - >>> quotepath('abc%20 def') - 'abc%20%20def' - >>> quotepath('abc def%20') - 'abc%20def%20' - >>> quotepath('abc def%2') - 'abc%20def%252' - >>> quotepath('abc def%') - 'abc%20def%25' - ''' - global _safeset, _hex - if _safeset is None: - _safeset = set(_safe) - _hex = set('abcdefABCDEF0123456789') - l = list(path) - for i in xrange(len(l)): - c = l[i] - if (c == '%' and i + 2 < len(l) and - l[i + 1] in _hex and l[i + 2] in _hex): - pass - elif c not in _safeset: - l[i] = '%%%02X' % ord(c) - return ''.join(l) - class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm): def __init__(self, ui): urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self) @@ -431,7 +95,7 @@ if not (proxyurl.startswith('http:') or proxyurl.startswith('https:')): proxyurl = 'http://' + proxyurl + '/' - proxy = url(proxyurl) + proxy = util.url(proxyurl) if not proxy.user: proxy.user = ui.config("http_proxy", "user") proxy.passwd = ui.config("http_proxy", "passwd") @@ -619,7 +283,7 @@ new_tunnel = False if new_tunnel or tunnel_host == req.get_full_url(): # has proxy - u = url(tunnel_host) + u = util.url(tunnel_host) if new_tunnel or u.scheme == 'https': # only use CONNECT for HTTPS h.realhostport = ':'.join([u.host, (u.port or '443')]) h.headers = req.headers.copy() @@ -781,7 +445,7 @@ host = self.host if self.realhostport: # use CONNECT proxy - something = _generic_proxytunnel(self) + _generic_proxytunnel(self) host = self.realhostport.rsplit(':', 1)[0] cacerts = self.ui.config('web', 'cacerts') @@ -950,7 +614,7 @@ return opener def open(ui, url_, data=None): - u = url(url_) + u = util.url(url_) if u.scheme: u.scheme = u.scheme.lower() url_, authinfo = u.authinfo()
--- a/mercurial/util.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/util.py Sun May 01 06:04:08 2011 -0500 @@ -17,7 +17,7 @@ import error, osutil, encoding import errno, re, shutil, sys, tempfile, traceback import os, time, calendar, textwrap, unicodedata, signal -import imp, socket +import imp, socket, urllib # Python compatibility @@ -771,6 +771,20 @@ makedirs(parent, mode) makedirs(name, mode) +def readfile(path): + fp = open(path) + try: + return fp.read() + finally: + fp.close() + +def writefile(path, mode, text): + fp = open(path, mode) + try: + fp.write(text) + finally: + fp.close() + class chunkbuffer(object): """Allow arbitrary sized chunks of data to be efficiently read from an iterator over chunks of arbitrary size.""" @@ -933,7 +947,6 @@ # fill out defaults now = makedate() defaults = {} - nowmap = {} for part in ("d", "mb", "yY", "HI", "M", "S"): # this piece is for rounding the specific end of unknowns b = bias.get(part) @@ -1284,3 +1297,285 @@ If s is not a valid boolean, returns None. """ return _booleans.get(s.lower(), None) + +_hexdig = '0123456789ABCDEFabcdef' +_hextochr = dict((a + b, chr(int(a + b, 16))) + for a in _hexdig for b in _hexdig) + +def _urlunquote(s): + """unquote('abc%20def') -> 'abc def'.""" + res = s.split('%') + # fastpath + if len(res) == 1: + return s + s = res[0] + for item in res[1:]: + try: + s += _hextochr[item[:2]] + item[2:] + except KeyError: + s += '%' + item + except UnicodeDecodeError: + s += unichr(int(item[:2], 16)) + item[2:] + return s + +class url(object): + """Reliable URL parser. + + This parses URLs and provides attributes for the following + components: + + <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment> + + Missing components are set to None. The only exception is + fragment, which is set to '' if present but empty. + + If parsefragment is False, fragment is included in query. If + parsequery is False, query is included in path. If both are + False, both fragment and query are included in path. + + See http://www.ietf.org/rfc/rfc2396.txt for more information. + + Note that for backward compatibility reasons, bundle URLs do not + take host names. That means 'bundle://../' has a path of '../'. + + Examples: + + >>> url('http://www.ietf.org/rfc/rfc2396.txt') + <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'> + >>> url('ssh://[::1]:2200//home/joe/repo') + <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'> + >>> url('file:///home/joe/repo') + <url scheme: 'file', path: '/home/joe/repo'> + >>> url('bundle:foo') + <url scheme: 'bundle', path: 'foo'> + >>> url('bundle://../foo') + <url scheme: 'bundle', path: '../foo'> + >>> url('c:\\\\foo\\\\bar') + <url path: 'c:\\\\foo\\\\bar'> + + Authentication credentials: + + >>> url('ssh://joe:xyz@x/repo') + <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'> + >>> url('ssh://joe@x/repo') + <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'> + + Query strings and fragments: + + >>> url('http://host/a?b#c') + <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'> + >>> url('http://host/a?b#c', parsequery=False, parsefragment=False) + <url scheme: 'http', host: 'host', path: 'a?b#c'> + """ + + _safechars = "!~*'()+" + _safepchars = "/!~*'()+" + _matchscheme = re.compile(r'^[a-zA-Z0-9+.\-]+:').match + + def __init__(self, path, parsequery=True, parsefragment=True): + # We slowly chomp away at path until we have only the path left + self.scheme = self.user = self.passwd = self.host = None + self.port = self.path = self.query = self.fragment = None + self._localpath = True + self._hostport = '' + self._origpath = path + + # special case for Windows drive letters + if hasdriveletter(path): + self.path = path + return + + # For compatibility reasons, we can't handle bundle paths as + # normal URLS + if path.startswith('bundle:'): + self.scheme = 'bundle' + path = path[7:] + if path.startswith('//'): + path = path[2:] + self.path = path + return + + if self._matchscheme(path): + parts = path.split(':', 1) + if parts[0]: + self.scheme, path = parts + self._localpath = False + + if not path: + path = None + if self._localpath: + self.path = '' + return + else: + if parsefragment and '#' in path: + path, self.fragment = path.split('#', 1) + if not path: + path = None + if self._localpath: + self.path = path + return + + if parsequery and '?' in path: + path, self.query = path.split('?', 1) + if not path: + path = None + if not self.query: + self.query = None + + # // is required to specify a host/authority + if path and path.startswith('//'): + parts = path[2:].split('/', 1) + if len(parts) > 1: + self.host, path = parts + path = path + else: + self.host = parts[0] + path = None + if not self.host: + self.host = None + if path: + path = '/' + path + + if self.host and '@' in self.host: + self.user, self.host = self.host.rsplit('@', 1) + if ':' in self.user: + self.user, self.passwd = self.user.split(':', 1) + if not self.host: + self.host = None + + # Don't split on colons in IPv6 addresses without ports + if (self.host and ':' in self.host and + not (self.host.startswith('[') and self.host.endswith(']'))): + self._hostport = self.host + self.host, self.port = self.host.rsplit(':', 1) + if not self.host: + self.host = None + + if (self.host and self.scheme == 'file' and + self.host not in ('localhost', '127.0.0.1', '[::1]')): + raise Abort(_('file:// URLs can only refer to localhost')) + + self.path = path + + for a in ('user', 'passwd', 'host', 'port', + 'path', 'query', 'fragment'): + v = getattr(self, a) + if v is not None: + setattr(self, a, _urlunquote(v)) + + def __repr__(self): + attrs = [] + for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path', + 'query', 'fragment'): + v = getattr(self, a) + if v is not None: + attrs.append('%s: %r' % (a, v)) + return '<url %s>' % ', '.join(attrs) + + def __str__(self): + """Join the URL's components back into a URL string. + + Examples: + + >>> str(url('http://user:pw@host:80/?foo#bar')) + 'http://user:pw@host:80/?foo#bar' + >>> str(url('ssh://user:pw@[::1]:2200//home/joe#')) + 'ssh://user:pw@[::1]:2200//home/joe#' + >>> str(url('http://localhost:80//')) + 'http://localhost:80//' + >>> str(url('http://localhost:80/')) + 'http://localhost:80/' + >>> str(url('http://localhost:80')) + 'http://localhost:80/' + >>> str(url('bundle:foo')) + 'bundle:foo' + >>> str(url('bundle://../foo')) + 'bundle:../foo' + >>> str(url('path')) + 'path' + """ + if self._localpath: + s = self.path + if self.scheme == 'bundle': + s = 'bundle:' + s + if self.fragment: + s += '#' + self.fragment + return s + + s = self.scheme + ':' + if (self.user or self.passwd or self.host or + self.scheme and not self.path): + s += '//' + if self.user: + s += urllib.quote(self.user, safe=self._safechars) + if self.passwd: + s += ':' + urllib.quote(self.passwd, safe=self._safechars) + if self.user or self.passwd: + s += '@' + if self.host: + if not (self.host.startswith('[') and self.host.endswith(']')): + s += urllib.quote(self.host) + else: + s += self.host + if self.port: + s += ':' + urllib.quote(self.port) + if self.host: + s += '/' + if self.path: + s += urllib.quote(self.path, safe=self._safepchars) + if self.query: + s += '?' + urllib.quote(self.query, safe=self._safepchars) + if self.fragment is not None: + s += '#' + urllib.quote(self.fragment, safe=self._safepchars) + return s + + def authinfo(self): + user, passwd = self.user, self.passwd + try: + self.user, self.passwd = None, None + s = str(self) + finally: + self.user, self.passwd = user, passwd + if not self.user: + return (s, None) + return (s, (None, (str(self), self.host), + self.user, self.passwd or '')) + + def localpath(self): + if self.scheme == 'file' or self.scheme == 'bundle': + path = self.path or '/' + # For Windows, we need to promote hosts containing drive + # letters to paths with drive letters. + if hasdriveletter(self._hostport): + path = self._hostport + '/' + self.path + elif self.host is not None and self.path: + path = '/' + path + # We also need to handle the case of file:///C:/, which + # should return C:/, not /C:/. + elif hasdriveletter(path): + # Strip leading slash from paths with drive names + return path[1:] + return path + return self._origpath + +def hasscheme(path): + return bool(url(path).scheme) + +def hasdriveletter(path): + return path[1:2] == ':' and path[0:1].isalpha() + +def localpath(path): + return url(path, parsequery=False, parsefragment=False).localpath() + +def hidepassword(u): + '''hide user credential in a url string''' + u = url(u) + if u.passwd: + u.passwd = '***' + return str(u) + +def removeauth(u): + '''remove all authentication information from a url string''' + u = url(u) + u.user = u.passwd = None + return str(u)
--- a/mercurial/windows.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/windows.py Sun May 01 06:04:08 2011 -0500 @@ -6,8 +6,8 @@ # GNU General Public License version 2 or any later version. from i18n import _ -import osutil, error -import errno, msvcrt, os, re, sys, subprocess +import osutil +import errno, msvcrt, os, re, sys nulldev = 'NUL:' umask = 002
--- a/mercurial/wireproto.py Sun May 01 10:51:10 2011 +0200 +++ b/mercurial/wireproto.py Sun May 01 06:04:08 2011 -0500 @@ -233,6 +233,7 @@ else: caps.append('streamreqs=%s' % ','.join(requiredformats)) caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority)) + caps.append('httpheader=1024') return ' '.join(caps) def changegroup(repo, proto, roots): @@ -296,7 +297,7 @@ if len(new) == 20 and new.encode('string-escape') != new: # looks like it could be a binary node try: - u = new.decode('utf-8') + new.decode('utf-8') new = encoding.tolocal(new) # but cleanly decodes as UTF-8 except UnicodeDecodeError: pass # binary, leave unmodified
--- a/tests/run-tests.py Sun May 01 10:51:10 2011 +0200 +++ b/tests/run-tests.py Sun May 01 06:04:08 2011 -0500 @@ -303,6 +303,7 @@ return missing, failed def showdiff(expected, output, ref, err): + print for line in difflib.unified_diff(expected, output, ref, err): sys.stdout.write(line)
--- a/tests/test-acl.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-acl.t Sun May 01 06:04:08 2011 -0500 @@ -83,7 +83,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -137,7 +136,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 invalidating branch cache (tip differs) 3 changesets found list of changesets: @@ -195,7 +193,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 invalidating branch cache (tip differs) 3 changesets found list of changesets: @@ -262,7 +259,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 invalidating branch cache (tip differs) 3 changesets found list of changesets: @@ -327,7 +323,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -396,7 +391,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -462,7 +456,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -533,7 +526,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -601,7 +593,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -671,7 +662,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -744,7 +734,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 invalidating branch cache (tip differs) 3 changesets found list of changesets: @@ -822,7 +811,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -893,7 +881,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -976,7 +963,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -1050,7 +1036,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 invalidating branch cache (tip differs) 3 changesets found list of changesets: @@ -1121,7 +1106,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 invalidating branch cache (tip differs) 3 changesets found list of changesets: @@ -1195,7 +1179,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 3 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -1266,7 +1249,6 @@ """ pushing to ../b searching for changes - common changesets up to 6675d58eff77 invalidating branch cache (tip differs) 3 changesets found list of changesets: @@ -1378,7 +1360,6 @@ """ pushing to ../b searching for changes - common changesets up to 07e028174695 4 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -1456,7 +1437,6 @@ """ pushing to ../b searching for changes - common changesets up to 07e028174695 invalidating branch cache (tip differs) 4 changesets found list of changesets: @@ -1533,7 +1513,6 @@ """ pushing to ../b searching for changes - common changesets up to 07e028174695 4 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -1605,7 +1584,6 @@ """ pushing to ../b searching for changes - common changesets up to 07e028174695 4 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -1671,7 +1649,6 @@ """ pushing to ../b searching for changes - common changesets up to 07e028174695 4 changesets found list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 @@ -1754,7 +1731,6 @@ """ pushing to ../b searching for changes - common changesets up to 07e028174695 invalidating branch cache (tip differs) 4 changesets found list of changesets: @@ -1837,7 +1813,6 @@ """ pushing to ../b searching for changes - common changesets up to 07e028174695 invalidating branch cache (tip differs) 4 changesets found list of changesets:
--- a/tests/test-bundle-r.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-bundle-r.t Sun May 01 06:04:08 2011 -0500 @@ -184,7 +184,8 @@ issue76 msg2163 $ hg -R test bundle --base 3 -r 3 -r 3 test-bundle-cset-3.hg - 1 changesets found + no changes found + [1] Issue1910: 'hg bundle --base $head' does not exclude $head from result
--- a/tests/test-bundle.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-bundle.t Sun May 01 06:04:08 2011 -0500 @@ -562,7 +562,6 @@ $ hg bundle bundle.hg part --debug searching for changes - common changesets up to c0025332f9ed 2 changesets found list of changesets: d2ae7f538514cd87c17547b0de4cea71fe1af9fb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-casecollision.t Sun May 01 06:04:08 2011 -0500 @@ -0,0 +1,34 @@ +run only on case-sensitive filesystems + + $ "$TESTDIR/hghave" no-icasefs || exit 80 + +test file addition with colliding case + + $ hg init repo1 + $ cd repo1 + $ echo a > a + $ echo A > A + $ hg add a + $ hg st + A a + ? A + $ hg add --config ui.portablefilenames=abort A + abort: possible case-folding collision for A + [255] + $ hg st + A a + ? A + $ hg add A + warning: possible case-folding collision for A + $ hg st + A A + A a + $ hg forget A + $ hg st + A a + ? A + $ hg add --config ui.portablefilenames=no A + $ hg st + A A + A a + $ cd ..
--- a/tests/test-getbundle.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-getbundle.t Sun May 01 06:04:08 2011 -0500 @@ -247,7 +247,7 @@ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - (glob) * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) - * - - [*] "GET /?cmd=getbundle&common=c1818a9f5977dd4139a48f93f5425c67d44a9368+ea919464b16e003894c48b6cb68df3cd9411b544&heads=6b57ee934bb2996050540f84cdfc8dcad1e7267d+2114148793524fd045998f71a45b0aaf139f752b HTTP/1.1" 200 - (glob) + * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=c1818a9f5977dd4139a48f93f5425c67d44a9368+ea919464b16e003894c48b6cb68df3cd9411b544&heads=6b57ee934bb2996050540f84cdfc8dcad1e7267d+2114148793524fd045998f71a45b0aaf139f752b (glob) $ cat error.log
--- a/tests/test-glog.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-glog.t Sun May 01 06:04:08 2011 -0500 @@ -1393,3 +1393,38 @@ | | | date: Thu Jan 01 00:00:32 1970 +0000 | | | summary: (32) expand | | | + +Test log -G options + + $ hg log -G -u 'something nice' + $ hg log -G -b 'something nice' + abort: unknown revision 'something nice'! + [255] + $ hg log -G -k 'something nice' + $ hg log -G --only-branch 'something nice' + abort: unknown revision 'something nice'! + [255] + $ hg log -G --include 'some file' --exclude 'another file' + $ hg log -G --follow --template 'nodetag {rev}\n' | grep nodetag | wc -l + \s*36 (re) + $ hg log -G --removed --template 'nodetag {rev}\n' | grep nodetag | wc -l + \s*0 (re) + $ hg log -G --only-merges --template 'nodetag {rev}\n' | grep nodetag | wc -l + \s*28 (re) + $ hg log -G --no-merges --template 'nodetag {rev}\n' | grep nodetag | wc -l + \s*9 (re) + $ hg log -G -d 'brace ) in a date' + abort: invalid date: 'brace ) in a date' + [255] + $ hg log -G -P 32 --template '{rev}\n' + @ 36 + | + o 35 + | + o 34 + | + | o 33 + | | + $ hg log -G --follow a + abort: -G/--graph option is incompatible with --follow with file argument + [255]
--- a/tests/test-hgweb-commands.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-hgweb-commands.t Sun May 01 06:04:08 2011 -0500 @@ -952,7 +952,7 @@ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo 200 Script output follows - lookup changegroupsubset branchmap pushkey known getbundle unbundlehash unbundle=HG10GZ,HG10BZ,HG10UN + lookup changegroupsubset branchmap pushkey known getbundle unbundlehash unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 heads
--- a/tests/test-hook.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-hook.t Sun May 01 06:04:08 2011 -0500 @@ -168,6 +168,61 @@ update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc 2 files updated, 0 files merged, 0 files removed, 0 files unresolved +pushkey hook + + $ echo 'pushkey = python "$TESTDIR"/printenv.py pushkey' >> .hg/hgrc + $ cd ../b + $ hg bookmark -r null foo + $ hg push -B foo ../a + pushing to ../a + searching for changes + no changes found + exporting bookmark foo + pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1 + $ cd ../a + +listkeys hook + + $ echo 'listkeys = python "$TESTDIR"/printenv.py listkeys' >> .hg/hgrc + $ hg bookmark -r null bar + $ cd ../b + $ hg pull -B bar ../a + pulling from ../a + listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} + searching for changes + listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} + importing bookmark bar + $ cd ../a + +test that prepushkey can prevent incoming keys + + $ echo 'prepushkey = python "$TESTDIR"/printenv.py prepushkey.forbid 1' >> .hg/hgrc + $ cd ../b + $ hg bookmark -r null baz + $ hg push -B baz ../a + pushing to ../a + searching for changes + no changes found + listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} + listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} + exporting bookmark baz + prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 + abort: prepushkey hook exited with status 1 + [255] + $ cd ../a + +test that prelistkeys can prevent listing keys + + $ echo 'prelistkeys = python "$TESTDIR"/printenv.py prelistkeys.forbid 1' >> .hg/hgrc + $ hg bookmark -r null quux + $ cd ../b + $ hg pull -B quux ../a + pulling from ../a + prelistkeys.forbid hook: HG_NAMESPACE=bookmarks + abort: prelistkeys hook exited with status 1 + [255] + $ cd ../a + prechangegroup hook can prevent incoming changes $ cd ../b
--- a/tests/test-http-proxy.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-http-proxy.t Sun May 01 06:04:08 2011 -0500 @@ -100,21 +100,21 @@ $ cat proxy.log * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob) * - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 HTTP/1.1" - - (glob) - * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob) + * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
--- a/tests/test-parentrevspec.t Sun May 01 10:51:10 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ - - $ commit() - > { - > msg=$1 - > p1=$2 - > p2=$3 - > - > if [ "$p1" ]; then - > hg up -qC $p1 - > fi - > - > if [ "$p2" ]; then - > HGMERGE=true hg merge -q $p2 - > fi - > - > echo >> foo - > - > hg commit -qAm "$msg" - > } - $ hg init repo - $ cd repo - $ echo '[extensions]' > .hg/hgrc - $ echo 'parentrevspec =' >> .hg/hgrc - $ commit '0: add foo' - $ commit '1: change foo 1' - $ commit '2: change foo 2a' - $ commit '3: change foo 3a' - $ commit '4: change foo 2b' 1 - $ commit '5: merge' 3 4 - $ commit '6: change foo again' - $ hg log --template '{rev}:{node|short} {parents}\n' - 6:755d1e0d79e9 - 5:9ce2ce29723a 3:a3e00c7dbf11 4:bb4475edb621 - 4:bb4475edb621 1:5d953a1917d1 - 3:a3e00c7dbf11 - 2:befc7d89d081 - 1:5d953a1917d1 - 0:837088b6e1d9 - $ echo - - $ lookup() - > { - > for rev in "$@"; do - > printf "$rev: " - > hg id -nr $rev - > done - > true - > } - $ tipnode=`hg id -ir tip` - -should work with tag/branch/node/rev - - $ for r in tip default $tipnode 6; do - > lookup "$r^" - > done - tip^: 5 - default^: 5 - 755d1e0d79e9^: 5 - 6^: 5 - $ echo - - -some random lookups - - $ lookup "6^^" "6^^^" "6^^^^" "6^^^^^" "6^^^^^^" "6^1" "6^2" "6^^2" "6^1^2" "6^^3" - 6^^: 3 - 6^^^: 2 - 6^^^^: 1 - 6^^^^^: 0 - 6^^^^^^: -1 - 6^1: 5 - 6^2: hg: parse error at 1: syntax error - 6^^2: 4 - 6^1^2: 4 - 6^^3: hg: parse error at 1: syntax error - $ lookup "6~" "6~1" "6~2" "6~3" "6~4" "6~5" "6~42" "6~1^2" "6~1^2~2" - 6~: hg: parse error at 1: syntax error - 6~1: 5 - 6~2: 3 - 6~3: 2 - 6~4: 1 - 6~5: 0 - 6~42: -1 - 6~1^2: 4 - 6~1^2~2: 0 - $ echo - - -with a tag "6^" pointing to rev 1 - - $ hg tag -l -r 1 "6^" - $ lookup "6^" "6^1" "6~1" "6^^" - 6^: 1 - 6^1: 5 - 6~1: 5 - 6^^: 3 - $ echo - - -with a tag "foo^bar" pointing to rev 2 - - $ hg tag -l -r 2 "foo^bar" - $ lookup "foo^bar" "foo^bar^" - foo^bar: 2 - foo^bar^: hg: parse error at 3: syntax error
--- a/tests/test-patchbomb.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-patchbomb.t Sun May 01 06:04:08 2011 -0500 @@ -158,16 +158,30 @@ $ hg email -m test.mbox -f quux -t foo -c bar -s test 0:tip \ > --config extensions.progress= --config progress.assume-tty=1 \ - > --config progress.delay=0 --config progress.refresh=0 + > --config progress.delay=0 --config progress.refresh=0 \ + > --config progress.width=60 2>&1 | \ + > python $TESTDIR/filtercr.py This patch series consists of 2 patches. Write the introductory message for the patch series. - \rwriting [ ] 0/3\rwriting [ ] 0/3\r \r\r \r\rwriting [====================> ] 1/3\rwriting [====================> ] 1/3\r \r\r \r\rwriting [==========================================> ] 2/3\rwriting [==========================================> ] 2/3\r \r (esc) + + writing [ ] 0/3 + writing [ ] 0/3 + + + writing [==============> ] 1/3 + writing [==============> ] 1/3 + + + writing [=============================> ] 2/3 + writing [=============================> ] 2/3 + \r (esc) Writing [PATCH 0 of 2] test ... Writing [PATCH 1 of 2] a ... Writing [PATCH 2 of 2] b ... + $ cd ..
--- a/tests/test-push-http.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-push-http.t Sun May 01 06:04:08 2011 -0500 @@ -66,6 +66,23 @@ repository tip rolled back to revision 0 (undo serve) working directory now based on revision 0 +expect success, server lacks the httpheader capability + + $ CAP=httpheader + $ . "$TESTDIR/notcapable" + $ req + pushing to http://localhost:$HGPORT/ + searching for changes + remote: adding changesets + remote: adding manifests + remote: adding file changes + remote: added 1 changesets with 1 changes to 1 files + remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob) + % serve errors + $ hg rollback + repository tip rolled back to revision 0 (undo serve) + working directory now based on revision 0 + expect success, server lacks the unbundlehash capability $ CAP=unbundlehash
--- a/tests/test-push-warn.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-push-warn.t Sun May 01 06:04:08 2011 -0500 @@ -39,7 +39,6 @@ found new branch changeset 1c9246a22a0a found new changesets starting at 1c9246a22a0a 1 total queries - common changesets up to d8d565842d04 new remote heads on branch 'default' new remote head 1e108cc5548c abort: push creates new remote heads on branch 'default'!
--- a/tests/test-revset.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-revset.t Sun May 01 06:04:08 2011 -0500 @@ -2,7 +2,7 @@ $ export HGENCODING $ try() { - > hg debugrevspec --debug $@ + > hg debugrevspec --debug "$@" > } $ log() { @@ -374,3 +374,64 @@ 4 2 9 + +parentrevspec + + $ log 'merge()^0' + 6 + $ log 'merge()^' + 5 + $ log 'merge()^1' + 5 + $ log 'merge()^2' + 4 + $ log 'merge()^^' + 3 + $ log 'merge()^1^' + 3 + $ log 'merge()^^^' + 1 + + $ log 'merge()~0' + 6 + $ log 'merge()~1' + 5 + $ log 'merge()~2' + 3 + $ log 'merge()~2^1' + 1 + $ log 'merge()~3' + 1 + + $ log '(-3:tip)^' + 4 + 6 + 8 + + $ log 'tip^foo' + hg: parse error: ^ expects a number 0, 1, or 2 + [255] + +aliases: + + $ echo '[revsetalias]' >> .hg/hgrc + $ echo 'm = merge()' >> .hg/hgrc + $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc + $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc + + $ try m + ('symbol', 'm') + ('func', ('symbol', 'merge'), None) + 6 + $ try 'd(2:5)' + ('func', ('symbol', 'd'), ('range', ('symbol', '2'), ('symbol', '5'))) + ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('range', ('symbol', '2'), ('symbol', '5')), ('symbol', 'date')))) + 4 + 5 + 3 + 2 + $ try 'rs(2 or 3, date)' + ('func', ('symbol', 'rs'), ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'date'))) + ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'date')))) + 3 + 2
--- a/tests/test-unbundlehash.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-unbundlehash.t Sun May 01 06:04:08 2011 -0500 @@ -28,4 +28,4 @@ The hash here is always the same since the remote repository only has the null head. $ cat access.log | grep unbundle - * - - [*] "POST /?cmd=unbundle&heads=686173686564+6768033e216468247bd031a0a2d9876d79818f8f HTTP/1.1" 200 - (glob) + * - - [*] "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+6768033e216468247bd031a0a2d9876d79818f8f (glob)
--- a/tests/test-url.py Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-url.py Sun May 01 06:04:08 2011 -0500 @@ -53,7 +53,7 @@ def test_url(): """ - >>> from mercurial.url import url + >>> from mercurial.util import url This tests for edge cases in url.URL's parsing algorithm. Most of these aren't useful for documentation purposes, so they aren't
--- a/tests/test-wireproto.t Sun May 01 10:51:10 2011 +0200 +++ b/tests/test-wireproto.t Sun May 01 06:04:08 2011 -0500 @@ -23,14 +23,57 @@ $ hg debugwireargs http://localhost:$HGPORT/ un deux trois quatre un deux trois quatre None + $ hg debugwireargs http://localhost:$HGPORT/ \ un deux trois\ qu\ \ atre + un deux trois qu atre None $ hg debugwireargs http://localhost:$HGPORT/ eins zwei --four vier eins zwei None vier None $ hg debugwireargs http://localhost:$HGPORT/ eins zwei eins zwei None None None $ hg debugwireargs http://localhost:$HGPORT/ eins zwei --five fuenf eins zwei None None None + $ hg debugwireargs http://localhost:$HGPORT/ un deux trois onethousandcharactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + un deux trois onethousandcharactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx None + $ cat error.log $ cat access.log * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=quatre&one=un&three=trois&two=deux (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=quatre&one=un&three=trois&two=deux (glob) + * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=qu++atre&one=+un&three=trois+&two=deux (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=qu++atre&one=+un&three=trois+&two=deux (glob) + * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=vier&one=eins&two=zwei (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=vier&one=eins&two=zwei (glob) + * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:one=eins&two=zwei (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:one=eins&two=zwei (glob) + * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:one=eins&two=zwei (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:one=eins&two=zwei (glob) + * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=onethousandcharactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&one x-hgarg-2:=un&three=trois&two=deux (glob) + * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=onethousandcharactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&one x-hgarg-2:=un&three=trois&two=deux (glob) + +HTTP without the httpheader capability: + + $ HGRCPATH="`pwd`/repo/.hgrc" + $ CAP=httpheader + $ . "$TESTDIR/notcapable" + + $ hg serve -R repo -p $HGPORT2 -d --pid-file=hg2.pid -E error2.log -A access2.log + $ cat hg2.pid >> $DAEMON_PIDS + + $ hg debugwireargs http://localhost:$HGPORT2/ un deux trois quatre + un deux trois quatre None + $ hg debugwireargs http://localhost:$HGPORT2/ eins zwei --four vier + eins zwei None vier None + $ hg debugwireargs http://localhost:$HGPORT2/ eins zwei + eins zwei None None None + $ hg debugwireargs http://localhost:$HGPORT2/ eins zwei --five fuenf + eins zwei None None None + $ cat error2.log + $ cat access2.log + * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) * - - [*] "GET /?cmd=debugwireargs&four=quatre&one=un&three=trois&two=deux HTTP/1.1" 200 - (glob) * - - [*] "GET /?cmd=debugwireargs&four=quatre&one=un&three=trois&two=deux HTTP/1.1" 200 - (glob) * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
--- a/tests/tinyproxy.py Sun May 01 10:51:10 2011 +0200 +++ b/tests/tinyproxy.py Sun May 01 06:04:08 2011 -0500 @@ -30,6 +30,12 @@ else: self.__base_handle() + def log_request(self, code='-', size='-'): + xheaders = [h for h in self.headers.items() if h[0].startswith('x-')] + self.log_message('"%s" %s %s%s', + self.requestline, str(code), str(size), + ''.join([' %s:%s' % h for h in sorted(xheaders)])) + def _connect_to(self, netloc, soc): i = netloc.find(':') if i >= 0: