# HG changeset patch # User Martin von Zweigbergk # Date 1590505644 25200 # Node ID fd3b94f1712d2c76ce48248d9be2dbc8c53c2ba7 # Parent 708ad5cf5e5a7666ec6619829a68c6ef8d4cb3e0# Parent 91e509a12dbc4cd6cf2dcb9dae3ed383932132ac merge with stable diff -r 91e509a12dbc -r fd3b94f1712d hgext/extdiff.py --- a/hgext/extdiff.py Fri May 15 00:53:37 2020 +0200 +++ b/hgext/extdiff.py Tue May 26 08:07:24 2020 -0700 @@ -360,14 +360,12 @@ - just invoke the diff for a single file in the working dir ''' + cmdutil.check_at_most_one_arg(opts, b'rev', b'change') revs = opts.get(b'rev') change = opts.get(b'change') do3way = b'$parent2' in cmdline - if revs and change: - msg = _(b'cannot specify --rev and --change at the same time') - raise error.Abort(msg) - elif change: + if change: ctx2 = scmutil.revsingle(repo, change, None) ctx1a, ctx1b = ctx2.p1(), ctx2.p2() else: diff -r 91e509a12dbc -r fd3b94f1712d hgext/git/gitlog.py --- a/hgext/git/gitlog.py Fri May 15 00:53:37 2020 +0200 +++ b/hgext/git/gitlog.py Tue May 26 08:07:24 2020 -0700 @@ -247,6 +247,60 @@ def descendants(self, revs): return dagop.descendantrevs(revs, self.revs, self.parentrevs) + def incrementalmissingrevs(self, common=None): + """Return an object that can be used to incrementally compute the + revision numbers of the ancestors of arbitrary sets that are not + ancestors of common. This is an ancestor.incrementalmissingancestors + object. + + 'common' is a list of revision numbers. If common is not supplied, uses + nullrev. + """ + if common is None: + common = [nodemod.nullrev] + + return ancestor.incrementalmissingancestors(self.parentrevs, common) + + def findmissing(self, common=None, heads=None): + """Return the ancestors of heads that are not ancestors of common. + + More specifically, return a list of nodes N such that every N + satisfies the following constraints: + + 1. N is an ancestor of some node in 'heads' + 2. N is not an ancestor of any node in 'common' + + The list is sorted by revision number, meaning it is + topologically sorted. + + 'heads' and 'common' are both lists of node IDs. If heads is + not supplied, uses all of the revlog's heads. If common is not + supplied, uses nullid.""" + if common is None: + common = [nodemod.nullid] + if heads is None: + heads = self.heads() + + common = [self.rev(n) for n in common] + heads = [self.rev(n) for n in heads] + + inc = self.incrementalmissingrevs(common=common) + return [self.node(r) for r in inc.missingancestors(heads)] + + def children(self, node): + """find the children of a given node""" + c = [] + p = self.rev(node) + for r in self.revs(start=p + 1): + prevs = [pr for pr in self.parentrevs(r) if pr != nodemod.nullrev] + if prevs: + for pr in prevs: + if pr == p: + c.append(self.node(r)) + elif p == nodemod.nullrev: + c.append(self.node(r)) + return c + def reachableroots(self, minroot, heads, roots, includepath=False): return dagop._reachablerootspure( self.parentrevs, minroot, roots, heads, includepath @@ -270,7 +324,10 @@ def parentrevs(self, rev): n = self.node(rev) hn = gitutil.togitnode(n) - c = self.gitrepo[hn] + if hn != gitutil.nullgit: + c = self.gitrepo[hn] + else: + return nodemod.nullrev, nodemod.nullrev p1 = p2 = nodemod.nullrev if c.parents: p1 = self.rev(c.parents[0].id.raw) diff -r 91e509a12dbc -r fd3b94f1712d hgext/git/manifest.py --- a/hgext/git/manifest.py Fri May 15 00:53:37 2020 +0200 +++ b/hgext/git/manifest.py Tue May 26 08:07:24 2020 -0700 @@ -205,7 +205,7 @@ return memgittreemanifestctx(self._repo, self._tree) def find(self, path): - self.read()[path] + return self.read()[path] @interfaceutil.implementer(repository.imanifestrevisionwritable) diff -r 91e509a12dbc -r fd3b94f1712d hgext/mq.py --- a/hgext/mq.py Fri May 15 00:53:37 2020 +0200 +++ b/hgext/mq.py Tue May 26 08:07:24 2020 -0700 @@ -836,7 +836,15 @@ stat = opts.get(b'stat') m = scmutil.match(repo[node1], files, opts) logcmdutil.diffordiffstat( - self.ui, repo, diffopts, node1, node2, m, changes, stat, fp + self.ui, + repo, + diffopts, + repo[node1], + repo[node2], + m, + changes, + stat, + fp, ) def mergeone(self, repo, mergeq, head, patch, rev, diffopts): diff -r 91e509a12dbc -r fd3b94f1712d hgext/phabricator.py --- a/hgext/phabricator.py Fri May 15 00:53:37 2020 +0200 +++ b/hgext/phabricator.py Tue May 26 08:07:24 2020 -0700 @@ -238,8 +238,8 @@ def decorate(fn): def inner(*args, **kwargs): - cassette = pycompat.fsdecode(kwargs.pop('test_vcr', None)) - if cassette: + if kwargs.get('test_vcr'): + cassette = pycompat.fsdecode(kwargs.pop('test_vcr')) import hgdemandimport with hgdemandimport.deactivated(): diff -r 91e509a12dbc -r fd3b94f1712d mercurial/changelog.py --- a/mercurial/changelog.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/changelog.py Tue May 26 08:07:24 2020 -0700 @@ -385,9 +385,7 @@ datafile=datafile, checkambig=True, mmaplargeindex=True, - persistentnodemap=opener.options.get( - b'exp-persistent-nodemap', False - ), + persistentnodemap=opener.options.get(b'persistent-nodemap', False), ) if self._initempty and (self.version & 0xFFFF == revlog.REVLOGV1): diff -r 91e509a12dbc -r fd3b94f1712d mercurial/commands.py --- a/mercurial/commands.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/commands.py Tue May 26 08:07:24 2020 -0700 @@ -2350,7 +2350,7 @@ Returns 0 on success, 1 if errors are encountered. """ opts = pycompat.byteskwargs(opts) - with repo.wlock(False): + with repo.wlock(): return cmdutil.copy(ui, repo, pats, opts) @@ -2475,26 +2475,27 @@ Returns 0 on success. """ + cmdutil.check_at_most_one_arg(opts, 'rev', 'change') opts = pycompat.byteskwargs(opts) revs = opts.get(b'rev') change = opts.get(b'change') stat = opts.get(b'stat') reverse = opts.get(b'reverse') - if revs and change: - msg = _(b'cannot specify --rev and --change at the same time') - raise error.Abort(msg) - elif change: + if change: repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn') ctx2 = scmutil.revsingle(repo, change, None) ctx1 = ctx2.p1() else: repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn') ctx1, ctx2 = scmutil.revpair(repo, revs) - node1, node2 = ctx1.node(), ctx2.node() if reverse: - node1, node2 = node2, node1 + ctxleft = ctx2 + ctxright = ctx1 + else: + ctxleft = ctx1 + ctxright = ctx2 diffopts = patch.diffallopts(ui, opts) m = scmutil.match(ctx2, pats, opts) @@ -2504,8 +2505,8 @@ ui, repo, diffopts, - node1, - node2, + ctxleft, + ctxright, m, stat=stat, listsubrepos=opts.get(b'subrepos'), @@ -3427,8 +3428,11 @@ m = regexp.search(self.line, p) if not m: break - yield m.span() - p = m.end() + if m.end() == p: + p += 1 + else: + yield m.span() + p = m.end() matches = {} copies = {} @@ -3574,31 +3578,41 @@ getrenamed = scmutil.getrenamedfn(repo) - def get_file_content(filename, filelog, filenode, context, revision): - try: - content = filelog.read(filenode) - except error.WdirUnsupported: - content = context[filename].data() - except error.CensoredNodeError: - content = None - ui.warn( - _(b'cannot search in censored file: %(filename)s:%(revnum)s\n') - % {b'filename': filename, b'revnum': pycompat.bytestr(revision)} - ) - return content + def readfile(ctx, fn): + rev = ctx.rev() + if rev is None: + fctx = ctx[fn] + try: + return fctx.data() + except IOError as e: + if e.errno != errno.ENOENT: + raise + else: + flog = getfile(fn) + fnode = ctx.filenode(fn) + try: + return flog.read(fnode) + except error.CensoredNodeError: + ui.warn( + _( + b'cannot search in censored file: %(filename)s:%(revnum)s\n' + ) + % {b'filename': fn, b'revnum': pycompat.bytestr(rev),} + ) def prep(ctx, fns): rev = ctx.rev() pctx = ctx.p1() - parent = pctx.rev() matches.setdefault(rev, {}) - matches.setdefault(parent, {}) + if diff: + parent = pctx.rev() + matches.setdefault(parent, {}) files = revfiles.setdefault(rev, []) for fn in fns: - flog = getfile(fn) - try: - fnode = ctx.filenode(fn) - except error.LookupError: + # fn might not exist in the revision (could be a file removed by the + # revision). We could check `fn not in ctx` even when rev is None, + # but it's less racy to protect againt that in readfile. + if rev is not None and fn not in ctx: continue copy = None @@ -3613,17 +3627,12 @@ files.append(fn) if fn not in matches[rev]: - content = get_file_content(fn, flog, fnode, ctx, rev) - grepbody(fn, rev, content) - - pfn = copy or fn - if pfn not in matches[parent]: - try: - pfnode = pctx.filenode(pfn) - pcontent = get_file_content(pfn, flog, pfnode, pctx, parent) - grepbody(pfn, parent, pcontent) - except error.LookupError: - pass + grepbody(fn, rev, readfile(ctx, fn)) + + if diff: + pfn = copy or fn + if pfn not in matches[parent] and pfn in pctx: + grepbody(pfn, parent, readfile(pctx, pfn)) ui.pager(b'grep') fm = ui.formatter(b'grep', opts) @@ -5807,7 +5816,7 @@ Returns 0 on success, 1 if errors are encountered. """ opts = pycompat.byteskwargs(opts) - with repo.wlock(False): + with repo.wlock(): return cmdutil.copy(ui, repo, pats, opts, rename=True) @@ -6786,6 +6795,7 @@ """ + cmdutil.check_at_most_one_arg(opts, 'rev', 'change') opts = pycompat.byteskwargs(opts) revs = opts.get(b'rev') change = opts.get(b'change') @@ -6796,10 +6806,7 @@ else: terse = ui.config(b'commands', b'status.terse') - if revs and change: - msg = _(b'cannot specify --rev and --change at the same time') - raise error.Abort(msg) - elif revs and terse: + if revs and terse: msg = _(b'cannot use --terse with --rev') raise error.Abort(msg) elif change: diff -r 91e509a12dbc -r fd3b94f1712d mercurial/configitems.py --- a/mercurial/configitems.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/configitems.py Tue May 26 08:07:24 2020 -0700 @@ -405,18 +405,6 @@ coreconfigitem( b'devel', b'legacy.exchange', default=list, ) -# TODO before getting `persistent-nodemap` out of experimental -# -# * decide for a "status" of the persistent nodemap and associated location -# - part of the store next the revlog itself (new requirements) -# - part of the cache directory -# - part of an `index` directory -# (https://www.mercurial-scm.org/wiki/ComputedIndexPlan) -# * do we want to use this for more than just changelog? if so we need: -# - simpler "pending" logic for them -# - double check the memory story (we dont want to keep all revlog in memory) -# - think about the naming scheme if we are in "cache" -# * increment the version format to "1" and freeze it. coreconfigitem( b'devel', b'persistent-nodemap', default=False, ) @@ -675,12 +663,6 @@ b'experimental', b'rust.index', default=False, ) coreconfigitem( - b'experimental', b'exp-persistent-nodemap', default=False, -) -coreconfigitem( - b'experimental', b'exp-persistent-nodemap.mmap', default=True, -) -coreconfigitem( b'experimental', b'server.filesdata.recommended-batch-size', default=50000, ) coreconfigitem( @@ -783,6 +765,12 @@ coreconfigitem( b'format', b'usestore', default=True, ) +# Right now, the only efficient implement of the nodemap logic is in Rust, so +# the persistent nodemap feature needs to stay experimental as long as the Rust +# extensions are an experimental feature. +coreconfigitem( + b'format', b'use-persistent-nodemap', default=False, experimental=True +) coreconfigitem( b'format', b'exp-use-copies-side-data-changeset', @@ -1088,6 +1076,14 @@ default=True, alias=[(b'format', b'aggressivemergedeltas')], ) +# experimental as long as rust is experimental (or a C version is implemented) +coreconfigitem( + b'storage', b'revlog.nodemap.mmap', default=True, experimental=True +) +# experimental as long as format.use-persistent-nodemap is. +coreconfigitem( + b'storage', b'revlog.nodemap.mode', default=b'compat', experimental=True +) coreconfigitem( b'storage', b'revlog.reuse-external-delta', default=True, ) diff -r 91e509a12dbc -r fd3b94f1712d mercurial/copies.py --- a/mercurial/copies.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/copies.py Tue May 26 08:07:24 2020 -0700 @@ -183,10 +183,27 @@ * p1copies: mapping of copies from p1 * p2copies: mapping of copies from p2 * removed: a list of removed files + * ismerged: a callback to know if file was merged in that revision """ cl = repo.changelog parents = cl.parentrevs + def get_ismerged(rev): + ctx = repo[rev] + + def ismerged(path): + if path not in ctx.files(): + return False + fctx = ctx[path] + parents = fctx._filelog.parents(fctx._filenode) + nb_parents = 0 + for n in parents: + if n != node.nullid: + nb_parents += 1 + return nb_parents >= 2 + + return ismerged + if repo.filecopiesmode == b'changeset-sidedata': changelogrevision = cl.changelogrevision flags = cl.flags @@ -218,6 +235,7 @@ def revinfo(rev): p1, p2 = parents(rev) + value = None if flags(rev) & REVIDX_SIDEDATA: e = merge_caches.pop(rev, None) if e is not None: @@ -228,12 +246,22 @@ removed = c.filesremoved if p1 != node.nullrev and p2 != node.nullrev: # XXX some case we over cache, IGNORE - merge_caches[rev] = (p1, p2, p1copies, p2copies, removed) + value = merge_caches[rev] = ( + p1, + p2, + p1copies, + p2copies, + removed, + get_ismerged(rev), + ) else: p1copies = {} p2copies = {} removed = [] - return p1, p2, p1copies, p2copies, removed + + if value is None: + value = (p1, p2, p1copies, p2copies, removed, get_ismerged(rev)) + return value else: @@ -242,7 +270,7 @@ ctx = repo[rev] p1copies, p2copies = ctx._copies removed = ctx.filesremoved() - return p1, p2, p1copies, p2copies, removed + return p1, p2, p1copies, p2copies, removed, get_ismerged(rev) return revinfo @@ -256,6 +284,7 @@ revinfo = _revinfogetter(repo) cl = repo.changelog + isancestor = cl.isancestorrev # XXX we should had chaching to this. missingrevs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()]) mrset = set(missingrevs) roots = set() @@ -283,10 +312,14 @@ iterrevs.update(roots) iterrevs.remove(b.rev()) revs = sorted(iterrevs) - return _combinechangesetcopies(revs, children, b.rev(), revinfo, match) + return _combinechangesetcopies( + revs, children, b.rev(), revinfo, match, isancestor + ) -def _combinechangesetcopies(revs, children, targetrev, revinfo, match): +def _combinechangesetcopies( + revs, children, targetrev, revinfo, match, isancestor +): """combine the copies information for each item of iterrevs revs: sorted iterable of revision to visit @@ -305,7 +338,7 @@ # this is a root copies = {} for i, c in enumerate(children[r]): - p1, p2, p1copies, p2copies, removed = revinfo(c) + p1, p2, p1copies, p2copies, removed, ismerged = revinfo(c) if r == p1: parent = 1 childcopies = p1copies @@ -319,9 +352,12 @@ } newcopies = copies if childcopies: - newcopies = _chain(newcopies, childcopies) - # _chain makes a copies, we can avoid doing so in some - # simple/linear cases. + newcopies = copies.copy() + for dest, source in pycompat.iteritems(childcopies): + prev = copies.get(source) + if prev is not None and prev[1] is not None: + source = prev[1] + newcopies[dest] = (c, source) assert newcopies is not copies for f in removed: if f in newcopies: @@ -330,7 +366,7 @@ # branches. when there are no other branches, this # could be avoided. newcopies = copies.copy() - del newcopies[f] + newcopies[f] = (c, None) othercopies = all_copies.get(c) if othercopies is None: all_copies[c] = newcopies @@ -338,21 +374,55 @@ # we are the second parent to work on c, we need to merge our # work with the other. # - # Unlike when copies are stored in the filelog, we consider - # it a copy even if the destination already existed on the - # other branch. It's simply too expensive to check if the - # file existed in the manifest. - # # In case of conflict, parent 1 take precedence over parent 2. # This is an arbitrary choice made anew when implementing # changeset based copies. It was made without regards with # potential filelog related behavior. if parent == 1: - othercopies.update(newcopies) + _merge_copies_dict( + othercopies, newcopies, isancestor, ismerged + ) else: - newcopies.update(othercopies) + _merge_copies_dict( + newcopies, othercopies, isancestor, ismerged + ) all_copies[c] = newcopies - return all_copies[targetrev] + + final_copies = {} + for dest, (tt, source) in all_copies[targetrev].items(): + if source is not None: + final_copies[dest] = source + return final_copies + + +def _merge_copies_dict(minor, major, isancestor, ismerged): + """merge two copies-mapping together, minor and major + + In case of conflict, value from "major" will be picked. + + - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an + ancestors of `high_rev`, + + - `ismerged(path)`: callable return True if `path` have been merged in the + current revision, + """ + for dest, value in major.items(): + other = minor.get(dest) + if other is None: + minor[dest] = value + else: + new_tt = value[0] + other_tt = other[0] + if value[1] == other[1]: + continue + # content from "major" wins, unless it is older + # than the branch point or there is a merge + if ( + new_tt == other_tt + or not isancestor(new_tt, other_tt) + or ismerged(dest) + ): + minor[dest] = value def _forwardcopies(a, b, base=None, match=None): diff -r 91e509a12dbc -r fd3b94f1712d mercurial/dirstate.py --- a/mercurial/dirstate.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/dirstate.py Tue May 26 08:07:24 2020 -0700 @@ -187,7 +187,7 @@ @propertycache def _checkexec(self): - return util.checkexec(self._root) + return bool(util.checkexec(self._root)) @propertycache def _checkcase(self): @@ -1114,6 +1114,7 @@ unknown, warnings, bad, + traversed, ) = rustmod.status( self._map._rustmap, matcher, @@ -1124,7 +1125,13 @@ bool(list_clean), bool(list_ignored), bool(list_unknown), + bool(matcher.traversedir), ) + + if matcher.traversedir: + for dir in traversed: + matcher.traversedir(dir) + if self._ui.warn: for item in warnings: if isinstance(item, tuple): @@ -1200,10 +1207,8 @@ use_rust = False elif sparse.enabled: use_rust = False - elif match.traversedir is not None: - use_rust = False elif not isinstance(match, allowed_matchers): - # Matchers have yet to be implemented + # Some matchers have yet to be implemented use_rust = False if use_rust: diff -r 91e509a12dbc -r fd3b94f1712d mercurial/helptext/internals/requirements.txt --- a/mercurial/helptext/internals/requirements.txt Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/helptext/internals/requirements.txt Tue May 26 08:07:24 2020 -0700 @@ -142,3 +142,16 @@ August 2019). The requirement will only be present on repositories that have opted in to this format (by having ``format.bookmarks-in-store=true`` set when they were created). + +persistent-nodemap +================== + +The `nodemap` index (mapping nodeid to local revision number) is persisted on +disk. This provides speed benefit (if the associated native code is used). The +persistent nodemap is only used for two revlogs: the changelog and the +manifestlog. + +Support for this requirement was added in Mercurial 5.5 (released August 2020). +Note that as of 5.5, only installations compiled with the Rust extension will +benefit from a speedup. The other installations will do the necessary work to +keep the index up to date, but will suffer a slowdown. diff -r 91e509a12dbc -r fd3b94f1712d mercurial/hook.py --- a/mercurial/hook.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/hook.py Tue May 26 08:07:24 2020 -0700 @@ -158,6 +158,10 @@ env[b'HG_HOOKNAME'] = name for k, v in pycompat.iteritems(args): + # transaction changes can accumulate MBs of data, so skip it + # for external hooks + if k == b'changes': + continue if callable(v): v = v() if isinstance(v, (dict, list)): diff -r 91e509a12dbc -r fd3b94f1712d mercurial/interfaces/repository.py --- a/mercurial/interfaces/repository.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/interfaces/repository.py Tue May 26 08:07:24 2020 -0700 @@ -1395,6 +1395,9 @@ Raises ``error.LookupError`` if the node is not known. """ + def update_caches(transaction): + """update whatever cache are relevant for the used storage.""" + class ilocalrepositoryfilestorage(interfaceutil.Interface): """Local repository sub-interface providing access to tracked file storage. diff -r 91e509a12dbc -r fd3b94f1712d mercurial/localrepo.py --- a/mercurial/localrepo.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/localrepo.py Tue May 26 08:07:24 2020 -0700 @@ -445,6 +445,9 @@ # copies related information in changeset's sidedata. COPIESSDC_REQUIREMENT = b'exp-copies-sidedata-changeset' +# The repository use persistent nodemap for the changelog and the manifest. +NODEMAP_REQUIREMENT = b'persistent-nodemap' + # Functions receiving (ui, features) that extensions can register to impact # the ability to load repositories with custom requirements. Only # functions defined in loaded extensions are called. @@ -933,10 +936,12 @@ if ui.configbool(b'experimental', b'rust.index'): options[b'rust.index'] = True - if ui.configbool(b'experimental', b'exp-persistent-nodemap'): - options[b'exp-persistent-nodemap'] = True - if ui.configbool(b'experimental', b'exp-persistent-nodemap.mmap'): - options[b'exp-persistent-nodemap.mmap'] = True + if NODEMAP_REQUIREMENT in requirements: + options[b'persistent-nodemap'] = True + if ui.configbool(b'storage', b'revlog.nodemap.mmap'): + options[b'persistent-nodemap.mmap'] = True + epnm = ui.config(b'storage', b'revlog.nodemap.mode') + options[b'persistent-nodemap.mode'] = epnm if ui.configbool(b'devel', b'persistent-nodemap'): options[b'devel-force-nodemap'] = True @@ -1021,6 +1026,7 @@ REVLOGV2_REQUIREMENT, SIDEDATA_REQUIREMENT, SPARSEREVLOG_REQUIREMENT, + NODEMAP_REQUIREMENT, bookmarks.BOOKMARKS_IN_STORE_REQUIREMENT, } _basesupported = supportedformats | { @@ -2239,6 +2245,7 @@ tr.hookargs[b'txnid'] = txnid tr.hookargs[b'txnname'] = desc + tr.hookargs[b'changes'] = tr.changes # note: writing the fncache only during finalize mean that the file is # outdated when running hooks. As fncache is used for streaming clone, # this is not expected to break anything that happen during the hooks. @@ -2511,6 +2518,7 @@ unfi = self.unfiltered() self.changelog.update_caches(transaction=tr) + self.manifestlog.update_caches(transaction=tr) rbc = unfi.revbranchcache() for r in unfi.changelog: @@ -3018,6 +3026,12 @@ self.ui.write( _(b'note: commit message saved in %s\n') % msgfn ) + self.ui.write( + _( + b"note: use 'hg commit --logfile " + b".hg/last-message.txt --edit' to reuse it\n" + ) + ) raise def commithook(unused_success): @@ -3653,6 +3667,9 @@ if ui.configbool(b'format', b'bookmarks-in-store'): requirements.add(bookmarks.BOOKMARKS_IN_STORE_REQUIREMENT) + if ui.configbool(b'format', b'use-persistent-nodemap'): + requirements.add(NODEMAP_REQUIREMENT) + return requirements diff -r 91e509a12dbc -r fd3b94f1712d mercurial/logcmdutil.py --- a/mercurial/logcmdutil.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/logcmdutil.py Tue May 26 08:07:24 2020 -0700 @@ -72,8 +72,8 @@ ui, repo, diffopts, - node1, - node2, + ctx1, + ctx2, match, changes=None, stat=False, @@ -85,8 +85,6 @@ hunksfilterfn=None, ): '''show diff or diffstat.''' - ctx1 = repo[node1] - ctx2 = repo[node2] if root: relroot = pathutil.canonpath(repo.root, repo.getcwd(), root) else: @@ -173,6 +171,7 @@ for chunk, label in chunks: ui.write(chunk, label=label) + node2 = ctx2.node() for subpath, sub in scmutil.itersubrepos(ctx1, ctx2): tempnode2 = node2 try: @@ -208,15 +207,12 @@ return None def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False): - repo = ctx.repo() - node = ctx.node() - prev = ctx.p1().node() diffordiffstat( ui, - repo, + ctx.repo(), diffopts, - prev, - node, + ctx.p1(), + ctx, match=self._makefilematcher(ctx), stat=stat, graphwidth=graphwidth, diff -r 91e509a12dbc -r fd3b94f1712d mercurial/manifest.py --- a/mercurial/manifest.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/manifest.py Tue May 26 08:07:24 2020 -0700 @@ -1599,6 +1599,7 @@ checkambig=not bool(tree), mmaplargeindex=True, upperboundcomp=MAXCOMPRESSION, + persistentnodemap=opener.options.get(b'persistent-nodemap', False), ) self.index = self._revlog.index @@ -1959,6 +1960,9 @@ def rev(self, node): return self._rootstore.rev(node) + def update_caches(self, transaction): + return self._rootstore._revlog.update_caches(transaction=transaction) + @interfaceutil.implementer(repository.imanifestrevisionwritable) class memmanifestctx(object): diff -r 91e509a12dbc -r fd3b94f1712d mercurial/revlogutils/nodemap.py --- a/mercurial/revlogutils/nodemap.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/revlogutils/nodemap.py Tue May 26 08:07:24 2020 -0700 @@ -13,6 +13,8 @@ import re import struct +from ..i18n import _ + from .. import ( error, node as nodemod, @@ -48,7 +50,7 @@ docket.data_unused = data_unused filename = _rawdata_filepath(revlog, docket) - use_mmap = revlog.opener.options.get(b"exp-persistent-nodemap.mmap") + use_mmap = revlog.opener.options.get(b"persistent-nodemap.mmap") try: with revlog.opener(filename) as fd: if use_mmap: @@ -105,6 +107,9 @@ def addabort(self, *args, **kwargs): pass + def _report(self, *args): + pass + def update_persistent_nodemap(revlog): """update the persistent nodemap right now @@ -137,7 +142,14 @@ can_incremental = util.safehasattr(revlog.index, "nodemap_data_incremental") ondisk_docket = revlog._nodemap_docket feed_data = util.safehasattr(revlog.index, "update_nodemap_data") - use_mmap = revlog.opener.options.get(b"exp-persistent-nodemap.mmap") + use_mmap = revlog.opener.options.get(b"persistent-nodemap.mmap") + mode = revlog.opener.options.get(b"persistent-nodemap.mode") + if not can_incremental: + msg = _(b"persistent nodemap in strict mode without efficient method") + if mode == b'warn': + tr._report(b"%s\n" % msg) + elif mode == b'strict': + raise error.Abort(msg) data = None # first attemp an incremental update of the data @@ -255,8 +267,7 @@ # data. Its content is currently very light, but it will expand as the on disk # nodemap gains the necessary features to be used in production. -# version 0 is experimental, no BC garantee, do no use outside of tests. -ONDISK_VERSION = 0 +ONDISK_VERSION = 1 S_VERSION = struct.Struct(">B") S_HEADER = struct.Struct(">BQQQQ") diff -r 91e509a12dbc -r fd3b94f1712d mercurial/scmutil.py --- a/mercurial/scmutil.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/scmutil.py Tue May 26 08:07:24 2020 -0700 @@ -456,9 +456,7 @@ def resolvehexnodeidprefix(repo, prefix): - if prefix.startswith(b'x') and repo.ui.configbool( - b'experimental', b'revisions.prefixhexnode' - ): + if prefix.startswith(b'x'): prefix = prefix[1:] try: # Uses unfiltered repo because it's faster when prefix is ambiguous/ diff -r 91e509a12dbc -r fd3b94f1712d mercurial/subrepo.py --- a/mercurial/subrepo.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/subrepo.py Tue May 26 08:07:24 2020 -0700 @@ -617,8 +617,8 @@ ui, self._repo, diffopts, - node1, - node2, + self._repo[node1], + self._repo[node2], match, prefix=prefix, listsubrepos=True, diff -r 91e509a12dbc -r fd3b94f1712d mercurial/upgrade.py --- a/mercurial/upgrade.py Fri May 15 00:53:37 2020 +0200 +++ b/mercurial/upgrade.py Tue May 26 08:07:24 2020 -0700 @@ -78,6 +78,7 @@ localrepo.SPARSEREVLOG_REQUIREMENT, localrepo.SIDEDATA_REQUIREMENT, localrepo.COPIESSDC_REQUIREMENT, + localrepo.NODEMAP_REQUIREMENT, } for name in compression.compengines: engine = compression.compengines[name] @@ -105,6 +106,7 @@ localrepo.SPARSEREVLOG_REQUIREMENT, localrepo.SIDEDATA_REQUIREMENT, localrepo.COPIESSDC_REQUIREMENT, + localrepo.NODEMAP_REQUIREMENT, } for name in compression.compengines: engine = compression.compengines[name] @@ -132,6 +134,7 @@ localrepo.SPARSEREVLOG_REQUIREMENT, localrepo.SIDEDATA_REQUIREMENT, localrepo.COPIESSDC_REQUIREMENT, + localrepo.NODEMAP_REQUIREMENT, } for name in compression.compengines: engine = compression.compengines[name] @@ -374,6 +377,21 @@ @registerformatvariant +class persistentnodemap(requirementformatvariant): + name = b'persistent-nodemap' + + _requirement = localrepo.NODEMAP_REQUIREMENT + + default = False + + description = _( + b'persist the node -> rev mapping on disk to speedup lookup' + ) + + upgrademessage = _(b'Speedup revision lookup by node id.') + + +@registerformatvariant class copiessdc(requirementformatvariant): name = b'copies-sdc' @@ -807,14 +825,14 @@ if not revcount: return - ui.write( + ui.status( _( b'migrating %d total revisions (%d in filelogs, %d in manifests, ' b'%d in changelog)\n' ) % (revcount, frevcount, mrevcount, crevcount) ) - ui.write( + ui.status( _(b'migrating %s in store; %s tracked data\n') % ((util.bytecount(srcsize), util.bytecount(srcrawsize))) ) @@ -837,7 +855,7 @@ oldrl = _revlogfrompath(srcrepo, unencoded) if isinstance(oldrl, changelog.changelog) and b'c' not in seen: - ui.write( + ui.status( _( b'finished migrating %d manifest revisions across %d ' b'manifests; change in size: %s\n' @@ -845,7 +863,7 @@ % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize)) ) - ui.write( + ui.status( _( b'migrating changelog containing %d revisions ' b'(%s in store; %s tracked data)\n' @@ -861,7 +879,7 @@ _(b'changelog revisions'), total=crevcount ) elif isinstance(oldrl, manifest.manifestrevlog) and b'm' not in seen: - ui.write( + ui.status( _( b'finished migrating %d filelog revisions across %d ' b'filelogs; change in size: %s\n' @@ -869,7 +887,7 @@ % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize)) ) - ui.write( + ui.status( _( b'migrating %d manifests containing %d revisions ' b'(%s in store; %s tracked data)\n' @@ -888,7 +906,7 @@ _(b'manifest revisions'), total=mrevcount ) elif b'f' not in seen: - ui.write( + ui.status( _( b'migrating %d filelogs containing %d revisions ' b'(%s in store; %s tracked data)\n' @@ -941,7 +959,7 @@ progress.complete() - ui.write( + ui.status( _( b'finished migrating %d changelog revisions; change in size: ' b'%s\n' @@ -949,7 +967,7 @@ % (crevcount, util.bytecount(cdstsize - csrcsize)) ) - ui.write( + ui.status( _( b'finished migrating %d total revisions; total change in store ' b'size: %s\n' @@ -975,7 +993,7 @@ Function should return ``True`` if the file is to be copied. """ # Skip revlogs. - if path.endswith((b'.i', b'.d')): + if path.endswith((b'.i', b'.d', b'.n', b'.nd')): return False # Skip transaction related files. if path.startswith(b'undo'): @@ -1013,7 +1031,7 @@ assert srcrepo.currentwlock() assert dstrepo.currentwlock() - ui.write( + ui.status( _( b'(it is safe to interrupt this process any time before ' b'data migration completes)\n' @@ -1048,14 +1066,14 @@ if not _filterstorefile(srcrepo, dstrepo, requirements, p, kind, st): continue - srcrepo.ui.write(_(b'copying %s\n') % p) + srcrepo.ui.status(_(b'copying %s\n') % p) src = srcrepo.store.rawvfs.join(p) dst = dstrepo.store.rawvfs.join(p) util.copyfile(src, dst, copystat=True) _finishdatamigration(ui, srcrepo, dstrepo, requirements) - ui.write(_(b'data fully migrated to temporary repository\n')) + ui.status(_(b'data fully migrated to temporary repository\n')) backuppath = pycompat.mkdtemp(prefix=b'upgradebackup.', dir=srcrepo.path) backupvfs = vfsmod.vfs(backuppath) @@ -1067,7 +1085,7 @@ # as a mechanism to lock out new clients during the data swap. This is # better than allowing a client to continue while the repository is in # an inconsistent state. - ui.write( + ui.status( _( b'marking source repository as being upgraded; clients will be ' b'unable to read from repository\n' @@ -1077,18 +1095,18 @@ srcrepo.vfs, srcrepo.requirements | {b'upgradeinprogress'} ) - ui.write(_(b'starting in-place swap of repository data\n')) - ui.write(_(b'replaced files will be backed up at %s\n') % backuppath) + ui.status(_(b'starting in-place swap of repository data\n')) + ui.status(_(b'replaced files will be backed up at %s\n') % backuppath) # Now swap in the new store directory. Doing it as a rename should make # the operation nearly instantaneous and atomic (at least in well-behaved # environments). - ui.write(_(b'replacing store...\n')) + ui.status(_(b'replacing store...\n')) tstart = util.timer() util.rename(srcrepo.spath, backupvfs.join(b'store')) util.rename(dstrepo.spath, srcrepo.spath) elapsed = util.timer() - tstart - ui.write( + ui.status( _( b'store replacement complete; repository was inconsistent for ' b'%0.1fs\n' @@ -1098,7 +1116,7 @@ # We first write the requirements file. Any new requirements will lock # out legacy clients. - ui.write( + ui.status( _( b'finalizing requirements file and making repository readable ' b'again\n' @@ -1274,9 +1292,20 @@ ui.write((b'\n')) ui.write(b'\n') + def printoptimisations(): + optimisations = [a for a in actions if a.type == optimisation] + optimisations.sort(key=lambda a: a.name) + if optimisations: + ui.write(_(b'optimisations: ')) + write_labeled( + [a.name for a in optimisations], + "upgrade-repo.optimisation.performed", + ) + ui.write(b'\n\n') + def printupgradeactions(): for a in actions: - ui.write(b'%s\n %s\n\n' % (a.name, a.upgrademessage)) + ui.status(b'%s\n %s\n\n' % (a.name, a.upgrademessage)) if not run: fromconfig = [] @@ -1291,35 +1320,35 @@ if fromconfig or onlydefault: if fromconfig: - ui.write( + ui.status( _( b'repository lacks features recommended by ' b'current config options:\n\n' ) ) for i in fromconfig: - ui.write(b'%s\n %s\n\n' % (i.name, i.description)) + ui.status(b'%s\n %s\n\n' % (i.name, i.description)) if onlydefault: - ui.write( + ui.status( _( b'repository lacks features used by the default ' b'config options:\n\n' ) ) for i in onlydefault: - ui.write(b'%s\n %s\n\n' % (i.name, i.description)) + ui.status(b'%s\n %s\n\n' % (i.name, i.description)) - ui.write(b'\n') + ui.status(b'\n') else: - ui.write( + ui.status( _( b'(no feature deficiencies found in existing ' b'repository)\n' ) ) - ui.write( + ui.status( _( b'performing an upgrade with "--run" will make the following ' b'changes:\n\n' @@ -1327,31 +1356,33 @@ ) printrequirements() + printoptimisations() printupgradeactions() unusedoptimize = [i for i in alloptimizations if i not in actions] if unusedoptimize: - ui.write( + ui.status( _( b'additional optimizations are available by specifying ' b'"--optimize ":\n\n' ) ) for i in unusedoptimize: - ui.write(_(b'%s\n %s\n\n') % (i.name, i.description)) + ui.status(_(b'%s\n %s\n\n') % (i.name, i.description)) return # Else we're in the run=true case. ui.write(_(b'upgrade will perform the following actions:\n\n')) printrequirements() + printoptimisations() printupgradeactions() upgradeactions = [a.name for a in actions] - ui.write(_(b'beginning upgrade...\n')) + ui.status(_(b'beginning upgrade...\n')) with repo.wlock(), repo.lock(): - ui.write(_(b'repository locked and read-only\n')) + ui.status(_(b'repository locked and read-only\n')) # Our strategy for upgrading the repository is to create a new, # temporary repository, write data to it, then do a swap of the # data. There are less heavyweight ways to do this, but it is easier @@ -1360,7 +1391,7 @@ tmppath = pycompat.mkdtemp(prefix=b'upgrade.', dir=repo.path) backuppath = None try: - ui.write( + ui.status( _( b'creating temporary repository to stage migrated ' b'data: %s\n' @@ -1377,15 +1408,17 @@ ui, repo, dstrepo, newreqs, upgradeactions, revlogs=revlogs ) if not (backup or backuppath is None): - ui.write(_(b'removing old repository content%s\n') % backuppath) + ui.status( + _(b'removing old repository content%s\n') % backuppath + ) repo.vfs.rmtree(backuppath, forcibly=True) backuppath = None finally: - ui.write(_(b'removing temporary repository %s\n') % tmppath) + ui.status(_(b'removing temporary repository %s\n') % tmppath) repo.vfs.rmtree(tmppath, forcibly=True) - if backuppath: + if backuppath and not ui.quiet: ui.warn( _(b'copy of old repository backed up at %s\n') % backuppath ) diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/Cargo.lock --- a/rust/chg/Cargo.lock Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/Cargo.lock Tue May 26 08:07:24 2020 -0700 @@ -6,9 +6,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "autocfg" -version = "1.0.0" +name = "async-trait" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "bitflags" @@ -16,20 +21,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "byteorder" -version = "1.3.4" +name = "bytes" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "cc" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -43,91 +39,17 @@ name = "chg" version = "0.1.0" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "async-trait 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-hglib 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-hglib 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-queue" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-queue" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fnv" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -143,15 +65,84 @@ [[package]] name = "futures" -version = "0.1.29" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-channel" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "hermit-abi" -version = "0.1.10" +name = "futures-executor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-io" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-macro" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-sink" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-task" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-util" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -159,7 +150,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -178,18 +169,10 @@ [[package]] name = "libc" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "lock_api" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -198,19 +181,11 @@ ] [[package]] -name = "maybe-uninit" -version = "2.0.0" +name = "memchr" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "memoffset" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "mio" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -220,7 +195,7 @@ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -245,7 +220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -265,7 +240,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -275,41 +250,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "num_cpus" -version = "1.12.0" +name = "pin-project-lite" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro-hack" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro-nested" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "parking_lot" -version = "0.9.0" +name = "quote" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -318,38 +296,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] name = "signal-hook-registry" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arc-swap 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -358,240 +310,85 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "smallvec" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "socket2" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tokio" -version = "0.1.22" +name = "syn" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tokio-executor" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-hglib" -version = "0.2.0" +name = "tokio" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-process" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tokio-reactor" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-signal" -version = "0.2.9" +name = "tokio-hglib" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-sync" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "async-trait 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tokio-threadpool" -version = "0.1.18" +name = "tokio-macros" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tokio-udp" -version = "0.1.6" +name = "tokio-util" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tokio-uds" -version = "0.2.6" +name = "unicode-xid" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "winapi" @@ -633,66 +430,50 @@ [metadata] "checksum arc-swap 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d663a8e9a99154b5fb793032533f6328da35e23aac63d5c152279aa8ba356825" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum async-trait 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "da71fef07bc806586090247e971229289f64c210a278ee5ae419314eb386b31d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +"checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" -"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" -"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" +"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" +"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" +"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" +"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" -"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" +"checksum libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" "checksum mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +"checksum pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" +"checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" +"checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" +"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -"checksum tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" -"checksum tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -"checksum tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -"checksum tokio-fs 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" -"checksum tokio-hglib 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a138c3cb866c8a95ceddae44634bb159eefeebcdba45aec2158f8ad6c201e6d" -"checksum tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -"checksum tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "382d90f43fa31caebe5d3bc6cfd854963394fff3b8cb59d5146607aaae7e7e43" -"checksum tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -"checksum tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c34c6e548f101053321cba3da7cbb87a610b85555884c41b07da2eb91aff12" -"checksum tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -"checksum tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -"checksum tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -"checksum tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" -"checksum tokio-udp 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" -"checksum tokio-uds 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5076db410d6fdc6523df7595447629099a1fdc47b3d9f896220780fa48faf798" +"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +"checksum tokio 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "34ef16d072d2b6dc8b4a56c70f5c5ced1a37752116f8e7c1e80c659aa7cb6713" +"checksum tokio-hglib 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d7e2b5d44911ebf67a1044423604f5f69206c5cbbd7e911b4966e6831514bca" +"checksum tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" +"checksum tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/Cargo.toml --- a/rust/chg/Cargo.toml Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/Cargo.toml Tue May 26 08:07:24 2020 -0700 @@ -7,14 +7,16 @@ edition = "2018" [dependencies] -bytes = "0.4" -futures = "0.1" +async-trait = "0.1" +bytes = "0.5" +futures = "0.3" libc = "0.2" log = { version = "0.4", features = ["std"] } -tokio = "0.1" -tokio-hglib = "0.2" -tokio-process = "0.2.3" -tokio-timer = "0.2" +tokio-hglib = "0.3" + +[dependencies.tokio] +version = "0.2" +features = ["rt-core", "io-util", "time", "process", "macros"] [build-dependencies] cc = "1.0" diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/src/attachio.rs --- a/rust/chg/src/attachio.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/src/attachio.rs Tue May 26 08:07:24 2020 -0700 @@ -5,17 +5,15 @@ //! Functions to send client-side fds over the command server channel. -use futures::{try_ready, Async, Future, Poll}; use std::io; use std::os::unix::io::AsRawFd; use tokio_hglib::codec::ChannelMessage; -use tokio_hglib::protocol::MessageLoop; -use tokio_hglib::{Client, Connection}; +use tokio_hglib::{Connection, Protocol}; use crate::message; use crate::procutil; -/// Future to send client-side fds over the command server channel. +/// Sends client-side fds over the command server channel. /// /// This works as follows: /// 1. Client sends "attachio" request. @@ -23,92 +21,48 @@ /// 3. Client sends fds with 1-byte dummy payload in response. /// 4. Server returns the number of the fds received. /// -/// If the stderr is omitted, it will be redirected to the stdout. This -/// allows us to attach the pager stdin to both stdout and stderr, and -/// dispose of the client-side handle once attached. -#[must_use = "futures do nothing unless polled"] -pub struct AttachIo -where - C: Connection, -{ - msg_loop: MessageLoop, - stdin: I, - stdout: O, - stderr: Option, -} - -impl AttachIo -where - C: Connection + AsRawFd, - I: AsRawFd, - O: AsRawFd, - E: AsRawFd, -{ - pub fn with_client( - client: Client, - stdin: I, - stdout: O, - stderr: Option, - ) -> AttachIo { - let msg_loop = MessageLoop::start(client, b"attachio"); - AttachIo { - msg_loop, - stdin, - stdout, - stderr, - } - } -} - -impl Future for AttachIo -where - C: Connection + AsRawFd, - I: AsRawFd, - O: AsRawFd, - E: AsRawFd, -{ - type Item = Client; - type Error = io::Error; - - fn poll(&mut self) -> Poll { - loop { - let (client, msg) = try_ready!(self.msg_loop.poll()); - match msg { - ChannelMessage::Data(b'r', data) => { - let fd_cnt = message::parse_result_code(data)?; - if fd_cnt == 3 { - return Ok(Async::Ready(client)); - } else { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "unexpected attachio result", - )); - } - } - ChannelMessage::Data(..) => { - // just ignore data sent to uninteresting (optional) channel - self.msg_loop = MessageLoop::resume(client); - } - ChannelMessage::InputRequest(1) => { - // this may fail with EWOULDBLOCK in theory, but the - // payload is quite small, and the send buffer should - // be empty so the operation will complete immediately - let sock_fd = client.as_raw_fd(); - let ifd = self.stdin.as_raw_fd(); - let ofd = self.stdout.as_raw_fd(); - let efd = self.stderr.as_ref().map_or(ofd, |f| f.as_raw_fd()); - procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?; - self.msg_loop = MessageLoop::resume(client); - } - ChannelMessage::InputRequest(..) - | ChannelMessage::LineRequest(..) - | ChannelMessage::SystemRequest(..) => { +/// The client-side fds may be dropped once duplicated to the server. +pub async fn attach_io( + proto: &mut Protocol, + stdin: &impl AsRawFd, + stdout: &impl AsRawFd, + stderr: &impl AsRawFd, +) -> io::Result<()> { + proto.send_command("attachio").await?; + loop { + match proto.fetch_response().await? { + ChannelMessage::Data(b'r', data) => { + let fd_cnt = message::parse_result_code(data)?; + if fd_cnt == 3 { + return Ok(()); + } else { return Err(io::Error::new( io::ErrorKind::InvalidData, - "unsupported request while attaching io", + "unexpected attachio result", )); } } + ChannelMessage::Data(..) => { + // just ignore data sent to uninteresting (optional) channel + } + ChannelMessage::InputRequest(1) => { + // this may fail with EWOULDBLOCK in theory, but the + // payload is quite small, and the send buffer should + // be empty so the operation will complete immediately + let sock_fd = proto.as_raw_fd(); + let ifd = stdin.as_raw_fd(); + let ofd = stdout.as_raw_fd(); + let efd = stderr.as_raw_fd(); + procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?; + } + ChannelMessage::InputRequest(..) + | ChannelMessage::LineRequest(..) + | ChannelMessage::SystemRequest(..) => { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "unsupported request while attaching io", + )); + } } } } diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/src/clientext.rs --- a/rust/chg/src/clientext.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/src/clientext.rs Tue May 26 08:07:24 2020 -0700 @@ -5,55 +5,99 @@ //! cHg extensions to command server client. -use bytes::{BufMut, Bytes, BytesMut}; +use bytes::{BufMut, BytesMut}; use std::ffi::OsStr; use std::io; use std::mem; use std::os::unix::ffi::OsStrExt; use std::os::unix::io::AsRawFd; use std::path::Path; -use tokio_hglib::protocol::{OneShotQuery, OneShotRequest}; -use tokio_hglib::{Client, Connection}; +use tokio_hglib::UnixClient; -use crate::attachio::AttachIo; -use crate::message::{self, Instruction}; -use crate::runcommand::ChgRunCommand; +use crate::attachio; +use crate::message::{self, Instruction, ServerSpec}; +use crate::runcommand; use crate::uihandler::SystemHandler; -pub trait ChgClientExt -where - C: Connection + AsRawFd, -{ +/// Command-server client that also supports cHg extensions. +pub struct ChgClient { + client: UnixClient, +} + +impl ChgClient { + /// Connects to a command server listening at the specified socket path. + pub async fn connect(path: impl AsRef) -> io::Result { + let client = UnixClient::connect(path).await?; + Ok(ChgClient { client }) + } + + /// Server capabilities, encoding, etc. + pub fn server_spec(&self) -> &ServerSpec { + self.client.server_spec() + } + /// Attaches the client file descriptors to the server. - fn attach_io(self, stdin: I, stdout: O, stderr: E) -> AttachIo - where - I: AsRawFd, - O: AsRawFd, - E: AsRawFd; + pub async fn attach_io( + &mut self, + stdin: &impl AsRawFd, + stdout: &impl AsRawFd, + stderr: &impl AsRawFd, + ) -> io::Result<()> { + attachio::attach_io(self.client.borrow_protocol_mut(), stdin, stdout, stderr).await + } /// Changes the working directory of the server. - fn set_current_dir(self, dir: impl AsRef) -> OneShotRequest; + pub async fn set_current_dir(&mut self, dir: impl AsRef) -> io::Result<()> { + let dir_bytes = dir.as_ref().as_os_str().as_bytes().to_owned(); + self.client + .borrow_protocol_mut() + .send_command_with_args("chdir", dir_bytes) + .await + } /// Updates the environment variables of the server. - fn set_env_vars_os( - self, + pub async fn set_env_vars_os( + &mut self, vars: impl IntoIterator, impl AsRef)>, - ) -> OneShotRequest; + ) -> io::Result<()> { + self.client + .borrow_protocol_mut() + .send_command_with_args("setenv", message::pack_env_vars_os(vars)) + .await + } /// Changes the process title of the server. - fn set_process_name(self, name: impl AsRef) -> OneShotRequest; + pub async fn set_process_name(&mut self, name: impl AsRef) -> io::Result<()> { + let name_bytes = name.as_ref().as_bytes().to_owned(); + self.client + .borrow_protocol_mut() + .send_command_with_args("setprocname", name_bytes) + .await + } /// Changes the umask of the server process. - fn set_umask(self, mask: u32) -> OneShotRequest; + pub async fn set_umask(&mut self, mask: u32) -> io::Result<()> { + let mut mask_bytes = BytesMut::with_capacity(mem::size_of_val(&mask)); + mask_bytes.put_u32(mask); + self.client + .borrow_protocol_mut() + .send_command_with_args("setumask2", mask_bytes) + .await + } /// Runs the specified Mercurial command with cHg extension. - fn run_command_chg( - self, - handler: H, + pub async fn run_command_chg( + &mut self, + handler: &mut impl SystemHandler, args: impl IntoIterator>, - ) -> ChgRunCommand - where - H: SystemHandler; + ) -> io::Result { + runcommand::run_command( + self.client.borrow_protocol_mut(), + handler, + message::pack_args_os(args), + ) + .await + } /// Validates if the server can run Mercurial commands with the expected /// configuration. @@ -63,66 +107,15 @@ /// /// Client-side environment must be sent prior to this request, by /// `set_current_dir()` and `set_env_vars_os()`. - fn validate( - self, + pub async fn validate( + &mut self, args: impl IntoIterator>, - ) -> OneShotQuery io::Result>>; -} - -impl ChgClientExt for Client -where - C: Connection + AsRawFd, -{ - fn attach_io(self, stdin: I, stdout: O, stderr: E) -> AttachIo - where - I: AsRawFd, - O: AsRawFd, - E: AsRawFd, - { - AttachIo::with_client(self, stdin, stdout, Some(stderr)) - } - - fn set_current_dir(self, dir: impl AsRef) -> OneShotRequest { - OneShotRequest::start_with_args(self, b"chdir", dir.as_ref().as_os_str().as_bytes()) - } - - fn set_env_vars_os( - self, - vars: impl IntoIterator, impl AsRef)>, - ) -> OneShotRequest { - OneShotRequest::start_with_args(self, b"setenv", message::pack_env_vars_os(vars)) - } - - fn set_process_name(self, name: impl AsRef) -> OneShotRequest { - OneShotRequest::start_with_args(self, b"setprocname", name.as_ref().as_bytes()) - } - - fn set_umask(self, mask: u32) -> OneShotRequest { - let mut args = BytesMut::with_capacity(mem::size_of_val(&mask)); - args.put_u32_be(mask); - OneShotRequest::start_with_args(self, b"setumask2", args) - } - - fn run_command_chg( - self, - handler: H, - args: impl IntoIterator>, - ) -> ChgRunCommand - where - H: SystemHandler, - { - ChgRunCommand::with_client(self, handler, message::pack_args_os(args)) - } - - fn validate( - self, - args: impl IntoIterator>, - ) -> OneShotQuery io::Result>> { - OneShotQuery::start_with_args( - self, - b"validate", - message::pack_args_os(args), - message::parse_instructions, - ) + ) -> io::Result> { + let data = self + .client + .borrow_protocol_mut() + .query_with_args("validate", message::pack_args_os(args)) + .await?; + message::parse_instructions(data) } } diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/src/lib.rs --- a/rust/chg/src/lib.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/src/lib.rs Tue May 26 08:07:24 2020 -0700 @@ -11,5 +11,5 @@ mod runcommand; mod uihandler; -pub use clientext::ChgClientExt; +pub use clientext::ChgClient; pub use uihandler::{ChgUiHandler, SystemHandler}; diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/src/locator.rs --- a/rust/chg/src/locator.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/src/locator.rs Tue May 26 08:07:24 2020 -0700 @@ -5,7 +5,6 @@ //! Utility for locating command-server process. -use futures::future::{self, Either, Loop}; use log::debug; use std::env; use std::ffi::{OsStr, OsString}; @@ -14,14 +13,11 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; use std::os::unix::fs::{DirBuilderExt, MetadataExt}; use std::path::{Path, PathBuf}; -use std::process::{self, Command}; -use std::time::Duration; -use tokio::prelude::*; -use tokio_hglib::UnixClient; -use tokio_process::{Child, CommandExt}; -use tokio_timer; +use std::process::{self, Child, Command}; +use std::time::{Duration, Instant}; +use tokio::time; -use crate::clientext::ChgClientExt; +use crate::clientext::ChgClient; use crate::message::{Instruction, ServerSpec}; use crate::procutil; @@ -82,43 +78,33 @@ /// Connects to the server. /// /// The server process will be spawned if not running. - pub fn connect(self) -> impl Future { - future::loop_fn((self, 0), |(loc, cnt)| { - if cnt < 10 { - let fut = loc - .try_connect() - .and_then(|(loc, client)| { - client - .validate(&loc.hg_early_args) - .map(|(client, instructions)| (loc, client, instructions)) - }) - .and_then(move |(loc, client, instructions)| { - loc.run_instructions(client, instructions, cnt) - }); - Either::A(fut) - } else { - let msg = format!( - concat!( - "too many redirections.\n", - "Please make sure {:?} is not a wrapper which ", - "changes sensitive environment variables ", - "before executing hg. If you have to use a ", - "wrapper, wrap chg instead of hg.", - ), - loc.hg_command - ); - Either::B(future::err(io::Error::new(io::ErrorKind::Other, msg))) + pub async fn connect(&mut self) -> io::Result { + for _cnt in 0..10 { + let mut client = self.try_connect().await?; + let instructions = client.validate(&self.hg_early_args).await?; + let reconnect = self.run_instructions(&instructions)?; + if !reconnect { + return Ok(client); } - }) + } + + let msg = format!( + concat!( + "too many redirections.\n", + "Please make sure {:?} is not a wrapper which ", + "changes sensitive environment variables ", + "before executing hg. If you have to use a ", + "wrapper, wrap chg instead of hg.", + ), + self.hg_command + ); + Err(io::Error::new(io::ErrorKind::Other, msg)) } /// Runs instructions received from the server. - fn run_instructions( - mut self, - client: UnixClient, - instructions: Vec, - cnt: usize, - ) -> io::Result> { + /// + /// Returns true if the client should try connecting to the other server. + fn run_instructions(&mut self, instructions: &[Instruction]) -> io::Result { let mut reconnect = false; for inst in instructions { debug!("instruction: {:?}", inst); @@ -126,7 +112,7 @@ Instruction::Exit(_) => { // Just returns the current connection to run the // unparsable command and report the error - return Ok(Loop::Break((self, client))); + return Ok(false); } Instruction::Reconnect => { reconnect = true; @@ -139,7 +125,7 @@ ); return Err(io::Error::new(io::ErrorKind::InvalidData, msg)); } - self.redirect_sock_path = Some(path); + self.redirect_sock_path = Some(path.to_owned()); reconnect = true; } Instruction::Unlink(path) => { @@ -155,64 +141,44 @@ } } - if reconnect { - Ok(Loop::Continue((self, cnt + 1))) - } else { - Ok(Loop::Break((self, client))) - } + Ok(reconnect) } /// Tries to connect to the existing server, or spawns new if not running. - fn try_connect(self) -> impl Future { + async fn try_connect(&mut self) -> io::Result { let sock_path = self .redirect_sock_path .as_ref() .unwrap_or(&self.base_sock_path) .clone(); debug!("try connect to {}", sock_path.display()); - UnixClient::connect(sock_path) - .then(|res| { - match res { - Ok(client) => Either::A(future::ok((self, client))), - Err(_) => { - // Prevent us from being re-connected to the outdated - // master server: We were told by the server to redirect - // to redirect_sock_path, which didn't work. We do not - // want to connect to the same master server again - // because it would probably tell us the same thing. - if self.redirect_sock_path.is_some() { - fs::remove_file(&self.base_sock_path).unwrap_or(()); - // may race - } - Either::B(self.spawn_connect()) - } + let mut client = match ChgClient::connect(sock_path).await { + Ok(client) => client, + Err(_) => { + // Prevent us from being re-connected to the outdated + // master server: We were told by the server to redirect + // to redirect_sock_path, which didn't work. We do not + // want to connect to the same master server again + // because it would probably tell us the same thing. + if self.redirect_sock_path.is_some() { + fs::remove_file(&self.base_sock_path).unwrap_or(()); + // may race } - }) - .and_then(|(loc, client)| { - check_server_capabilities(client.server_spec())?; - Ok((loc, client)) - }) - .and_then(|(loc, client)| { - // It's purely optional, and the server might not support this command. - if client.server_spec().capabilities.contains("setprocname") { - let fut = client - .set_process_name(format!("chg[worker/{}]", loc.process_id)) - .map(|client| (loc, client)); - Either::A(fut) - } else { - Either::B(future::ok((loc, client))) - } - }) - .and_then(|(loc, client)| { - client - .set_current_dir(&loc.current_dir) - .map(|client| (loc, client)) - }) - .and_then(|(loc, client)| { - client - .set_env_vars_os(loc.env_vars.iter().cloned()) - .map(|client| (loc, client)) - }) + self.spawn_connect().await? + } + }; + check_server_capabilities(client.server_spec())?; + // It's purely optional, and the server might not support this command. + if client.server_spec().capabilities.contains("setprocname") { + client + .set_process_name(format!("chg[worker/{}]", self.process_id)) + .await?; + } + client.set_current_dir(&self.current_dir).await?; + client + .set_env_vars_os(self.env_vars.iter().cloned()) + .await?; + Ok(client) } /// Spawns new server process and connects to it. @@ -220,10 +186,10 @@ /// The server will be spawned at the current working directory, then /// chdir to "/", so that the server will load configs from the target /// repository. - fn spawn_connect(self) -> impl Future { + async fn spawn_connect(&mut self) -> io::Result { let sock_path = self.temp_sock_path(); debug!("start cmdserver at {}", sock_path.display()); - Command::new(&self.hg_command) + let server = Command::new(&self.hg_command) .arg("serve") .arg("--cmdserver") .arg("chgunix") @@ -236,68 +202,49 @@ .env_clear() .envs(self.env_vars.iter().cloned()) .env("CHGINTERNALMARK", "") - .spawn_async() - .into_future() - .and_then(|server| self.connect_spawned(server, sock_path)) - .and_then(|(loc, client, sock_path)| { - debug!( - "rename {} to {}", - sock_path.display(), - loc.base_sock_path.display() - ); - fs::rename(&sock_path, &loc.base_sock_path)?; - Ok((loc, client)) - }) + .spawn()?; + let client = self.connect_spawned(server, &sock_path).await?; + debug!( + "rename {} to {}", + sock_path.display(), + self.base_sock_path.display() + ); + fs::rename(&sock_path, &self.base_sock_path)?; + Ok(client) } /// Tries to connect to the just spawned server repeatedly until timeout /// exceeded. - fn connect_spawned( - self, - server: Child, - sock_path: PathBuf, - ) -> impl Future { + async fn connect_spawned( + &mut self, + mut server: Child, + sock_path: &Path, + ) -> io::Result { debug!("try connect to {} repeatedly", sock_path.display()); - let connect = future::loop_fn(sock_path, |sock_path| { - UnixClient::connect(sock_path.clone()).then(|res| { - match res { - Ok(client) => Either::A(future::ok(Loop::Break((client, sock_path)))), - Err(_) => { - // try again with slight delay - let fut = tokio_timer::sleep(Duration::from_millis(10)) - .map(|()| Loop::Continue(sock_path)) - .map_err(|err| io::Error::new(io::ErrorKind::Other, err)); - Either::B(fut) - } - } - }) - }); - // waits for either connection established or server failed to start - connect - .select2(server) - .map_err(|res| res.split().0) - .timeout(self.timeout) - .map_err(|err| { - err.into_inner().unwrap_or_else(|| { - io::Error::new( - io::ErrorKind::TimedOut, - "timed out while connecting to server", - ) - }) - }) - .and_then(|res| { - match res { - Either::A(((client, sock_path), server)) => { - server.forget(); // continue to run in background - Ok((self, client, sock_path)) - } - Either::B((st, _)) => Err(io::Error::new( - io::ErrorKind::Other, - format!("server exited too early: {}", st), - )), - } - }) + let start_time = Instant::now(); + while start_time.elapsed() < self.timeout { + if let Ok(client) = ChgClient::connect(&sock_path).await { + // server handle is dropped here, but the detached process + // will continue running in background + return Ok(client); + } + + if let Some(st) = server.try_wait()? { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("server exited too early: {}", st), + )); + } + + // try again with slight delay + time::delay_for(Duration::from_millis(10)).await; + } + + Err(io::Error::new( + io::ErrorKind::TimedOut, + "timed out while connecting to server", + )) } } diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/src/main.rs --- a/rust/chg/src/main.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/src/main.rs Tue May 26 08:07:24 2020 -0700 @@ -5,13 +5,12 @@ use chg::locator::{self, Locator}; use chg::procutil; -use chg::{ChgClientExt, ChgUiHandler}; -use futures::sync::oneshot; +use chg::ChgUiHandler; use std::env; use std::io; +use std::io::Write; use std::process; use std::time::Instant; -use tokio::prelude::*; struct DebugLogger { start: Instant, @@ -67,31 +66,23 @@ process::exit(code); } -fn run(umask: u32) -> io::Result { +#[tokio::main] +async fn run(umask: u32) -> io::Result { let mut loc = Locator::prepare_from_env()?; loc.set_early_args(locator::collect_early_args(env::args_os().skip(1))); - let handler = ChgUiHandler::new(); - let (result_tx, result_rx) = oneshot::channel(); - let fut = loc - .connect() - .and_then(|(_, client)| client.attach_io(io::stdin(), io::stdout(), io::stderr())) - .and_then(move |client| client.set_umask(umask)) - .and_then(|client| { - let pid = client.server_spec().process_id.unwrap(); - let pgid = client.server_spec().process_group_id; - procutil::setup_signal_handler_once(pid, pgid)?; - Ok(client) - }) - .and_then(|client| client.run_command_chg(handler, env::args_os().skip(1))) - .map(|(_client, _handler, code)| { - procutil::restore_signal_handler_once()?; - Ok(code) - }) - .or_else(|err| Ok(Err(err))) // pass back error to caller - .map(|res| result_tx.send(res).unwrap()); - tokio::run(fut); - result_rx.wait().unwrap_or(Err(io::Error::new( - io::ErrorKind::Other, - "no exit code set", - ))) + let mut handler = ChgUiHandler::new(); + let mut client = loc.connect().await?; + client + .attach_io(&io::stdin(), &io::stdout(), &io::stderr()) + .await?; + client.set_umask(umask).await?; + let pid = client.server_spec().process_id.unwrap(); + let pgid = client.server_spec().process_group_id; + procutil::setup_signal_handler_once(pid, pgid)?; + let code = client + .run_command_chg(&mut handler, env::args_os().skip(1)) + .await?; + procutil::restore_signal_handler_once()?; + handler.wait_pager().await?; + Ok(code) } diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/src/runcommand.rs --- a/rust/chg/src/runcommand.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/src/runcommand.rs Tue May 26 08:07:24 2020 -0700 @@ -6,164 +6,56 @@ //! Functions to run Mercurial command in cHg-aware command server. use bytes::Bytes; -use futures::future::IntoFuture; -use futures::{Async, Future, Poll}; use std::io; -use std::mem; use std::os::unix::io::AsRawFd; use tokio_hglib::codec::ChannelMessage; -use tokio_hglib::protocol::MessageLoop; -use tokio_hglib::{Client, Connection}; +use tokio_hglib::{Connection, Protocol}; -use crate::attachio::AttachIo; +use crate::attachio; use crate::message::{self, CommandType}; use crate::uihandler::SystemHandler; -enum AsyncS { - Ready(R), - NotReady(S), - PollAgain(S), -} - -enum CommandState -where - C: Connection, - H: SystemHandler, -{ - Running(MessageLoop, H), - SpawningPager(Client, ::Future), - AttachingPager(AttachIo, H), - WaitingSystem(Client, ::Future), - Finished, -} - -type CommandPoll = io::Result, H, i32), CommandState>>; - -/// Future resolves to `(exit_code, client)`. -#[must_use = "futures do nothing unless polled"] -pub struct ChgRunCommand -where - C: Connection, - H: SystemHandler, -{ - state: CommandState, -} - -impl ChgRunCommand -where - C: Connection + AsRawFd, - H: SystemHandler, -{ - pub fn with_client(client: Client, handler: H, packed_args: Bytes) -> ChgRunCommand { - let msg_loop = MessageLoop::start_with_args(client, b"runcommand", packed_args); - ChgRunCommand { - state: CommandState::Running(msg_loop, handler), - } - } -} - -impl Future for ChgRunCommand -where - C: Connection + AsRawFd, - H: SystemHandler, -{ - type Item = (Client, H, i32); - type Error = io::Error; - - fn poll(&mut self) -> Poll { - loop { - let state = mem::replace(&mut self.state, CommandState::Finished); - match state.poll()? { - AsyncS::Ready((client, handler, code)) => { - return Ok(Async::Ready((client, handler, code))); - } - AsyncS::NotReady(newstate) => { - self.state = newstate; - return Ok(Async::NotReady); - } - AsyncS::PollAgain(newstate) => { - self.state = newstate; - } - } - } - } -} - -impl CommandState -where - C: Connection + AsRawFd, - H: SystemHandler, -{ - fn poll(self) -> CommandPoll { - match self { - CommandState::Running(mut msg_loop, handler) => { - if let Async::Ready((client, msg)) = msg_loop.poll()? { - process_message(client, handler, msg) - } else { - Ok(AsyncS::NotReady(CommandState::Running(msg_loop, handler))) - } - } - CommandState::SpawningPager(client, mut fut) => { - if let Async::Ready((handler, pin)) = fut.poll()? { - let fut = AttachIo::with_client(client, io::stdin(), pin, None); - Ok(AsyncS::PollAgain(CommandState::AttachingPager( - fut, handler, - ))) - } else { - Ok(AsyncS::NotReady(CommandState::SpawningPager(client, fut))) - } - } - CommandState::AttachingPager(mut fut, handler) => { - if let Async::Ready(client) = fut.poll()? { - let msg_loop = MessageLoop::start(client, b""); // terminator - Ok(AsyncS::PollAgain(CommandState::Running(msg_loop, handler))) - } else { - Ok(AsyncS::NotReady(CommandState::AttachingPager(fut, handler))) - } - } - CommandState::WaitingSystem(client, mut fut) => { - if let Async::Ready((handler, code)) = fut.poll()? { - let data = message::pack_result_code(code); - let msg_loop = MessageLoop::resume_with_data(client, data); - Ok(AsyncS::PollAgain(CommandState::Running(msg_loop, handler))) - } else { - Ok(AsyncS::NotReady(CommandState::WaitingSystem(client, fut))) - } - } - CommandState::Finished => panic!("poll ChgRunCommand after it's done"), - } - } -} - -fn process_message(client: Client, handler: H, msg: ChannelMessage) -> CommandPoll -where - C: Connection, - H: SystemHandler, -{ - { - match msg { +/// Runs the given Mercurial command in cHg-aware command server, and +/// fetches the result code. +/// +/// This is a subset of tokio-hglib's `run_command()` with the additional +/// SystemRequest support. +pub async fn run_command( + proto: &mut Protocol, + handler: &mut impl SystemHandler, + packed_args: impl Into, +) -> io::Result { + proto + .send_command_with_args("runcommand", packed_args) + .await?; + loop { + match proto.fetch_response().await? { ChannelMessage::Data(b'r', data) => { - let code = message::parse_result_code(data)?; - Ok(AsyncS::Ready((client, handler, code))) + return message::parse_result_code(data); } ChannelMessage::Data(..) => { // just ignores data sent to optional channel - let msg_loop = MessageLoop::resume(client); - Ok(AsyncS::PollAgain(CommandState::Running(msg_loop, handler))) } - ChannelMessage::InputRequest(..) | ChannelMessage::LineRequest(..) => Err( - io::Error::new(io::ErrorKind::InvalidData, "unsupported request"), - ), + ChannelMessage::InputRequest(..) | ChannelMessage::LineRequest(..) => { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "unsupported request", + )); + } ChannelMessage::SystemRequest(data) => { let (cmd_type, cmd_spec) = message::parse_command_spec(data)?; match cmd_type { CommandType::Pager => { - let fut = handler.spawn_pager(cmd_spec).into_future(); - Ok(AsyncS::PollAgain(CommandState::SpawningPager(client, fut))) + // server spins new command loop while pager request is + // in progress, which can be terminated by "" command. + let pin = handler.spawn_pager(&cmd_spec).await?; + attachio::attach_io(proto, &io::stdin(), &pin, &pin).await?; + proto.send_command("").await?; // terminator } CommandType::System => { - let fut = handler.run_system(cmd_spec).into_future(); - Ok(AsyncS::PollAgain(CommandState::WaitingSystem(client, fut))) + let code = handler.run_system(&cmd_spec).await?; + let data = message::pack_result_code(code); + proto.send_data(data).await?; } } } diff -r 91e509a12dbc -r fd3b94f1712d rust/chg/src/uihandler.rs --- a/rust/chg/src/uihandler.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/chg/src/uihandler.rs Tue May 26 08:07:24 2020 -0700 @@ -3,76 +3,75 @@ // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. -use futures::future::IntoFuture; -use futures::Future; +use async_trait::async_trait; use std::io; use std::os::unix::io::AsRawFd; use std::os::unix::process::ExitStatusExt; -use std::process::{Command, Stdio}; +use std::process::Stdio; use tokio; -use tokio_process::{ChildStdin, CommandExt}; +use tokio::process::{Child, ChildStdin, Command}; use crate::message::CommandSpec; use crate::procutil; /// Callback to process shell command requests received from server. -pub trait SystemHandler: Sized { +#[async_trait] +pub trait SystemHandler { type PagerStdin: AsRawFd; - type SpawnPagerResult: IntoFuture; - type RunSystemResult: IntoFuture; /// Handles pager command request. /// /// Returns the pipe to be attached to the server if the pager is spawned. - fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult; + async fn spawn_pager(&mut self, spec: &CommandSpec) -> io::Result; /// Handles system command request. /// /// Returns command exit code (positive) or signal number (negative). - fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult; + async fn run_system(&mut self, spec: &CommandSpec) -> io::Result; } /// Default cHg implementation to process requests received from server. -pub struct ChgUiHandler {} +pub struct ChgUiHandler { + pager: Option, +} impl ChgUiHandler { pub fn new() -> ChgUiHandler { - ChgUiHandler {} + ChgUiHandler { pager: None } + } + + /// Waits until the pager process exits. + pub async fn wait_pager(&mut self) -> io::Result<()> { + if let Some(p) = self.pager.take() { + p.await?; + } + Ok(()) } } +#[async_trait] impl SystemHandler for ChgUiHandler { type PagerStdin = ChildStdin; - type SpawnPagerResult = io::Result<(Self, Self::PagerStdin)>; - type RunSystemResult = Box + Send>; - fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult { - let mut pager = new_shell_command(&spec) - .stdin(Stdio::piped()) - .spawn_async()?; - let pin = pager.stdin().take().unwrap(); + async fn spawn_pager(&mut self, spec: &CommandSpec) -> io::Result { + let mut pager = new_shell_command(&spec).stdin(Stdio::piped()).spawn()?; + let pin = pager.stdin.take().unwrap(); procutil::set_blocking_fd(pin.as_raw_fd())?; // TODO: if pager exits, notify the server with SIGPIPE immediately. // otherwise the server won't get SIGPIPE if it does not write // anything. (issue5278) // kill(peerpid, SIGPIPE); - tokio::spawn(pager.map(|_| ()).map_err(|_| ())); // just ignore errors - Ok((self, pin)) + self.pager = Some(pager); + Ok(pin) } - fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult { - let fut = new_shell_command(&spec) - .spawn_async() - .into_future() - .flatten() - .map(|status| { - let code = status - .code() - .or_else(|| status.signal().map(|n| -n)) - .expect("either exit code or signal should be set"); - (self, code) - }); - Box::new(fut) + async fn run_system(&mut self, spec: &CommandSpec) -> io::Result { + let status = new_shell_command(&spec).spawn()?.await?; + let code = status + .code() + .or_else(|| status.signal().map(|n| -n)) + .expect("either exit code or signal should be set"); + Ok(code) } } diff -r 91e509a12dbc -r fd3b94f1712d rust/hg-core/src/dirstate/status.rs --- a/rust/hg-core/src/dirstate/status.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/hg-core/src/dirstate/status.rs Tue May 26 08:07:24 2020 -0700 @@ -221,6 +221,7 @@ dmap: &'a DirstateMap, root_dir: impl AsRef + Sync + Send + 'a, options: StatusOptions, + traversed_sender: crossbeam::Sender, ) -> impl ParallelIterator> { files .unwrap_or(&DEFAULT_WORK) @@ -255,6 +256,13 @@ Some(Ok((normalized, Dispatch::Unknown))) } else { if file_type.is_dir() { + if options.collect_traversed_dirs { + // The receiver always outlives the sender, + // so unwrap. + traversed_sender + .send(normalized.to_owned()) + .unwrap() + } Some(Ok(( normalized, Dispatch::Directory { @@ -302,6 +310,9 @@ pub list_clean: bool, pub list_unknown: bool, pub list_ignored: bool, + /// Whether to collect traversed dirs for applying a callback later. + /// Used by `hg purge` for example. + pub collect_traversed_dirs: bool, } /// Dispatch a single entry (file, folder, symlink...) found during `traverse`. @@ -319,6 +330,7 @@ options: StatusOptions, filename: HgPathBuf, dir_entry: DirEntry, + traversed_sender: crossbeam::Sender, ) -> IoResult<()> { let file_type = dir_entry.file_type()?; let entry_option = dmap.get(&filename); @@ -341,6 +353,7 @@ options, entry_option, filename, + traversed_sender, ); } else if file_type.is_file() || file_type.is_symlink() { if let Some(entry) = entry_option { @@ -371,9 +384,11 @@ .unwrap(); } } else { - files_sender - .send(Ok((filename.to_owned(), Dispatch::Unknown))) - .unwrap(); + if options.list_unknown { + files_sender + .send(Ok((filename.to_owned(), Dispatch::Unknown))) + .unwrap(); + } } } else if ignore_fn(&filename) && options.list_ignored { files_sender @@ -405,6 +420,7 @@ options: StatusOptions, entry_option: Option<&'a DirstateEntry>, directory: HgPathBuf, + traversed_sender: crossbeam::Sender, ) { scope.spawn(move |_| { // Nested `if` until `rust-lang/rust#53668` is stable @@ -431,6 +447,7 @@ ignore_fn, dir_ignore_fn, options, + traversed_sender, ) .unwrap_or_else(|e| files_sender.send(Err(e)).unwrap()) } @@ -449,9 +466,15 @@ ignore_fn: &IgnoreFnType, dir_ignore_fn: &IgnoreFnType, options: StatusOptions, + traversed_sender: crossbeam::Sender, ) -> IoResult<()> { let directory = directory.as_ref(); + if options.collect_traversed_dirs { + // The receiver always outlives the sender, so unwrap. + traversed_sender.send(directory.to_owned()).unwrap() + } + let visit_entries = match matcher.visit_children_set(directory) { VisitChildrenSet::Empty => return Ok(()), VisitChildrenSet::This | VisitChildrenSet::Recursive => None, @@ -508,6 +531,7 @@ options, filename, dir_entry, + traversed_sender.clone(), )?; } } @@ -531,6 +555,7 @@ dir_ignore_fn: &IgnoreFnType, options: StatusOptions, results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>, + traversed_sender: crossbeam::Sender, ) -> IoResult<()> { let root_dir = root_dir.as_ref(); @@ -548,6 +573,7 @@ &ignore_fn, &dir_ignore_fn, options, + traversed_sender, )?; // Disconnect the channel so the receiver stops waiting @@ -638,11 +664,14 @@ pub ignored: Vec>, pub unknown: Vec>, pub bad: Vec<(Cow<'a, HgPath>, BadMatch)>, + /// Only filled if `collect_traversed_dirs` is `true` + pub traversed: Vec, } #[timed] fn build_response<'a>( results: impl IntoIterator, Dispatch)>, + traversed: Vec, ) -> (Vec>, DirstateStatus<'a>) { let mut lookup = vec![]; let mut modified = vec![]; @@ -681,6 +710,7 @@ ignored, unknown, bad, + traversed, }, ) } @@ -817,7 +847,7 @@ Vec, )> { // Needs to outlive `dir_ignore_fn` since it's captured. - let mut ignore_fn: IgnoreFnType; + let ignore_fn: IgnoreFnType; // Only involve real ignore mechanism if we're listing unknowns or ignored. let (dir_ignore_fn, warnings): (IgnoreFnType, _) = if options.list_ignored @@ -847,8 +877,17 @@ let files = matcher.file_set(); + // `crossbeam::Sender` is `Send`, while `mpsc::Sender` is not. + let (traversed_sender, traversed_recv) = crossbeam::channel::unbounded(); + // Step 1: check the files explicitly mentioned by the user - let explicit = walk_explicit(files, &dmap, root_dir, options); + let explicit = walk_explicit( + files, + &dmap, + root_dir, + options, + traversed_sender.clone(), + ); // Collect results into a `Vec` because we do very few lookups in most // cases. @@ -886,6 +925,7 @@ &dir_ignore_fn, options, &mut results, + traversed_sender.clone(), )?; } } @@ -909,5 +949,9 @@ } } - Ok((build_response(results), warnings)) + // Close the channel + drop(traversed_sender); + let traversed_dirs = traversed_recv.into_iter().collect(); + + Ok((build_response(results, traversed_dirs), warnings)) } diff -r 91e509a12dbc -r fd3b94f1712d rust/hg-core/src/filepatterns.rs --- a/rust/hg-core/src/filepatterns.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/hg-core/src/filepatterns.rs Tue May 26 08:07:24 2020 -0700 @@ -176,14 +176,15 @@ return vec![]; } match syntax { - // The `regex` crate adds `.*` to the start and end of expressions - // if there are no anchors, so add them. - PatternSyntax::Regexp => [b"^", &pattern[..], b"$"].concat(), + PatternSyntax::Regexp => pattern.to_owned(), PatternSyntax::RelRegexp => { // The `regex` crate accepts `**` while `re2` and Python's `re` // do not. Checking for `*` correctly triggers the same error all // engines. - if pattern[0] == b'^' || pattern[0] == b'*' { + if pattern[0] == b'^' + || pattern[0] == b'*' + || pattern.starts_with(b".*") + { return pattern.to_owned(); } [&b".*"[..], pattern].concat() @@ -196,15 +197,14 @@ } PatternSyntax::RootFiles => { let mut res = if pattern == b"." { - vec![b'^'] + vec![] } else { // Pattern is a directory name. - [b"^", escape_pattern(pattern).as_slice(), b"/"].concat() + [escape_pattern(pattern).as_slice(), b"/"].concat() }; // Anything after the pattern must be a non-directory. res.extend(b"[^/]+$"); - res.push(b'$'); res } PatternSyntax::RelGlob => { @@ -216,7 +216,7 @@ } } PatternSyntax::Glob | PatternSyntax::RootGlob => { - [b"^", glob_to_re(pattern).as_slice(), GLOB_SUFFIX].concat() + [glob_to_re(pattern).as_slice(), GLOB_SUFFIX].concat() } PatternSyntax::Include | PatternSyntax::SubInclude => unreachable!(), } @@ -271,7 +271,7 @@ /// that don't need to be transformed into a regex. pub fn build_single_regex( entry: &IgnorePattern, -) -> Result, PatternError> { +) -> Result>, PatternError> { let IgnorePattern { pattern, syntax, .. } = entry; @@ -288,16 +288,11 @@ if *syntax == PatternSyntax::RootGlob && !pattern.iter().any(|b| GLOB_SPECIAL_CHARACTERS.contains(b)) { - // The `regex` crate adds `.*` to the start and end of expressions - // if there are no anchors, so add the start anchor. - let mut escaped = vec![b'^']; - escaped.extend(escape_pattern(&pattern)); - escaped.extend(GLOB_SUFFIX); - Ok(escaped) + Ok(None) } else { let mut entry = entry.clone(); entry.pattern = pattern; - Ok(_build_single_regex(&entry)) + Ok(Some(_build_single_regex(&entry))) } } @@ -628,7 +623,16 @@ Path::new("") )) .unwrap(), - br"(?:.*/)?rust/target(?:/|$)".to_vec(), + Some(br"(?:.*/)?rust/target(?:/|$)".to_vec()), + ); + assert_eq!( + build_single_regex(&IgnorePattern::new( + PatternSyntax::Regexp, + br"rust/target/\d+", + Path::new("") + )) + .unwrap(), + Some(br"rust/target/\d+".to_vec()), ); } @@ -641,7 +645,7 @@ Path::new("") )) .unwrap(), - br"^\.(?:/|$)".to_vec(), + None, ); assert_eq!( build_single_regex(&IgnorePattern::new( @@ -650,7 +654,7 @@ Path::new("") )) .unwrap(), - br"^whatever(?:/|$)".to_vec(), + None, ); assert_eq!( build_single_regex(&IgnorePattern::new( @@ -659,7 +663,7 @@ Path::new("") )) .unwrap(), - br"^[^/]*\.o(?:/|$)".to_vec(), + Some(br"[^/]*\.o(?:/|$)".to_vec()), ); } } diff -r 91e509a12dbc -r fd3b94f1712d rust/hg-core/src/matchers.rs --- a/rust/hg-core/src/matchers.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/hg-core/src/matchers.rs Tue May 26 08:07:24 2020 -0700 @@ -24,6 +24,7 @@ PatternSyntax, }; +use crate::filepatterns::normalize_path_bytes; use std::borrow::ToOwned; use std::collections::HashSet; use std::fmt::{Display, Error, Formatter}; @@ -31,6 +32,8 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; +use micro_timer::timed; + #[derive(Debug, PartialEq)] pub enum VisitChildrenSet<'a> { /// Don't visit anything @@ -322,6 +325,7 @@ /// /// This can fail when the pattern is invalid or not supported by the /// underlying engine `Re2`, for instance anything with back-references. +#[timed] fn re_matcher( pattern: &[u8], ) -> PatternResult bool + Sync> { @@ -337,12 +341,15 @@ /// This can fail when the pattern is invalid or not supported by the /// underlying engine (the `regex` crate), for instance anything with /// back-references. +#[timed] fn re_matcher( pattern: &[u8], ) -> PatternResult bool + Sync> { use std::io::Write; - let mut escaped_bytes = vec![]; + // The `regex` crate adds `.*` to the start and end of expressions if there + // are no anchors, so add the start anchor. + let mut escaped_bytes = vec![b'^', b'(', b'?', b':']; for byte in pattern { if *byte > 127 { write!(escaped_bytes, "\\x{:x}", *byte).unwrap(); @@ -350,6 +357,7 @@ escaped_bytes.push(*byte); } } + escaped_bytes.push(b')'); // Avoid the cost of UTF8 checking // @@ -373,15 +381,32 @@ fn build_regex_match<'a>( ignore_patterns: &'a [&'a IgnorePattern], ) -> PatternResult<(Vec, Box bool + Sync>)> { - let regexps: Result, PatternError> = ignore_patterns - .into_iter() - .map(|k| build_single_regex(*k)) - .collect(); - let regexps = regexps?; + let mut regexps = vec![]; + let mut exact_set = HashSet::new(); + + for pattern in ignore_patterns { + if let Some(re) = build_single_regex(pattern)? { + regexps.push(re); + } else { + let exact = normalize_path_bytes(&pattern.pattern); + exact_set.insert(HgPathBuf::from_bytes(&exact)); + } + } + let full_regex = regexps.join(&b'|'); - let matcher = re_matcher(&full_regex)?; - let func = Box::new(move |filename: &HgPath| matcher(filename)); + // An empty pattern would cause the regex engine to incorrectly match the + // (empty) root directory + let func = if !(regexps.is_empty()) { + let matcher = re_matcher(&full_regex)?; + let func = move |filename: &HgPath| { + exact_set.contains(filename) || matcher(filename) + }; + Box::new(func) as Box bool + Sync> + } else { + let func = move |filename: &HgPath| exact_set.contains(filename); + Box::new(func) as Box bool + Sync> + }; Ok((full_regex, func)) } @@ -652,6 +677,12 @@ impl<'a> Display for IncludeMatcher<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + // XXX What about exact matches? + // I'm not sure it's worth it to clone the HashSet and keep it + // around just in case someone wants to display the matcher, plus + // it's going to be unreadable after a few entries, but we need to + // inform in this display that exact matches are being used and are + // (on purpose) missing from the `includes`. write!( f, "IncludeMatcher(includes='{}')", diff -r 91e509a12dbc -r fd3b94f1712d rust/hg-cpython/src/dirstate.rs --- a/rust/hg-cpython/src/dirstate.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/hg-cpython/src/dirstate.rs Tue May 26 08:07:24 2020 -0700 @@ -133,7 +133,8 @@ last_normal_time: i64, list_clean: bool, list_ignored: bool, - list_unknown: bool + list_unknown: bool, + collect_traversed_dirs: bool ) ), )?; diff -r 91e509a12dbc -r fd3b94f1712d rust/hg-cpython/src/dirstate/status.rs --- a/rust/hg-cpython/src/dirstate/status.rs Fri May 15 00:53:37 2020 +0200 +++ b/rust/hg-cpython/src/dirstate/status.rs Tue May 26 08:07:24 2020 -0700 @@ -104,6 +104,7 @@ list_clean: bool, list_ignored: bool, list_unknown: bool, + collect_traversed_dirs: bool, ) -> PyResult { let bytes = root_dir.extract::(py)?; let root_dir = get_path_from_bytes(bytes.data(py)); @@ -134,6 +135,7 @@ list_clean, list_ignored, list_unknown, + collect_traversed_dirs, }, ) .map_err(|e| handle_fallback(py, e))?; @@ -170,6 +172,7 @@ list_clean, list_ignored, list_unknown, + collect_traversed_dirs, }, ) .map_err(|e| handle_fallback(py, e))?; @@ -224,6 +227,7 @@ list_clean, list_ignored, list_unknown, + collect_traversed_dirs, }, ) .map_err(|e| handle_fallback(py, e))?; @@ -256,6 +260,7 @@ let unknown = collect_pybytes_list(py, status_res.unknown.as_ref()); let lookup = collect_pybytes_list(py, lookup.as_ref()); let bad = collect_bad_matches(py, status_res.bad.as_ref())?; + let traversed = collect_pybytes_list(py, status_res.traversed.as_ref()); let py_warnings = PyList::new(py, &[]); for warning in warnings.iter() { // We use duck-typing on the Python side for dispatch, good enough for @@ -292,6 +297,7 @@ unknown.into_object(), py_warnings.into_object(), bad.into_object(), + traversed.into_object(), ][..], )) } diff -r 91e509a12dbc -r fd3b94f1712d rust/hgcli/pyoxidizer.bzl --- a/rust/hgcli/pyoxidizer.bzl Fri May 15 00:53:37 2020 +0200 +++ b/rust/hgcli/pyoxidizer.bzl Tue May 26 08:07:24 2020 -0700 @@ -3,19 +3,16 @@ # Code to run in Python interpreter. RUN_CODE = "import hgdemandimport; hgdemandimport.enable(); from mercurial import dispatch; dispatch.run()" - set_build_path(ROOT + "/build/pyoxidizer") - def make_distribution(): return default_python_distribution() - def make_distribution_windows(): - return default_python_distribution(flavor="standalone_dynamic") - + return default_python_distribution(flavor = "standalone_dynamic") def make_exe(dist): + """Builds a Rust-wrapped Mercurial binary.""" config = PythonInterpreterConfig( raw_allocator = "system", run_eval = RUN_CODE, @@ -58,23 +55,20 @@ # On Windows, we install extra packages for convenience. if "windows" in BUILD_TARGET_TRIPLE: exe.add_python_resources( - dist.pip_install(["-r", ROOT + "/contrib/packaging/requirements_win32.txt"]) + dist.pip_install(["-r", ROOT + "/contrib/packaging/requirements_win32.txt"]), ) return exe - def make_manifest(dist, exe): m = FileManifest() m.add_python_resource(".", exe) return m - def make_embedded_resources(exe): return exe.to_embedded_resources() - register_target("distribution_posix", make_distribution) register_target("distribution_windows", make_distribution_windows) diff -r 91e509a12dbc -r fd3b94f1712d setup.py --- a/setup.py Fri May 15 00:53:37 2020 +0200 +++ b/setup.py Tue May 26 08:07:24 2020 -0700 @@ -1396,7 +1396,7 @@ env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir - cargocmd = ['cargo', 'rustc', '-vv', '--release'] + cargocmd = ['cargo', 'rustc', '--release'] feature_flags = [] diff -r 91e509a12dbc -r fd3b94f1712d tests/test-check-rust-format.t --- a/tests/test-check-rust-format.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-check-rust-format.t Tue May 26 08:07:24 2020 -0700 @@ -5,5 +5,5 @@ $ cd "$TESTDIR"/.. $ RUSTFMT=$(rustup which --toolchain nightly rustfmt) $ for f in `testrepohg files 'glob:**/*.rs'` ; do - > $RUSTFMT --check --unstable-features --color=never $f + > $RUSTFMT --check --edition=2018 --unstable-features --color=never $f > done diff -r 91e509a12dbc -r fd3b94f1712d tests/test-copies-chain-merge.t --- a/tests/test-copies-chain-merge.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-copies-chain-merge.t Tue May 26 08:07:24 2020 -0700 @@ -1,3 +1,5 @@ +#testcases filelog compatibility sidedata + ===================================================== Test Copy tracing for chain of copies involving merge ===================================================== @@ -6,6 +8,7 @@ are involved. It cheks we do not have unwanted update of behavior and that the different options to retrieve copies behave correctly. + Setup ===== @@ -18,6 +21,22 @@ > logtemplate={rev} {desc}\n > EOF +#if compatibility + $ cat >> $HGRCPATH << EOF + > [experimental] + > copies.read-from = compatibility + > EOF +#endif + +#if sidedata + $ cat >> $HGRCPATH << EOF + > [format] + > exp-use-side-data = yes + > exp-use-copies-side-data-changeset = yes + > EOF +#endif + + $ hg init repo-chain $ cd repo-chain @@ -453,17 +472,26 @@ 0 4 0dd616bc7ab1 000000000000 000000000000 1 10 6da5a2eecb9c 000000000000 000000000000 2 19 eb806e34ef6b 0dd616bc7ab1 6da5a2eecb9c + +# Here the filelog based implementation is not looking at the rename +# information (because the file exist on both side). However the changelog +# based on works fine. We have different output. + $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")' M f + b (no-filelog !) R b $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")' M f + b (no-filelog !) R b $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")' M f + d (no-filelog !) R d $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")' M f + d (no-filelog !) R d $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")' A f @@ -473,6 +501,18 @@ A f b R b + +# From here, we run status against revision where both source file exists. +# +# The filelog based implementation picks an arbitrary side based on revision +# numbers. So the same side "wins" whatever the parents order is. This is +# sub-optimal because depending on revision numbers means the result can be +# different from one repository to the next. +# +# The changeset based algorithm use the parent order to break tie on conflicting +# information and will have a different order depending on who is p1 and p2. +# That order is stable accross repositories. (data from p1 prevails) + $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")' A f d @@ -480,7 +520,8 @@ R d $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")' A f - d + d (filelog !) + b (no-filelog !) R b R d $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")' @@ -490,7 +531,8 @@ R b $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")' A f - a + a (filelog !) + b (no-filelog !) R a R b @@ -563,21 +605,25 @@ R h $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")' M d + h (no-filelog !) R h $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")' M b $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")' M b M d + i (no-filelog !) R i $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")' M d + h (no-filelog !) R h $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")' M b $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")' M b M d + i (no-filelog !) R i The following graphlog is wrong, the "a -> c -> d" chain was overwritten and should not appear. @@ -645,9 +691,15 @@ | o 0 i-0 initial commit: a b h +One side of the merge have a long history with rename. The other side of the +merge point to a new file with a smaller history. Each side is "valid". + +(and again the filelog based algorithm only explore one, with a pick based on +revision numbers) + $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")' A d - a + a (filelog !) R a $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")' A d @@ -740,7 +792,8 @@ $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")' A d - a + h (no-filelog !) + a (filelog !) R a R h $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")' @@ -754,15 +807,19 @@ M d $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")' M d + i (no-filelog !) R i $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")' M d + i (no-filelog !) R i $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")' M d + h (no-filelog !) R h $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")' M d + h (no-filelog !) R h $ hg log -Gfr 'desc("mFGm-0")' d diff -r 91e509a12dbc -r fd3b94f1712d tests/test-copies-in-changeset.t --- a/tests/test-copies-in-changeset.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-copies-in-changeset.t Tue May 26 08:07:24 2020 -0700 @@ -33,28 +33,30 @@ $ cd repo #if sidedata $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: yes yes no - copies-sdc: yes yes no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: yes yes no + persistent-nodemap: no no no + copies-sdc: yes yes no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default #else $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default #endif $ echo a > a $ hg add a @@ -424,16 +426,17 @@ downgrading (keeping some sidedata) $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: yes yes no - copies-sdc: yes yes no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: yes yes no + persistent-nodemap: no no no + copies-sdc: yes yes no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugsidedata -c -- 0 1 sidedata entries entry-0012 size 1 @@ -448,16 +451,17 @@ > EOF $ hg debugupgraderepo --run --quiet --no-backup > /dev/null $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: yes yes no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: yes yes no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugsidedata -c -- 0 $ hg debugsidedata -c -- 1 $ hg debugsidedata -m -- 0 @@ -470,16 +474,17 @@ > EOF $ hg debugupgraderepo --run --quiet --no-backup > /dev/null $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: yes yes no - copies-sdc: yes yes no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: yes yes no + persistent-nodemap: no no no + copies-sdc: yes yes no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugsidedata -c -- 0 1 sidedata entries entry-0012 size 1 diff -r 91e509a12dbc -r fd3b94f1712d tests/test-grep.t --- a/tests/test-grep.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-grep.t Tue May 26 08:07:24 2020 -0700 @@ -645,18 +645,24 @@ $ hg init sng $ cd sng $ echo "unmod" >> um - $ hg ci -A -m "adds unmod to um" - adding um + $ echo old > old + $ hg ci -q -A -m "adds unmod to um" $ echo "something else" >> new $ hg ci -A -m "second commit" adding new $ hg grep -r "." "unmod" um:1:unmod -Working directory is searched by default +Existing tracked files in the working directory are searched by default $ echo modified >> new - $ hg grep mod + $ echo 'added' > added; hg add added + $ echo 'added, missing' > added-missing; hg add added-missing; rm added-missing + $ echo 'untracked' > untracked + $ hg rm old + $ hg grep '' + added:added + new:something else new:modified um:unmod @@ -670,17 +676,6 @@ $ cd .. -Fix_Wdir(): test that passing wdir() t -r flag does greps on the -files modified in the working directory - - $ cd a - $ echo "abracadara" >> a - $ hg add a - $ hg grep -r "wdir()" "abra" - a:2147483647:abracadara - - $ cd .. - Change Default of grep by ui.tweakdefaults, that is, the files not in current working directory should not be grepp-ed on diff -r 91e509a12dbc -r fd3b94f1712d tests/test-histedit-edit.t --- a/tests/test-histedit-edit.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-histedit-edit.t Tue May 26 08:07:24 2020 -0700 @@ -373,6 +373,7 @@ transaction abort! rollback completed note: commit message saved in .hg/last-message.txt + note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it abort: pretxncommit.unexpectedabort hook exited with status 1 [255] $ cat .hg/last-message.txt @@ -397,6 +398,7 @@ transaction abort! rollback completed note: commit message saved in .hg/last-message.txt + note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it abort: pretxncommit.unexpectedabort hook exited with status 1 [255] diff -r 91e509a12dbc -r fd3b94f1712d tests/test-hook.t --- a/tests/test-hook.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-hook.t Tue May 26 08:07:24 2020 -0700 @@ -443,7 +443,7 @@ HG_PENDING=$TESTTMP/a transaction abort! - txnabort Python hook: txnid,txnname + txnabort Python hook: changes,txnid,txnname txnabort hook: HG_HOOKNAME=txnabort.1 HG_HOOKTYPE=txnabort HG_TXNID=TXN:$ID$ diff -r 91e509a12dbc -r fd3b94f1712d tests/test-lfs-serve.t --- a/tests/test-lfs-serve.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-lfs-serve.t Tue May 26 08:07:24 2020 -0700 @@ -133,30 +133,6 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store - beginning upgrade... - repository locked and read-only - creating temporary repository to stage migrated data: * (glob) - (it is safe to interrupt this process any time before data migration completes) - migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog) - migrating 324 bytes in store; 129 bytes tracked data - migrating 1 filelogs containing 1 revisions (73 bytes in store; 8 bytes tracked data) - finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes - migrating 1 manifests containing 1 revisions (117 bytes in store; 52 bytes tracked data) - finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes - migrating changelog containing 1 revisions (134 bytes in store; 69 bytes tracked data) - finished migrating 1 changelog revisions; change in size: 0 bytes - finished migrating 3 total revisions; total change in store size: 0 bytes - copying phaseroots - data fully migrated to temporary repository - marking source repository as being upgraded; clients will be unable to read from repository - starting in-place swap of repository data - replaced files will be backed up at * (glob) - replacing store... - store replacement complete; repository was inconsistent for *s (glob) - finalizing requirements file and making repository readable again - removing temporary repository * (glob) - copy of old repository backed up at * (glob) - the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified $ grep 'lfs' .hg/requires $SERVER_REQUIRES [1] diff -r 91e509a12dbc -r fd3b94f1712d tests/test-mq-qfold.t --- a/tests/test-mq-qfold.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-mq-qfold.t Tue May 26 08:07:24 2020 -0700 @@ -230,6 +230,7 @@ HG: changed a ==== note: commit message saved in .hg/last-message.txt + note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it transaction abort! rollback completed qrefresh interrupted while patch was popped! (revert --all, qpush to recover) diff -r 91e509a12dbc -r fd3b94f1712d tests/test-mq-qnew.t --- a/tests/test-mq-qnew.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-mq-qnew.t Tue May 26 08:07:24 2020 -0700 @@ -308,6 +308,7 @@ transaction abort! rollback completed note: commit message saved in .hg/last-message.txt + note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it abort: pretxncommit.unexpectedabort hook exited with status 1 [255] $ cat .hg/last-message.txt diff -r 91e509a12dbc -r fd3b94f1712d tests/test-mq-qrefresh-replace-log-message.t --- a/tests/test-mq-qrefresh-replace-log-message.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-mq-qrefresh-replace-log-message.t Tue May 26 08:07:24 2020 -0700 @@ -186,6 +186,7 @@ HG: added file2 ==== note: commit message saved in .hg/last-message.txt + note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it transaction abort! rollback completed qrefresh interrupted while patch was popped! (revert --all, qpush to recover) @@ -229,6 +230,7 @@ A file2 ==== note: commit message saved in .hg/last-message.txt + note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it transaction abort! rollback completed qrefresh interrupted while patch was popped! (revert --all, qpush to recover) diff -r 91e509a12dbc -r fd3b94f1712d tests/test-persistent-nodemap.t --- a/tests/test-persistent-nodemap.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-persistent-nodemap.t Tue May 26 08:07:24 2020 -0700 @@ -2,20 +2,34 @@ Test the persistent on-disk nodemap =================================== - $ hg init test-repo - $ cd test-repo - $ cat << EOF >> .hg/hgrc - > [experimental] - > exp-persistent-nodemap=yes + $ cat << EOF >> $HGRCPATH + > [format] + > use-persistent-nodemap=yes > [devel] > persistent-nodemap=yes > EOF - $ hg debugbuilddag .+5000 + $ hg init test-repo + $ cd test-repo + $ hg debugformat + format-variant repo + fncache: yes + dotencode: yes + generaldelta: yes + sparserevlog: yes + sidedata: no + persistent-nodemap: yes + copies-sdc: no + plain-cl-delta: yes + compression: zlib + compression-level: default + $ hg debugbuilddag .+5000 --new-file --config "storage.revlog.nodemap.mode=warn" + persistent nodemap in strict mode without efficient method (no-rust no-pure !) + persistent nodemap in strict mode without efficient method (no-rust no-pure !) $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5000 - tip-node: 06ddac466af534d365326c13c3879f97caca3cb1 - data-length: 122880 + tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c + data-length: 121088 data-unused: 0 data-unused: 0.000% $ f --size .hg/store/00changelog.n @@ -31,53 +45,56 @@ #if rust $ f --sha256 .hg/store/00changelog-*.nd - .hg/store/00changelog-????????????????.nd: sha256=1e38e9ffaa45cad13f15c1a9880ad606f4241e8beea2f61b4d5365abadfb55f6 (glob) + .hg/store/00changelog-????????????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob) + + $ f --sha256 .hg/store/00manifest-*.nd + .hg/store/00manifest-????????????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob) $ hg debugnodemap --dump-new | f --sha256 --size - size=122880, sha256=1e38e9ffaa45cad13f15c1a9880ad606f4241e8beea2f61b4d5365abadfb55f6 + size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size - size=122880, sha256=1e38e9ffaa45cad13f15c1a9880ad606f4241e8beea2f61b4d5365abadfb55f6 - 0000: 00 00 00 76 00 00 01 65 00 00 00 95 00 00 01 34 |...v...e.......4| - 0010: 00 00 00 19 00 00 01 69 00 00 00 ab 00 00 00 4b |.......i.......K| - 0020: 00 00 00 07 00 00 01 4c 00 00 00 f8 00 00 00 8f |.......L........| - 0030: 00 00 00 c0 00 00 00 a7 00 00 00 89 00 00 01 46 |...............F| - 0040: 00 00 00 92 00 00 01 bc 00 00 00 71 00 00 00 ac |...........q....| - 0050: 00 00 00 af 00 00 00 b4 00 00 00 34 00 00 01 ca |...........4....| - 0060: 00 00 00 23 00 00 01 45 00 00 00 2d 00 00 00 b2 |...#...E...-....| - 0070: 00 00 00 56 00 00 01 0f 00 00 00 4e 00 00 02 4c |...V.......N...L| - 0080: 00 00 00 e7 00 00 00 cd 00 00 01 5b 00 00 00 78 |...........[...x| - 0090: 00 00 00 e3 00 00 01 8e 00 00 00 4f 00 00 00 b1 |...........O....| - 00a0: 00 00 00 30 00 00 00 11 00 00 00 25 00 00 00 d2 |...0.......%....| - 00b0: 00 00 00 ec 00 00 00 69 00 00 01 2b 00 00 01 2e |.......i...+....| - 00c0: 00 00 00 aa 00 00 00 15 00 00 00 3a 00 00 01 4e |...........:...N| - 00d0: 00 00 00 4d 00 00 00 9d 00 00 00 8e 00 00 00 a4 |...M............| - 00e0: 00 00 00 c3 00 00 00 eb 00 00 00 29 00 00 00 ad |...........)....| - 00f0: 00 00 01 3a 00 00 01 32 00 00 00 04 00 00 00 53 |...:...2.......S| + size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd + 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........| + 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."| + 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^| + 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....| + 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8| + 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i| + 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....| + 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........| + 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....| + 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................| + 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+| + 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................| + 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5| + 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U| + 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................| + 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................| #else $ f --sha256 .hg/store/00changelog-*.nd - .hg/store/00changelog-????????????????.nd: sha256=b961925120e1c9bc345c199b2cc442abc477029fdece37ef9d99cbe59c0558b7 (glob) + .hg/store/00changelog-????????????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob) $ hg debugnodemap --dump-new | f --sha256 --size - size=122880, sha256=b961925120e1c9bc345c199b2cc442abc477029fdece37ef9d99cbe59c0558b7 + size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size - size=122880, sha256=b961925120e1c9bc345c199b2cc442abc477029fdece37ef9d99cbe59c0558b7 + size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| - 0010: ff ff ff ff ff ff ff ff ff ff fa c2 ff ff ff ff |................| - 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| - 0030: ff ff ff ff ff ff ed b3 ff ff ff ff ff ff ff ff |................| - 0040: ff ff ff ff ff ff ee 34 00 00 00 00 ff ff ff ff |.......4........| - 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| - 0060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................| + 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................| + 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............| 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| - 0080: ff ff ff ff ff ff f8 50 ff ff ff ff ff ff ff ff |.......P........| - 0090: ff ff ff ff ff ff ff ff ff ff ec c7 ff ff ff ff |................| - 00a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| - 00b0: ff ff ff ff ff ff fa be ff ff f2 fc ff ff ff ff |................| - 00c0: ff ff ff ff ff ff ef ea ff ff ff ff ff ff f9 17 |................| + 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................| + 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........| + 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| - 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| - 00f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................| + 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................| #endif @@ -88,27 +105,38 @@ add a new commit $ hg up - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved $ echo foo > foo $ hg add foo + +#if no-pure no-rust + + $ hg ci -m 'foo' --config "storage.revlog.nodemap.mode=strict" + transaction abort! + rollback completed + abort: persistent nodemap in strict mode without efficient method + [255] + +#endif + $ hg ci -m 'foo' #if no-pure no-rust $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5001 - tip-node: 2dd9b5258caa46469ff07d4a3da1eb3529a51f49 - data-length: 122880 + tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c + data-length: 121088 data-unused: 0 data-unused: 0.000% #else $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5001 - tip-node: 2dd9b5258caa46469ff07d4a3da1eb3529a51f49 - data-length: 123072 - data-unused: 192 - data-unused: 0.156% + tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c + data-length: 121344 + data-unused: 256 + data-unused: 0.211% #endif $ f --size .hg/store/00changelog.n @@ -118,17 +146,17 @@ #if pure $ f --sha256 .hg/store/00changelog-*.nd --size - .hg/store/00changelog-????????????????.nd: size=123072, sha256=136472751566c8198ff09e306a7d2f9bd18bd32298d614752b73da4d6df23340 (glob) + .hg/store/00changelog-????????????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob) #endif #if rust $ f --sha256 .hg/store/00changelog-*.nd --size - .hg/store/00changelog-????????????????.nd: size=123072, sha256=ccc8a43310ace13812fcc648683e259346754ef934c12dd238cf9b7fadfe9a4b (glob) + .hg/store/00changelog-????????????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob) #endif #if no-pure no-rust $ f --sha256 .hg/store/00changelog-*.nd --size - .hg/store/00changelog-????????????????.nd: size=122880, sha256=bfafebd751c4f6d116a76a37a1dee2a251747affe7efbcc4f4842ccc746d4db9 (glob) + .hg/store/00changelog-????????????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob) #endif $ hg debugnodemap --check @@ -140,12 +168,12 @@ $ echo bar > bar $ hg add bar - $ hg ci -m 'bar' --config experimental.exp-persistent-nodemap.mmap=no + $ hg ci -m 'bar' --config storage.revlog.nodemap.mmap=no - $ hg debugnodemap --check --config experimental.exp-persistent-nodemap.mmap=yes + $ hg debugnodemap --check --config storage.revlog.nodemap.mmap=yes revision in index: 5003 revision in nodemap: 5003 - $ hg debugnodemap --check --config experimental.exp-persistent-nodemap.mmap=no + $ hg debugnodemap --check --config storage.revlog.nodemap.mmap=no revision in index: 5003 revision in nodemap: 5003 @@ -154,34 +182,34 @@ $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5002 - tip-node: 6ce944fafcee85af91f29ea5b51654cc6101ad7e - data-length: 123328 - data-unused: 384 - data-unused: 0.311% + tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd + data-length: 121600 + data-unused: 512 + data-unused: 0.421% $ f --sha256 .hg/store/00changelog-*.nd --size - .hg/store/00changelog-????????????????.nd: size=123328, sha256=10d26e9776b6596af0f89143a54eba8cc581e929c38242a02a7b0760698c6c70 (glob) + .hg/store/00changelog-????????????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob) #endif #if rust $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5002 - tip-node: 6ce944fafcee85af91f29ea5b51654cc6101ad7e - data-length: 123328 - data-unused: 384 - data-unused: 0.311% + tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd + data-length: 121600 + data-unused: 512 + data-unused: 0.421% $ f --sha256 .hg/store/00changelog-*.nd --size - .hg/store/00changelog-????????????????.nd: size=123328, sha256=081eec9eb6708f2bf085d939b4c97bc0b6762bc8336bc4b93838f7fffa1516bf (glob) + .hg/store/00changelog-????????????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob) #endif #if no-pure no-rust $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5002 - tip-node: 6ce944fafcee85af91f29ea5b51654cc6101ad7e - data-length: 122944 + tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd + data-length: 121088 data-unused: 0 data-unused: 0.000% $ f --sha256 .hg/store/00changelog-*.nd --size - .hg/store/00changelog-????????????????.nd: size=122944, sha256=755976b22b64ab680401b45395953504e64e7fa8c31ac570f58dee21e15f9bc0 (glob) + .hg/store/00changelog-????????????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob) #endif Test force warming the cache @@ -193,16 +221,16 @@ $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5002 - tip-node: 6ce944fafcee85af91f29ea5b51654cc6101ad7e - data-length: 122944 + tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd + data-length: 121088 data-unused: 0 data-unused: 0.000% #else $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5002 - tip-node: 6ce944fafcee85af91f29ea5b51654cc6101ad7e - data-length: 122944 + tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd + data-length: 121088 data-unused: 0 data-unused: 0.000% #endif @@ -231,22 +259,22 @@ $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5003 - tip-node: 5c049e9c4a4af159bdcd65dce1b6bf303a0da6cf - data-length: 123200 (pure !) - data-length: 123200 (rust !) - data-length: 122944 (no-rust no-pure !) - data-unused: 256 (pure !) - data-unused: 256 (rust !) + tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3 + data-length: 121344 (pure !) + data-length: 121344 (rust !) + data-length: 121152 (no-rust no-pure !) + data-unused: 192 (pure !) + data-unused: 192 (rust !) data-unused: 0 (no-rust no-pure !) - data-unused: 0.208% (pure !) - data-unused: 0.208% (rust !) + data-unused: 0.158% (pure !) + data-unused: 0.158% (rust !) data-unused: 0.000% (no-rust no-pure !) $ cp -f ../tmp-copies/* .hg/store/ $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5002 - tip-node: 6ce944fafcee85af91f29ea5b51654cc6101ad7e - data-length: 122944 + tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd + data-length: 121088 data-unused: 0 data-unused: 0.000% $ hg log -r "$NODE" -T '{rev}\n' @@ -260,7 +288,7 @@ compatible with the persistent nodemap. We need to detect that. $ hg up "$NODE~5" - 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + 0 files updated, 0 files merged, 4 files removed, 0 files unresolved $ echo bar > babar $ hg add babar $ hg ci -m 'babar' @@ -276,23 +304,23 @@ $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5002 - tip-node: 42bf3068c7ddfdfded53c4eb11d02266faeebfee - data-length: 123456 (pure !) - data-length: 123008 (rust !) - data-length: 123008 (no-pure no-rust !) + tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944 + data-length: 121536 (pure !) + data-length: 121088 (rust !) + data-length: 121088 (no-pure no-rust !) data-unused: 448 (pure !) data-unused: 0 (rust !) data-unused: 0 (no-pure no-rust !) data-unused: 0.000% (rust !) - data-unused: 0.363% (pure !) + data-unused: 0.369% (pure !) data-unused: 0.000% (no-pure no-rust !) $ cp -f ../tmp-copies/* .hg/store/ $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5002 - tip-node: 6ce944fafcee85af91f29ea5b51654cc6101ad7e - data-length: 122944 + tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd + data-length: 121088 data-unused: 0 data-unused: 0.000% $ hg log -r "$OTHERNODE" -T '{rev}\n' @@ -309,36 +337,36 @@ $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5003 - tip-node: c91af76d172f1053cca41b83f7c2e4e514fe2bcf - data-length: 123008 + tip-node: a52c5079765b5865d97b993b303a18740113bbb2 + data-length: 121088 data-unused: 0 data-unused: 0.000% $ echo babar2 > babar $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata" uid: ???????????????? (glob) tip-rev: 5004 - tip-node: ba87cd9559559e4b91b28cb140d003985315e031 - data-length: 123328 (pure !) - data-length: 123328 (rust !) - data-length: 123136 (no-pure no-rust !) + tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984 + data-length: 121280 (pure !) + data-length: 121280 (rust !) + data-length: 121088 (no-pure no-rust !) data-unused: 192 (pure !) data-unused: 192 (rust !) data-unused: 0 (no-pure no-rust !) - data-unused: 0.156% (pure !) - data-unused: 0.156% (rust !) + data-unused: 0.158% (pure !) + data-unused: 0.158% (rust !) data-unused: 0.000% (no-pure no-rust !) $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5004 - tip-node: ba87cd9559559e4b91b28cb140d003985315e031 - data-length: 123328 (pure !) - data-length: 123328 (rust !) - data-length: 123136 (no-pure no-rust !) + tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984 + data-length: 121280 (pure !) + data-length: 121280 (rust !) + data-length: 121088 (no-pure no-rust !) data-unused: 192 (pure !) data-unused: 192 (rust !) data-unused: 0 (no-pure no-rust !) - data-unused: 0.156% (pure !) - data-unused: 0.156% (rust !) + data-unused: 0.158% (pure !) + data-unused: 0.158% (rust !) data-unused: 0.000% (no-pure no-rust !) Another process does not see the pending nodemap content during run. @@ -356,28 +384,28 @@ > wait-on-file 20 sync-txn-close sync-repo-read uid: ???????????????? (glob) tip-rev: 5004 - tip-node: ba87cd9559559e4b91b28cb140d003985315e031 - data-length: 123328 (pure !) - data-length: 123328 (rust !) - data-length: 123136 (no-pure no-rust !) + tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984 + data-length: 121280 (pure !) + data-length: 121280 (rust !) + data-length: 121088 (no-pure no-rust !) data-unused: 192 (pure !) data-unused: 192 (rust !) data-unused: 0 (no-pure no-rust !) - data-unused: 0.156% (pure !) - data-unused: 0.156% (rust !) + data-unused: 0.158% (pure !) + data-unused: 0.158% (rust !) data-unused: 0.000% (no-pure no-rust !) $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5005 - tip-node: bae4d45c759e30f1cb1a40e1382cf0e0414154db - data-length: 123584 (pure !) - data-length: 123584 (rust !) - data-length: 123136 (no-pure no-rust !) + tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe + data-length: 121536 (pure !) + data-length: 121536 (rust !) + data-length: 121088 (no-pure no-rust !) data-unused: 448 (pure !) data-unused: 448 (rust !) data-unused: 0 (no-pure no-rust !) - data-unused: 0.363% (pure !) - data-unused: 0.363% (rust !) + data-unused: 0.369% (pure !) + data-unused: 0.369% (rust !) data-unused: 0.000% (no-pure no-rust !) $ cat output.txt @@ -386,9 +414,9 @@ $ echo plakfe > a $ f --size --sha256 .hg/store/00changelog-*.nd - .hg/store/00changelog-????????????????.nd: size=123584, sha256=8c6cef6fd3d3fac291968793ee19a4be6d0b8375e9508bd5c7d4a8879e8df180 (glob) (pure !) - .hg/store/00changelog-????????????????.nd: size=123584, sha256=eb9e9a4bcafdb5e1344bc8a0cbb3288b2106413b8efae6265fb8a7973d7e97f9 (glob) (rust !) - .hg/store/00changelog-????????????????.nd: size=123136, sha256=4f504f5a834db3811ced50ab3e9e80bcae3581bb0f9b13a7a9f94b7fc34bcebe (glob) (no-pure no-rust !) + .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !) + .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !) + .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !) $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py" transaction abort! rollback completed @@ -397,17 +425,113 @@ $ hg debugnodemap --metadata uid: ???????????????? (glob) tip-rev: 5005 - tip-node: bae4d45c759e30f1cb1a40e1382cf0e0414154db - data-length: 123584 (pure !) - data-length: 123584 (rust !) - data-length: 123136 (no-pure no-rust !) + tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe + data-length: 121536 (pure !) + data-length: 121536 (rust !) + data-length: 121088 (no-pure no-rust !) data-unused: 448 (pure !) data-unused: 448 (rust !) data-unused: 0 (no-pure no-rust !) - data-unused: 0.363% (pure !) - data-unused: 0.363% (rust !) + data-unused: 0.369% (pure !) + data-unused: 0.369% (rust !) data-unused: 0.000% (no-pure no-rust !) $ f --size --sha256 .hg/store/00changelog-*.nd - .hg/store/00changelog-????????????????.nd: size=123584, sha256=8c6cef6fd3d3fac291968793ee19a4be6d0b8375e9508bd5c7d4a8879e8df180 (glob) (pure !) - .hg/store/00changelog-????????????????.nd: size=123584, sha256=eb9e9a4bcafdb5e1344bc8a0cbb3288b2106413b8efae6265fb8a7973d7e97f9 (glob) (rust !) - .hg/store/00changelog-????????????????.nd: size=123136, sha256=4f504f5a834db3811ced50ab3e9e80bcae3581bb0f9b13a7a9f94b7fc34bcebe (glob) (no-pure no-rust !) + .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !) + .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !) + .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !) + +Test upgrade / downgrade +======================== + +downgrading + + $ cat << EOF >> .hg/hgrc + > [format] + > use-persistent-nodemap=no + > EOF + $ hg debugformat -v + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: yes no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default + $ hg debugupgraderepo --run --no-backup --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + removed: persistent-nodemap + + $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' + [1] + $ hg debugnodemap --metadata + + +upgrading + + $ cat << EOF >> .hg/hgrc + > [format] + > use-persistent-nodemap=yes + > EOF + $ hg debugformat -v + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no yes no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default + $ hg debugupgraderepo --run --no-backup --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + added: persistent-nodemap + + $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' + 00changelog-*.nd (glob) + 00changelog.n + 00manifest-*.nd (glob) + 00manifest.n + + $ hg debugnodemap --metadata + uid: * (glob) + tip-rev: 5005 + tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe + data-length: 121088 + data-unused: 0 + data-unused: 0.000% + +Running unrelated upgrade + + $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store + + optimisations: re-delta-all + + $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' + 00changelog-*.nd (glob) + 00changelog.n + 00manifest-*.nd (glob) + 00manifest.n + + $ hg debugnodemap --metadata + uid: * (glob) + tip-rev: 5005 + tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe + data-length: 121088 + data-unused: 0 + data-unused: 0.000% diff -r 91e509a12dbc -r fd3b94f1712d tests/test-revset.t --- a/tests/test-revset.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-revset.t Tue May 26 08:07:24 2020 -0700 @@ -1864,12 +1864,12 @@ $ log 'id(2)' $ log 'id(8)' 3 - $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'id(x8)' + $ hg log --template '{rev}\n' -r 'id(x8)' 3 - $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'x8' + $ hg log --template '{rev}\n' -r 'x8' 3 - $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'id(x)' - $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'x' + $ hg log --template '{rev}\n' -r 'id(x)' + $ hg log --template '{rev}\n' -r 'x' abort: 00changelog.i@: ambiguous identifier! [255] $ log 'id(23268)' diff -r 91e509a12dbc -r fd3b94f1712d tests/test-rollback.t --- a/tests/test-rollback.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-rollback.t Tue May 26 08:07:24 2020 -0700 @@ -116,6 +116,7 @@ transaction abort! rollback completed note: commit message saved in .hg/last-message.txt + note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it abort: pretxncommit hook exited with status * (glob) [255] $ cat .hg/last-message.txt diff -r 91e509a12dbc -r fd3b94f1712d tests/test-sidedata.t --- a/tests/test-sidedata.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-sidedata.t Tue May 26 08:07:24 2020 -0700 @@ -50,27 +50,29 @@ $ hg init up-no-side-data --config format.exp-use-side-data=no $ hg debugformat -v -R up-no-side-data - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugformat -v -R up-no-side-data --config format.exp-use-side-data=yes - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no yes no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no yes no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugupgraderepo -R up-no-side-data --config format.exp-use-side-data=yes > /dev/null Check that we can downgrade from sidedata @@ -78,25 +80,27 @@ $ hg init up-side-data --config format.exp-use-side-data=yes $ hg debugformat -v -R up-side-data - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: yes no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: yes no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugformat -v -R up-side-data --config format.exp-use-side-data=no - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: yes no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: yes no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugupgraderepo -R up-side-data --config format.exp-use-side-data=no > /dev/null diff -r 91e509a12dbc -r fd3b94f1712d tests/test-tag.t --- a/tests/test-tag.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-tag.t Tue May 26 08:07:24 2020 -0700 @@ -323,6 +323,7 @@ transaction abort! rollback completed note: commit message saved in .hg/last-message.txt + note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it abort: pretxncommit.unexpectedabort hook exited with status 1 [255] $ cat .hg/last-message.txt diff -r 91e509a12dbc -r fd3b94f1712d tests/test-upgrade-repo.t --- a/tests/test-upgrade-repo.t Fri May 15 00:53:37 2020 +0200 +++ b/tests/test-upgrade-repo.t Tue May 26 08:07:24 2020 -0700 @@ -52,49 +52,53 @@ $ hg init empty $ cd empty $ hg debugformat - format-variant repo - fncache: yes - dotencode: yes - generaldelta: yes - sparserevlog: yes - sidedata: no - copies-sdc: no - plain-cl-delta: yes - compression: zlib - compression-level: default + format-variant repo + fncache: yes + dotencode: yes + generaldelta: yes + sparserevlog: yes + sidedata: no + persistent-nodemap: no + copies-sdc: no + plain-cl-delta: yes + compression: zlib + compression-level: default $ hg debugformat --verbose - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugformat --verbose --config format.usefncache=no - format-variant repo config default - fncache: yes no yes - dotencode: yes no yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes no yes + dotencode: yes no yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugformat --verbose --config format.usefncache=no --color=debug - format-variant repo config default - [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes] - [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes] - [formatvariant.name.uptodate|generaldelta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] - [formatvariant.name.uptodate|sparserevlog: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] - [formatvariant.name.uptodate|sidedata: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] - [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] - [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] - [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] - [formatvariant.name.uptodate|compression-level:][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default] + format-variant repo config default + [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes] + [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes] + [formatvariant.name.uptodate|generaldelta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] + [formatvariant.name.uptodate|sparserevlog: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] + [formatvariant.name.uptodate|sidedata: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] + [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] + [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] + [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] + [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] + [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default] $ hg debugformat -Tjson [ { @@ -130,6 +134,12 @@ { "config": false, "default": false, + "name": "persistent-nodemap", + "repo": false + }, + { + "config": false, + "default": false, "name": "copies-sdc", "repo": false }, @@ -174,6 +184,11 @@ every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved. + $ hg debugupgraderepo --quiet + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + + --optimize can be used to add optimizations $ hg debugupgrade --optimize redeltaparent @@ -183,6 +198,8 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + optimisations: re-delta-parent + re-delta-parent deltas within internal storage will choose a new base revision if needed @@ -207,6 +224,8 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + optimisations: re-delta-parent + re-delta-parent deltas within internal storage will choose a new base revision if needed @@ -221,6 +240,12 @@ re-delta-fulladd every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved. + $ hg debugupgrade --optimize re-delta-parent --quiet + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + + optimisations: re-delta-parent + unknown optimization: @@ -237,49 +262,53 @@ > EOF $ hg debugformat - format-variant repo - fncache: no - dotencode: no - generaldelta: no - sparserevlog: no - sidedata: no - copies-sdc: no - plain-cl-delta: yes - compression: zlib - compression-level: default + format-variant repo + fncache: no + dotencode: no + generaldelta: no + sparserevlog: no + sidedata: no + persistent-nodemap: no + copies-sdc: no + plain-cl-delta: yes + compression: zlib + compression-level: default $ hg debugformat --verbose - format-variant repo config default - fncache: no yes yes - dotencode: no yes yes - generaldelta: no yes yes - sparserevlog: no yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: no yes yes + dotencode: no yes yes + generaldelta: no yes yes + sparserevlog: no yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugformat --verbose --config format.usegeneraldelta=no - format-variant repo config default - fncache: no yes yes - dotencode: no yes yes - generaldelta: no no yes - sparserevlog: no no yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: no yes yes + dotencode: no yes yes + generaldelta: no no yes + sparserevlog: no no yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ hg debugformat --verbose --config format.usegeneraldelta=no --color=debug - format-variant repo config default - [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes] - [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes] - [formatvariant.name.mismatchdefault|generaldelta: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes] - [formatvariant.name.mismatchdefault|sparserevlog: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes] - [formatvariant.name.uptodate|sidedata: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] - [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] - [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] - [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] - [formatvariant.name.uptodate|compression-level:][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default] + format-variant repo config default + [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes] + [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes] + [formatvariant.name.mismatchdefault|generaldelta: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes] + [formatvariant.name.mismatchdefault|sparserevlog: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes] + [formatvariant.name.uptodate|sidedata: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] + [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] + [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] + [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] + [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] + [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default] $ hg debugupgraderepo repository lacks features recommended by current config options: @@ -328,6 +357,11 @@ re-delta-fulladd every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved. + $ hg debugupgraderepo --quiet + requirements + preserved: revlogv1, store + added: dotencode, fncache, generaldelta, sparserevlog + $ hg --config format.dotencode=false debugupgraderepo repository lacks features recommended by current config options: @@ -569,6 +603,8 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + optimisations: re-delta-parent + re-delta-parent deltas within internal storage will choose a new base revision if needed @@ -643,6 +679,8 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + optimisations: re-delta-parent + re-delta-parent deltas within internal storage will choose a new base revision if needed @@ -689,6 +727,8 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + optimisations: re-delta-parent + re-delta-parent deltas within internal storage will choose a new base revision if needed @@ -735,6 +775,8 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + optimisations: re-delta-parent + re-delta-parent deltas within internal storage will choose a new base revision if needed @@ -786,6 +828,8 @@ preserved: dotencode, fncache, generaldelta, revlogv1, store removed: sparserevlog + optimisations: re-delta-parent + re-delta-parent deltas within internal storage will choose a new base revision if needed @@ -835,6 +879,8 @@ preserved: dotencode, fncache, generaldelta, revlogv1, store added: sparserevlog + optimisations: re-delta-parent + sparserevlog Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server. @@ -923,6 +969,8 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + optimisations: re-delta-fulladd + re-delta-fulladd each revision will be added as new content to the internal storage; this will likely drastically slow down execution time, but some extensions might need it @@ -1135,6 +1183,8 @@ requirements preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + optimisations: re-delta-all + re-delta-all deltas within internal storage will be fully recomputed; this will likely drastically slow down execution time @@ -1190,9 +1240,13 @@ store Check that we can add the sparse-revlog format requirement - $ hg --config format.sparse-revlog=yes debugupgraderepo --run >/dev/null - copy of old repository backed up at $TESTTMP/sparserevlogrepo/.hg/upgradebackup.* (glob) - the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified + $ hg --config format.sparse-revlog=yes debugupgraderepo --run --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, store + added: sparserevlog + $ cat .hg/requires dotencode fncache @@ -1202,9 +1256,13 @@ store Check that we can remove the sparse-revlog format requirement - $ hg --config format.sparse-revlog=no debugupgraderepo --run >/dev/null - copy of old repository backed up at $TESTTMP/sparserevlogrepo/.hg/upgradebackup.* (glob) - the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified + $ hg --config format.sparse-revlog=no debugupgraderepo --run --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, store + removed: sparserevlog + $ cat .hg/requires dotencode fncache @@ -1219,18 +1277,25 @@ upgrade - $ hg --config format.revlog-compression=zstd debugupgraderepo --run --no-backup >/dev/null + $ hg --config format.revlog-compression=zstd debugupgraderepo --run --no-backup --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, store + added: revlog-compression-zstd, sparserevlog + $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zstd zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zstd zlib zlib + compression-level: default default default $ cat .hg/requires dotencode fncache @@ -1242,18 +1307,25 @@ downgrade - $ hg debugupgraderepo --run --no-backup > /dev/null + $ hg debugupgraderepo --run --no-backup --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + removed: revlog-compression-zstd + $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zlib zlib zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib + compression-level: default default default $ cat .hg/requires dotencode fncache @@ -1268,18 +1340,25 @@ > [format] > revlog-compression=zstd > EOF - $ hg debugupgraderepo --run --no-backup > /dev/null + $ hg debugupgraderepo --run --no-backup --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + added: revlog-compression-zstd + $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zstd zstd zlib - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zstd zstd zlib + compression-level: default default default $ cat .hg/requires dotencode fncache @@ -1296,19 +1375,28 @@ upgrade - $ hg --config format.exp-use-side-data=yes debugupgraderepo --run --no-backup --config "extensions.sidedata=$TESTDIR/testlib/ext-sidedata.py" >/dev/null + $ hg --config format.exp-use-side-data=yes debugupgraderepo --run --no-backup --config "extensions.sidedata=$TESTDIR/testlib/ext-sidedata.py" --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, store (no-zstd !) + preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !) + added: exp-sidedata-flag (zstd !) + added: exp-sidedata-flag, sparserevlog (no-zstd !) + $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: yes no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zstd zstd zlib (zstd !) - compression: zlib zlib zlib (no-zstd !) - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: yes no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib (no-zstd !) + compression: zstd zstd zlib (zstd !) + compression-level: default default default $ cat .hg/requires dotencode exp-sidedata-flag @@ -1325,19 +1413,27 @@ downgrade - $ hg debugupgraderepo --config format.exp-use-side-data=no --run --no-backup > /dev/null + $ hg debugupgraderepo --config format.exp-use-side-data=no --run --no-backup --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd !) + preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !) + removed: exp-sidedata-flag + $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: no no no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zstd zstd zlib (zstd !) - compression: zlib zlib zlib (no-zstd !) - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: no no no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib (no-zstd !) + compression: zstd zstd zlib (zstd !) + compression-level: default default default $ cat .hg/requires dotencode fncache @@ -1354,19 +1450,27 @@ > [format] > exp-use-side-data=yes > EOF - $ hg debugupgraderepo --run --no-backup > /dev/null + $ hg debugupgraderepo --run --no-backup --quiet + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd !) + preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !) + added: exp-sidedata-flag + $ hg debugformat -v - format-variant repo config default - fncache: yes yes yes - dotencode: yes yes yes - generaldelta: yes yes yes - sparserevlog: yes yes yes - sidedata: yes yes no - copies-sdc: no no no - plain-cl-delta: yes yes yes - compression: zstd zstd zlib (zstd !) - compression: zlib zlib zlib (no-zstd !) - compression-level: default default default + format-variant repo config default + fncache: yes yes yes + dotencode: yes yes yes + generaldelta: yes yes yes + sparserevlog: yes yes yes + sidedata: yes yes no + persistent-nodemap: no no no + copies-sdc: no no no + plain-cl-delta: yes yes yes + compression: zlib zlib zlib (no-zstd !) + compression: zstd zstd zlib (zstd !) + compression-level: default default default $ cat .hg/requires dotencode exp-sidedata-flag