Mercurial > hg
changeset 26047:d9d3d49c4cf7
merge with stable
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Tue, 18 Aug 2015 18:38:56 -0500 |
parents | b3ad349d0e50 (diff) b930d4ef7739 (current diff) |
children | 0be2f81aadc3 |
files | tests/test-convert-git.t |
diffstat | 99 files changed, 1831 insertions(+), 608 deletions(-) [+] |
line wrap: on
line diff
--- 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)