Mercurial > hg-stable
changeset 32285:3a755652ce3a
merge with stable
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Fri, 12 May 2017 11:20:25 -0700 |
parents | 3de4c61b5087 (diff) 176ed32dc159 (current diff) |
children | 7e79373263ab |
files | hgext/win32mbcs.py mercurial/commands.py tests/hghave.py tests/test-graft.t tests/test-https.t |
diffstat | 86 files changed, 1007 insertions(+), 748 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Fri May 12 21:46:14 2017 +0900 +++ b/.hgignore Fri May 12 11:20:25 2017 -0700 @@ -54,14 +54,6 @@ locale/*/LC_MESSAGES/hg.mo hgext/__index__.py -# files installed with a local --pure build -mercurial/base85.py -mercurial/bdiff.py -mercurial/diffhelpers.py -mercurial/mpatch.py -mercurial/osutil.py -mercurial/parsers.py - # Generated wheels wheelhouse/
--- a/Makefile Fri May 12 21:46:14 2017 +0900 +++ b/Makefile Fri May 12 11:20:25 2017 -0700 @@ -64,7 +64,6 @@ -$(PYTHON) setup.py clean --all # ignore errors from this command find contrib doc hgext hgext3rd i18n mercurial tests \ \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';' - rm -f $(addprefix mercurial/,$(notdir $(wildcard mercurial/pure/[a-z]*.py))) rm -f MANIFEST MANIFEST.in hgext/__index__.py tests/*.err rm -f mercurial/__modulepolicy__.py if test -d .hg; then rm -f mercurial/__version__.py; fi
--- a/contrib/bdiff-torture.py Fri May 12 21:46:14 2017 +0900 +++ b/contrib/bdiff-torture.py Fri May 12 11:20:25 2017 -0700 @@ -5,8 +5,7 @@ import sys from mercurial import ( - bdiff, - mpatch, + mdiff, ) def reducetest(a, b): @@ -42,10 +41,10 @@ sys.exit(0) def test1(a, b): - d = bdiff.bdiff(a, b) + d = mdiff.textdiff(a, b) if not d: raise ValueError("empty") - c = mpatch.patches(a, [d]) + c = mdiff.patches(a, [d]) if c != b: raise ValueError("bad")
--- a/contrib/check-code.py Fri May 12 21:46:14 2017 +0900 +++ b/contrib/check-code.py Fri May 12 11:20:25 2017 -0700 @@ -474,7 +474,7 @@ py3pats = [ [ - (r'os\.environ', "use encoding.environ instead (py3)"), + (r'os\.environ', "use encoding.environ instead (py3)", r'#.*re-exports'), (r'os\.name', "use pycompat.osname instead (py3)"), (r'os\.getcwd', "use pycompat.getcwd instead (py3)"), (r'os\.sep', "use pycompat.ossep instead (py3)"), @@ -492,8 +492,8 @@ checks = [ ('python', r'.*\.(py|cgi)$', r'^#!.*python', pyfilters, pypats), ('python', r'.*hgext.*\.py$', '', [], pyextnfpats), - ('python 3', r'.*(hgext|mercurial).*(?<!pycompat)\.py', '', - pyfilters, py3pats), + ('python 3', r'.*(hgext|mercurial)/(?!demandimport|policy|pycompat).*\.py', + '', pyfilters, py3pats), ('test script', r'(.*/)?test-[^.~]*$', '', testfilters, testpats), ('c', r'.*\.[ch]$', '', cfilters, cpats), ('unified test', r'.*\.t$', '', utestfilters, utestpats),
--- a/contrib/check-py3-compat.py Fri May 12 21:46:14 2017 +0900 +++ b/contrib/check-py3-compat.py Fri May 12 11:20:25 2017 -0700 @@ -14,6 +14,16 @@ import sys import traceback +# Modules that have both Python and C implementations. +_dualmodules = ( + 'base85.py', + 'bdiff.py', + 'diffhelpers.py', + 'mpatch.py', + 'osutil.py', + 'parsers.py', +) + def check_compat_py2(f): """Check Python 3 compatibility for a file with Python 2""" with open(f, 'rb') as fh: @@ -55,7 +65,9 @@ # out module paths for things not in a package can be confusing. if f.startswith(('hgext/', 'mercurial/')) and not f.endswith('__init__.py'): assert f.endswith('.py') - name = f.replace('/', '.')[:-3].replace('.pure.', '.') + name = f.replace('/', '.')[:-3] + if f.endswith(_dualmodules): + name = name.replace('.pure.', '.') try: importlib.import_module(name) except Exception as e:
--- a/contrib/debian/control Fri May 12 21:46:14 2017 +0900 +++ b/contrib/debian/control Fri May 12 11:20:25 2017 -0700 @@ -12,7 +12,7 @@ unzip, zip Standards-Version: 3.9.4 -X-Python-Version: >= 2.6 +X-Python-Version: >= 2.7 Package: mercurial Depends:
--- a/contrib/import-checker.py Fri May 12 21:46:14 2017 +0900 +++ b/contrib/import-checker.py Fri May 12 11:20:25 2017 -0700 @@ -24,6 +24,16 @@ 'mercurial.node', ) +# Modules that have both Python and C implementations. +_dualmodules = ( + 'base85.py', + 'bdiff.py', + 'diffhelpers.py', + 'mpatch.py', + 'osutil.py', + 'parsers.py', +) + # Modules that must be aliased because they are commonly confused with # common variables and can create aliasing and readability issues. requirealias = { @@ -691,7 +701,8 @@ used_imports = {} any_errors = False for source_path in argv[1:]: - modname = dotted_name_of_path(source_path, trimpure=True) + trimpure = source_path.endswith(_dualmodules) + modname = dotted_name_of_path(source_path, trimpure=trimpure) localmods[modname] = source_path for localmodname, source_path in sorted(localmods.items()): for src, modname, name, line in sources(source_path, localmodname):
--- a/contrib/mercurial.spec Fri May 12 21:46:14 2017 +0900 +++ b/contrib/mercurial.spec Fri May 12 11:20:25 2017 -0700 @@ -37,8 +37,8 @@ %if "%{?withpython}" BuildRequires: readline-devel, openssl-devel, ncurses-devel, zlib-devel, bzip2-devel %else -BuildRequires: python >= 2.6, python-devel, python-docutils >= 0.5 -Requires: python >= 2.6 +BuildRequires: python >= 2.7, python-devel, python-docutils >= 0.5 +Requires: python >= 2.7 %endif # The hgk extension uses the wish tcl interpreter, but we don't enforce it #Requires: tk
--- a/contrib/perf.py Fri May 12 21:46:14 2017 +0900 +++ b/contrib/perf.py Fri May 12 11:20:25 2017 -0700 @@ -26,7 +26,6 @@ import sys import time from mercurial import ( - bdiff, changegroup, cmdutil, commands, @@ -812,7 +811,7 @@ def d(): for pair in textpairs: - bdiff.bdiff(*pair) + mdiff.textdiff(*pair) timer, fm = gettimer(ui, opts) timer(d) @@ -851,23 +850,24 @@ The start revision can be defined via ``-s/--startrev``. """ - timer, fm = gettimer(ui, opts) - _len = getlen(ui) + rl = cmdutil.openrevlog(repo, 'perfrevlog', file_, opts) + rllen = getlen(ui)(rl) def d(): - r = cmdutil.openrevlog(repo, 'perfrevlog', file_, opts) + rl.clearcaches() - startrev = 0 - endrev = _len(r) + beginrev = startrev + endrev = rllen dist = opts['dist'] if reverse: - startrev, endrev = endrev, startrev + beginrev, endrev = endrev, beginrev dist = -1 * dist - for x in xrange(startrev, endrev, dist): - r.revision(r.node(x)) + for x in xrange(beginrev, endrev, dist): + rl.revision(x) + timer, fm = gettimer(ui, opts) timer(d) fm.end() @@ -889,6 +889,12 @@ """ rl = cmdutil.openrevlog(repo, 'perfrevlogchunks', file_, opts) + # _chunkraw was renamed to _getsegmentforrevs. + try: + segmentforrevs = rl._getsegmentforrevs + except AttributeError: + segmentforrevs = rl._chunkraw + # Verify engines argument. if engines: engines = set(e.strip() for e in engines.split(',')) @@ -919,22 +925,22 @@ def doread(): rl.clearcaches() for rev in revs: - rl._chunkraw(rev, rev) + segmentforrevs(rev, rev) def doreadcachedfh(): rl.clearcaches() fh = rlfh(rl) for rev in revs: - rl._chunkraw(rev, rev, df=fh) + segmentforrevs(rev, rev, df=fh) def doreadbatch(): rl.clearcaches() - rl._chunkraw(revs[0], revs[-1]) + segmentforrevs(revs[0], revs[-1]) def doreadbatchcachedfh(): rl.clearcaches() fh = rlfh(rl) - rl._chunkraw(revs[0], revs[-1], df=fh) + segmentforrevs(revs[0], revs[-1], df=fh) def dochunk(): rl.clearcaches() @@ -1003,6 +1009,13 @@ raise error.CommandError('perfrevlogrevision', 'invalid arguments') r = cmdutil.openrevlog(repo, 'perfrevlogrevision', file_, opts) + + # _chunkraw was renamed to _getsegmentforrevs. + try: + segmentforrevs = r._getsegmentforrevs + except AttributeError: + segmentforrevs = r._chunkraw + node = r.lookup(rev) rev = r.rev(node) @@ -1034,7 +1047,7 @@ def doread(chain): if not cache: r.clearcaches() - r._chunkraw(chain[0], chain[-1]) + segmentforrevs(chain[0], chain[-1]) def dorawchunks(data, chain): if not cache: @@ -1062,7 +1075,7 @@ r.revision(node) chain = r._deltachain(rev)[0] - data = r._chunkraw(chain[0], chain[-1])[1] + data = segmentforrevs(chain[0], chain[-1])[1] rawchunks = getrawchunks(data, chain) bins = r._chunks(chain) text = str(bins[0])
--- a/hgext/blackbox.py Fri May 12 21:46:14 2017 +0900 +++ b/hgext/blackbox.py Fri May 12 11:20:25 2017 -0700 @@ -173,7 +173,7 @@ ui._bbinlog = True date = util.datestr(None, '%Y/%m/%d %H:%M:%S') user = util.getuser() - pid = str(util.getpid()) + pid = '%d' % util.getpid() formattedmsg = msg[0] % msg[1:] rev = '(unknown)' changed = ''
--- a/hgext/extdiff.py Fri May 12 21:46:14 2017 +0900 +++ b/hgext/extdiff.py Fri May 12 11:20:25 2017 -0700 @@ -101,7 +101,7 @@ dirname = '%s.%s' % (dirname, short(node)) base = os.path.join(tmproot, dirname) os.mkdir(base) - fns_and_mtime = [] + fnsandstat = [] if node is not None: ui.note(_('making snapshot of %d files from rev %s\n') % @@ -124,9 +124,8 @@ if node is None: dest = os.path.join(base, wfn) - fns_and_mtime.append((dest, repo.wjoin(fn), - os.lstat(dest).st_mtime)) - return dirname, fns_and_mtime + fnsandstat.append((dest, repo.wjoin(fn), os.lstat(dest))) + return dirname, fnsandstat def dodiff(ui, repo, cmdline, pats, opts): '''Do the actual diff: @@ -199,7 +198,7 @@ dir1b = None rev1b = '' - fns_and_mtime = [] + fnsandstat = [] # If node2 in not the wc or there is >1 change, copy it dir2root = '' @@ -212,8 +211,8 @@ #the working dir in this case (because the other cases #are: diffing 2 revisions or single file -- in which case #the file is already directly passed to the diff tool). - dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot, - subrepos) + dir2, fnsandstat = snapshot(ui, repo, modadd, None, tmproot, + subrepos) else: # This lets the diff tool open the changed file directly dir2 = '' @@ -249,7 +248,7 @@ dir2 = repo.vfs.reljoin(tmproot, label2) dir1b = None label1b = None - fns_and_mtime = [] + fnsandstat = [] # Function to quote file/dir names in the argument string. # When not operating in 3-way mode, an empty string is @@ -275,8 +274,13 @@ ui.debug('running %r in %s\n' % (cmdline, tmproot)) ui.system(cmdline, cwd=tmproot, blockedtag='extdiff') - for copy_fn, working_fn, mtime in fns_and_mtime: - if os.lstat(copy_fn).st_mtime != mtime: + for copy_fn, working_fn, st in fnsandstat: + cpstat = os.lstat(copy_fn) + # Some tools copy the file and attributes, so mtime may not detect + # all changes. A size check will detect more cases, but not all. + # The only certain way to detect every case is to diff all files, + # which could be expensive. + if cpstat.st_mtime != st.st_mtime or cpstat.st_size != st.st_size: ui.debug('file changed while diffing. ' 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn)
--- a/hgext/fsmonitor/__init__.py Fri May 12 21:46:14 2017 +0900 +++ b/hgext/fsmonitor/__init__.py Fri May 12 11:20:25 2017 -0700 @@ -692,11 +692,13 @@ # at this point since fsmonitorstate wasn't present, repo.dirstate is # not a fsmonitordirstate - repo.dirstate.__class__ = makedirstate(repo.dirstate.__class__) - # nuke the dirstate so that _fsmonitorinit and subsequent configuration - # changes take effect on it - del repo._filecache['dirstate'] - delattr(repo.unfiltered(), 'dirstate') + dirstate = repo.dirstate + dirstate.__class__ = makedirstate(dirstate.__class__) + dirstate._fsmonitorinit(fsmonitorstate, client) + # invalidate property cache, but keep filecache which contains the + # wrapped dirstate object + del repo.unfiltered().__dict__['dirstate'] + assert dirstate is repo._filecache['dirstate'].obj class fsmonitorrepo(repo.__class__): def status(self, *args, **kwargs):
--- a/hgext/largefiles/overrides.py Fri May 12 21:46:14 2017 +0900 +++ b/hgext/largefiles/overrides.py Fri May 12 11:20:25 2017 -0700 @@ -105,9 +105,9 @@ scmutil.matchandpats) def addlargefiles(ui, repo, isaddremove, matcher, **opts): - large = opts.get('large') + large = opts.get(r'large') lfsize = lfutil.getminsize( - ui, lfutil.islfilesrepo(repo), opts.get('lfsize')) + ui, lfutil.islfilesrepo(repo), opts.get(r'lfsize')) lfmatcher = None if lfutil.islfilesrepo(repo): @@ -258,7 +258,7 @@ def cmdutiladd(orig, ui, repo, matcher, prefix, explicitonly, **opts): # The --normal flag short circuits this override - if opts.get('normal'): + if opts.get(r'normal'): return orig(ui, repo, matcher, prefix, explicitonly, **opts) ladded, lbad = addlargefiles(ui, repo, False, matcher, **opts)
--- a/hgext/mq.py Fri May 12 21:46:14 2017 +0900 +++ b/hgext/mq.py Fri May 12 11:20:25 2017 -0700 @@ -3540,7 +3540,7 @@ """Add --mq option to operate on patch repository instead of main""" # some commands do not like getting unknown options - mq = kwargs.pop('mq', None) + mq = kwargs.pop(r'mq', None) if not mq: return orig(ui, repo, *args, **kwargs)
--- a/hgext/rebase.py Fri May 12 21:46:14 2017 +0900 +++ b/hgext/rebase.py Fri May 12 11:20:25 2017 -0700 @@ -1246,7 +1246,7 @@ if not roots: raise error.Abort(_('no matching revisions')) roots.sort() - state = {} + state = dict.fromkeys(rebaseset, revtodo) detachset = set() for root in roots: commonbase = root.ancestor(dest) @@ -1264,7 +1264,6 @@ return None repo.ui.debug('rebase onto %s starting from %s\n' % (dest, root)) - state.update(dict.fromkeys(rebaseset, revtodo)) # Rebase tries to turn <dest> into a parent of <root> while # preserving the number of parents of rebased changesets: #
--- a/hgext/win32mbcs.py Fri May 12 21:46:14 2017 +0900 +++ b/hgext/win32mbcs.py Fri May 12 11:20:25 2017 -0700 @@ -183,7 +183,8 @@ if pycompat.osname == 'nt': for f in winfuncs.split(): wrapname(f, wrapper) - wrapname("mercurial.osutil.listdir", wrapperforlistdir) + wrapname("mercurial.util.listdir", wrapperforlistdir) + wrapname("mercurial.windows.listdir", wrapperforlistdir) # wrap functions to be called with local byte string arguments for f in rfuncs.split(): wrapname(f, reversewrapper)
--- a/mercurial/__init__.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/__init__.py Fri May 12 11:20:25 2017 -0700 @@ -165,7 +165,8 @@ if not spec: return None - if fullname.startswith('mercurial.pure.'): + if (fullname.startswith('mercurial.pure.') + and fullname.replace('.pure.', '.') in _dualmodules): spec.name = spec.name.replace('.pure.', '.') # TODO need to support loaders from alternate specs, like zip
--- a/mercurial/branchmap.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/branchmap.py Fri May 12 11:20:25 2017 -0700 @@ -67,8 +67,6 @@ partial.setdefault(label, []).append(node) if state == 'c': partial._closednodes.add(node) - except KeyboardInterrupt: - raise except Exception as inst: if repo.ui.debugflag: msg = 'invalid branchheads cache'
--- a/mercurial/bundle2.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/bundle2.py Fri May 12 11:20:25 2017 -0700 @@ -1005,7 +1005,7 @@ # backup exception data for later ui.debug('bundle2-input-stream-interrupt: encoding exception %s' % exc) - exc_info = sys.exc_info() + tb = sys.exc_info()[2] msg = 'unexpected error: %s' % exc interpart = bundlepart('error:abort', [('message', msg)], mandatory=False) @@ -1016,10 +1016,7 @@ outdebug(ui, 'closing payload chunk') # abort current part payload yield _pack(_fpayloadsize, 0) - if pycompat.ispy3: - raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) - else: - exec("""raise exc_info[0], exc_info[1], exc_info[2]""") + pycompat.raisewithtb(exc, tb) # end of payload outdebug(ui, 'closing payload chunk') yield _pack(_fpayloadsize, 0) @@ -1342,6 +1339,68 @@ obscaps = caps.get('obsmarkers', ()) return [int(c[1:]) for c in obscaps if c.startswith('V')] +def writenewbundle(ui, repo, source, filename, bundletype, outgoing, opts, + vfs=None, compression=None, compopts=None): + if bundletype.startswith('HG10'): + cg = changegroup.getchangegroup(repo, source, outgoing, version='01') + return writebundle(ui, cg, filename, bundletype, vfs=vfs, + compression=compression, compopts=compopts) + elif not bundletype.startswith('HG20'): + raise error.ProgrammingError('unknown bundle type: %s' % bundletype) + + bundle = bundle20(ui) + bundle.setcompression(compression, compopts) + _addpartsfromopts(ui, repo, bundle, source, outgoing, opts) + chunkiter = bundle.getchunks() + + return changegroup.writechunks(ui, chunkiter, filename, vfs=vfs) + +def _addpartsfromopts(ui, repo, bundler, source, outgoing, opts): + # We should eventually reconcile this logic with the one behind + # 'exchange.getbundle2partsgenerator'. + # + # The type of input from 'getbundle' and 'writenewbundle' are a bit + # different right now. So we keep them separated for now for the sake of + # simplicity. + + # we always want a changegroup in such bundle + cgversion = opts.get('cg.version') + if cgversion is None: + cgversion = changegroup.safeversion(repo) + cg = changegroup.getchangegroup(repo, source, outgoing, + version=cgversion) + part = bundler.newpart('changegroup', data=cg.getchunks()) + part.addparam('version', cg.version) + if 'clcount' in cg.extras: + part.addparam('nbchanges', str(cg.extras['clcount']), + mandatory=False) + + addparttagsfnodescache(repo, bundler, outgoing) + +def addparttagsfnodescache(repo, bundler, outgoing): + # we include the tags fnode cache for the bundle changeset + # (as an optional parts) + cache = tags.hgtagsfnodescache(repo.unfiltered()) + chunks = [] + + # .hgtags fnodes are only relevant for head changesets. While we could + # transfer values for all known nodes, there will likely be little to + # no benefit. + # + # We don't bother using a generator to produce output data because + # a) we only have 40 bytes per head and even esoteric numbers of heads + # consume little memory (1M heads is 40MB) b) we don't want to send the + # part if we don't have entries and knowing if we have entries requires + # cache lookups. + for node in outgoing.missingheads: + # Don't compute missing, as this may slow down serving. + fnode = cache.getfnode(node, computemissing=False) + if fnode is not None: + chunks.extend([node, fnode]) + + if chunks: + bundler.newpart('hgtagsfnodes', data=''.join(chunks)) + def writebundle(ui, cg, filename, bundletype, vfs=None, compression=None, compopts=None): """Write a bundle file and return its filename.
--- a/mercurial/changegroup.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/changegroup.py Fri May 12 11:20:25 2017 -0700 @@ -502,16 +502,9 @@ class cg1packer(object): deltaheader = _CHANGEGROUPV1_DELTA_HEADER version = '01' - def __init__(self, repo, bundlecaps=None): + def __init__(self, repo): """Given a source repo, construct a bundler. - - bundlecaps is optional and can be used to specify the set of - capabilities which can be used to build the bundle. """ - # Set of capabilities we can use to build the bundle. - if bundlecaps is None: - bundlecaps = set() - self._bundlecaps = bundlecaps # experimental config: bundle.reorder reorder = repo.ui.config('bundle', 'reorder', 'auto') if reorder == 'auto': @@ -815,8 +808,8 @@ version = '02' deltaheader = _CHANGEGROUPV2_DELTA_HEADER - def __init__(self, repo, bundlecaps=None): - super(cg2packer, self).__init__(repo, bundlecaps) + def __init__(self, repo): + super(cg2packer, self).__init__(repo) if self._reorder is None: # Since generaldelta is directly supported by cg2, reordering # generally doesn't help, so we disable it by default (treating @@ -910,9 +903,9 @@ assert versions return min(versions) -def getbundler(version, repo, bundlecaps=None): +def getbundler(version, repo): assert version in supportedoutgoingversions(repo) - return _packermap[version][0](repo, bundlecaps) + return _packermap[version][0](repo) def getunbundler(version, fh, alg, extras=None): return _packermap[version][1](fh, alg, extras=extras) @@ -963,40 +956,30 @@ bundler = getbundler(version, repo) return getsubset(repo, outgoing, bundler, source) -def getlocalchangegroupraw(repo, source, outgoing, bundlecaps=None, - version='01'): +def getlocalchangegroupraw(repo, source, outgoing, version='01'): """Like getbundle, but taking a discovery.outgoing as an argument. This is only implemented for local repos and reuses potentially precomputed sets in outgoing. Returns a raw changegroup generator.""" if not outgoing.missing: return None - bundler = getbundler(version, repo, bundlecaps) + bundler = getbundler(version, repo) return getsubsetraw(repo, outgoing, bundler, source) -def getlocalchangegroup(repo, source, outgoing, bundlecaps=None, - version='01'): +def getchangegroup(repo, source, outgoing, version='01'): """Like getbundle, but taking a discovery.outgoing as an argument. This is only implemented for local repos and reuses potentially precomputed sets in outgoing.""" if not outgoing.missing: return None - bundler = getbundler(version, repo, bundlecaps) + bundler = getbundler(version, repo) return getsubset(repo, outgoing, bundler, source) -def getchangegroup(repo, source, outgoing, bundlecaps=None, - version='01'): - """Like changegroupsubset, but returns the set difference between the - ancestors of heads and the ancestors common. - - If heads is None, use the local heads. If common is None, use [nullid]. - - The nodes in common might not all be known locally due to the way the - current discovery protocol works. - """ - return getlocalchangegroup(repo, source, outgoing, bundlecaps=bundlecaps, - version=version) +def getlocalchangegroup(repo, *args, **kwargs): + repo.ui.deprecwarn('getlocalchangegroup is deprecated, use getchangegroup', + '4.3') + return getchangegroup(repo, *args, **kwargs) def changegroup(repo, basenodes, source): # to avoid a race we use changegroupsubset() (issue1320)
--- a/mercurial/changelog.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/changelog.py Fri May 12 11:20:25 2017 -0700 @@ -190,7 +190,7 @@ # The list of files may be empty. Which means nl3 is the first of the # double newline that precedes the description. - if text[nl3 + 1] == '\n': + if text[nl3 + 1:nl3 + 2] == '\n': doublenl = nl3 else: doublenl = text.index('\n\n', nl3 + 1)
--- a/mercurial/chgserver.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/chgserver.py Fri May 12 11:20:25 2017 -0700 @@ -44,6 +44,7 @@ import inspect import os import re +import socket import struct import time @@ -54,7 +55,6 @@ encoding, error, extensions, - osutil, pycompat, util, ) @@ -313,7 +313,7 @@ # tell client to sendmsg() with 1-byte payload, which makes it # distinctive from "attachio\n" command consumed by client.read() self.clientsock.sendall(struct.pack('>cI', 'I', 1)) - clientfds = osutil.recvfds(self.clientsock.fileno()) + clientfds = util.recvfds(self.clientsock.fileno()) _log('received fds: %r\n' % clientfds) ui = self.ui @@ -458,12 +458,12 @@ 'setenv': setenv, 'setumask': setumask}) - if util.safehasattr(osutil, 'setprocname'): + if util.safehasattr(util, 'setprocname'): def setprocname(self): """Change process title""" name = self._readstr() _log('setprocname: %r\n' % name) - osutil.setprocname(name) + util.setprocname(name) capabilities['setprocname'] = setprocname def _tempaddress(address): @@ -492,6 +492,7 @@ self._checkextensions() self._bind(sock) self._createsymlink() + # no "listening at" message should be printed to simulate hg behavior def _inithashstate(self, address): self._baseaddress = address @@ -517,6 +518,7 @@ tempaddress = _tempaddress(self._realaddress) util.bindunixsocket(sock, tempaddress) self._socketstat = os.stat(tempaddress) + sock.listen(socket.SOMAXCONN) # rename will replace the old socket file if exists atomically. the # old server will detect ownership change and exit. util.rename(tempaddress, self._realaddress) @@ -545,10 +547,6 @@ # the client will start a new server on demand. util.tryunlink(self._realaddress) - def printbanner(self, address): - # no "listening at" message should be printed to simulate hg behavior - pass - def shouldexit(self): if not self._issocketowner(): self.ui.debug('%s is not owned, exiting.\n' % self._realaddress)
--- a/mercurial/cmdutil.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/cmdutil.py Fri May 12 11:20:25 2017 -0700 @@ -115,6 +115,7 @@ def dorecord(ui, repo, commitfunc, cmdsuggest, backupall, filterfn, *pats, **opts): from . import merge as mergemod + opts = pycompat.byteskwargs(opts) if not ui.interactive(): if cmdsuggest: msg = _('running non-interactively, use %s instead') % cmdsuggest @@ -490,10 +491,10 @@ patlen = len(pat) i = 0 while i < patlen: - c = pat[i] + c = pat[i:i + 1] if c == '%': i += 1 - c = pat[i] + c = pat[i:i + 1] c = expander[c]() newname.append(c) i += 1 @@ -1360,7 +1361,7 @@ if rev is None: jrev = jnode = 'null' else: - jrev = str(rev) + jrev = '%d' % rev jnode = '"%s"' % hex(ctx.node()) j = encoding.jsonescape @@ -1607,7 +1608,7 @@ if rev in results: ui.status(_("found revision %s from %s\n") % (rev, util.datestr(results[rev]))) - return str(rev) + return '%d' % rev raise error.Abort(_("revision matching date not found")) @@ -2278,7 +2279,7 @@ sub = wctx.sub(subpath) try: submatch = matchmod.subdirmatcher(subpath, match) - if opts.get('subrepos'): + if opts.get(r'subrepos'): bad.extend(sub.add(ui, submatch, prefix, False, **opts)) else: bad.extend(sub.add(ui, submatch, prefix, True, **opts)) @@ -2286,7 +2287,7 @@ ui.status(_("skipping missing subrepository: %s\n") % join(subpath)) - if not opts.get('dry_run'): + if not opts.get(r'dry_run'): rejected = wctx.add(names, prefix) bad.extend(f for f in rejected if f in match.files()) return bad @@ -2308,7 +2309,7 @@ forgot = [] s = repo.status(match=matchmod.badmatch(match, badfn), clean=True) - forget = sorted(s[0] + s[1] + s[3] + s[6]) + forget = sorted(s.modified + s.added + s.deleted + s.clean) if explicitonly: forget = [f for f in forget if match.exact(f)]
--- a/mercurial/commands.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/commands.py Fri May 12 11:20:25 2017 -0700 @@ -255,7 +255,7 @@ Returns 0 if all files are successfully added. """ - m = scmutil.match(repo[None], pats, opts) + m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts)) rejected = cmdutil.add(ui, repo, m, "", False, **opts) return rejected and 1 or 0 @@ -325,6 +325,7 @@ Returns 0 if all files are successfully added. """ + opts = pycompat.byteskwargs(opts) try: sim = float(opts.get('similarity') or 100) except ValueError: @@ -368,6 +369,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) if not pats: raise error.Abort(_('at least one filename or pattern is required')) @@ -452,7 +454,7 @@ whitespace=True) for abs in ctx.walk(m): fctx = ctx[abs] - if not opts.get('text') and util.binary(fctx.data()): + if not opts.get('text') and fctx.isbinary(): fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs)) continue @@ -532,6 +534,7 @@ Returns 0 on success. ''' + opts = pycompat.byteskwargs(opts) ctx = scmutil.revsingle(repo, opts.get('rev')) if not ctx: raise error.Abort(_('no working directory: please specify a revision')) @@ -627,6 +630,7 @@ release(lock, wlock) def _dobackout(ui, repo, node=None, rev=None, **opts): + opts = pycompat.byteskwargs(opts) if opts.get('commit') and opts.get('no_commit'): raise error.Abort(_("cannot use --commit with --no-commit")) if opts.get('merge') and opts.get('no_commit'): @@ -702,7 +706,8 @@ def commitfunc(ui, repo, message, match, opts): editform = 'backout' - e = cmdutil.getcommiteditor(editform=editform, **opts) + e = cmdutil.getcommiteditor(editform=editform, + **pycompat.strkwargs(opts)) if not message: # we don't translate commit messages message = "Backed out changeset %s" % short(node) @@ -837,8 +842,6 @@ elif extra or good + bad + skip + reset + extend + bool(command) > 1: raise error.Abort(_('incompatible arguments')) - cmdutil.checkunfinished(repo) - if reset: hbisect.resetstate(repo) return @@ -865,6 +868,7 @@ """common used update sequence""" if noupdate: return + cmdutil.checkunfinished(repo) cmdutil.bailifchanged(repo) return hg.clean(repo, node, show_stats=show_stats) @@ -1002,6 +1006,7 @@ hg book -f @ ''' + opts = pycompat.byteskwargs(opts) force = opts.get('force') rev = opts.get('rev') delete = opts.get('delete') @@ -1178,6 +1183,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) if label: label = label.strip() @@ -1226,6 +1232,7 @@ Returns 0. """ + opts = pycompat.byteskwargs(opts) ui.pager('branches') fm = ui.formatter('branches', opts) hexfunc = fm.hexfunc @@ -1309,6 +1316,7 @@ Returns 0 on success, 1 if no changes found. """ + opts = pycompat.byteskwargs(opts) revs = None if 'rev' in opts: revstrings = opts['rev'] @@ -1339,8 +1347,6 @@ base = ['null'] else: base = scmutil.revrange(repo, opts.get('base')) - # TODO: get desired bundlecaps from command line. - bundlecaps = None if cgversion not in changegroup.supportedoutgoingversions(repo): raise error.Abort(_("repository does not support bundle version %s") % cgversion) @@ -1352,10 +1358,6 @@ common = [repo.lookup(rev) for rev in base] heads = revs and map(repo.lookup, revs) or None outgoing = discovery.outgoing(repo, common, heads) - cg = changegroup.getchangegroup(repo, 'bundle', outgoing, - bundlecaps=bundlecaps, - version=cgversion) - outgoing = None else: dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest, opts.get('branch')) @@ -1366,10 +1368,9 @@ onlyheads=heads, force=opts.get('force'), portable=True) - cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing, - bundlecaps, version=cgversion) - if not cg: - scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded) + + if not outgoing.missing: + scmutil.nochangesfound(ui, repo, not base and outgoing.excluded) return 1 if cgversion == '01': #bundle1 @@ -1392,8 +1393,11 @@ if complevel is not None: compopts['level'] = complevel - bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression, - compopts=compopts) + + contentopts = {'cg.version': cgversion} + bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing, + contentopts, compression=bcompression, + compopts=compopts) @command('cat', [('o', 'output', '', @@ -1549,6 +1553,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) if opts.get('noupdate') and opts.get('updaterev'): raise error.Abort(_("cannot specify both --noupdate and --updaterev")) @@ -1639,16 +1644,16 @@ release(lock, wlock) def _docommit(ui, repo, *pats, **opts): - opts = pycompat.byteskwargs(opts) - if opts.get('interactive'): - opts.pop('interactive') + if opts.get(r'interactive'): + opts.pop(r'interactive') ret = cmdutil.dorecord(ui, repo, commit, None, False, cmdutil.recordfilter, *pats, - **pycompat.strkwargs(opts)) + **opts) # ret can be 0 (no changes to record) or the value returned by # commit(), 1 if nothing changed or None on success. return 1 if ret == 0 else ret + opts = pycompat.byteskwargs(opts) if opts.get('subrepos'): if opts.get('amend'): raise error.Abort(_('cannot amend with --subrepos')) @@ -1769,6 +1774,7 @@ """ + opts = pycompat.byteskwargs(opts) if opts.get('edit') or opts.get('local') or opts.get('global'): if opts.get('local') and opts.get('global'): raise error.Abort(_("can't use --local and --global together")) @@ -1871,6 +1877,7 @@ Returns 0 on success, 1 if errors are encountered. """ + opts = pycompat.byteskwargs(opts) with repo.wlock(False): return cmdutil.copy(ui, repo, pats, opts) @@ -1938,6 +1945,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) revs = opts.get('rev') change = opts.get('change') stat = opts.get('stat') @@ -2094,7 +2102,9 @@ Returns 0 if a match is found, 1 otherwise. """ - ctx = scmutil.revsingle(repo, opts.get(r'rev'), None) + + opts = pycompat.byteskwargs(opts) + ctx = scmutil.revsingle(repo, opts.get('rev'), None) end = '\n' if opts.get('print0'): @@ -2136,6 +2146,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) if not pats: raise error.Abort(_('no files specified')) @@ -2220,6 +2231,7 @@ return _dograft(ui, repo, *revs, **opts) def _dograft(ui, repo, *revs, **opts): + opts = pycompat.byteskwargs(opts) if revs and opts.get('rev'): ui.warn(_('warning: inconsistent use of --rev might give unexpected ' 'revision ordering!\n')) @@ -2232,7 +2244,8 @@ if not opts.get('date') and opts.get('currentdate'): opts['date'] = "%d %d" % util.makedate() - editor = cmdutil.getcommiteditor(editform='graft', **opts) + editor = cmdutil.getcommiteditor(editform='graft', + **pycompat.strkwargs(opts)) cont = False if opts.get('continue'): @@ -2439,6 +2452,7 @@ Returns 0 if a match is found, 1 otherwise. """ + opts = pycompat.byteskwargs(opts) reflags = re.M if opts.get('ignore_case'): reflags |= re.I @@ -2685,6 +2699,7 @@ Returns 0 if matching heads are found, 1 if not. """ + opts = pycompat.byteskwargs(opts) start = None if 'rev' in opts: start = scmutil.revsingle(repo, opts['rev'], None).node() @@ -2743,7 +2758,7 @@ Returns 0 if successful. """ - keep = opts.get('system') or [] + keep = opts.get(r'system') or [] if len(keep) == 0: if pycompat.sysplatform.startswith('win'): keep.append('windows') @@ -2810,6 +2825,7 @@ Returns 0 if successful. """ + opts = pycompat.byteskwargs(opts) if not repo and not source: raise error.Abort(_("there is no Mercurial repository here " "(.hg not found)")) @@ -3033,6 +3049,7 @@ Returns 0 on success, 1 on partial success (see --partial). """ + opts = pycompat.byteskwargs(opts) if not patch1: raise error.Abort(_('need at least one patch to import')) @@ -3237,6 +3254,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) hg.peer(ui, opts, ui.expandpath(dest), create=True) @command('locate', @@ -3267,6 +3285,7 @@ Returns 0 if a match is found, 1 otherwise. """ + opts = pycompat.byteskwargs(opts) if opts.get('print0'): end = '\0' else: @@ -3473,6 +3492,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) fm = ui.formatter('manifest', opts) if opts.get('all'): @@ -3551,6 +3571,7 @@ Returns 0 on success, 1 if there are unresolved files. """ + opts = pycompat.byteskwargs(opts) if opts.get('rev') and node: raise error.Abort(_("please specify just one revision")) if not node: @@ -3630,6 +3651,7 @@ Returns 0 if there are outgoing changes, 1 otherwise. """ + opts = pycompat.byteskwargs(opts) if opts.get('graph'): cmdutil.checkunsupportedgraphflags([], opts) o, other = hg._outgoing(ui, repo, dest, opts) @@ -3687,6 +3709,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) ctx = scmutil.revsingle(repo, opts.get('rev'), None) if file_: @@ -3749,6 +3772,8 @@ Returns 0 on success. """ + + opts = pycompat.byteskwargs(opts) ui.pager('paths') if search: pathitems = [(name, path) for name, path in ui.paths.iteritems() @@ -3811,6 +3836,7 @@ (For more information about the phases concept, see :hg:`help phases`.) """ + opts = pycompat.byteskwargs(opts) # search for a unique phase argument targetphase = None for idx, name in enumerate(phases.phasenames): @@ -3943,6 +3969,7 @@ Returns 0 on success, 1 if an update had unresolved files. """ + opts = pycompat.byteskwargs(opts) if ui.configbool('commands', 'update.requiredest') and opts.get('update'): msg = _('update destination required by configuration') hint = _('use hg pull followed by hg update DEST') @@ -4073,6 +4100,7 @@ Returns 0 if push was successful, 1 if nothing to push. """ + opts = pycompat.byteskwargs(opts) if opts.get('bookmark'): ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push') for b in opts['bookmark']: @@ -4198,6 +4226,7 @@ Returns 0 on success, 1 if any warnings encountered. """ + opts = pycompat.byteskwargs(opts) after, force = opts.get('after'), opts.get('force') if not pats and not after: raise error.Abort(_('no files specified')) @@ -4227,6 +4256,7 @@ Returns 0 on success, 1 if errors are encountered. """ + opts = pycompat.byteskwargs(opts) with repo.wlock(False): return cmdutil.copy(ui, repo, pats, opts, rename=True) @@ -4281,6 +4311,7 @@ Returns 0 on success, 1 if any files fail a resolve attempt. """ + opts = pycompat.byteskwargs(opts) flaglist = 'all mark unmark list no_status'.split() all, mark, unmark, show, nostatus = \ [opts.get(o) for o in flaglist] @@ -4586,8 +4617,8 @@ if not ui.configbool('ui', 'rollback', True): raise error.Abort(_('rollback is disabled because it is unsafe'), hint=('see `hg help -v rollback` for information')) - return repo.rollback(dryrun=opts.get('dry_run'), - force=opts.get('force')) + return repo.rollback(dryrun=opts.get(r'dry_run'), + force=opts.get(r'force')) @command('root', []) def root(ui, repo): @@ -4652,6 +4683,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) if opts["stdio"] and opts["cmdserver"]: raise error.Abort(_("cannot use --stdio with --cmdserver")) @@ -4817,6 +4849,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) ui.pager('summary') ctx = repo[None] parents = ctx.parents() @@ -5125,6 +5158,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) wlock = lock = None try: wlock = repo.wlock() @@ -5189,7 +5223,8 @@ editform = 'tag.remove' else: editform = 'tag.add' - editor = cmdutil.getcommiteditor(editform=editform, **opts) + editor = cmdutil.getcommiteditor(editform=editform, + **pycompat.strkwargs(opts)) # don't allow tagging the null rev if (not opts.get('remove') and @@ -5212,6 +5247,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) ui.pager('tags') fm = ui.formatter('tags', opts) hexfunc = fm.hexfunc @@ -5256,6 +5292,7 @@ Returns 0 on success. """ + opts = pycompat.byteskwargs(opts) displayer = cmdutil.show_changeset(ui, repo, opts) displayer.show(repo['tip']) displayer.close() @@ -5303,7 +5340,7 @@ else: modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname) - return postincoming(ui, repo, modheads, opts.get('update'), None, None) + return postincoming(ui, repo, modheads, opts.get(r'update'), None, None) @command('^update|up|checkout|co', [('C', 'clean', None, _('discard uncommitted changes (no backup)')), @@ -5430,6 +5467,7 @@ @command('version', [] + formatteropts, norepo=True) def version_(ui, **opts): """output version and copyright information""" + opts = pycompat.byteskwargs(opts) if ui.verbose: ui.pager('version') fm = ui.formatter("version", opts)
--- a/mercurial/commandserver.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/commandserver.py Fri May 12 11:20:25 2017 -0700 @@ -409,14 +409,13 @@ def bindsocket(self, sock, address): util.bindunixsocket(sock, address) + sock.listen(socket.SOMAXCONN) + self.ui.status(_('listening at %s\n') % address) + self.ui.flush() # avoid buffering of status message def unlinksocket(self, address): os.unlink(address) - def printbanner(self, address): - self.ui.status(_('listening at %s\n') % address) - self.ui.flush() # avoid buffering of status message - def shouldexit(self): """True if server should shut down; checked per pollinterval""" return False @@ -452,10 +451,8 @@ def init(self): self._sock = socket.socket(socket.AF_UNIX) self._servicehandler.bindsocket(self._sock, self.address) - self._sock.listen(socket.SOMAXCONN) o = signal.signal(signal.SIGCHLD, self._sigchldhandler) self._oldsigchldhandler = o - self._servicehandler.printbanner(self.address) self._socketunlinked = False def _unlinksocket(self):
--- a/mercurial/context.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/context.py Fri May 12 11:20:25 2017 -0700 @@ -257,13 +257,13 @@ return changectx(self._repo, nullrev) def _fileinfo(self, path): - if '_manifest' in self.__dict__: + if r'_manifest' in self.__dict__: try: return self._manifest[path], self._manifest.flags(path) except KeyError: raise error.ManifestLookupError(self._node, path, _('not found in manifest')) - if '_manifestdelta' in self.__dict__ or path in self.files(): + if r'_manifestdelta' in self.__dict__ or path in self.files(): if path in self._manifestdelta: return (self._manifestdelta[path], self._manifestdelta.flags(path)) @@ -687,21 +687,20 @@ in the repo, workingfilectx: a filecontext that represents files from the working directory, - memfilectx: a filecontext that represents files in-memory.""" - def __new__(cls, repo, path, *args, **kwargs): - return super(basefilectx, cls).__new__(cls) - + memfilectx: a filecontext that represents files in-memory, + overlayfilectx: duplicate another filecontext with some fields overridden. + """ @propertycache def _filelog(self): return self._repo.file(self._path) @propertycache def _changeid(self): - if '_changeid' in self.__dict__: + if r'_changeid' in self.__dict__: return self._changeid - elif '_changectx' in self.__dict__: + elif r'_changectx' in self.__dict__: return self._changectx.rev() - elif '_descendantrev' in self.__dict__: + elif r'_descendantrev' in self.__dict__: # this file context was created from a revision with a known # descendant, we can (lazily) correct for linkrev aliases return self._adjustlinkrev(self._descendantrev) @@ -710,7 +709,7 @@ @propertycache def _filenode(self): - if '_fileid' in self.__dict__: + if r'_fileid' in self.__dict__: return self._filelog.lookup(self._fileid) else: return self._changectx.filenode(self._path) @@ -762,8 +761,11 @@ return self._filerev def filenode(self): return self._filenode + @propertycache + def _flags(self): + return self._changectx.flags(self._path) def flags(self): - return self._changectx.flags(self._path) + return self._flags def filelog(self): return self._filelog def rev(self): @@ -794,8 +796,12 @@ return self._changectx.manifest() def changectx(self): return self._changectx + def renamed(self): + return self._copied def repo(self): return self._repo + def size(self): + return len(self.data()) def path(self): return self._path @@ -1134,6 +1140,10 @@ def rawdata(self): return self._filelog.revision(self._filenode, raw=True) + def rawflags(self): + """low-level revlog flags""" + return self._filelog.flags(self._filerev) + def data(self): try: return self._filelog.read(self._filenode) @@ -1146,7 +1156,8 @@ def size(self): return self._filelog.size(self._filerev) - def renamed(self): + @propertycache + def _copied(self): """check if file was actually renamed in this changeset revision If rename logged in file revision, we report copy for changeset only @@ -1396,7 +1407,7 @@ return [] def flags(self, path): - if '_manifest' in self.__dict__: + if r'_manifest' in self.__dict__: try: return self._manifest.flags(path) except KeyError: @@ -2059,12 +2070,6 @@ def data(self): return self._data - def size(self): - return len(self.data()) - def flags(self): - return self._flags - def renamed(self): - return self._copied def remove(self, ignoremissing=False): """wraps unlink for a repo's working directory""" @@ -2075,6 +2080,77 @@ """wraps repo.wwrite""" self._data = data +class overlayfilectx(committablefilectx): + """Like memfilectx but take an original filectx and optional parameters to + override parts of it. This is useful when fctx.data() is expensive (i.e. + flag processor is expensive) and raw data, flags, and filenode could be + reused (ex. rebase or mode-only amend a REVIDX_EXTSTORED file). + """ + + def __init__(self, originalfctx, datafunc=None, path=None, flags=None, + copied=None, ctx=None): + """originalfctx: filecontext to duplicate + + datafunc: None or a function to override data (file content). It is a + function to be lazy. path, flags, copied, ctx: None or overridden value + + copied could be (path, rev), or False. copied could also be just path, + and will be converted to (path, nullid). This simplifies some callers. + """ + + if path is None: + path = originalfctx.path() + if ctx is None: + ctx = originalfctx.changectx() + ctxmatch = lambda: True + else: + ctxmatch = lambda: ctx == originalfctx.changectx() + + repo = originalfctx.repo() + flog = originalfctx.filelog() + super(overlayfilectx, self).__init__(repo, path, flog, ctx) + + if copied is None: + copied = originalfctx.renamed() + copiedmatch = lambda: True + else: + if copied and not isinstance(copied, tuple): + # repo._filecommit will recalculate copyrev so nullid is okay + copied = (copied, nullid) + copiedmatch = lambda: copied == originalfctx.renamed() + + # When data, copied (could affect data), ctx (could affect filelog + # parents) are not overridden, rawdata, rawflags, and filenode may be + # reused (repo._filecommit should double check filelog parents). + # + # path, flags are not hashed in filelog (but in manifestlog) so they do + # not affect reusable here. + # + # If ctx or copied is overridden to a same value with originalfctx, + # still consider it's reusable. originalfctx.renamed() may be a bit + # expensive so it's not called unless necessary. Assuming datafunc is + # always expensive, do not call it for this "reusable" test. + reusable = datafunc is None and ctxmatch() and copiedmatch() + + if datafunc is None: + datafunc = originalfctx.data + if flags is None: + flags = originalfctx.flags() + + self._datafunc = datafunc + self._flags = flags + self._copied = copied + + if reusable: + # copy extra fields from originalfctx + attrs = ['rawdata', 'rawflags', '_filenode', '_filerev'] + for attr in attrs: + if util.safehasattr(originalfctx, attr): + setattr(self, attr, getattr(originalfctx, attr)) + + def data(self): + return self._datafunc() + class metadataonlyctx(committablectx): """Like memctx but it's reusing the manifest of different commit. Intended to be used by lightweight operations that are creating
--- a/mercurial/debugcommands.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/debugcommands.py Fri May 12 11:20:25 2017 -0700 @@ -1020,19 +1020,20 @@ fm.write('hgmodules', _("checking installed modules (%s)...\n"), os.path.dirname(pycompat.fsencode(__file__))) - err = None - try: - from . import ( - base85, - bdiff, - mpatch, - osutil, - ) - dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes - except Exception as inst: - err = inst - problems += 1 - fm.condwrite(err, 'extensionserror', " %s\n", err) + if policy.policy in ('c', 'allow'): + err = None + try: + from . import ( + base85, + bdiff, + mpatch, + osutil, + ) + dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes + except Exception as inst: + err = inst + problems += 1 + fm.condwrite(err, 'extensionserror', " %s\n", err) compengines = util.compengines._engines.values() fm.write('compengines', _('checking registered compression engines (%s)\n'), @@ -1706,9 +1707,9 @@ numother += 1 # Obtain data on the raw chunks in the revlog. - chunk = r._chunkraw(rev, rev)[1] - if chunk: - chunktype = chunk[0] + segment = r._getsegmentforrevs(rev, rev)[1] + if segment: + chunktype = segment[0] else: chunktype = 'empty'
--- a/mercurial/demandimport.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/demandimport.py Fri May 12 11:20:25 2017 -0700 @@ -297,6 +297,7 @@ 'distutils.msvc9compiler', '__builtin__', 'builtins', + 'urwid.command_map', # for pudb ] if _pypy:
--- a/mercurial/dirstate.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/dirstate.py Fri May 12 11:20:25 2017 -0700 @@ -18,7 +18,6 @@ encoding, error, match as matchmod, - osutil, parsers, pathutil, pycompat, @@ -988,7 +987,7 @@ matchalways = match.always() matchtdir = match.traversedir dmap = self._map - listdir = osutil.listdir + listdir = util.listdir lstat = os.lstat dirkind = stat.S_IFDIR regkind = stat.S_IFREG @@ -1021,6 +1020,8 @@ wadd = work.append while work: nd = work.pop() + if not match.visitdir(nd): + continue skip = None if nd == '.': nd = ''
--- a/mercurial/dispatch.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/dispatch.py Fri May 12 11:20:25 2017 -0700 @@ -162,9 +162,13 @@ ret = None try: ret = _runcatch(req) - except KeyboardInterrupt: + except KeyboardInterrupt as inst: try: - req.ui.warn(_("interrupted!\n")) + if isinstance(inst, error.SignalInterrupt): + msg = _("killed!\n") + else: + msg = _("interrupted!\n") + req.ui.warn(msg) except error.SignalInterrupt: # maybe pager would quit without consuming all the output, and # SIGPIPE was raised. we cannot print anything in this case. @@ -179,7 +183,7 @@ if req.ui.logblockedtimes: req.ui._blockedtimes['command_duration'] = duration * 1000 req.ui.log('uiblocked', 'ui blocked ms', **req.ui._blockedtimes) - req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n", + req.ui.log("commandfinish", "%s exited %d after %0.2f seconds\n", msg, ret or 0, duration) try: req._runexithandlers() @@ -475,7 +479,8 @@ return aliasargs(self.fn, args) def __getattr__(self, name): - adefaults = {'norepo': True, 'optionalrepo': False, 'inferrepo': False} + adefaults = {r'norepo': True, + r'optionalrepo': False, r'inferrepo': False} if name not in adefaults: raise AttributeError(name) if self.badalias or util.safehasattr(self, 'shell'):
--- a/mercurial/encoding.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/encoding.py Fri May 12 11:20:25 2017 -0700 @@ -51,14 +51,14 @@ # the process environment _nativeenviron = (not pycompat.ispy3 or os.supports_bytes_environ) if not pycompat.ispy3: - environ = os.environ + environ = os.environ # re-exports elif _nativeenviron: - environ = os.environb + environ = os.environb # re-exports else: # preferred encoding isn't known yet; use utf-8 to avoid unicode error # and recreate it once encoding is settled environ = dict((k.encode(u'utf-8'), v.encode(u'utf-8')) - for k, v in os.environ.items()) + for k, v in os.environ.items()) # re-exports def _getpreferredencoding(): ''' @@ -218,7 +218,7 @@ # now encoding and helper functions are available, recreate the environ # dict to be exported to other modules environ = dict((tolocal(k.encode(u'utf-8')), tolocal(v.encode(u'utf-8'))) - for k, v in os.environ.items()) + for k, v in os.environ.items()) # re-exports # How to treat ambiguous-width characters. Set to 'wide' to treat as wide. wide = (environ.get("HGENCODINGAMBIGUOUS", "narrow") == "wide" @@ -429,7 +429,7 @@ _jsonmap = [] _jsonmap.extend("\\u%04x" % x for x in range(32)) -_jsonmap.extend(chr(x) for x in range(32, 127)) +_jsonmap.extend(pycompat.bytechr(x) for x in range(32, 127)) _jsonmap.append('\\u007f') _jsonmap[0x09] = '\\t' _jsonmap[0x0a] = '\\n' @@ -441,7 +441,7 @@ _paranoidjsonmap = _jsonmap[:] _paranoidjsonmap[0x3c] = '\\u003c' # '<' (e.g. escape "</script>") _paranoidjsonmap[0x3e] = '\\u003e' # '>' -_jsonmap.extend(chr(x) for x in range(128, 256)) +_jsonmap.extend(pycompat.bytechr(x) for x in range(128, 256)) def jsonescape(s, paranoid=False): '''returns a string suitable for JSON
--- a/mercurial/exchange.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/exchange.py Fri May 12 11:20:25 2017 -0700 @@ -16,7 +16,6 @@ nullid, ) from . import ( - base85, bookmarks as bookmod, bundle2, changegroup, @@ -29,7 +28,6 @@ scmutil, sslutil, streamclone, - tags, url as urlmod, util, ) @@ -938,22 +936,19 @@ pushop.repo.prepushoutgoinghooks(pushop) outgoing = pushop.outgoing unbundle = pushop.remote.capable('unbundle') - # TODO: get bundlecaps from remote - bundlecaps = None # create a changegroup from local if pushop.revs is None and not (outgoing.excluded or pushop.repo.changelog.filteredrevs): # push everything, # use the fast path, no race possible on push - bundler = changegroup.cg1packer(pushop.repo, bundlecaps) + bundler = changegroup.cg1packer(pushop.repo) cg = changegroup.getsubset(pushop.repo, outgoing, bundler, 'push', fastpath=True) else: - cg = changegroup.getlocalchangegroup(pushop.repo, 'push', outgoing, - bundlecaps) + cg = changegroup.getchangegroup(pushop.repo, 'push', outgoing) # apply changegroup to remote if unbundle: @@ -1512,7 +1507,7 @@ markers = [] for key in sorted(remoteobs, reverse=True): if key.startswith('dump'): - data = base85.b85decode(remoteobs[key]) + data = util.b85decode(remoteobs[key]) version, newmarks = obsolete._readmarkers(data) markers += newmarks if markers: @@ -1578,7 +1573,7 @@ raise ValueError(_('unsupported getbundle arguments: %s') % ', '.join(sorted(kwargs.keys()))) outgoing = _computeoutgoing(repo, heads, common) - bundler = changegroup.getbundler('01', repo, bundlecaps) + bundler = changegroup.getbundler('01', repo) return changegroup.getsubsetraw(repo, outgoing, bundler, source) # bundle20 case @@ -1616,7 +1611,6 @@ version = max(cgversions) outgoing = _computeoutgoing(repo, heads, common) cg = changegroup.getlocalchangegroupraw(repo, source, outgoing, - bundlecaps=bundlecaps, version=version) if cg: @@ -1668,30 +1662,7 @@ return outgoing = _computeoutgoing(repo, heads, common) - - if not outgoing.missingheads: - return - - cache = tags.hgtagsfnodescache(repo.unfiltered()) - chunks = [] - - # .hgtags fnodes are only relevant for head changesets. While we could - # transfer values for all known nodes, there will likely be little to - # no benefit. - # - # We don't bother using a generator to produce output data because - # a) we only have 40 bytes per head and even esoteric numbers of heads - # consume little memory (1M heads is 40MB) b) we don't want to send the - # part if we don't have entries and knowing if we have entries requires - # cache lookups. - for node in outgoing.missingheads: - # Don't compute missing, as this may slow down serving. - fnode = cache.getfnode(node, computemissing=False) - if fnode is not None: - chunks.extend([node, fnode]) - - if chunks: - bundler.newpart('hgtagsfnodes', data=''.join(chunks)) + bundle2.addparttagsfnodescache(repo, bundler, outgoing) def _getbookmarks(repo, **kwargs): """Returns bookmark to node mapping.
--- a/mercurial/extensions.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/extensions.py Fri May 12 11:20:25 2017 -0700 @@ -171,8 +171,6 @@ continue try: load(ui, name, path) - except KeyboardInterrupt: - raise except Exception as inst: inst = _forbytes(inst) if path:
--- a/mercurial/filelog.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/filelog.py Fri May 12 11:20:25 2017 -0700 @@ -18,7 +18,7 @@ _mdre = re.compile('\1\n') def parsemeta(text): - """return (metadatadict, keylist, metadatasize)""" + """return (metadatadict, metadatasize)""" # text can be buffer, so we can't use .startswith or .index if text[:2] != '\1\n': return None, None
--- a/mercurial/fileset.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/fileset.py Fri May 12 11:20:25 2017 -0700 @@ -256,7 +256,7 @@ """ # i18n: "binary" is a keyword getargs(x, 0, 0, _("binary takes no arguments")) - return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())] + return [f for f in mctx.existing() if mctx.ctx[f].isbinary()] @predicate('exec()', callexisting=True) def exec_(mctx, x):
--- a/mercurial/formatter.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/formatter.py Fri May 12 11:20:25 2017 -0700 @@ -114,6 +114,7 @@ from . import ( error, + pycompat, templatefilters, templatekw, templater, @@ -178,6 +179,7 @@ pass def data(self, **data): '''insert data into item that's not shown in default output''' + data = pycompat.byteskwargs(data) self._item.update(data) def write(self, fields, deftext, *fielddata, **opts): '''do default text output while assigning data to item'''
--- a/mercurial/graphmod.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/graphmod.py Fri May 12 11:20:25 2017 -0700 @@ -273,7 +273,7 @@ # | | | | | | line.extend(echars[idx * 2:(idx + 1) * 2]) else: - line.extend(' ') + line.extend([' ', ' ']) # all edges to the right of the current node remainder = ncols - idx - 1 if remainder > 0: @@ -410,14 +410,17 @@ # shift_interline is the line containing the non-vertical # edges between this entry and the next shift_interline = echars[:idx * 2] - shift_interline.extend(' ' * (2 + coldiff)) + for i in xrange(2 + coldiff): + shift_interline.append(' ') count = ncols - idx - 1 if coldiff == -1: - shift_interline.extend('/ ' * count) + for i in xrange(count): + shift_interline.extend(['/', ' ']) elif coldiff == 0: shift_interline.extend(echars[(idx + 1) * 2:ncols * 2]) else: - shift_interline.extend(r'\ ' * count) + for i in xrange(count): + shift_interline.extend(['\\', ' ']) # draw edges from the current node to its parents _drawedges(echars, edges, nodeline, shift_interline)
--- a/mercurial/help.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/help.py Fri May 12 11:20:25 2017 -0700 @@ -23,6 +23,7 @@ filemerge, fileset, minirst, + pycompat, revset, templatefilters, templatekw, @@ -304,6 +305,7 @@ ''' from . import commands # avoid cycle + opts = pycompat.byteskwargs(opts) def helpcmd(name, subtopic=None): try:
--- a/mercurial/help/internals/wireprotocol.txt Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/help/internals/wireprotocol.txt Fri May 12 11:20:25 2017 -0700 @@ -632,6 +632,9 @@ branches -------- +(Legacy command used for discovery in old clients. Clients with ``getbundle`` +use the ``known`` and ``heads`` commands instead.) + Obtain ancestor changesets of specific nodes back to a branch point. Despite the name, this command has nothing to do with Mercurial named branches.
--- a/mercurial/hg.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/hg.py Fri May 12 11:20:25 2017 -0700 @@ -869,7 +869,7 @@ revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)] other = peer(repo, opts, dest) - outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs, + outgoing = discovery.findcommonoutgoing(repo, other, revs, force=opts.get('force')) o = outgoing.missing if not o:
--- a/mercurial/hgweb/webcommands.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/hgweb/webcommands.py Fri May 12 11:20:25 2017 -0700 @@ -808,7 +808,7 @@ context = parsecontext(web.config('web', 'comparisoncontext', '5')) def filelines(f): - if util.binary(f.data()): + if f.isbinary(): mt = mimetypes.guess_type(f.path())[0] if not mt: mt = 'application/octet-stream' @@ -886,7 +886,7 @@ yield p def annotate(**map): - if util.binary(fctx.data()): + if fctx.isbinary(): mt = (mimetypes.guess_type(fctx.path())[0] or 'application/octet-stream') lines = [((fctx.filectx(fctx.filerev()), 1), '(binary:%s)' % mt)]
--- a/mercurial/localrepo.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/localrepo.py Fri May 12 11:20:25 2017 -0700 @@ -164,7 +164,7 @@ **kwargs) cb = util.chunkbuffer(chunks) - if bundlecaps is not None and 'HG20' in bundlecaps: + if exchange.bundle2requested(bundlecaps): # When requesting a bundle2, getbundle returns a stream to make the # wire level function happier. We need to build a proper object # from it in local peer. @@ -385,16 +385,6 @@ # generic mapping between names and nodes self.names = namespaces.namespaces() - @property - def wopener(self): - self.ui.deprecwarn("use 'repo.wvfs' instead of 'repo.wopener'", '4.2') - return self.wvfs - - @property - def opener(self): - self.ui.deprecwarn("use 'repo.vfs' instead of 'repo.opener'", '4.2') - return self.vfs - def close(self): self._writecaches() @@ -649,11 +639,6 @@ """ return hook.hook(self.ui, self, name, throw, **args) - def tag(self, names, node, message, local, user, date, editor=False): - self.ui.deprecwarn("use 'tagsmod.tag' instead of 'repo.tag'", '4.2') - tagsmod.tag(self, names, node, message, local, user, date, - editor=editor) - @filteredpropertycache def _tagscache(self): '''Returns a tagscache object that contains various tags related @@ -841,10 +826,6 @@ return 'store' return None - def join(self, f, *insidef): - self.ui.deprecwarn("use 'repo.vfs.join' instead of 'repo.join'", '4.2') - return self.vfs.join(os.path.join(f, *insidef)) - def wjoin(self, f, *insidef): return self.vfs.reljoin(self.root, f, *insidef) @@ -884,15 +865,6 @@ def pathto(self, f, cwd=None): return self.dirstate.pathto(f, cwd) - def wfile(self, f, mode='r'): - self.ui.deprecwarn("use 'repo.wvfs' instead of 'repo.wfile'", '4.2') - return self.wvfs(f, mode) - - def _link(self, f): - self.ui.deprecwarn("use 'repo.wvfs.islink' instead of 'repo._link'", - '4.2') - return self.wvfs.islink(f) - def _loadfilter(self, filter): if filter not in self.filterpats: l = []
--- a/mercurial/manifest.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/manifest.py Fri May 12 11:20:25 2017 -0700 @@ -1317,8 +1317,7 @@ cachesize = opts.get('manifestcachesize', cachesize) self._treeinmem = usetreemanifest - self._oldmanifest = repo._constructmanifest() - self._revlog = self._oldmanifest + self._revlog = repo._constructmanifest() # A cache of the manifestctx or treemanifestctx for each directory self._dirmancache = {} @@ -1340,12 +1339,7 @@ the revlog """ if node in self._dirmancache.get(dir, ()): - cachemf = self._dirmancache[dir][node] - # The old manifest may put non-ctx manifests in the cache, so - # skip those since they don't implement the full api. - if (isinstance(cachemf, manifestctx) or - isinstance(cachemf, treemanifestctx)): - return cachemf + return self._dirmancache[dir][node] if dir: if self._revlog._treeondisk:
--- a/mercurial/match.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/match.py Fri May 12 11:20:25 2017 -0700 @@ -52,7 +52,7 @@ return fset, other def _expandsubinclude(kindpats, root): - '''Returns the list of subinclude matchers and the kindpats without the + '''Returns the list of subinclude matcher args and the kindpats without the subincludes in it.''' relmatchers = [] other = [] @@ -64,12 +64,12 @@ path = pathutil.join(sourceroot, pat) newroot = pathutil.dirname(path) - relmatcher = match(newroot, '', [], ['include:%s' % path]) + matcherargs = (newroot, '', [], ['include:%s' % path]) prefix = pathutil.canonpath(root, root, newroot) if prefix: prefix += '/' - relmatchers.append((prefix, relmatcher)) + relmatchers.append((prefix, matcherargs)) else: other.append((kind, pat, source)) @@ -134,7 +134,7 @@ self._includeroots = set() self._excluderoots = set() # dirs are directories which are non-recursively included. - self._includedirs = set(['.']) + self._includedirs = set() if badfn is not None: self.bad = badfn @@ -254,7 +254,7 @@ return 'all' if dir in self._excluderoots: return False - if ((self._includeroots or self._includedirs != set(['.'])) and + if ((self._includeroots or self._includedirs) and '.' not in self._includeroots and dir not in self._includeroots and dir not in self._includedirs and @@ -584,10 +584,17 @@ subincludes, kindpats = _expandsubinclude(kindpats, root) if subincludes: + submatchers = {} def matchsubinclude(f): - for prefix, mf in subincludes: - if f.startswith(prefix) and mf(f[len(prefix):]): - return True + for prefix, matcherargs in subincludes: + if f.startswith(prefix): + mf = submatchers.get(prefix) + if mf is None: + mf = match(*matcherargs) + submatchers[prefix] = mf + + if mf(f[len(prefix):]): + return True return False matchfuncs.append(matchsubinclude) @@ -677,16 +684,16 @@ >>> _rootsanddirs(\ [('glob', 'g/h/*', ''), ('glob', 'g/h', ''), ('glob', 'g*', '')]) - (['g/h', 'g/h', '.'], ['g']) + (['g/h', 'g/h', '.'], ['g', '.']) >>> _rootsanddirs(\ [('rootfilesin', 'g/h', ''), ('rootfilesin', '', '')]) - ([], ['g/h', '.', 'g']) + ([], ['g/h', '.', 'g', '.']) >>> _rootsanddirs(\ [('relpath', 'r', ''), ('path', 'p/p', ''), ('path', '', '')]) - (['r', 'p/p', '.'], ['p']) + (['r', 'p/p', '.'], ['p', '.']) >>> _rootsanddirs(\ [('relglob', 'rg*', ''), ('re', 're/', ''), ('relre', 'rr', '')]) - (['.', '.', '.'], []) + (['.', '.', '.'], ['.']) ''' r, d = _patternrootsanddirs(kindpats) @@ -694,6 +701,8 @@ # scanned to get to either the roots or the other exact directories. d.extend(util.dirs(d)) d.extend(util.dirs(r)) + # util.dirs() does not include the root directory, so add it manually + d.append('.') return r, d
--- a/mercurial/mdiff.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/mdiff.py Fri May 12 11:20:25 2017 -0700 @@ -13,7 +13,6 @@ from .i18n import _ from . import ( - base85, bdiff, error, mpatch, @@ -21,6 +20,12 @@ util, ) +blocks = bdiff.blocks +fixws = bdiff.fixws +patches = mpatch.patches +patchedsize = mpatch.patchedsize +textdiff = bdiff.bdiff + def splitnewlines(text): '''like str.splitlines, but only split on newlines.''' lines = [l + '\n' for l in text.split('\n')] @@ -426,7 +431,7 @@ l = chr(ord('A') + l - 1) else: l = chr(l - 26 + ord('a') - 1) - return '%c%s\n' % (l, base85.b85encode(line, True)) + return '%c%s\n' % (l, util.b85encode(line, True)) def chunk(text, csize=52): l = len(text) @@ -478,7 +483,3 @@ def replacediffheader(oldlen, newlen): return struct.pack(">lll", 0, oldlen, newlen) - -patches = mpatch.patches -patchedsize = mpatch.patchedsize -textdiff = bdiff.bdiff
--- a/mercurial/merge.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/merge.py Fri May 12 11:20:25 2017 -0700 @@ -786,7 +786,7 @@ return True def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher, - acceptremote, followcopies): + acceptremote, followcopies, forcefulldiff=False): """ Merge wctx and p2 with ancestor pa and generate merge action list @@ -821,6 +821,26 @@ if any(wctx.sub(s).dirty() for s in wctx.substate): m1['.hgsubstate'] = modifiednodeid + # Don't use m2-vs-ma optimization if: + # - ma is the same as m1 or m2, which we're just going to diff again later + # - The matcher is set already, so we can't override it + # - The caller specifically asks for a full diff, which is useful during bid + # merge. + if (pa not in ([wctx, p2] + wctx.parents()) and + matcher is None and not forcefulldiff): + # Identify which files are relevant to the merge, so we can limit the + # total m1-vs-m2 diff to just those files. This has significant + # performance benefits in large repositories. + relevantfiles = set(ma.diff(m2).keys()) + + # For copied and moved files, we need to add the source file too. + for copykey, copyvalue in copy.iteritems(): + if copyvalue in relevantfiles: + relevantfiles.add(copykey) + for movedirkey in movewithdir.iterkeys(): + relevantfiles.add(movedirkey) + matcher = scmutil.matchfiles(repo, relevantfiles) + diff = m1.diff(m2, match=matcher) if matcher is None: @@ -974,7 +994,7 @@ repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor) actions, diverge1, renamedelete1 = manifestmerge( repo, wctx, mctx, ancestor, branchmerge, force, matcher, - acceptremote, followcopies) + acceptremote, followcopies, forcefulldiff=True) _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce) # Track the shortest set of warning on the theory that bid
--- a/mercurial/obsolete.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/obsolete.py Fri May 12 11:20:25 2017 -0700 @@ -74,7 +74,6 @@ from .i18n import _ from . import ( - base85, error, node, parsers, @@ -744,7 +743,7 @@ currentlen += len(nextdata) for idx, part in enumerate(reversed(parts)): data = ''.join([_pack('>B', _fm0version)] + part) - keys['dump%i' % idx] = base85.b85encode(data) + keys['dump%i' % idx] = util.b85encode(data) return keys def listmarkers(repo): @@ -761,7 +760,7 @@ if old: repo.ui.warn(_('unexpected old value for %r') % key) return 0 - data = base85.b85decode(new) + data = util.b85decode(new) lock = repo.lock() try: tr = repo.transaction('pushkey: obsolete markers')
--- a/mercurial/patch.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/patch.py Fri May 12 11:20:25 2017 -0700 @@ -26,7 +26,6 @@ short, ) from . import ( - base85, copies, diffhelpers, encoding, @@ -1430,7 +1429,7 @@ else: l = ord(l) - ord('a') + 27 try: - dec.append(base85.b85decode(line[1:])[:l]) + dec.append(util.b85decode(line[1:])[:l]) except ValueError as e: raise PatchError(_('could not decode "%s" binary patch: %s') % (self._fname, str(e))) @@ -2508,6 +2507,9 @@ revinfo = ' '.join(["-r %s" % rev for rev in revs]) return 'diff %s %s' % (revinfo, f) + def isempty(fctx): + return fctx is None or fctx.size() == 0 + date1 = util.datestr(ctx1.date()) date2 = util.datestr(ctx2.date()) @@ -2523,28 +2525,30 @@ for f1, f2, copyop in _filepairs(modified, added, removed, copy, opts): content1 = None content2 = None + fctx1 = None + fctx2 = None flag1 = None flag2 = None if f1: - content1 = getfilectx(f1, ctx1).data() + fctx1 = getfilectx(f1, ctx1) if opts.git or losedatafn: flag1 = ctx1.flags(f1) if f2: - content2 = getfilectx(f2, ctx2).data() + fctx2 = getfilectx(f2, ctx2) if opts.git or losedatafn: flag2 = ctx2.flags(f2) - binary = False - if opts.git or losedatafn: - binary = util.binary(content1) or util.binary(content2) + # if binary is True, output "summary" or "base85", but not "text diff" + binary = not opts.text and any(f.isbinary() + for f in [fctx1, fctx2] if f is not None) if losedatafn and not opts.git: if (binary or # copy/rename f2 in copy or # empty file creation - (not f1 and not content2) or + (not f1 and isempty(fctx2)) or # empty file deletion - (not content1 and not f2) or + (isempty(fctx1) and not f2) or # create with flags (not f1 and flag2) or # change flags @@ -2577,7 +2581,37 @@ elif revs and not repo.ui.quiet: header.append(diffline(path1, revs)) - if binary and opts.git and not opts.nobinary and not opts.text: + # fctx.is | diffopts | what to | is fctx.data() + # binary() | text nobinary git index | output? | outputted? + # ------------------------------------|---------------------------- + # yes | no no no * | summary | no + # yes | no no yes * | base85 | yes + # yes | no yes no * | summary | no + # yes | no yes yes 0 | summary | no + # yes | no yes yes >0 | summary | semi [1] + # yes | yes * * * | text diff | yes + # no | * * * * | text diff | yes + # [1]: hash(fctx.data()) is outputted. so fctx.data() cannot be faked + if binary and (not opts.git or (opts.git and opts.nobinary and not + opts.index)): + # fast path: no binary content will be displayed, content1 and + # content2 are only used for equivalent test. cmp() could have a + # fast path. + if fctx1 is not None: + content1 = b'\0' + if fctx2 is not None: + if fctx1 is not None and not fctx1.cmp(fctx2): + content2 = b'\0' # not different + else: + content2 = b'\0\0' + else: + # normal path: load contents + if fctx1 is not None: + content1 = fctx1.data() + if fctx2 is not None: + content2 = fctx2.data() + + if binary and opts.git and not opts.nobinary: text = mdiff.b85diff(content1, content2) if text: header.append('index %s..%s' %
--- a/mercurial/policy.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/policy.py Fri May 12 11:20:25 2017 -0700 @@ -33,8 +33,8 @@ # # The canonical way to do this is to test platform.python_implementation(). # But we don't import platform and don't bloat for it here. -if '__pypy__' in sys.builtin_module_names: - policy = 'cffi' +if r'__pypy__' in sys.builtin_module_names: + policy = b'cffi' # Our C extensions aren't yet compatible with Python 3. So use pure Python # on Python 3 for now. @@ -43,7 +43,7 @@ # Environment variable can always force settings. if sys.version_info[0] >= 3: - if 'HGMODULEPOLICY' in os.environ: - policy = os.environ['HGMODULEPOLICY'].encode('utf-8') + if r'HGMODULEPOLICY' in os.environ: + policy = os.environ[r'HGMODULEPOLICY'].encode(r'utf-8') else: - policy = os.environ.get('HGMODULEPOLICY', policy) + policy = os.environ.get(r'HGMODULEPOLICY', policy)
--- a/mercurial/posix.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/posix.py Fri May 12 11:20:25 2017 -0700 @@ -494,7 +494,7 @@ def getuser(): '''return name of current user''' - return getpass.getuser() + return pycompat.fsencode(getpass.getuser()) def username(uid=None): """Return the name of the user with the given uid.
--- a/mercurial/pvec.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/pvec.py Fri May 12 11:20:25 2017 -0700 @@ -52,7 +52,6 @@ from .node import nullrev from . import ( - base85, util, ) @@ -166,13 +165,13 @@ else: pvc[n] = _mergevec(pvc[p1], pvc[p2], node) bs = _join(*pvc[ctx.rev()]) - return pvec(base85.b85encode(bs)) + return pvec(util.b85encode(bs)) class pvec(object): def __init__(self, hashorctx): if isinstance(hashorctx, str): self._bs = hashorctx - self._depth, self._vec = _split(base85.b85decode(hashorctx)) + self._depth, self._vec = _split(util.b85decode(hashorctx)) else: self._vec = ctxpvec(hashorctx)
--- a/mercurial/pycompat.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/pycompat.py Fri May 12 11:20:25 2017 -0700 @@ -164,6 +164,10 @@ return s return s.decode(u'latin-1') + def raisewithtb(exc, tb): + """Raise exception with the given traceback""" + raise exc.with_traceback(tb) + def _wrapattrfunc(f): @functools.wraps(f) def w(object, name, *args): @@ -224,6 +228,10 @@ sysbytes = identity sysstr = identity + # this can't be parsed on Python 3 + exec('def raisewithtb(exc, tb):\n' + ' raise exc, None, tb\n') + # Partial backport from os.py in Python 3, which only accepts bytes. # In Python 2, our paths should only ever be bytes, a unicode path # indicates a bug.
--- a/mercurial/rcutil.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/rcutil.py Fri May 12 11:20:25 2017 -0700 @@ -11,7 +11,6 @@ from . import ( encoding, - osutil, pycompat, util, ) @@ -30,7 +29,7 @@ p = util.expandpath(path) if os.path.isdir(p): join = os.path.join - return [join(p, f) for f, k in osutil.listdir(p) if f.endswith('.rc')] + return [join(p, f) for f, k in util.listdir(p) if f.endswith('.rc')] return [p] def envrcitems(env=None):
--- a/mercurial/repair.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/repair.py Fri May 12 11:20:25 2017 -0700 @@ -165,13 +165,8 @@ tr.startgroup() cl.strip(striprev, tr) mfst.strip(striprev, tr) - if 'treemanifest' in repo.requirements: # safe but unnecessary - # otherwise - for unencoded, encoded, size in repo.store.datafiles(): - if (unencoded.startswith('meta/') and - unencoded.endswith('00manifest.i')): - dir = unencoded[5:-12] - repo.manifestlog._revlog.dirlog(dir).strip(striprev, tr) + striptrees(repo, tr, striprev, files) + for fn in files: repo.file(fn).strip(striprev, tr) tr.endgroup() @@ -240,6 +235,16 @@ # extensions can use it return backupfile +def striptrees(repo, tr, striprev, files): + if 'treemanifest' in repo.requirements: # safe but unnecessary + # otherwise + treerevlog = repo.manifestlog._revlog + for dir in util.dirs(files): + # If the revlog doesn't exist, this returns an empty revlog and is a + # no-op. + rl = treerevlog.dirlog(dir) + rl.strip(striprev, tr) + def rebuildfncache(ui, repo): """Rebuilds the fncache file from repo history.
--- a/mercurial/revlog.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/revlog.py Fri May 12 11:20:25 2017 -0700 @@ -1075,7 +1075,7 @@ p1, p2 = self.parents(node) return hash(text, p1, p2) != node - def _addchunk(self, offset, data): + def _cachesegment(self, offset, data): """Add a segment to the revlog cache. Accepts an absolute offset and the data that is at that location. @@ -1087,7 +1087,7 @@ else: self._chunkcache = offset, data - def _loadchunk(self, offset, length, df=None): + def _readsegment(self, offset, length, df=None): """Load a segment of raw data from the revlog. Accepts an absolute offset, length to read, and an optional existing @@ -1118,12 +1118,12 @@ d = df.read(reallength) if closehandle: df.close() - self._addchunk(realoffset, d) + self._cachesegment(realoffset, d) if offset != realoffset or reallength != length: return util.buffer(d, offset - realoffset, length) return d - def _getchunk(self, offset, length, df=None): + def _getsegment(self, offset, length, df=None): """Obtain a segment of raw data from the revlog. Accepts an absolute offset, length of bytes to obtain, and an @@ -1145,9 +1145,9 @@ return d # avoid a copy return util.buffer(d, cachestart, cacheend - cachestart) - return self._loadchunk(offset, length, df=df) + return self._readsegment(offset, length, df=df) - def _chunkraw(self, startrev, endrev, df=None): + def _getsegmentforrevs(self, startrev, endrev, df=None): """Obtain a segment of raw data corresponding to a range of revisions. Accepts the start and end revisions and an optional already-open @@ -1179,7 +1179,7 @@ end += (endrev + 1) * self._io.size length = end - start - return start, self._getchunk(start, length, df=df) + return start, self._getsegment(start, length, df=df) def _chunk(self, rev, df=None): """Obtain a single decompressed chunk for a revision. @@ -1190,7 +1190,7 @@ Returns a str holding uncompressed data for the requested revision. """ - return self.decompress(self._chunkraw(rev, rev, df=df)[1]) + return self.decompress(self._getsegmentforrevs(rev, rev, df=df)[1]) def _chunks(self, revs, df=None): """Obtain decompressed chunks for the specified revisions. @@ -1217,7 +1217,7 @@ ladd = l.append try: - offset, data = self._chunkraw(revs[0], revs[-1], df=df) + offset, data = self._getsegmentforrevs(revs[0], revs[-1], df=df) except OverflowError: # issue4215 - we can't cache a run of chunks greater than # 2G on Windows @@ -1443,7 +1443,7 @@ df = self.opener(self.datafile, 'w') try: for r in self: - df.write(self._chunkraw(r, r)[1]) + df.write(self._getsegmentforrevs(r, r)[1]) finally: df.close() @@ -1502,6 +1502,15 @@ if validatehash: self.checkhash(rawtext, node, p1=p1, p2=p2) + return self.addrawrevision(rawtext, transaction, link, p1, p2, node, + flags, cachedelta=cachedelta) + + def addrawrevision(self, rawtext, transaction, link, p1, p2, node, flags, + cachedelta=None): + """add a raw revision with known flags, node and parents + useful when reusing a revision not stored in this revlog (ex: received + over wire, or read from an external bundle). + """ dfh = None if not self._inline: dfh = self.opener(self.datafile, "a+")
--- a/mercurial/scmposix.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/scmposix.py Fri May 12 11:20:25 2017 -0700 @@ -8,8 +8,8 @@ from . import ( encoding, - osutil, pycompat, + util, ) # BSD 'more' escapes ANSI color sequences by default. This can be disabled by @@ -23,7 +23,7 @@ rcdir = os.path.join(path, 'hgrc.d') try: rcs.extend([os.path.join(rcdir, f) - for f, kind in osutil.listdir(rcdir) + for f, kind in util.listdir(rcdir) if f.endswith(".rc")]) except OSError: pass
--- a/mercurial/scmutil.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/scmutil.py Fri May 12 11:20:25 2017 -0700 @@ -26,7 +26,6 @@ revsetlang, similar, util, - vfs as vfsmod, ) if pycompat.osname == 'nt': @@ -121,10 +120,6 @@ secretlist = [] if excluded: for n in excluded: - if n not in repo: - # discovery should not have included the filtered revision, - # we have to explicitly exclude it until discovery is cleanup. - continue ctx = repo[n] if ctx.phase() >= phases.secret and not ctx.extinct(): secretlist.append(n) @@ -186,8 +181,6 @@ ui.warn(_("abort: file censored %s!\n") % inst) except error.RevlogError as inst: ui.warn(_("abort: %s!\n") % inst) - except error.SignalInterrupt: - ui.warn(_("killed!\n")) except error.InterventionRequired as inst: ui.warn("%s\n" % inst) if inst.hint: @@ -215,7 +208,7 @@ reason = inst.reason if isinstance(reason, unicode): # SSLError of Python 2.7.9 contains a unicode - reason = reason.encode(encoding.encoding, 'replace') + reason = encoding.unitolocal(reason) ui.warn(_("abort: error: %s\n") % reason) elif (util.safehasattr(inst, "args") and inst.args and inst.args[0] == errno.EPIPE): @@ -335,27 +328,6 @@ key = s.digest() return key -def _deprecated(old, new, func): - msg = ('class at mercurial.scmutil.%s moved to mercurial.vfs.%s' - % (old, new)) - def wrapper(*args, **kwargs): - util.nouideprecwarn(msg, '4.2') - return func(*args, **kwargs) - return wrapper - -# compatibility layer since all 'vfs' code moved to 'mercurial.vfs' -# -# This is hard to instal deprecation warning to this since we do not have -# access to a 'ui' object. -opener = _deprecated('opener', 'vfs', vfsmod.vfs) -vfs = _deprecated('vfs', 'vfs', vfsmod.vfs) -filteropener = _deprecated('filteropener', 'filtervfs', vfsmod.filtervfs) -filtervfs = _deprecated('filtervfs', 'filtervfs', vfsmod.filtervfs) -abstractvfs = _deprecated('abstractvfs', 'abstractvfs', vfsmod.abstractvfs) -readonlyvfs = _deprecated('readonlyvfs', 'readonlyvfs', vfsmod.readonlyvfs) -auditvfs = _deprecated('auditvfs', 'auditvfs', vfsmod.auditvfs) -checkambigatclosing = vfsmod.checkambigatclosing - def walkrepos(path, followsym=False, seen_dirs=None, recurse=False): '''yield every hg repository under path, always recursively. The recurse flag will only control recursion into repo working dirs'''
--- a/mercurial/scmwindows.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/scmwindows.py Fri May 12 11:20:25 2017 -0700 @@ -4,7 +4,6 @@ from . import ( encoding, - osutil, pycompat, util, win32, @@ -29,7 +28,7 @@ # Use hgrc.d found in directory with hg.exe progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d') if os.path.isdir(progrcd): - for f, kind in osutil.listdir(progrcd): + for f, kind in util.listdir(progrcd): if f.endswith('.rc'): rcpath.append(os.path.join(progrcd, f)) # else look for a system rcpath in the registry @@ -42,7 +41,7 @@ if p.lower().endswith('mercurial.ini'): rcpath.append(p) elif os.path.isdir(p): - for f, kind in osutil.listdir(p): + for f, kind in util.listdir(p): if f.endswith('.rc'): rcpath.append(os.path.join(p, f)) return rcpath
--- a/mercurial/similar.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/similar.py Fri May 12 11:20:25 2017 -0700 @@ -9,7 +9,6 @@ from .i18n import _ from . import ( - bdiff, mdiff, ) @@ -56,10 +55,10 @@ def _score(fctx, otherdata): orig, lines = otherdata text = fctx.data() - # bdiff.blocks() returns blocks of matching lines + # mdiff.blocks() returns blocks of matching lines # count the number of bytes in each equal = 0 - matches = bdiff.blocks(text, orig) + matches = mdiff.blocks(text, orig) for x1, x2, y1, y2 in matches: for line in lines[y1:y2]: equal += len(line)
--- a/mercurial/smartset.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/smartset.py Fri May 12 11:20:25 2017 -0700 @@ -245,7 +245,7 @@ @util.propertycache def _list(self): # _list is only lazily constructed if we have _set - assert '_set' in self.__dict__ + assert r'_set' in self.__dict__ return list(self._set) def __iter__(self):
--- a/mercurial/subrepo.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/subrepo.py Fri May 12 11:20:25 2017 -0700 @@ -1771,7 +1771,7 @@ if exact: rejected.append(f) continue - if not opts.get('dry_run'): + if not opts.get(r'dry_run'): self._gitcommand(command + [f]) for f in rejected: @@ -1878,9 +1878,9 @@ deleted, unknown, ignored, clean = [], [], [], [] command = ['status', '--porcelain', '-z'] - if opts.get('unknown'): + if opts.get(r'unknown'): command += ['--untracked-files=all'] - if opts.get('ignored'): + if opts.get(r'ignored'): command += ['--ignored'] out = self._gitcommand(command) @@ -1908,7 +1908,7 @@ elif st == '!!': ignored.append(filename1) - if opts.get('clean'): + if opts.get(r'clean'): out = self._gitcommand(['ls-files']) for f in out.split('\n'): if not f in changedfiles: @@ -1921,7 +1921,7 @@ def diff(self, ui, diffopts, node2, match, prefix, **opts): node1 = self._state[1] cmd = ['diff', '--no-renames'] - if opts['stat']: + if opts[r'stat']: cmd.append('--stat') else: # for Git, this also implies '-p' @@ -1964,7 +1964,7 @@ @annotatesubrepoerror def revert(self, substate, *pats, **opts): self.ui.status(_('reverting subrepo %s\n') % substate[0]) - if not opts.get('no_backup'): + if not opts.get(r'no_backup'): status = self.status(None) names = status.modified for name in names: @@ -1973,7 +1973,7 @@ (name, bakname)) self.wvfs.rename(name, bakname) - if not opts.get('dry_run'): + if not opts.get(r'dry_run'): self.get(substate, overwrite=True) return []
--- a/mercurial/templatefilters.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/templatefilters.py Fri May 12 11:20:25 2017 -0700 @@ -16,6 +16,7 @@ encoding, hbisect, node, + pycompat, registrar, templatekw, util, @@ -24,6 +25,9 @@ urlerr = util.urlerr urlreq = util.urlreq +if pycompat.ispy3: + long = int + # filters are callables like: # fn(obj) # with: @@ -226,8 +230,8 @@ elif obj is True: return 'true' elif isinstance(obj, (int, long, float)): - return str(obj) - elif isinstance(obj, str): + return pycompat.bytestr(obj) + elif isinstance(obj, bytes): return '"%s"' % encoding.jsonescape(obj, paranoid=paranoid) elif util.safehasattr(obj, 'keys'): out = ['%s: %s' % (json(k), json(v)) @@ -351,11 +355,11 @@ text and concatenating them. """ thing = templatekw.unwraphybrid(thing) - if util.safehasattr(thing, '__iter__') and not isinstance(thing, str): + if util.safehasattr(thing, '__iter__') and not isinstance(thing, bytes): return "".join([stringify(t) for t in thing if t is not None]) if thing is None: return "" - return str(thing) + return pycompat.bytestr(thing) @templatefilter('stripdir') def stripdir(text):
--- a/mercurial/templater.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/templater.py Fri May 12 11:20:25 2017 -0700 @@ -53,6 +53,7 @@ """Parse a template expression into a stream of tokens, which must end with term if specified""" pos = start + program = pycompat.bytestr(program) while pos < end: c = program[pos] if c.isspace(): # skip inter-token whitespace
--- a/mercurial/util.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/util.py Fri May 12 11:20:25 2017 -0700 @@ -42,6 +42,7 @@ import zlib from . import ( + base85, encoding, error, i18n, @@ -50,6 +51,9 @@ pycompat, ) +b85decode = base85.b85decode +b85encode = base85.b85encode + cookielib = pycompat.cookielib empty = pycompat.empty httplib = pycompat.httplib @@ -102,6 +106,7 @@ hidewindow = platform.hidewindow isexec = platform.isexec isowner = platform.isowner +listdir = osutil.listdir localpath = platform.localpath lookupreg = platform.lookupreg makedir = platform.makedir @@ -139,6 +144,15 @@ unlink = platform.unlink username = platform.username +try: + recvfds = osutil.recvfds +except AttributeError: + pass +try: + setprocname = osutil.setprocname +except AttributeError: + pass + # Python compatibility _notset = object() @@ -1161,7 +1175,7 @@ os.stat(os.path.dirname(dst)).st_dev) topic = gettopic() os.mkdir(dst) - for name, kind in osutil.listdir(src): + for name, kind in listdir(src): srcname = os.path.join(src, name) dstname = os.path.join(dst, name) def nprog(t, pos): @@ -1724,8 +1738,7 @@ iterator over chunks of arbitrary size.""" def __init__(self, in_iter): - """in_iter is the iterator that's iterating over the input chunks. - targetsize is how big a buffer to try to maintain.""" + """in_iter is the iterator that's iterating over the input chunks.""" def splitbig(chunks): for chunk in chunks: if len(chunk) > 2**20: @@ -1914,6 +1927,7 @@ # add missing elements from defaults usenow = False # default to using biased defaults for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity + part = pycompat.bytestr(part) found = [True for p in part if ("%"+p) in format] if not found: date += "@" + defaults[part][usenow] @@ -1981,13 +1995,13 @@ # this piece is for rounding the specific end of unknowns b = bias.get(part) if b is None: - if part[0] in "HMS": + if part[0:1] in "HMS": b = "00" else: b = "0" # this piece is for matching the generic end to today's date - n = datestr(now, "%" + part[0]) + n = datestr(now, "%" + part[0:1]) defaults[part] = (b, n)
--- a/mercurial/vfs.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/vfs.py Fri May 12 11:20:25 2017 -0700 @@ -17,7 +17,6 @@ from .i18n import _ from . import ( error, - osutil, pathutil, pycompat, util, @@ -163,7 +162,7 @@ return fd, fname def readdir(self, path=None, stat=None, skip=None): - return osutil.listdir(self.join(path), stat, skip) + return util.listdir(self.join(path), stat, skip) def readlock(self, path): return util.readlock(self.join(path))
--- a/mercurial/windows.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/windows.py Fri May 12 11:20:25 2017 -0700 @@ -136,6 +136,9 @@ # convert to a friendlier exception raise IOError(err.errno, '%s: %s' % (name, err.strerror)) +# may be wrapped by win32mbcs extension +listdir = osutil.listdir + class winstdout(object): '''stdout on windows misbehaves if sent through a pipe''' @@ -349,7 +352,7 @@ if cache is None: try: dmap = dict([(normcase(n), s) - for n, k, s in osutil.listdir(dir, True) + for n, k, s in listdir(dir, True) if getkind(s.st_mode) in _wantedkinds]) except OSError as err: # Python >= 2.5 returns ENOENT and adds winerror field @@ -376,7 +379,7 @@ def removedirs(name): """special version of os.removedirs that does not remove symlinked directories or junction points if they actually contain files""" - if osutil.listdir(name): + if listdir(name): return os.rmdir(name) head, tail = os.path.split(name) @@ -384,7 +387,7 @@ head, tail = os.path.split(head) while head and tail: try: - if osutil.listdir(head): + if listdir(head): return os.rmdir(head) except (ValueError, OSError):
--- a/mercurial/worker.py Fri May 12 21:46:14 2017 +0900 +++ b/mercurial/worker.py Fri May 12 11:20:25 2017 -0700 @@ -134,37 +134,43 @@ killworkers() oldchldhandler = signal.signal(signal.SIGCHLD, sigchldhandler) ui.flush() + parentpid = os.getpid() for pargs in partition(args, workers): - pid = os.fork() - if pid == 0: - signal.signal(signal.SIGINT, oldhandler) - signal.signal(signal.SIGCHLD, oldchldhandler) - - def workerfunc(): - os.close(rfd) - for i, item in func(*(staticargs + (pargs,))): - os.write(wfd, '%d %s\n' % (i, item)) - return 0 + # make sure we use os._exit in all worker code paths. otherwise the + # worker may do some clean-ups which could cause surprises like + # deadlock. see sshpeer.cleanup for example. + # override error handling *before* fork. this is necessary because + # exception (signal) may arrive after fork, before "pid =" assignment + # completes, and other exception handler (dispatch.py) can lead to + # unexpected code path without os._exit. + ret = -1 + try: + pid = os.fork() + if pid == 0: + signal.signal(signal.SIGINT, oldhandler) + signal.signal(signal.SIGCHLD, oldchldhandler) - # make sure we use os._exit in all code paths. otherwise the worker - # may do some clean-ups which could cause surprises like deadlock. - # see sshpeer.cleanup for example. - ret = 0 - try: + def workerfunc(): + os.close(rfd) + for i, item in func(*(staticargs + (pargs,))): + os.write(wfd, '%d %s\n' % (i, item)) + return 0 + + ret = scmutil.callcatch(ui, workerfunc) + except: # parent re-raises, child never returns + if os.getpid() == parentpid: + raise + exctype = sys.exc_info()[0] + force = not issubclass(exctype, KeyboardInterrupt) + ui.traceback(force=force) + finally: + if os.getpid() != parentpid: try: - ret = scmutil.callcatch(ui, workerfunc) - finally: ui.flush() - except KeyboardInterrupt: - os._exit(255) - except: # never return, therefore no re-raises - try: - ui.traceback(force=True) - ui.flush() + except: # never returns, no re-raises + pass finally: - os._exit(255) - else: - os._exit(ret & 255) + os._exit(ret & 255) pids.add(pid) os.close(wfd) fp = os.fdopen(rfd, pycompat.sysstr('rb'), 0)
--- a/setup.py Fri May 12 21:46:14 2017 +0900 +++ b/setup.py Fri May 12 11:20:25 2017 -0700 @@ -5,8 +5,8 @@ # 'python setup.py --help' for more options import sys, platform -if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'): - raise SystemExit("Mercurial requires Python 2.6 or later.") +if sys.version_info < (2, 7, 0, 'final'): + raise SystemExit('Mercurial requires Python 2.7 or later.') if sys.version_info[0] >= 3: printf = eval('print') @@ -577,7 +577,10 @@ 'build_hgexe': buildhgexe, } -packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient', +packages = ['mercurial', + 'mercurial.cext', + 'mercurial.hgweb', + 'mercurial.httpclient', 'mercurial.pure', 'hgext', 'hgext.convert', 'hgext.fsmonitor', 'hgext.fsmonitor.pywatchman', 'hgext.highlight', @@ -586,6 +589,7 @@ common_depends = ['mercurial/bitmanipulation.h', 'mercurial/compat.h', 'mercurial/util.h'] +common_include_dirs = ['mercurial'] osutil_cflags = [] osutil_ldflags = [] @@ -615,21 +619,27 @@ extmodules = [ Extension('mercurial.base85', ['mercurial/base85.c'], + include_dirs=common_include_dirs, depends=common_depends), Extension('mercurial.bdiff', ['mercurial/bdiff.c', 'mercurial/bdiff_module.c'], + include_dirs=common_include_dirs, depends=common_depends + ['mercurial/bdiff.h']), Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'], + include_dirs=common_include_dirs, depends=common_depends), Extension('mercurial.mpatch', ['mercurial/mpatch.c', 'mercurial/mpatch_module.c'], + include_dirs=common_include_dirs, depends=common_depends), Extension('mercurial.parsers', ['mercurial/dirs.c', 'mercurial/manifest.c', 'mercurial/parsers.c', 'mercurial/pathencode.c'], + include_dirs=common_include_dirs, depends=common_depends), Extension('mercurial.osutil', ['mercurial/osutil.c'], + include_dirs=common_include_dirs, extra_compile_args=osutil_cflags, extra_link_args=osutil_ldflags, depends=common_depends),
--- a/tests/hghave.py Fri May 12 21:46:14 2017 +0900 +++ b/tests/hghave.py Fri May 12 11:20:25 2017 -0700 @@ -580,10 +580,6 @@ from mercurial import util return util.safehasattr(__future__, "absolute_import") -@check("py27+", "running with Python 2.7+") -def has_python27ornewer(): - return sys.version_info[0:2] >= (2, 7) - @check("py3k", "running with Python 3.x") def has_py3k(): return 3 == sys.version_info[0]
--- a/tests/test-bdiff.py Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-bdiff.py Fri May 12 11:20:25 2017 -0700 @@ -4,8 +4,7 @@ import unittest from mercurial import ( - bdiff, - mpatch, + mdiff, ) class diffreplace( @@ -16,10 +15,10 @@ class BdiffTests(unittest.TestCase): def assert_bdiff_applies(self, a, b): - d = bdiff.bdiff(a, b) + d = mdiff.textdiff(a, b) c = a if d: - c = mpatch.patches(a, [d]) + c = mdiff.patches(a, [d]) self.assertEqual( c, b, ("bad diff+patch result from\n %r to\n " "%r: \nbdiff: %r\npatched: %r" % (a, b, d, c[:200]))) @@ -54,7 +53,7 @@ self.assert_bdiff(a, b) def showdiff(self, a, b): - bin = bdiff.bdiff(a, b) + bin = mdiff.textdiff(a, b) pos = 0 q = 0 actions = [] @@ -110,7 +109,7 @@ ("", "", 0), ] for a, b, allws in cases: - c = bdiff.fixws(a, allws) + c = mdiff.fixws(a, allws) self.assertEqual( c, b, 'fixws(%r) want %r got %r (allws=%r)' % (a, b, c, allws))
--- a/tests/test-bisect.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-bisect.t Fri May 12 11:20:25 2017 -0700 @@ -551,7 +551,14 @@ date: Thu Jan 01 00:00:06 1970 +0000 summary: msg 6 - + $ hg graft -q 15 + warning: conflicts while merging a! (edit, then use 'hg resolve --mark') + abort: unresolved conflicts, can't continue + (use 'hg resolve' and 'hg graft --continue') + [255] + $ hg bisect --reset + $ hg up -C . + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved Check that bisect does not break on obsolete changesets =========================================================
--- a/tests/test-bundle2-format.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-bundle2-format.t Fri May 12 11:20:25 2017 -0700 @@ -113,7 +113,7 @@ > headmissing = [c.node() for c in repo.set('heads(%ld)', revs)] > headcommon = [c.node() for c in repo.set('parents(%ld) - %ld', revs, revs)] > outgoing = discovery.outgoing(repo, headcommon, headmissing) - > cg = changegroup.getlocalchangegroup(repo, 'test:bundle2', outgoing, None) + > cg = changegroup.getchangegroup(repo, 'test:bundle2', outgoing) > bundler.newpart('changegroup', data=cg.getchunks(), > mandatory=False) >
--- a/tests/test-bundle2-multiple-changegroups.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-bundle2-multiple-changegroups.t Fri May 12 11:20:25 2017 -0700 @@ -13,13 +13,11 @@ > # in 'heads' as intermediate heads for the first changegroup. > intermediates = [repo[r].p1().node() for r in heads] > outgoing = discovery.outgoing(repo, common, intermediates) - > cg = changegroup.getchangegroup(repo, source, outgoing, - > bundlecaps=bundlecaps) + > cg = changegroup.getchangegroup(repo, source, outgoing) > bundler.newpart('output', data='changegroup1') > bundler.newpart('changegroup', data=cg.getchunks()) > outgoing = discovery.outgoing(repo, common + intermediates, heads) - > cg = changegroup.getchangegroup(repo, source, outgoing, - > bundlecaps=bundlecaps) + > cg = changegroup.getchangegroup(repo, source, outgoing) > bundler.newpart('output', data='changegroup2') > bundler.newpart('changegroup', data=cg.getchunks()) >
--- a/tests/test-check-code.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-check-code.t Fri May 12 11:20:25 2017 -0700 @@ -9,39 +9,11 @@ $ hg locate -X contrib/python-zstandard -X hgext/fsmonitor/pywatchman | > sed 's-\\-/-g' | "$check_code" --warnings --per-file=0 - || false - contrib/perf.py:869: - > r.revision(r.node(x)) - don't convert rev to node before passing to revision(nodeorrev) Skipping i18n/polib.py it has no-che?k-code (glob) - mercurial/demandimport.py:313: - > if os.environ.get('HGDEMANDIMPORT') != 'disable': - use encoding.environ instead (py3) - mercurial/encoding.py:54: - > environ = os.environ - use encoding.environ instead (py3) - mercurial/encoding.py:56: - > environ = os.environb - use encoding.environ instead (py3) - mercurial/encoding.py:61: - > for k, v in os.environ.items()) - use encoding.environ instead (py3) - mercurial/encoding.py:221: - > for k, v in os.environ.items()) - use encoding.environ instead (py3) Skipping mercurial/httpclient/__init__.py it has no-che?k-code (glob) Skipping mercurial/httpclient/_readers.py it has no-che?k-code (glob) - mercurial/policy.py:46: - > if 'HGMODULEPOLICY' in os.environ: - use encoding.environ instead (py3) - mercurial/policy.py:47: - > policy = os.environ['HGMODULEPOLICY'].encode('utf-8') - use encoding.environ instead (py3) - mercurial/policy.py:49: - > policy = os.environ.get('HGMODULEPOLICY', policy) - use encoding.environ instead (py3) Skipping mercurial/statprof.py it has no-che?k-code (glob) Skipping tests/badserverext.py it has no-che?k-code (glob) - [1] @commands in debugcommands.py should be in alphabetical order.
--- a/tests/test-check-py3-commands.t Fri May 12 21:46:14 2017 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -#require py3exe - -This test helps in keeping a track on which commands we can run on -Python 3 and see what kind of errors are coming up. -The full traceback is hidden to have a stable output. - $ HGBIN=`which hg` - - $ for cmd in version debuginstall ; do - > echo $cmd - > $PYTHON3 $HGBIN $cmd 2>&1 2>&1 | tail -1 - > done - version - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - debuginstall - no problems detected - -#if test-repo -Make a clone so that any features in the developer's .hg/hgrc that -might confuse Python 3 don't break this test. When we can do commit in -Python 3, we'll stop doing this. We use e76ed1e480ef for the clone -because it has different files than 273ce12ad8f1, so we can test both -`files` from dirstate and `files` loaded from a specific revision. - - $ hg clone -r e76ed1e480ef "`dirname "$TESTDIR"`" testrepo 2>&1 | tail -1 - 15 files updated, 0 files merged, 0 files removed, 0 files unresolved - -Test using -R, which exercises some URL code: - $ $PYTHON3 $HGBIN -R testrepo files -r 273ce12ad8f1 | tail -1 - testrepo/tkmerge - -Now prove `hg files` is reading the whole manifest. We have to grep -out some potential warnings that come from hgrc as yet. - $ cd testrepo - $ $PYTHON3 $HGBIN files -r 273ce12ad8f1 - .hgignore - PKG-INFO - README - hg - mercurial/__init__.py - mercurial/byterange.py - mercurial/fancyopts.py - mercurial/hg.py - mercurial/mdiff.py - mercurial/revlog.py - mercurial/transaction.py - notes.txt - setup.py - tkmerge - - $ $PYTHON3 $HGBIN files -r 273ce12ad8f1 | wc -l - \s*14 (re) - $ $PYTHON3 $HGBIN files | wc -l - \s*15 (re) - -Test if log-like commands work: - - $ $PYTHON3 $HGBIN tip - changeset: 10:e76ed1e480ef - tag: tip - user: oxymoron@cinder.waste.org - date: Tue May 03 23:37:43 2005 -0800 - summary: Fix linking of changeset revs when merging - - - $ $PYTHON3 $HGBIN log -r0 - changeset: 0:9117c6561b0b - user: mpm@selenic.com - date: Tue May 03 13:16:10 2005 -0800 - summary: Add back links from file revisions to changeset revisions - - - $ cd .. -#endif - -Test if `hg config` works: - - $ $PYTHON3 $HGBIN config - defaults.backout=-d "0 0" - defaults.commit=-d "0 0" - defaults.shelve=--date "0 0" - defaults.tag=-d "0 0" - devel.all-warnings=true - largefiles.usercache=$TESTTMP/.cache/largefiles - ui.slash=True - ui.interactive=False - ui.mergemarkers=detailed - ui.promptecho=True - web.address=localhost - web.ipv6=False - - $ cat > included-hgrc <<EOF - > [extensions] - > babar = imaginary_elephant - > EOF - $ cat >> $HGRCPATH <<EOF - > %include $TESTTMP/included-hgrc - > EOF - $ $PYTHON3 $HGBIN version | tail -1 - *** failed to import extension babar from imaginary_elephant: *: 'imaginary_elephant' (glob) - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - $ rm included-hgrc - $ touch included-hgrc - -Test bytes-ness of policy.policy with HGMODULEPOLICY - - $ HGMODULEPOLICY=py - $ export HGMODULEPOLICY - $ $PYTHON3 `which hg` debuginstall 2>&1 2>&1 | tail -1 - no problems detected - -`hg init` can create empty repos -`hg status works fine` -`hg summary` also works! - - $ $PYTHON3 `which hg` init py3repo - $ cd py3repo - $ echo "This is the file 'iota'." > iota - $ $PYTHON3 $HGBIN status - ? iota - $ $PYTHON3 $HGBIN add iota - $ $PYTHON3 $HGBIN status - A iota - $ $PYTHON3 $HGBIN commit --message 'commit performed in Python 3' - $ $PYTHON3 $HGBIN status - - $ mkdir A - $ echo "This is the file 'mu'." > A/mu - $ $PYTHON3 $HGBIN addremove - adding A/mu - $ $PYTHON3 $HGBIN status - A A/mu - $ HGEDITOR='echo message > ' $PYTHON3 $HGBIN commit - $ $PYTHON3 $HGBIN status - $ $PYHON3 $HGBIN summary - parent: 1:e1e9167203d4 tip - message - branch: default - commit: (clean) - update: (current) - phases: 2 draft - -Prove the repo is valid using the Python 2 `hg`: - $ hg verify - checking changesets - checking manifests - crosschecking files in changesets and manifests - checking files - 2 files, 2 changesets, 2 total revisions - $ hg log - changeset: 1:e1e9167203d4 - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: message - - changeset: 0:71c96e924262 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: commit performed in Python 3 -
--- a/tests/test-commit-interactive-curses.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-commit-interactive-curses.t Fri May 12 11:20:25 2017 -0700 @@ -343,7 +343,7 @@ $ cp $HGRCPATH.pretest $HGRCPATH $ chunkselectorinterface() { > python <<EOF - > from mercurial import hg, ui, parsers;\ + > from mercurial import hg, ui;\ > repo = hg.repository(ui.ui.load(), ".");\ > print repo.ui.interface("chunkselector") > EOF
--- a/tests/test-contrib-perf.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-contrib-perf.t Fri May 12 11:20:25 2017 -0700 @@ -165,7 +165,3 @@ $ (hg files -r 1.2 glob:mercurial/*.c glob:mercurial/*.py; > hg files -r tip glob:mercurial/*.c glob:mercurial/*.py) | > "$TESTDIR"/check-perf-code.py contrib/perf.py - contrib/perf.py:869: - > r.revision(r.node(x)) - don't convert rev to node before passing to revision(nodeorrev) - [1]
--- a/tests/test-extdiff.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-extdiff.t Fri May 12 11:20:25 2017 -0700 @@ -62,15 +62,10 @@ Should diff cloned files directly: -#if windows $ hg falabala -r 0:1 - diffing "*\\extdiff.*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) + diffing "*\\extdiff.*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) (windows !) + diffing */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) (no-windows !) [1] -#else - $ hg falabala -r 0:1 - diffing */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) - [1] -#endif Specifying an empty revision should abort. @@ -92,41 +87,27 @@ Should diff cloned file against wc file: -#if windows $ hg falabala - diffing "*\\extdiff.*\\a.2a13a4d2da36\\a" "*\\a\\a" (glob) + diffing "*\\extdiff.*\\a.2a13a4d2da36\\a" "*\\a\\a" (glob) (windows !) + diffing */extdiff.*/a.2a13a4d2da36/a */a/a (glob) (no-windows !) [1] -#else - $ hg falabala - diffing */extdiff.*/a.2a13a4d2da36/a */a/a (glob) - [1] -#endif Test --change option: $ hg ci -d '2 0' -mtest3 -#if windows + $ hg falabala -c 1 - diffing "*\\extdiff.*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) + diffing "*\\extdiff.*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) (windows !) + diffing */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) (no-windows !) [1] -#else - $ hg falabala -c 1 - diffing */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) - [1] -#endif Check diff are made from the first parent: -#if windows $ hg falabala -c 3 || echo "diff-like tools yield a non-zero exit code" - diffing "*\\extdiff.*\\a.2a13a4d2da36\\a" "a.46c0e4daeb72\\a" (glob) + diffing "*\\extdiff.*\\a.2a13a4d2da36\\a" "a.46c0e4daeb72\\a" (glob) (windows !) + diffing */extdiff.*/a.2a13a4d2da36/a a.46c0e4daeb72/a (glob) (no-windows !) diff-like tools yield a non-zero exit code -#else - $ hg falabala -c 3 || echo "diff-like tools yield a non-zero exit code" - diffing */extdiff.*/a.2a13a4d2da36/a a.46c0e4daeb72/a (glob) - diff-like tools yield a non-zero exit code -#endif issue3153: ensure using extdiff with removed subrepos doesn't crash: @@ -158,21 +139,16 @@ > EOF $ hg update -q -C 0 $ echo a >> a -#if windows + $ hg --debug 4463a | grep '^running' - running 'echo a-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob) + running 'echo a-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob) (windows !) + running 'echo a-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob) (no-windows !) $ hg --debug 4463b | grep '^running' - running 'echo b-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob) + running 'echo b-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob) (windows !) + running 'echo b-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob) (no-windows !) $ hg --debug echo | grep '^running' - running '*echo* "*\\a" "*\\a"' in */extdiff.* (glob) -#else - $ hg --debug 4463a | grep '^running' - running 'echo a-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob) - $ hg --debug 4463b | grep '^running' - running 'echo b-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob) - $ hg --debug echo | grep '^running' - running '*echo */a $TESTTMP/a/a' in */extdiff.* (glob) -#endif + running '*echo* "*\\a" "*\\a"' in */extdiff.* (glob) (windows !) + running '*echo */a $TESTTMP/a/a' in */extdiff.* (glob) (no-windows !) (getting options from other than extdiff section) @@ -189,29 +165,22 @@ > [merge-tools] > 4463b3.diffargs = b3-naked 'single quoted' "double quoted" > EOF -#if windows + $ hg --debug 4463b2 | grep '^running' - running 'echo b2-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob) + running 'echo b2-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob) (windows !) + running 'echo b2-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob) (no-windows !) $ hg --debug 4463b3 | grep '^running' - running 'echo b3-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob) + running 'echo b3-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob) (windows !) + running 'echo b3-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob) (no-windows !) $ hg --debug 4463b4 | grep '^running' - running 'echo "*\\a" "*\\a"' in */extdiff.* (glob) + running 'echo "*\\a" "*\\a"' in */extdiff.* (glob) (windows !) + running 'echo */a $TESTTMP/a/a' in */extdiff.* (glob) (no-windows !) $ hg --debug 4463b4 --option b4-naked --option 'being quoted' | grep '^running' - running 'echo b4-naked "being quoted" "*\\a" "*\\a"' in */extdiff.* (glob) + running 'echo b4-naked "being quoted" "*\\a" "*\\a"' in */extdiff.* (glob) (windows !) + running "echo b4-naked 'being quoted' */a $TESTTMP/a/a" in */extdiff.* (glob) (no-windows !) $ hg --debug extdiff -p echo --option echo-naked --option 'being quoted' | grep '^running' - running 'echo echo-naked "being quoted" "*\\a" "*\\a"' in */extdiff.* (glob) -#else - $ hg --debug 4463b2 | grep '^running' - running 'echo b2-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob) - $ hg --debug 4463b3 | grep '^running' - running 'echo b3-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob) - $ hg --debug 4463b4 | grep '^running' - running 'echo */a $TESTTMP/a/a' in */extdiff.* (glob) - $ hg --debug 4463b4 --option b4-naked --option 'being quoted' | grep '^running' - running "echo b4-naked 'being quoted' */a $TESTTMP/a/a" in */extdiff.* (glob) - $ hg --debug extdiff -p echo --option echo-naked --option 'being quoted' | grep '^running' - running "echo echo-naked 'being quoted' */a $TESTTMP/a/a" in */extdiff.* (glob) -#endif + running 'echo echo-naked "being quoted" "*\\a" "*\\a"' in */extdiff.* (glob) (windows !) + running "echo echo-naked 'being quoted' */a $TESTTMP/a/a" in */extdiff.* (glob) (no-windows !) $ touch 'sp ace' $ hg add 'sp ace' @@ -228,12 +197,10 @@ > odd.diffargs = --foo='\$clabel' '\$clabel' "--bar=\$clabel" "\$clabel" > odd.executable = echo > EOF -#if windows -TODO -#else + $ hg --debug odd | grep '^running' - running "*/echo --foo='sp ace' 'sp ace' --bar='sp ace' 'sp ace'" in * (glob) -#endif + running '"*\\echo.exe" --foo="sp ace" "sp ace" --bar="sp ace" "sp ace"' in * (glob) (windows !) + running "*/echo --foo='sp ace' 'sp ace' --bar='sp ace' 'sp ace'" in * (glob) (no-windows !) Empty argument must be quoted @@ -243,22 +210,20 @@ > [merge-tools] > kdiff3.diffargs=--L1 \$plabel1 --L2 \$clabel \$parent \$child > EOF -#if windows - $ hg --debug kdiff3 -r0 | grep '^running' - running 'echo --L1 "@0" --L2 "" a.8a5febb7f867 a' in * (glob) -#else + $ hg --debug kdiff3 -r0 | grep '^running' - running "echo --L1 '@0' --L2 '' a.8a5febb7f867 a" in * (glob) -#endif + running 'echo --L1 "@0" --L2 "" a.8a5febb7f867 a' in * (glob) (windows !) + running "echo --L1 '@0' --L2 '' a.8a5febb7f867 a" in * (glob) (no-windows !) -#if execbit Test extdiff of multiple files in tmp dir: $ hg update -C 0 > /dev/null $ echo changed > a $ echo changed > b +#if execbit $ chmod +x b +#endif Diff in working directory, before: @@ -270,8 +235,8 @@ -a +changed diff --git a/b b/b - old mode 100644 - new mode 100755 + old mode 100644 (execbit !) + new mode 100755 (execbit !) --- a/b +++ b/b @@ -1,1 +1,1 @@ @@ -291,7 +256,9 @@ > file('a/b', 'ab').write('edited\n') > EOT +#if execbit $ chmod +x 'diff tool.py' +#endif will change to /tmp/extdiff.TMP and populate directories a.TMP and a and start tool @@ -310,8 +277,8 @@ +changed +edited diff --git a/b b/b - old mode 100644 - new mode 100755 + old mode 100644 (execbit !) + new mode 100755 (execbit !) --- a/b +++ b/b @@ -1,1 +1,2 @@ @@ -322,41 +289,67 @@ Test extdiff with --option: $ hg extdiff -p echo -o this -c 1 - this */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) + this "*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) (windows !) + this */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) (no-windows !) [1] $ hg falabala -o this -c 1 - diffing this */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) + diffing this "*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) (windows !) + diffing this */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) (no-windows !) [1] Test extdiff's handling of options with spaces in them: $ hg edspace -c 1 - name <user@example.com> */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) + "name <user@example.com>" "*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) (windows !) + name <user@example.com> */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) (no-windows !) [1] $ hg extdiff -p echo -o "name <user@example.com>" -c 1 - name <user@example.com> */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) + "name <user@example.com>" "*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) (windows !) + name <user@example.com> */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) (no-windows !) [1] Test with revsets: $ hg extdif -p echo -c "rev(1)" - */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) + "*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) (windows !) + */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) (no-windows !) [1] $ hg extdif -p echo -r "0::1" - */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) + "*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob) (windows !) + */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob) (no-windows !) [1] Fallback to merge-tools.tool.executable|regkey $ mkdir dir - $ cat > 'dir/tool.sh' << EOF + $ cat > 'dir/tool.sh' << 'EOF' > #!/bin/sh + > # Mimic a tool that syncs all attrs, including mtime + > cp $1/a $2/a + > touch -r $1/a $2/a > echo "** custom diff **" > EOF +#if execbit $ chmod +x dir/tool.sh +#endif + +Windows can't run *.sh directly, so create a shim executable that can be. +Without something executable, the next hg command will try to run `tl` instead +of $tool (and fail). +#if windows + $ cat > dir/tool.bat <<EOF + > @sh -c "`pwd`/dir/tool.sh %1 %2" + > EOF + $ tool=`pwd`/dir/tool.bat +#else $ tool=`pwd`/dir/tool.sh +#endif + + $ cat a + changed + edited $ hg --debug tl --config extdiff.tl= --config merge-tools.tl.executable=$tool making snapshot of 2 files from rev * (glob) a @@ -364,15 +357,17 @@ making snapshot of 2 files from working directory a b - running '$TESTTMP/a/dir/tool.sh a.* a' in */extdiff.* (glob) + running '$TESTTMP/a/dir/tool.bat a.* a' in */extdiff.* (glob) (windows !) + running '$TESTTMP/a/dir/tool.sh a.* a' in */extdiff.* (glob) (no-windows !) ** custom diff ** + file changed while diffing. Overwriting: $TESTTMP/a/a (src: */extdiff.*/a/a) (glob) cleaning up temp directory [1] + $ cat a + a $ cd .. -#endif - #if symlink Test symlinks handling (issue1909)
--- a/tests/test-graft.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-graft.t Fri May 12 11:20:25 2017 -0700 @@ -186,7 +186,6 @@ ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746 e: remote is newer -> g getting e - b: remote unchanged -> k committing files: e committing manifest @@ -203,7 +202,6 @@ preserving e for resolve of e d: remote is newer -> g getting d - b: remote unchanged -> k e: versions differ -> m (premerge) picked tool ':merge' for e (binary False symlink False changedelete False) merging e
--- a/tests/test-https.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-https.t Fri May 12 11:20:25 2017 -0700 @@ -333,20 +333,9 @@ > --config hostsecurity.disabletls10warning=true 5fed3813f7f5 -#if no-sslcontext no-py27+ -Setting ciphers doesn't work in Python 2.6 - $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/ - warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info - abort: setting ciphers in [hostsecurity] is not supported by this version of Python - (remove the config option or run Mercurial with a modern Python version (preferred)) - [255] -#endif +Error message for setting ciphers is different depending on SSLContext support -Setting ciphers works in Python 2.7+ but the error message is different on -legacy ssl. We test legacy once and do more feature checking on modern -configs. - -#if py27+ no-sslcontext +#if no-sslcontext $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/ warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info abort: *No cipher can be selected. (glob)
--- a/tests/test-install.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-install.t Fri May 12 11:20:25 2017 -0700 @@ -34,7 +34,7 @@ "editornotfound": false, "encoding": "ascii", "encodingerror": null, - "extensionserror": null, + "extensionserror": null, (no-pure !) "hgmodulepolicy": "*", (glob) "hgmodules": "*mercurial", (glob) "hgver": "*", (glob)
--- a/tests/test-issue672.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-issue672.t Fri May 12 11:20:25 2017 -0700 @@ -38,7 +38,6 @@ removing 1 1a: remote created -> g getting 1a - 2: remote unchanged -> k 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-py3-commands.t Fri May 12 11:20:25 2017 -0700 @@ -0,0 +1,201 @@ +#require py3exe + +This test helps in keeping a track on which commands we can run on +Python 3 and see what kind of errors are coming up. +The full traceback is hidden to have a stable output. + $ HGBIN=`which hg` + + $ for cmd in version debuginstall ; do + > echo $cmd + > $PYTHON3 $HGBIN $cmd 2>&1 2>&1 | tail -1 + > done + version + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + debuginstall + no problems detected + +#if test-repo +Make a clone so that any features in the developer's .hg/hgrc that +might confuse Python 3 don't break this test. When we can do commit in +Python 3, we'll stop doing this. We use e76ed1e480ef for the clone +because it has different files than 273ce12ad8f1, so we can test both +`files` from dirstate and `files` loaded from a specific revision. + + $ hg clone -r e76ed1e480ef "`dirname "$TESTDIR"`" testrepo 2>&1 | tail -1 + 15 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Test using -R, which exercises some URL code: + $ $PYTHON3 $HGBIN -R testrepo files -r 273ce12ad8f1 | tail -1 + testrepo/tkmerge + +Now prove `hg files` is reading the whole manifest. We have to grep +out some potential warnings that come from hgrc as yet. + $ cd testrepo + $ $PYTHON3 $HGBIN files -r 273ce12ad8f1 + .hgignore + PKG-INFO + README + hg + mercurial/__init__.py + mercurial/byterange.py + mercurial/fancyopts.py + mercurial/hg.py + mercurial/mdiff.py + mercurial/revlog.py + mercurial/transaction.py + notes.txt + setup.py + tkmerge + + $ $PYTHON3 $HGBIN files -r 273ce12ad8f1 | wc -l + \s*14 (re) + $ $PYTHON3 $HGBIN files | wc -l + \s*15 (re) + +Test if log-like commands work: + + $ $PYTHON3 $HGBIN tip + changeset: 10:e76ed1e480ef + tag: tip + user: oxymoron@cinder.waste.org + date: Tue May 03 23:37:43 2005 -0800 + summary: Fix linking of changeset revs when merging + + + $ $PYTHON3 $HGBIN log -r0 + changeset: 0:9117c6561b0b + user: mpm@selenic.com + date: Tue May 03 13:16:10 2005 -0800 + summary: Add back links from file revisions to changeset revisions + + + $ cd .. +#endif + +Test if `hg config` works: + + $ $PYTHON3 $HGBIN config + defaults.backout=-d "0 0" + defaults.commit=-d "0 0" + defaults.shelve=--date "0 0" + defaults.tag=-d "0 0" + devel.all-warnings=true + largefiles.usercache=$TESTTMP/.cache/largefiles + ui.slash=True + ui.interactive=False + ui.mergemarkers=detailed + ui.promptecho=True + web.address=localhost + web.ipv6=False + + $ cat > included-hgrc <<EOF + > [extensions] + > babar = imaginary_elephant + > EOF + $ cat >> $HGRCPATH <<EOF + > %include $TESTTMP/included-hgrc + > EOF + $ $PYTHON3 $HGBIN version | tail -1 + *** failed to import extension babar from imaginary_elephant: *: 'imaginary_elephant' (glob) + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + $ rm included-hgrc + $ touch included-hgrc + +Test bytes-ness of policy.policy with HGMODULEPOLICY + + $ HGMODULEPOLICY=py + $ export HGMODULEPOLICY + $ $PYTHON3 `which hg` debuginstall 2>&1 2>&1 | tail -1 + no problems detected + +`hg init` can create empty repos +`hg status works fine` +`hg summary` also works! + + $ $PYTHON3 `which hg` init py3repo + $ cd py3repo + $ echo "This is the file 'iota'." > iota + $ $PYTHON3 $HGBIN status + ? iota + $ $PYTHON3 $HGBIN add iota + $ $PYTHON3 $HGBIN status + A iota + $ $PYTHON3 $HGBIN commit --message 'commit performed in Python 3' + $ $PYTHON3 $HGBIN status + + $ mkdir A + $ echo "This is the file 'mu'." > A/mu + $ $PYTHON3 $HGBIN addremove + adding A/mu + $ $PYTHON3 $HGBIN status + A A/mu + $ HGEDITOR='echo message > ' $PYTHON3 $HGBIN commit + $ $PYTHON3 $HGBIN status + $ $PYHON3 $HGBIN summary + parent: 1:e1e9167203d4 tip + message + branch: default + commit: (clean) + update: (current) + phases: 2 draft + +Prove the repo is valid using the Python 2 `hg`: + $ hg verify + checking changesets + checking manifests + crosschecking files in changesets and manifests + checking files + 2 files, 2 changesets, 2 total revisions + $ hg log + changeset: 1:e1e9167203d4 + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: message + + changeset: 0:71c96e924262 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: commit performed in Python 3 + + + $ hg log -G + @ changeset: 1:e1e9167203d4 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: message + | + o changeset: 0:71c96e924262 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: commit performed in Python 3 + + $ hg log -Tjson + [ + { + "rev": 1, + "node": "e1e9167203d450ca2f558af628955b5f5afd4489", + "branch": "default", + "phase": "draft", + "user": "test", + "date": [0, 0], + "desc": "message", + "bookmarks": [], + "tags": ["tip"], + "parents": ["71c96e924262969ff0d8d3d695b0f75412ccc3d8"] + }, + { + "rev": 0, + "node": "71c96e924262969ff0d8d3d695b0f75412ccc3d8", + "branch": "default", + "phase": "draft", + "user": "test", + "date": [0, 0], + "desc": "commit performed in Python 3", + "bookmarks": [], + "tags": [], + "parents": ["0000000000000000000000000000000000000000"] + } + ]
--- a/tests/test-rename-merge2.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-rename-merge2.t Fri May 12 11:20:25 2017 -0700 @@ -89,7 +89,6 @@ preserving a for resolve of b preserving rev for resolve of rev starting 4 threads for background file closing (?) - a: remote unchanged -> k b: remote copied from a -> m (premerge) picked tool 'python ../merge' for b (binary False symlink False changedelete False) merging a and b to b @@ -652,7 +651,6 @@ preserving b for resolve of b preserving rev for resolve of rev starting 4 threads for background file closing (?) - a: remote unchanged -> k b: both created -> m (premerge) picked tool 'python ../merge' for b (binary False symlink False changedelete False) merging b
--- a/tests/test-tags.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-tags.t Fri May 12 11:20:25 2017 -0700 @@ -716,3 +716,15 @@ 0040: ff ff ff ff ff ff ff ff 40 f0 35 8c 19 e0 a7 d3 |........@.5.....| 0050: 8a 5c 6a 82 4d cf fb a5 87 d0 2f a3 1e 4f 2f 8a |.\j.M...../..O/.| +Check that the bundle includes cache data + + $ hg -R tagsclient bundle --all ./test-cache-in-bundle-all-rev.hg + 4 changesets found + $ hg debugbundle ./test-cache-in-bundle-all-rev.hg + Stream params: sortdict([('Compression', 'BZ')]) + changegroup -- "sortdict([('version', '02'), ('nbchanges', '4')])" + 96ee1d7354c4ad7372047672c36a1f561e3a6a4c + c4dab0c2fd337eb9191f80c3024830a4889a8f34 + f63cc8fe54e4d326f8d692805d70e092f851ddb1 + 40f0358cb314c824a5929ee527308d90e023bc10 + hgtagsfnodes -- 'sortdict()'
--- a/tests/test-worker.t Fri May 12 21:46:14 2017 +0900 +++ b/tests/test-worker.t Fri May 12 11:20:25 2017 -0700 @@ -2,6 +2,7 @@ $ cat > t.py <<EOF > from __future__ import absolute_import, print_function + > import time > from mercurial import ( > cmdutil, > error, @@ -22,6 +23,7 @@ > for arg in args: > ui.status('run\n') > yield 1, arg + > time.sleep(0.1) # easier to trigger killworkers code path > functable = { > 'abort': abort, > 'exc': exc, @@ -74,21 +76,53 @@ Known exception should be caught, but printed if --traceback is enabled - $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=2' \ - > test 100000.0 abort + $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \ + > test 100000.0 abort 2>&1 start abort: known exception [255] - $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=2' \ - > test 100000.0 abort --traceback 2>&1 | grep '^Traceback' - Traceback (most recent call last): - Traceback (most recent call last): + $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \ + > test 100000.0 abort --traceback 2>&1 | egrep '^(SystemExit|Abort)' + Abort: known exception + SystemExit: 255 Traceback must be printed for unknown exceptions - $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=2' \ - > test 100000.0 exc 2>&1 | grep '^Traceback' - Traceback (most recent call last): + $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \ + > test 100000.0 exc 2>&1 | grep '^Exception' + Exception: unknown exception + +Workers should not do cleanups in all cases + + $ cat > $TESTTMP/detectcleanup.py <<EOF + > from __future__ import absolute_import + > import atexit + > import os + > import time + > oldfork = os.fork + > count = 0 + > parentpid = os.getpid() + > def delayedfork(): + > global count + > count += 1 + > pid = oldfork() + > # make it easier to test SIGTERM hitting other workers when they have + > # not set up error handling yet. + > if count > 1 and pid == 0: + > time.sleep(0.1) + > return pid + > os.fork = delayedfork + > def cleanup(): + > if os.getpid() != parentpid: + > os.write(1, 'should never happen\n') + > atexit.register(cleanup) + > EOF + + $ hg --config "extensions.t=$abspath" --config worker.numcpus=8 --config \ + > "extensions.d=$TESTTMP/detectcleanup.py" test 100000 abort + start + abort: known exception + [255] #endif