--- a/contrib/revsetbenchmarks.py Tue Aug 18 18:37:50 2015 -0500
+++ b/contrib/revsetbenchmarks.py Tue Aug 18 18:38:56 2015 -0500
@@ -33,6 +33,8 @@
"""update the repo to a revision"""
try:
check_call(['hg', 'update', '--quiet', '--check', str(rev)])
+ check_output(['make', 'local'],
+ stderr=None) # suppress output except for error/warning
except CalledProcessError as exc:
print >> sys.stderr, 'update to revision %s failed, aborting' % rev
sys.exit(exc.returncode)
--- a/hgext/convert/common.py Tue Aug 18 18:37:50 2015 -0500
+++ b/hgext/convert/common.py Tue Aug 18 18:38:56 2015 -0500
@@ -82,6 +82,13 @@
def after(self):
pass
+ def targetfilebelongstosource(self, targetfilename):
+ """Returns true if the given targetfile belongs to the source repo. This
+ is useful when only a subdirectory of the target belongs to the source
+ repo."""
+ # For normal full repo converts, this is always True.
+ return True
+
def setrevmap(self, revmap):
"""set the map of already-converted revisions"""
pass
--- a/hgext/convert/convcmd.py Tue Aug 18 18:37:50 2015 -0500
+++ b/hgext/convert/convcmd.py Tue Aug 18 18:38:56 2015 -0500
@@ -120,6 +120,9 @@
item=file, total=self.filecount)
return self.source.getfile(file, rev)
+ def targetfilebelongstosource(self, targetfilename):
+ return self.source.targetfilebelongstosource(targetfilename)
+
def lookuprev(self, rev):
return self.source.lookuprev(rev)
--- a/hgext/convert/filemap.py Tue Aug 18 18:37:50 2015 -0500
+++ b/hgext/convert/filemap.py Tue Aug 18 18:38:56 2015 -0500
@@ -42,6 +42,7 @@
self.include = {}
self.exclude = {}
self.rename = {}
+ self.targetprefixes = None
if path:
if self.parse(path):
raise util.Abort(_('errors in filemap'))
@@ -100,6 +101,30 @@
pass
return '', name, ''
+ def istargetfile(self, filename):
+ """Return true if the given target filename is covered as a destination
+ of the filemap. This is useful for identifying what parts of the target
+ repo belong to the source repo and what parts don't."""
+ if self.targetprefixes is None:
+ self.targetprefixes = set()
+ for before, after in self.rename.iteritems():
+ self.targetprefixes.add(after)
+
+ # If "." is a target, then all target files are considered from the
+ # source.
+ if not self.targetprefixes or '.' in self.targetprefixes:
+ return True
+
+ filename = normalize(filename)
+ for pre, suf in rpairs(filename):
+ # This check is imperfect since it doesn't account for the
+ # include/exclude list, but it should work in filemaps that don't
+ # apply include/exclude to the same source directories they are
+ # renaming.
+ if pre in self.targetprefixes:
+ return True
+ return False
+
def __call__(self, name):
if self.include:
inc = self.lookup(name, self.include)[0]
@@ -410,6 +435,9 @@
return files, ncopies, ncleanp2
+ def targetfilebelongstosource(self, targetfilename):
+ return self.filemapper.istargetfile(targetfilename)
+
def getfile(self, name, rev):
realname, realrev = rev
return self.base.getfile(realname, realrev)
--- a/hgext/convert/git.py Tue Aug 18 18:37:50 2015 -0500
+++ b/hgext/convert/git.py Tue Aug 18 18:38:56 2015 -0500
@@ -377,28 +377,31 @@
def getbookmarks(self):
bookmarks = {}
- # Interesting references in git are prefixed
- prefix = 'refs/heads/'
- prefixlen = len(prefix)
+ # Handle local and remote branches
+ remoteprefix = self.ui.config('convert', 'git.remoteprefix', 'remote')
+ reftypes = [
+ # (git prefix, hg prefix)
+ ('refs/remotes/origin/', remoteprefix + '/'),
+ ('refs/heads/', '')
+ ]
- # factor two commands
- remoteprefix = self.ui.config('convert', 'git.remoteprefix', 'remote')
- gitcmd = { remoteprefix + '/': 'git ls-remote --heads origin',
- '': 'git show-ref'}
+ exclude = set([
+ 'refs/remotes/origin/HEAD',
+ ])
- # Origin heads
- for reftype in gitcmd:
- try:
- fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
- for line in fh:
- line = line.strip()
- rev, name = line.split(None, 1)
- if not name.startswith(prefix):
+ try:
+ fh = self.gitopen('git show-ref', err=subprocess.PIPE)
+ for line in fh:
+ line = line.strip()
+ rev, name = line.split(None, 1)
+ # Process each type of branch
+ for gitprefix, hgprefix in reftypes:
+ if not name.startswith(gitprefix) or name in exclude:
continue
- name = '%s%s' % (reftype, name[prefixlen:])
+ name = '%s%s' % (hgprefix, name[len(gitprefix):])
bookmarks[name] = rev
- except Exception:
- pass
+ except Exception:
+ pass
return bookmarks
--- a/hgext/convert/hg.py Tue Aug 18 18:37:50 2015 -0500
+++ b/hgext/convert/hg.py Tue Aug 18 18:38:56 2015 -0500
@@ -23,6 +23,7 @@
from mercurial.node import bin, hex, nullid
from mercurial import hg, util, context, bookmarks, error, scmutil, exchange
from mercurial import phases
+from mercurial import merge as mergemod
from common import NoRepo, commit, converter_source, converter_sink, mapfile
@@ -176,12 +177,51 @@
return fp.getvalue()
+ def _calculatemergedfiles(self, source, p1ctx, p2ctx):
+ """Calculates the files from p2 that we need to pull in when merging p1
+ and p2, given that the merge is coming from the given source.
+
+ This prevents us from losing files that only exist in the target p2 and
+ that don't come from the source repo (like if you're merging multiple
+ repositories together).
+ """
+ anc = [p1ctx.ancestor(p2ctx)]
+ # Calculate what files are coming from p2
+ actions, diverge, rename = mergemod.calculateupdates(
+ self.repo, p1ctx, p2ctx, anc,
+ True, # branchmerge
+ True, # force
+ False, # partial
+ False, # acceptremote
+ False, # followcopies
+ )
+
+ for file, (action, info, msg) in actions.iteritems():
+ if source.targetfilebelongstosource(file):
+ # If the file belongs to the source repo, ignore the p2
+ # since it will be covered by the existing fileset.
+ continue
+
+ # If the file requires actual merging, abort. We don't have enough
+ # context to resolve merges correctly.
+ if action in ['m', 'dm', 'cd', 'dc']:
+ raise util.Abort(_("unable to convert merge commit "
+ "since target parents do not merge cleanly (file "
+ "%s, parents %s and %s)") % (file, p1ctx,
+ p2ctx))
+ elif action == 'k':
+ # 'keep' means nothing changed from p1
+ continue
+ else:
+ # Any other change means we want to take the p2 version
+ yield file
+
def putcommit(self, files, copies, parents, commit, source, revmap, full,
cleanp2):
files = dict(files)
def getfilectx(repo, memctx, f):
- if p2ctx and f in cleanp2 and f not in copies:
+ if p2ctx and f in p2files and f not in copies:
self.ui.debug('reusing %s from p2\n' % f)
return p2ctx[f]
try:
@@ -255,6 +295,7 @@
while parents:
p1 = p2
p2 = parents.pop(0)
+ p1ctx = self.repo[p1]
p2ctx = None
if p2 != nullid:
p2ctx = self.repo[p2]
@@ -262,6 +303,13 @@
if full:
fileset.update(self.repo[p1])
fileset.update(self.repo[p2])
+
+ if p2ctx:
+ p2files = set(cleanp2)
+ for file in self._calculatemergedfiles(source, p1ctx, p2ctx):
+ p2files.add(file)
+ fileset.add(file)
+
ctx = context.memctx(self.repo, (p1, p2), text, fileset,
getfilectx, commit.author, commit.date, extra)
--- a/hgext/highlight/highlight.py Tue Aug 18 18:37:50 2015 -0500
+++ b/hgext/highlight/highlight.py Tue Aug 18 18:38:56 2015 -0500
@@ -49,7 +49,12 @@
try:
lexer = guess_lexer(text[:1024], stripnl=False)
except (ClassNotFound, ValueError):
- lexer = TextLexer(stripnl=False)
+ # Don't highlight unknown files
+ return
+
+ # Don't highlight text files
+ if isinstance(lexer, TextLexer):
+ return
formatter = HtmlFormatter(nowrap=True, style=style)
--- a/hgext/histedit.py Tue Aug 18 18:37:50 2015 -0500
+++ b/hgext/histedit.py Tue Aug 18 18:38:56 2015 -0500
@@ -778,7 +778,7 @@
return
elif goal == 'abort':
state.read()
- mapping, tmpnodes, leafs, _ntm = processreplacement(state)
+ tmpnodes, leafs = newnodestoabort(state)
ui.debug('restore wc to old parent %s\n' % node.short(state.topmost))
# Recover our old commits if necessary
@@ -791,13 +791,9 @@
os.remove(backupfile)
# check whether we should update away
- parentnodes = [c.node() for c in repo[None].parents()]
- for n in leafs | set([state.parentctxnode]):
- if n in parentnodes:
- hg.clean(repo, state.topmost)
- break
- else:
- pass
+ if repo.unfiltered().revs('parents() and (%n or %ln::)',
+ state.parentctxnode, leafs | tmpnodes):
+ hg.clean(repo, state.topmost)
cleanupnode(ui, repo, 'created', tmpnodes)
cleanupnode(ui, repo, 'temp', leafs)
state.clear()
@@ -1009,6 +1005,25 @@
hint=_('do you want to use the drop action?'))
return parsed
+def newnodestoabort(state):
+ """process the list of replacements to return
+
+ 1) the list of final node
+ 2) the list of temporary node
+
+ This meant to be used on abort as less data are required in this case.
+ """
+ replacements = state.replacements
+ allsuccs = set()
+ replaced = set()
+ for rep in replacements:
+ allsuccs.update(rep[1])
+ replaced.add(rep[0])
+ newnodes = allsuccs - replaced
+ tmpnodes = allsuccs & replaced
+ return newnodes, tmpnodes
+
+
def processreplacement(state):
"""process the list of replacements to return
@@ -1019,15 +1034,15 @@
allsuccs = set()
replaced = set()
fullmapping = {}
- # initialise basic set
- # fullmapping record all operation recorded in replacement
+ # initialize basic set
+ # fullmapping records all operations recorded in replacement
for rep in replacements:
allsuccs.update(rep[1])
replaced.add(rep[0])
fullmapping.setdefault(rep[0], set()).update(rep[1])
new = allsuccs - replaced
tmpnodes = allsuccs & replaced
- # Reduce content fullmapping into direct relation between original nodes
+ # Reduce content fullmapping into direct relation between original nodes
# and final node created during history edition
# Dropped changeset are replaced by an empty list
toproceed = set(fullmapping)
@@ -1113,6 +1128,10 @@
lock = None
try:
lock = repo.lock()
+ # do not let filtering get in the way of the cleanse
+ # we should probably get ride of obsolescence marker created during the
+ # histedit, but we currently do not have such information.
+ repo = repo.unfiltered()
# Find all node that need to be stripped
# (we hg %lr instead of %ln to silently ignore unknown item
nm = repo.changelog.nodemap
--- a/mercurial/ancestor.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/ancestor.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,12 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import collections
import heapq
-from node import nullrev
+
+from .node import nullrev
def commonancestorsheads(pfunc, *nodes):
"""Returns a set with the heads of all common ancestors of all nodes,
--- a/mercurial/archival.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/archival.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,14 +5,27 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import match as matchmod
-import cmdutil
-import scmutil, util, encoding
-import cStringIO, os, tarfile, time, zipfile
-import zlib, gzip
+from __future__ import absolute_import
+
+import cStringIO
+import gzip
+import os
import struct
-import error
+import tarfile
+import time
+import zipfile
+import zlib
+
+from .i18n import _
+
+from . import (
+ cmdutil,
+ encoding,
+ error,
+ match as matchmod,
+ scmutil,
+ util,
+)
# from unzip source code:
_UNX_IFREG = 0x8000
--- a/mercurial/bookmarks.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/bookmarks.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,11 +5,22 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
+import errno
import os
-from mercurial.i18n import _
-from mercurial.node import hex, bin
-from mercurial import encoding, util, obsolete, lock as lockmod
-import errno
+
+from .i18n import _
+from .node import (
+ bin,
+ hex,
+)
+from . import (
+ encoding,
+ lock as lockmod,
+ obsolete,
+ util,
+)
class bmstore(dict):
"""Storage for bookmarks.
@@ -79,6 +90,11 @@
can be copied back on rollback.
'''
repo = self._repo
+ if (repo.ui.configbool('devel', 'all-warnings')
+ or repo.ui.configbool('devel', 'check-locks')):
+ l = repo._wlockref and repo._wlockref()
+ if l is None or not l.held:
+ repo.ui.develwarn('bookmarks write with no wlock')
self._writerepo(repo)
repo.invalidatevolatilesets()
--- a/mercurial/branchmap.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/branchmap.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,13 +5,28 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import bin, hex, nullid, nullrev
-import encoding
-import scmutil
-import util
+from __future__ import absolute_import
+
+import array
+import struct
import time
-from array import array
-from struct import calcsize, pack, unpack
+
+from .node import (
+ bin,
+ hex,
+ nullid,
+ nullrev,
+)
+from . import (
+ encoding,
+ scmutil,
+ util,
+)
+
+array = array.array
+calcsize = struct.calcsize
+pack = struct.pack
+unpack = struct.unpack
def _filename(repo):
"""name of a branchcache file for a given repo or repoview"""
--- a/mercurial/bundle2.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/bundle2.py Tue Aug 18 18:38:56 2015 -0500
@@ -145,19 +145,25 @@
preserve.
"""
+from __future__ import absolute_import
+
import errno
-import sys
-import util
-import struct
-import urllib
+import re
import string
-import obsolete
-import pushkey
-import url
-import re
+import struct
+import sys
+import urllib
-import changegroup, error, tags
-from i18n import _
+from .i18n import _
+from . import (
+ changegroup,
+ error,
+ obsolete,
+ pushkey,
+ tags,
+ url,
+ util,
+)
_pack = struct.pack
_unpack = struct.unpack
@@ -1233,7 +1239,7 @@
# we need to make sure we trigger the creation of a transaction object used
# for the whole processing scope.
op.gettransaction()
- import exchange
+ from . import exchange
cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
if not isinstance(cg, changegroup.cg1unpacker):
raise util.Abort(_('%s: not a bundle version 1.0') %
--- a/mercurial/bundlerepo.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/bundlerepo.py Tue Aug 18 18:38:56 2015 -0500
@@ -11,12 +11,33 @@
were part of the actual repository.
"""
-from node import nullid
-from i18n import _
-import os, tempfile, shutil
-import changegroup, util, mdiff, discovery, cmdutil, scmutil, exchange
-import localrepo, changelog, manifest, filelog, revlog, error, phases, bundle2
-import pathutil
+from __future__ import absolute_import
+
+import os
+import shutil
+import tempfile
+
+from .i18n import _
+from .node import nullid
+
+from . import (
+ bundle2,
+ changegroup,
+ changelog,
+ cmdutil,
+ discovery,
+ error,
+ exchange,
+ filelog,
+ localrepo,
+ manifest,
+ mdiff,
+ pathutil,
+ phases,
+ revlog,
+ scmutil,
+ util,
+)
class bundlerevlog(revlog.revlog):
def __init__(self, opener, indexfile, bundle, linkmapper):
--- a/mercurial/changegroup.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/changegroup.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,12 +5,32 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
+import bz2
+import os
+import struct
+import tempfile
import weakref
-from i18n import _
-from node import nullrev, nullid, hex, short
-import mdiff, util, dagutil
-import struct, os, bz2, zlib, tempfile
-import discovery, error, phases, branchmap
+import zlib
+
+from .i18n import _
+from .node import (
+ hex,
+ nullid,
+ nullrev,
+ short,
+)
+
+from . import (
+ branchmap,
+ dagutil,
+ discovery,
+ error,
+ mdiff,
+ phases,
+ util,
+)
_CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s"
_CHANGEGROUPV2_DELTA_HEADER = "20s20s20s20s20s"
@@ -103,7 +123,7 @@
cleanup = filename
if bundletype == "HG20":
- import bundle2
+ from . import bundle2
bundle = bundle2.bundle20(ui)
part = bundle.newpart('changegroup', data=cg.getchunks())
part.addparam('version', cg.version)
--- a/mercurial/changelog.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/changelog.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,22 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import bin, hex, nullid
-from i18n import _
-import util, error, revlog, encoding
+from __future__ import absolute_import
+
+from .i18n import _
+from .node import (
+ bin,
+ hex,
+ nullid,
+)
+
+from . import (
+ encoding,
+ error,
+ revlog,
+ revset,
+ util,
+)
_defaultextra = {'branch': 'default'}
@@ -172,6 +185,10 @@
self.rev(self.node(0))
return self._nodecache
+ def reachableroots(self, minroot, heads, roots, includepath=False):
+ return revset.baseset(sorted(
+ self.index.reachableroots(minroot, heads, roots, includepath)))
+
def headrevs(self):
if self.filteredrevs:
try:
--- a/mercurial/cmdutil.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/cmdutil.py Tue Aug 18 18:38:56 2015 -0500
@@ -10,7 +10,7 @@
import os, sys, errno, re, tempfile, cStringIO, shutil
import util, scmutil, templater, patch, error, templatekw, revlog, copies
import match as matchmod
-import context, repair, graphmod, revset, phases, obsolete, pathutil
+import repair, graphmod, revset, phases, obsolete, pathutil
import changelog
import bookmarks
import encoding
@@ -848,6 +848,8 @@
:updatefunc: a function that update a repo to a given node
updatefunc(<repo>, <node>)
"""
+ # avoid cycle context -> subrepo -> cmdutil
+ import context
tmpname, message, user, date, branch, nodeid, p1, p2 = \
patch.extract(ui, hunk)
@@ -2464,6 +2466,9 @@
return commitfunc(ui, repo, message, matcher, opts)
def amend(ui, repo, commitfunc, old, extra, pats, opts):
+ # avoid cycle context -> subrepo -> cmdutil
+ import context
+
# amend will reuse the existing user if not specified, but the obsolete
# marker creation requires that the current user's name is specified.
if obsolete.isenabled(repo, obsolete.createmarkersopt):
--- a/mercurial/commands.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/commands.py Tue Aug 18 18:38:56 2015 -0500
@@ -13,7 +13,7 @@
import hg, scmutil, util, revlog, copies, error, bookmarks
import patch, help, encoding, templatekw, discovery
import archival, changegroup, cmdutil, hbisect
-import sshserver, hgweb, commandserver
+import sshserver, hgweb
import extensions
from hgweb import server as hgweb_server
import merge as mergemod
@@ -2700,9 +2700,12 @@
pa.distance(pb), rel))
@command('debugrebuilddirstate|debugrebuildstate',
- [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
+ [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
+ ('', 'minimal', None, _('only rebuild files that are inconsistent with '
+ 'the working copy parent')),
+ ],
_('[-r REV]'))
-def debugrebuilddirstate(ui, repo, rev):
+def debugrebuilddirstate(ui, repo, rev, **opts):
"""rebuild the dirstate as it would look like for the given revision
If no revision is specified the first current parent will be used.
@@ -2711,13 +2714,33 @@
The actual working directory content or existing dirstate
information such as adds or removes is not considered.
+ ``minimal`` will only rebuild the dirstate status for files that claim to be
+ tracked but are not in the parent manifest, or that exist in the parent
+ manifest but are not in the dirstate. It will not change adds, removes, or
+ modified files that are in the working copy parent.
+
One use of this command is to make the next :hg:`status` invocation
check the actual file content.
"""
ctx = scmutil.revsingle(repo, rev)
wlock = repo.wlock()
try:
- repo.dirstate.rebuild(ctx.node(), ctx.manifest())
+ dirstate = repo.dirstate
+
+ # See command doc for what minimal does.
+ if opts.get('minimal'):
+ dirstatefiles = set(dirstate)
+ ctxfiles = set(ctx.manifest().keys())
+ for file in (dirstatefiles | ctxfiles):
+ indirstate = file in dirstatefiles
+ inctx = file in ctxfiles
+
+ if indirstate and not inctx and dirstate[file] != 'a':
+ dirstate.drop(file)
+ elif inctx and not indirstate:
+ dirstate.normallookup(file)
+ else:
+ dirstate.rebuild(ctx.node(), ctx.manifest())
finally:
wlock.release()
@@ -2933,7 +2956,7 @@
expansion.
"""
if ui.verbose:
- tree = revset.parse(expr)
+ tree = revset.parse(expr, lookup=repo.__contains__)
ui.note(revset.prettyformat(tree), "\n")
newtree = revset.findaliases(ui, tree)
if newtree != tree:
@@ -2945,7 +2968,7 @@
if opts["optimize"]:
weight, optimizedtree = revset.optimize(newtree, True)
ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
- func = revset.match(ui, expr)
+ func = revset.match(ui, expr, repo)
revs = func(repo)
if ui.verbose:
ui.note("* set:\n", revset.prettyformatset(revs), "\n")
@@ -5713,6 +5736,7 @@
s.serve_forever()
if opts["cmdserver"]:
+ import commandserver
service = commandserver.createservice(ui, repo, opts)
return cmdutil.service(opts, initfn=service.init, runfn=service.run)
@@ -6248,7 +6272,7 @@
raise util.Abort(_("tag '%s' is not a global tag") % n)
else:
raise util.Abort(_("tag '%s' is not a local tag") % n)
- rev_ = nullid
+ rev_ = 'null'
if not message:
# we don't translate commit messages
message = 'Removed tag %s' % ', '.join(names)
--- a/mercurial/config.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/config.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,16 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import error, util
-import os, errno
+from __future__ import absolute_import
+
+import errno
+import os
+
+from .i18n import _
+from . import (
+ error,
+ util,
+)
class config(object):
def __init__(self, data=None, includepaths=[]):
--- a/mercurial/copies.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/copies.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,15 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import util, pathutil
+from __future__ import absolute_import
+
import heapq
+from . import (
+ pathutil,
+ util,
+)
+
def _findlimit(repo, a, b):
"""
Find the last revision that needs to be checked to ensure that a full
@@ -185,6 +191,9 @@
return cm
def _backwardrenames(a, b):
+ if a._repo.ui.configbool('experimental', 'disablecopytrace'):
+ return {}
+
# Even though we're not taking copies into account, 1:n rename situations
# can still exist (e.g. hg cp a b; hg mv a c). In those cases we
# arbitrarily pick one of the renames.
@@ -258,6 +267,12 @@
if c2.node() is None and c1.node() == repo.dirstate.p1():
return repo.dirstate.copies(), {}, {}, {}
+ # Copy trace disabling is explicitly below the node == p1 logic above
+ # because the logic above is required for a simple copy to be kept across a
+ # rebase.
+ if repo.ui.configbool('experimental', 'disablecopytrace'):
+ return {}, {}, {}, {}
+
limit = _findlimit(repo, c1.rev(), c2.rev())
if limit is None:
# no common ancestor, no copies
@@ -507,7 +522,12 @@
copies between fromrev and rev.
'''
exclude = {}
- if skiprev is not None:
+ if (skiprev is not None and
+ not repo.ui.configbool('experimental', 'disablecopytrace')):
+ # disablecopytrace skips this line, but not the entire function because
+ # the line below is O(size of the repo) during a rebase, while the rest
+ # of the function is much faster (and is required for carrying copy
+ # metadata across the rebase anyway).
exclude = pathcopies(repo[fromrev], repo[skiprev])
for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
# copies.pathcopies returns backward renames, so dst might not
--- a/mercurial/crecord.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/crecord.py Tue Aug 18 18:38:56 2015 -0500
@@ -8,11 +8,23 @@
# This code is based on the Mark Edgington's crecord extension.
# (Itself based on Bryan O'Sullivan's record extension.)
-from i18n import _
-import patch as patchmod
-import util, encoding
+from __future__ import absolute_import
-import os, re, sys, struct, signal, tempfile, locale, cStringIO
+import cStringIO
+import locale
+import os
+import re
+import signal
+import struct
+import sys
+import tempfile
+
+from .i18n import _
+from . import (
+ encoding,
+ patch as patchmod,
+ util,
+)
# This is required for ncurses to display non-ASCII characters in default user
# locale encoding correctly. --immerrr
@@ -21,7 +33,8 @@
# os.name is one of: 'posix', 'nt', 'dos', 'os2', 'mac', or 'ce'
if os.name == 'posix':
import curses
- import fcntl, termios
+ import fcntl
+ import termios
else:
# I have no idea if wcurses works with crecord...
try:
--- a/mercurial/dagparser.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/dagparser.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,13 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import re, string
-import util
-from i18n import _
+from __future__ import absolute_import
+
+import re
+import string
+
+from .i18n import _
+from . import util
def parsedag(desc):
'''parses a DAG from a concise textual description; generates events
--- a/mercurial/dagutil.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/dagutil.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,9 +6,10 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import nullrev
-from i18n import _
+from __future__ import absolute_import
+from .i18n import _
+from .node import nullrev
class basedag(object):
'''generic interface for DAGs
--- a/mercurial/demandimport.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/demandimport.py Tue Aug 18 18:38:56 2015 -0500
@@ -24,8 +24,11 @@
b = __import__(a)
'''
-import os, sys
-from contextlib import contextmanager
+from __future__ import absolute_import
+
+import contextlib
+import os
+import sys
# __builtin__ in Python 2, builtins in Python 3.
try:
@@ -33,26 +36,21 @@
except ImportError:
import builtins
+contextmanager = contextlib.contextmanager
+
_origimport = __import__
nothing = object()
-try:
- # Python 3 doesn't have relative imports nor level -1.
- level = -1
- if sys.version_info[0] >= 3:
- level = 0
- _origimport(builtins.__name__, {}, {}, None, level)
-except TypeError: # no level argument
- def _import(name, globals, locals, fromlist, level):
- "call _origimport with no level argument"
- return _origimport(name, globals, locals, fromlist)
-else:
- _import = _origimport
+# Python 3 doesn't have relative imports nor level -1.
+level = -1
+if sys.version_info[0] >= 3:
+ level = 0
+_import = _origimport
-def _hgextimport(importfunc, name, globals, *args):
+def _hgextimport(importfunc, name, globals, *args, **kwargs):
try:
- return importfunc(name, globals, *args)
+ return importfunc(name, globals, *args, **kwargs)
except ImportError:
if not globals:
raise
@@ -63,7 +61,7 @@
if nameroot != contextroot:
raise
# retry to import with "hgext_" prefix
- return importfunc(hgextname, globals, *args)
+ return importfunc(hgextname, globals, *args, **kwargs)
class _demandmod(object):
"""module demand-loader and proxy"""
@@ -135,15 +133,44 @@
return locals[base]
return _demandmod(name, globals, locals, level)
else:
- if level != -1:
- # from . import b,c,d or from .a import b,c,d
- return _origimport(name, globals, locals, fromlist, level)
+ # There is a fromlist.
# from a import b,c,d
+ # from . import b,c,d
+ # from .a import b,c,d
+
+ # level == -1: relative and absolute attempted (Python 2 only).
+ # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
+ # The modern Mercurial convention is to use absolute_import everywhere,
+ # so modern Mercurial code will have level >= 0.
+
+ if level >= 0:
+ # Mercurial's enforced import style does not use
+ # "from a import b,c,d" or "from .a import b,c,d" syntax. In
+ # addition, this appears to be giving errors with some modules
+ # for unknown reasons. Since we shouldn't be using this syntax
+ # much, work around the problems.
+ if name:
+ return _hgextimport(_origimport, name, globals, locals,
+ fromlist, level)
+
+ mod = _hgextimport(_origimport, name, globals, locals, level=level)
+ for x in fromlist:
+ # Missing symbols mean they weren't defined in the module
+ # itself which means they are sub-modules.
+ if getattr(mod, x, nothing) is nothing:
+ setattr(mod, x,
+ _demandmod(x, mod.__dict__, locals, level=level))
+
+ return mod
+
+ # But, we still need to support lazy loading of standard library and 3rd
+ # party modules. So handle level == -1.
mod = _hgextimport(_origimport, name, globals, locals)
# recurse down the module chain
for comp in name.split('.')[1:]:
if getattr(mod, comp, nothing) is nothing:
- setattr(mod, comp, _demandmod(comp, mod.__dict__, mod.__dict__))
+ setattr(mod, comp,
+ _demandmod(comp, mod.__dict__, mod.__dict__))
mod = getattr(mod, comp)
for x in fromlist:
# set requested submodules for demand load
@@ -152,6 +179,7 @@
return mod
ignore = [
+ '__future__',
'_hashlib',
'_xmlplus',
'fcntl',
--- a/mercurial/discovery.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/discovery.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,10 +5,23 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import nullid, short
-from i18n import _
-import util, setdiscovery, treediscovery, phases, obsolete, bookmarks
-import branchmap
+from __future__ import absolute_import
+
+from .i18n import _
+from .node import (
+ nullid,
+ short,
+)
+
+from . import (
+ bookmarks,
+ branchmap,
+ obsolete,
+ phases,
+ setdiscovery,
+ treediscovery,
+ util,
+)
def findcommonincoming(repo, remote, heads=None, force=False):
"""Return a tuple (common, anyincoming, heads) used to identify the common
--- a/mercurial/dispatch.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/dispatch.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,13 +5,37 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
+from __future__ import absolute_import
+
+import atexit
import difflib
-import util, commands, hg, fancyopts, extensions, hook, error
-import cmdutil, encoding
-import ui as uimod
-import demandimport
+import errno
+import os
+import pdb
+import re
+import shlex
+import signal
+import socket
+import sys
+import time
+import traceback
+
+
+from .i18n import _
+
+from . import (
+ cmdutil,
+ commands,
+ demandimport,
+ encoding,
+ error,
+ extensions,
+ fancyopts,
+ hg,
+ hook,
+ ui as uimod,
+ util,
+)
class request(object):
def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
@@ -909,7 +933,7 @@
format = 'text'
try:
- from mercurial import lsprof
+ from . import lsprof
except ImportError:
raise util.Abort(_(
'lsprof not available - install from '
@@ -922,7 +946,7 @@
p.disable()
if format == 'kcachegrind':
- import lsprofcalltree
+ from . import lsprofcalltree
calltree = lsprofcalltree.KCacheGrind(p)
calltree.output(fp)
else:
--- a/mercurial/error.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/error.py Tue Aug 18 18:38:56 2015 -0500
@@ -11,6 +11,8 @@
imports.
"""
+from __future__ import absolute_import
+
# Do not import anything here, please
class HintException(Exception):
@@ -32,7 +34,7 @@
# Python 2.6+ complain about the 'message' property being deprecated
self.lookupmessage = message
if isinstance(name, str) and len(name) == 20:
- from node import short
+ from .node import short
name = short(name)
RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
@@ -78,7 +80,7 @@
"""Exception raised when a {rev,file}set references an unknown identifier"""
def __init__(self, function, symbols):
- from i18n import _
+ from .i18n import _
ParseError.__init__(self, _("unknown identifier: %s") % function)
self.function = function
self.symbols = symbols
@@ -173,7 +175,7 @@
"""
def __init__(self, filename, node, tombstone):
- from node import short
+ from .node import short
RevlogError.__init__(self, '%s:%s' % (filename, short(node)))
self.tombstone = tombstone
--- a/mercurial/exchange.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/exchange.py Tue Aug 18 18:38:56 2015 -0500
@@ -571,7 +571,7 @@
@b2partsgenerator('bookmarks')
def _pushb2bookmarks(pushop, bundler):
- """handle phase push through bundle2"""
+ """handle bookmark push through bundle2"""
if 'bookmarks' in pushop.stepsdone:
return
b2caps = bundle2.bundle2caps(pushop.remote)
@@ -1419,7 +1419,7 @@
op = bundle2.bundleoperation(repo, lambda: tr,
captureoutput=captureoutput)
try:
- r = bundle2.processbundle(repo, cg, op=op)
+ op = bundle2.processbundle(repo, cg, op=op)
finally:
r = op.reply
if captureoutput and r is not None:
--- a/mercurial/extensions.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/extensions.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,21 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import imp, os
-import util, cmdutil, error
-from i18n import _, gettext
+from __future__ import absolute_import
+
+import imp
+import os
+
+from .i18n import (
+ _,
+ gettext,
+)
+
+from . import (
+ cmdutil,
+ error,
+ util,
+)
_extensions = {}
_aftercallbacks = {}
--- a/mercurial/fancyopts.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/fancyopts.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,12 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import getopt
-import util
-from i18n import _
+
+from .i18n import _
+from . import util
def gnugetopt(args, options, longoptions):
"""Parse options mostly like getopt.gnu_getopt.
--- a/mercurial/filelog.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/filelog.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,8 +5,16 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import error, mdiff, revlog
-import re, struct
+from __future__ import absolute_import
+
+import re
+import struct
+
+from . import (
+ error,
+ mdiff,
+ revlog,
+)
_mdre = re.compile('\1\n')
def parsemeta(text):
--- a/mercurial/filemerge.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/filemerge.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,11 +5,25 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import short
-from i18n import _
-import util, simplemerge, match, error, templater, templatekw
-import os, tempfile, re, filecmp
-import tagmerge
+from __future__ import absolute_import
+
+import filecmp
+import os
+import re
+import tempfile
+
+from .i18n import _
+from .node import short
+
+from . import (
+ error,
+ match,
+ simplemerge,
+ tagmerge,
+ templatekw,
+ templater,
+ util,
+)
def _toolstr(ui, tool, part, default=""):
return ui.config("merge-tools", tool + "." + part, default)
--- a/mercurial/fileset.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/fileset.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,17 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import re
-import parser, error, util, merge
-from i18n import _
+
+from .i18n import _
+from . import (
+ error,
+ merge,
+ parser,
+ util,
+)
elements = {
# token-type: binding-strength, primary, prefix, infix, suffix
@@ -410,7 +418,7 @@
# i18n: "subrepo" is a keyword
pat = getstring(x, _("subrepo requires a pattern or no arguments"))
- import match as matchmod # avoid circular import issues
+ from . import match as matchmod # avoid circular import issues
fast = not matchmod.patkind(pat)
if fast:
def m(s):
--- a/mercurial/formatter.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/formatter.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,13 +5,23 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import cPickle
-from node import hex, short
-from i18n import _
-import encoding, util
-import templater
import os
+from .i18n import _
+from .node import (
+ hex,
+ short,
+)
+
+from . import (
+ encoding,
+ templater,
+ util,
+)
+
class baseformatter(object):
def __init__(self, ui, topic, opts):
self._ui = ui
--- a/mercurial/graphmod.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/graphmod.py Tue Aug 18 18:38:56 2015 -0500
@@ -17,11 +17,16 @@
Data depends on type.
"""
-from mercurial.node import nullrev
-import util
+from __future__ import absolute_import
import heapq
+from .node import nullrev
+from . import (
+ revset,
+ util,
+)
+
CHANGESET = 'C'
def groupbranchiter(revs, parentsfunc, firstbranch=()):
@@ -233,8 +238,6 @@
if not revs:
return
- cl = repo.changelog
- lowestrev = revs.min()
gpcache = {}
if repo.ui.configbool('experimental', 'graph-group-branches', False):
@@ -256,7 +259,7 @@
for mpar in mpars:
gp = gpcache.get(mpar)
if gp is None:
- gp = gpcache[mpar] = grandparent(cl, lowestrev, revs, mpar)
+ gp = gpcache[mpar] = revset.reachableroots(repo, revs, [mpar])
if not gp:
parents.append(mpar)
else:
@@ -354,24 +357,6 @@
yield (cur, type, data, (col, color), edges)
seen = next
-def grandparent(cl, lowestrev, roots, head):
- """Return all ancestors of head in roots which revision is
- greater or equal to lowestrev.
- """
- pending = set([head])
- seen = set()
- kept = set()
- llowestrev = max(nullrev, lowestrev)
- while pending:
- r = pending.pop()
- if r >= llowestrev and r not in seen:
- if r in roots:
- kept.add(r)
- else:
- pending.update([p for p in cl.parentrevs(r)])
- seen.add(r)
- return sorted(kept)
-
def asciiedges(type, char, lines, seen, rev, parents):
"""adds edge info to changelog DAG walk suitable for ascii()"""
if rev not in seen:
--- a/mercurial/hbisect.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/hbisect.py Tue Aug 18 18:38:56 2015 -0500
@@ -8,12 +8,20 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import collections
import os
-import error
-from i18n import _
-from node import short, hex
-import util
+
+from .i18n import _
+from .node import (
+ hex,
+ short,
+)
+from . import (
+ error,
+ util,
+)
def bisect(changelog, state):
"""find the next node (if any) for testing during a bisect search.
--- a/mercurial/hg.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/hg.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,17 +6,41 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-from lock import release
-from node import nullid
+from __future__ import absolute_import
+
+import errno
+import os
+import shutil
+
+from .i18n import _
+from .node import nullid
-import localrepo, bundlerepo, unionrepo, httppeer, sshpeer, statichttprepo
-import bookmarks, lock, util, extensions, error, node, scmutil, phases, url
-import cmdutil, discovery, repoview, exchange
-import ui as uimod
-import merge as mergemod
-import verify as verifymod
-import errno, os, shutil
+from . import (
+ bookmarks,
+ bundlerepo,
+ cmdutil,
+ discovery,
+ error,
+ exchange,
+ extensions,
+ httppeer,
+ localrepo,
+ lock,
+ merge as mergemod,
+ node,
+ phases,
+ repoview,
+ scmutil,
+ sshpeer,
+ statichttprepo,
+ ui as uimod,
+ unionrepo,
+ url,
+ util,
+ verify as verifymod,
+)
+
+release = lock.release
def _local(path):
path = util.expandpath(util.urllocalpath(path))
--- a/mercurial/hgweb/webutil.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/hgweb/webutil.py Tue Aug 18 18:38:56 2015 -0500
@@ -203,7 +203,7 @@
path = path.lstrip('/')
return pathutil.canonpath(repo.root, '', path)
-def changeidctx (repo, changeid):
+def changeidctx(repo, changeid):
try:
ctx = repo[changeid]
except error.RepoError:
@@ -212,11 +212,11 @@
return ctx
-def changectx (repo, req):
+def changectx(repo, req):
changeid = "tip"
if 'node' in req.form:
changeid = req.form['node'][0]
- ipos=changeid.find(':')
+ ipos = changeid.find(':')
if ipos != -1:
changeid = changeid[(ipos + 1):]
elif 'manifest' in req.form:
@@ -227,7 +227,7 @@
def basechangectx(repo, req):
if 'node' in req.form:
changeid = req.form['node'][0]
- ipos=changeid.find(':')
+ ipos = changeid.find(':')
if ipos != -1:
changeid = changeid[:ipos]
return changeidctx(repo, changeid)
--- a/mercurial/hook.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/hook.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,19 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import os, sys, time
-import extensions, util, demandimport, error
+from __future__ import absolute_import
+
+import os
+import sys
+import time
+
+from .i18n import _
+from . import (
+ demandimport,
+ error,
+ extensions,
+ util,
+)
def _pythonhook(ui, repo, name, hname, funcname, args, throw):
'''call python hook. hook is callable object, looked up as
--- a/mercurial/httppeer.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/httppeer.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,12 +6,28 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import nullid
-from i18n import _
+from __future__ import absolute_import
+
+import errno
+import httplib
+import os
+import socket
import tempfile
-import changegroup, statichttprepo, error, httpconnection, url, util, wireproto
-import os, urllib, urllib2, zlib, httplib
-import errno, socket
+import urllib
+import urllib2
+import zlib
+
+from .i18n import _
+from .node import nullid
+from . import (
+ changegroup,
+ error,
+ httpconnection,
+ statichttprepo,
+ url,
+ util,
+ wireproto,
+)
def zgenerator(f):
zd = zlib.decompressobj()
--- a/mercurial/i18n.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/i18n.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,8 +5,14 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import encoding
-import gettext as gettextmod, sys, os, locale
+from __future__ import absolute_import
+
+import gettext as gettextmod
+import locale
+import os
+import sys
+
+from . import encoding
# modelled after templater.templatepath:
if getattr(sys, 'frozen', None) is not None:
--- a/mercurial/lock.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/lock.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,10 +5,19 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import util, error
-import errno, os, socket, time
+from __future__ import absolute_import
+
+import errno
+import os
+import socket
+import time
import warnings
+from . import (
+ error,
+ util,
+)
+
class lock(object):
'''An advisory lock held by one process to control access to a set
of files. Non-cooperating processes or incorrectly written scripts
--- a/mercurial/mail.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/mail.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,10 +5,22 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import util, encoding, sslutil
-import os, smtplib, socket, quopri, time, sys
+from __future__ import absolute_import
+
import email
+import os
+import quopri
+import smtplib
+import socket
+import sys
+import time
+
+from .i18n import _
+from . import (
+ encoding,
+ sslutil,
+ util,
+)
_oldheaderinit = email.Header.Header.__init__
def _unifiedheaderinit(self, *args, **kw):
--- a/mercurial/match.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/match.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,17 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import copy, os, re
-import util, pathutil
-from i18n import _
+from __future__ import absolute_import
+
+import copy
+import os
+import re
+
+from .i18n import _
+from . import (
+ pathutil,
+ util,
+)
propertycache = util.propertycache
--- a/mercurial/merge.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/merge.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,13 +5,29 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
+import errno
+import os
+import shutil
import struct
-from node import nullid, nullrev, hex, bin
-from i18n import _
-from mercurial import obsolete
-import error as errormod, util, filemerge, copies, subrepo, worker
-import errno, os, shutil
+from .i18n import _
+from .node import (
+ bin,
+ hex,
+ nullid,
+ nullrev,
+)
+from . import (
+ copies,
+ error as errormod,
+ filemerge,
+ obsolete,
+ subrepo,
+ util,
+ worker,
+)
_pack = struct.pack
_unpack = struct.unpack
--- a/mercurial/minirst.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/minirst.py Tue Aug 18 18:38:56 2015 -0500
@@ -18,11 +18,16 @@
when adding support for new constructs.
"""
-import re
-import util, encoding
-from i18n import _
+from __future__ import absolute_import
import cgi
+import re
+
+from .i18n import _
+from . import (
+ encoding,
+ util,
+)
def section(s):
return "%s\n%s\n\n" % (s, "\"" * encoding.colwidth(s))
--- a/mercurial/namespaces.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/namespaces.py Tue Aug 18 18:38:56 2015 -0500
@@ -1,6 +1,10 @@
-from i18n import _
-from mercurial import util
-import templatekw
+from __future__ import absolute_import
+
+from .i18n import _
+from . import (
+ templatekw,
+ util,
+)
def tolist(val):
"""
--- a/mercurial/node.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/node.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,6 +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.
+from __future__ import absolute_import
+
import binascii
nullrev = -1
--- a/mercurial/parser.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/parser.py Tue Aug 18 18:38:56 2015 -0500
@@ -16,8 +16,10 @@
# an action is a tree node name, a tree label, and an optional match
# __call__(program) parses program into a labeled tree
-import error
-from i18n import _
+from __future__ import absolute_import
+
+from .i18n import _
+from . import error
class parser(object):
def __init__(self, elements, methods=None):
--- a/mercurial/parsers.c Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/parsers.c Tue Aug 18 18:38:56 2015 -0500
@@ -1105,6 +1105,153 @@
phases[i] = phases[parent_2];
}
+static PyObject *reachableroots(indexObject *self, PyObject *args)
+{
+
+ /* Input */
+ long minroot;
+ PyObject *includepatharg = NULL;
+ int includepath = 0;
+ /* heads is a list */
+ PyObject *heads = NULL;
+ /* roots is a set */
+ PyObject *roots = NULL;
+ PyObject *reachable = NULL;
+
+ PyObject *val;
+ Py_ssize_t len = index_length(self) - 1;
+ long revnum;
+ Py_ssize_t k;
+ Py_ssize_t i;
+ Py_ssize_t l;
+ int r;
+ int minidx;
+ int parents[2];
+
+ /* Internal data structure:
+ * tovisit: array of length len+1 (all revs + nullrev), filled upto lentovisit
+ * revstates: array of length len+1 (all revs + nullrev) */
+ int *tovisit = NULL;
+ long lentovisit = 0;
+ enum { RS_SEEN = 1 };
+ char *revstates = NULL;
+
+ /* Get arguments */
+ if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
+ &PySet_Type, &roots, &PyBool_Type, &includepatharg))
+ goto bail;
+
+ if (includepatharg == Py_True)
+ includepath = 1;
+
+ /* Initialize return set */
+ reachable = PySet_New(NULL);
+ if (reachable == NULL) {
+ PyErr_NoMemory();
+ goto bail;
+ }
+
+ /* Initialize internal datastructures */
+ tovisit = (int *)malloc((len + 1) * sizeof(int));
+ if (tovisit == NULL) {
+ PyErr_NoMemory();
+ goto bail;
+ }
+
+ revstates = (char *)calloc(len + 1, 1);
+ if (revstates == NULL) {
+ PyErr_NoMemory();
+ goto bail;
+ }
+
+ /* Populate tovisit with all the heads */
+ l = PyList_GET_SIZE(heads);
+ for (i = 0; i < l; i++) {
+ revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
+ if (revnum == -1 && PyErr_Occurred())
+ goto bail;
+ if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
+ PyErr_SetString(PyExc_IndexError, "head out of range");
+ goto bail;
+ }
+ if (!(revstates[revnum + 1] & RS_SEEN)) {
+ tovisit[lentovisit++] = revnum;
+ revstates[revnum + 1] |= RS_SEEN;
+ }
+ }
+
+ /* Visit the tovisit list and find the reachable roots */
+ k = 0;
+ while (k < lentovisit) {
+ /* Add the node to reachable if it is a root*/
+ revnum = tovisit[k++];
+ val = PyInt_FromLong(revnum);
+ if (val == NULL)
+ goto bail;
+ if (PySet_Contains(roots, val) == 1) {
+ PySet_Add(reachable, val);
+ if (includepath == 0) {
+ Py_DECREF(val);
+ continue;
+ }
+ }
+ Py_DECREF(val);
+
+ /* Add its parents to the list of nodes to visit */
+ if (revnum == -1)
+ continue;
+ r = index_get_parents(self, revnum, parents, (int)len - 1);
+ if (r < 0)
+ goto bail;
+ for (i = 0; i < 2; i++) {
+ if (!(revstates[parents[i] + 1] & RS_SEEN)
+ && parents[i] >= minroot) {
+ tovisit[lentovisit++] = parents[i];
+ revstates[parents[i] + 1] |= RS_SEEN;
+ }
+ }
+ }
+
+ /* Find all the nodes in between the roots we found and the heads
+ * and add them to the reachable set */
+ if (includepath == 1) {
+ minidx = minroot;
+ if (minidx < 0)
+ minidx = 0;
+ for (i = minidx; i < len; i++) {
+ if (!(revstates[i + 1] & RS_SEEN))
+ continue;
+ r = index_get_parents(self, i, parents, (int)len - 1);
+ /* Corrupted index file, error is set from
+ * index_get_parents */
+ if (r < 0)
+ goto bail;
+ for (k = 0; k < 2; k++) {
+ PyObject *p = PyInt_FromLong(parents[k]);
+ if (p == NULL)
+ goto bail;
+ if (PySet_Contains(reachable, p) == 1) {
+ val = PyInt_FromLong(i);
+ if (val == NULL)
+ goto bail;
+ PySet_Add(reachable, val);
+ Py_DECREF(val);
+ }
+ Py_DECREF(p);
+ }
+ }
+ }
+
+ free(revstates);
+ free(tovisit);
+ return reachable;
+bail:
+ Py_XDECREF(reachable);
+ free(revstates);
+ free(tovisit);
+ return NULL;
+}
+
static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
{
PyObject *roots = Py_None;
@@ -2282,6 +2429,8 @@
"get an index entry"},
{"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
METH_VARARGS, "compute phases"},
+ {"reachableroots", (PyCFunction)reachableroots, METH_VARARGS,
+ "reachableroots"},
{"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
"get head revisions"}, /* Can do filtering since 3.2 */
{"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
--- a/mercurial/pathutil.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/pathutil.py Tue Aug 18 18:38:56 2015 -0500
@@ -1,8 +1,15 @@
-import os, errno, stat, posixpath
+from __future__ import absolute_import
-import encoding
-import util
-from i18n import _
+import errno
+import os
+import posixpath
+import stat
+
+from .i18n import _
+from . import (
+ encoding,
+ util,
+)
def _lowerclean(s):
return encoding.hfsignoreclean(s.lower())
--- a/mercurial/peer.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/peer.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,11 +6,91 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import error
+from __future__ import absolute_import
+
+from .i18n import _
+from . import (
+ error,
+ util,
+)
+
+# abstract batching support
+
+class future(object):
+ '''placeholder for a value to be set later'''
+ def set(self, value):
+ if util.safehasattr(self, 'value'):
+ raise error.RepoError("future is already set")
+ self.value = value
+
+class batcher(object):
+ '''base class for batches of commands submittable in a single request
+
+ All methods invoked on instances of this class are simply queued and
+ return a a future for the result. Once you call submit(), all the queued
+ calls are performed and the results set in their respective futures.
+ '''
+ def __init__(self):
+ self.calls = []
+ def __getattr__(self, name):
+ def call(*args, **opts):
+ resref = future()
+ self.calls.append((name, args, opts, resref,))
+ return resref
+ return call
+ def submit(self):
+ pass
+
+class localbatch(batcher):
+ '''performs the queued calls directly'''
+ def __init__(self, local):
+ batcher.__init__(self)
+ self.local = local
+ def submit(self):
+ for name, args, opts, resref in self.calls:
+ resref.set(getattr(self.local, name)(*args, **opts))
+
+def batchable(f):
+ '''annotation for batchable methods
+
+ Such methods must implement a coroutine as follows:
+
+ @batchable
+ def sample(self, one, two=None):
+ # Handle locally computable results first:
+ if not one:
+ yield "a local result", None
+ # Build list of encoded arguments suitable for your wire protocol:
+ encargs = [('one', encode(one),), ('two', encode(two),)]
+ # Create future for injection of encoded result:
+ encresref = future()
+ # Return encoded arguments and future:
+ yield encargs, encresref
+ # Assuming the future to be filled with the result from the batched
+ # request now. Decode it:
+ yield decode(encresref.value)
+
+ The decorator returns a function which wraps this coroutine as a plain
+ method, but adds the original method as an attribute called "batchable",
+ which is used by remotebatch to split the call into separate encoding and
+ decoding phases.
+ '''
+ def plain(*args, **opts):
+ batchable = f(*args, **opts)
+ encargsorres, encresref = batchable.next()
+ if not encresref:
+ return encargsorres # a local result in this case
+ self = args[0]
+ encresref.set(self._submitone(f.func_name, encargsorres))
+ return batchable.next()
+ setattr(plain, 'batchable', f)
+ return plain
class peerrepository(object):
+ def batch(self):
+ return localbatch(self)
+
def capable(self, name):
'''tell whether repo supports named capability.
return False if not supported.
--- a/mercurial/phases.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/phases.py Tue Aug 18 18:38:56 2015 -0500
@@ -100,11 +100,23 @@
"""
-import os
+from __future__ import absolute_import
+
import errno
-from node import nullid, nullrev, bin, hex, short
-from i18n import _
-import util, error
+import os
+
+from .i18n import _
+from .node import (
+ bin,
+ hex,
+ nullid,
+ nullrev,
+ short,
+)
+from . import (
+ error,
+ util,
+)
allphases = public, draft, secret = range(3)
trackedphases = allphases[1:]
--- a/mercurial/posix.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/posix.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,11 +5,26 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import encoding
-import os, sys, errno, stat, getpass, pwd, grp, socket, tempfile, unicodedata
+from __future__ import absolute_import
+
+import errno
+import fcntl
+import getpass
+import grp
+import os
+import pwd
+import re
import select
-import fcntl, re
+import socket
+import stat
+import sys
+import tempfile
+import unicodedata
+
+from .i18n import _
+from . import (
+ encoding,
+)
posixfile = open
normpath = os.path.normpath
@@ -459,7 +474,8 @@
def termwidth():
try:
- import termios, array
+ import array
+ import termios
for dev in (sys.stderr, sys.stdout, sys.stdin):
try:
try:
--- a/mercurial/progress.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/progress.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,13 +5,14 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import sys
-import time
import threading
-from mercurial import encoding
+import time
-from mercurial.i18n import _
-
+from .i18n import _
+from . import encoding
def spacejoin(*args):
return ' '.join(s for s in args if s)
--- a/mercurial/pushkey.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/pushkey.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,7 +5,14 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import bookmarks, phases, obsolete, encoding
+from __future__ import absolute_import
+
+from . import (
+ bookmarks,
+ encoding,
+ obsolete,
+ phases,
+)
def _nslist(repo):
n = {}
--- a/mercurial/repair.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/repair.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,11 +6,19 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from mercurial import changegroup, exchange, util, bundle2
-from mercurial.node import short
-from mercurial.i18n import _
+from __future__ import absolute_import
+
import errno
+from .i18n import _
+from .node import short
+from . import (
+ bundle2,
+ changegroup,
+ exchange,
+ util,
+)
+
def _bundle(repo, bases, heads, node, suffix, compress=True):
"""create a bundle with the specified revisions as a backup"""
usebundle2 = (repo.ui.configbool('experimental', 'bundle2-exp', True) and
--- a/mercurial/repoview.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/repoview.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,15 +6,20 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import heapq
+from __future__ import absolute_import
+
import copy
-import error
-import phases
-import util
-import obsolete
+import heapq
import struct
-import tags as tagsmod
-from node import nullrev
+
+from .node import nullrev
+from . import (
+ error,
+ obsolete,
+ phases,
+ tags as tagsmod,
+ util,
+)
def hideablerevs(repo):
"""Revisions candidates to be hidden
--- a/mercurial/revlog.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/revlog.py Tue Aug 18 18:38:56 2015 -0500
@@ -100,11 +100,10 @@
# 4 bytes: compressed length
# 4 bytes: base rev
# 4 bytes: link rev
-# 32 bytes: parent 1 nodeid
-# 32 bytes: parent 2 nodeid
-# 32 bytes: nodeid
+# 20 bytes: parent 1 nodeid
+# 20 bytes: parent 2 nodeid
+# 20 bytes: nodeid
indexformatv0 = ">4l20s20s20s"
-v0shaoffset = 56
class revlogoldio(object):
def __init__(self):
@@ -150,7 +149,6 @@
# 4 bytes: parent 2 rev
# 32 bytes: nodeid
indexformatng = ">Qiiiiii20s12x"
-ngshaoffset = 32
versionformat = ">I"
# corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
--- a/mercurial/revset.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/revset.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,16 +5,25 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import re
-import parser, util, error, hbisect, phases
-import node
+from __future__ import absolute_import
+
import heapq
-import match as matchmod
-from i18n import _
-import encoding
-import obsolete as obsmod
-import pathutil
-import repoview
+import re
+
+from .i18n import _
+from . import (
+ encoding,
+ error,
+ hbisect,
+ match as matchmod,
+ node,
+ obsolete as obsmod,
+ parser,
+ pathutil,
+ phases,
+ repoview,
+ util,
+)
def _revancestors(repo, revs, followfirst):
"""Like revlog.ancestors(), but supports followfirst."""
@@ -78,19 +87,16 @@
return generatorset(iterate(), iterasc=True)
-def _revsbetween(repo, roots, heads):
- """Return all paths between roots and heads, inclusive of both endpoint
- sets."""
+def reachablerootspure(repo, minroot, roots, heads, includepath):
+ """return (heads(::<roots> and ::<heads>))
+
+ If includepath is True, return (<roots>::<heads>)."""
if not roots:
return baseset()
parentrevs = repo.changelog.parentrevs
visit = list(heads)
reachable = set()
seen = {}
- # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
- # (and if it is not, it should.)
- minroot = min(roots)
- roots = set(roots)
# prefetch all the things! (because python is slow)
reached = reachable.add
dovisit = visit.append
@@ -101,6 +107,8 @@
rev = nextvisit()
if rev in roots:
reached(rev)
+ if not includepath:
+ continue
parents = parentrevs(rev)
seen[rev] = parents
for parent in parents:
@@ -108,12 +116,30 @@
dovisit(parent)
if not reachable:
return baseset()
+ if not includepath:
+ return reachable
for rev in sorted(seen):
for parent in seen[rev]:
if parent in reachable:
reached(rev)
return baseset(sorted(reachable))
+def reachableroots(repo, roots, heads, includepath=False):
+ """return (heads(::<roots> and ::<heads>))
+
+ If includepath is True, return (<roots>::<heads>)."""
+ if not roots:
+ return baseset()
+ # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
+ # (and if it is not, it should.)
+ minroot = min(roots)
+ roots = set(roots)
+ heads = list(heads)
+ try:
+ return repo.changelog.reachableroots(minroot, heads, roots, includepath)
+ except AttributeError:
+ return reachablerootspure(repo, minroot, roots, heads, includepath)
+
elements = {
# token-type: binding-strength, primary, prefix, infix, suffix
"(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None),
@@ -178,6 +204,21 @@
if symletters is None:
symletters = _symletters
+ if program and lookup:
+ # attempt to parse old-style ranges first to deal with
+ # things like old-tag which contain query metacharacters
+ parts = program.split(':', 1)
+ if all(lookup(sym) for sym in parts if sym):
+ if parts[0]:
+ yield ('symbol', parts[0], 0)
+ if len(parts) > 1:
+ s = len(parts[0])
+ yield (':', None, s)
+ if parts[1]:
+ yield ('symbol', parts[1], s + 1)
+ yield ('end', None, len(program))
+ return
+
pos, l = 0, len(program)
while pos < l:
c = program[pos]
@@ -382,7 +423,8 @@
def dagrange(repo, subset, x, y):
r = fullreposet(repo)
- xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
+ xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
+ includepath=True)
# XXX We should combine with subset first: 'subset & baseset(...)'. This is
# necessary to ensure we preserve the order in subset.
return xs & subset
@@ -391,8 +433,13 @@
return getset(repo, getset(repo, subset, x), y)
def orset(repo, subset, *xs):
- rs = [getset(repo, subset, x) for x in xs]
- return _combinesets(rs)
+ assert xs
+ if len(xs) == 1:
+ return getset(repo, subset, xs[0])
+ p = len(xs) // 2
+ a = orset(repo, subset, *xs[:p])
+ b = orset(repo, subset, *xs[p:])
+ return a + b
def notset(repo, subset, x):
return subset - getset(repo, subset, x)
@@ -1415,8 +1462,10 @@
default push location.
"""
# Avoid cycles.
- import discovery
- import hg
+ from . import (
+ discovery,
+ hg,
+ )
# i18n: "outgoing" is a keyword
l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
# i18n: "outgoing" is a keyword
@@ -1597,7 +1646,7 @@
synonym for the current local branch.
"""
- import hg # avoid start-up nasties
+ from . import hg # avoid start-up nasties
# i18n: "remote" is a keyword
l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
@@ -2654,6 +2703,27 @@
if repo:
lookup = repo.__contains__
tree = parse(spec, lookup)
+ return _makematcher(ui, tree, repo)
+
+def matchany(ui, specs, repo=None):
+ """Create a matcher that will include any revisions matching one of the
+ given specs"""
+ if not specs:
+ def mfunc(repo, subset=None):
+ return baseset()
+ return mfunc
+ if not all(specs):
+ raise error.ParseError(_("empty query"))
+ lookup = None
+ if repo:
+ lookup = repo.__contains__
+ if len(specs) == 1:
+ tree = parse(specs[0], lookup)
+ else:
+ tree = ('or',) + tuple(parse(s, lookup) for s in specs)
+ return _makematcher(ui, tree, repo)
+
+def _makematcher(ui, tree, repo):
if ui:
tree = findaliases(ui, tree, showwarning=ui.warn)
tree = foldconcat(tree)
@@ -3073,20 +3143,6 @@
def __repr__(self):
return '<%s %r>' % (type(self).__name__, self._subset)
-# this function will be removed, or merged to addset or orset, when
-# - scmutil.revrange() can be rewritten to not combine calculated smartsets
-# - or addset can handle more than two sets without balanced tree
-def _combinesets(subsets):
- """Create balanced tree of addsets representing union of given sets"""
- if not subsets:
- return baseset()
- if len(subsets) == 1:
- return subsets[0]
- p = len(subsets) // 2
- xs = _combinesets(subsets[:p])
- ys = _combinesets(subsets[p:])
- return addset(xs, ys)
-
def _iterordered(ascending, iter1, iter2):
"""produce an ordered iteration from two iterators with the same order
--- a/mercurial/scmutil.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/scmutil.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,7 +6,7 @@
# GNU General Public License version 2 or any later version.
from i18n import _
-from mercurial.node import nullrev, wdirrev
+from mercurial.node import wdirrev
import util, error, osutil, revset, similar, encoding, phases
import pathutil
import match as matchmod
@@ -690,6 +690,11 @@
raise util.Abort(_('empty revision set'))
return repo[l.last()]
+def _pairspec(revspec):
+ tree = revset.parse(revspec)
+ tree = revset.optimize(tree, True)[1] # fix up "x^:y" -> "(x^):y"
+ return tree and tree[0] in ('range', 'rangepre', 'rangepost', 'rangeall')
+
def revpair(repo, revs):
if not revs:
return repo.dirstate.p1(), None
@@ -711,67 +716,21 @@
if first is None:
raise util.Abort(_('empty revision range'))
- if first == second and len(revs) == 1 and _revrangesep not in revs[0]:
+ # if top-level is range expression, the result must always be a pair
+ if first == second and len(revs) == 1 and not _pairspec(revs[0]):
return repo.lookup(first), None
return repo.lookup(first), repo.lookup(second)
-_revrangesep = ':'
-
def revrange(repo, revs):
"""Yield revision as strings from a list of revision specifications."""
-
- def revfix(repo, val, defval):
- if not val and val != 0 and defval is not None:
- return defval
- return repo[val].rev()
-
- subsets = []
-
- revsetaliases = [alias for (alias, _) in
- repo.ui.configitems("revsetalias")]
-
+ allspecs = []
for spec in revs:
- # attempt to parse old-style ranges first to deal with
- # things like old-tag which contain query metacharacters
- try:
- # ... except for revset aliases without arguments. These
- # should be parsed as soon as possible, because they might
- # clash with a hash prefix.
- if spec in revsetaliases:
- raise error.RepoLookupError
-
- if isinstance(spec, int):
- subsets.append(revset.baseset([spec]))
- continue
-
- if _revrangesep in spec:
- start, end = spec.split(_revrangesep, 1)
- if start in revsetaliases or end in revsetaliases:
- raise error.RepoLookupError
-
- start = revfix(repo, start, 0)
- end = revfix(repo, end, len(repo) - 1)
- if end == nullrev and start < 0:
- start = nullrev
- if start < end:
- l = revset.spanset(repo, start, end + 1)
- else:
- l = revset.spanset(repo, start, end - 1)
- subsets.append(l)
- continue
- elif spec and spec in repo: # single unquoted rev
- rev = revfix(repo, spec, None)
- subsets.append(revset.baseset([rev]))
- continue
- except error.RepoLookupError:
- pass
-
- # fall through to new-style queries if old-style fails
- m = revset.match(repo.ui, spec, repo)
- subsets.append(m(repo))
-
- return revset._combinesets(subsets)
+ if isinstance(spec, int):
+ spec = revset.formatspec('rev(%d)', spec)
+ allspecs.append(spec)
+ m = revset.matchany(repo.ui, allspecs, repo)
+ return m(repo)
def expandpats(pats):
'''Expand bare globs when running on windows.
--- a/mercurial/setdiscovery.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/setdiscovery.py Tue Aug 18 18:38:56 2015 -0500
@@ -40,11 +40,20 @@
classified with it (since all ancestors or descendants will be marked as well).
"""
+from __future__ import absolute_import
+
import collections
-from node import nullid, nullrev
-from i18n import _
import random
-import util, dagutil
+
+from .i18n import _
+from .node import (
+ nullid,
+ nullrev,
+)
+from . import (
+ dagutil,
+ util,
+)
def _updatesample(dag, nodes, sample, quicksamplesize=0):
"""update an existing sample to match the expected size
@@ -138,22 +147,12 @@
sample = _limitsample(ownheads, initialsamplesize)
# indices between sample and externalized version must match
sample = list(sample)
- if remote.local():
- # stopgap until we have a proper localpeer that supports batch()
- srvheadhashes = remote.heads()
- yesno = remote.known(dag.externalizeall(sample))
- elif remote.capable('batch'):
- batch = remote.batch()
- srvheadhashesref = batch.heads()
- yesnoref = batch.known(dag.externalizeall(sample))
- batch.submit()
- srvheadhashes = srvheadhashesref.value
- yesno = yesnoref.value
- else:
- # compatibility with pre-batch, but post-known remotes during 1.9
- # development
- srvheadhashes = remote.heads()
- sample = []
+ batch = remote.batch()
+ srvheadhashesref = batch.heads()
+ yesnoref = batch.known(dag.externalizeall(sample))
+ batch.submit()
+ srvheadhashes = srvheadhashesref.value
+ yesno = yesnoref.value
if cl.tip() == nullid:
if srvheadhashes != [nullid]:
--- a/mercurial/simplemerge.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/simplemerge.py Tue Aug 18 18:38:56 2015 -0500
@@ -16,9 +16,17 @@
# mbp: "you know that thing where cvs gives you conflict markers?"
# s: "i hate that."
-from i18n import _
-import scmutil, util, mdiff
-import sys, os
+from __future__ import absolute_import
+
+import os
+import sys
+
+from .i18n import _
+from . import (
+ mdiff,
+ scmutil,
+ util,
+)
class CantReprocessAndShowBase(Exception):
pass
--- a/mercurial/sshpeer.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/sshpeer.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,16 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import re
-from i18n import _
-import util, error, wireproto
+
+from .i18n import _
+from . import (
+ error,
+ util,
+ wireproto,
+)
class remotelock(object):
def __init__(self, repo):
--- a/mercurial/sshserver.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/sshserver.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,8 +6,16 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import util, hook, wireproto
-import os, sys
+from __future__ import absolute_import
+
+import os
+import sys
+
+from . import (
+ hook,
+ util,
+ wireproto,
+)
class sshserver(wireproto.abstractserverproto):
def __init__(self, ui, repo):
--- a/mercurial/sslutil.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/sslutil.py Tue Aug 18 18:38:56 2015 -0500
@@ -6,10 +6,15 @@
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import os, sys, ssl
+
+from __future__ import absolute_import
-from mercurial import util
-from mercurial.i18n import _
+import os
+import ssl
+import sys
+
+from .i18n import _
+from . import util
_canloaddefaultcerts = False
try:
--- a/mercurial/statichttprepo.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/statichttprepo.py Tue Aug 18 18:38:56 2015 -0500
@@ -7,10 +7,26 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import changelog, byterange, url, error, namespaces
-import localrepo, manifest, util, scmutil, store
-import urllib, urllib2, errno, os
+from __future__ import absolute_import
+
+import errno
+import os
+import urllib
+import urllib2
+
+from .i18n import _
+from . import (
+ byterange,
+ changelog,
+ error,
+ localrepo,
+ manifest,
+ namespaces,
+ scmutil,
+ store,
+ url,
+ util,
+)
class httprangereader(object):
def __init__(self, url, opener):
--- a/mercurial/strutil.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/strutil.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,6 +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.
+from __future__ import absolute_import
+
def findall(haystack, needle, start=0, end=None):
if end is None:
end = len(haystack)
--- a/mercurial/subrepo.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/subrepo.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,15 +5,34 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import copy
-import errno, os, re, posixpath, sys
+import errno
+import os
+import posixpath
+import re
+import stat
+import subprocess
+import sys
+import tarfile
import xml.dom.minidom
-import stat, subprocess, tarfile
-from i18n import _
-import config, util, node, error, cmdutil, scmutil, match as matchmod
-import phases
-import pathutil
-import exchange
+
+
+from .i18n import _
+from . import (
+ cmdutil,
+ config,
+ error,
+ exchange,
+ match as matchmod,
+ node,
+ pathutil,
+ phases,
+ scmutil,
+ util,
+)
+
hg = None
propertycache = util.propertycache
@@ -328,7 +347,7 @@
# so we manually delay the circular imports to not break
# scripts that don't use our demand-loading
global hg
- import hg as h
+ from . import hg as h
hg = h
pathutil.pathauditor(ctx.repo().root)(path)
@@ -346,7 +365,7 @@
# so we manually delay the circular imports to not break
# scripts that don't use our demand-loading
global hg
- import hg as h
+ from . import hg as h
hg = h
pathutil.pathauditor(ctx.repo().root)(path)
--- a/mercurial/tagmerge.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/tagmerge.py Tue Aug 18 18:38:56 2015 -0500
@@ -71,11 +71,20 @@
# - put blocks whose nodes come all from p2 first
# - write the tag blocks in the sorted order
-import tags as tagsmod
-import util
-from node import nullid, hex
-from i18n import _
+from __future__ import absolute_import
+
import operator
+
+from .i18n import _
+from .node import (
+ hex,
+ nullid,
+)
+from .import (
+ tags as tagsmod,
+ util,
+)
+
hexnullid = hex(nullid)
def readtagsformerge(ui, repo, lines, fn='', keeplinenums=False):
--- a/mercurial/tags.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/tags.py Tue Aug 18 18:38:56 2015 -0500
@@ -10,15 +10,27 @@
# Eventually, it could take care of updating (adding/removing/moving)
# tags too.
-from node import nullid, bin, hex, short
-from i18n import _
-import util
-import encoding
-import error
-from array import array
+from __future__ import absolute_import
+
+import array
import errno
import time
+from .i18n import _
+from .node import (
+ bin,
+ hex,
+ nullid,
+ short,
+)
+from . import (
+ encoding,
+ error,
+ util,
+)
+
+array = array.array
+
# Tags computation can be expensive and caches exist to make it fast in
# the common case.
#
@@ -263,7 +275,7 @@
If the cache is not up to date, the caller is responsible for reading tag
info from each returned head. (See findglobaltags().)
'''
- import scmutil # avoid cycle
+ from . import scmutil # avoid cycle
try:
cachefile = repo.vfs(_filename(repo), 'r')
--- a/mercurial/templatefilters.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/templatefilters.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,10 +5,21 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import cgi, re, os, time, urllib
-import encoding, node, util
-import hbisect
-import templatekw
+from __future__ import absolute_import
+
+import cgi
+import os
+import re
+import time
+import urllib
+
+from . import (
+ encoding,
+ hbisect,
+ node,
+ templatekw,
+ util,
+)
def addbreaks(text):
""":addbreaks: Any text. Add an XHTML "<br />" tag before the end of
--- a/mercurial/templatekw.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/templatekw.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,16 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import hex
-import patch, scmutil, util, error
-import hbisect
+from __future__ import absolute_import
+
+from .node import hex
+from . import (
+ error,
+ hbisect,
+ patch,
+ scmutil,
+ util,
+)
# This helper class allows us to handle both:
# "{files}" (legacy command-line-specific list hack) and
--- a/mercurial/templater.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/templater.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,12 +5,23 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import os, re
-import util, config, templatefilters, templatekw, parser, error
-import revset as revsetmod
+from __future__ import absolute_import
+
+import os
+import re
import types
-import minirst
+
+from .i18n import _
+from . import (
+ config,
+ error,
+ minirst,
+ parser,
+ revset as revsetmod,
+ templatefilters,
+ templatekw,
+ util,
+)
# template parsing
--- a/mercurial/templates/monoblue/footer.tmpl Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/templates/monoblue/footer.tmpl Tue Aug 18 18:38:56 2015 -0500
@@ -12,11 +12,6 @@
<p><a href="{logourl}" title="Mercurial"><img src="{staticurl|urlescape}{logoimg}" width=75 height=90 border=0 alt="mercurial" /></a></p>
</div>
- <div id="corner-top-left"></div>
- <div id="corner-top-right"></div>
- <div id="corner-bottom-left"></div>
- <div id="corner-bottom-right"></div>
-
</div>
</body>
--- a/mercurial/templates/monoblue/index.tmpl Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/templates/monoblue/index.tmpl Tue Aug 18 18:38:56 2015 -0500
@@ -29,11 +29,6 @@
<p><a href="{logourl}" title="Mercurial"><img src="{staticurl|urlescape}{logoimg}" width=75 height=90 border=0 alt="mercurial"></a></p>
</div>
- <div id="corner-top-left"></div>
- <div id="corner-top-right"></div>
- <div id="corner-bottom-left"></div>
- <div id="corner-bottom-right"></div>
-
</div>
<script type="text/javascript">process_dates()</script>
</body>
--- a/mercurial/templates/static/style-monoblue.css Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/templates/static/style-monoblue.css Tue Aug 18 18:38:56 2015 -0500
@@ -263,7 +263,6 @@
td.source {
white-space: pre;
- font-family: monospace;
margin: 10px 30px 0;
font-size: 1.2em;
font-family: monospace;
@@ -311,44 +310,6 @@
div#powered-by a:hover {
text-decoration: underline;
}
-/*
-div#monoblue-corner-top-left {
- position: absolute;
- top: 0;
- left: 0;
- width: 10px;
- height: 10px;
- background: url(./monoblue-corner.png) top left no-repeat !important;
- background: none;
-}
-div#monoblue-corner-top-right {
- position: absolute;
- top: 0;
- right: 0;
- width: 10px;
- height: 10px;
- background: url(./monoblue-corner.png) top right no-repeat !important;
- background: none;
-}
-div#monoblue-corner-bottom-left {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 10px;
- height: 10px;
- background: url(./monoblue-corner.png) bottom left no-repeat !important;
- background: none;
-}
-div#monoblue-corner-bottom-right {
- position: absolute;
- bottom: 0;
- right: 0;
- width: 10px;
- height: 10px;
- background: url(./monoblue-corner.png) bottom right no-repeat !important;
- background: none;
-}
-*/
/** end of common settings **/
/** summary **/
--- a/mercurial/transaction.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/transaction.py Tue Aug 18 18:38:56 2015 -0500
@@ -11,9 +11,15 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
+from __future__ import absolute_import
+
import errno
-import error, util
+
+from .i18n import _
+from . import (
+ error,
+ util,
+)
version = 2
--- a/mercurial/treediscovery.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/treediscovery.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,10 +5,19 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
import collections
-from node import nullid, short
-from i18n import _
-import util, error
+
+from .i18n import _
+from .node import (
+ nullid,
+ short,
+)
+from . import (
+ error,
+ util,
+)
def findcommonincoming(repo, remote, heads=None, force=False):
"""Return a tuple (common, fetch, heads) used to identify the common
--- a/mercurial/ui.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/ui.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,11 +5,28 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from __future__ import absolute_import
+
+import errno
+import getpass
import inspect
-from i18n import _
-import errno, getpass, os, socket, sys, tempfile, traceback
-import config, scmutil, util, error, formatter, progress
-from node import hex
+import os
+import socket
+import sys
+import tempfile
+import traceback
+
+from .i18n import _
+from .node import hex
+
+from . import (
+ config,
+ error,
+ formatter,
+ progress,
+ scmutil,
+ util,
+)
samplehgrcs = {
'user':
--- a/mercurial/unionrepo.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/unionrepo.py Tue Aug 18 18:38:56 2015 -0500
@@ -11,11 +11,25 @@
allowing operations like diff and log with revsets.
"""
-from node import nullid
-from i18n import _
+from __future__ import absolute_import
+
import os
-import util, mdiff, cmdutil, scmutil
-import localrepo, changelog, manifest, filelog, revlog, pathutil
+
+from .i18n import _
+from .node import nullid
+
+from . import (
+ changelog,
+ cmdutil,
+ filelog,
+ localrepo,
+ manifest,
+ mdiff,
+ pathutil,
+ revlog,
+ scmutil,
+ util,
+)
class unionrevlog(revlog.revlog):
def __init__(self, opener, indexfile, revlog2, linkmapper):
--- a/mercurial/url.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/url.py Tue Aug 18 18:38:56 2015 -0500
@@ -7,10 +7,23 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import urllib, urllib2, httplib, os, socket, cStringIO, base64
-from i18n import _
-import keepalive, util, sslutil
-import httpconnection as httpconnectionmod
+from __future__ import absolute_import
+
+import base64
+import cStringIO
+import httplib
+import os
+import socket
+import urllib
+import urllib2
+
+from .i18n import _
+from . import (
+ httpconnection as httpconnectionmod,
+ keepalive,
+ sslutil,
+ util,
+)
class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
def __init__(self, ui):
--- a/mercurial/verify.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/verify.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,10 +5,21 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import nullid, short
-from i18n import _
+from __future__ import absolute_import
+
import os
-import revlog, util, error
+
+from .i18n import _
+from .node import (
+ nullid,
+ short,
+)
+
+from . import (
+ error,
+ revlog,
+ util,
+)
def verify(repo):
lock = repo.lock()
--- a/mercurial/win32.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/win32.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,7 +5,14 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import ctypes, errno, msvcrt, os, subprocess, random
+from __future__ import absolute_import
+
+import ctypes
+import errno
+import msvcrt
+import os
+import random
+import subprocess
_kernel32 = ctypes.windll.kernel32
_advapi32 = ctypes.windll.advapi32
--- a/mercurial/wireproto.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/wireproto.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,12 +5,29 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import urllib, tempfile, os, sys
-from i18n import _
-from node import bin, hex
-import changegroup as changegroupmod, bundle2, pushkey as pushkeymod
-import peer, error, encoding, util, exchange
+from __future__ import absolute_import
+
+import os
+import sys
+import tempfile
+import urllib
+from .i18n import _
+from .node import (
+ bin,
+ hex,
+)
+
+from . import (
+ bundle2,
+ changegroup as changegroupmod,
+ encoding,
+ error,
+ exchange,
+ peer,
+ pushkey as pushkeymod,
+ util,
+)
class abstractserverproto(object):
"""abstract class that summarizes the protocol API
@@ -58,48 +75,12 @@
Some protocols may have compressed the contents."""
raise NotImplementedError()
-# abstract batching support
-
-class future(object):
- '''placeholder for a value to be set later'''
- def set(self, value):
- if util.safehasattr(self, 'value'):
- raise error.RepoError("future is already set")
- self.value = value
-
-class batcher(object):
- '''base class for batches of commands submittable in a single request
-
- All methods invoked on instances of this class are simply queued and
- return a a future for the result. Once you call submit(), all the queued
- calls are performed and the results set in their respective futures.
- '''
- def __init__(self):
- self.calls = []
- def __getattr__(self, name):
- def call(*args, **opts):
- resref = future()
- self.calls.append((name, args, opts, resref,))
- return resref
- return call
- def submit(self):
- pass
-
-class localbatch(batcher):
- '''performs the queued calls directly'''
- def __init__(self, local):
- batcher.__init__(self)
- self.local = local
- def submit(self):
- for name, args, opts, resref in self.calls:
- resref.set(getattr(self.local, name)(*args, **opts))
-
-class remotebatch(batcher):
+class remotebatch(peer.batcher):
'''batches the queued calls; uses as few roundtrips as possible'''
def __init__(self, remote):
'''remote must support _submitbatch(encbatch) and
_submitone(op, encargs)'''
- batcher.__init__(self)
+ peer.batcher.__init__(self)
self.remote = remote
def submit(self):
req, rsp = [], []
@@ -128,41 +109,10 @@
encresref.set(encres)
resref.set(batchable.next())
-def batchable(f):
- '''annotation for batchable methods
-
- Such methods must implement a coroutine as follows:
-
- @batchable
- def sample(self, one, two=None):
- # Handle locally computable results first:
- if not one:
- yield "a local result", None
- # Build list of encoded arguments suitable for your wire protocol:
- encargs = [('one', encode(one),), ('two', encode(two),)]
- # Create future for injection of encoded result:
- encresref = future()
- # Return encoded arguments and future:
- yield encargs, encresref
- # Assuming the future to be filled with the result from the batched
- # request now. Decode it:
- yield decode(encresref.value)
-
- The decorator returns a function which wraps this coroutine as a plain
- method, but adds the original method as an attribute called "batchable",
- which is used by remotebatch to split the call into separate encoding and
- decoding phases.
- '''
- def plain(*args, **opts):
- batchable = f(*args, **opts)
- encargsorres, encresref = batchable.next()
- if not encresref:
- return encargsorres # a local result in this case
- self = args[0]
- encresref.set(self._submitone(f.func_name, encargsorres))
- return batchable.next()
- setattr(plain, 'batchable', f)
- return plain
+# Forward a couple of names from peer to make wireproto interactions
+# slightly more sensible.
+batchable = peer.batchable
+future = peer.future
# list of nodes encoding / decoding
@@ -216,7 +166,10 @@
class wirepeer(peer.peerrepository):
def batch(self):
- return remotebatch(self)
+ if self.capable('batch'):
+ return remotebatch(self)
+ else:
+ return peer.localbatch(self)
def _submitbatch(self, req):
cmds = []
for op, argsdict in req:
--- a/mercurial/worker.py Tue Aug 18 18:37:50 2015 -0500
+++ b/mercurial/worker.py Tue Aug 18 18:38:56 2015 -0500
@@ -5,9 +5,16 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from i18n import _
-import errno, os, signal, sys, threading
-import util
+from __future__ import absolute_import
+
+import errno
+import os
+import signal
+import sys
+import threading
+
+from .i18n import _
+from . import util
def countcpus():
'''try to count the number of CPUs on the system'''
--- a/tests/filterpyflakes.py Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/filterpyflakes.py Tue Aug 18 18:38:56 2015 -0500
@@ -2,7 +2,7 @@
# Filter output by pyflakes to control which warnings we check
-import sys, re, os
+import sys, re
def makekey(typeandline):
"""
@@ -42,7 +42,7 @@
else:
continue # no pattern matched, next line
fn = line.split(':', 1)[0]
- f = open(os.path.join(os.path.dirname(os.path.dirname(__file__)), fn))
+ f = open(fn)
data = f.read()
f.close()
if 'no-' 'check-code' in data:
--- a/tests/test-batching.py Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-batching.py Tue Aug 18 18:38:56 2015 -0500
@@ -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.
-from mercurial.wireproto import localbatch, remotebatch, batchable, future
+from mercurial.peer import localbatch, batchable, future
+from mercurial.wireproto import remotebatch
# equivalent of repo.repository
class thing(object):
--- a/tests/test-bookmarks.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-bookmarks.t Tue Aug 18 18:38:56 2015 -0500
@@ -511,10 +511,10 @@
test clone with update to a bookmark
- $ hg clone -u Z . cloned-bookmarks-update
+ $ hg clone -u Z . ../cloned-bookmarks-update
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
- $ hg -R cloned-bookmarks-update bookmarks
+ $ hg -R ../cloned-bookmarks-update bookmarks
X2 1:925d80f479bb
Y 2:db815d6d32e6
* Z 2:db815d6d32e6
@@ -569,10 +569,10 @@
$ hg bookmark -r3 Y
moving bookmark 'Y' forward from db815d6d32e6
- $ hg -R cloned-bookmarks-update update Y
+ $ hg -R ../cloned-bookmarks-update update Y
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
(activating bookmark Y)
- $ hg -R cloned-bookmarks-update pull --update .
+ $ hg -R ../cloned-bookmarks-update pull --update .
pulling from .
searching for changes
adding changesets
--- a/tests/test-completion.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-completion.t Tue Aug 18 18:38:56 2015 -0500
@@ -254,7 +254,7 @@
debugpathcomplete: full, normal, added, removed
debugpushkey:
debugpvec:
- debugrebuilddirstate: rev
+ debugrebuilddirstate: rev, minimal
debugrebuildfncache:
debugrename: rev
debugrevlog: changelog, manifest, dir, dump
--- a/tests/test-convert-filemap.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-convert-filemap.t Tue Aug 18 18:38:56 2015 -0500
@@ -671,3 +671,61 @@
|/
o 0:c334dc3be0da@default "add" files: a
+ $ cd ..
+
+test converting merges into a repo that contains other files
+
+ $ hg init merge-test1
+ $ cd merge-test1
+ $ touch a && hg commit -Aqm a
+ $ hg up -q null
+ $ touch b && hg commit -Aqm b
+ $ hg merge -q 0 && hg commit -qm merge
+ $ cd ..
+ $ hg init merge-test2
+ $ cd merge-test2
+ $ mkdir converted
+ $ touch converted/a && hg commit -Aqm 'a'
+ $ touch x && hg commit -Aqm 'x'
+ $ cd ..
+ $ hg log -G -T '{node}' -R merge-test1
+ @ ea7c1a7ae9588677a715ce4f204cd89c28d5471f
+ |\
+ | o d7486e00c6f1b633dcadc0582f78006d805c7a0f
+ |
+ o 3903775176ed42b1458a6281db4a0ccf4d9f287a
+
+ $ hg log -G -T '{node}' -R merge-test2
+ @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
+ |
+ o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
+
+- Build a shamap where the target converted/a is in on top of an unrelated
+- change to 'x'. This simulates using convert to merge several repositories
+- together.
+ $ cat >> merge-test2/.hg/shamap <<EOF
+ > 3903775176ed42b1458a6281db4a0ccf4d9f287a 34f1aa7da42559bae87920880b522d47b3ddbc0d
+ > EOF
+ $ cat >> merge-test-filemap <<EOF
+ > rename . converted/
+ > EOF
+ $ hg convert --filemap merge-test-filemap merge-test1 merge-test2 --traceback
+ scanning source...
+ sorting...
+ converting...
+ 1 b
+ 0 merge
+ $ hg -R merge-test2 manifest -r tip
+ converted/a
+ converted/b
+ x
+ $ hg -R merge-test2 log -G -T '{node}\n{files % "{file}\n"}'
+ o 4b5e2f0218d3442a0c14892b18685bf9c8059c4a
+ |\
+ | o 214325dd2e4cff981dcf00cb120cd39e1ea36dcc
+ | converted/b
+ @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
+ | x
+ o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
+ converted/a
+
--- a/tests/test-convert-git.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-convert-git.t Tue Aug 18 18:38:56 2015 -0500
@@ -678,6 +678,28 @@
master 0:03bf38caa4c6
origin/master 0:03bf38caa4c6
+Run convert when the remote branches have changed
+(there was an old bug where the local convert read branches from the server)
+
+ $ cd git-repo7
+ $ echo a >> a
+ $ git commit -am "move master forward"
+ [master 0c81947] move master forward
+ Author: nottest <test@example.org>
+ 1 file changed, 1 insertion(+)
+ $ cd ..
+ $ rm -rf hg-repo7
+ $ hg convert --config convert.git.remoteprefix=origin git-repo7-client hg-repo7
+ initializing destination hg-repo7 repository
+ scanning source...
+ sorting...
+ converting...
+ 0 commit a
+ updating bookmarks
+ $ hg -R hg-repo7 bookmarks
+ master 0:03bf38caa4c6
+ origin/master 0:03bf38caa4c6
+
damaged git repository tests:
In case the hard-coded hashes change, the following commands can be used to
list the hashes and their corresponding types in the repository:
--- a/tests/test-copy-move-merge.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-copy-move-merge.t Tue Aug 18 18:38:56 2015 -0500
@@ -59,4 +59,107 @@
1
2
+Test disabling copy tracing
+
+- first verify copy metadata was kept
+
+ $ hg up -qC 2
+ $ hg rebase --keep -d 1 -b 2 --config extensions.rebase=
+ rebasing 2:add3f11052fa "other" (tip)
+ merging b and a to b
+ merging c and a to c
+
+ $ cat b
+ 0
+ 1
+ 2
+
+- next verify copy metadata is lost when disabled
+
+ $ hg strip -r . --config extensions.strip=
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/t/.hg/strip-backup/550bd84c0cd3-fc575957-backup.hg (glob)
+ $ hg up -qC 2
+ $ hg rebase --keep -d 1 -b 2 --config extensions.rebase= --config experimental.disablecopytrace=True
+ rebasing 2:add3f11052fa "other" (tip)
+ remote changed a which local deleted
+ use (c)hanged version or leave (d)eleted? c
+
+ $ cat b
+ 1
+ 2
+
$ cd ..
+
+Verify disabling copy tracing still keeps copies from rebase source
+
+ $ hg init copydisable
+ $ cd copydisable
+ $ touch a
+ $ hg ci -Aqm 'add a'
+ $ touch b
+ $ hg ci -Aqm 'add b, c'
+ $ hg cp b x
+ $ echo x >> x
+ $ hg ci -qm 'copy b->x'
+ $ hg up -q 1
+ $ touch z
+ $ hg ci -Aqm 'add z'
+ $ hg log -G -T '{rev} {desc}\n'
+ @ 3 add z
+ |
+ | o 2 copy b->x
+ |/
+ o 1 add b, c
+ |
+ o 0 add a
+
+ $ hg rebase -d . -b 2 --config extensions.rebase= --config experimental.disablecopytrace=True
+ rebasing 2:6adcf8c12e7d "copy b->x"
+ saved backup bundle to $TESTTMP/copydisable/.hg/strip-backup/6adcf8c12e7d-ce4b3e75-backup.hg (glob)
+ $ hg up -q 3
+ $ hg log -f x -T '{rev} {desc}\n'
+ 3 copy b->x
+ 1 add b, c
+
+ $ cd ../
+
+Verify we duplicate existing copies, instead of detecting them
+
+ $ hg init copydisable3
+ $ cd copydisable3
+ $ touch a
+ $ hg ci -Aqm 'add a'
+ $ hg cp a b
+ $ hg ci -Aqm 'copy a->b'
+ $ hg mv b c
+ $ hg ci -Aqm 'move b->c'
+ $ hg up -q 0
+ $ hg cp a b
+ $ echo b >> b
+ $ hg ci -Aqm 'copy a->b (2)'
+ $ hg log -G -T '{rev} {desc}\n'
+ @ 3 copy a->b (2)
+ |
+ | o 2 move b->c
+ | |
+ | o 1 copy a->b
+ |/
+ o 0 add a
+
+ $ hg rebase -d 2 -s 3 --config extensions.rebase= --config experimental.disablecopytrace=True
+ rebasing 3:47e1a9e6273b "copy a->b (2)" (tip)
+ saved backup bundle to $TESTTMP/copydisable3/.hg/strip-backup/47e1a9e6273b-2d099c59-backup.hg (glob)
+
+ $ hg log -G -f b
+ @ changeset: 3:76024fb4b05b
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: copy a->b (2)
+ |
+ o changeset: 0:ac82d8b1f7c4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
--- a/tests/test-diff-change.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-diff-change.t Tue Aug 18 18:38:56 2015 -0500
@@ -29,15 +29,59 @@
-first
+second
-Test dumb revspecs (issue3474)
+ $ cd ..
+
+Test dumb revspecs: top-level "x:y", "x:", ":y" and ":" ranges should be handled
+as pairs even if x == y, but not for "f(x:y)" nor "x::y" (issue3474, issue4774)
+
+ $ hg clone -q a dumbspec
+ $ cd dumbspec
+ $ echo "wdir" > file.txt
$ hg diff -r 2:2
+ $ hg diff -r 2:.
+ $ hg diff -r 2:
+ $ hg diff -r :0
+ $ hg diff -r '2:first(2:2)'
+ $ hg diff -r 'first(2:2)' --nodates
+ diff -r bf5ff72eb7e0 file.txt
+ --- a/file.txt
+ +++ b/file.txt
+ @@ -1,1 +1,1 @@
+ -third
+ +wdir
+ $ hg diff -r 2::2 --nodates
+ diff -r bf5ff72eb7e0 file.txt
+ --- a/file.txt
+ +++ b/file.txt
+ @@ -1,1 +1,1 @@
+ -third
+ +wdir
$ hg diff -r "2 and 1"
abort: empty revision range
[255]
+ $ cd ..
+
+ $ hg clone -qr0 a dumbspec-rev0
+ $ cd dumbspec-rev0
+ $ echo "wdir" > file.txt
+
+ $ hg diff -r :
+ $ hg diff -r 'first(:)' --nodates
+ diff -r 4bb65dda5db4 file.txt
+ --- a/file.txt
+ +++ b/file.txt
+ @@ -1,1 +1,1 @@
+ -first
+ +wdir
+
+ $ cd ..
+
Testing diff --change when merge:
+ $ cd a
+
$ for i in 1 2 3 4 5 6 7 8 9 10; do
> echo $i >> file.txt
> done
--- a/tests/test-hgweb-descend-empties.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-hgweb-descend-empties.t Tue Aug 18 18:38:56 2015 -0500
@@ -373,11 +373,6 @@
<p><a href="http://mercurial.selenic.com/" title="Mercurial"><img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a></p>
</div>
- <div id="corner-top-left"></div>
- <div id="corner-top-right"></div>
- <div id="corner-bottom-left"></div>
- <div id="corner-bottom-right"></div>
-
</div>
</body>
--- a/tests/test-module-imports.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-module-imports.t Tue Aug 18 18:38:56 2015 -0500
@@ -112,22 +112,5 @@
these may expose other cycles.
$ hg locate 'mercurial/**.py' 'hgext/**.py' | sed 's-\\-/-g' | python "$import_checker" -
- mercurial/dispatch.py mixed imports
- stdlib: commands
- relative: error, extensions, fancyopts, hg, hook, util
- mercurial/fileset.py mixed imports
- stdlib: parser
- relative: error, merge, util
- mercurial/revset.py mixed imports
- stdlib: parser
- relative: error, hbisect, phases, util
- mercurial/templater.py mixed imports
- stdlib: parser
- relative: config, error, templatefilters, templatekw, util
- mercurial/ui.py mixed imports
- stdlib: formatter
- relative: config, error, progress, scmutil, util
- Import cycle: mercurial.cmdutil -> mercurial.context -> mercurial.subrepo -> mercurial.cmdutil
Import cycle: hgext.largefiles.basestore -> hgext.largefiles.localstore -> hgext.largefiles.basestore
- Import cycle: mercurial.commands -> mercurial.commandserver -> mercurial.dispatch -> mercurial.commands
[1]
--- a/tests/test-parseindex.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-parseindex.t Tue Aug 18 18:38:56 2015 -0500
@@ -60,9 +60,41 @@
$ cd ..
-Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
+#if no-pure
+
+Test SEGV caused by bad revision passed to reachableroots() (issue4775):
+
+ $ cd a
-#if no-pure
+ $ python <<EOF
+ > from mercurial import changelog, scmutil
+ > cl = changelog.changelog(scmutil.vfs('.hg/store'))
+ > print 'goods:'
+ > for head in [0, len(cl) - 1, -1]:
+ > print'%s: %r' % (head, cl.reachableroots(0, [head], set([0])))
+ > print 'bads:'
+ > for head in [len(cl), 10000, -2, -10000, None]:
+ > print '%s:' % head,
+ > try:
+ > cl.reachableroots(0, [head], set([0]))
+ > print 'uncaught buffer overflow?'
+ > except (IndexError, TypeError) as inst:
+ > print inst
+ > EOF
+ goods:
+ 0: <baseset [0]>
+ 1: <baseset [0]>
+ -1: <baseset []>
+ bads:
+ 2: head out of range
+ 10000: head out of range
+ -2: head out of range
+ -10000: head out of range
+ None: an integer is required
+
+ $ cd ..
+
+Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
$ mkdir invalidparent
$ cd invalidparent
@@ -94,6 +126,8 @@
> cl = changelog.changelog(scmutil.vfs(sys.argv[1]))
> n0, n1 = cl.node(0), cl.node(1)
> ops = [
+ > ('reachableroots',
+ > lambda: cl.index.reachableroots(0, [1], set([0]), False)),
> ('compute_phases_map_sets', lambda: cl.computephases([[0], []])),
> ('index_headrevs', lambda: cl.headrevs()),
> ('find_gca_candidates', lambda: cl.commonancestorsheads(n0, n1)),
@@ -109,11 +143,13 @@
> EOF
$ python test.py limit/.hg/store
+ reachableroots: parent out of range
compute_phases_map_sets: parent out of range
index_headrevs: parent out of range
find_gca_candidates: parent out of range
find_deepest: parent out of range
$ python test.py segv/.hg/store
+ reachableroots: parent out of range
compute_phases_map_sets: parent out of range
index_headrevs: parent out of range
find_gca_candidates: parent out of range
--- a/tests/test-revset.t Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-revset.t Tue Aug 18 18:38:56 2015 -0500
@@ -197,11 +197,53 @@
<filteredset
<baseset [7]>>
7
- $ try -- '-a-b-c-' # complains
- hg: parse error at 7: not a prefix: end
- [255]
- $ log -a-b-c- # succeeds with fallback
+
+names that should be caught by fallback mechanism
+
+ $ try -- '-a-b-c-'
+ ('symbol', '-a-b-c-')
+ * set:
+ <baseset [4]>
+ 4
+ $ log -a-b-c-
+ 4
+ $ try '+a+b+c+'
+ ('symbol', '+a+b+c+')
+ * set:
+ <baseset [3]>
+ 3
+ $ try '+a+b+c+:'
+ (rangepost
+ ('symbol', '+a+b+c+'))
+ * set:
+ <spanset+ 3:9>
+ 3
4
+ 5
+ 6
+ 7
+ 8
+ 9
+ $ try ':+a+b+c+'
+ (rangepre
+ ('symbol', '+a+b+c+'))
+ * set:
+ <spanset+ 0:3>
+ 0
+ 1
+ 2
+ 3
+ $ try -- '-a-b-c-:+a+b+c+'
+ (range
+ ('symbol', '-a-b-c-')
+ ('symbol', '+a+b+c+'))
+ * set:
+ <spanset- 3:4>
+ 4
+ 3
+ $ log '-a-b-c-:+a+b+c+'
+ 4
+ 3
$ try -- -a-b-c--a # complains
(minus
@@ -1473,10 +1515,16 @@
(single rev)
$ hg diff -r 'tip^' -r 'tip^'
- $ hg diff -r 'tip^::tip^ or tip^'
+ $ hg diff -r 'tip^:tip^'
(single rev that does not looks like a range)
+ $ hg diff -r 'tip^::tip^ or tip^'
+ diff -r d5d0dcbdc4d9 .hgtags
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/.hgtags * (glob)
+ @@ -0,0 +1,1 @@
+ +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
$ hg diff -r 'tip^ or tip^'
diff -r d5d0dcbdc4d9 .hgtags
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
--- a/tests/test-wireproto.py Tue Aug 18 18:37:50 2015 -0500
+++ b/tests/test-wireproto.py Tue Aug 18 18:38:56 2015 -0500
@@ -12,6 +12,10 @@
class clientpeer(wireproto.wirepeer):
def __init__(self, serverrepo):
self.serverrepo = serverrepo
+
+ def _capabilities(self):
+ return ['batch']
+
def _call(self, cmd, **args):
return wireproto.dispatch(self.serverrepo, proto(args), cmd)