Mercurial > hg
changeset 19915:1989111687a3
merge with stable
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Sat, 19 Oct 2013 14:21:05 -0700 |
parents | 1c58e368fbfd (diff) f91e932b2cfe (current diff) |
children | fb583a1efef0 |
files | |
diffstat | 144 files changed, 4671 insertions(+), 1653 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/check-code.py Sat Oct 19 14:20:31 2013 -0700 +++ b/contrib/check-code.py Sat Oct 19 14:21:05 2013 -0700 @@ -61,11 +61,13 @@ (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"), (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"), (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"), + (r'(?<!hg )grep.*-a', "don't use 'grep -a', use in-line python"), (r'sed.*-i', "don't use 'sed -i', use a temporary file"), (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"), (r'echo -n', "don't use 'echo -n', use printf"), (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"), (r'head -c', "don't use 'head -c', use 'dd'"), + (r'tail -n', "don't use the '-n' option to tail, just use '-<num>'"), (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"), (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"), (r'printf.*[^\\]\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"), @@ -118,7 +120,7 @@ (uprefix + r'.*\|\| echo.*(fail|error)', "explicit exit code checks unnecessary"), (uprefix + r'set -e', "don't use set -e"), - (uprefix + r'\s', "don't indent commands, use > for continued lines"), + (uprefix + r'(\s|fi\b|done\b)', "use > for continued lines"), (r'^ saved backup bundle to \$TESTTMP.*\.hg$', winglobmsg), (r'^ changeset .* references (corrupted|missing) \$TESTTMP/.*[^)]$', winglobmsg), @@ -160,6 +162,9 @@ "tuple parameter unpacking not available in Python 3+"), (r'lambda\s*\(.*,.*\)', "tuple parameter unpacking not available in Python 3+"), + (r'import (.+,[^.]+\.[^.]+|[^.]+\.[^.]+,)', + '2to3 can\'t always rewrite "import qux, foo.bar", ' + 'use "import foo.bar" on its own line instead.'), (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"), (r'\breduce\s*\(.*', "reduce is not available in Python 3+"), (r'\.has_key\b', "dict.has_key is not available in Python 3+"), @@ -221,6 +226,8 @@ "missing whitespace around operator"), (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]', "wrong whitespace around ="), + (r'\([^()]*( =[^=]|[^<>!=]= )', + "no whitespace around = for named parameters"), (r'raise Exception', "don't raise generic exceptions"), (r'raise [^,(]+, (\([^\)]+\)|[^,\(\)]+)$', "don't use old-style two-argument raise, use Exception(message)"), @@ -285,8 +292,9 @@ (r'(while|if|do|for)\(', "use space after while/if/do/for"), (r'return\(', "return is not a function"), (r' ;', "no space before ;"), + (r'[)][{]', "space between ) and {"), (r'\w+\* \w+', "use int *foo, not int* foo"), - (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"), + (r'\W\([^\)]+\) \w+', "use (int)foo, not (int) foo"), (r'\w+ (\+\+|--)', "use foo++, not foo ++"), (r'\w,\w', "missing whitespace after ,"), (r'^[^#]\w[+/*]\w', "missing whitespace in expression"), @@ -324,7 +332,7 @@ checks = [ ('python', r'.*\.(py|cgi)$', pyfilters, pypats), ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats), - ('c', r'.*\.c$', cfilters, cpats), + ('c', r'.*\.[ch]$', cfilters, cpats), ('unified test', r'.*\.t$', utestfilters, utestpats), ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters, inrevlogpats),
--- a/contrib/debugshell.py Sat Oct 19 14:20:31 2013 -0700 +++ b/contrib/debugshell.py Sat Oct 19 14:21:05 2013 -0700 @@ -1,20 +1,52 @@ # debugshell extension """a python shell with repo, changelog & manifest objects""" +import sys import mercurial import code -def debugshell(ui, repo, **opts): +def pdb(ui, repo, msg, **opts): objects = { 'mercurial': mercurial, 'repo': repo, 'cl': repo.changelog, 'mf': repo.manifest, } + + code.interact(msg, local=objects) + +def ipdb(ui, repo, msg, **opts): + import IPython + + cl = repo.changelog + mf = repo.manifest + cl, mf # use variables to appease pyflakes + + IPython.embed() + +def debugshell(ui, repo, **opts): bannermsg = "loaded repo : %s\n" \ "using source: %s" % (repo.root, mercurial.__path__[0]) - code.interact(bannermsg, local=objects) + + pdbmap = { + 'pdb' : 'code', + 'ipdb' : 'IPython' + } + + debugger = ui.config("ui", "debugger") + if not debugger: + debugger = 'pdb' + + # if IPython doesn't exist, fallback to code.interact + try: + __import__(pdbmap[debugger]) + except ImportError: + ui.warn("%s debugger specified but %s module was not found\n" + % (debugger, pdbmap[debugger])) + debugger = 'pdb' + + getattr(sys.modules[__name__], debugger)(ui, repo, bannermsg, **opts) cmdtable = { "debugshell|dbsh": (debugshell, [])
--- a/contrib/hgfixes/fix_bytesmod.py Sat Oct 19 14:20:31 2013 -0700 +++ b/contrib/hgfixes/fix_bytesmod.py Sat Oct 19 14:21:05 2013 -0700 @@ -58,6 +58,6 @@ else: args = [formatstr, Comma().clone(), data] - call = Call(Name('bytesformatter', prefix = ' '), args) + call = Call(Name('bytesformatter', prefix=' '), args) return call
--- a/contrib/perf.py Sat Oct 19 14:20:31 2013 -0700 +++ b/contrib/perf.py Sat Oct 19 14:21:05 2013 -0700 @@ -87,7 +87,8 @@ @command('perftags') def perftags(ui, repo): - import mercurial.changelog, mercurial.manifest + import mercurial.changelog + import mercurial.manifest def t(): repo.changelog = mercurial.changelog.changelog(repo.sopener) repo.manifest = mercurial.manifest.manifest(repo.sopener) @@ -171,13 +172,14 @@ copies.pathcopies(ctx1, ctx2) timer(d) -@command('perfmanifest') -def perfmanifest(ui, repo): +@command('perfmanifest', [], 'REV') +def perfmanifest(ui, repo, rev): + ctx = scmutil.revsingle(repo, rev, rev) + t = ctx.manifestnode() def d(): - t = repo.manifest.tip() + repo.manifest._mancache.clear() + repo.manifest._cache = None repo.manifest.read(t) - repo.manifest.mapcache = None - repo.manifest._cache = None timer(d) @command('perfchangeset')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/plan9/9mail Sat Oct 19 14:21:05 2013 -0700 @@ -0,0 +1,26 @@ +#!/bin/rc +# 9mail - Mercurial email wrapper for upas/marshal + +fn usage { + echo >[1=2] usage: mercurial/9mail -f from to [cc] + exit usage +} + +from=() +cc=() +to=() + +switch($1){ +case -f + from=$2 +case * + usage +} + +to=($3) +if(~ $#* 4) + cc=(-C $4) + +upasname=$from +upas/marshal $cc $to +
--- a/contrib/plan9/hgrc.d/9diff.rc Sat Oct 19 14:20:31 2013 -0700 +++ b/contrib/plan9/hgrc.d/9diff.rc Sat Oct 19 14:21:05 2013 -0700 @@ -4,4 +4,4 @@ extdiff = [extdiff] -9diff = 9diff -cm $parent $child $root +9diff = /bin/mercurial/9diff -cm $parent $child $root
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/plan9/hgrc.d/9mail.rc Sat Oct 19 14:21:05 2013 -0700 @@ -0,0 +1,4 @@ +# The 9mail to support patchbomb and other email wrappers +[email] +method = /bin/mercurial/9mail +
--- a/hgext/acl.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/acl.py Sat Oct 19 14:21:05 2013 -0700 @@ -284,8 +284,8 @@ cfg = ui.config('acl', 'config') if cfg: - ui.readconfig(cfg, sections = ['acl.groups', 'acl.allow.branches', - 'acl.deny.branches', 'acl.allow', 'acl.deny']) + ui.readconfig(cfg, sections=['acl.groups', 'acl.allow.branches', + 'acl.deny.branches', 'acl.allow', 'acl.deny']) allowbranches = buildmatch(ui, None, user, 'acl.allow.branches') denybranches = buildmatch(ui, None, user, 'acl.deny.branches')
--- a/hgext/color.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/color.py Sat Oct 19 14:21:05 2013 -0700 @@ -63,6 +63,10 @@ rebase.rebased = blue rebase.remaining = red bold + shelve.age = cyan + shelve.newest = green bold + shelve.name = blue bold + histedit.remaining = red bold The available effects in terminfo mode are 'blink', 'bold', 'dim', @@ -259,6 +263,9 @@ 'rebase.remaining': 'red bold', 'resolve.resolved': 'green bold', 'resolve.unresolved': 'red bold', + 'shelve.age': 'cyan', + 'shelve.newest': 'green bold', + 'shelve.name': 'blue bold', 'status.added': 'green bold', 'status.clean': 'none', 'status.copied': 'none',
--- a/hgext/convert/__init__.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/convert/__init__.py Sat Oct 19 14:21:05 2013 -0700 @@ -155,8 +155,7 @@ (forces target IDs to change). It takes a boolean argument and defaults to False. - :convert.hg.startrev: convert start revision and its descendants. - It takes a hg revision identifier and defaults to 0. + :convert.hg.revs: revset specifying the source revisions to convert. CVS Source ########## @@ -311,7 +310,7 @@ ('d', 'dest-type', '', _('destination repository type'), _('TYPE')), ('r', 'rev', '', - _('import up to target revision REV'), _('REV')), + _('import up to source revision REV'), _('REV')), ('A', 'authormap', '', _('remap usernames using this file'), _('FILE')), ('', 'filemap', '',
--- a/hgext/convert/convcmd.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/convert/convcmd.py Sat Oct 19 14:21:05 2013 -0700 @@ -516,10 +516,7 @@ destc.setfilemapmode(True) if not revmapfile: - try: - revmapfile = destc.revmapfile() - except Exception: - revmapfile = os.path.join(destc, "map") + revmapfile = destc.revmapfile() c = converter(ui, srcc, destc, revmapfile, opts) c.convert(sortmode)
--- a/hgext/convert/filemap.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/convert/filemap.py Sat Oct 19 14:21:05 2013 -0700 @@ -7,7 +7,7 @@ import posixpath import shlex from mercurial.i18n import _ -from mercurial import util +from mercurial import util, error from common import SKIPREV, converter_source def rpairs(name): @@ -195,12 +195,19 @@ self.seenchildren.clear() for rev, wanted, arg in self.convertedorder: if rev not in self.origparents: - self.origparents[rev] = self.getcommit(rev).parents + try: + self.origparents[rev] = self.getcommit(rev).parents + except error.RepoLookupError: + self.ui.debug("unknown revmap source: %s\n" % rev) + continue if arg is not None: self.children[arg] = self.children.get(arg, 0) + 1 for rev, wanted, arg in self.convertedorder: - parents = self.origparents[rev] + try: + parents = self.origparents[rev] + except KeyError: + continue # unknown revmap source if wanted: self.mark_wanted(rev, parents) else: @@ -231,8 +238,8 @@ continue self.seenchildren[r] = self.seenchildren.get(r, 0) + 1 if self.seenchildren[r] == self.children[r]: - del self.wantedancestors[r] - del self.parentmap[r] + self.wantedancestors.pop(r, None) + self.parentmap.pop(r, None) del self.seenchildren[r] if self._rebuilt: del self.children[r] @@ -281,7 +288,11 @@ # of wanted ancestors of its parents. Plus rev itself. wrev = set() for p in parents: - wrev.update(self.wantedancestors[p]) + if p in self.wantedancestors: + wrev.update(self.wantedancestors[p]) + else: + self.ui.warn(_('warning: %s parent %s is missing\n') % + (rev, p)) wrev.add(rev) self.wantedancestors[rev] = wrev @@ -398,3 +409,6 @@ def getbookmarks(self): return self.base.getbookmarks() + + def converted(self, rev, sinkrev): + self.base.converted(rev, sinkrev)
--- a/hgext/convert/hg.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/convert/hg.py Sat Oct 19 14:21:05 2013 -0700 @@ -21,7 +21,7 @@ import os, time, cStringIO from mercurial.i18n import _ from mercurial.node import bin, hex, nullid -from mercurial import hg, util, context, bookmarks, error +from mercurial import hg, util, context, bookmarks, error, scmutil from common import NoRepo, commit, converter_source, converter_sink @@ -252,19 +252,37 @@ self.convertfp = None # Restrict converted revisions to startrev descendants startnode = ui.config('convert', 'hg.startrev') - if startnode is not None: - try: - startnode = self.repo.lookup(startnode) - except error.RepoError: - raise util.Abort(_('%s is not a valid start revision') - % startnode) - startrev = self.repo.changelog.rev(startnode) - children = {startnode: 1} - for rev in self.repo.changelog.descendants([startrev]): - children[self.repo.changelog.node(rev)] = 1 - self.keep = children.__contains__ + hgrevs = ui.config('convert', 'hg.revs') + if hgrevs is None: + if startnode is not None: + try: + startnode = self.repo.lookup(startnode) + except error.RepoError: + raise util.Abort(_('%s is not a valid start revision') + % startnode) + startrev = self.repo.changelog.rev(startnode) + children = {startnode: 1} + for r in self.repo.changelog.descendants([startrev]): + children[self.repo.changelog.node(r)] = 1 + self.keep = children.__contains__ + else: + self.keep = util.always + if rev: + self._heads = [self.repo[rev].node()] + else: + self._heads = self.repo.heads() else: - self.keep = util.always + if rev or startnode is not None: + raise util.Abort(_('hg.revs cannot be combined with ' + 'hg.startrev or --rev')) + nodes = set() + parents = set() + for r in scmutil.revrange(self.repo, [hgrevs]): + ctx = self.repo[r] + nodes.add(ctx.node()) + parents.update(p.node() for p in ctx.parents()) + self.keep = nodes.__contains__ + self._heads = nodes - parents def changectx(self, rev): if self.lastrev != rev: @@ -276,11 +294,7 @@ return [p for p in ctx.parents() if p and self.keep(p.node())] def getheads(self): - if self.rev: - heads = [self.repo[self.rev].node()] - else: - heads = self.repo.heads() - return [hex(h) for h in heads if self.keep(h)] + return [hex(h) for h in self._heads if self.keep(h)] def getfile(self, name, rev): try:
--- a/hgext/convert/subversion.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/convert/subversion.py Sat Oct 19 14:21:05 2013 -0700 @@ -2,7 +2,8 @@ # # Copyright(C) 2007 Daniel Holth et al -import os, re, sys, tempfile, urllib, urllib2, xml.dom.minidom +import os, re, sys, tempfile, urllib, urllib2 +import xml.dom.minidom import cPickle as pickle from mercurial import strutil, scmutil, util, encoding
--- a/hgext/factotum.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/factotum.py Sat Oct 19 14:21:05 2013 -0700 @@ -101,7 +101,7 @@ user, passwd = auth.get('username'), auth.get('password') if not user or not passwd: if not prefix: - prefix = '*' + prefix = realm.split(' ')[0].lower() params = 'service=%s prefix=%s' % (_service, prefix) if user: params = '%s user=%s' % (params, user)
--- a/hgext/highlight/__init__.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/highlight/__init__.py Sat Oct 19 14:21:05 2013 -0700 @@ -50,7 +50,7 @@ def generate_css(web, req, tmpl): pg_style = web.config('web', 'pygments_style', 'colorful') - fmter = highlight.HtmlFormatter(style = pg_style) + fmter = highlight.HtmlFormatter(style=pg_style) req.respond(common.HTTP_OK, 'text/css') return ['/* pygments_style = %s */\n\n' % pg_style, fmter.get_style_defs('')]
--- a/hgext/histedit.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/histedit.py Sat Oct 19 14:21:05 2013 -0700 @@ -419,10 +419,6 @@ if revs: revs = [repo.lookup(rev) for rev in revs] - # hexlify nodes from outgoing, because we're going to parse - # parent[0] using revsingle below, and if the binary hash - # contains special revset characters like ":" the revset - # parser can choke. outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force) if not outgoing.missing: raise util.Abort(_('no outgoing ancestors')) @@ -519,7 +515,6 @@ if goal == 'continue': (parentctxnode, rules, keep, topmost, replacements) = readstate(repo) - currentparent, wantnull = repo.dirstate.parents() parentctx = repo[parentctxnode] parentctx, repl = bootstrapcontinue(ui, repo, parentctx, rules, opts) replacements.extend(repl)
--- a/hgext/inotify/server.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/inotify/server.py Sat Oct 19 14:21:05 2013 -0700 @@ -451,8 +451,9 @@ runargs = util.hgcmd() + sys.argv[1:] pidfile = ui.config('inotify', 'pidfile') - if opts['daemon'] and pidfile is not None and 'pid-file' not in runargs: - runargs.append("--pid-file=%s" % pidfile) + opts.setdefault('pid_file', '') + if opts['daemon'] and pidfile is not None and not opts['pid_file']: + opts['pid_file'] = pidfile service = service() logfile = ui.config('inotify', 'log')
--- a/hgext/largefiles/__init__.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/largefiles/__init__.py Sat Oct 19 14:21:05 2013 -0700 @@ -105,16 +105,26 @@ command. ''' -from mercurial import commands +from mercurial import commands, localrepo, extensions import lfcommands import reposetup -import uisetup +import uisetup as uisetupmod testedwith = 'internal' reposetup = reposetup.reposetup -uisetup = uisetup.uisetup + +def featuresetup(ui, supported): + for name, module in extensions.extensions(ui): + if __name__ == module.__name__: + # don't die on seeing a repo with the largefiles requirement + supported |= set(['largefiles']) + return + +def uisetup(ui): + localrepo.localrepository.featuresetupfuncs.add(featuresetup) + uisetupmod.uisetup(ui) commands.norepo += " lfconvert"
--- a/hgext/largefiles/overrides.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/largefiles/overrides.py Sat Oct 19 14:21:05 2013 -0700 @@ -315,7 +315,7 @@ lfdirstate.normal(lfile) lfdirstate.write() if mod: - raise util.Abort(_('uncommitted local changes')) + raise util.Abort(_('uncommitted changes')) # XXX handle removed differently if not opts['clean']: for lfile in unsure + modified + added: @@ -717,7 +717,6 @@ ui.debug('--update and --rebase are not compatible, ignoring ' 'the update flag\n') del opts['rebase'] - cmdutil.bailifchanged(repo) origpostincoming = commands.postincoming def _dummy(*args, **kwargs): pass @@ -947,7 +946,7 @@ modified, added, removed, deleted = repo.status()[:4] repo.lfstatus = False if modified or added or removed or deleted: - raise util.Abort(_('outstanding uncommitted changes')) + raise util.Abort(_('uncommitted changes')) # Fetch doesn't use cmdutil.bailifchanged so override it to add the check def overridefetch(orig, ui, repo, *pats, **opts): @@ -955,7 +954,7 @@ modified, added, removed, deleted = repo.status()[:4] repo.lfstatus = False if modified or added or removed or deleted: - raise util.Abort(_('outstanding uncommitted changes')) + raise util.Abort(_('uncommitted changes')) return orig(ui, repo, *pats, **opts) def overrideforget(orig, ui, repo, *pats, **opts):
--- a/hgext/largefiles/reposetup.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/largefiles/reposetup.py Sat Oct 19 14:21:05 2013 -0700 @@ -10,8 +10,7 @@ import copy import os -from mercurial import context, error, manifest, match as match_, util, \ - discovery +from mercurial import error, manifest, match as match_, util, discovery from mercurial import node as node_ from mercurial.i18n import _ from mercurial import localrepo @@ -92,14 +91,8 @@ else: # some calls in this function rely on the old version of status self.lfstatus = False - if isinstance(node1, context.changectx): - ctx1 = node1 - else: - ctx1 = self[node1] - if isinstance(node2, context.changectx): - ctx2 = node2 - else: - ctx2 = self[node2] + ctx1 = self[node1] + ctx2 = self[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] @@ -414,6 +407,14 @@ wlock.release() def push(self, remote, force=False, revs=None, newbranch=False): + if remote.local(): + missing = set(self.requirements) - remote.local().supported + if missing: + msg = _("required features are not" + " supported in the destination:" + " %s") % (', '.join(sorted(missing))) + raise util.Abort(msg) + outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=force) if outgoing.missing:
--- a/hgext/largefiles/uisetup.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/largefiles/uisetup.py Sat Oct 19 14:21:05 2013 -0700 @@ -9,7 +9,7 @@ '''setup for largefiles extension: uisetup''' from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \ - httppeer, localrepo, merge, scmutil, sshpeer, wireproto, revset + httppeer, merge, scmutil, sshpeer, wireproto, revset from mercurial.i18n import _ from mercurial.hgweb import hgweb_mod, webcommands from mercurial.subrepo import hgsubrepo @@ -152,9 +152,6 @@ sshpeer.sshpeer._callstream = proto.sshrepocallstream httppeer.httppeer._callstream = proto.httprepocallstream - # don't die on seeing a repo with the largefiles requirement - localrepo.localrepository.supported |= set(['largefiles']) - # override some extensions' stuff as well for name, module in extensions.extensions(): if name == 'fetch':
--- a/hgext/mq.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/mq.py Sat Oct 19 14:21:05 2013 -0700 @@ -57,15 +57,19 @@ make them behave as if --keep-changes were passed, and non-conflicting local changes will be tolerated and preserved. If incompatible options such as -f/--force or --exact are passed, this setting is ignored. + +This extension used to provide a strip command. This command now lives +in the strip extension. ''' from mercurial.i18n import _ from mercurial.node import bin, hex, short, nullid, nullrev from mercurial.lock import release from mercurial import commands, cmdutil, hg, scmutil, util, revset -from mercurial import repair, extensions, error, phases, bookmarks +from mercurial import extensions, error, phases from mercurial import patch as patchmod from mercurial import localrepo +from mercurial import subrepo import os, re, errno, shutil commands.norepo += " qclone" @@ -76,6 +80,22 @@ command = cmdutil.command(cmdtable) testedwith = 'internal' +# force load strip extension formely included in mq and import some utility +try: + stripext = extensions.find('strip') +except KeyError: + # note: load is lazy so we could avoid the try-except, + # but I (marmoute) prefer this explicite code. + class dummyui(object): + def debug(self, msg): + pass + stripext = extensions.load(dummyui(), 'strip', '') + +strip = stripext.strip +checksubstate = stripext.checksubstate +checklocalchanges = stripext.checklocalchanges + + # Patch names looks like unix-file names. # They must be joinable with queue directory and result in the patch path. normname = util.normpath @@ -282,15 +302,11 @@ phase = phases.secret if phase is not None: backup = repo.ui.backupconfig('phases', 'new-commit') - # Marking the repository as committing an mq patch can be used - # to optimize operations like branchtags(). - repo._committingpatch = True try: if phase is not None: repo.ui.setconfig('phases', 'new-commit', phase) return repo.commit(*args, **kwargs) finally: - repo._committingpatch = False if phase is not None: repo.ui.restoreconfig(backup) @@ -331,6 +347,7 @@ except error.ConfigError: self.gitmode = ui.config('mq', 'git', 'auto').lower() self.plainmode = ui.configbool('mq', 'plain', False) + self.checkapplied = True @util.propertycache def applied(self): @@ -606,7 +623,7 @@ # apply failed, strip away that rev and merge. hg.clean(repo, head) - self.strip(repo, [n], update=False, backup='strip') + strip(self.ui, repo, [n], update=False, backup='strip') ctx = repo[rev] ret = hg.merge(repo, rev) @@ -631,6 +648,14 @@ return (0, n) def qparents(self, repo, rev=None): + """return the mq handled parent or p1 + + In some case where mq get himself in being the parent of a merge the + paappropriate parent may be p2. + (eg: an in progress merge started with mq disabled) + + If no parent are managed by mq, p1 is returned. + """ if rev is None: (p1, p2) = repo.dirstate.parents() if p2 == nullid: @@ -800,6 +825,14 @@ p1, p2 = repo.dirstate.parents() repo.setparents(p1, merge) + if all_files and '.hgsubstate' in all_files: + wctx = repo['.'] + mctx = actx = repo[None] + overwrite = False + mergedsubstate = subrepo.submerge(repo, wctx, mctx, actx, + overwrite) + files += mergedsubstate.keys() + match = scmutil.matchfiles(repo, files or []) oldtip = repo['tip'] n = newcommit(repo, None, message, ph.user, ph.date, match=match, @@ -940,23 +973,6 @@ return top, patch return None, None - def checksubstate(self, repo, baserev=None): - '''return list of subrepos at a different revision than substate. - Abort if any subrepos have uncommitted changes.''' - inclsubs = [] - wctx = repo[None] - if baserev: - bctx = repo[baserev] - else: - bctx = wctx.parents()[0] - for s in sorted(wctx.substate): - if wctx.sub(s).dirty(True): - raise util.Abort( - _("uncommitted changes in subrepository %s") % s) - elif s not in bctx.substate or bctx.sub(s).dirty(): - inclsubs.append(s) - return inclsubs - def putsubstate2changes(self, substatestate, changes): for files in changes[:3]: if '.hgsubstate' in files: @@ -969,18 +985,14 @@ else: # modified changes[0].append('.hgsubstate') - def localchangesfound(self, refresh=True): + def checklocalchanges(self, repo, force=False, refresh=True): + excsuffix = '' if refresh: - raise util.Abort(_("local changes found, refresh first")) - else: - raise util.Abort(_("local changes found")) - - def checklocalchanges(self, repo, force=False, refresh=True): - cmdutil.checkunfinished(repo) - m, a, r, d = repo.status()[:4] - if (m or a or r or d) and not force: - self.localchangesfound(refresh) - return m, a, r, d + excsuffix = ', refresh first' + # plain versions for i18n tool to detect them + _("local changes found, refresh first") + _("local changed subrepos found, refresh first") + return checklocalchanges(repo, force, excsuffix) _reserved = ('series', 'status', 'guards', '.', '..') def checkreservedname(self, name): @@ -1021,7 +1033,7 @@ diffopts = self.diffopts({'git': opts.get('git')}) if opts.get('checkname', True): self.checkpatchname(patchfn) - inclsubs = self.checksubstate(repo) + inclsubs = checksubstate(repo) if inclsubs: inclsubs.append('.hgsubstate') substatestate = repo.dirstate['.hgsubstate'] @@ -1111,22 +1123,6 @@ finally: release(wlock) - def strip(self, repo, revs, update=True, backup="all", force=None): - wlock = lock = None - try: - wlock = repo.wlock() - lock = repo.lock() - - if update: - self.checklocalchanges(repo, force=force, refresh=False) - urev = self.qparents(repo, revs[0]) - hg.clean(repo, urev) - repo.dirstate.write() - - repair.strip(self.ui, repo, revs, backup) - finally: - release(lock, wlock) - def isapplied(self, patch): """returns (index, rev, patch)""" for i, a in enumerate(self.applied): @@ -1435,7 +1431,7 @@ tobackup = set(a + m + r) & tobackup if keepchanges and tobackup: - self.localchangesfound() + raise util.Abort(_("local changes found, refresh first")) self.backup(repo, tobackup) for f in a: @@ -1449,7 +1445,9 @@ for patch in reversed(self.applied[start:end]): self.ui.status(_("popping %s\n") % patch.name) del self.applied[start:end] - self.strip(repo, [rev], update=False, backup='strip') + strip(self.ui, repo, [rev], update=False, backup='strip') + for s, state in repo['.'].substate.items(): + repo['.'].sub(s).get(state) if self.applied: self.ui.write(_("now at: %s\n") % self.applied[-1].name) else: @@ -1493,7 +1491,7 @@ cparents = repo.changelog.parents(top) patchparent = self.qparents(repo, top) - inclsubs = self.checksubstate(repo, hex(patchparent)) + inclsubs = checksubstate(repo, hex(patchparent)) if inclsubs: inclsubs.append('.hgsubstate') substatestate = repo.dirstate['.hgsubstate'] @@ -1650,8 +1648,7 @@ repo.setparents(*cparents) self.applied.pop() self.applieddirty = True - self.strip(repo, [top], update=False, - backup='strip') + strip(self.ui, repo, [top], update=False, backup='strip') except: # re-raises repo.dirstate.invalidate() raise @@ -1823,7 +1820,7 @@ update = True else: update = False - self.strip(repo, [rev], update=update, backup='strip') + strip(self.ui, repo, [rev], update=update, backup='strip') if qpp: self.ui.warn(_("saved queue repository parents: %s %s\n") % (short(qpp[0]), short(qpp[1]))) @@ -2304,7 +2301,7 @@ if qbase: ui.note(_('stripping applied patches from destination ' 'repository\n')) - repo.mq.strip(repo, [qbase], update=False, backup=None) + strip(ui, repo, [qbase], update=False, backup=None) if not opts.get('noupdate'): ui.note(_('updating destination repository\n')) hg.update(repo, repo.changelog.tip()) @@ -2919,158 +2916,6 @@ q.savedirty() return 0 -@command("strip", - [ - ('r', 'rev', [], _('strip specified revision (optional, ' - 'can specify revisions without this ' - 'option)'), _('REV')), - ('f', 'force', None, _('force removal of changesets, discard ' - 'uncommitted changes (no backup)')), - ('b', 'backup', None, _('bundle only changesets with local revision' - ' number greater than REV which are not' - ' descendants of REV (DEPRECATED)')), - ('', 'no-backup', None, _('no backups')), - ('', 'nobackup', None, _('no backups (DEPRECATED)')), - ('n', '', None, _('ignored (DEPRECATED)')), - ('k', 'keep', None, _("do not modify working copy during strip")), - ('B', 'bookmark', '', _("remove revs only reachable from given" - " bookmark"))], - _('hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...')) -def strip(ui, repo, *revs, **opts): - """strip changesets and all their descendants from the repository - - The strip command removes the specified changesets and all their - descendants. If the working directory has uncommitted changes, the - operation is aborted unless the --force flag is supplied, in which - case changes will be discarded. - - If a parent of the working directory is stripped, then the working - directory will automatically be updated to the most recent - available ancestor of the stripped parent after the operation - completes. - - Any stripped changesets are stored in ``.hg/strip-backup`` as a - bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can - be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`, - where BUNDLE is the bundle file created by the strip. Note that - the local revision numbers will in general be different after the - restore. - - Use the --no-backup option to discard the backup bundle once the - operation completes. - - Strip is not a history-rewriting operation and can be used on - changesets in the public phase. But if the stripped changesets have - been pushed to a remote repository you will likely pull them again. - - Return 0 on success. - """ - backup = 'all' - if opts.get('backup'): - backup = 'strip' - elif opts.get('no_backup') or opts.get('nobackup'): - backup = 'none' - - cl = repo.changelog - revs = list(revs) + opts.get('rev') - revs = set(scmutil.revrange(repo, revs)) - - if opts.get('bookmark'): - mark = opts.get('bookmark') - marks = repo._bookmarks - if mark not in marks: - raise util.Abort(_("bookmark '%s' not found") % mark) - - # If the requested bookmark is not the only one pointing to a - # a revision we have to only delete the bookmark and not strip - # anything. revsets cannot detect that case. - uniquebm = True - for m, n in marks.iteritems(): - if m != mark and n == repo[mark].node(): - uniquebm = False - break - if uniquebm: - rsrevs = repo.revs("ancestors(bookmark(%s)) - " - "ancestors(head() and not bookmark(%s)) - " - "ancestors(bookmark() and not bookmark(%s))", - mark, mark, mark) - revs.update(set(rsrevs)) - if not revs: - del marks[mark] - marks.write() - ui.write(_("bookmark '%s' deleted\n") % mark) - - if not revs: - raise util.Abort(_('empty revision set')) - - descendants = set(cl.descendants(revs)) - strippedrevs = revs.union(descendants) - roots = revs.difference(descendants) - - update = False - # if one of the wdir parent is stripped we'll need - # to update away to an earlier revision - for p in repo.dirstate.parents(): - if p != nullid and cl.rev(p) in strippedrevs: - update = True - break - - rootnodes = set(cl.node(r) for r in roots) - - q = repo.mq - if q.applied: - # refresh queue state if we're about to strip - # applied patches - if cl.rev(repo.lookup('qtip')) in strippedrevs: - q.applieddirty = True - start = 0 - end = len(q.applied) - for i, statusentry in enumerate(q.applied): - if statusentry.node in rootnodes: - # if one of the stripped roots is an applied - # patch, only part of the queue is stripped - start = i - break - del q.applied[start:end] - q.savedirty() - - revs = sorted(rootnodes) - if update and opts.get('keep'): - wlock = repo.wlock() - try: - urev = repo.mq.qparents(repo, revs[0]) - uctx = repo[urev] - - # only reset the dirstate for files that would actually change - # between the working context and uctx - descendantrevs = repo.revs("%s::." % uctx.rev()) - changedfiles = [] - for rev in descendantrevs: - # blindly reset the files, regardless of what actually changed - changedfiles.extend(repo[rev].files()) - - # reset files that only changed in the dirstate too - dirstate = repo.dirstate - dirchanges = [f for f in dirstate if dirstate[f] != 'n'] - changedfiles.extend(dirchanges) - - repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles) - repo.dirstate.write() - update = False - finally: - wlock.release() - - if opts.get('bookmark'): - if mark == repo._bookmarkcurrent: - bookmarks.setcurrent(repo, None) - del marks[mark] - marks.write() - ui.write(_("bookmark '%s' deleted\n") % mark) - - repo.mq.strip(repo, revs, backup=backup, update=update, - force=opts.get('force')) - - return 0 @command("qselect", [('n', 'none', None, _('disable all guards')), @@ -3420,7 +3265,7 @@ return queue(self.ui, self.baseui, self.path) def abortifwdirpatched(self, errmsg, force=False): - if self.mq.applied and not force: + if self.mq.applied and self.mq.checkapplied and not force: parents = self.dirstate.parents() patches = [s.node for s in self.mq.applied] if parents[0] in patches or parents[1] in patches: @@ -3436,7 +3281,7 @@ editor, extra) def checkpush(self, force, revs): - if self.mq.applied and not force: + if self.mq.applied and self.mq.checkapplied and not force: outapplied = [e.node for e in self.mq.applied] if revs: # Assume applied patches have no non-patch descendants and
--- a/hgext/notify.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/notify.py Sat Oct 19 14:21:05 2013 -0700 @@ -133,9 +133,13 @@ ''' +import email, socket, time +# On python2.4 you have to import this by name or they fail to +# load. This was not a problem on Python 2.7. +import email.Parser from mercurial.i18n import _ from mercurial import patch, cmdutil, templater, util, mail -import email.Parser, email.Errors, fnmatch, socket, time +import fnmatch testedwith = 'internal'
--- a/hgext/patchbomb.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/patchbomb.py Sat Oct 19 14:21:05 2013 -0700 @@ -46,8 +46,12 @@ ''' import os, errno, socket, tempfile, cStringIO -import email.MIMEMultipart, email.MIMEBase -import email.Utils, email.Encoders, email.Generator +import email +# On python2.4 you have to import these by name or they fail to +# load. This was not a problem on Python 2.7. +import email.Generator +import email.MIMEMultipart + from mercurial import cmdutil, commands, hg, mail, patch, util from mercurial import scmutil from mercurial.i18n import _
--- a/hgext/progress.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/progress.py Sat Oct 19 14:21:05 2013 -0700 @@ -239,6 +239,13 @@ # this one are also closed if topic in self.topics: self.topics = self.topics[:self.topics.index(topic)] + # reset the last topic to the one we just unwound to, + # so that higher-level topics will be stickier than + # lower-level topics + if self.topics: + self.lasttopic = self.topics[-1] + else: + self.lasttopic = None else: if topic not in self.topics: self.starttimes[topic] = now
--- a/hgext/rebase.py Sat Oct 19 14:20:31 2013 -0700 +++ b/hgext/rebase.py Sat Oct 19 14:21:05 2013 -0700 @@ -29,6 +29,25 @@ command = cmdutil.command(cmdtable) testedwith = 'internal' +def _savegraft(ctx, extra): + s = ctx.extra().get('source', None) + if s is not None: + extra['source'] = s + +def _savebranch(ctx, extra): + extra['branch'] = ctx.branch() + +def _makeextrafn(copiers): + """make an extrafn out of the given copy-functions. + + A copy function takes a context and an extra dict, and mutates the + extra dict as needed based on the given context. + """ + def extrafn(ctx, extra): + for c in copiers: + c(ctx, extra) + return extrafn + @command('rebase', [('s', 'source', '', _('rebase from the specified changeset'), _('REV')), @@ -136,7 +155,10 @@ abortf = opts.get('abort') collapsef = opts.get('collapse', False) collapsemsg = cmdutil.logmessage(ui, opts) - extrafn = opts.get('extrafn') # internal, used by e.g. hgsubversion + e = opts.get('extrafn') # internal, used by e.g. hgsubversion + extrafns = [_savegraft] + if e: + extrafns = [e] keepf = opts.get('keep', False) keepbranchesf = opts.get('keepbranches', False) # keepopen is not meant for use on the command line, but by @@ -240,9 +262,10 @@ external = checkexternal(repo, state, targetancestors) if keepbranchesf: - assert not extrafn, 'cannot use both keepbranches and extrafn' - def extrafn(ctx, extra): - extra['branch'] = ctx.branch() + # insert _savebranch at the start of extrafns so if + # there's a user-provided extrafn it can clobber branch if + # desired + extrafns.insert(0, _savebranch) if collapsef: branches = set() for rev in state: @@ -262,6 +285,8 @@ if activebookmark: bookmarks.unsetcurrent(repo) + extrafn = _makeextrafn(extrafns) + sortedstate = sorted(state) total = len(sortedstate) pos = 0 @@ -780,7 +805,6 @@ 'the update flag\n') movemarkfrom = repo['.'].node() - cmdutil.bailifchanged(repo) revsprepull = len(repo) origpostincoming = commands.postincoming def _dummy(*args, **kwargs):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/shelve.py Sat Oct 19 14:21:05 2013 -0700 @@ -0,0 +1,633 @@ +# shelve.py - save/restore working directory state +# +# Copyright 2013 Facebook, Inc. +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +"""save and restore changes to the working directory + +The "hg shelve" command saves changes made to the working directory +and reverts those changes, resetting the working directory to a clean +state. + +Later on, the "hg unshelve" command restores the changes saved by "hg +shelve". Changes can be restored even after updating to a different +parent, in which case Mercurial's merge machinery will resolve any +conflicts if necessary. + +You can have more than one shelved change outstanding at a time; each +shelved change has a distinct name. For details, see the help for "hg +shelve". +""" + +from mercurial.i18n import _ +from mercurial.node import nullid, bin, hex +from mercurial import changegroup, cmdutil, scmutil, phases +from mercurial import error, hg, mdiff, merge, patch, repair, util +from mercurial import templatefilters +from mercurial import lock as lockmod +import errno + +cmdtable = {} +command = cmdutil.command(cmdtable) +testedwith = 'internal' + +class shelvedfile(object): + """Helper for the file storing a single shelve + + Handles common functions on shelve files (.hg/.files/.patch) using + the vfs layer""" + def __init__(self, repo, name, filetype=None): + self.repo = repo + self.name = name + self.vfs = scmutil.vfs(repo.join('shelved')) + if filetype: + self.fname = name + '.' + filetype + else: + self.fname = name + + def exists(self): + return self.vfs.exists(self.fname) + + def filename(self): + return self.vfs.join(self.fname) + + def unlink(self): + util.unlink(self.filename()) + + def stat(self): + return self.vfs.stat(self.fname) + + def opener(self, mode='rb'): + try: + return self.vfs(self.fname, mode) + except IOError, err: + if err.errno != errno.ENOENT: + raise + if mode[0] in 'wa': + try: + self.vfs.mkdir() + return self.vfs(self.fname, mode) + except IOError, err: + if err.errno != errno.EEXIST: + raise + elif mode[0] == 'r': + raise util.Abort(_("shelved change '%s' not found") % + self.name) + +class shelvedstate(object): + """Handle persistence during unshelving operations. + + Handles saving and restoring a shelved state. Ensures that different + versions of a shelved state are possible and handles them appropriately. + """ + _version = 1 + _filename = 'shelvedstate' + + @classmethod + def load(cls, repo): + fp = repo.opener(cls._filename) + try: + version = int(fp.readline().strip()) + + if version != cls._version: + raise util.Abort(_('this version of shelve is incompatible ' + 'with the version used in this repo')) + name = fp.readline().strip() + parents = [bin(h) for h in fp.readline().split()] + stripnodes = [bin(h) for h in fp.readline().split()] + finally: + fp.close() + + obj = cls() + obj.name = name + obj.parents = parents + obj.stripnodes = stripnodes + + return obj + + @classmethod + def save(cls, repo, name, stripnodes): + fp = repo.opener(cls._filename, 'wb') + fp.write('%i\n' % cls._version) + fp.write('%s\n' % name) + fp.write('%s\n' % ' '.join([hex(p) for p in repo.dirstate.parents()])) + fp.write('%s\n' % ' '.join([hex(n) for n in stripnodes])) + fp.close() + + @classmethod + def clear(cls, repo): + util.unlinkpath(repo.join(cls._filename), ignoremissing=True) + +def createcmd(ui, repo, pats, opts): + """subcommand that creates a new shelve""" + + def publicancestors(ctx): + """Compute the heads of the public ancestors of a commit. + + Much faster than the revset heads(ancestors(ctx) - draft())""" + seen = set() + visit = util.deque() + visit.append(ctx) + while visit: + ctx = visit.popleft() + for parent in ctx.parents(): + rev = parent.rev() + if rev not in seen: + seen.add(rev) + if parent.mutable(): + visit.append(parent) + else: + yield parent.node() + + wctx = repo[None] + parents = wctx.parents() + if len(parents) > 1: + raise util.Abort(_('cannot shelve while merging')) + parent = parents[0] + + # we never need the user, so we use a generic user for all shelve operations + user = 'shelve@localhost' + label = repo._bookmarkcurrent or parent.branch() or 'default' + + # slashes aren't allowed in filenames, therefore we rename it + origlabel, label = label, label.replace('/', '_') + + def gennames(): + yield label + for i in xrange(1, 100): + yield '%s-%02d' % (label, i) + + shelvedfiles = [] + + def commitfunc(ui, repo, message, match, opts): + # check modified, added, removed, deleted only + for flist in repo.status(match=match)[:4]: + shelvedfiles.extend(flist) + hasmq = util.safehasattr(repo, 'mq') + if hasmq: + saved, repo.mq.checkapplied = repo.mq.checkapplied, False + try: + return repo.commit(message, user, opts.get('date'), match) + finally: + if hasmq: + repo.mq.checkapplied = saved + + if parent.node() != nullid: + desc = parent.description().split('\n', 1)[0] + else: + desc = '(empty repository)' + + if not opts['message']: + opts['message'] = desc + + name = opts['name'] + + wlock = lock = tr = bms = None + try: + wlock = repo.wlock() + lock = repo.lock() + + bms = repo._bookmarks.copy() + # use an uncommited transaction to generate the bundle to avoid + # pull races. ensure we don't print the abort message to stderr. + tr = repo.transaction('commit', report=lambda x: None) + + if name: + if shelvedfile(repo, name, 'hg').exists(): + raise util.Abort(_("a shelved change named '%s' already exists") + % name) + else: + for n in gennames(): + if not shelvedfile(repo, n, 'hg').exists(): + name = n + break + else: + raise util.Abort(_("too many shelved changes named '%s'") % + label) + + # ensure we are not creating a subdirectory or a hidden file + if '/' in name or '\\' in name: + raise util.Abort(_('shelved change names may not contain slashes')) + if name.startswith('.'): + raise util.Abort(_("shelved change names may not start with '.'")) + + node = cmdutil.commit(ui, repo, commitfunc, pats, opts) + + if not node: + stat = repo.status(match=scmutil.match(repo[None], pats, opts)) + if stat[3]: + ui.status(_("nothing changed (%d missing files, see " + "'hg status')\n") % len(stat[3])) + else: + ui.status(_("nothing changed\n")) + return 1 + + phases.retractboundary(repo, phases.secret, [node]) + + fp = shelvedfile(repo, name, 'files').opener('wb') + fp.write('\0'.join(shelvedfiles)) + + bases = list(publicancestors(repo[node])) + cg = repo.changegroupsubset(bases, [node], 'shelve') + changegroup.writebundle(cg, shelvedfile(repo, name, 'hg').filename(), + 'HG10UN') + cmdutil.export(repo, [node], + fp=shelvedfile(repo, name, 'patch').opener('wb'), + opts=mdiff.diffopts(git=True)) + + + if ui.formatted(): + desc = util.ellipsis(desc, ui.termwidth()) + ui.status(_('shelved as %s\n') % name) + hg.update(repo, parent.node()) + finally: + if bms: + # restore old bookmarks + repo._bookmarks.update(bms) + repo._bookmarks.write() + if tr: + tr.abort() + lockmod.release(lock, wlock) + +def cleanupcmd(ui, repo): + """subcommand that deletes all shelves""" + + wlock = None + try: + wlock = repo.wlock() + for (name, _) in repo.vfs.readdir('shelved'): + suffix = name.rsplit('.', 1)[-1] + if suffix in ('hg', 'files', 'patch'): + shelvedfile(repo, name).unlink() + finally: + lockmod.release(wlock) + +def deletecmd(ui, repo, pats): + """subcommand that deletes a specific shelve""" + if not pats: + raise util.Abort(_('no shelved changes specified!')) + wlock = None + try: + wlock = repo.wlock() + try: + for name in pats: + for suffix in 'hg files patch'.split(): + shelvedfile(repo, name, suffix).unlink() + except OSError, err: + if err.errno != errno.ENOENT: + raise + raise util.Abort(_("shelved change '%s' not found") % name) + finally: + lockmod.release(wlock) + +def listshelves(repo): + """return all shelves in repo as list of (time, filename)""" + try: + names = repo.vfs.readdir('shelved') + except OSError, err: + if err.errno != errno.ENOENT: + raise + return [] + info = [] + for (name, _) in names: + pfx, sfx = name.rsplit('.', 1) + if not pfx or sfx != 'patch': + continue + st = shelvedfile(repo, name).stat() + info.append((st.st_mtime, shelvedfile(repo, pfx).filename())) + return sorted(info, reverse=True) + +def listcmd(ui, repo, pats, opts): + """subcommand that displays the list of shelves""" + pats = set(pats) + width = 80 + if not ui.plain(): + width = ui.termwidth() + namelabel = 'shelve.newest' + for mtime, name in listshelves(repo): + sname = util.split(name)[1] + if pats and sname not in pats: + continue + ui.write(sname, label=namelabel) + namelabel = 'shelve.name' + if ui.quiet: + ui.write('\n') + continue + ui.write(' ' * (16 - len(sname))) + used = 16 + age = '(%s)' % templatefilters.age(util.makedate(mtime), abbrev=True) + ui.write(age, label='shelve.age') + ui.write(' ' * (12 - len(age))) + used += 12 + fp = open(name + '.patch', 'rb') + try: + while True: + line = fp.readline() + if not line: + break + if not line.startswith('#'): + desc = line.rstrip() + if ui.formatted(): + desc = util.ellipsis(desc, width - used) + ui.write(desc) + break + ui.write('\n') + if not (opts['patch'] or opts['stat']): + continue + difflines = fp.readlines() + if opts['patch']: + for chunk, label in patch.difflabel(iter, difflines): + ui.write(chunk, label=label) + if opts['stat']: + for chunk, label in patch.diffstatui(difflines, width=width, + git=True): + ui.write(chunk, label=label) + finally: + fp.close() + +def readshelvedfiles(repo, basename): + """return the list of files touched in a shelve""" + fp = shelvedfile(repo, basename, 'files').opener() + return fp.read().split('\0') + +def checkparents(repo, state): + """check parent while resuming an unshelve""" + if state.parents != repo.dirstate.parents(): + raise util.Abort(_('working directory parents do not match unshelve ' + 'state')) + +def unshelveabort(ui, repo, state, opts): + """subcommand that abort an in-progress unshelve""" + wlock = repo.wlock() + lock = None + try: + checkparents(repo, state) + lock = repo.lock() + merge.mergestate(repo).reset() + if opts['keep']: + repo.setparents(repo.dirstate.parents()[0]) + else: + revertfiles = readshelvedfiles(repo, state.name) + wctx = repo.parents()[0] + cmdutil.revert(ui, repo, wctx, [wctx.node(), nullid], + *revertfiles, **{'no_backup': True}) + # fix up the weird dirstate states the merge left behind + mf = wctx.manifest() + dirstate = repo.dirstate + for f in revertfiles: + if f in mf: + dirstate.normallookup(f) + else: + dirstate.drop(f) + dirstate._pl = (wctx.node(), nullid) + dirstate._dirty = True + repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') + shelvedstate.clear(repo) + ui.warn(_("unshelve of '%s' aborted\n") % state.name) + finally: + lockmod.release(lock, wlock) + +def unshelvecleanup(ui, repo, name, opts): + """remove related files after an unshelve""" + if not opts['keep']: + for filetype in 'hg files patch'.split(): + shelvedfile(repo, name, filetype).unlink() + +def finishmerge(ui, repo, ms, stripnodes, name, opts): + # Reset the working dir so it's no longer in a merge state. + dirstate = repo.dirstate + dirstate.setparents(dirstate._pl[0]) + shelvedstate.clear(repo) + +def unshelvecontinue(ui, repo, state, opts): + """subcommand to continue an in-progress unshelve""" + # We're finishing off a merge. First parent is our original + # parent, second is the temporary "fake" commit we're unshelving. + wlock = repo.wlock() + lock = None + try: + checkparents(repo, state) + ms = merge.mergestate(repo) + if [f for f in ms if ms[f] == 'u']: + raise util.Abort( + _("unresolved conflicts, can't continue"), + hint=_("see 'hg resolve', then 'hg unshelve --continue'")) + finishmerge(ui, repo, ms, state.stripnodes, state.name, opts) + lock = repo.lock() + repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') + unshelvecleanup(ui, repo, state.name, opts) + ui.status(_("unshelve of '%s' complete\n") % state.name) + finally: + lockmod.release(lock, wlock) + +@command('unshelve', + [('a', 'abort', None, + _('abort an incomplete unshelve operation')), + ('c', 'continue', None, + _('continue an incomplete unshelve operation')), + ('', 'keep', None, + _('keep shelve after unshelving'))], + _('hg unshelve [SHELVED]')) +def unshelve(ui, repo, *shelved, **opts): + """restore a shelved change to the working directory + + This command accepts an optional name of a shelved change to + restore. If none is given, the most recent shelved change is used. + + If a shelved change is applied successfully, the bundle that + contains the shelved changes is deleted afterwards. + + Since you can restore a shelved change on top of an arbitrary + commit, it is possible that unshelving will result in a conflict + between your changes and the commits you are unshelving onto. If + this occurs, you must resolve the conflict, then use + ``--continue`` to complete the unshelve operation. (The bundle + will not be deleted until you successfully complete the unshelve.) + + (Alternatively, you can use ``--abort`` to abandon an unshelve + that causes a conflict. This reverts the unshelved changes, and + does not delete the bundle.) + """ + abortf = opts['abort'] + continuef = opts['continue'] + if not abortf and not continuef: + cmdutil.checkunfinished(repo) + + if abortf or continuef: + if abortf and continuef: + raise util.Abort(_('cannot use both abort and continue')) + if shelved: + raise util.Abort(_('cannot combine abort/continue with ' + 'naming a shelved change')) + + try: + state = shelvedstate.load(repo) + except IOError, err: + if err.errno != errno.ENOENT: + raise + raise util.Abort(_('no unshelve operation underway')) + + if abortf: + return unshelveabort(ui, repo, state, opts) + elif continuef: + return unshelvecontinue(ui, repo, state, opts) + elif len(shelved) > 1: + raise util.Abort(_('can only unshelve one change at a time')) + elif not shelved: + shelved = listshelves(repo) + if not shelved: + raise util.Abort(_('no shelved changes to apply!')) + basename = util.split(shelved[0][1])[1] + ui.status(_("unshelving change '%s'\n") % basename) + else: + basename = shelved[0] + + shelvedfiles = readshelvedfiles(repo, basename) + + m, a, r, d = repo.status()[:4] + unsafe = set(m + a + r + d).intersection(shelvedfiles) + if unsafe: + ui.warn(_('the following shelved files have been modified:\n')) + for f in sorted(unsafe): + ui.warn(' %s\n' % f) + ui.warn(_('you must commit, revert, or shelve your changes before you ' + 'can proceed\n')) + raise util.Abort(_('cannot unshelve due to local changes\n')) + + wlock = lock = tr = None + try: + lock = repo.lock() + + tr = repo.transaction('unshelve', report=lambda x: None) + oldtiprev = len(repo) + try: + fp = shelvedfile(repo, basename, 'hg').opener() + gen = changegroup.readbundle(fp, fp.name) + repo.addchangegroup(gen, 'unshelve', 'bundle:' + fp.name) + nodes = [ctx.node() for ctx in repo.set('%d:', oldtiprev)] + phases.retractboundary(repo, phases.secret, nodes) + tr.close() + finally: + fp.close() + + tip = repo['tip'] + wctx = repo['.'] + ancestor = tip.ancestor(wctx) + + wlock = repo.wlock() + + if ancestor.node() != wctx.node(): + conflicts = hg.merge(repo, tip.node(), force=True, remind=False) + ms = merge.mergestate(repo) + stripnodes = [repo.changelog.node(rev) + for rev in xrange(oldtiprev, len(repo))] + if conflicts: + shelvedstate.save(repo, basename, stripnodes) + # Fix up the dirstate entries of files from the second + # parent as if we were not merging, except for those + # with unresolved conflicts. + parents = repo.parents() + revertfiles = set(parents[1].files()).difference(ms) + cmdutil.revert(ui, repo, parents[1], + (parents[0].node(), nullid), + *revertfiles, **{'no_backup': True}) + raise error.InterventionRequired( + _("unresolved conflicts (see 'hg resolve', then " + "'hg unshelve --continue')")) + finishmerge(ui, repo, ms, stripnodes, basename, opts) + else: + parent = tip.parents()[0] + hg.update(repo, parent.node()) + cmdutil.revert(ui, repo, tip, repo.dirstate.parents(), *tip.files(), + **{'no_backup': True}) + + prevquiet = ui.quiet + ui.quiet = True + try: + repo.rollback(force=True) + finally: + ui.quiet = prevquiet + + unshelvecleanup(ui, repo, basename, opts) + finally: + if tr: + tr.release() + lockmod.release(lock, wlock) + +@command('shelve', + [('A', 'addremove', None, + _('mark new/missing files as added/removed before shelving')), + ('', 'cleanup', None, + _('delete all shelved changes')), + ('', 'date', '', + _('shelve with the specified commit date'), _('DATE')), + ('d', 'delete', None, + _('delete the named shelved change(s)')), + ('l', 'list', None, + _('list current shelves')), + ('m', 'message', '', + _('use text as shelve message'), _('TEXT')), + ('n', 'name', '', + _('use the given name for the shelved commit'), _('NAME')), + ('p', 'patch', None, + _('show patch')), + ('', 'stat', None, + _('output diffstat-style summary of changes'))], + _('hg shelve')) +def shelvecmd(ui, repo, *pats, **opts): + '''save and set aside changes from the working directory + + Shelving takes files that "hg status" reports as not clean, saves + the modifications to a bundle (a shelved change), and reverts the + files so that their state in the working directory becomes clean. + + To restore these changes to the working directory, using "hg + unshelve"; this will work even if you switch to a different + commit. + + When no files are specified, "hg shelve" saves all not-clean + files. If specific files or directories are named, only changes to + those files are shelved. + + Each shelved change has a name that makes it easier to find later. + The name of a shelved change defaults to being based on the active + bookmark, or if there is no active bookmark, the current named + branch. To specify a different name, use ``--name``. + + To see a list of existing shelved changes, use the ``--list`` + option. For each shelved change, this will print its name, age, + and description; use ``--patch`` or ``--stat`` for more details. + + To delete specific shelved changes, use ``--delete``. To delete + all shelved changes, use ``--cleanup``. + ''' + cmdutil.checkunfinished(repo) + + def checkopt(opt, incompatible): + if opts[opt]: + for i in incompatible.split(): + if opts[i]: + raise util.Abort(_("options '--%s' and '--%s' may not be " + "used together") % (opt, i)) + return True + if checkopt('cleanup', 'addremove delete list message name patch stat'): + if pats: + raise util.Abort(_("cannot specify names when using '--cleanup'")) + return cleanupcmd(ui, repo) + elif checkopt('delete', 'addremove cleanup list message name patch stat'): + return deletecmd(ui, repo, pats) + elif checkopt('list', 'addremove cleanup delete message name'): + return listcmd(ui, repo, pats, opts) + else: + for i in ('patch', 'stat'): + if opts[i]: + raise util.Abort(_("option '--%s' may not be " + "used when shelving a change") % (i,)) + return createcmd(ui, repo, pats, opts) + +def extsetup(ui): + cmdutil.unfinishedstates.append( + [shelvedstate._filename, False, True, _('unshelve already in progress'), + _("use 'hg unshelve --continue' or 'hg unshelve --abort'")])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/strip.py Sat Oct 19 14:21:05 2013 -0700 @@ -0,0 +1,217 @@ +"""strip changesets and their descendents from history + +This extension allows to strip changesets and all their descendants from the +repository. See the command help for details. +""" +from mercurial.i18n import _ +from mercurial.node import nullid +from mercurial.lock import release +from mercurial import cmdutil, hg, scmutil, util +from mercurial import repair, bookmarks + +cmdtable = {} +command = cmdutil.command(cmdtable) +testedwith = 'internal' + +def checksubstate(repo, baserev=None): + '''return list of subrepos at a different revision than substate. + Abort if any subrepos have uncommitted changes.''' + inclsubs = [] + wctx = repo[None] + if baserev: + bctx = repo[baserev] + else: + bctx = wctx.parents()[0] + for s in sorted(wctx.substate): + if wctx.sub(s).dirty(True): + raise util.Abort( + _("uncommitted changes in subrepository %s") % s) + elif s not in bctx.substate or bctx.sub(s).dirty(): + inclsubs.append(s) + return inclsubs + +def checklocalchanges(repo, force=False, excsuffix=''): + cmdutil.checkunfinished(repo) + m, a, r, d = repo.status()[:4] + if not force: + if (m or a or r or d): + _("local changes found") # i18n tool detection + raise util.Abort(_("local changes found" + excsuffix)) + if checksubstate(repo): + _("local changed subrepos found") # i18n tool detection + raise util.Abort(_("local changed subrepos found" + excsuffix)) + return m, a, r, d + +def strip(ui, repo, revs, update=True, backup="all", force=None): + wlock = lock = None + try: + wlock = repo.wlock() + lock = repo.lock() + + if update: + checklocalchanges(repo, force=force) + urev, p2 = repo.changelog.parents(revs[0]) + if p2 != nullid and p2 in [x.node for x in repo.mq.applied]: + urev = p2 + hg.clean(repo, urev) + repo.dirstate.write() + + repair.strip(ui, repo, revs, backup) + finally: + release(lock, wlock) + + +@command("strip", + [ + ('r', 'rev', [], _('strip specified revision (optional, ' + 'can specify revisions without this ' + 'option)'), _('REV')), + ('f', 'force', None, _('force removal of changesets, discard ' + 'uncommitted changes (no backup)')), + ('b', 'backup', None, _('bundle only changesets with local revision' + ' number greater than REV which are not' + ' descendants of REV (DEPRECATED)')), + ('', 'no-backup', None, _('no backups')), + ('', 'nobackup', None, _('no backups (DEPRECATED)')), + ('n', '', None, _('ignored (DEPRECATED)')), + ('k', 'keep', None, _("do not modify working copy during strip")), + ('B', 'bookmark', '', _("remove revs only reachable from given" + " bookmark"))], + _('hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...')) +def stripcmd(ui, repo, *revs, **opts): + """strip changesets and all their descendants from the repository + + The strip command removes the specified changesets and all their + descendants. If the working directory has uncommitted changes, the + operation is aborted unless the --force flag is supplied, in which + case changes will be discarded. + + If a parent of the working directory is stripped, then the working + directory will automatically be updated to the most recent + available ancestor of the stripped parent after the operation + completes. + + Any stripped changesets are stored in ``.hg/strip-backup`` as a + bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can + be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`, + where BUNDLE is the bundle file created by the strip. Note that + the local revision numbers will in general be different after the + restore. + + Use the --no-backup option to discard the backup bundle once the + operation completes. + + Strip is not a history-rewriting operation and can be used on + changesets in the public phase. But if the stripped changesets have + been pushed to a remote repository you will likely pull them again. + + Return 0 on success. + """ + backup = 'all' + if opts.get('backup'): + backup = 'strip' + elif opts.get('no_backup') or opts.get('nobackup'): + backup = 'none' + + cl = repo.changelog + revs = list(revs) + opts.get('rev') + revs = set(scmutil.revrange(repo, revs)) + + if opts.get('bookmark'): + mark = opts.get('bookmark') + marks = repo._bookmarks + if mark not in marks: + raise util.Abort(_("bookmark '%s' not found") % mark) + + # If the requested bookmark is not the only one pointing to a + # a revision we have to only delete the bookmark and not strip + # anything. revsets cannot detect that case. + uniquebm = True + for m, n in marks.iteritems(): + if m != mark and n == repo[mark].node(): + uniquebm = False + break + if uniquebm: + rsrevs = repo.revs("ancestors(bookmark(%s)) - " + "ancestors(head() and not bookmark(%s)) - " + "ancestors(bookmark() and not bookmark(%s))", + mark, mark, mark) + revs.update(set(rsrevs)) + if not revs: + del marks[mark] + marks.write() + ui.write(_("bookmark '%s' deleted\n") % mark) + + if not revs: + raise util.Abort(_('empty revision set')) + + descendants = set(cl.descendants(revs)) + strippedrevs = revs.union(descendants) + roots = revs.difference(descendants) + + update = False + # if one of the wdir parent is stripped we'll need + # to update away to an earlier revision + for p in repo.dirstate.parents(): + if p != nullid and cl.rev(p) in strippedrevs: + update = True + break + + rootnodes = set(cl.node(r) for r in roots) + + q = getattr(repo, 'mq', None) + if q is not None and q.applied: + # refresh queue state if we're about to strip + # applied patches + if cl.rev(repo.lookup('qtip')) in strippedrevs: + q.applieddirty = True + start = 0 + end = len(q.applied) + for i, statusentry in enumerate(q.applied): + if statusentry.node in rootnodes: + # if one of the stripped roots is an applied + # patch, only part of the queue is stripped + start = i + break + del q.applied[start:end] + q.savedirty() + + revs = sorted(rootnodes) + if update and opts.get('keep'): + wlock = repo.wlock() + try: + urev, p2 = repo.changelog.parents(revs[0]) + if (util.safehasattr(repo, 'mq') and p2 != nullid + and p2 in [x.node for x in repo.mq.applied]): + urev = p2 + uctx = repo[urev] + + # only reset the dirstate for files that would actually change + # between the working context and uctx + descendantrevs = repo.revs("%s::." % uctx.rev()) + changedfiles = [] + for rev in descendantrevs: + # blindly reset the files, regardless of what actually changed + changedfiles.extend(repo[rev].files()) + + # reset files that only changed in the dirstate too + dirstate = repo.dirstate + dirchanges = [f for f in dirstate if dirstate[f] != 'n'] + changedfiles.extend(dirchanges) + + repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles) + repo.dirstate.write() + update = False + finally: + wlock.release() + + if opts.get('bookmark'): + if mark == repo._bookmarkcurrent: + bookmarks.setcurrent(repo, None) + del marks[mark] + marks.write() + ui.write(_("bookmark '%s' deleted\n") % mark) + + strip(ui, repo, revs, backup=backup, update=update, force=opts.get('force')) + + return 0
--- a/mercurial/bookmarks.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/bookmarks.py Sat Oct 19 14:21:05 2013 -0700 @@ -8,7 +8,7 @@ from mercurial.i18n import _ from mercurial.node import hex from mercurial import encoding, error, util, obsolete -import errno, os +import errno class bmstore(dict): """Storage for bookmarks. @@ -70,7 +70,7 @@ # touch 00changelog.i so hgweb reloads bookmarks (no lock needed) try: - os.utime(repo.sjoin('00changelog.i'), None) + repo.svfs.utime('00changelog.i', None) except OSError: pass @@ -126,7 +126,7 @@ wlock = repo.wlock() try: try: - util.unlink(repo.join('bookmarks.current')) + repo.vfs.unlink('bookmarks.current') repo._bookmarkcurrent = None except OSError, inst: if inst.errno != errno.ENOENT:
--- a/mercurial/branchmap.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/branchmap.py Sat Oct 19 14:21:05 2013 -0700 @@ -198,20 +198,7 @@ self.tipnode = cl.node(tiprev) self.tiprev = tiprev - # There may be branches that cease to exist when the last commit in the - # branch was stripped. This code filters them out. Note that the - # branch that ceased to exist may not be in newbranches because - # newbranches is the set of candidate heads, which when you strip the - # last commit in a branch will be the parent branch. - droppednodes = [] - for branch in self.keys(): - nodes = [head for head in self[branch] - if cl.hasnode(head)] - if not nodes: - droppednodes.extend(nodes) - del self[branch] - if ((not self.validfor(repo)) or (self.tipnode in droppednodes)): - + if not self.validfor(repo): # cache key are not valid anymore self.tipnode = nullid self.tiprev = nullrev
--- a/mercurial/bundlerepo.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/bundlerepo.py Sat Oct 19 14:21:05 2013 -0700 @@ -120,7 +120,7 @@ chain.append(iterrev) iterrev = self.index[iterrev][3] if text is None: - text = revlog.revlog.revision(self, iterrev) + text = self.baserevision(iterrev) while chain: delta = self._chunk(chain.pop()) @@ -130,6 +130,12 @@ self._cache = (node, rev, text) return text + def baserevision(self, nodeorrev): + # Revlog subclasses may override 'revision' method to modify format of + # content retrieved from revlog. To use bundlerevlog with such class one + # needs to override 'baserevision' and make more specific call here. + return revlog.revlog.revision(self, nodeorrev) + def addrevision(self, text, transaction, link, p1=None, p2=None, d=None): raise NotImplementedError def addgroup(self, revs, linkmapper, transaction): @@ -146,12 +152,21 @@ bundlerevlog.__init__(self, opener, self.indexfile, bundle, linkmapper) + def baserevision(self, nodeorrev): + # Although changelog doesn't override 'revision' method, some extensions + # may replace this class with another that does. Same story with + # manifest and filelog classes. + return changelog.changelog.revision(self, nodeorrev) + class bundlemanifest(bundlerevlog, manifest.manifest): def __init__(self, opener, bundle, linkmapper): manifest.manifest.__init__(self, opener) bundlerevlog.__init__(self, opener, self.indexfile, bundle, linkmapper) + def baserevision(self, nodeorrev): + return manifest.manifest.revision(self, nodeorrev) + class bundlefilelog(bundlerevlog, filelog.filelog): def __init__(self, opener, path, bundle, linkmapper, repo): filelog.filelog.__init__(self, opener, path) @@ -159,6 +174,9 @@ linkmapper) self._repo = repo + def baserevision(self, nodeorrev): + return filelog.filelog.revision(self, nodeorrev) + def _file(self, f): self._repo.file(f)
--- a/mercurial/changelog.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/changelog.py Sat Oct 19 14:21:05 2013 -0700 @@ -59,11 +59,12 @@ class appender(object): '''the changelog index must be updated last on disk, so we use this class to delay writes to it''' - def __init__(self, fp, buf): + def __init__(self, vfs, name, mode, buf): self.data = buf + fp = vfs(name, mode) self.fp = fp self.offset = fp.tell() - self.size = util.fstat(fp).st_size + self.size = vfs.fstat(fp).st_size def end(self): return self.size + len("".join(self.data)) @@ -114,7 +115,7 @@ if divert: return opener(name + ".a", mode.replace('a', 'w')) # otherwise, divert to memory - return appender(opener(name, mode), buf) + return appender(opener, name, mode, buf) return o class changelog(revlog.revlog): @@ -224,10 +225,10 @@ self.opener = self._realopener # move redirected index data back into place if self._divert: - nfile = self.opener(self.indexfile + ".a") - n = nfile.name + tmpname = self.indexfile + ".a" + nfile = self.opener.open(tmpname) nfile.close() - util.rename(n, n[:-2]) + self.opener.rename(tmpname, self.indexfile) elif self._delaybuf: fp = self.opener(self.indexfile, 'a') fp.write("".join(self._delaybuf))
--- a/mercurial/cmdutil.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/cmdutil.py Sat Oct 19 14:21:05 2013 -0700 @@ -84,7 +84,7 @@ raise util.Abort(_('outstanding uncommitted merge')) modified, added, removed, deleted = repo.status()[:4] if modified or added or removed or deleted: - raise util.Abort(_("outstanding uncommitted changes")) + raise util.Abort(_('uncommitted changes')) ctx = repo[None] for s in sorted(ctx.substate): if ctx.sub(s).dirty(): @@ -468,6 +468,13 @@ runargs=None, appendpid=False): '''Run a command as a service.''' + def writepid(pid): + if opts['pid_file']: + mode = appendpid and 'a' or 'w' + fp = open(opts['pid_file'], mode) + fp.write(str(pid) + '\n') + fp.close() + if opts['daemon'] and not opts['daemon_pipefds']: # Signal child process startup with file removal lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-') @@ -490,6 +497,7 @@ pid = util.rundetached(runargs, condfn) if pid < 0: raise util.Abort(_('child process failed to start')) + writepid(pid) finally: try: os.unlink(lockpath) @@ -504,11 +512,8 @@ if initfn: initfn() - if opts['pid_file']: - mode = appendpid and 'a' or 'w' - fp = open(opts['pid_file'], mode) - fp.write(str(os.getpid()) + '\n') - fp.close() + if not opts['daemon']: + writepid(os.getpid()) if opts['daemon_pipefds']: lockpath = opts['daemon_pipefds'] @@ -928,7 +933,7 @@ regular display via changeset_printer() is done. """ # options - patch = False + patch = None if opts.get('patch') or opts.get('stat'): patch = scmutil.matchall(repo) @@ -1172,12 +1177,34 @@ 'filenames')) # The slow path checks files modified in every changeset. - for i in sorted(revs): - ctx = change(i) - matches = filter(match, ctx.files()) - if matches: - fncache[i] = matches - wanted.add(i) + # This is really slow on large repos, so compute the set lazily. + class lazywantedset(object): + def __init__(self): + self.set = set() + self.revs = set(revs) + + # No need to worry about locality here because it will be accessed + # in the same order as the increasing window below. + def __contains__(self, value): + if value in self.set: + return True + elif not value in self.revs: + return False + else: + self.revs.discard(value) + ctx = change(value) + matches = filter(match, ctx.files()) + if matches: + fncache[value] = matches + self.set.add(value) + return True + return False + + def discard(self, value): + self.revs.discard(value) + self.set.discard(value) + + wanted = lazywantedset() class followfilter(object): def __init__(self, onlyfirst=False):
--- a/mercurial/commands.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/commands.py Sat Oct 19 14:21:05 2013 -0700 @@ -12,7 +12,8 @@ import hg, scmutil, util, revlog, copies, error, bookmarks import patch, help, encoding, templatekw, discovery import archival, changegroup, cmdutil, hbisect -import sshserver, hgweb, hgweb.server, commandserver +import sshserver, hgweb, commandserver +from hgweb import server as hgweb_server import merge as mergemod import minirst, revset, fileset import dagparser, context, simplemerge, graphmod @@ -1807,7 +1808,7 @@ [('c', 'changelog', False, _('open changelog')), ('m', 'manifest', False, _('open manifest'))], _('-c|-m|FILE REV')) -def debugdata(ui, repo, file_, rev = None, **opts): +def debugdata(ui, repo, file_, rev=None, **opts): """dump the contents of a data file revision""" if opts.get('changelog') or opts.get('manifest'): file_, rev = None, file_ @@ -1918,11 +1919,12 @@ ui.write("%s\n" % f) @command('debugfsinfo', [], _('[PATH]')) -def debugfsinfo(ui, path = "."): +def debugfsinfo(ui, path="."): """show information detected about current filesystem""" util.writefile('.debugfsinfo', '') ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no')) ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no')) + ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no')) ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo') and 'yes' or 'no')) os.unlink('.debugfsinfo') @@ -1972,7 +1974,7 @@ ('m', 'manifest', False, _('open manifest')), ('f', 'format', 0, _('revlog format'), _('FORMAT'))], _('[-f FORMAT] -c|-m|FILE')) -def debugindex(ui, repo, file_ = None, **opts): +def debugindex(ui, repo, file_=None, **opts): """dump the contents of an index file""" r = cmdutil.openrevlog(repo, 'debugindex', file_, opts) format = opts.get('format', 0) @@ -2353,7 +2355,7 @@ ('m', 'manifest', False, _('open manifest')), ('d', 'dump', False, _('dump index data'))], _('-c|-m|FILE')) -def debugrevlog(ui, repo, file_ = None, **opts): +def debugrevlog(ui, repo, file_=None, **opts): """show data and statistics about a revlog""" r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts) @@ -3019,11 +3021,12 @@ if n in ids: r = repo[n].rev() if r in revs: - ui.warn(_('skipping already grafted revision %s\n') % r) + ui.warn(_('skipping revision %s (already grafted to %s)\n') + % (r, rev)) revs.remove(r) elif ids[n] in revs: ui.warn(_('skipping already grafted revision %s ' - '(same origin %d)\n') % (ids[n], r)) + '(%s also has origin %d)\n') % (ids[n], rev, r)) revs.remove(ids[n]) elif ctx.hex() in ids: r = ids[ctx.hex()] @@ -4525,6 +4528,8 @@ ret = hg.update(repo, checkout) except util.Abort, inst: ui.warn(_("not updating: %s\n") % str(inst)) + if inst.hint: + ui.warn(_("(%s)\n") % inst.hint) return 0 if not ret and not checkout: if bookmarks.update(repo, [movemarkfrom], repo['.'].node()): @@ -5182,7 +5187,7 @@ class service(object): def init(self): util.setsignalhandler() - self.httpd = hgweb.server.create_server(ui, app) + self.httpd = hgweb_server.create_server(ui, app) if opts['port'] and not ui.verbose: return @@ -5846,7 +5851,7 @@ if check: c = repo[None] if c.dirty(merge=False, branch=False, missing=True): - raise util.Abort(_("uncommitted local changes")) + raise util.Abort(_("uncommitted changes")) if rev is None: rev = repo[repo[None].branch()].rev() mergemod._checkunknown(repo, repo[None], repo[rev])
--- a/mercurial/context.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/context.py Sat Oct 19 14:21:05 2013 -0700 @@ -16,11 +16,197 @@ propertycache = util.propertycache -class changectx(object): +class basectx(object): + """A basectx object represents the common logic for its children: + changectx: read-only context that is already present in the repo, + workingctx: a context that represents the working directory and can + be committed, + memctx: a context that represents changes in-memory and can also + be committed.""" + def __new__(cls, repo, changeid='', *args, **kwargs): + if isinstance(changeid, basectx): + return changeid + + o = super(basectx, cls).__new__(cls) + + o._repo = repo + o._rev = nullrev + o._node = nullid + + return o + + def __str__(self): + return short(self.node()) + + def __int__(self): + return self.rev() + + def __repr__(self): + return "<%s %s>" % (type(self).__name__, str(self)) + + def __eq__(self, other): + try: + return type(self) == type(other) and self._rev == other._rev + except AttributeError: + return False + + def __ne__(self, other): + return not (self == other) + + def __contains__(self, key): + return key in self._manifest + + def __getitem__(self, key): + return self.filectx(key) + + def __iter__(self): + for f in sorted(self._manifest): + yield f + + @propertycache + def substate(self): + return subrepo.state(self, self._repo.ui) + + def rev(self): + return self._rev + def node(self): + return self._node + def hex(self): + return hex(self.node()) + def manifest(self): + return self._manifest + def phasestr(self): + return phases.phasenames[self.phase()] + def mutable(self): + return self.phase() > phases.public + + def obsolete(self): + """True if the changeset is obsolete""" + return self.rev() in obsmod.getrevs(self._repo, 'obsolete') + + def extinct(self): + """True if the changeset is extinct""" + return self.rev() in obsmod.getrevs(self._repo, 'extinct') + + def unstable(self): + """True if the changeset is not obsolete but it's ancestor are""" + return self.rev() in obsmod.getrevs(self._repo, 'unstable') + + def bumped(self): + """True if the changeset try to be a successor of a public changeset + + Only non-public and non-obsolete changesets may be bumped. + """ + return self.rev() in obsmod.getrevs(self._repo, 'bumped') + + def divergent(self): + """Is a successors of a changeset with multiple possible successors set + + Only non-public and non-obsolete changesets may be divergent. + """ + return self.rev() in obsmod.getrevs(self._repo, 'divergent') + + def troubled(self): + """True if the changeset is either unstable, bumped or divergent""" + return self.unstable() or self.bumped() or self.divergent() + + def troubles(self): + """return the list of troubles affecting this changesets. + + Troubles are returned as strings. possible values are: + - unstable, + - bumped, + - divergent. + """ + troubles = [] + if self.unstable(): + troubles.append('unstable') + if self.bumped(): + troubles.append('bumped') + if self.divergent(): + troubles.append('divergent') + return troubles + + def parents(self): + """return contexts for each parent changeset""" + return self._parents + + def p1(self): + return self._parents[0] + + def p2(self): + if len(self._parents) == 2: + return self._parents[1] + return changectx(self._repo, -1) + + def _fileinfo(self, path): + if '_manifest' in self.__dict__: + try: + return self._manifest[path], self._manifest.flags(path) + except KeyError: + raise error.ManifestLookupError(self._node, path, + _('not found in manifest')) + if '_manifestdelta' in self.__dict__ or path in self.files(): + if path in self._manifestdelta: + return (self._manifestdelta[path], + self._manifestdelta.flags(path)) + node, flag = self._repo.manifest.find(self._changeset[0], path) + if not node: + raise error.ManifestLookupError(self._node, path, + _('not found in manifest')) + + return node, flag + + def filenode(self, path): + return self._fileinfo(path)[0] + + def flags(self, path): + try: + return self._fileinfo(path)[1] + except error.LookupError: + return '' + + def sub(self, path): + return subrepo.subrepo(self, path) + + def match(self, pats=[], include=None, exclude=None, default='glob'): + r = self._repo + return matchmod.match(r.root, r.getcwd(), pats, + include, exclude, default, + auditor=r.auditor, ctx=self) + + def diff(self, ctx2=None, match=None, **opts): + """Returns a diff generator for the given contexts and matcher""" + if ctx2 is None: + ctx2 = self.p1() + if ctx2 is not None: + ctx2 = self._repo[ctx2] + diffopts = patch.diffopts(self._repo.ui, opts) + return patch.diff(self._repo, ctx2.node(), self.node(), + match=match, opts=diffopts) + + @propertycache + def _dirs(self): + return scmutil.dirs(self._manifest) + + def dirs(self): + return self._dirs + + def dirty(self): + return False + +class changectx(basectx): """A changecontext object makes access to data related to a particular - changeset convenient.""" + changeset convenient. It represents a read-only context already presnt in + the repo.""" def __init__(self, repo, changeid=''): """changeid is a revision number, node, or tag""" + + # since basectx.__new__ already took care of copying the object, we + # don't need to do anything in __init__, so we just exit here + if isinstance(changeid, basectx): + return + if changeid == '': changeid = '.' self._repo = repo @@ -114,30 +300,12 @@ raise error.RepoLookupError( _("unknown revision '%s'") % changeid) - def __str__(self): - return short(self.node()) - - def __int__(self): - return self.rev() - - def __repr__(self): - return "<changectx %s>" % str(self) - def __hash__(self): try: return hash(self._rev) except AttributeError: return id(self) - def __eq__(self, other): - try: - return self._rev == other._rev - except AttributeError: - return False - - def __ne__(self, other): - return not (self == other) - def __nonzero__(self): return self._rev != nullrev @@ -160,33 +328,11 @@ p = p[:-1] return [changectx(self._repo, x) for x in p] - @propertycache - def substate(self): - return subrepo.state(self, self._repo.ui) - - def __contains__(self, key): - return key in self._manifest - - def __getitem__(self, key): - return self.filectx(key) - - def __iter__(self): - for f in sorted(self._manifest): - yield f - def changeset(self): return self._changeset - def manifest(self): - return self._manifest def manifestnode(self): return self._changeset[0] - def rev(self): - return self._rev - def node(self): - return self._node - def hex(self): - return hex(self._node) def user(self): return self._changeset[1] def date(self): @@ -207,25 +353,9 @@ return self._repo.nodebookmarks(self._node) def phase(self): return self._repo._phasecache.phase(self._repo, self._rev) - def phasestr(self): - return phases.phasenames[self.phase()] - def mutable(self): - return self.phase() > phases.public def hidden(self): return self._rev in repoview.filterrevs(self._repo, 'visible') - def parents(self): - """return contexts for each parent changeset""" - return self._parents - - def p1(self): - return self._parents[0] - - def p2(self): - if len(self._parents) == 2: - return self._parents[1] - return changectx(self._repo, -1) - def children(self): """return contexts for each child changeset""" c = self._repo.changelog.children(self._node) @@ -239,80 +369,6 @@ for d in self._repo.changelog.descendants([self._rev]): yield changectx(self._repo, d) - def obsolete(self): - """True if the changeset is obsolete""" - return self.rev() in obsmod.getrevs(self._repo, 'obsolete') - - def extinct(self): - """True if the changeset is extinct""" - return self.rev() in obsmod.getrevs(self._repo, 'extinct') - - def unstable(self): - """True if the changeset is not obsolete but it's ancestor are""" - return self.rev() in obsmod.getrevs(self._repo, 'unstable') - - def bumped(self): - """True if the changeset try to be a successor of a public changeset - - Only non-public and non-obsolete changesets may be bumped. - """ - return self.rev() in obsmod.getrevs(self._repo, 'bumped') - - def divergent(self): - """Is a successors of a changeset with multiple possible successors set - - Only non-public and non-obsolete changesets may be divergent. - """ - return self.rev() in obsmod.getrevs(self._repo, 'divergent') - - def troubled(self): - """True if the changeset is either unstable, bumped or divergent""" - return self.unstable() or self.bumped() or self.divergent() - - def troubles(self): - """return the list of troubles affecting this changesets. - - Troubles are returned as strings. possible values are: - - unstable, - - bumped, - - divergent. - """ - troubles = [] - if self.unstable(): - troubles.append('unstable') - if self.bumped(): - troubles.append('bumped') - if self.divergent(): - troubles.append('divergent') - return troubles - - def _fileinfo(self, path): - if '_manifest' in self.__dict__: - try: - return self._manifest[path], self._manifest.flags(path) - except KeyError: - raise error.ManifestLookupError(self._node, path, - _('not found in manifest')) - if '_manifestdelta' in self.__dict__ or path in self.files(): - if path in self._manifestdelta: - return (self._manifestdelta[path], - self._manifestdelta.flags(path)) - node, flag = self._repo.manifest.find(self._changeset[0], path) - if not node: - raise error.ManifestLookupError(self._node, path, - _('not found in manifest')) - - return node, flag - - def filenode(self, path): - return self._fileinfo(path)[0] - - def flags(self, path): - try: - return self._fileinfo(path)[1] - except error.LookupError: - return '' - def filectx(self, path, fileid=None, filelog=None): """get a file context from this changeset""" if fileid is None: @@ -353,83 +409,15 @@ if match.bad(fn, _('no such file in rev %s') % self) and match(fn): yield fn - def sub(self, path): - return subrepo.subrepo(self, path) - - def match(self, pats=[], include=None, exclude=None, default='glob'): - r = self._repo - return matchmod.match(r.root, r.getcwd(), pats, - include, exclude, default, - auditor=r.auditor, ctx=self) - - def diff(self, ctx2=None, match=None, **opts): - """Returns a diff generator for the given contexts and matcher""" - if ctx2 is None: - ctx2 = self.p1() - if ctx2 is not None and not isinstance(ctx2, changectx): - ctx2 = self._repo[ctx2] - diffopts = patch.diffopts(self._repo.ui, opts) - return patch.diff(self._repo, ctx2.node(), self.node(), - match=match, opts=diffopts) - - @propertycache - def _dirs(self): - return scmutil.dirs(self._manifest) - - def dirs(self): - return self._dirs - - def dirty(self): - return False - -class filectx(object): - """A filecontext object makes access to data related to a particular - filerevision convenient.""" - def __init__(self, repo, path, changeid=None, fileid=None, - filelog=None, changectx=None): - """changeid can be a changeset revision, node, or tag. - fileid can be a file revision or node.""" - self._repo = repo - self._path = path - - assert (changeid is not None - or fileid is not None - or changectx is not None), \ - ("bad args: changeid=%r, fileid=%r, changectx=%r" - % (changeid, fileid, changectx)) - - if filelog is not None: - self._filelog = filelog - - if changeid is not None: - self._changeid = changeid - if changectx is not None: - self._changectx = changectx - if fileid is not None: - self._fileid = fileid - - @propertycache - def _changectx(self): - try: - return changectx(self._repo, self._changeid) - except error.RepoLookupError: - # Linkrev may point to any revision in the repository. When the - # repository is filtered this may lead to `filectx` trying to build - # `changectx` for filtered revision. In such case we fallback to - # creating `changectx` on the unfiltered version of the reposition. - # This fallback should not be an issue because `changectx` from - # `filectx` are not used in complex operations that care about - # filtering. - # - # This fallback is a cheap and dirty fix that prevent several - # crashes. It does not ensure the behavior is correct. However the - # behavior was not correct before filtering either and "incorrect - # behavior" is seen as better as "crash" - # - # Linkrevs have several serious troubles with filtering that are - # complicated to solve. Proper handling of the issue here should be - # considered when solving linkrev issue are on the table. - return changectx(self._repo.unfiltered(), self._changeid) +class basefilectx(object): + """A filecontext object represents the common logic for its children: + filectx: read-only access to a filerevision that is already present + in the repo, + workingfilectx: a filecontext that represents files from the working + directory, + memfilectx: a filecontext that represents files in-memory.""" + def __new__(cls, repo, path, *args, **kwargs): + return super(basefilectx, cls).__new__(cls) @propertycache def _filelog(self): @@ -468,10 +456,10 @@ return False def __str__(self): - return "%s@%s" % (self.path(), short(self.node())) + return "%s@%s" % (self.path(), self._changectx) def __repr__(self): - return "<filectx %s>" % str(self) + return "<%s %s>" % (type(self).__name__, str(self)) def __hash__(self): try: @@ -481,7 +469,7 @@ def __eq__(self, other): try: - return (self._path == other._path + return (type(self) == type(other) and self._path == other._path and self._filenode == other._filenode) except AttributeError: return False @@ -489,12 +477,6 @@ def __ne__(self, other): return not (self == other) - def filectx(self, fileid): - '''opens an arbitrary revision of the file without - opening a new filelog''' - return filectx(self._repo, self._path, fileid=fileid, - filelog=self._filelog) - def filerev(self): return self._filerev def filenode(self): @@ -510,7 +492,7 @@ def node(self): return self._changectx.node() def hex(self): - return hex(self.node()) + return self._changectx.hex() def user(self): return self._changectx.user() def date(self): @@ -532,12 +514,8 @@ def changectx(self): return self._changectx - def data(self): - return self._filelog.read(self._filenode) def path(self): return self._path - def size(self): - return self._filelog.size(self._filerev) def isbinary(self): try: @@ -560,31 +538,6 @@ return True - def renamed(self): - """check if file was actually renamed in this changeset revision - - If rename logged in file revision, we report copy for changeset only - if file revisions linkrev points back to the changeset in question - or both changeset parents contain different file revisions. - """ - - renamed = self._filelog.renamed(self._filenode) - if not renamed: - return renamed - - if self.rev() == self.linkrev(): - return renamed - - name = self.path() - fnode = self._filenode - for p in self._changectx.parents(): - try: - if fnode == p.filenode(name): - return None - except error.LookupError: - pass - return renamed - def parents(self): p = self._path fl = self._filelog @@ -606,12 +559,6 @@ return p[1] return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog) - def children(self): - # hard for renames - c = self._filelog.children(self._filenode) - return [filectx(self._repo, self._path, fileid=x, - filelog=self._filelog) for x in c] - def annotate(self, follow=False, linenumber=None, diffopts=None): '''returns a list of tuples of (ctx, line) for each line in the file, where ctx is the filectx of the node where @@ -783,15 +730,100 @@ self._copycache[sc2] = copies.pathcopies(c2) return self._copycache[sc2] -class workingctx(changectx): - """A workingctx object makes access to data related to - the current working directory convenient. - date - any valid date string or (unixtime, offset), or None. - user - username string, or None. - extra - a dictionary of extra values, or None. - changes - a list of file lists as returned by localrepo.status() - or None to use the repository status. - """ +class filectx(basefilectx): + """A filecontext object makes access to data related to a particular + filerevision convenient.""" + def __init__(self, repo, path, changeid=None, fileid=None, + filelog=None, changectx=None): + """changeid can be a changeset revision, node, or tag. + fileid can be a file revision or node.""" + self._repo = repo + self._path = path + + assert (changeid is not None + or fileid is not None + or changectx is not None), \ + ("bad args: changeid=%r, fileid=%r, changectx=%r" + % (changeid, fileid, changectx)) + + if filelog is not None: + self._filelog = filelog + + if changeid is not None: + self._changeid = changeid + if changectx is not None: + self._changectx = changectx + if fileid is not None: + self._fileid = fileid + + @propertycache + def _changectx(self): + try: + return changectx(self._repo, self._changeid) + except error.RepoLookupError: + # Linkrev may point to any revision in the repository. When the + # repository is filtered this may lead to `filectx` trying to build + # `changectx` for filtered revision. In such case we fallback to + # creating `changectx` on the unfiltered version of the reposition. + # This fallback should not be an issue because `changectx` from + # `filectx` are not used in complex operations that care about + # filtering. + # + # This fallback is a cheap and dirty fix that prevent several + # crashes. It does not ensure the behavior is correct. However the + # behavior was not correct before filtering either and "incorrect + # behavior" is seen as better as "crash" + # + # Linkrevs have several serious troubles with filtering that are + # complicated to solve. Proper handling of the issue here should be + # considered when solving linkrev issue are on the table. + return changectx(self._repo.unfiltered(), self._changeid) + + def filectx(self, fileid): + '''opens an arbitrary revision of the file without + opening a new filelog''' + return filectx(self._repo, self._path, fileid=fileid, + filelog=self._filelog) + + def data(self): + return self._filelog.read(self._filenode) + def size(self): + return self._filelog.size(self._filerev) + + def renamed(self): + """check if file was actually renamed in this changeset revision + + If rename logged in file revision, we report copy for changeset only + if file revisions linkrev points back to the changeset in question + or both changeset parents contain different file revisions. + """ + + renamed = self._filelog.renamed(self._filenode) + if not renamed: + return renamed + + if self.rev() == self.linkrev(): + return renamed + + name = self.path() + fnode = self._filenode + for p in self._changectx.parents(): + try: + if fnode == p.filenode(name): + return None + except error.LookupError: + pass + return renamed + + def children(self): + # hard for renames + c = self._filelog.children(self._filenode) + return [filectx(self._repo, self._path, fileid=x, + filelog=self._filelog) for x in c] + +class committablectx(basectx): + """A committablectx object provides common functionality for a context that + wants the ability to commit, e.g. workingctx or memctx.""" def __init__(self, repo, text="", user=None, date=None, extra=None, changes=None): self._repo = repo @@ -827,9 +859,6 @@ def __str__(self): return str(self._parents[0]) + "+" - def __repr__(self): - return "<workingctx %s>" % str(self) - def __nonzero__(self): return True @@ -904,12 +933,6 @@ return man - def __iter__(self): - d = self._repo.dirstate - for f in d: - if d[f] != 'r': - yield f - @propertycache def _status(self): return self._repo.status()[:4] @@ -922,13 +945,6 @@ def _date(self): return util.makedate() - @propertycache - def _parents(self): - p = self._repo.dirstate.parents() - if p[1] == nullid: - p = p[:-1] - return [changectx(self._repo, x) for x in p] - def status(self, ignored=False, clean=False, unknown=False): """Explicit status query Unless this method is used to query the working copy status, the @@ -945,8 +961,6 @@ self._status = stat[:4] return stat - def manifest(self): - return self._manifest def user(self): return self._user or self._repo.ui.username() def date(self): @@ -1016,11 +1030,6 @@ except OSError: return '' - def filectx(self, path, filelog=None): - """get a file context from the working directory""" - return workingfilectx(self._repo, path, workingctx=self, - filelog=filelog) - def ancestor(self, c2): """return the ancestor context of self and c2""" return self._parents[0].ancestor(c2) # punt on two parents for now @@ -1029,6 +1038,61 @@ return sorted(self._repo.dirstate.walk(match, sorted(self.substate), True, False)) + def ancestors(self): + for a in self._repo.changelog.ancestors( + [p.rev() for p in self._parents]): + yield changectx(self._repo, a) + + def markcommitted(self, node): + """Perform post-commit cleanup necessary after committing this ctx + + Specifically, this updates backing stores this working context + wraps to reflect the fact that the changes reflected by this + workingctx have been committed. For example, it marks + modified and added files as normal in the dirstate. + + """ + + for f in self.modified() + self.added(): + self._repo.dirstate.normal(f) + for f in self.removed(): + self._repo.dirstate.drop(f) + self._repo.dirstate.setparents(node) + + def dirs(self): + return self._repo.dirstate.dirs() + +class workingctx(committablectx): + """A workingctx object makes access to data related to + the current working directory convenient. + date - any valid date string or (unixtime, offset), or None. + user - username string, or None. + extra - a dictionary of extra values, or None. + changes - a list of file lists as returned by localrepo.status() + or None to use the repository status. + """ + def __init__(self, repo, text="", user=None, date=None, extra=None, + changes=None): + super(workingctx, self).__init__(repo, text, user, date, extra, changes) + + def __iter__(self): + d = self._repo.dirstate + for f in d: + if d[f] != 'r': + yield f + + @propertycache + def _parents(self): + p = self._repo.dirstate.parents() + if p[1] == nullid: + p = p[:-1] + return [changectx(self._repo, x) for x in p] + + def filectx(self, path, filelog=None): + """get a file context from the working directory""" + return workingfilectx(self._repo, path, workingctx=self, + filelog=filelog) + def dirty(self, missing=False, merge=True, branch=True): "check whether a working directory is modified" # check subrepos first @@ -1047,11 +1111,11 @@ ui, ds = self._repo.ui, self._repo.dirstate try: rejected = [] + lstat = self._repo.wvfs.lstat for f in list: scmutil.checkportable(ui, join(f)) - p = self._repo.wjoin(f) try: - st = os.lstat(p) + st = lstat(f) except OSError: ui.warn(_("%s does not exist!\n") % join(f)) rejected.append(f) @@ -1065,7 +1129,7 @@ if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)): ui.warn(_("%s not added: only files and symlinks " "supported currently\n") % join(f)) - rejected.append(p) + rejected.append(f) elif ds[f] in 'amn': ui.warn(_("%s already tracked!\n") % join(f)) elif ds[f] == 'r': @@ -1093,11 +1157,6 @@ finally: wlock.release() - def ancestors(self): - for a in self._repo.changelog.ancestors( - [p.rev() for p in self._parents]): - yield changectx(self._repo, a) - def undelete(self, list): pctxs = self.parents() wlock = self._repo.wlock() @@ -1114,10 +1173,14 @@ wlock.release() def copy(self, source, dest): - p = self._repo.wjoin(dest) - if not os.path.lexists(p): + try: + st = self._repo.wvfs.lstat(dest) + except OSError, err: + if err.errno != errno.ENOENT: + raise self._repo.ui.warn(_("%s does not exist!\n") % dest) - elif not (os.path.isfile(p) or os.path.islink(p)): + return + if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)): self._repo.ui.warn(_("copy failed: %s is not a file or a " "symbolic link\n") % dest) else: @@ -1129,31 +1192,10 @@ finally: wlock.release() - def markcommitted(self, node): - """Perform post-commit cleanup necessary after committing this ctx - - Specifically, this updates backing stores this working context - wraps to reflect the fact that the changes reflected by this - workingctx have been committed. For example, it marks - modified and added files as normal in the dirstate. - - """ - - for f in self.modified() + self.added(): - self._repo.dirstate.normal(f) - for f in self.removed(): - self._repo.dirstate.drop(f) - self._repo.dirstate.setparents(node) - - def dirs(self): - return self._repo.dirstate.dirs() - -class workingfilectx(filectx): - """A workingfilectx object makes access to data related to a particular - file in the working directory convenient.""" - def __init__(self, repo, path, filelog=None, workingctx=None): - """changeid can be a changeset revision, node, or tag. - fileid can be a file revision or node.""" +class committablefilectx(basefilectx): + """A committablefilectx provides common functionality for a file context + that wants the ability to commit, e.g. workingfilectx or memfilectx.""" + def __init__(self, repo, path, filelog=None, ctx=None): self._repo = repo self._path = path self._changeid = None @@ -1161,30 +1203,12 @@ if filelog is not None: self._filelog = filelog - if workingctx: - self._changectx = workingctx - - @propertycache - def _changectx(self): - return workingctx(self._repo) + if ctx: + self._changectx = ctx def __nonzero__(self): return True - def __str__(self): - return "%s@%s" % (self.path(), self._changectx) - - def __repr__(self): - return "<workingfilectx %s>" % str(self) - - def data(self): - return self._repo.wread(self._path) - def renamed(self): - rp = self._repo.dirstate.copied(self._path) - if not rp: - return None - return rp, self._changectx._parents[0]._manifest.get(rp, nullid) - def parents(self): '''return parent filectxs, following copies if necessary''' def filenode(ctx, path): @@ -1209,12 +1233,30 @@ def children(self): return [] +class workingfilectx(committablefilectx): + """A workingfilectx object makes access to data related to a particular + file in the working directory convenient.""" + def __init__(self, repo, path, filelog=None, workingctx=None): + super(workingfilectx, self).__init__(repo, path, filelog, workingctx) + + @propertycache + def _changectx(self): + return workingctx(self._repo) + + def data(self): + return self._repo.wread(self._path) + def renamed(self): + rp = self._repo.dirstate.copied(self._path) + if not rp: + return None + return rp, self._changectx._parents[0]._manifest.get(rp, nullid) + def size(self): - return os.lstat(self._repo.wjoin(self._path)).st_size + return self._repo.wvfs.lstat(self._path).st_size def date(self): t, tz = self._changectx.date() try: - return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz) + return (int(self._repo.wvfs.lstat(self._path).st_mtime), tz) except OSError, err: if err.errno != errno.ENOENT: raise
--- a/mercurial/dirstate.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/dirstate.py Sat Oct 19 14:21:05 2013 -0700 @@ -801,12 +801,9 @@ mexact = match.exact dirignore = self._dirignore checkexec = self._checkexec - checklink = self._checklink copymap = self._copymap lastnormaltime = self._lastnormaltime - lnkkind = stat.S_IFLNK - # We need to do full walks when either # - we're listing all clean files, or # - match.traversedir does something, because match.traversedir should @@ -818,7 +815,7 @@ if (listignored or mexact(fn)) and dirignore(fn): if listignored: iadd(fn) - elif listunknown: + else: uadd(fn) continue @@ -827,20 +824,14 @@ if not st and state in "nma": dadd(fn) elif state == 'n': - # The "mode & lnkkind != lnkkind or self._checklink" - # lines are an expansion of "islink => checklink" - # where islink means "is this a link?" and checklink - # means "can we check links?". mtime = int(st.st_mtime) if (size >= 0 and ((size != st.st_size and size != st.st_size & _rangemask) or ((mode ^ st.st_mode) & 0100 and checkexec)) - and (mode & lnkkind != lnkkind or checklink) or size == -2 # other parent or fn in copymap): madd(fn) - elif ((time != mtime and time != mtime & _rangemask) - and (mode & lnkkind != lnkkind or checklink)): + elif time != mtime and time != mtime & _rangemask: ladd(fn) elif mtime == lastnormaltime: # fn may have been changed in the same timeslot without
--- a/mercurial/discovery.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/discovery.py Sat Oct 19 14:21:05 2013 -0700 @@ -269,13 +269,12 @@ allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common)) allfuturecommon.update(allmissing) for branch, heads in sorted(headssum.iteritems()): - if heads[0] is None: - # Maybe we should abort if we push more that one head - # for new branches ? - continue candidate_newhs = set(heads[1]) # add unsynced data - oldhs = set(heads[0]) + if heads[0] is None: + oldhs = set() + else: + oldhs = set(heads[0]) oldhs.update(heads[2]) candidate_newhs.update(heads[2]) dhs = None @@ -310,7 +309,16 @@ newhs = candidate_newhs if [h for h in heads[2] if h not in discardedheads]: unsynced = True - if len(newhs) > len(oldhs): + if heads[0] is None: + if 1 < len(newhs): + dhs = list(newhs) + if error is None: + error = (_("push creates multiple headed new branch '%s'") + % (branch)) + hint = _("merge or" + " see \"hg help push\" for detail about" + " pushing new heads") + elif len(newhs) > len(oldhs): # strip updates to existing remote heads from the new heads list dhs = sorted(newhs - bookmarkedheads - oldhs) if dhs:
--- a/mercurial/dispatch.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/dispatch.py Sat Oct 19 14:21:05 2013 -0700 @@ -88,11 +88,47 @@ try: try: + debugger = 'pdb' + debugtrace = { + 'pdb' : pdb.set_trace + } + debugmortem = { + 'pdb' : pdb.post_mortem + } + + # read --config before doing anything else + # (e.g. to change trust settings for reading .hg/hgrc) + cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args)) + + if req.repo: + # copy configs that were passed on the cmdline (--config) to + # the repo ui + for cfg in cfgs: + req.repo.ui.setconfig(*cfg) + + debugger = ui.config("ui", "debugger") + if not debugger: + debugger = 'pdb' + + try: + debugmod = __import__(debugger) + except ImportError: + debugmod = pdb + + debugtrace[debugger] = debugmod.set_trace + debugmortem[debugger] = debugmod.post_mortem + # enter the debugger before command execution if '--debugger' in req.args: ui.warn(_("entering debugger - " "type c to continue starting hg or h for help\n")) - pdb.set_trace() + + if (debugger != 'pdb' and + debugtrace[debugger] == debugtrace['pdb']): + ui.warn(_("%s debugger specified " + "but its module was not found\n") % debugger) + + debugtrace[debugger]() try: return _dispatch(req) finally: @@ -101,7 +137,7 @@ # enter the debugger when we hit an exception if '--debugger' in req.args: traceback.print_exc() - pdb.post_mortem(sys.exc_info()[2]) + debugmortem[debugger](sys.exc_info()[2]) ui.traceback() raise @@ -619,10 +655,6 @@ args = req.args ui = req.ui - # read --config before doing anything else - # (e.g. to change trust settings for reading .hg/hgrc) - cfgs = _parseconfig(ui, _earlygetopt(['--config'], args)) - # check for cwd cwd = _earlygetopt(['--cwd'], args) if cwd: @@ -699,10 +731,6 @@ if req.repo: uis.add(req.repo.ui) - # copy configs that were passed on the cmdline (--config) to the repo ui - for cfg in cfgs: - req.repo.ui.setconfig(*cfg) - if options['verbose'] or options['debug'] or options['quiet']: for opt in ('verbose', 'debug', 'quiet'): val = str(bool(options[opt]))
--- a/mercurial/extensions.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/extensions.py Sat Oct 19 14:21:05 2013 -0700 @@ -13,10 +13,18 @@ _order = [] _ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg'] -def extensions(): +def extensions(ui=None): + if ui: + def enabled(name): + for format in ['%s', 'hgext.%s']: + conf = ui.config('extensions', format % name) + if conf is not None and not conf.startswith('!'): + return True + else: + enabled = lambda name: True for name in _order: module = _extensions[name] - if module: + if module and enabled(name): yield name, module def find(name):
--- a/mercurial/hg.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/hg.py Sat Oct 19 14:21:05 2013 -0700 @@ -101,7 +101,7 @@ """return a repository object for the specified path""" obj = _peerlookup(path).instance(ui, path, create) ui = getattr(obj, "ui", ui) - for name, module in extensions.extensions(): + for name, module in extensions.extensions(ui): hook = getattr(module, 'reposetup', None) if hook: hook(ui, obj)
--- a/mercurial/hgweb/hgweb_mod.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/hgweb/hgweb_mod.py Sat Oct 19 14:21:05 2013 -0700 @@ -331,12 +331,6 @@ # some functions for the templater - def header(**map): - yield tmpl('header', encoding=encoding.encoding, **map) - - def footer(**map): - yield tmpl("footer", **map) - def motd(**map): yield self.config("web", "motd", "") @@ -373,8 +367,7 @@ "staticurl": staticurl, "urlbase": urlbase, "repo": self.reponame, - "header": header, - "footer": footer, + "encoding": encoding.encoding, "motd": motd, "sessionvars": sessionvars, "pathdef": makebreadcrumb(req.url),
--- a/mercurial/hgweb/hgwebdir_mod.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/hgweb/hgwebdir_mod.py Sat Oct 19 14:21:05 2013 -0700 @@ -408,12 +408,6 @@ def templater(self, req): - def header(**map): - yield tmpl('header', encoding=encoding.encoding, **map) - - def footer(**map): - yield tmpl("footer", **map) - def motd(**map): if self.motd is not None: yield self.motd @@ -448,8 +442,7 @@ staticurl += '/' tmpl = templater.templater(mapfile, - defaults={"header": header, - "footer": footer, + defaults={"encoding": encoding.encoding, "motd": motd, "url": url, "logourl": logourl,
--- a/mercurial/hgweb/webcommands.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/hgweb/webcommands.py Sat Oct 19 14:21:05 2013 -0700 @@ -9,13 +9,15 @@ import webutil from mercurial import error, encoding, archival, templater, templatefilters from mercurial.node import short, hex, nullid -from mercurial.util import binary +from mercurial import util from common import paritygen, staticfile, get_contact, ErrorResponse from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND from mercurial import graphmod, patch from mercurial import help as helpmod from mercurial import scmutil from mercurial.i18n import _ +from mercurial.error import ParseError, RepoLookupError, Abort +from mercurial import revset # __all__ is populated with the allowed commands. Be sure to add to it if # you're adding a new command, or the new command won't work. @@ -57,7 +59,7 @@ if guessmime: mt = mimetypes.guess_type(path)[0] if mt is None: - mt = binary(text) and 'application/binary' or 'text/plain' + mt = util.binary(text) and 'application/binary' or 'text/plain' if mt.startswith('text/'): mt += '; charset="%s"' % encoding.encoding @@ -69,7 +71,7 @@ text = fctx.data() parity = paritygen(web.stripecount) - if binary(text): + if util.binary(text): mt = mimetypes.guess_type(f)[0] or 'application/octet-stream' text = '(binary:%s)' % mt @@ -109,9 +111,14 @@ raise inst def _search(web, req, tmpl): + MODE_REVISION = 'rev' + MODE_KEYWORD = 'keyword' + MODE_REVSET = 'revset' - def changelist(**map): - count = 0 + def revsearch(ctx): + yield ctx + + def keywordsearch(query): lower = encoding.lower qw = lower(query).split() @@ -137,6 +144,62 @@ if miss: continue + yield ctx + + def revsetsearch(revs): + for r in revs: + yield web.repo[r] + + searchfuncs = { + MODE_REVISION: (revsearch, _('exact revision search')), + MODE_KEYWORD: (keywordsearch, _('literal keyword search')), + MODE_REVSET: (revsetsearch, _('revset expression search')), + } + + def getsearchmode(query): + try: + ctx = web.repo[query] + except (error.RepoError, error.LookupError): + # query is not an exact revision pointer, need to + # decide if it's a revset expession or keywords + pass + else: + return MODE_REVISION, ctx + + revdef = 'reverse(%s)' % query + try: + tree, pos = revset.parse(revdef) + except ParseError: + # can't parse to a revset tree + return MODE_KEYWORD, query + + if revset.depth(tree) <= 2: + # no revset syntax used + return MODE_KEYWORD, query + + if util.any((token, (value or '')[:3]) == ('string', 're:') + for token, value, pos in revset.tokenize(revdef)): + return MODE_KEYWORD, query + + funcsused = revset.funcsused(tree) + if not funcsused.issubset(revset.safesymbols): + return MODE_KEYWORD, query + + mfunc = revset.match(web.repo.ui, revdef) + try: + revs = mfunc(web.repo, list(web.repo)) + return MODE_REVSET, revs + # ParseError: wrongly placed tokens, wrongs arguments, etc + # RepoLookupError: no such revision, e.g. in 'revision:' + # Abort: bookmark/tag not exists + # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo + except (ParseError, RepoLookupError, Abort, LookupError): + return MODE_KEYWORD, query + + def changelist(**map): + count = 0 + + for ctx in searchfunc[0](funcarg): count += 1 n = ctx.node() showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n) @@ -176,35 +239,45 @@ morevars['revcount'] = revcount * 2 morevars['rev'] = query + mode, funcarg = getsearchmode(query) + + if 'forcekw' in req.form: + showforcekw = '' + showunforcekw = searchfuncs[mode][1] + mode = MODE_KEYWORD + funcarg = query + else: + if mode != MODE_KEYWORD: + showforcekw = searchfuncs[MODE_KEYWORD][1] + else: + showforcekw = '' + showunforcekw = '' + + searchfunc = searchfuncs[mode] + tip = web.repo['tip'] parity = paritygen(web.stripecount) return tmpl('search', query=query, node=tip.hex(), entries=changelist, archives=web.archivelist("tip"), - morevars=morevars, lessvars=lessvars) + morevars=morevars, lessvars=lessvars, + modedesc=searchfunc[1], + showforcekw=showforcekw, showunforcekw=showunforcekw) def changelog(web, req, tmpl, shortlog=False): query = '' if 'node' in req.form: ctx = webutil.changectx(web.repo, req) + elif 'rev' in req.form: + return _search(web, req, tmpl) else: - if 'rev' in req.form: - query = req.form['rev'][0] - hi = query - else: - hi = 'tip' - try: - ctx = web.repo[hi] - except (error.RepoError, error.LookupError): - return _search(web, req, tmpl) # XXX redirect to 404 page? + ctx = web.repo['tip'] - def changelist(latestonly, **map): + def changelist(): revs = [] if pos != -1: revs = web.repo.changelog.revs(pos, 0) - if latestonly: - revs = (revs.next(),) curcount = 0 for i in revs: ctx = web.repo[i] @@ -213,7 +286,7 @@ files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles) curcount += 1 - if curcount > revcount: + if curcount > revcount + 1: break yield {"parity": parity.next(), "author": ctx.user(), @@ -249,15 +322,23 @@ changenav = webutil.revnav(web.repo).gen(pos, revcount, count) + entries = list(changelist()) + latestentry = entries[:1] + if len(entries) > revcount: + nextentry = entries[-1:] + entries = entries[:-1] + else: + nextentry = [] + return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav, node=ctx.hex(), rev=pos, changesets=count, - entries=lambda **x: changelist(latestonly=False, **x), - latestentry=lambda **x: changelist(latestonly=True, **x), + entries=entries, + latestentry=latestentry, nextentry=nextentry, archives=web.archivelist("tip"), revcount=revcount, morevars=morevars, lessvars=lessvars, query=query) def shortlog(web, req, tmpl): - return changelog(web, req, tmpl, shortlog = True) + return changelog(web, req, tmpl, shortlog=True) def changeset(web, req, tmpl): ctx = webutil.changectx(web.repo, req) @@ -617,7 +698,7 @@ context = parsecontext(web.config('web', 'comparisoncontext', '5')) def filelines(f): - if binary(f.data()): + if util.binary(f.data()): mt = mimetypes.guess_type(f.path())[0] if not mt: mt = 'application/octet-stream' @@ -675,7 +756,7 @@ def annotate(**map): last = None - if binary(fctx.data()): + if util.binary(fctx.data()): mt = (mimetypes.guess_type(fctx.path())[0] or 'application/octet-stream') lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
--- a/mercurial/httpclient/__init__.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/httpclient/__init__.py Sat Oct 19 14:21:05 2013 -0700 @@ -292,7 +292,7 @@ def __init__(self, host, port=None, use_ssl=None, ssl_validator=None, timeout=TIMEOUT_DEFAULT, continue_timeout=TIMEOUT_ASSUME_CONTINUE, - proxy_hostport=None, **ssl_opts): + proxy_hostport=None, ssl_wrap_socket=None, **ssl_opts): """Create a new HTTPConnection. Args: @@ -307,12 +307,23 @@ "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE. proxy_hostport: Optional. Tuple of (host, port) to use as an http proxy for the connection. Default is to not use a proxy. + ssl_wrap_socket: Optional function to use for wrapping + sockets. If unspecified, the one from the ssl module will + be used if available, or something that's compatible with + it if on a Python older than 2.6. + + Any extra keyword arguments to this function will be provided + to the ssl_wrap_socket method. If no ssl """ if port is None and host.count(':') == 1 or ']:' in host: host, port = host.rsplit(':', 1) port = int(port) if '[' in host: host = host[1:-1] + if ssl_wrap_socket is not None: + self._ssl_wrap_socket = ssl_wrap_socket + else: + self._ssl_wrap_socket = socketutil.wrap_socket if use_ssl is None and port is None: use_ssl = False port = 80 @@ -387,7 +398,7 @@ sock.setblocking(1) logger.debug('wrapping socket for ssl with options %r', self.ssl_opts) - sock = socketutil.wrap_socket(sock, **self.ssl_opts) + sock = self._ssl_wrap_socket(sock, **self.ssl_opts) if self._ssl_validator: self._ssl_validator(sock) sock.setblocking(0) @@ -495,6 +506,10 @@ else: raise BadRequestData('body has no __len__() nor read()') + # If we're reusing the underlying socket, there are some + # conditions where we'll want to retry, so make a note of the + # state of self.sock + fresh_socket = self.sock is None self._connect() outgoing_headers = self._buildheaders( method, path, hdrs, self.http_version) @@ -640,6 +655,26 @@ # the whole request if response is None: response = self.response_class(self.sock, self.timeout, method) + if not fresh_socket: + if not response._select(): + # This means the response failed to get any response + # data at all, and in all probability the socket was + # closed before the server even saw our request. Try + # the request again on a fresh socket. + logging.debug('response._select() failed during request().' + ' Assuming request needs to be retried.') + self.sock = None + # Call this method explicitly to re-try the + # request. We don't use self.request() because + # some tools (notably Mercurial) expect to be able + # to subclass and redefine request(), and they + # don't have the same argspec as we do. + # + # TODO restructure sending of requests to avoid + # this recursion + return HTTPConnection.request( + self, method, path, body=body, headers=headers, + expect_continue=expect_continue) data_left = bool(outgoing_headers or body) if data_left: logger.info('stopped sending request early, '
--- a/mercurial/httpconnection.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/httpconnection.py Sat Oct 19 14:21:05 2013 -0700 @@ -275,14 +275,13 @@ if '[' in host: host = host[1:-1] - if keyfile: - kwargs['keyfile'] = keyfile - if certfile: - kwargs['certfile'] = certfile + kwargs['keyfile'] = keyfile + kwargs['certfile'] = certfile kwargs.update(sslutil.sslkwargs(self.ui, host)) con = HTTPConnection(host, port, use_ssl=True, + ssl_wrap_socket=sslutil.ssl_wrap_socket, ssl_validator=sslutil.validator(self.ui, host), **kwargs) return con
--- a/mercurial/keepalive.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/keepalive.py Sat Oct 19 14:21:05 2013 -0700 @@ -499,7 +499,7 @@ data, self._rbuf = self._rbuf[:i], self._rbuf[i:] return data - def readlines(self, sizehint = 0): + def readlines(self, sizehint=0): total = 0 list = [] while True:
--- a/mercurial/localrepo.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/localrepo.py Sat Oct 19 14:21:05 2013 -0700 @@ -147,12 +147,14 @@ class localrepository(object): supportedformats = set(('revlogv1', 'generaldelta')) - supported = supportedformats | set(('store', 'fncache', 'shared', - 'dotencode')) + _basesupported = supportedformats | set(('store', 'fncache', 'shared', + 'dotencode')) openerreqs = set(('revlogv1', 'generaldelta')) requirements = ['revlogv1'] filtername = None + featuresetupfuncs = set() + def _baserequirements(self, create): return self.requirements[:] @@ -177,6 +179,13 @@ except IOError: pass + if self.featuresetupfuncs: + self.supported = set(self._basesupported) # use private copy + for setupfunc in self.featuresetupfuncs: + setupfunc(self.ui, self.supported) + else: + self.supported = self._basesupported + if not self.vfs.isdir(): if create: if not self.wvfs.exists(): @@ -804,7 +813,7 @@ def wwritedata(self, filename, data): return self._filter(self._decodefilterpats, filename, data) - def transaction(self, desc): + def transaction(self, desc, report=None): tr = self._transref and self._transref() or None if tr and tr.running(): return tr.nest() @@ -816,8 +825,8 @@ self._writejournal(desc) renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()] - - tr = transaction.transaction(self.ui.warn, self.sopener, + rp = report and report or self.ui.warn + tr = transaction.transaction(rp, self.sopener, self.sjoin("journal"), aftertrans(renames), self.store.createmode) @@ -1460,14 +1469,8 @@ del mf[fn] return mf - if isinstance(node1, context.changectx): - ctx1 = node1 - else: - ctx1 = self[node1] - if isinstance(node2, context.changectx): - ctx2 = node2 - else: - ctx2 = self[node2] + ctx1 = self[node1] + ctx2 = self[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] @@ -1564,7 +1567,7 @@ for f in modified: if ctx2.flags(f) == 'l': d = ctx2[f].data() - if len(d) >= 1024 or '\n' in d or util.binary(d): + if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d): self.ui.debug('ignoring suspect symlink placeholder' ' "%s"\n' % f) continue @@ -1656,6 +1659,14 @@ return r def pull(self, remote, heads=None, force=False): + if remote.local(): + missing = set(remote.requirements) - self.supported + if missing: + msg = _("required features are not" + " supported in the destination:" + " %s") % (', '.join(sorted(missing))) + raise util.Abort(msg) + # don't open transaction for nothing or you break future useful # rollback call tr = None @@ -1756,6 +1767,14 @@ we have outgoing changesets but refused to push - other values as described by addchangegroup() ''' + if remote.local(): + missing = set(self.requirements) - remote.local().supported + if missing: + msg = _("required features are not" + " supported in the destination:" + " %s") % (', '.join(sorted(missing))) + raise util.Abort(msg) + # there are two ways to push to remote repo: # # addchangegroup assumes local user can lock remote @@ -2210,6 +2229,12 @@ # In other case we can safely update cache on disk. branchmap.updatecache(self.filtered('served')) def runhooks(): + # These hooks run when the lock releases, not when the + # transaction closes. So it's possible for the changelog + # to have changed since we last saw it. + if clstart >= len(self): + return + # forcefully update the on-disk branch cache self.ui.debug("updating the branch cache\n") self.hook("changegroup", node=hex(cl.node(clstart)),
--- a/mercurial/mail.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/mail.py Sat Oct 19 14:21:05 2013 -0700 @@ -8,7 +8,11 @@ from i18n import _ import util, encoding, sslutil import os, smtplib, socket, quopri, time, sys -import email.Header, email.MIMEText, email.Utils +import email +# On python2.4 you have to import these by name or they fail to +# load. This was not a problem on Python 2.7. +import email.Header +import email.MIMEText _oldheaderinit = email.Header.Header.__init__ def _unifiedheaderinit(self, *args, **kw):
--- a/mercurial/match.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/match.py Sat Oct 19 14:21:05 2013 -0700 @@ -140,7 +140,7 @@ class exact(match): def __init__(self, root, cwd, files): - match.__init__(self, root, cwd, files, exact = True) + match.__init__(self, root, cwd, files, exact=True) class always(match): def __init__(self, root, cwd):
--- a/mercurial/merge.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/merge.py Sat Oct 19 14:21:05 2013 -0700 @@ -656,19 +656,21 @@ -c -C dirty rev | linear same cross n n n n | ok (1) x n n n y | ok ok ok - n n y * | merge (2) (2) + n n y n | merge (2) (2) + n n y y | merge (3) (3) n y * * | --- discard --- - y n y * | --- (3) --- + y n y * | --- (4) --- y n n * | --- ok --- - y y * * | --- (4) --- + y y * * | --- (5) --- x = can't happen * = don't-care - 1 = abort: crosses branches (use 'hg merge' or 'hg update -c') - 2 = abort: crosses branches (use 'hg merge' to merge or - use 'hg update -C' to discard changes) - 3 = abort: uncommitted local changes - 4 = incompatible options (checked in commands.py) + 1 = abort: not a linear update (merge or update --check to force update) + 2 = abort: uncommitted changes (commit and merge, or update --clean to + discard changes) + 3 = abort: uncommitted changes (commit or update --clean to discard changes) + 4 = abort: uncommitted changes (checked in commands.py) + 5 = incompatible options (checked in commands.py) Return the same tuple as applyupdates(). """ @@ -709,11 +711,11 @@ hint=_("use 'hg update' " "or check 'hg heads'")) if not force and (wc.files() or wc.deleted()): - raise util.Abort(_("outstanding uncommitted changes"), + raise util.Abort(_("uncommitted changes"), hint=_("use 'hg status' to list changes")) for s in sorted(wc.substate): if wc.sub(s).dirty(): - raise util.Abort(_("outstanding uncommitted changes in " + raise util.Abort(_("uncommitted changes in " "subrepository '%s'") % s) elif not overwrite: @@ -727,13 +729,18 @@ if repo[node].node() in foreground: pa = p1 # allow updating to successors elif dirty: - msg = _("crosses branches (merge branches or use" - " --clean to discard changes)") - raise util.Abort(msg) + msg = _("uncommitted changes") + if onode is None: + hint = _("commit and merge, or update --clean to" + " discard changes") + else: + hint = _("commit or update --clean to discard" + " changes") + raise util.Abort(msg, hint=hint) else: # node is none - msg = _("crosses branches (merge branches or update" - " --check to force update)") - raise util.Abort(msg) + msg = _("not a linear update") + hint = _("merge or update --check to force update") + raise util.Abort(msg, hint=hint) else: # Allow jumping branches if clean and specific rev given pa = p1
--- a/mercurial/obsolete.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/obsolete.py Sat Oct 19 14:21:05 2013 -0700 @@ -371,7 +371,7 @@ lock.release() def syncpush(repo, remote): - """utility function to push bookmark to a remote + """utility function to push obsolete markers to a remote Exist mostly to allow overridding for experimentation purpose""" if (_enabled and repo.obsstore and @@ -387,7 +387,7 @@ repo.ui.warn(msg) def syncpull(repo, remote, gettransaction): - """utility function to pull bookmark to a remote + """utility function to pull obsolete markers from a remote The `gettransaction` is function that return the pull transaction, creating one if necessary. We return the transaction to inform the calling code that
--- a/mercurial/parsers.c Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/parsers.c Sat Oct 19 14:21:05 2013 -0700 @@ -14,16 +14,32 @@ #include "util.h" +static int8_t hextable[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + static inline int hexdigit(const char *p, Py_ssize_t off) { - char c = p[off]; + int8_t val = hextable[(unsigned char)p[off]]; - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; + if (val >= 0) { + return val; + } PyErr_SetString(PyExc_ValueError, "input contains non-hex character"); return 0; @@ -61,7 +77,7 @@ static PyObject *parse_manifest(PyObject *self, PyObject *args) { PyObject *mfdict, *fdict; - char *str, *cur, *start, *zero; + char *str, *start, *end; int len; if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest", @@ -70,30 +86,34 @@ &str, &len)) goto quit; - for (start = cur = str, zero = NULL; cur < str + len; cur++) { + start = str; + end = str + len; + while (start < end) { PyObject *file = NULL, *node = NULL; PyObject *flags = NULL; + char *zero = NULL, *newline = NULL; ptrdiff_t nlen; - if (!*cur) { - zero = cur; - continue; - } - else if (*cur != '\n') - continue; - + zero = memchr(start, '\0', end - start); if (!zero) { PyErr_SetString(PyExc_ValueError, "manifest entry has no separator"); goto quit; } + newline = memchr(zero + 1, '\n', end - (zero + 1)); + if (!newline) { + PyErr_SetString(PyExc_ValueError, + "manifest contains trailing garbage"); + goto quit; + } + file = PyBytes_FromStringAndSize(start, zero - start); if (!file) goto bail; - nlen = cur - zero - 1; + nlen = newline - zero - 1; node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen); if (!node) @@ -112,8 +132,7 @@ if (PyDict_SetItem(mfdict, file, node) == -1) goto bail; - start = cur + 1; - zero = NULL; + start = newline + 1; Py_XDECREF(flags); Py_XDECREF(node); @@ -126,12 +145,6 @@ goto quit; } - if (len > 0 && *(cur - 1) != '\n') { - PyErr_SetString(PyExc_ValueError, - "manifest contains trailing garbage"); - goto quit; - } - Py_INCREF(Py_None); return Py_None; quit: @@ -142,8 +155,8 @@ { PyObject *dmap, *cmap, *parents = NULL, *ret = NULL; PyObject *fname = NULL, *cname = NULL, *entry = NULL; - char *str, *cur, *end, *cpos; - int state, mode, size, mtime; + char state, *str, *cur, *end, *cpos; + int mode, size, mtime; unsigned int flen; int len; @@ -330,7 +343,7 @@ * this. */ if (PyDict_SetItem(map, k, dirstate_unset) == -1) goto bail; - mode = 0, size = -1, mtime = -1; + mtime = -1; } putbe32(mode, p); putbe32(size, p + 4); @@ -524,11 +537,12 @@ uncomp_len, base_rev, link_rev, parent_1, parent_2, c_node_id, 20); - if (entry) + if (entry) { PyObject_GC_UnTrack(entry); + Py_INCREF(entry); + } self->cache[pos] = entry; - Py_INCREF(entry); return entry; } @@ -1195,14 +1209,19 @@ long sp; bitmask *seen; + if (gca == NULL) + return PyErr_NoMemory(); + for (i = 0; i < revcount; i++) { if (revs[i] > maxrev) maxrev = revs[i]; } seen = calloc(sizeof(*seen), maxrev + 1); - if (seen == NULL) + if (seen == NULL) { + Py_DECREF(gca); return PyErr_NoMemory(); + } for (i = 0; i < revcount; i++) seen[revs[i]] = 1ull << i;
--- a/mercurial/patch.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/patch.py Sat Oct 19 14:21:05 2013 -0700 @@ -6,8 +6,12 @@ # 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, email.Parser, os, errno, re, posixpath +import cStringIO, email, os, errno, re, posixpath import tempfile, zlib, shutil +# On python2.4 you have to import these by name or they fail to +# load. This was not a problem on Python 2.7. +import email.Generator +import email.Parser from i18n import _ from node import hex, short
--- a/mercurial/pure/parsers.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/pure/parsers.py Sat Oct 19 14:21:05 2013 -0700 @@ -100,11 +100,11 @@ # systems with a granularity of 1 sec). This commonly happens # for at least a couple of files on 'update'. # The user could change the file without changing its size - # within the same second. Invalidate the file's stat data in + # within the same second. Invalidate the file's mtime in # dirstate, forcing future 'status' calls to compare the - # contents of the file. This prevents mistakenly treating such - # files as clean. - e = (e[0], 0, -1, -1) # mark entry as 'unset' + # contents of the file if the size is the same. This prevents + # mistakenly treating such files as clean. + e = (e[0], e[1], e[2], -1) dmap[f] = e if f in copymap:
--- a/mercurial/revlog.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/revlog.py Sat Oct 19 14:21:05 2013 -0700 @@ -14,7 +14,7 @@ # import stuff from node for others to import from revlog from node import bin, hex, nullid, nullrev from i18n import _ -import ancestor, mdiff, parsers, error, util +import ancestor, mdiff, parsers, error, util, templatefilters import struct, zlib, errno _pack = struct.pack @@ -845,16 +845,43 @@ def _chunkraw(self, startrev, endrev): start = self.start(startrev) - length = self.end(endrev) - start + end = self.end(endrev) if self._inline: start += (startrev + 1) * self._io.size + end += (endrev + 1) * self._io.size + length = end - start return self._getchunk(start, length) def _chunk(self, rev): return decompress(self._chunkraw(rev, rev)) - def _chunkbase(self, rev): - return self._chunk(rev) + def _chunks(self, revs): + '''faster version of [self._chunk(rev) for rev in revs] + + Assumes that revs is in ascending order.''' + if not revs: + return [] + start = self.start + length = self.length + inline = self._inline + iosize = self._io.size + buffer = util.buffer + + l = [] + ladd = l.append + + # preload the cache + self._chunkraw(revs[0], revs[-1]) + offset, data = self._chunkcache + + for rev in revs: + chunkstart = start(rev) + if inline: + chunkstart += (rev + 1) * iosize + chunklength = length(rev) + ladd(decompress(buffer(data, chunkstart - offset, chunklength))) + + return l def _chunkclear(self): self._chunkcache = (0, '') @@ -919,21 +946,22 @@ else: iterrev -= 1 e = index[iterrev] - chain.reverse() - base = iterrev if iterrev == cachedrev: # cache hit text = self._cache[2] + else: + chain.append(iterrev) + chain.reverse() # drop cache to save memory self._cache = None - self._chunkraw(base, rev) + bins = self._chunks(chain) if text is None: - text = str(self._chunkbase(base)) + text = str(bins[0]) + bins = bins[1:] - bins = [self._chunk(r) for r in chain] text = mdiff.patches(text, bins) text = self._checkhash(text, node, rev) @@ -943,10 +971,16 @@ def _checkhash(self, text, node, rev): p1, p2 = self.parents(node) + self.checkhash(text, p1, p2, node, rev) + return text + + def checkhash(self, text, p1, p2, node, rev=None): if node != hash(text, p1, p2): - raise RevlogError(_("integrity check failed on %s:%d") - % (self.indexfile, rev)) - return text + revornode = rev + if revornode is None: + revornode = templatefilters.short(hex(node)) + raise RevlogError(_("integrity check failed on %s:%s") + % (self.indexfile, revornode)) def checkinlinesize(self, tr, fp=None): if not self._inline or (self.start(-2) + self.length(-2)) < _maxinline: @@ -987,7 +1021,8 @@ tr.replace(self.indexfile, trindex * self._io.size) self._chunkclear() - def addrevision(self, text, transaction, link, p1, p2, cachedelta=None): + def addrevision(self, text, transaction, link, p1, p2, cachedelta=None, + node=None): """add a revision to the log text - the revision data to add @@ -995,11 +1030,14 @@ link - the linkrev data to add p1, p2 - the parent nodeids of the revision cachedelta - an optional precomputed delta + node - nodeid of revision; typically node is not specified, and it is + computed by default as hash(text, p1, p2), however subclasses might + use different hashing method (and override checkhash() in such case) """ if link == nullrev: raise RevlogError(_("attempted to add linkrev -1 to %s") % self.indexfile) - node = hash(text, p1, p2) + node = node or hash(text, p1, p2) if node in self.nodemap: return node @@ -1063,9 +1101,7 @@ ifh.flush() basetext = self.revision(self.node(cachedelta[0])) btext[0] = mdiff.patch(basetext, cachedelta[1]) - chk = hash(btext[0], p1, p2) - if chk != node: - raise RevlogError(_("consistency error in delta")) + self.checkhash(btext[0], p1, p2, node) return btext[0] def builddelta(rev):
--- a/mercurial/revset.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/revset.py Sat Oct 19 14:21:05 2013 -0700 @@ -1599,6 +1599,75 @@ "_list": _list, } +# symbols which can't be used for a DoS attack for any given input +# (e.g. those which accept regexes as plain strings shouldn't be included) +# functions that just return a lot of changesets (like all) don't count here +safesymbols = set([ + "adds", + "all", + "ancestor", + "ancestors", + "_firstancestors", + "author", + "bisect", + "bisected", + "bookmark", + "branch", + "branchpoint", + "bumped", + "bundle", + "children", + "closed", + "converted", + "date", + "desc", + "descendants", + "_firstdescendants", + "destination", + "divergent", + "draft", + "extinct", + "extra", + "file", + "filelog", + "first", + "follow", + "_followfirst", + "head", + "heads", + "hidden", + "id", + "keyword", + "last", + "limit", + "_matchfiles", + "max", + "merge", + "min", + "modifies", + "obsolete", + "origin", + "outgoing", + "p1", + "p2", + "parents", + "present", + "public", + "remote", + "removes", + "rev", + "reverse", + "roots", + "sort", + "secret", + "matching", + "tag", + "tagged", + "user", + "unstable", + "_list", +]) + methods = { "range": rangeset, "dagrange": dagrange, @@ -1935,5 +2004,22 @@ output = '\n'.join((' '*l + s) for l, s in lines) return output +def depth(tree): + if isinstance(tree, tuple): + return max(map(depth, tree)) + 1 + else: + return 0 + +def funcsused(tree): + if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'): + return set() + else: + funcs = set() + for s in tree[1:]: + funcs |= funcsused(s) + if tree[0] == 'func': + funcs.add(tree[1][1]) + return funcs + # tell hggettext to extract docstrings from these functions: i18nfunctions = symbols.values()
--- a/mercurial/scmutil.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/scmutil.py Sat Oct 19 14:21:05 2013 -0700 @@ -217,6 +217,10 @@ raise return "" + def open(self, path, mode="r", text=False, atomictemp=False): + self.open = self.__call__ + return self.__call__(path, mode, text, atomictemp) + def read(self, path): fp = self(path, 'rb') try: @@ -241,12 +245,18 @@ def exists(self, path=None): return os.path.exists(self.join(path)) + def fstat(self, fp): + return util.fstat(fp) + def isdir(self, path=None): return os.path.isdir(self.join(path)) def islink(self, path=None): return os.path.islink(self.join(path)) + def lstat(self, path=None): + return os.lstat(self.join(path)) + def makedir(self, path=None, notindexed=True): return util.makedir(self.join(path), notindexed) @@ -271,6 +281,12 @@ def stat(self, path=None): return os.stat(self.join(path)) + def unlink(self, path=None): + return util.unlink(self.join(path)) + + def utime(self, path=None, t=None): + return os.utime(self.join(path), t) + class vfs(abstractvfs): '''Operate files relative to a base directory @@ -755,7 +771,8 @@ ctx = repo[None] dirstate = repo.dirstate - walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False) + walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False, + full=False) for abs, st in walkresults.iteritems(): dstate = dirstate[abs] if dstate == '?' and audit_path.check(abs):
--- a/mercurial/sslutil.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/sslutil.py Sat Oct 19 14:21:05 2013 -0700 @@ -14,10 +14,13 @@ # avoid using deprecated/broken FakeSocket in python 2.6 import ssl CERT_REQUIRED = ssl.CERT_REQUIRED - def ssl_wrap_socket(sock, keyfile, certfile, + PROTOCOL_SSLv23 = ssl.PROTOCOL_SSLv23 + PROTOCOL_TLSv1 = ssl.PROTOCOL_TLSv1 + def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1, cert_reqs=ssl.CERT_NONE, ca_certs=None): sslsocket = ssl.wrap_socket(sock, keyfile, certfile, - cert_reqs=cert_reqs, ca_certs=ca_certs) + cert_reqs=cert_reqs, ca_certs=ca_certs, + ssl_version=ssl_version) # check if wrap_socket failed silently because socket had been closed # - see http://bugs.python.org/issue13721 if not sslsocket.cipher(): @@ -26,9 +29,12 @@ except ImportError: CERT_REQUIRED = 2 + PROTOCOL_SSLv23 = 2 + PROTOCOL_TLSv1 = 3 + import socket, httplib - def ssl_wrap_socket(sock, key_file, cert_file, + def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1, cert_reqs=CERT_REQUIRED, ca_certs=None): if not util.safehasattr(socket, 'ssl'): raise util.Abort(_('Python SSL support not found')) @@ -36,7 +42,7 @@ raise util.Abort(_( 'certificate checking requires Python 2.6')) - ssl = socket.ssl(sock, key_file, cert_file) + ssl = socket.ssl(sock, keyfile, certfile) return httplib.FakeSocket(sock, ssl) def _verifycert(cert, hostname): @@ -84,15 +90,22 @@ def sslkwargs(ui, host): cacerts = ui.config('web', 'cacerts') + forcetls = ui.configbool('ui', 'tls', default=True) + if forcetls: + ssl_version = PROTOCOL_TLSv1 + else: + ssl_version = PROTOCOL_SSLv23 hostfingerprint = ui.config('hostfingerprints', host) + kws = {'ssl_version': ssl_version, + } if cacerts and not hostfingerprint: cacerts = util.expandpath(cacerts) if not os.path.exists(cacerts): raise util.Abort(_('could not find web.cacerts: %s') % cacerts) - return {'ca_certs': cacerts, - 'cert_reqs': CERT_REQUIRED, - } - return {} + kws.update({'ca_certs': cacerts, + 'cert_reqs': CERT_REQUIRED, + }) + return kws class validator(object): def __init__(self, ui, host):
--- a/mercurial/statichttprepo.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/statichttprepo.py Sat Oct 19 14:21:05 2013 -0700 @@ -89,6 +89,8 @@ return False class statichttprepository(localrepo.localrepository): + supported = localrepo.localrepository._basesupported + def __init__(self, ui, path): self._url = path self.ui = ui
--- a/mercurial/store.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/store.py Sat Oct 19 14:21:05 2013 -0700 @@ -344,12 +344,12 @@ '''Checks if the store contains path''' path = "/".join(("data", path)) # file? - if os.path.exists(self.join(path + ".i")): + if self.vfs.exists(path + ".i"): return True # dir? if not path.endswith("/"): path = path + "/" - return os.path.exists(self.join(path)) + return self.vfs.exists(path) class encodedstore(basicstore): def __init__(self, path, vfstype):
--- a/mercurial/subrepo.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/subrepo.py Sat Oct 19 14:21:05 2013 -0700 @@ -5,7 +5,8 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import errno, os, re, xml.dom.minidom, shutil, posixpath, sys +import errno, os, re, shutil, posixpath, sys +import xml.dom.minidom import stat, subprocess, tarfile from i18n import _ import config, scmutil, util, node, error, cmdutil, bookmarks, match as matchmod @@ -201,9 +202,24 @@ wctx.sub(s).get(r, overwrite) sm[s] = r else: - debug(s, "both sides changed, merge with", r) - wctx.sub(s).merge(r) - sm[s] = l + debug(s, "both sides changed") + option = repo.ui.promptchoice( + _(' subrepository %s diverged (local revision: %s, ' + 'remote revision: %s)\n' + '(M)erge, keep (l)ocal or keep (r)emote?' + '$$ &Merge $$ &Local $$ &Remote') + % (s, l[1][:12], r[1][:12]), 0) + if option == 0: + wctx.sub(s).merge(r) + sm[s] = l + debug(s, "merge with", r) + elif option == 1: + sm[s] = l + debug(s, "keep local subrepo revision", l) + else: + wctx.sub(s).get(r, overwrite) + sm[s] = r + debug(s, "get remote subrepo revision", r) elif ld == a: # remote removed, local unchanged debug(s, "remote removed, remove") wctx.sub(s).remove() @@ -237,6 +253,7 @@ # record merged .hgsubstate writestate(repo, sm) + return sm def _updateprompt(ui, sub, dirty, local, remote): if dirty:
--- a/mercurial/templatefilters.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templatefilters.py Sat Oct 19 14:21:05 2013 -0700 @@ -15,15 +15,15 @@ """ return text.replace('\n', '<br/>\n') -agescales = [("year", 3600 * 24 * 365), - ("month", 3600 * 24 * 30), - ("week", 3600 * 24 * 7), - ("day", 3600 * 24), - ("hour", 3600), - ("minute", 60), - ("second", 1)] +agescales = [("year", 3600 * 24 * 365, 'Y'), + ("month", 3600 * 24 * 30, 'M'), + ("week", 3600 * 24 * 7, 'W'), + ("day", 3600 * 24, 'd'), + ("hour", 3600, 'h'), + ("minute", 60, 'm'), + ("second", 1, 's')] -def age(date): +def age(date, abbrev=False): """:age: Date. Returns a human-readable date/time difference between the given date/time and the current date/time. """ @@ -32,7 +32,9 @@ if c == 1: return t return t + "s" - def fmt(t, c): + def fmt(t, c, a): + if abbrev: + return "%d%s" % (c, a) return "%d %s" % (c, plural(t, c)) now = time.time() @@ -48,12 +50,12 @@ if delta > agescales[0][1] * 2: return util.shortdate(date) - for t, s in agescales: + for t, s, a in agescales: n = delta // s if n >= 2 or s == 1: if future: - return '%s from now' % fmt(t, n) - return '%s ago' % fmt(t, n) + return '%s from now' % fmt(t, n, a) + return '%s ago' % fmt(t, n, a) def basename(path): """:basename: Any text. Treats the text as a path, and returns the last @@ -99,7 +101,7 @@ para_re = None space_re = None -def fill(text, width, initindent = '', hangindent = ''): +def fill(text, width, initindent='', hangindent=''): '''fill many paragraphs with optional indentation.''' global para_re, space_re if para_re is None:
--- a/mercurial/templater.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templater.py Sat Oct 19 14:21:05 2013 -0700 @@ -139,7 +139,12 @@ def runsymbol(context, mapping, key): v = mapping.get(key) if v is None: - v = context._defaults.get(key, '') + v = context._defaults.get(key) + if v is None: + try: + v = context.process(key, mapping) + except TemplateNotFound: + v = '' if util.safehasattr(v, '__call__'): return v(**mapping) if isinstance(v, types.GeneratorType): @@ -449,6 +454,9 @@ stylelist.append(split[1]) return ", ".join(sorted(stylelist)) +class TemplateNotFound(util.Abort): + pass + class templater(object): def __init__(self, mapfile, filters={}, defaults={}, cache={}, @@ -500,7 +508,8 @@ try: self.cache[t] = util.readfile(self.map[t][1]) except KeyError, inst: - raise util.Abort(_('"%s" not in template map') % inst.args[0]) + raise TemplateNotFound(_('"%s" not in template map') % + inst.args[0]) except IOError, inst: raise IOError(inst.args[0], _('template file %s: %s') % (self.map[t][1], inst.args[1]))
--- a/mercurial/templates/paper/bookmarks.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/bookmarks.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -38,8 +38,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <table class="bigtable">
--- a/mercurial/templates/paper/branches.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/branches.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -38,8 +38,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <table class="bigtable">
--- a/mercurial/templates/paper/changeset.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/changeset.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -36,8 +36,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="description">{desc|strip|escape|websub|nonempty}</div>
--- a/mercurial/templates/paper/error.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/error.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -29,8 +29,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30"></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="description">
--- a/mercurial/templates/paper/fileannotate.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/fileannotate.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -42,8 +42,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="description">{desc|strip|escape|websub|nonempty}</div> @@ -65,7 +64,6 @@ <th class="author">children</th> <td class="author">{child%filerevchild}</td> </tr> -{changesettag} </table> <div class="overflow">
--- a/mercurial/templates/paper/filecomparison.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/filecomparison.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -41,8 +41,7 @@ <form class="search" action="{url|urlescape}log"> <p>{sessionvars%hiddenformentry}</p> <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="description">{desc|strip|escape|websub|nonempty}</div> @@ -64,7 +63,6 @@ <th>children</th> <td>{child%filerevchild}</td> </tr> -{changesettag} </table> <div class="overflow">
--- a/mercurial/templates/paper/filediff.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/filediff.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -41,8 +41,7 @@ <form class="search" action="{url|urlescape}log"> <p>{sessionvars%hiddenformentry}</p> <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="description">{desc|strip|escape|websub|nonempty}</div> @@ -64,7 +63,6 @@ <th>children</th> <td>{child%filerevchild}</td> </tr> -{changesettag} </table> <div class="overflow">
--- a/mercurial/templates/paper/filelog.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/filelog.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -49,8 +49,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="navigate">
--- a/mercurial/templates/paper/filerevision.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/filerevision.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -40,8 +40,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="description">{desc|strip|escape|websub|nonempty}</div> @@ -63,7 +62,6 @@ <th class="author">children</th> <td class="author">{child%filerevchild}</td> </tr> -{changesettag} </table> <div class="overflow">
--- a/mercurial/templates/paper/graph.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/graph.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -43,8 +43,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="navigate"> @@ -123,6 +122,17 @@ | rev {rev}: {changenav%navgraph} </div> +<script type="text/javascript"> + ajaxScrollInit( + '{url|urlescape}graph/{rev}?revcount=%next%', + {revcount}+60, + function (htmlText, previousVal) \{ return previousVal + 60; }, + '#wrapper', + '<div class="%class%" style="text-align: center;">%text%</div>', + 'graph' + ); +</script> + </div> </div>
--- a/mercurial/templates/paper/help.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/help.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -28,8 +28,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div id="doc"> {rstdoc(doc, "html")}
--- a/mercurial/templates/paper/helptopics.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/helptopics.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -26,8 +26,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <table class="bigtable"> <tr><td colspan="2"><h2><a name="main" href="#topics">Topics</a></h2></td></tr>
--- a/mercurial/templates/paper/manifest.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/manifest.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -35,8 +35,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <table class="bigtable">
--- a/mercurial/templates/paper/map Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/map Sat Oct 19 14:21:05 2013 -0700 @@ -243,3 +243,6 @@ urlparameter = '{separator}{name}={value|urlescape}' hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />' breadcrumb = '> <a href="{url|urlescape}">{name|escape}</a> ' + +searchhint = 'Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="{url|urlescape}help/revsets">revset expression</a>.'
--- a/mercurial/templates/paper/search.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/search.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -23,11 +23,18 @@ <h2 class="breadcrumb"><a href="/">Mercurial</a> {pathdef%breadcrumb}</h2> <h3>searching for '{query|escape}'</h3> +<p> +Assuming {modedesc}. +{if(showforcekw, '<a href="{url|urlescape}log?rev={query|urlescape}&forcekw=1"> +Use {showforcekw}</a> instead.')} +{if(showunforcekw, '<a href="{url|urlescape}log?rev={query|urlescape}"> +Use {showunforcekw}</a> instead.')} +</p> + <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" value="{query|escape}"></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="navigate">
--- a/mercurial/templates/paper/shortlog.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/shortlog.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -45,8 +45,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" value="{query|escape}" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <div class="navigate"> @@ -72,6 +71,21 @@ | rev {rev}: {changenav%navshort} </div> +<script type="text/javascript"> + ajaxScrollInit( + '{url|urlescape}shortlog/%next%', + '{nextentry%"{node}"}', <!-- NEXTHASH + function (htmlText, previousVal) \{ + var m = htmlText.match(/'(\w+)', <!-- NEXTHASH/); + return m ? m[1] : null; + }, + '.bigtable > tbody:nth-of-type(2)', + '<tr class="%class%">\ + <td colspan="3" style="text-align: center;">%text%</td>\ + </tr>' + ); +</script> + </div> </div>
--- a/mercurial/templates/paper/shortlogentry.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/shortlogentry.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -1,5 +1,5 @@ <tr> <td class="age">{date|rfc822date}</td> <td class="author">{author|person}</td> - <td class="description"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags % '<span class="tag">{name|escape}</span> '}{bookmarks % '<span class="tag">{name|escape}</span> '}</td> + <td class="description"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}{bookmarks%changelogtag}</td> </tr>
--- a/mercurial/templates/paper/tags.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/paper/tags.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -37,8 +37,7 @@ <form class="search" action="{url|urlescape}log"> {sessionvars%hiddenformentry} <p><input name="rev" id="search1" type="text" size="30" /></p> -<div id="hint">find changesets by author, revision, -files, or words in the commit message</div> +<div id="hint">{searchhint}</div> </form> <table class="bigtable">
--- a/mercurial/templates/raw/changelog.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/raw/changelog.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -1,5 +1,5 @@ {header} -# HG shortlog +# HG changelog # Node ID {node} {entries%changelogentry}
--- a/mercurial/templates/raw/search.tmpl Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/raw/search.tmpl Sat Oct 19 14:21:05 2013 -0700 @@ -2,5 +2,6 @@ # HG changesets search # Node ID {node} # Query "{query}" +# Mode {modedesc} {entries%changelogentry}
--- a/mercurial/templates/static/mercurial.js Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/static/mercurial.js Sat Oct 19 14:21:05 2013 -0700 @@ -23,7 +23,7 @@ ]; function Graph() { - + this.canvas = document.getElementById('graph'); if (window.G_vmlCanvasManager) this.canvas = window.G_vmlCanvasManager.initElement(this.canvas); this.ctx = this.canvas.getContext('2d'); @@ -35,13 +35,21 @@ this.cell = [2, 0]; this.columns = 0; this.revlink = ''; - + + this.reset = function() { + this.bg = [0, 4]; + this.cell = [2, 0]; + this.columns = 0; + document.getElementById('nodebgs').innerHTML = ''; + document.getElementById('graphnodes').innerHTML = ''; + } + this.scale = function(height) { this.bg_height = height; this.box_size = Math.floor(this.bg_height / 1.2); this.cell_height = this.box_size; } - + function colorPart(num) { num *= 255 num = num < 0 ? 0 : num; @@ -55,7 +63,7 @@ } this.setColor = function(color, bg, fg) { - + // Set the colour. // // If color is a string, expect an hexadecimal RGB @@ -81,11 +89,11 @@ this.ctx.strokeStyle = s; this.ctx.fillStyle = s; return s; - + } this.edge = function(x0, y0, x1, y1, color, width) { - + this.setColor(color, 0.0, 0.65); if(width >= 0) this.ctx.lineWidth = width; @@ -93,28 +101,28 @@ this.ctx.moveTo(x0, y0); this.ctx.lineTo(x1, y1); this.ctx.stroke(); - + } this.render = function(data) { - + var backgrounds = ''; var nodedata = ''; - + for (var i in data) { - + var parity = i % 2; this.cell[1] += this.bg_height; this.bg[1] += this.bg_height; - + var cur = data[i]; var node = cur[1]; var edges = cur[2]; var fold = false; - + var prevWidth = this.ctx.lineWidth; for (var j in edges) { - + line = edges[j]; start = line[0]; end = line[1]; @@ -125,50 +133,50 @@ var branchcolor = line[4]; if(branchcolor) color = branchcolor; - + if (end > this.columns || start > this.columns) { this.columns += 1; } - + if (start == this.columns && start > end) { var fold = true; } - + x0 = this.cell[0] + this.box_size * start + this.box_size / 2; y0 = this.bg[1] - this.bg_height / 2; x1 = this.cell[0] + this.box_size * end + this.box_size / 2; y1 = this.bg[1] + this.bg_height / 2; - + this.edge(x0, y0, x1, y1, color, width); - + } this.ctx.lineWidth = prevWidth; - + // Draw the revision node in the right column - + column = node[0] color = node[1] - + radius = this.box_size / 8; x = this.cell[0] + this.box_size * column + this.box_size / 2; y = this.bg[1] - this.bg_height / 2; var add = this.vertex(x, y, color, parity, cur); backgrounds += add[0]; nodedata += add[1]; - + if (fold) this.columns -= 1; - + } - + document.getElementById('nodebgs').innerHTML += backgrounds; document.getElementById('graphnodes').innerHTML += nodedata; - + } } -process_dates = (function(document, RegExp, Math, isNaN, Date, _false, _true){ +function process_dates(parentSelector){ // derived from code from mercurial/templatefilter.py @@ -219,9 +227,9 @@ var delta = Math.floor((now.getTime() - once.getTime()) / 1000); - var future = _false; + var future = false; if (delta < 0){ - future = _true; + future = true; delta = -delta; if (delta > (30 * scales.year)){ return "in the distant future"; @@ -245,25 +253,21 @@ } } - return function(){ - var nodes = document.getElementsByTagName('*'); - var ageclass = new RegExp('\\bage\\b'); - var dateclass = new RegExp('\\bdate\\b'); - for (var i=0; i<nodes.length; ++i){ - var node = nodes[i]; - var classes = node.className; - if (ageclass.test(classes)){ - var agevalue = age(node.textContent); - if (dateclass.test(classes)){ - // We want both: date + (age) - node.textContent += ' ('+agevalue+')'; - } else { - node.textContent = agevalue; - } - } + var nodes = document.querySelectorAll((parentSelector || '') + ' .age'); + var dateclass = new RegExp('\\bdate\\b'); + for (var i=0; i<nodes.length; ++i){ + var node = nodes[i]; + var classes = node.className; + var agevalue = age(node.textContent); + if (dateclass.test(classes)){ + // We want both: date + (age) + node.textContent += ' ('+agevalue+')'; + } else { + node.title = node.textContent; + node.textContent = agevalue; } } -})(document, RegExp, Math, isNaN, Date, false, true) +} function toggleDiffstat() { var curdetails = document.getElementById('diffstatdetails').style.display; @@ -297,3 +301,142 @@ setLinewrap(!getLinewrap()); } + +function format(str, replacements) { + return str.replace(/%(\w+)%/g, function(match, p1) { + return String(replacements[p1]); + }); +} + +function makeRequest(url, method, onstart, onsuccess, onerror, oncomplete) { + xfr = new XMLHttpRequest(); + xfr.onreadystatechange = function() { + if (xfr.readyState === 4) { + try { + if (xfr.status === 200) { + onsuccess(xfr.responseText); + } else { + throw 'server error'; + } + } catch (e) { + onerror(e); + } finally { + oncomplete(); + } + } + }; + + xfr.open(method, url); + xfr.send(); + onstart(); + return xfr; +} + +function removeByClassName(className) { + var nodes = document.getElementsByClassName(className); + while (nodes.length) { + nodes[0].parentNode.removeChild(nodes[0]); + } +} + +function docFromHTML(html) { + var doc = document.implementation.createHTMLDocument(''); + doc.documentElement.innerHTML = html; + return doc; +} + +function appendFormatHTML(element, formatStr, replacements) { + element.insertAdjacentHTML('beforeend', format(formatStr, replacements)); +} + +function ajaxScrollInit(urlFormat, + nextPageVar, + nextPageVarGet, + containerSelector, + messageFormat, + mode) { + updateInitiated = false; + container = document.querySelector(containerSelector); + + function scrollHandler() { + if (updateInitiated) { + return; + } + + var scrollHeight = document.documentElement.scrollHeight; + var clientHeight = document.documentElement.clientHeight; + var scrollTop = document.body.scrollTop + || document.documentElement.scrollTop; + + if (scrollHeight - (scrollTop + clientHeight) < 50) { + updateInitiated = true; + removeByClassName('scroll-loading-error'); + container.lastElementChild.classList.add('scroll-separator'); + + if (!nextPageVar) { + var message = { + class: 'scroll-loading-info', + text: 'No more entries' + }; + appendFormatHTML(container, messageFormat, message); + return; + } + + makeRequest( + format(urlFormat, {next: nextPageVar}), + 'GET', + function onstart() { + var message = { + class: 'scroll-loading', + text: 'Loading...' + }; + appendFormatHTML(container, messageFormat, message); + }, + function onsuccess(htmlText) { + if (mode == 'graph') { + var addHeight = htmlText.match(/^<canvas id="graph".*height="(\d+)"><\/canvas>$/m)[1]; + addHeight = parseInt(addHeight); + graph.canvas.height = addHeight; + + var dataStr = htmlText.match(/^\s*var data = (.*);$/m)[1]; + var data = JSON.parse(dataStr) + if (data.length < nextPageVar) { + nextPageVar = undefined; + } + graph.reset(); + graph.render(data); + } else { + var doc = docFromHTML(htmlText); + var nodes = doc.querySelector(containerSelector).children; + var curClass = 'c' + Date.now(); + while (nodes.length) { + var node = nodes[0]; + node = document.adoptNode(node); + node.classList.add(curClass); + container.appendChild(node); + } + process_dates('.' + curClass); + } + + nextPageVar = nextPageVarGet(htmlText, nextPageVar); + }, + function onerror(errorText) { + var message = { + class: 'scroll-loading-error', + text: 'Error: ' + errorText + }; + appendFormatHTML(container, messageFormat, message); + }, + function oncomplete() { + removeByClassName('scroll-loading'); + updateInitiated = false; + scrollHandler(); + } + ); + } + } + + window.addEventListener('scroll', scrollHandler); + window.addEventListener('resize', scrollHandler); + scrollHandler(); +}
--- a/mercurial/templates/static/style-paper.css Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/templates/static/style-paper.css Sat Oct 19 14:21:05 2013 -0700 @@ -382,3 +382,27 @@ .breadcrumb a { color: blue; } + +.scroll-loading { + -webkit-animation: change_color 1s linear 0s infinite alternate; + -moz-animation: change_color 1s linear 0s infinite alternate; + -o-animation: change_color 1s linear 0s infinite alternate; + animation: change_color 1s linear 0s infinite alternate; +} + +@-webkit-keyframes change_color { + from { background-color: #A0CEFF; } to { } +} +@-moz-keyframes change_color { + from { background-color: #A0CEFF; } to { } +} +@-o-keyframes change_color { + from { background-color: #A0CEFF; } to { } +} +@keyframes change_color { + from { background-color: #A0CEFF; } to { } +} + +.scroll-loading-error { + background-color: #FFCCCC !important; +}
--- a/mercurial/ui.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/ui.py Sat Oct 19 14:21:05 2013 -0700 @@ -176,7 +176,7 @@ alternates = [name] for n in alternates: - value = self._data(untrusted).get(section, name, None) + value = self._data(untrusted).get(section, n, None) if value is not None: name = n break @@ -184,10 +184,11 @@ value = default if self.debugflag and not untrusted and self._reportuntrusted: - uvalue = self._ucfg.get(section, name) - if uvalue is not None and uvalue != value: - self.debug("ignoring untrusted configuration option " - "%s.%s = %s\n" % (section, name, uvalue)) + for n in alternates: + uvalue = self._ucfg.get(section, n) + if uvalue is not None and uvalue != value: + self.debug("ignoring untrusted configuration option " + "%s.%s = %s\n" % (section, n, uvalue)) return value def configpath(self, section, name, default=None, untrusted=False):
--- a/mercurial/unionrepo.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/unionrepo.py Sat Oct 19 14:21:05 2013 -0700 @@ -70,7 +70,7 @@ self.revlog2.rev(self.node(rev1)), self.revlog2.rev(self.node(rev2))) elif rev1 <= self.repotiprev and rev2 <= self.repotiprev: - return revlog.revlog.revdiff(self, rev1, rev2) + return self.baserevdiff(rev1, rev2) return mdiff.textdiff(self.revision(self.node(rev1)), self.revision(self.node(rev2))) @@ -93,10 +93,20 @@ text = self.revlog2.revision(node) self._cache = (node, rev, text) else: - text = revlog.revlog.revision(self, rev) + text = self.baserevision(rev) # already cached return text + def baserevision(self, nodeorrev): + # Revlog subclasses may override 'revision' method to modify format of + # content retrieved from revlog. To use unionrevlog with such class one + # needs to override 'baserevision' and make more specific call here. + return revlog.revlog.revision(self, nodeorrev) + + def baserevdiff(self, rev1, rev2): + # Exists for the same purpose as baserevision. + return revlog.revlog.revdiff(self, rev1, rev2) + def addrevision(self, text, transaction, link, p1=None, p2=None, d=None): raise NotImplementedError def addgroup(self, revs, linkmapper, transaction): @@ -114,6 +124,15 @@ unionrevlog.__init__(self, opener, self.indexfile, changelog2, linkmapper) + def baserevision(self, nodeorrev): + # Although changelog doesn't override 'revision' method, some extensions + # may replace this class with another that does. Same story with + # manifest and filelog classes. + return changelog.changelog.revision(self, nodeorrev) + + def baserevdiff(self, rev1, rev2): + return changelog.changelog.revdiff(self, rev1, rev2) + class unionmanifest(unionrevlog, manifest.manifest): def __init__(self, opener, opener2, linkmapper): manifest.manifest.__init__(self, opener) @@ -121,6 +140,12 @@ unionrevlog.__init__(self, opener, self.indexfile, manifest2, linkmapper) + def baserevision(self, nodeorrev): + return manifest.manifest.revision(self, nodeorrev) + + def baserevdiff(self, rev1, rev2): + return manifest.manifest.revdiff(self, rev1, rev2) + class unionfilelog(unionrevlog, filelog.filelog): def __init__(self, opener, path, opener2, linkmapper, repo): filelog.filelog.__init__(self, opener, path) @@ -129,6 +154,12 @@ linkmapper) self._repo = repo + def baserevision(self, nodeorrev): + return filelog.filelog.revision(self, nodeorrev) + + def baserevdiff(self, rev1, rev2): + return filelog.filelog.revdiff(self, rev1, rev2) + def _file(self, f): self._repo.file(f)
--- a/mercurial/url.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/url.py Sat Oct 19 14:21:05 2013 -0700 @@ -108,8 +108,13 @@ def proxy_open(self, req, proxy, type_): host = req.get_host().split(':')[0] - if host in self.no_list: - return None + for e in self.no_list: + if host == e: + return None + if e.startswith('*.') and host.endswith(e[2:]): + return None + if e.startswith('.') and host.endswith(e[1:]): + return None # work around a bug in Python < 2.4.2 # (it leaves a "\n" at the end of Proxy-authorization headers)
--- a/mercurial/util.h Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/util.h Sat Oct 19 14:21:05 2013 -0700 @@ -121,7 +121,12 @@ #ifdef _MSC_VER /* msvc 6.0 has problems */ #define inline __inline +typedef signed char int8_t; +typedef short int16_t; +typedef long int32_t; +typedef __int64 int64_t; typedef unsigned char uint8_t; +typedef unsigned short uint16_t; typedef unsigned long uint32_t; typedef unsigned __int64 uint64_t; #else
--- a/mercurial/util.py Sat Oct 19 14:20:31 2013 -0700 +++ b/mercurial/util.py Sat Oct 19 14:21:05 2013 -0700 @@ -242,6 +242,10 @@ def __contains__(self, key): return key in self._cache + def clear(self): + self._cache.clear() + self._order = deque() + def lrucachefunc(func): '''cache most recent results of function calls''' cache = {} @@ -466,7 +470,8 @@ return str(val) origcmd = cmd cmd = quotecommand(cmd) - if sys.platform == 'plan9': + if sys.platform == 'plan9' and (sys.version_info[0] == 2 + and sys.version_info[1] < 7): # subprocess kludge to work around issues in half-baked Python # ports, notably bichued/python: if not cwd is None:
--- a/setup.py Sat Oct 19 14:20:31 2013 -0700 +++ b/setup.py Sat Oct 19 14:21:05 2013 -0700 @@ -423,14 +423,21 @@ pymodules = [] +common_depends = ['mercurial/util.h'] + extmodules = [ - Extension('mercurial.base85', ['mercurial/base85.c']), - Extension('mercurial.bdiff', ['mercurial/bdiff.c']), - Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']), - Extension('mercurial.mpatch', ['mercurial/mpatch.c']), + Extension('mercurial.base85', ['mercurial/base85.c'], + depends=common_depends), + Extension('mercurial.bdiff', ['mercurial/bdiff.c'], + depends=common_depends), + Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'], + depends=common_depends), + Extension('mercurial.mpatch', ['mercurial/mpatch.c'], + depends=common_depends), Extension('mercurial.parsers', ['mercurial/dirs.c', 'mercurial/parsers.c', - 'mercurial/pathencode.c']), + 'mercurial/pathencode.c'], + depends=common_depends), ] osutil_ldflags = [] @@ -443,7 +450,8 @@ pymodules.append('mercurial.pure.osutil') else: extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'], - extra_link_args=osutil_ldflags)) + extra_link_args=osutil_ldflags, + depends=common_depends)) # the -mno-cygwin option has been deprecated for years Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler @@ -467,7 +475,8 @@ if hasfunction(cc, 'inotify_add_watch'): inotify = Extension('hgext.inotify.linux._inotify', ['hgext/inotify/linux/_inotify.c'], - ['mercurial']) + ['mercurial'], + depends=common_depends) inotify.optional = True extmodules.append(inotify) packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
--- a/tests/filterpyflakes.py Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/filterpyflakes.py Sat Oct 19 14:21:05 2013 -0700 @@ -46,6 +46,6 @@ continue lines.append((msgtype, line)) -for msgtype, line in sorted(lines, key = makekey): +for msgtype, line in sorted(lines, key=makekey): sys.stdout.write(line) print
--- a/tests/get-with-headers.py Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/get-with-headers.py Sat Oct 19 14:21:05 2013 -0700 @@ -43,8 +43,9 @@ print "%s: %s" % (h, response.getheader(h)) if not headeronly: print - data = response.read() - sys.stdout.write(data) + if response.status != 500: + data = response.read() + sys.stdout.write(data) if twice and response.getheader('ETag', None): tag = response.getheader('ETag')
--- a/tests/run-tests.py Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/run-tests.py Sat Oct 19 14:21:05 2013 -0700 @@ -341,6 +341,7 @@ hgrc.write('[defaults]\n') hgrc.write('backout = -d "0 0"\n') hgrc.write('commit = -d "0 0"\n') + hgrc.write('shelve = --date "0 0"\n') hgrc.write('tag = -d "0 0"\n') if options.inotify: hgrc.write('[extensions]\n') @@ -460,6 +461,9 @@ if options.compiler: compiler = '--compiler ' + options.compiler pure = options.pure and "--pure" or "" + py3 = '' + if sys.version_info[0] == 3: + py3 = '--c2to3' # Run installer in hg root script = os.path.realpath(sys.argv[0]) @@ -472,11 +476,11 @@ # least on Windows for now, deal with .pydistutils.cfg bugs # when they happen. nohome = '' - cmd = ('%(exe)s setup.py %(pure)s clean --all' + cmd = ('%(exe)s setup.py %(py3)s %(pure)s clean --all' ' build %(compiler)s --build-base="%(base)s"' ' install --force --prefix="%(prefix)s" --install-lib="%(libdir)s"' ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1' - % dict(exe=sys.executable, pure=pure, compiler=compiler, + % dict(exe=sys.executable, py3=py3, pure=pure, compiler=compiler, base=os.path.join(HGTMP, "build"), prefix=INST, libdir=PYTHONDIR, bindir=BINDIR, nohome=nohome, logfile=installerrs)) @@ -758,21 +762,19 @@ addsalt(n + 1, False) # Write out the script and execute it - fd, name = tempfile.mkstemp(suffix='hg-tst') - try: - for l in script: - os.write(fd, l) - os.close(fd) + name = wd + '.sh' + f = open(name, 'w') + for l in script: + f.write(l) + f.close() - cmd = '%s "%s"' % (options.shell, name) - vlog("# Running", cmd) - exitcode, output = run(cmd, wd, options, replacements, env) - # do not merge output if skipped, return hghave message instead - # similarly, with --debug, output is None - if exitcode == SKIPPED_STATUS or output is None: - return exitcode, output - finally: - os.remove(name) + cmd = '%s "%s"' % (options.shell, name) + vlog("# Running", cmd) + exitcode, output = run(cmd, wd, options, replacements, env) + # do not merge output if skipped, return hghave message instead + # similarly, with --debug, output is None + if exitcode == SKIPPED_STATUS or output is None: + return exitcode, output # Merge the script output back into a unified test @@ -921,8 +923,10 @@ else: return ignore("doesn't match keyword") + if not lctest.startswith("test-"): + return skip("not a test file") for ext, func, out in testtypes: - if lctest.startswith("test-") and lctest.endswith(ext): + if lctest.endswith(ext): runner = func ref = os.path.join(TESTDIR, test + out) break @@ -1043,7 +1047,7 @@ if _hgpath is not None: return _hgpath - cmd = '%s -c "import mercurial; print mercurial.__path__[0]"' + cmd = '%s -c "import mercurial; print (mercurial.__path__[0])"' pipe = os.popen(cmd % PYTHON) try: _hgpath = pipe.read().strip()
--- a/tests/test-archive.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-archive.t Sat Oct 19 14:21:05 2013 -0700 @@ -209,8 +209,7 @@ test-2c0277f05ed4/foo $ hg archive -r 0 -t tar rev-%r.tar - $ if [ -f rev-0.tar ]; then - $ fi + $ [ -f rev-0.tar ] test .hg_archival.txt
--- a/tests/test-casecollision-merge.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-casecollision-merge.t Sat Oct 19 14:21:05 2013 -0700 @@ -293,7 +293,7 @@ [255] $ hg update --check - abort: uncommitted local changes + abort: uncommitted changes [255] $ hg update --clean
--- a/tests/test-command-template.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-command-template.t Sat Oct 19 14:21:05 2013 -0700 @@ -500,6 +500,28 @@ 1 0 +Missing non-standard names give no error (backward compatibility): + + $ echo "changeset = '{c}'" > t + $ hg log --style ./t + +Defining non-standard name works: + + $ cat <<EOF > t + > changeset = '{c}' + > c = q + > EOF + $ hg log --style ./t + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0 + ui.style works: $ echo '[ui]' > .hg/hgrc
--- a/tests/test-commandserver.py.out Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-commandserver.py.out Sat Oct 19 14:21:05 2013 -0700 @@ -73,6 +73,7 @@ bundle.mainreporoot=$TESTTMP defaults.backout=-d "0 0" defaults.commit=-d "0 0" +defaults.shelve=--date "0 0" defaults.tag=-d "0 0" ui.slash=True ui.interactive=False @@ -81,6 +82,7 @@ runcommand -R foo showconfig ui defaults defaults.backout=-d "0 0" defaults.commit=-d "0 0" +defaults.shelve=--date "0 0" defaults.tag=-d "0 0" ui.slash=True ui.interactive=False
--- a/tests/test-convert-filemap.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-convert-filemap.t Sat Oct 19 14:21:05 2013 -0700 @@ -88,6 +88,32 @@ copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd $ cd .. + + +Test interaction with startrev and verify that changing it is handled properly: + + $ > empty + $ hg convert --filemap empty source movingstart --config convert.hg.startrev=3 -r4 + initializing destination movingstart repository + scanning source... + sorting... + converting... + 1 3: change bar quux + 0 4: first merge; change bar baz + $ hg convert --filemap empty source movingstart + scanning source... + sorting... + converting... + 3 5: change bar baz quux + 2 6: change foo baz + 1 7: second merge; change bar + warning: af455ce4166b3c9c88e6309c2b9332171dcea595 parent 61e22ca76c3b3e93df20338c4e02ce286898e825 is missing + warning: cf908b3eeedc301c9272ebae931da966d5b326c7 parent 59e1ab45c888289513b7354484dac8a88217beab is missing + 0 8: change foo + + +splitrepo tests + $ splitrepo() > { > msg="$1" @@ -384,6 +410,32 @@ o 0 "addb" files: b +Test rebuilding of map with unknown revisions in shamap - it used to crash + + $ cd branchpruning + $ hg up -r 2 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg merge 4 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ hg ci -m 'merging something' + $ cd .. + $ echo "53792d18237d2b64971fa571936869156655338d 6d955580116e82c4b029bd30f321323bae71a7f0" >> branchpruning-hg2/.hg/shamap + $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2 --debug + run hg source pre-conversion action + run hg sink pre-conversion action + scanning source... + scanning: 1 revisions + sorting... + converting... + 0 merging something + source: 2503605b178fe50e8fbbb0e77b97939540aa8c87 + converting: 0/1 revisions (0.00%) + unknown revmap source: 53792d18237d2b64971fa571936869156655338d + run hg sink post-conversion action + run hg source post-conversion action + + filemap rename undoing revision rename $ hg init renameundo
--- a/tests/test-convert-hg-sink.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-convert-hg-sink.t Sat Oct 19 14:21:05 2013 -0700 @@ -122,3 +122,271 @@ tip 2:6f4fd1df87fb some-tag 0:ba8636729451 $ cd .. + + +Test cases for hg-hg roundtrip + +Helper + + $ glog() + > { + > hg log -G --template '{rev} {node|short} "{desc}" files: {files}\n' $* + > } + +Create a tricky source repo + + $ hg init source + $ cd source + + $ echo 0 > 0 + $ hg ci -Aqm '0: add 0' + $ echo a > a + $ mkdir dir + $ echo b > dir/b + $ hg ci -qAm '1: add a and dir/b' + $ echo c > dir/c + $ hg ci -qAm '2: add dir/c' + $ hg copy a e + $ echo b >> b + $ hg ci -qAm '3: copy a to e, change b' + $ hg up -qr -3 + $ echo a >> a + $ hg ci -qAm '4: change a' + $ hg merge + merging a and e to e + 2 files updated, 1 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ hg copy b dir/d + $ hg ci -qAm '5: merge 2 and 3, copy b to dir/d' + $ echo a >> a + $ hg ci -qAm '6: change a' + + $ hg mani + 0 + a + b + dir/b + dir/c + dir/d + e + $ glog + @ 6 0613c8e59a3d "6: change a" files: a + | + o 5 717e9b37cdb7 "5: merge 2 and 3, copy b to dir/d" files: dir/d e + |\ + | o 4 86a55cb968d5 "4: change a" files: a + | | + o | 3 0e6e235919dd "3: copy a to e, change b" files: b e + | | + o | 2 0394b0d5e4f7 "2: add dir/c" files: dir/c + |/ + o 1 333546584845 "1: add a and dir/b" files: a dir/b + | + o 0 d1a24e2ebd23 "0: add 0" files: 0 + + $ cd .. + +Convert excluding rev 0 and dir/ (and thus rev2): + + $ cat << EOF > filemap + > exclude dir + > EOF + + $ hg convert --filemap filemap source dest --config convert.hg.revs=1:: + initializing destination dest repository + scanning source... + sorting... + converting... + 5 1: add a and dir/b + 4 2: add dir/c + 3 3: copy a to e, change b + 2 4: change a + 1 5: merge 2 and 3, copy b to dir/d + 0 6: change a + +Verify that conversion skipped rev 2: + + $ glog -R dest + o 4 78814e84a217 "6: change a" files: a + | + o 3 f7cff662c5e5 "5: merge 2 and 3, copy b to dir/d" files: e + |\ + | o 2 ab40a95b0072 "4: change a" files: a + | | + o | 1 bd51f17597bf "3: copy a to e, change b" files: b e + |/ + o 0 a4a1dae0fe35 "1: add a and dir/b" files: 0 a + + +Verify mapping correct in both directions: + + $ cat source/.hg/shamap + a4a1dae0fe3514cefd9b8541b7abbc8f44f946d5 333546584845f70c4cfecb992341aaef0e708166 + bd51f17597bf32268e68a560b206898c3960cda2 0e6e235919dd8e9285ba8eb5adf703af9ad99378 + ab40a95b00725307e79c2fd271000aa8af9759f4 86a55cb968d51770cba2a1630d6cc637b574580a + f7cff662c5e581e6f3f1a85ffdd2bcb35825f6ba 717e9b37cdb7eb9917ca8e30aa3f986e6d5b177d + 78814e84a217894517c2de392b903ed05e6871a4 0613c8e59a3ddb9789072ef52f1ed13496489bb4 + $ cat dest/.hg/shamap + 333546584845f70c4cfecb992341aaef0e708166 a4a1dae0fe3514cefd9b8541b7abbc8f44f946d5 + 0394b0d5e4f761ced559fd0bbdc6afc16cb3f7d1 a4a1dae0fe3514cefd9b8541b7abbc8f44f946d5 + 0e6e235919dd8e9285ba8eb5adf703af9ad99378 bd51f17597bf32268e68a560b206898c3960cda2 + 86a55cb968d51770cba2a1630d6cc637b574580a ab40a95b00725307e79c2fd271000aa8af9759f4 + 717e9b37cdb7eb9917ca8e30aa3f986e6d5b177d f7cff662c5e581e6f3f1a85ffdd2bcb35825f6ba + 0613c8e59a3ddb9789072ef52f1ed13496489bb4 78814e84a217894517c2de392b903ed05e6871a4 + +Verify meta data converted correctly: + + $ hg -R dest log -r 1 --debug -p --git + changeset: 1:bd51f17597bf32268e68a560b206898c3960cda2 + phase: draft + parent: 0:a4a1dae0fe3514cefd9b8541b7abbc8f44f946d5 + parent: -1:0000000000000000000000000000000000000000 + manifest: 1:040c72ed9b101773c24ac314776bfc846943781f + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + files+: b e + extra: branch=default + description: + 3: copy a to e, change b + + + diff --git a/b b/b + new file mode 100644 + --- /dev/null + +++ b/b + @@ -0,0 +1,1 @@ + +b + diff --git a/a b/e + copy from a + copy to e + +Verify files included and excluded correctly: + + $ hg -R dest manifest -r tip + 0 + a + b + e + + +Make changes in dest and convert back: + + $ hg -R dest up -q + $ echo dest > dest/dest + $ hg -R dest ci -Aqm 'change in dest' + $ hg -R dest tip + changeset: 5:a2e0e3cc6d1d + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: change in dest + + +(converting merges back after using a filemap will probably cause chaos so we +exclude merges.) + + $ hg convert dest source --config convert.hg.revs='!merge()' + scanning source... + sorting... + converting... + 0 change in dest + +Verify the conversion back: + + $ hg -R source log --debug -r tip + changeset: 7:e6d364a69ff1248b2099e603b0c145504cade6f0 + tag: tip + phase: draft + parent: 6:0613c8e59a3ddb9789072ef52f1ed13496489bb4 + parent: -1:0000000000000000000000000000000000000000 + manifest: 7:aa3e9542f3b76d4f1f1b2e9c7ce9dbb48b6a95ec + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + files+: dest + extra: branch=default + description: + change in dest + + +Files that had been excluded are still present: + + $ hg -R source manifest -r tip + 0 + a + b + dest + dir/b + dir/c + dir/d + e + +More source changes + + $ cd source + $ echo 1 >> a + $ hg ci -m '8: source first branch' + created new head + $ hg up -qr -2 + $ echo 2 >> a + $ hg ci -m '9: source second branch' + $ hg merge -q --tool internal:local + $ hg ci -m '10: source merge' + $ echo >> a + $ hg ci -m '11: source change' + + $ hg mani + 0 + a + b + dest + dir/b + dir/c + dir/d + e + + $ glog -r 6: + @ 11 0c8927d1f7f4 "11: source change" files: a + | + o 10 9ccb7ee8d261 "10: source merge" files: a + |\ + | o 9 f131b1518dba "9: source second branch" files: a + | | + o | 8 669cf0e74b50 "8: source first branch" files: a + | | + | o 7 e6d364a69ff1 "change in dest" files: dest + |/ + o 6 0613c8e59a3d "6: change a" files: a + | + $ cd .. + + $ hg convert --filemap filemap source dest --config convert.hg.revs=3: + scanning source... + sorting... + converting... + 3 8: source first branch + 2 9: source second branch + 1 10: source merge + 0 11: source change + + $ glog -R dest + o 9 8432d597b263 "11: source change" files: a + | + o 8 632ffacdcd6f "10: source merge" files: a + |\ + | o 7 049cfee90ee6 "9: source second branch" files: a + | | + o | 6 9b6845e036e5 "8: source first branch" files: a + | | + | @ 5 a2e0e3cc6d1d "change in dest" files: dest + |/ + o 4 78814e84a217 "6: change a" files: a + | + o 3 f7cff662c5e5 "5: merge 2 and 3, copy b to dir/d" files: e + |\ + | o 2 ab40a95b0072 "4: change a" files: a + | | + o | 1 bd51f17597bf "3: copy a to e, change b" files: b e + |/ + o 0 a4a1dae0fe35 "1: add a and dir/b" files: 0 a + + $ cd ..
--- a/tests/test-convert-hg-startrev.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-convert-hg-startrev.t Sat Oct 19 14:21:05 2013 -0700 @@ -183,3 +183,23 @@ b $ hg -q verify $ cd .. + +Convert from revset in convert.hg.revs + + $ hg convert --config convert.hg.revs='3:4+0' source revsetrepo + initializing destination revsetrepo repository + scanning source... + sorting... + converting... + 2 0: add a b f + 1 3: change a + 0 4: merge 2 and 3 + + $ glog revsetrepo + o 2 "4: merge 2 and 3" files: b c d e f + | + o 1 "3: change a" files: a + | + o 0 "0: add a b f" files: a b f + + $ cd ..
--- a/tests/test-convert.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-convert.t Sat Oct 19 14:21:05 2013 -0700 @@ -135,9 +135,8 @@ store original revision ID in changeset (forces target IDs to change). It takes a boolean argument and defaults to False. - convert.hg.startrev - convert start revision and its descendants. It takes a hg - revision identifier and defaults to 0. + convert.hg.revs + revset specifying the source revisions to convert. CVS Source ########## @@ -262,7 +261,7 @@ -s --source-type TYPE source repository type -d --dest-type TYPE destination repository type - -r --rev REV import up to target revision REV + -r --rev REV import up to source revision REV -A --authormap FILE remap usernames using this file --filemap FILE remap file names using contents of file --splicemap FILE splice synthesized history into place
--- a/tests/test-extension.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-extension.t Sat Oct 19 14:21:05 2013 -0700 @@ -406,17 +406,21 @@ > EOF $ echo "debugissue811 = $debugpath" >> $HGRCPATH $ echo "mq=" >> $HGRCPATH + $ echo "strip=" >> $HGRCPATH $ echo "hgext.mq=" >> $HGRCPATH $ echo "hgext/mq=" >> $HGRCPATH Show extensions: +(note that mq force load strip, also checking it's not loaded twice) $ hg debugextensions debugissue811 + strip mq Disabled extension commands: + $ ORGHGRCPATH=$HGRCPATH $ HGRCPATH= $ export HGRCPATH $ hg help email @@ -573,3 +577,134 @@ ** Python * (glob) ** Mercurial Distributed SCM (*) (glob) ** Extensions loaded: throw + +Restore HGRCPATH + + $ HGRCPATH=$ORGHGRCPATH + $ export HGRCPATH + +Commands handling multiple repositories at a time should invoke only +"reposetup()" of extensions enabling in the target repository. + + $ mkdir reposetup-test + $ cd reposetup-test + + $ cat > $TESTTMP/reposetuptest.py <<EOF + > from mercurial import extensions + > def reposetup(ui, repo): + > ui.write('reposetup() for %s\n' % (repo.root)) + > EOF + $ hg init src + $ echo a > src/a + $ hg -R src commit -Am '#0 at src/a' + adding a + $ echo '[extensions]' >> src/.hg/hgrc + $ echo '# enable extension locally' >> src/.hg/hgrc + $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc + $ hg -R src status + reposetup() for $TESTTMP/reposetup-test/src + + $ hg clone -U src clone-dst1 + reposetup() for $TESTTMP/reposetup-test/src + $ hg init push-dst1 + $ hg -q -R src push push-dst1 + reposetup() for $TESTTMP/reposetup-test/src + $ hg init pull-src1 + $ hg -q -R pull-src1 pull src + reposetup() for $TESTTMP/reposetup-test/src + + $ echo '[extensions]' >> $HGRCPATH + $ echo '# disable extension globally and explicitly' >> $HGRCPATH + $ echo 'reposetuptest = !' >> $HGRCPATH + $ hg clone -U src clone-dst2 + reposetup() for $TESTTMP/reposetup-test/src + $ hg init push-dst2 + $ hg -q -R src push push-dst2 + reposetup() for $TESTTMP/reposetup-test/src + $ hg init pull-src2 + $ hg -q -R pull-src2 pull src + reposetup() for $TESTTMP/reposetup-test/src + + $ echo '[extensions]' >> $HGRCPATH + $ echo '# enable extension globally' >> $HGRCPATH + $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> $HGRCPATH + $ hg clone -U src clone-dst3 + reposetup() for $TESTTMP/reposetup-test/src + reposetup() for $TESTTMP/reposetup-test/clone-dst3 + $ hg init push-dst3 + reposetup() for $TESTTMP/reposetup-test/push-dst3 + $ hg -q -R src push push-dst3 + reposetup() for $TESTTMP/reposetup-test/src + reposetup() for $TESTTMP/reposetup-test/push-dst3 + $ hg init pull-src3 + reposetup() for $TESTTMP/reposetup-test/pull-src3 + $ hg -q -R pull-src3 pull src + reposetup() for $TESTTMP/reposetup-test/pull-src3 + reposetup() for $TESTTMP/reposetup-test/src + + $ echo '[extensions]' >> src/.hg/hgrc + $ echo '# disable extension locally' >> src/.hg/hgrc + $ echo 'reposetuptest = !' >> src/.hg/hgrc + $ hg clone -U src clone-dst4 + reposetup() for $TESTTMP/reposetup-test/clone-dst4 + $ hg init push-dst4 + reposetup() for $TESTTMP/reposetup-test/push-dst4 + $ hg -q -R src push push-dst4 + reposetup() for $TESTTMP/reposetup-test/push-dst4 + $ hg init pull-src4 + reposetup() for $TESTTMP/reposetup-test/pull-src4 + $ hg -q -R pull-src4 pull src + reposetup() for $TESTTMP/reposetup-test/pull-src4 + +disabling in command line overlays with all configuration + $ hg --config extensions.reposetuptest=! clone -U src clone-dst5 + $ hg --config extensions.reposetuptest=! init push-dst5 + $ hg --config extensions.reposetuptest=! -q -R src push push-dst5 + $ hg --config extensions.reposetuptest=! init pull-src5 + $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src + + $ echo '[extensions]' >> $HGRCPATH + $ echo '# disable extension globally and explicitly' >> $HGRCPATH + $ echo 'reposetuptest = !' >> $HGRCPATH + $ hg init parent + $ hg init parent/sub1 + $ echo 1 > parent/sub1/1 + $ hg -R parent/sub1 commit -Am '#0 at parent/sub1' + adding 1 + $ hg init parent/sub2 + $ hg init parent/sub2/sub21 + $ echo 21 > parent/sub2/sub21/21 + $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21' + adding 21 + $ cat > parent/sub2/.hgsub <<EOF + > sub21 = sub21 + > EOF + $ hg -R parent/sub2 commit -Am '#0 at parent/sub2' + adding .hgsub + $ hg init parent/sub3 + $ echo 3 > parent/sub3/3 + $ hg -R parent/sub3 commit -Am '#0 at parent/sub3' + adding 3 + $ cat > parent/.hgsub <<EOF + > sub1 = sub1 + > sub2 = sub2 + > sub3 = sub3 + > EOF + $ hg -R parent commit -Am '#0 at parent' + adding .hgsub + $ echo '[extensions]' >> parent/.hg/hgrc + $ echo '# enable extension locally' >> parent/.hg/hgrc + $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc + $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc + $ hg -R parent status -S -A + reposetup() for $TESTTMP/reposetup-test/parent + reposetup() for $TESTTMP/reposetup-test/parent/sub2 + C .hgsub + C .hgsubstate + C sub1/1 + C sub2/.hgsub + C sub2/.hgsubstate + C sub2/sub21/21 + C sub3/3 + + $ cd ..
--- a/tests/test-generaldelta.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-generaldelta.t Sat Oct 19 14:21:05 2013 -0700 @@ -18,6 +18,6 @@ $ cd .. $ regsize=`du -s -b repo/.hg/store/00manifest.i | cut -f 1` $ gdsize=`du -s -b gdrepo/.hg/store/00manifest.i | cut -f 1` - $ if [ $regsize -gt $gdsize ]; then + $ if [ $regsize -lt $gdsize ]; then > echo 'generaldelta increased size of a revlog!' > fi
--- a/tests/test-graft.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-graft.t Sat Oct 19 14:21:05 2013 -0700 @@ -71,7 +71,7 @@ $ hg up -q 0 $ echo foo > a $ hg graft 1 - abort: outstanding uncommitted changes + abort: uncommitted changes [255] $ hg revert a @@ -117,7 +117,7 @@ $ hg graft 1 5 4 3 'merge()' 2 -n skipping ungraftable merge revision 6 - skipping already grafted revision 2 + skipping revision 2 (already grafted to 7) grafting revision 1 grafting revision 5 grafting revision 4 @@ -126,7 +126,7 @@ $ hg graft 1 5 4 3 'merge()' 2 --debug skipping ungraftable merge revision 6 scanning for duplicate grafts - skipping already grafted revision 2 + skipping revision 2 (already grafted to 7) grafting revision 1 searching for copies back to rev 1 unmatched files in local: @@ -196,9 +196,9 @@ $ hg graft 1 5 4 3 'merge()' 2 skipping ungraftable merge revision 6 - skipping already grafted revision 2 - skipping already grafted revision 1 - skipping already grafted revision 5 + skipping revision 2 (already grafted to 7) + skipping revision 1 (already grafted to 8) + skipping revision 5 (already grafted to 9) grafting revision 4 merging e warning: conflicts during merge. @@ -314,18 +314,18 @@ Disallow grafting already grafted csets with the same origin onto each other $ hg up -q 13 $ hg graft 2 - skipping already grafted revision 2 + skipping revision 2 (already grafted to 13) [255] $ hg graft 7 - skipping already grafted revision 7 (same origin 2) + skipping already grafted revision 7 (13 also has origin 2) [255] $ hg up -q 7 $ hg graft 2 - skipping already grafted revision 2 + skipping revision 2 (already grafted to 7) [255] $ hg graft tip - skipping already grafted revision 13 (same origin 2) + skipping already grafted revision 13 (7 also has origin 2) [255] Graft with --log
--- a/tests/test-help.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-help.t Sat Oct 19 14:21:05 2013 -0700 @@ -930,8 +930,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <table class="bigtable"> <tr><td colspan="2"><h2><a name="main" href="#topics">Topics</a></h2></td></tr> @@ -1490,8 +1490,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div id="doc"> <p> @@ -1656,8 +1656,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div id="doc"> <p> @@ -1852,8 +1852,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div id="doc"> <h1>Specifying Single Revisions</h1>
--- a/tests/test-hgweb-commands.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-hgweb-commands.t Sat Oct 19 14:21:05 2013 -0700 @@ -258,8 +258,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" value="" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -305,6 +305,21 @@ | rev 3: <a href="/shortlog/2ef0ac749a14">(0)</a> <a href="/shortlog/tip">tip</a> </div> + <script type="text/javascript"> + ajaxScrollInit( + '/shortlog/%next%', + '', <!-- NEXTHASH + function (htmlText, previousVal) { + var m = htmlText.match(/'(\w+)', <!-- NEXTHASH/); + return m ? m[1] : null; + }, + '.bigtable > tbody:nth-of-type(2)', + '<tr class="%class%">\ + <td colspan="3" style="text-align: center;">%text%</td>\ + </tr>' + ); + </script> + </div> </div> @@ -362,8 +377,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">base</div> @@ -495,11 +510,17 @@ <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2> <h3>searching for 'base'</h3> + <p> + Assuming literal keyword search. + + + </p> + <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" value="base"></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -537,6 +558,162 @@ </body> </html> + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=stable&style=raw' | grep 'revision:' + revision: 2 + +Search with revset syntax + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=tip^&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "tip^" + # Mode revset expression search + + changeset: 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe + revision: 2 + user: test + date: Thu, 01 Jan 1970 00:00:00 +0000 + summary: branch + branch: stable + + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(),2)^&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "last(all(),2)^" + # Mode revset expression search + + changeset: 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe + revision: 2 + user: test + date: Thu, 01 Jan 1970 00:00:00 +0000 + summary: branch + branch: stable + + changeset: a4f92ed23982be056b9852de5dfe873eaac7f0de + revision: 1 + user: test + date: Thu, 01 Jan 1970 00:00:00 +0000 + summary: Added tag 1.0 for changeset 2ef0ac749a14 + branch: default + + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(,2)^&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "last(all(,2)^" + # Mode literal keyword search + + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(al(),2)^&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "last(al(),2)^" + # Mode literal keyword search + + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(anotherthing)&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "bookmark(anotherthing)" + # Mode revset expression search + + changeset: 2ef0ac749a14e4f57a5a822464a0902c6f7f448f + revision: 0 + user: test + date: Thu, 01 Jan 1970 00:00:00 +0000 + summary: base + tag: 1.0 + bookmark: anotherthing + + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(abc)&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "bookmark(abc)" + # Mode literal keyword search + + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=deadbeef:&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "deadbeef:" + # Mode literal keyword search + + + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=user("test")&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "user("test")" + # Mode revset expression search + + changeset: cad8025a2e87f88c06259790adfa15acb4080123 + revision: 3 + user: test + date: Thu, 01 Jan 1970 00:00:00 +0000 + summary: branch commit with null character: \x00 (esc) + branch: unstable + tag: tip + bookmark: something + + changeset: 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe + revision: 2 + user: test + date: Thu, 01 Jan 1970 00:00:00 +0000 + summary: branch + branch: stable + + changeset: a4f92ed23982be056b9852de5dfe873eaac7f0de + revision: 1 + user: test + date: Thu, 01 Jan 1970 00:00:00 +0000 + summary: Added tag 1.0 for changeset 2ef0ac749a14 + branch: default + + changeset: 2ef0ac749a14e4f57a5a822464a0902c6f7f448f + revision: 0 + user: test + date: Thu, 01 Jan 1970 00:00:00 +0000 + summary: base + tag: 1.0 + bookmark: anotherthing + + + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=user("re:test")&style=raw' + 200 Script output follows + + + # HG changesets search + # Node ID cad8025a2e87f88c06259790adfa15acb4080123 + # Query "user("re:test")" + # Mode literal keyword search + + File-related @@ -614,8 +791,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">Added tag 1.0 for changeset 2ef0ac749a14</div> @@ -637,7 +814,6 @@ <th class="author">children</th> <td class="author"><a href="/file/1d22e65f027e/foo">1d22e65f027e</a> </td> </tr> - </table> <div class="overflow"> @@ -1256,8 +1432,10 @@ Graph json escape of multibyte character - $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/' \ - > | grep -a '^var data =' + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/' > out + >>> for line in open("out"): + ... if line.startswith("var data ="): + ... print line, var data = [["061dd13ba3c3", [0, 1], [[0, 0, 1, -1, ""]], "\\u80fd", "test", "1970-01-01", ["unstable", true], ["tip"], ["something"]], ["cad8025a2e87", [0, 1], [[0, 0, 1, 3, "FF0000"]], "branch commit with null character: \x00", "test", "1970-01-01", ["unstable", false], [], []], ["1d22e65f027e", [0, 1], [[0, 0, 1, 3, ""]], "branch", "test", "1970-01-01", ["stable", true], [], []], ["a4f92ed23982", [0, 1], [[0, 0, 1, 3, ""]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]]; (esc) capabilities
--- a/tests/test-hgweb-descend-empties.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-hgweb-descend-empties.t Sat Oct 19 14:21:05 2013 -0700 @@ -76,8 +76,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <table class="bigtable">
--- a/tests/test-hgweb-diffs.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-hgweb-diffs.t Sat Oct 19 14:21:05 2013 -0700 @@ -84,8 +84,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">a</div> @@ -246,8 +246,8 @@ <form class="search" action="/log"> <p></p> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">b</div> @@ -269,7 +269,6 @@ <th>children</th> <td></td> </tr> - </table> <div class="overflow"> @@ -349,8 +348,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">a</div> @@ -515,8 +514,8 @@ <form class="search" action="/log"> <p></p> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">b</div> @@ -538,7 +537,6 @@ <th>children</th> <td></td> </tr> - </table> <div class="overflow"> @@ -615,8 +613,8 @@ <form class="search" action="/log"> <p></p> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">a</div> @@ -638,7 +636,6 @@ <th>children</th> <td></td> </tr> - </table> <div class="overflow"> @@ -737,8 +734,8 @@ <form class="search" action="/log"> <p></p> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">c</div> @@ -760,7 +757,6 @@ <th>children</th> <td></td> </tr> - </table> <div class="overflow"> @@ -861,8 +857,8 @@ <form class="search" action="/log"> <p></p> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">d</div> @@ -884,7 +880,6 @@ <th>children</th> <td></td> </tr> - </table> <div class="overflow">
--- a/tests/test-hgweb-empty.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-hgweb-empty.t Sat Oct 19 14:21:05 2013 -0700 @@ -63,8 +63,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" value="" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -90,6 +90,21 @@ | rev -1: </div> + <script type="text/javascript"> + ajaxScrollInit( + '/shortlog/%next%', + '', <!-- NEXTHASH + function (htmlText, previousVal) { + var m = htmlText.match(/'(\w+)', <!-- NEXTHASH/); + return m ? m[1] : null; + }, + '.bigtable > tbody:nth-of-type(2)', + '<tr class="%class%">\ + <td colspan="3" style="text-align: center;">%text%</td>\ + </tr>' + ); + </script> + </div> </div> @@ -158,8 +173,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" value="" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -185,6 +200,21 @@ | rev -1: </div> + <script type="text/javascript"> + ajaxScrollInit( + '/shortlog/%next%', + '', <!-- NEXTHASH + function (htmlText, previousVal) { + var m = htmlText.match(/'(\w+)', <!-- NEXTHASH/); + return m ? m[1] : null; + }, + '.bigtable > tbody:nth-of-type(2)', + '<tr class="%class%">\ + <td colspan="3" style="text-align: center;">%text%</td>\ + </tr>' + ); + </script> + </div> </div> @@ -249,8 +279,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -329,6 +359,17 @@ | rev -1: </div> + <script type="text/javascript"> + ajaxScrollInit( + '/graph/-1?revcount=%next%', + 60+60, + function (htmlText, previousVal) { return previousVal + 60; }, + '#wrapper', + '<div class="%class%" style="text-align: center;">%text%</div>', + 'graph' + ); + </script> + </div> </div> @@ -385,8 +426,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <table class="bigtable">
--- a/tests/test-hgweb-filelog.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-hgweb-filelog.t Sat Oct 19 14:21:05 2013 -0700 @@ -170,8 +170,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -279,8 +279,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -388,8 +388,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -492,8 +492,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="navigate"> @@ -576,8 +576,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30"></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">
--- a/tests/test-hgweb-removed.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-hgweb-removed.t Sat Oct 19 14:21:05 2013 -0700 @@ -65,8 +65,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">del</div> @@ -190,8 +190,8 @@ <form class="search" action="/log"> <p></p> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">del</div> @@ -213,7 +213,6 @@ <th>children</th> <td></td> </tr> - </table> <div class="overflow">
--- a/tests/test-hgweb.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-hgweb.t Sat Oct 19 14:21:05 2013 -0700 @@ -81,8 +81,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30"></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description"> @@ -171,8 +171,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30"></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description"> @@ -249,8 +249,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <table class="bigtable">
--- a/tests/test-highlight.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-highlight.t Sat Oct 19 14:21:05 2013 -0700 @@ -109,8 +109,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">a</div> @@ -132,7 +132,6 @@ <th class="author">children</th> <td class="author"></td> </tr> - </table> <div class="overflow"> @@ -241,8 +240,8 @@ <form class="search" action="/log"> <p><input name="rev" id="search1" type="text" size="30" /></p> - <div id="hint">find changesets by author, revision, - files, or words in the commit message</div> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> </form> <div class="description">a</div> @@ -264,7 +263,6 @@ <th class="author">children</th> <td class="author"></td> </tr> - </table> <div class="overflow">
--- a/tests/test-import-merge.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-import-merge.t Sat Oct 19 14:21:05 2013 -0700 @@ -129,7 +129,9 @@ $ echo a>>a $ hg ci -m3 $ hg export 2 | head -7 > ../a.patch - $ hg export tip | tail -n +8 >> ../a.patch + $ hg export tip > out + >>> apatch = open("../a.patch", "a") + >>> apatch.write("".join(open("out").readlines()[7:])) $ cd .. $ hg clone -qr0 repo3 repo3-clone
--- a/tests/test-issue1502.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-issue1502.t Sat Oct 19 14:21:05 2013 -0700 @@ -19,7 +19,8 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) - not updating: crosses branches (merge branches or update --check to force update) + not updating: not a linear update + (merge or update --check to force update) $ hg -R foo1 book branchy $ hg -R foo1 book
--- a/tests/test-largefiles.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-largefiles.t Sat Oct 19 14:21:05 2013 -0700 @@ -1104,7 +1104,7 @@ "update --check" refuses to update with uncommitted changes. $ hg update --check 8 - abort: uncommitted local changes + abort: uncommitted changes [255] "update --clean" leaves correct largefiles in working copy, even when there is @@ -2191,3 +2191,64 @@ $ cd .. + +Check whether "largefiles" feature is supported only in repositories +enabling largefiles extension. + + $ mkdir individualenabling + $ cd individualenabling + + $ hg init enabledlocally + $ echo large > enabledlocally/large + $ hg -R enabledlocally add --large enabledlocally/large + $ hg -R enabledlocally commit -m '#0' + Invoking status precommit hook + A large + + $ hg init notenabledlocally + $ echo large > notenabledlocally/large + $ hg -R notenabledlocally add --large notenabledlocally/large + $ hg -R notenabledlocally commit -m '#0' + Invoking status precommit hook + A large + + $ cat >> $HGRCPATH <<EOF + > [extensions] + > # disable globally + > largefiles=! + > EOF + $ cat >> enabledlocally/.hg/hgrc <<EOF + > [extensions] + > # enable locally + > largefiles= + > EOF + $ hg -R enabledlocally root + $TESTTMP/individualenabling/enabledlocally + $ hg -R notenabledlocally root + abort: unknown repository format: requires features 'largefiles' (upgrade Mercurial)! + [255] + + $ hg init push-dst + $ hg -R enabledlocally push push-dst + pushing to push-dst + abort: required features are not supported in the destination: largefiles + [255] + + $ hg init pull-src + $ hg -R pull-src pull enabledlocally + pulling from enabledlocally + abort: required features are not supported in the destination: largefiles + [255] + + $ hg clone enabledlocally clone-dst + abort: unknown repository format: requires features 'largefiles' (upgrade Mercurial)! + [255] + $ test -d clone-dst + [1] + $ hg clone --pull enabledlocally clone-pull-dst + abort: required features are not supported in the destination: largefiles + [255] + $ test -d clone-pull-dst + [1] + + $ cd ..
--- a/tests/test-lrucachedict.py Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-lrucachedict.py Sat Oct 19 14:21:05 2013 -0700 @@ -31,5 +31,8 @@ d['f'] = 'vf' printifpresent(d, ['b', 'c', 'd', 'e', 'f']) + d.clear() + printifpresent(d, ['b', 'c', 'd', 'e', 'f']) + if __name__ == '__main__': test_lrucachedict()
--- a/tests/test-lrucachedict.py.out Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-lrucachedict.py.out Sat Oct 19 14:21:05 2013 -0700 @@ -24,3 +24,8 @@ 'e' in d: False 'f' in d: True d['f']: vf +'b' in d: False +'c' in d: False +'d' in d: False +'e' in d: False +'f' in d: False
--- a/tests/test-merge-force.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-merge-force.t Sat Oct 19 14:21:05 2013 -0700 @@ -19,7 +19,7 @@ Should fail, since there are deleted files: $ hg merge - abort: outstanding uncommitted changes + abort: uncommitted changes (use 'hg status' to list changes) [255]
--- a/tests/test-merge-subrepos.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-merge-subrepos.t Sat Oct 19 14:21:05 2013 -0700 @@ -21,5 +21,5 @@ Should fail, since there are added files to subrepo: $ hg merge - abort: outstanding uncommitted changes in subrepository 'subrepo' + abort: uncommitted changes in subrepository 'subrepo' [255]
--- a/tests/test-merge1.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-merge1.t Sat Oct 19 14:21:05 2013 -0700 @@ -140,7 +140,7 @@ $ echo This is file b22 > b merge fails $ hg merge 2 - abort: outstanding uncommitted changes + abort: uncommitted changes (use 'hg status' to list changes) [255] merge expected! @@ -177,7 +177,7 @@ $ echo This is file b33 > b merge of b should fail $ hg merge 2 - abort: outstanding uncommitted changes + abort: uncommitted changes (use 'hg status' to list changes) [255] merge of b expected
--- a/tests/test-merge5.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-merge5.t Sat Oct 19 14:21:05 2013 -0700 @@ -14,11 +14,12 @@ $ hg update 1 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg update - abort: crosses branches (merge branches or update --check to force update) + abort: not a linear update + (merge or update --check to force update) [255] $ rm b $ hg update -c - abort: uncommitted local changes + abort: uncommitted changes [255] $ hg revert b $ hg update -c @@ -32,7 +33,8 @@ Should abort: $ hg update -y 1 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) [255] $ mv c a
--- a/tests/test-mq-strip.t Sat Oct 19 14:20:31 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,503 +0,0 @@ - $ echo "[extensions]" >> $HGRCPATH - $ echo "mq=" >> $HGRCPATH - $ echo "graphlog=" >> $HGRCPATH - - $ restore() { - > hg unbundle -q .hg/strip-backup/* - > rm .hg/strip-backup/* - > } - $ teststrip() { - > hg up -C $1 - > echo % before update $1, strip $2 - > hg parents - > hg --traceback strip $2 - > echo % after update $1, strip $2 - > hg parents - > restore - > } - - $ hg init test - $ cd test - - $ echo foo > bar - $ hg ci -Ama - adding bar - - $ echo more >> bar - $ hg ci -Amb - - $ echo blah >> bar - $ hg ci -Amc - - $ hg up 1 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ echo blah >> bar - $ hg ci -Amd - created new head - - $ echo final >> bar - $ hg ci -Ame - - $ hg log - changeset: 4:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - changeset: 3:65bd5f99a4a3 - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: d - - changeset: 2:264128213d29 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: c - - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - - $ teststrip 4 4 - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 4, strip 4 - changeset: 4:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 4, strip 4 - changeset: 3:65bd5f99a4a3 - tag: tip - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: d - - $ teststrip 4 3 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 4, strip 3 - changeset: 4:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 4, strip 3 - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - $ teststrip 1 4 - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 1, strip 4 - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 1, strip 4 - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - $ teststrip 4 2 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 4, strip 2 - changeset: 4:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 4, strip 2 - changeset: 3:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - $ teststrip 4 1 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 4, strip 1 - changeset: 4:264128213d29 - tag: tip - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: c - - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 4, strip 1 - changeset: 0:9ab35a2d17cb - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - $ teststrip null 4 - 0 files updated, 0 files merged, 1 files removed, 0 files unresolved - % before update null, strip 4 - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update null, strip 4 - - $ hg log - changeset: 4:264128213d29 - tag: tip - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: c - - changeset: 3:443431ffac4f - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - changeset: 2:65bd5f99a4a3 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: d - - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - - $ hg up -C 2 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg merge 4 - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - (branch merge, don't forget to commit) - -before strip of merge parent - - $ hg parents - changeset: 2:65bd5f99a4a3 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: d - - changeset: 4:264128213d29 - tag: tip - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: c - - $ hg strip 4 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - -after strip of merge parent - - $ hg parents - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - $ restore - - $ hg up - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg glog - @ changeset: 4:264128213d29 - | tag: tip - | parent: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: c - | - | o changeset: 3:443431ffac4f - | | user: test - | | date: Thu Jan 01 00:00:00 1970 +0000 - | | summary: e - | | - | o changeset: 2:65bd5f99a4a3 - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: d - | - o changeset: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - -2 is parent of 3, only one strip should happen - - $ hg strip "roots(2)" 3 - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg glog - @ changeset: 2:264128213d29 - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: c - | - o changeset: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - $ restore - $ hg glog - o changeset: 4:443431ffac4f - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: e - | - o changeset: 3:65bd5f99a4a3 - | parent: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: d - | - | @ changeset: 2:264128213d29 - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: c - | - o changeset: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - -2 different branches: 2 strips - - $ hg strip 2 4 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg glog - o changeset: 2:65bd5f99a4a3 - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: d - | - @ changeset: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - $ restore - -2 different branches and a common ancestor: 1 strip - - $ hg strip 1 "2|4" - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ restore - -stripping an empty revset - - $ hg strip "1 and not 1" - abort: empty revision set - [255] - -remove branchy history for qimport tests - - $ hg strip 3 - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - - -strip of applied mq should cleanup status file - - $ hg up -C 3 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ echo fooagain >> bar - $ hg ci -mf - $ hg qimport -r tip:2 - -applied patches before strip - - $ hg qapplied - 2.diff - 3.diff - 4.diff - -stripping revision in queue - - $ hg strip 3 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - -applied patches after stripping rev in queue - - $ hg qapplied - 2.diff - -stripping ancestor of queue - - $ hg strip 1 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - -applied patches after stripping ancestor of queue - - $ hg qapplied - -Verify strip protects against stripping wc parent when there are uncommited mods - - $ echo b > b - $ hg add b - $ hg ci -m 'b' - $ hg log --graph - @ changeset: 1:7519abd79d14 - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - - $ echo c > b - $ echo c > bar - $ hg strip tip - abort: local changes found - [255] - $ hg strip tip --keep - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg log --graph - @ changeset: 0:9ab35a2d17cb - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - $ hg status - M bar - ? b - -Strip adds, removes, modifies with --keep - - $ touch b - $ hg add b - $ hg commit -mb - $ touch c - -... with a clean working dir - - $ hg add c - $ hg rm bar - $ hg commit -mc - $ hg status - $ hg strip --keep tip - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg status - ! bar - ? c - -... with a dirty working dir - - $ hg add c - $ hg rm bar - $ hg commit -mc - $ hg status - $ echo b > b - $ echo d > d - $ hg strip --keep tip - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg status - M b - ! bar - ? c - ? d - $ cd .. - -stripping many nodes on a complex graph (issue3299) - - $ hg init issue3299 - $ cd issue3299 - $ hg debugbuilddag '@a.:a@b.:b.:x<a@a.:a<b@b.:b<a@a.:a' - $ hg strip 'not ancestors(x)' - saved backup bundle to $TESTTMP/issue3299/.hg/strip-backup/*-backup.hg (glob) - -test hg strip -B bookmark - - $ cd .. - $ hg init bookmarks - $ cd bookmarks - $ hg debugbuilddag '..<2.*1/2:m<2+3:c<m+3:a<2.:b' - $ hg bookmark -r 'a' 'todelete' - $ hg bookmark -r 'b' 'B' - $ hg bookmark -r 'b' 'nostrip' - $ hg bookmark -r 'c' 'delete' - $ hg up -C todelete - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg strip -B nostrip - bookmark 'nostrip' deleted - abort: empty revision set - [255] - $ hg strip -B todelete - bookmark 'todelete' deleted - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob) - $ hg id -ir dcbb326fdec2 - abort: unknown revision 'dcbb326fdec2'! - [255] - $ hg id -ir d62d843c9a01 - d62d843c9a01 - $ hg bookmarks - B 9:ff43616e5d0f - delete 6:2702dd0c91e7 - $ hg strip -B delete - bookmark 'delete' deleted - saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob) - $ hg id -ir 6:2702dd0c91e7 - abort: unknown revision '2702dd0c91e7'! - [255] - - $ cd ..
--- a/tests/test-mq-subrepo.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-mq-subrepo.t Sat Oct 19 14:21:05 2013 -0700 @@ -213,6 +213,7 @@ handle subrepos safely on qpush/qpop +(and we cannot qpop / qpush with a modified subrepo) $ mkrepo repo-2499-qpush $ mksubrepo sub @@ -220,31 +221,58 @@ $ hg -R sub ci -m0sub $ echo sub = sub > .hgsub $ hg add .hgsub - $ hg qnew -m0 0.diff + $ hg commit -m0 $ hg debugsub path sub source sub revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31 + $ echo foo > ./sub/a + $ hg -R sub commit -m foo + $ hg commit -m1 + $ hg qimport -r "0:tip" + $ hg -R sub id --id + aa037b301eba qpop + $ hg -R sub update 0000 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg qpop - popping 0.diff - patch queue now empty - $ hg status -AS - $ hg debugsub - -qpush - $ hg qpush - applying 0.diff + abort: local changed subrepos found, refresh first + [255] + $ hg revert sub + reverting subrepo sub + adding sub/a + $ hg qpop + popping 1.diff now at: 0.diff $ hg status -AS C .hgsub C .hgsubstate C sub/a - $ hg debugsub - path sub - source sub - revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31 + $ hg -R sub id --id + b2fdb12cd82b + +qpush + $ hg -R sub update 0000 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg qpush + abort: local changed subrepos found, refresh first + [255] + $ hg revert sub + reverting subrepo sub + adding sub/a + $ hg qpush + applying 1.diff + subrepository sub diverged (local revision: b2fdb12cd82b, remote revision: aa037b301eba) + (M)erge, keep (l)ocal or keep (r)emote? m + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + now at: 1.diff + $ hg status -AS + C .hgsub + C .hgsubstate + C sub/a + $ hg -R sub id --id + aa037b301eba $ cd ..
--- a/tests/test-mq.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-mq.t Sat Oct 19 14:21:05 2013 -0700 @@ -67,6 +67,9 @@ changes will be tolerated and preserved. If incompatible options such as -f/--force or --exact are passed, this setting is ignored. + This extension used to provide a strip command. This command now lives in the + strip extension. + list of commands: qapplied print the patches already applied @@ -91,7 +94,6 @@ qseries print the entire series file qtop print the name of the current patch qunapplied print the patches not yet applied - strip strip changesets and all their descendants from the repository use "hg -v help mq" to show builtin aliases and global options
--- a/tests/test-parse-date.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-parse-date.t Sat Oct 19 14:21:05 2013 -0700 @@ -242,7 +242,7 @@ >>> yesterday = (datetime.date.today() - datetime.timedelta(days=1)).strftime("%b %d") >>> dates = open('dates', 'w') >>> dates.write(today + '\n') - >>> dates.write(yesterday) + >>> dates.write(yesterday + '\n') >>> dates.close() $ hg ci -d "`sed -n '1p' dates`" -m "today is a good day to code" $ hg log -d today --template '{desc}\n'
--- a/tests/test-progress.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-progress.t Sat Oct 19 14:21:05 2013 -0700 @@ -1,6 +1,14 @@ $ cat > loop.py <<EOF > from mercurial import commands + > import time + > class incrementingtime(object): + > def __init__(self): + > self._time = 0.0 + > def __call__(self): + > self._time += 0.25 + > return self._time + > time.time = incrementingtime() > > def loop(ui, loops, **opts): > loops = int(loops) @@ -19,9 +27,14 @@ > if opts.get('parallel'): > ui.progress('other', i, 'other.%d' % i, 'othernum', total) > if nested: - > for j in range(2): - > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2) - > ui.progress('nested', None, 'nested.done', 'nestnum', 2) + > nested_steps = 2 + > if i and i % 4 == 0: + > nested_steps = 5 + > for j in range(nested_steps): + > ui.progress( + > 'nested', j, 'nested.%d' % j, 'nestnum', nested_steps) + > ui.progress( + > 'nested', None, 'nested.done', 'nestnum', nested_steps) > ui.progress('loop', None, 'loop.done', 'loopnum', total) > > commands.norepo += " loop" @@ -69,6 +82,24 @@ loop [===============================> ] 2/3\r (no-eol) (esc) \r (no-eol) (esc) +Test nested long-lived topic which has the same name as a short-lived +peer. We shouldn't get stuck showing the short-lived inner steps, and +should go back to skipping the inner steps when the slow nested step +finishes. + + $ hg -y loop 7 --nested + \r (no-eol) (esc) + loop [ ] 0/7\r (no-eol) (esc) + loop [=====> ] 1/7\r (no-eol) (esc) + loop [============> ] 2/7\r (no-eol) (esc) + loop [===================> ] 3/7\r (no-eol) (esc) + loop [==========================> ] 4/7\r (no-eol) (esc) + nested [==========================> ] 3/5\r (no-eol) (esc) + nested [===================================> ] 4/5\r (no-eol) (esc) + loop [=================================> ] 5/7\r (no-eol) (esc) + loop [========================================> ] 6/7\r (no-eol) (esc) + \r (no-eol) (esc) + $ hg --config progress.changedelay=0 -y loop 3 --nested \r (no-eol) (esc)
--- a/tests/test-pull-update.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-pull-update.t Sat Oct 19 14:21:05 2013 -0700 @@ -25,7 +25,8 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) - not updating: crosses branches (merge branches or update --check to force update) + not updating: not a linear update + (merge or update --check to force update) $ cd ../tt @@ -38,7 +39,8 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) - not updating: crosses branches (merge branches or update --check to force update) + not updating: not a linear update + (merge or update --check to force update) $ HGMERGE=true hg merge merging foo
--- a/tests/test-push-warn.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-push-warn.t Sat Oct 19 14:21:05 2013 -0700 @@ -354,6 +354,29 @@ adding file changes added 1 changesets with 1 changes to 1 files +Pushing muliple headed new branch: + + $ echo 14 > foo + $ hg -q branch f + $ hg -q ci -m 14 + $ echo 15 > foo + $ hg -q ci -m 15 + $ hg -q up 14 + $ echo 16 > foo + $ hg -q ci -m 16 + $ hg push --branch f --new-branch ../f + pushing to ../f + searching for changes + abort: push creates multiple headed new branch 'f' + (merge or see "hg help push" for detail about pushing new heads) + [255] + $ hg push --branch f --new-branch --force ../f + pushing to ../f + searching for changes + adding changesets + adding manifests + adding file changes + added 3 changesets with 3 changes to 1 files (+1 heads) Checking prepush logic does not allow silently pushing multiple new heads:
--- a/tests/test-rebase-obsolete.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-rebase-obsolete.t Sat Oct 19 14:21:05 2013 -0700 @@ -178,9 +178,9 @@ 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {'date': '*', 'user': 'test'} (glob) 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 {'date': '*', 'user': 'test'} (glob) 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {'date': '*', 'user': 'test'} (glob) - 08483444fef91d6224f6655ee586a65d263ad34c cbc07f26687521cecfc9a141bf5ecfc0fd2b8531 0 {'date': '* *', 'user': 'test'} (glob) + 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 {'date': '* *', 'user': 'test'} (glob) $ hg log -G - @ 11:cbc07f266875 D + @ 11:4596109a6a43 D | | o 10:5ae4c968c6ac C | | @@ -203,17 +203,17 @@ 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {'date': '* *', 'user': 'test'} (glob) 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 {'date': '* *', 'user': 'test'} (glob) 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {'date': '* *', 'user': 'test'} (glob) - 08483444fef91d6224f6655ee586a65d263ad34c cbc07f26687521cecfc9a141bf5ecfc0fd2b8531 0 {'date': '* *', 'user': 'test'} (glob) - 8877864f1edb05d0e07dc4ba77b67a80a7b86672 b1861c79d66ec3aa1b607ac3c9fb819e38b12238 0 {'date': '* *', 'user': 'test'} (glob) + 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 {'date': '* *', 'user': 'test'} (glob) + 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 {'date': '* *', 'user': 'test'} (glob) 08483444fef91d6224f6655ee586a65d263ad34c 0 {'date': '* *', 'user': 'test'} (glob) - 5ae4c968c6aca831df823664e706c9d4aa34473d dd4be135457a404ce5541de427ae1d98a28f4acd 0 {'date': '* *', 'user': 'test'} (glob) + 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 {'date': '* *', 'user': 'test'} (glob) $ hg log --rev 'divergent()' $ hg log -G - @ 13:dd4be135457a C + @ 13:98f6af4ee953 C | - o 12:b1861c79d66e B + o 12:462a34d07e59 B | - o 11:cbc07f266875 D + o 11:4596109a6a43 D | o 7:02de42196ebe H | @@ -225,7 +225,22 @@ |/ o 0:cd010b8cd998 A - + $ hg log --style default --debug -r 4596109a6a4328c398bde3a4a3b6737cfade3003 + changeset: 11:4596109a6a4328c398bde3a4a3b6737cfade3003 + phase: draft + parent: 7:02de42196ebee42ef284b6780a87cdc96e8eaab6 + parent: -1:0000000000000000000000000000000000000000 + manifest: 11:a91006e3a02f1edf631f7018e6e5684cf27dd905 + user: Nicolas Dumazet <nicdumz.commits@gmail.com> + date: Sat Apr 30 15:24:48 2011 +0200 + files+: D + extra: branch=default + extra: rebase_source=08483444fef91d6224f6655ee586a65d263ad34c + extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a + description: + D + + $ cd .. collapse rebase
--- a/tests/test-requires.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-requires.t Sat Oct 19 14:21:05 2013 -0700 @@ -15,5 +15,55 @@ $ hg tip abort: unknown repository format: requires features 'indoor-pool', 'outdoor-pool' (upgrade Mercurial)! [255] + $ cd .. + +Test checking between features supported locally and ones required in +another repository of push/pull/clone on localhost: + + $ mkdir supported-locally + $ cd supported-locally + + $ hg init supported + $ echo a > supported/a + $ hg -R supported commit -Am '#0 at supported' + adding a + + $ echo 'featuresetup-test' >> supported/.hg/requires + $ cat > $TESTTMP/supported-locally/supportlocally.py <<EOF + > from mercurial import localrepo, extensions + > def featuresetup(ui, supported): + > for name, module in extensions.extensions(ui): + > if __name__ == module.__name__: + > # support specific feature locally + > supported |= set(['featuresetup-test']) + > return + > def uisetup(ui): + > localrepo.localrepository.featuresetupfuncs.add(featuresetup) + > EOF + $ cat > supported/.hg/hgrc <<EOF + > [extensions] + > # enable extension locally + > supportlocally = $TESTTMP/supported-locally/supportlocally.py + > EOF + $ hg -R supported status + + $ hg init push-dst + $ hg -R supported push push-dst + pushing to push-dst + abort: required features are not supported in the destination: featuresetup-test + [255] + + $ hg init pull-src + $ hg -R pull-src pull supported + pulling from supported + abort: required features are not supported in the destination: featuresetup-test + [255] + + $ hg clone supported clone-dst + abort: unknown repository format: requires features 'featuresetup-test' (upgrade Mercurial)! + [255] + $ hg clone --pull supported clone-dst + abort: required features are not supported in the destination: featuresetup-test + [255] $ cd ..
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-shelve.t Sat Oct 19 14:21:05 2013 -0700 @@ -0,0 +1,484 @@ + $ echo "[extensions]" >> $HGRCPATH + $ echo "mq=" >> $HGRCPATH + $ echo "shelve=" >> $HGRCPATH + $ echo "[defaults]" >> $HGRCPATH + $ echo "diff = --nodates --git" >> $HGRCPATH + $ echo "qnew = --date '0 0'" >> $HGRCPATH + + $ hg init repo + $ cd repo + $ mkdir a b + $ echo a > a/a + $ echo b > b/b + $ echo c > c + $ echo d > d + $ echo x > x + $ hg addremove -q + +shelving in an empty repo should be possible + + $ hg shelve + shelved as default + 0 files updated, 0 files merged, 5 files removed, 0 files unresolved + + $ hg unshelve + unshelving change 'default' + adding changesets + adding manifests + adding file changes + added 1 changesets with 5 changes to 5 files + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ hg commit -q -m 'initial commit' + + $ hg shelve + nothing changed + [1] + +create an mq patch - shelving should work fine with a patch applied + + $ echo n > n + $ hg add n + $ hg commit n -m second + $ hg qnew second.patch + +shelve a change that we will delete later + + $ echo a >> a/a + $ hg shelve + shelved as default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + +set up some more complex changes to shelve + + $ echo a >> a/a + $ hg mv b b.rename + moving b/b to b.rename/b (glob) + $ hg cp c c.copy + $ hg status -C + M a/a + A b.rename/b + b/b + A c.copy + c + R b/b + +prevent some foot-shooting + + $ hg shelve -n foo/bar + abort: shelved change names may not contain slashes + [255] + $ hg shelve -n .baz + abort: shelved change names may not start with '.' + [255] + +the common case - no options or filenames + + $ hg shelve + shelved as default-01 + 2 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ hg status -C + +ensure that our shelved changes exist + + $ hg shelve -l + default-01 (*) [mq]: second.patch (glob) + default (*) [mq]: second.patch (glob) + + $ hg shelve -l -p default + default (*) [mq]: second.patch (glob) + + diff --git a/a/a b/a/a + --- a/a/a + +++ b/a/a + @@ -1,1 +1,2 @@ + a + +a + +delete our older shelved change + + $ hg shelve -d default + $ hg qfinish -a -q + +local edits should prevent a shelved change from applying + + $ echo e>>a/a + $ hg unshelve + unshelving change 'default-01' + the following shelved files have been modified: + a/a + you must commit, revert, or shelve your changes before you can proceed + abort: cannot unshelve due to local changes + + [255] + + $ hg revert -C a/a + +apply it and make sure our state is as expected + + $ hg unshelve + unshelving change 'default-01' + adding changesets + adding manifests + adding file changes + added 1 changesets with 3 changes to 8 files + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg status -C + M a/a + A b.rename/b + b/b + A c.copy + c + R b/b + $ hg shelve -l + + $ hg unshelve + abort: no shelved changes to apply! + [255] + $ hg unshelve foo + abort: shelved change 'foo' not found + [255] + +named shelves, specific filenames, and "commit messages" should all work + + $ hg status -C + M a/a + A b.rename/b + b/b + A c.copy + c + R b/b + $ hg shelve -q -n wibble -m wat a + +expect "a" to no longer be present, but status otherwise unchanged + + $ hg status -C + A b.rename/b + b/b + A c.copy + c + R b/b + $ hg shelve -l --stat + wibble (*) wat (glob) + a/a | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +and now "a/a" should reappear + + $ hg unshelve -q wibble + $ hg status -C + M a/a + A b.rename/b + b/b + A c.copy + c + R b/b + +cause unshelving to result in a merge with 'a' conflicting + + $ hg shelve -q + $ echo c>>a/a + $ hg commit -m second + $ hg tip --template '{files}\n' + a/a + +add an unrelated change that should be preserved + + $ mkdir foo + $ echo foo > foo/foo + $ hg add foo/foo + +force a conflicted merge to occur + + $ hg unshelve + unshelving change 'default' + adding changesets + adding manifests + adding file changes + added 1 changesets with 3 changes to 8 files (+1 heads) + merging a/a + warning: conflicts during merge. + merging a/a incomplete! (edit conflicts, then use 'hg resolve --mark') + 2 files updated, 0 files merged, 1 files removed, 1 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue') + [1] + +ensure that we have a merge with unresolved conflicts + + $ hg heads -q + 4:cebf2b8de087 + 3:2e69b451d1ea + $ hg parents -q + 3:2e69b451d1ea + 4:cebf2b8de087 + $ hg status + M a/a + M b.rename/b + M c.copy + A foo/foo + R b/b + ? a/a.orig + $ hg diff + diff --git a/a/a b/a/a + --- a/a/a + +++ b/a/a + @@ -1,2 +1,6 @@ + a + +<<<<<<< local + c + +======= + +a + +>>>>>>> other + diff --git a/b.rename/b b/b.rename/b + --- /dev/null + +++ b/b.rename/b + @@ -0,0 +1,1 @@ + +b + diff --git a/b/b b/b/b + deleted file mode 100644 + --- a/b/b + +++ /dev/null + @@ -1,1 +0,0 @@ + -b + diff --git a/c.copy b/c.copy + --- /dev/null + +++ b/c.copy + @@ -0,0 +1,1 @@ + +c + diff --git a/foo/foo b/foo/foo + new file mode 100644 + --- /dev/null + +++ b/foo/foo + @@ -0,0 +1,1 @@ + +foo + $ hg resolve -l + U a/a + + $ hg shelve + abort: unshelve already in progress + (use 'hg unshelve --continue' or 'hg unshelve --abort') + [255] + +abort the unshelve and be happy + + $ hg status + M a/a + M b.rename/b + M c.copy + A foo/foo + R b/b + ? a/a.orig + $ hg unshelve -a + unshelve of 'default' aborted + $ hg heads -q + 3:2e69b451d1ea + $ hg parents + changeset: 3:2e69b451d1ea + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: second + + $ hg resolve -l + $ hg status + A foo/foo + ? a/a.orig + +try to continue with no unshelve underway + + $ hg unshelve -c + abort: no unshelve operation underway + [255] + $ hg status + A foo/foo + ? a/a.orig + +redo the unshelve to get a conflict + + $ hg unshelve -q + warning: conflicts during merge. + merging a/a incomplete! (edit conflicts, then use 'hg resolve --mark') + unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue') + [1] + +attempt to continue + + $ hg unshelve -c + abort: unresolved conflicts, can't continue + (see 'hg resolve', then 'hg unshelve --continue') + [255] + + $ hg revert -r . a/a + $ hg resolve -m a/a + + $ hg unshelve -c + unshelve of 'default' complete + +ensure the repo is as we hope + + $ hg parents + changeset: 3:2e69b451d1ea + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: second + + $ hg heads -q + 3:2e69b451d1ea + + $ hg status -C + M b.rename/b + b/b + M c.copy + c + A foo/foo + R b/b + ? a/a.orig + +there should be no shelves left + + $ hg shelve -l + +#if execbit + +ensure that metadata-only changes are shelved + + $ chmod +x a/a + $ hg shelve -q -n execbit a/a + $ hg status a/a + $ hg unshelve -q execbit + $ hg status a/a + M a/a + $ hg revert a/a + +#endif + +#if symlink + + $ rm a/a + $ ln -s foo a/a + $ hg shelve -q -n symlink a/a + $ hg status a/a + $ hg unshelve -q symlink + $ hg status a/a + M a/a + $ hg revert a/a + +#endif + +set up another conflict between a commit and a shelved change + + $ hg revert -q -C -a + $ echo a >> a/a + $ hg shelve -q + $ echo x >> a/a + $ hg ci -m 'create conflict' + $ hg add foo/foo + +if we resolve a conflict while unshelving, the unshelve should succeed + + $ HGMERGE=true hg unshelve + unshelving change 'default' + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 6 files (+1 heads) + merging a/a + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + $ hg parents -q + 4:33f7f61e6c5e + $ hg shelve -l + $ hg status + A foo/foo + $ cat a/a + a + c + x + +test keep and cleanup + + $ hg shelve + shelved as default + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg shelve --list + default (*) create conflict (glob) + $ hg unshelve --keep + unshelving change 'default' + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 7 files + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg shelve --list + default (*) create conflict (glob) + $ hg shelve --cleanup + $ hg shelve --list + +test bookmarks + + $ hg bookmark test + $ hg bookmark + * test 4:33f7f61e6c5e + $ hg shelve + shelved as test + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg bookmark + * test 4:33f7f61e6c5e + $ hg unshelve + unshelving change 'test' + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 7 files + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg bookmark + * test 4:33f7f61e6c5e + +shelve should still work even if mq is disabled + + $ hg --config extensions.mq=! shelve + shelved as test + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg --config extensions.mq=! shelve --list + test (1s ago) create conflict + $ hg --config extensions.mq=! unshelve + unshelving change 'test' + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 7 files + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + +shelve should leave dirstate clean (issue 4055) + + $ cd .. + $ hg init shelverebase + $ cd shelverebase + $ printf 'x\ny\n' > x + $ echo z > z + $ hg commit -Aqm xy + $ echo z >> x + $ hg commit -Aqm z + $ hg up 0 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ printf 'a\nx\ny\nz\n' > x + $ hg commit -Aqm xyz + $ echo c >> z + $ hg shelve + shelved as default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg rebase -d 1 --config extensions.rebase= + merging x + saved backup bundle to $TESTTMP/shelverebase/.hg/strip-backup/323bfa07f744-backup.hg (glob) + $ hg unshelve + unshelving change 'default' + adding changesets + adding manifests + adding file changes + added 2 changesets with 2 changes to 2 files (+1 heads) + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg status + M z + + $ cd ..
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-strip.t Sat Oct 19 14:21:05 2013 -0700 @@ -0,0 +1,504 @@ + $ echo "[extensions]" >> $HGRCPATH + $ echo "strip=" >> $HGRCPATH + $ echo "graphlog=" >> $HGRCPATH + + $ restore() { + > hg unbundle -q .hg/strip-backup/* + > rm .hg/strip-backup/* + > } + $ teststrip() { + > hg up -C $1 + > echo % before update $1, strip $2 + > hg parents + > hg --traceback strip $2 + > echo % after update $1, strip $2 + > hg parents + > restore + > } + + $ hg init test + $ cd test + + $ echo foo > bar + $ hg ci -Ama + adding bar + + $ echo more >> bar + $ hg ci -Amb + + $ echo blah >> bar + $ hg ci -Amc + + $ hg up 1 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo blah >> bar + $ hg ci -Amd + created new head + + $ echo final >> bar + $ hg ci -Ame + + $ hg log + changeset: 4:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + changeset: 3:65bd5f99a4a3 + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: d + + changeset: 2:264128213d29 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: c + + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + + $ teststrip 4 4 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 4, strip 4 + changeset: 4:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 4, strip 4 + changeset: 3:65bd5f99a4a3 + tag: tip + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: d + + $ teststrip 4 3 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 4, strip 3 + changeset: 4:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 4, strip 3 + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + $ teststrip 1 4 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 1, strip 4 + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 1, strip 4 + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + $ teststrip 4 2 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 4, strip 2 + changeset: 4:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 4, strip 2 + changeset: 3:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + $ teststrip 4 1 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 4, strip 1 + changeset: 4:264128213d29 + tag: tip + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: c + + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 4, strip 1 + changeset: 0:9ab35a2d17cb + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + $ teststrip null 4 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + % before update null, strip 4 + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update null, strip 4 + + $ hg log + changeset: 4:264128213d29 + tag: tip + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: c + + changeset: 3:443431ffac4f + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + changeset: 2:65bd5f99a4a3 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: d + + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + + $ hg up -C 2 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg merge 4 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + +before strip of merge parent + + $ hg parents + changeset: 2:65bd5f99a4a3 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: d + + changeset: 4:264128213d29 + tag: tip + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: c + + $ hg strip 4 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + +after strip of merge parent + + $ hg parents + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + $ restore + + $ hg up + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg glog + @ changeset: 4:264128213d29 + | tag: tip + | parent: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: c + | + | o changeset: 3:443431ffac4f + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: e + | | + | o changeset: 2:65bd5f99a4a3 + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: d + | + o changeset: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + +2 is parent of 3, only one strip should happen + + $ hg strip "roots(2)" 3 + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg glog + @ changeset: 2:264128213d29 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: c + | + o changeset: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + $ restore + $ hg glog + o changeset: 4:443431ffac4f + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: e + | + o changeset: 3:65bd5f99a4a3 + | parent: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: d + | + | @ changeset: 2:264128213d29 + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: c + | + o changeset: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + +2 different branches: 2 strips + + $ hg strip 2 4 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg glog + o changeset: 2:65bd5f99a4a3 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: d + | + @ changeset: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + $ restore + +2 different branches and a common ancestor: 1 strip + + $ hg strip 1 "2|4" + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ restore + +stripping an empty revset + + $ hg strip "1 and not 1" + abort: empty revision set + [255] + +remove branchy history for qimport tests + + $ hg strip 3 + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + + +strip of applied mq should cleanup status file + + $ echo "mq=" >> $HGRCPATH + $ hg up -C 3 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo fooagain >> bar + $ hg ci -mf + $ hg qimport -r tip:2 + +applied patches before strip + + $ hg qapplied + 2.diff + 3.diff + 4.diff + +stripping revision in queue + + $ hg strip 3 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + +applied patches after stripping rev in queue + + $ hg qapplied + 2.diff + +stripping ancestor of queue + + $ hg strip 1 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + +applied patches after stripping ancestor of queue + + $ hg qapplied + +Verify strip protects against stripping wc parent when there are uncommited mods + + $ echo b > b + $ hg add b + $ hg ci -m 'b' + $ hg log --graph + @ changeset: 1:7519abd79d14 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + + $ echo c > b + $ echo c > bar + $ hg strip tip + abort: local changes found + [255] + $ hg strip tip --keep + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg log --graph + @ changeset: 0:9ab35a2d17cb + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + $ hg status + M bar + ? b + +Strip adds, removes, modifies with --keep + + $ touch b + $ hg add b + $ hg commit -mb + $ touch c + +... with a clean working dir + + $ hg add c + $ hg rm bar + $ hg commit -mc + $ hg status + $ hg strip --keep tip + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg status + ! bar + ? c + +... with a dirty working dir + + $ hg add c + $ hg rm bar + $ hg commit -mc + $ hg status + $ echo b > b + $ echo d > d + $ hg strip --keep tip + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg status + M b + ! bar + ? c + ? d + $ cd .. + +stripping many nodes on a complex graph (issue3299) + + $ hg init issue3299 + $ cd issue3299 + $ hg debugbuilddag '@a.:a@b.:b.:x<a@a.:a<b@b.:b<a@a.:a' + $ hg strip 'not ancestors(x)' + saved backup bundle to $TESTTMP/issue3299/.hg/strip-backup/*-backup.hg (glob) + +test hg strip -B bookmark + + $ cd .. + $ hg init bookmarks + $ cd bookmarks + $ hg debugbuilddag '..<2.*1/2:m<2+3:c<m+3:a<2.:b' + $ hg bookmark -r 'a' 'todelete' + $ hg bookmark -r 'b' 'B' + $ hg bookmark -r 'b' 'nostrip' + $ hg bookmark -r 'c' 'delete' + $ hg up -C todelete + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg strip -B nostrip + bookmark 'nostrip' deleted + abort: empty revision set + [255] + $ hg strip -B todelete + bookmark 'todelete' deleted + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob) + $ hg id -ir dcbb326fdec2 + abort: unknown revision 'dcbb326fdec2'! + [255] + $ hg id -ir d62d843c9a01 + d62d843c9a01 + $ hg bookmarks + B 9:ff43616e5d0f + delete 6:2702dd0c91e7 + $ hg strip -B delete + bookmark 'delete' deleted + saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob) + $ hg id -ir 6:2702dd0c91e7 + abort: unknown revision '2702dd0c91e7'! + [255] + + $ cd ..
--- a/tests/test-subrepo-git.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-subrepo-git.t Sat Oct 19 14:21:05 2013 -0700 @@ -155,6 +155,8 @@ added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg merge 2>/dev/null + subrepository s diverged (local revision: 796959400868, remote revision: aa84837ccfbd) + (M)erge, keep (l)ocal or keep (r)emote? m pulling subrepo s from $TESTTMP/gitroot 0 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) @@ -462,6 +464,8 @@ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7 $ cd .. $ hg update 4 + subrepository s diverged (local revision: da5f5b1d8ffc, remote revision: aa84837ccfbd) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (da5f5b1) or (r)emote source (aa84837)? l @@ -487,6 +491,8 @@ HEAD is now at aa84837... f $ cd .. $ hg update 1 + subrepository s diverged (local revision: 32a343883b74, remote revision: da5f5b1d8ffc) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ (in checked out version) use (l)ocal source (32a3438) or (r)emote source (da5f5b1)? l @@ -508,6 +514,8 @@ $ hg id -n 1+ $ hg update 7 + subrepository s diverged (local revision: 32a343883b74, remote revision: 32a343883b74) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (32a3438) or (r)emote source (32a3438)? l
--- a/tests/test-subrepo-svn.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-subrepo-svn.t Sat Oct 19 14:21:05 2013 -0700 @@ -319,6 +319,8 @@ 2M $ cd .. $ hg update tip + subrepository s diverged (local revision: 2, remote revision: 3) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (2) or (r)emote source (3)? l @@ -349,6 +351,8 @@ $ svn update -qr 1 $ cd .. $ hg update 1 + subrepository s diverged (local revision: 3, remote revision: 2) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ (in checked out version) use (l)ocal source (1) or (r)emote source (2)? l @@ -371,6 +375,8 @@ $ hg id -n 1+ $ hg update tip + subrepository s diverged (local revision: 3, remote revision: 3) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (1) or (r)emote source (3)? l @@ -404,6 +410,8 @@ $ svn update -qr 2 $ cd .. $ hg update 1 + subrepository s diverged (local revision: 3, remote revision: 2) + (M)erge, keep (l)ocal or keep (r)emote? m 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg id -n 1+ @@ -477,7 +485,8 @@ This is surprising, but is also correct based on the current code: $ echo "updating should (maybe) fail" > obstruct/other $ hg co tip - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) [255] Point to a Subversion branch which has since been deleted and recreated
--- a/tests/test-subrepo.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-subrepo.t Sat Oct 19 14:21:05 2013 -0700 @@ -236,7 +236,9 @@ .hgsubstate: versions differ -> m updating: .hgsubstate 1/1 files (100.00%) subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4 - subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg + subrepo t: both sides changed + subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198) + (M)erge, keep (l)ocal or keep (r)emote? m merging subrepo t searching for copies back to rev 2 resolving manifests @@ -252,6 +254,7 @@ merging t incomplete! (edit conflicts, then use 'hg resolve --mark') 0 files updated, 0 files merged, 0 files removed, 1 files unresolved use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg 0 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) @@ -620,6 +623,8 @@ $ hg up 5 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg merge 4 # try to merge default into br again + subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88) + (M)erge, keep (l)ocal or keep (r)emote? m 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) $ cd .. @@ -922,9 +927,13 @@ $ hg -R t id e95bcfa18a35+ $ hg update tip + subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)? l + subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for t differ use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)? l @@ -953,6 +962,10 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd .. $ hg update 10 + subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f) + (M)erge, keep (l)ocal or keep (r)emote? m + subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for t differ (in checked out version) use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)? l @@ -976,9 +989,13 @@ $ hg -R t id 7af322bc1198+ $ hg update tip + subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)? l + subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for t differ use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)? l @@ -1006,6 +1023,8 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd .. $ hg update 11 + subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f) + (M)erge, keep (l)ocal or keep (r)emote? m 0 files updated, 0 files merged, 0 files removed, 0 files unresolved 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg id -n
--- a/tests/test-symlink-placeholder.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-symlink-placeholder.t Sat Oct 19 14:21:05 2013 -0700 @@ -41,6 +41,13 @@ a (no-eol) $ hg --config extensions.n=$TESTTMP/nolink.py st --debug +Empty placeholder: + + $ rm b + $ touch b + $ hg --config extensions.n=$TESTTMP/nolink.py st --debug + ignoring suspect symlink placeholder "b" + Write binary data to the placeholder: >>> open('b', 'w').write('this is a binary\0')
--- a/tests/test-trusted.py Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-trusted.py Sat Oct 19 14:21:05 2013 -0700 @@ -145,7 +145,7 @@ f.write('[foobar]\n') f.write('baz = quux\n') f.close() -u.readconfig(filename, sections = ['foobar']) +u.readconfig(filename, sections=['foobar']) print u.config('foobar', 'baz') print
--- a/tests/test-up-local-change.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-up-local-change.t Sat Oct 19 14:21:05 2013 -0700 @@ -167,10 +167,11 @@ summary: 2 $ hg --debug up - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit and merge, or update --clean to discard changes) [255] $ hg --debug merge - abort: outstanding uncommitted changes + abort: uncommitted changes (use 'hg status' to list changes) [255] $ hg --debug merge -f
--- a/tests/test-update-branches.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-update-branches.t Sat Oct 19 14:21:05 2013 -0700 @@ -94,7 +94,8 @@ parent=5 $ norevtest 'none clean same' clean 2 - abort: crosses branches (merge branches or update --check to force update) + abort: not a linear update + (merge or update --check to force update) parent=2 @@ -122,22 +123,32 @@ M sub/suba $ revtest 'none dirty same' dirty 2 3 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) parent=2 M foo $ revtest 'none dirtysub same' dirtysub 2 3 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) parent=2 M sub/suba $ revtest 'none dirty cross' dirty 3 4 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) parent=3 M foo + $ norevtest 'none dirty cross' dirty 2 + abort: uncommitted changes + (commit and merge, or update --clean to discard changes) + parent=2 + M foo + $ revtest 'none dirtysub cross' dirtysub 3 4 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) parent=3 M sub/suba @@ -146,12 +157,12 @@ parent=2 $ revtest '-c dirty linear' dirty 1 2 -c - abort: uncommitted local changes + abort: uncommitted changes parent=1 M foo $ revtest '-c dirtysub linear' dirtysub 1 2 -c - abort: uncommitted local changes + abort: uncommitted changes parent=1 M sub/suba @@ -222,5 +233,6 @@ $ hg up --quiet 0 $ hg up --quiet 2 $ hg up 5 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) [255]
--- a/tests/test-update-issue1456.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-update-issue1456.t Sat Oct 19 14:21:05 2013 -0700 @@ -18,7 +18,7 @@ $ echo dirty > foo $ hg up -c - abort: uncommitted local changes + abort: uncommitted changes [255] $ hg up -q $ cat foo
--- a/tests/test-walk.t Sat Oct 19 14:20:31 2013 -0700 +++ b/tests/test-walk.t Sat Oct 19 14:21:05 2013 -0700 @@ -3,11 +3,11 @@ $ mkdir -p beans $ for b in kidney navy turtle borlotti black pinto; do > echo $b > beans/$b - $ done + > done $ mkdir -p mammals/Procyonidae $ for m in cacomistle coatimundi raccoon; do > echo $m > mammals/Procyonidae/$m - $ done + > done $ echo skunk > mammals/skunk $ echo fennel > fennel $ echo fenugreek > fenugreek