Mercurial > evolve
changeset 5901:8bd3348c4150 mercurial-4.7
test-compat: merge mercurial-4.8 into mercurial-4.7
author | Anton Shestakov <av6@dwimlabs.net> |
---|---|
date | Sun, 25 Apr 2021 13:21:56 +0800 |
parents | be8f7eb3f3a0 (current diff) 14fe42125a7a (diff) |
children | 3641f0a2d1cc 5472f45017ce |
files | .gitlab-ci.yml tests/test-discovery-obshashrange.t tests/test-prev-next.t tests/test-topic-server.t |
diffstat | 26 files changed, 801 insertions(+), 140 deletions(-) [+] |
line wrap: on
line diff
--- a/.gitlab-ci.yml Thu Mar 11 14:48:12 2021 +0800 +++ b/.gitlab-ci.yml Sun Apr 25 13:21:56 2021 +0800 @@ -60,3 +60,14 @@ artifacts: paths: - html/* + +sdist: + stage: .post + image: registry.heptapod.net/mercurial/ci-images/py3-hgext3rd + script: + - python3 setup.py sdist + artifacts: + paths: + - dist/* + only: + - tags
--- a/.hgtags Thu Mar 11 14:48:12 2021 +0800 +++ b/.hgtags Sun Apr 25 13:21:56 2021 +0800 @@ -92,3 +92,4 @@ 782cbadb123fe4991e91a03d367e02d0b5ae969c 10.1.0 35b883a4ff5a97973eb9e6f00014e71f14cebe70 10.2.0 eadc1d09f2f567fdae7280aefc8cf4cdc4d78cbc 10.2.0.post1 +c0ed8e57463875414d1c06f0428d550c4480d289 10.3.0
--- a/CHANGELOG Thu Mar 11 14:48:12 2021 +0800 +++ b/CHANGELOG Sun Apr 25 13:21:56 2021 +0800 @@ -1,25 +1,40 @@ Changelog ========= -10.3.0 - in progress +10.3.1 - in progress -------------------- + * cache: fix corruption issue when mixing 32-bit and 64-bit environments + * next: unstable changesets with a different topic are no longer targets for + hg next as long as it's invoked without --no-topic flag + * next: when some potential targets are unstable, ask user which changeset + they want to update to (only mixing stable and unstable when --evolve flag + is given, which is the default) + +10.3.0 -- 2021-03-11 +-------------------- + + * doc: document stack as a substitue for MQ's qseries + * doc: document revsets provided by evolve extension + * evolve: add a experimental.evolution.in-memory config for running evolve in memory (hg >= 5.6) * evolve: improve content-divergence resolution that involves parent changes * evolve: preserve wdir parent when using `hg evolve --stop` + * obslog: clarify the command name in the help, + * pdiff, pstatus: drop some irrelevant command flags inherited from `hg diff` and `hg status` respectively + * rewind: detect and abort on cases when we rewind to changesets that are precessors / successors of each other * rewind: when user gives only some parts of a fold, include the other parts as well, or abort if they are missing from local repo -10.2.1 - in progress --------------------- +topic (0.22.0) - * doc: document stack as a substitue for MQ's qseries + * doc: change topic phrase 'disappear' to 'fade out' 10.2.0.post1 -- 2021-02-01 --------------------------
--- a/Makefile Thu Mar 11 14:48:12 2021 +0800 +++ b/Makefile Sun Apr 25 13:21:56 2021 +0800 @@ -1,4 +1,4 @@ -PYTHON ?= python +PYTHON ?= python3 VERSION = $(shell python setup.py --version) TESTFLAGS ?= $(shell echo $$HGTESTFLAGS) HGTESTS = $(HGROOT)/tests
--- a/debian/changelog Thu Mar 11 14:48:12 2021 +0800 +++ b/debian/changelog Sun Apr 25 13:21:56 2021 +0800 @@ -1,3 +1,9 @@ +mercurial-evolve (10.3.0-1) unstable; urgency=medium + + * new upstream release + + -- Anton Shestakov <av6@dwimlabs.net> Thu, 11 Mar 2021 18:32:26 +0800 + mercurial-evolve (10.2.0.post1-1) unstable; urgency=medium * identical release
--- a/hgext3rd/evolve/__init__.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/__init__.py Sun Apr 25 13:21:56 2021 +0800 @@ -743,13 +743,13 @@ else: header = _(b"multiple parents, choose one to update:") prevs = [p.rev() for p in parents] - choosedrev = utility.revselectionprompt(repo.ui, repo, prevs, header) - if choosedrev is None: + selectedrev = utility.revselectionprompt(repo.ui, repo, prevs, header) + if selectedrev is None: for p in parents: display(p) repo.ui.warn(_(b'multiple parents, explicitly update to one\n')) else: - target = repo[choosedrev] + target = repo[selectedrev] return target, bookmark @eh.command( @@ -845,9 +845,9 @@ topic = _getcurrenttopic(repo) filtered = set() template = shorttemplate - if topic and not opts.get("no_topic", False): - filtered = set(ctx for ctx in children if ctx.topic() != topic) - children = [ctx for ctx in children if ctx not in filtered] + if topic and not opts['no_topic']: + filtered = set(ctx.rev() for ctx in children if ctx.topic() != topic) + children = [ctx for ctx in children if ctx.rev() not in filtered] template = utility.stacktemplate opts['stacktemplate'] = True display = compat.format_changeset_summary_fn(ui, repo, b'next', @@ -856,10 +856,10 @@ # check if we need to evolve while updating to the next child revision needevolve = False aspchildren = evolvecmd._aspiringchildren(repo, [repo[b'.'].rev()]) - if topic: - filtered.update(repo[c] for c in aspchildren - if repo[c].topic() != topic) - aspchildren = [ctx for ctx in aspchildren if ctx not in filtered] + if topic and not opts['no_topic']: + filtered.update(rev for rev in aspchildren + if repo[rev].topic() != topic) + aspchildren = [rev for rev in aspchildren if rev not in filtered] # To catch and prevent the case when `next` would get confused by split, # lets filter those aspiring children which can be stablized on one of @@ -869,7 +869,7 @@ possdests = evolvecmd._possibledestination(repo, aspchild) if possdests & aspirants: filtered.add(aspchild) - aspchildren = [ctx for ctx in aspchildren if ctx not in filtered] + aspchildren = [rev for rev in aspchildren if rev not in filtered] if aspchildren: needevolve = True @@ -885,21 +885,21 @@ else: cmdutil.bailifchanged(repo, hint=_(b'do you want --merge?')) - if len(children) == 1: + if len(children) == 1 and (not opts['evolve'] or not aspchildren): c = children[0] return _updatetonext(ui, repo, c, display, opts) elif children: cheader = _(b"ambiguous next changeset, choose one to update:") - crevs = [c.rev() for c in children] - choosedrev = utility.revselectionprompt(ui, repo, crevs, cheader) - if choosedrev is None: + crevs = [c.rev() for c in children] + aspchildren + selectedrev = utility.revselectionprompt(ui, repo, crevs, cheader) + if selectedrev is None: ui.warn(_(b"ambiguous next changeset:\n")) - for c in children: - display(c) + for rev in crevs: + display(repo[rev]) ui.warn(_(b"explicitly update to one of them\n")) return 1 else: - return _updatetonext(ui, repo, repo[choosedrev], display, opts) + return _updatetonext(ui, repo, repo[selectedrev], display, opts) else: if not opts['evolve'] or not aspchildren: if filtered: @@ -915,16 +915,16 @@ elif len(aspchildren) > 1: cheader = _(b"ambiguous next (unstable) changeset, choose one to" b" evolve and update:") - choosedrev = utility.revselectionprompt(ui, repo, - aspchildren, cheader) - if choosedrev is None: + selectedrev = utility.revselectionprompt(ui, repo, + aspchildren, cheader) + if selectedrev is None: ui.warn(_(b"ambiguous next (unstable) changeset:\n")) for c in aspchildren: display(repo[c]) ui.warn(_(b"(run 'hg evolve --rev REV' on one of them)\n")) return 1 else: - return _nextevolve(ui, repo, repo[choosedrev], opts) + return _nextevolve(ui, repo, repo[selectedrev], opts) else: return _nextevolve(ui, repo, aspchildren[0], opts) finally:
--- a/hgext3rd/evolve/compat.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/compat.py Sun Apr 25 13:21:56 2021 +0800 @@ -6,7 +6,6 @@ Compatibility module """ -import array import contextlib from mercurial import ( @@ -17,7 +16,6 @@ logcmdutil, merge as mergemod, obsolete, - pycompat, registrar, repair, scmutil, @@ -25,13 +23,6 @@ ui as uimod, ) -if pycompat.ispy3: - arraytobytes = array.array.tobytes - arrayfrombytes = array.array.frombytes -else: - arraytobytes = array.array.tostring - arrayfrombytes = array.array.fromstring - # hg <= 5.2 (c21aca51b392) try: from mercurial import pathutil
--- a/hgext3rd/evolve/depthcache.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/depthcache.py Sun Apr 25 13:21:56 2021 +0800 @@ -11,6 +11,7 @@ import array +from mercurial.i18n import _ from mercurial import ( localrepo, scmutil, @@ -26,8 +27,6 @@ utility, ) -from mercurial.i18n import _ - filterparents = utility.filterparents eh = exthelper.exthelper() @@ -117,7 +116,7 @@ def progress(pos, rev=None): revstr = b'' if rev is None else (b'rev %d' % rev) compat.progress(repo.ui, b'updating depth cache', - pos, revstr, unit=b'revision', total=total) + pos, revstr, unit=_(b'changesets'), total=total) progress(0) for idx, rev in enumerate(data, 1): assert rev == len(self._data), (rev, len(self._data)) @@ -182,20 +181,23 @@ assert repo.filtername is None data = repo.cachevfs.tryread(self._filepath) + self._cachekey = self.emptykey self._data = array.array(r'l') - if not data: - self._cachekey = self.emptykey - else: + if data: headerdata = data[:self._cachekeysize] - self._cachekey = self._deserializecachekey(headerdata) - compat.arrayfrombytes(self._data, data[self._cachekeysize:]) + cachekey = self._deserializecachekey(headerdata) + expected = self._datastruct.size * (cachekey[0] + 1) + data = data[self._cachekeysize:] + if len(data) == expected: + self._data.extend(self._deserializedata(data)) + self._cachekey = cachekey + else: + repo.ui.debug(b'depthcache file seems to be corrupted, ' + b'it will be rebuilt from scratch\n') self._ondiskkey = self._cachekey def save(self, repo): """save the data to disk - - Format is pretty simple, we serialise the cache key and then drop the - bytearray. """ if self._cachekey is None or self._cachekey == self._ondiskkey: return @@ -204,7 +206,7 @@ cachefile = repo.cachevfs(self._filepath, b'w', atomictemp=True) headerdata = self._serializecachekey() cachefile.write(headerdata) - cachefile.write(compat.arraytobytes(self._data)) + cachefile.write(self._serializedata(self._data)) cachefile.close() self._ondiskkey = self._cachekey except (IOError, OSError) as exc:
--- a/hgext3rd/evolve/firstmergecache.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/firstmergecache.py Sun Apr 25 13:21:56 2021 +0800 @@ -11,6 +11,7 @@ import array +from mercurial.i18n import _ from mercurial import ( localrepo, node as nodemod, @@ -30,6 +31,15 @@ eh = exthelper.exthelper() +@eh.command(b'debugfirstmergecache', []) +def debugfirstmergecache(ui, repo, **opts): + """display the contents of firstmergecache""" + cache = repo.firstmergecache + cache.save(repo) + for r in repo: + ctx = repo[r] + ui.write(b'%s %d\n' % (ctx, cache.get(r))) + @eh.reposetup def setupcache(ui, repo): @@ -43,7 +53,7 @@ @localrepo.unfilteredmethod def destroyed(self): - if r'firstmergecach' in vars(self): + if r'firstmergecache' in vars(self): self.firstmergecache.clear() super(firstmergecacherepo, self).destroyed() @@ -79,7 +89,7 @@ def progress(pos, rev=None): revstr = b'' if rev is None else (b'rev %d' % rev) compat.progress(repo.ui, b'updating firstmerge cache', - pos, revstr, unit=b'revision', total=total) + pos, revstr, unit=_(b'changesets'), total=total) progress(0) for idx, rev in enumerate(data, 1): assert rev == len(self._data), (rev, len(self._data)) @@ -119,20 +129,23 @@ assert repo.filtername is None data = repo.cachevfs.tryread(self._filepath) + self._cachekey = self.emptykey self._data = array.array(r'l') - if not data: - self._cachekey = self.emptykey - else: + if data: headerdata = data[:self._cachekeysize] - self._cachekey = self._deserializecachekey(headerdata) - compat.arrayfrombytes(self._data, data[self._cachekeysize:]) + cachekey = self._deserializecachekey(headerdata) + expected = self._datastruct.size * (cachekey[0] + 1) + data = data[self._cachekeysize:] + if len(data) == expected: + self._data.extend(self._deserializedata(data)) + self._cachekey = cachekey + else: + repo.ui.debug(b'firstmergecache file seems to be corrupted, ' + b'it will be rebuilt from scratch\n') self._ondiskkey = self._cachekey def save(self, repo): """save the data to disk - - Format is pretty simple, we serialise the cache key and then drop the - bytearray. """ if self._cachekey is None or self._cachekey == self._ondiskkey: return @@ -141,7 +154,7 @@ cachefile = repo.cachevfs(self._filepath, b'w', atomictemp=True) headerdata = self._serializecachekey() cachefile.write(headerdata) - cachefile.write(compat.arraytobytes(self._data)) + cachefile.write(self._serializedata(self._data)) cachefile.close() self._ondiskkey = self._cachekey except (IOError, OSError) as exc:
--- a/hgext3rd/evolve/genericcaches.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/genericcaches.py Sun Apr 25 13:21:56 2021 +0800 @@ -34,6 +34,8 @@ _cachekeyspec = b'' # used for serialization _cachename = None # used for debug message + _datastruct = struct.Struct('<q') + @abc.abstractmethod def __init__(self): super(incrementalcachebase, self).__init__() @@ -67,7 +69,7 @@ Subclasses MUST overide this method to actually affect the cache data. """ if reset: - self._cachekey = self.emptykey if reset else None + self._cachekey = self.emptykey else: self._cachekey = None @@ -133,6 +135,17 @@ """read the cachekey from bytes""" return self._cachekeystruct.unpack(data) + def _serializedata(self, data): + """turn data into binary form""" + return b''.join(self._datastruct.pack(item) for item in data) + + def _deserializedata(self, data): + """turn binary into data""" + return ( + self._datastruct.unpack_from(data, i)[0] + for i in range(0, len(data), self._datastruct.size) + ) + class changelogsourcebase(incrementalcachebase): # pytype: disable=ignored-metaclass """an abstract class for cache sourcing data from the changelog @@ -143,7 +156,7 @@ __metaclass__ = abc.ABCMeta # default key used for an empty cache - emptykey = (0, node.nullid) + emptykey = (node.nullrev, node.nullid) _cachekeyspec = b'i20s' _cachename = None # used for debug message @@ -153,10 +166,9 @@ """use a cachekey to fetch incremental data Exists as its own method to help subclass to reuse it.""" - tiprev = len(cl) - 1 + tiprev = cl.tiprev() tipnode = cl.node(tiprev) newkey = (tiprev, tipnode) - tiprev = len(cl) - 1 if newkey == cachekey: return False, [], newkey keyrev, keynode = cachekey
--- a/hgext3rd/evolve/metadata.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/metadata.py Sun Apr 25 13:21:56 2021 +0800 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -__version__ = b'10.3.0.dev' +__version__ = b'10.3.1.dev' testedwith = b'4.6.2 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7' minimumhgversion = b'4.6' buglink = b'https://bz.mercurial-scm.org/'
--- a/hgext3rd/evolve/obscache.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/obscache.py Sun Apr 25 13:21:56 2021 +0800 @@ -137,7 +137,7 @@ # /!\ IMPORTANT /!\ # You must overide this method to actually if reset: - self._cachekey = self.emptykey if reset else None + self._cachekey = self.emptykey else: self._cachekey = None @@ -195,7 +195,7 @@ # update the key from the new data key = list(self._cachekey) if revs: - key[0] = len(cl) - 1 + key[0] = cl.tiprev() key[1] = cl.node(key[0]) if obsmarkers: key[2] += len(obsmarkers) @@ -213,7 +213,7 @@ ### Is the cache valid ? keytiprev, keytipnode, keyobslength, keyobssize, keyobskey = key # check for changelog strip - tiprev = len(changelog) - 1 + tiprev = changelog.tiprev() if (tiprev < keytiprev or changelog.node(keytiprev) != keytipnode): return None @@ -251,7 +251,7 @@ reset = True key = self.emptykey obssize, obskey = obsstore.cachekey() - tiprev = len(cl) - 1 + tiprev = cl.tiprev() else: tiprev, obssize, obskey = status
--- a/hgext3rd/evolve/obsdiscovery.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/obsdiscovery.py Sun Apr 25 13:21:56 2021 +0800 @@ -22,6 +22,7 @@ import struct import weakref +from mercurial.i18n import _ from mercurial import ( encoding, error, @@ -34,7 +35,6 @@ store, util, ) -from mercurial.i18n import _ from mercurial.utils.stringutil import forcebytestr @@ -472,7 +472,7 @@ def progress(pos, rev=None): revstr = b'' if rev is None else (b'rev %d' % rev) compat.progress(repo.ui, b'updating obshashrange cache', - pos, revstr, unit=b'revision', total=total) + pos, revstr, unit=_(b'changesets'), total=total) # warm the cache for the new revs progress(0) for idx, r in enumerate(revs):
--- a/hgext3rd/evolve/stablerange.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/stablerange.py Sun Apr 25 13:21:56 2021 +0800 @@ -953,7 +953,7 @@ starttime = util.timer() if upto is None: - upto = len(cl) - 1 + upto = cl.tiprev() if self._tiprev is None: revs = cl.revs(stop=upto) nbrevs = upto + 1
--- a/hgext3rd/evolve/stablerangecache.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/stablerangecache.py Sun Apr 25 13:21:56 2021 +0800 @@ -14,6 +14,7 @@ import sqlite3 import time +from mercurial.i18n import _ from mercurial import ( commands, encoding, @@ -34,8 +35,6 @@ utility, ) -from mercurial.i18n import _ - eh = exthelper.exthelper() LONG_WARNING_TIME = 60
--- a/hgext3rd/evolve/stablesort.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/evolve/stablesort.py Sun Apr 25 13:21:56 2021 +0800 @@ -250,6 +250,7 @@ import collections import struct +from mercurial.i18n import _ from mercurial import ( commands, error, @@ -262,8 +263,6 @@ from mercurial.utils.stringutil import forcebytestr -from mercurial.i18n import _ - from . import ( compat, depthcache, @@ -337,11 +336,12 @@ unfi = repo.unfiltered() revs = unfi.revs('all()') nbrevs = len(revs) - ui.write('number of revisions: %12d\n' % nbrevs) + ui.write(b'number of revisions: %12d\n' % nbrevs) merge = unfi.revs('merge()') nbmerge = len(merge) cache = unfi.stablesort - ui.write('number of merge: %12d\n' % nbmerge) + cache.save(repo) + ui.write(b'number of merge: %12d\n' % nbmerge) alljumps = [] alljumpssize = [] for r in merge: @@ -352,20 +352,20 @@ alljumps.append(jumps) alljumpssize.append(len(jumps)) nbjumps = sum(alljumpssize) - ui.write('number of jumps: %12d\n' % nbjumps) + ui.write(b'number of jumps: %12d\n' % nbjumps) if not nbjumps: return 0 avgjumps = nbjumps / float(len(alljumpssize)) - ui.write('average jumps: %6.3f\n' % avgjumps) + ui.write(b'average jumps: %6.3f\n' % avgjumps) alljumpssize.sort() medianjumps = alljumpssize[len(alljumpssize) // 2] - ui.write('median jumps: %12d\n' % medianjumps) + ui.write(b'median jumps: %12d\n' % medianjumps) tensjumps = alljumpssize[len(alljumpssize) * 9 // 10] - ui.write('90%% jumps: %12d\n' % tensjumps) + ui.write(b'90%% jumps: %12d\n' % tensjumps) centsjumps = alljumpssize[len(alljumpssize) * 99 // 100] - ui.write('99%% jumps: %12d\n' % centsjumps) - ui.write('max jumps: %12d\n' % max(alljumpssize)) - ui.write('jump cache size: %12d bytes\n' % (nbjumps * 12)) + ui.write(b'99%% jumps: %12d\n' % centsjumps) + ui.write(b'max jumps: %12d\n' % max(alljumpssize)) + ui.write(b'jump cache size: %12d bytes\n' % (nbjumps * 12)) def stablesort_branchpoint(repo, revs, mergecallback=None): """return '::revs' topologically sorted in "stable" order @@ -864,7 +864,7 @@ def progress(pos, rev=None): revstr = b'' if rev is None else (b'rev %d' % rev) compat.progress(repo.ui, b'updating stablesort cache', - pos, revstr, unit=b'revision', total=total) + pos, revstr, unit=_(b'changesets'), total=total) progress(0) for idx, rev in enumerate(data): @@ -895,20 +895,31 @@ assert repo.filtername is None data = repo.cachevfs.tryread(self._filepath) + self._cachekey = self.emptykey self._index = array.array(r'l') self._data = array.array(r'l') - if not data: - self._cachekey = self.emptykey - else: + if data: headerdata = data[:self._cachekeysize] - self._cachekey = self._deserializecachekey(headerdata) + cachekey = self._deserializecachekey(headerdata) offset = self._cachekeysize indexsizedata = data[offset:offset + S_INDEXSIZE.size] indexsize = S_INDEXSIZE.unpack(indexsizedata)[0] offset += S_INDEXSIZE.size - compat.arrayfrombytes(self._index, data[offset:offset + indexsize]) - offset += indexsize - compat.arrayfrombytes(self._data, data[offset:]) + if indexsize % self._datastruct.size == 0 and len(data) - offset >= indexsize: + index = list(self._deserializedata(data[offset:offset + indexsize])) + offset += indexsize + expected = index[-1] * self._datastruct.size * 3 + data = data[offset:] + else: + # index cannot be read, so we need to abort somehow + expected = None + if len(data) == expected: + self._index.extend(index) + self._data.extend(self._deserializedata(data)) + self._cachekey = cachekey + else: + repo.ui.debug(b'stablesortcache file seems to be corrupted, ' + b'it will be rebuilt from scratch\n') self._ondiskkey = self._cachekey pass @@ -924,8 +935,8 @@ # data to write headerdata = self._serializecachekey() - indexdata = compat.arraytobytes(self._index) - data = compat.arraytobytes(self._data) + indexdata = self._serializedata(self._index) + data = self._serializedata(self._data) indexsize = S_INDEXSIZE.pack(len(indexdata)) # writing
--- a/hgext3rd/serverminitopic.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/serverminitopic.py Sun Apr 25 13:21:56 2021 +0800 @@ -167,8 +167,12 @@ else: # hg <= 4.9 (624d6683c705+b137a6793c51) _entries = self - new = self.__class__(_entries, self.tipnode, self.tiprev, - self.filteredhash, self._closednodes) + args = (_entries, self.tipnode, self.tiprev, self.filteredhash, + self._closednodes) + if util.safehasattr(self, '_repo'): + # hg <= 5.7 (6266d19556ad) + args = (self._repo,) + args + new = self.__class__(*args) new.phaseshash = self.phaseshash return new
--- a/hgext3rd/topic/__init__.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/topic/__init__.py Sun Apr 25 13:21:56 2021 +0800 @@ -232,7 +232,7 @@ b'topic.active': b'green', } -__version__ = b'0.22.0.dev' +__version__ = b'0.22.1.dev' testedwith = b'4.6.2 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7' minimumhgversion = b'4.6'
--- a/hgext3rd/topic/topicmap.py Thu Mar 11 14:48:12 2021 +0800 +++ b/hgext3rd/topic/topicmap.py Sun Apr 25 13:21:56 2021 +0800 @@ -173,8 +173,12 @@ else: # hg <= 4.9 (624d6683c705+b137a6793c51) _entries = self - new = self.__class__(_entries, self.tipnode, self.tiprev, - self.filteredhash, self._closednodes) + args = (_entries, self.tipnode, self.tiprev, self.filteredhash, + self._closednodes) + if util.safehasattr(self, '_repo'): + # hg <= 5.7 (6266d19556ad) + args = (self._repo,) + args + new = self.__class__(*args) new.phaseshash = self.phaseshash return new
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-cache-corruption.t Sun Apr 25 13:21:56 2021 +0800 @@ -0,0 +1,360 @@ +Testing cache corruption and recovery +https://bz.mercurial-scm.org/show_bug.cgi?id=6354 + + $ . $TESTDIR/testlib/pythonpath.sh + + $ cat << EOF >> $HGRCPATH + > [extensions] + > evolve = + > [experimental] + > obshashrange = 1 + > obshashrange.warm-cache = yes + > [ui] + > logtemplate = "{rev} {node|short} {desc} {tags}\n" + > EOF + + $ cat >> repack.py << EOF + > import struct + > import sys + > # imitating array.array().tobytes() with a platform-dependent item size + > sixtyfour = struct.Struct('<q') # as seen on 64-bit platforms + > thirtytwo = struct.Struct('<l') # as seen on 32-bit platforms + > iss = struct.Struct('<I') # for rewriting indexsize of stablesortcache + > data = [] + > with open(sys.argv[1], 'rb') as f: + > header = f.read(24) + > if '--index' in sys.argv: + > indexsize = iss.unpack(f.read(iss.size))[0] + > while True: + > buf = f.read(sixtyfour.size) + > if not buf: break + > data.append(sixtyfour.unpack(buf)[0]) + > with open(sys.argv[1], 'wb') as f: + > f.write(header) + > if '--index' in sys.argv: + > indexsize = int(indexsize * thirtytwo.size / sixtyfour.size) + > f.write(iss.pack(indexsize)) + > for item in data: + > f.write(thirtytwo.pack(item)) + > EOF + + $ cat >> truncate.py << EOF + > import os + > import sys + > with open(sys.argv[1], 'ab') as fp: + > fp.seek(int(sys.argv[2]), os.SEEK_END) + > fp.truncate() + > EOF + +Simple linear setup + + $ hg init linear + $ cd linear + + $ hg debugbuilddag '+3' + $ hg log -G + o 2 01241442b3c2 r2 tip + | + o 1 66f7d451a68b r1 + | + o 0 1ea73414a91b r0 + + $ f -s .hg/cache/evoext-* + .hg/cache/evoext-depthcache-00: size=48 + .hg/cache/evoext-firstmerge-00: size=48 + .hg/cache/evoext-obscache-00: size=67 + .hg/cache/evoext-stablesortcache-00: size=52 + +testing depthcache + + $ f -H .hg/cache/evoext-depthcache-00 + .hg/cache/evoext-depthcache-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 01 00 00 00 00 00 00 00 |I.U.e...........| + 0020: 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 |................| + + $ hg debugdepth --rev 'all()' --method compare --debug + 1ea73414a91b 1 + 66f7d451a68b 2 + 01241442b3c2 3 + + $ "$PYTHON" ../repack.py .hg/cache/evoext-depthcache-00 + $ f -H .hg/cache/evoext-depthcache-00 + .hg/cache/evoext-depthcache-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 01 00 00 00 02 00 00 00 |I.U.e...........| + 0020: 03 00 00 00 |....| + + $ hg debugdepth --rev 'all()' --method compare --debug + depthcache file seems to be corrupted, it will be rebuilt from scratch + 1ea73414a91b 1 + 66f7d451a68b 2 + 01241442b3c2 3 + + $ "$PYTHON" ../truncate.py .hg/cache/evoext-depthcache-00 -4 + $ f -H .hg/cache/evoext-depthcache-00 + .hg/cache/evoext-depthcache-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 01 00 00 00 00 00 00 00 |I.U.e...........| + 0020: 02 00 00 00 00 00 00 00 03 00 00 00 |............| + + $ hg debugdepth --rev 'all()' --method compare --debug + depthcache file seems to be corrupted, it will be rebuilt from scratch + 1ea73414a91b 1 + 66f7d451a68b 2 + 01241442b3c2 3 + +testing firstmergecache + + $ f -H .hg/cache/evoext-firstmerge-00 + .hg/cache/evoext-firstmerge-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 ff ff ff ff ff ff ff ff |I.U.e...........| + 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + + $ hg debugfirstmergecache --debug + 1ea73414a91b -1 + 66f7d451a68b -1 + 01241442b3c2 -1 + + $ "$PYTHON" ../repack.py .hg/cache/evoext-firstmerge-00 + $ f -H .hg/cache/evoext-firstmerge-00 + .hg/cache/evoext-firstmerge-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 ff ff ff ff ff ff ff ff |I.U.e...........| + 0020: ff ff ff ff |....| + + $ hg debugfirstmergecache --debug + firstmergecache file seems to be corrupted, it will be rebuilt from scratch + 1ea73414a91b -1 + 66f7d451a68b -1 + 01241442b3c2 -1 + + $ "$PYTHON" ../truncate.py .hg/cache/evoext-firstmerge-00 -4 + $ f -H .hg/cache/evoext-firstmerge-00 + .hg/cache/evoext-firstmerge-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 ff ff ff ff ff ff ff ff |I.U.e...........| + 0020: ff ff ff ff ff ff ff ff ff ff ff ff |............| + + $ hg debugfirstmergecache --debug + firstmergecache file seems to be corrupted, it will be rebuilt from scratch + 1ea73414a91b -1 + 66f7d451a68b -1 + 01241442b3c2 -1 + +testing stablesortcache + + $ f -H .hg/cache/evoext-stablesortcache-00 + .hg/cache/evoext-stablesortcache-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 00 00 00 18 00 00 00 00 |I.U.e...........| + 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0030: 00 00 00 00 |....| + + $ hg debugstablesortcache --debug + number of revisions: 3 + number of merge: 0 + number of jumps: 0 + + $ "$PYTHON" ../repack.py .hg/cache/evoext-stablesortcache-00 --index + $ f -H .hg/cache/evoext-stablesortcache-00 + .hg/cache/evoext-stablesortcache-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 00 00 00 0c 00 00 00 00 |I.U.e...........| + 0020: 00 00 00 00 00 00 00 00 |........| + + $ hg debugstablesortcache --debug + number of revisions: 3 + stablesortcache file seems to be corrupted, it will be rebuilt from scratch + number of merge: 0 + number of jumps: 0 + + $ "$PYTHON" ../truncate.py .hg/cache/evoext-stablesortcache-00 -4 + $ f -H .hg/cache/evoext-stablesortcache-00 + .hg/cache/evoext-stablesortcache-00: + 0000: 00 00 00 02 01 24 14 42 b3 c2 bf 32 11 e5 93 b5 |.....$.B...2....| + 0010: 49 c6 55 ea 65 b2 95 e3 00 00 00 18 00 00 00 00 |I.U.e...........| + 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + + $ hg debugstablesortcache --debug + number of revisions: 3 + stablesortcache file seems to be corrupted, it will be rebuilt from scratch + number of merge: 0 + number of jumps: 0 + + $ cd .. + +A "diamond" setup with a merge + + $ hg init with-a-merge + $ cd with-a-merge + + $ hg debugbuilddag '+2 *2 /2' + $ hg log -G + o 3 2b6d669947cd r3 tip + |\ + | o 2 fa942426a6fd r2 + | | + o | 1 66f7d451a68b r1 + |/ + o 0 1ea73414a91b r0 + + $ f -s .hg/cache/evoext-* + .hg/cache/evoext-depthcache-00: size=56 + .hg/cache/evoext-firstmerge-00: size=56 + .hg/cache/evoext-obscache-00: size=68 + .hg/cache/evoext-stablesortcache-00: size=84 + +testing depthcache + + $ f -H .hg/cache/evoext-depthcache-00 + .hg/cache/evoext-depthcache-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef 01 00 00 00 00 00 00 00 |.....p~.........| + 0020: 02 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................| + 0030: 04 00 00 00 00 00 00 00 |........| + + $ hg debugdepth --rev 'all()' --method compare --debug + 1ea73414a91b 1 + 66f7d451a68b 2 + fa942426a6fd 2 + 2b6d669947cd 4 + + $ "$PYTHON" ../repack.py .hg/cache/evoext-depthcache-00 + $ f -H .hg/cache/evoext-depthcache-00 + .hg/cache/evoext-depthcache-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef 01 00 00 00 02 00 00 00 |.....p~.........| + 0020: 02 00 00 00 04 00 00 00 |........| + + $ hg debugdepth --rev 'all()' --method compare --debug + depthcache file seems to be corrupted, it will be rebuilt from scratch + 1ea73414a91b 1 + 66f7d451a68b 2 + fa942426a6fd 2 + 2b6d669947cd 4 + + $ "$PYTHON" ../truncate.py .hg/cache/evoext-depthcache-00 -4 + $ f -H .hg/cache/evoext-depthcache-00 + .hg/cache/evoext-depthcache-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef 01 00 00 00 00 00 00 00 |.....p~.........| + 0020: 02 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................| + 0030: 04 00 00 00 |....| + + $ hg debugdepth --rev 'all()' --method compare --debug + depthcache file seems to be corrupted, it will be rebuilt from scratch + 1ea73414a91b 1 + 66f7d451a68b 2 + fa942426a6fd 2 + 2b6d669947cd 4 + +testing firstmergecache + + $ f -H .hg/cache/evoext-firstmerge-00 + .hg/cache/evoext-firstmerge-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef ff ff ff ff ff ff ff ff |.....p~.........| + 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0030: 03 00 00 00 00 00 00 00 |........| + + $ hg debugfirstmergecache --debug + 1ea73414a91b -1 + 66f7d451a68b -1 + fa942426a6fd -1 + 2b6d669947cd 3 + + $ "$PYTHON" ../repack.py .hg/cache/evoext-firstmerge-00 + $ f -H .hg/cache/evoext-firstmerge-00 + .hg/cache/evoext-firstmerge-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef ff ff ff ff ff ff ff ff |.....p~.........| + 0020: ff ff ff ff 03 00 00 00 |........| + + $ hg debugfirstmergecache --debug + firstmergecache file seems to be corrupted, it will be rebuilt from scratch + 1ea73414a91b -1 + 66f7d451a68b -1 + fa942426a6fd -1 + 2b6d669947cd 3 + + $ "$PYTHON" ../truncate.py .hg/cache/evoext-firstmerge-00 -4 + $ f -H .hg/cache/evoext-firstmerge-00 + .hg/cache/evoext-firstmerge-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef ff ff ff ff ff ff ff ff |.....p~.........| + 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0030: 03 00 00 00 |....| + + $ hg debugfirstmergecache --debug + firstmergecache file seems to be corrupted, it will be rebuilt from scratch + 1ea73414a91b -1 + 66f7d451a68b -1 + fa942426a6fd -1 + 2b6d669947cd 3 + +testing stablesortcache + + $ f -H .hg/cache/evoext-stablesortcache-00 + .hg/cache/evoext-stablesortcache-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef 00 00 00 20 00 00 00 00 |.....p~.... ....| + 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0030: 00 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 |................| + 0040: 00 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 |................| + 0050: 00 00 00 00 |....| + + $ hg debugstablesortcache --debug + number of revisions: 4 + number of merge: 1 + number of jumps: 1 + average jumps: 1.000 + median jumps: 1 + 90% jumps: 1 + 99% jumps: 1 + max jumps: 1 + jump cache size: 12 bytes + + $ "$PYTHON" ../repack.py .hg/cache/evoext-stablesortcache-00 --index + $ f -H .hg/cache/evoext-stablesortcache-00 + .hg/cache/evoext-stablesortcache-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef 00 00 00 10 00 00 00 00 |.....p~.........| + 0020: 00 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 |................| + 0030: 01 00 00 00 02 00 00 00 |........| + + $ hg debugstablesortcache --debug + number of revisions: 4 + stablesortcache file seems to be corrupted, it will be rebuilt from scratch + number of merge: 1 + number of jumps: 1 + average jumps: 1.000 + median jumps: 1 + 90% jumps: 1 + 99% jumps: 1 + max jumps: 1 + jump cache size: 12 bytes + + $ "$PYTHON" ../truncate.py .hg/cache/evoext-stablesortcache-00 -4 + $ f -H .hg/cache/evoext-stablesortcache-00 + .hg/cache/evoext-stablesortcache-00: + 0000: 00 00 00 03 2b 6d 66 99 47 cd 52 4d 74 f4 3c 1b |....+mf.G.RMt.<.| + 0010: 11 c7 84 85 89 70 7e ef 00 00 00 20 00 00 00 00 |.....p~.... ....| + 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0030: 00 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 |................| + 0040: 00 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 |................| + + $ hg debugstablesortcache --debug + number of revisions: 4 + stablesortcache file seems to be corrupted, it will be rebuilt from scratch + number of merge: 1 + number of jumps: 1 + average jumps: 1.000 + median jumps: 1 + 90% jumps: 1 + 99% jumps: 1 + max jumps: 1 + jump cache size: 12 bytes + + $ cd ..
--- a/tests/test-check-sdist.t Thu Mar 11 14:48:12 2021 +0800 +++ b/tests/test-check-sdist.t Sun Apr 25 13:21:56 2021 +0800 @@ -35,7 +35,7 @@ $ tar -tzf hg-evolve-*.tar.gz | sed 's|^hg-evolve-[^/]*/||' | sort > files $ wc -l files - 346 files + 348 files $ fgrep debian files tests/test-check-debian.t $ fgrep __init__.py files
--- a/tests/test-discovery-obshashrange-cache.t Thu Mar 11 14:48:12 2021 +0800 +++ b/tests/test-discovery-obshashrange-cache.t Sun Apr 25 13:21:56 2021 +0800 @@ -7,7 +7,7 @@ $ cat << EOF >> $HGRCPATH > [extensions] - > hgext3rd.evolve = + > evolve = > blackbox = > [defaults] > blackbox = -l 100 @@ -17,8 +17,6 @@ > [ui] > logtemplate = "{rev} {node|short} {desc} {tags}\n" > ssh = "$PYTHON" "$RUNTESTDIR/dummyssh" - > [alias] - > debugobsolete=debugobsolete -d '0 0' > EOF $ hg init main @@ -26,9 +24,7 @@ $ hg -R main debugbuilddag '.+7' $ for node in `hg -R main log -T '{node}\n'`; do - > printf $node | grep -o . | sort |tr -d "\n" > ancfile - > anc=`cat ancfile` - > rm ancfile + > anc=`echo $node | grep -o . | sort | tr -d "\n"` > echo "marking $anc as predecessors of $node" > hg -R main debugobsolete $anc $node > done @@ -72,7 +68,7 @@ remote: added 8 changesets with 0 changes to 0 files remote: 8 new obsolescence markers -sever cash is warm +server cache is warm $ f -s server/.hg/cache/evoext* server/.hg/cache/evoext-depthcache-00: size=88 @@ -82,7 +78,7 @@ server/.hg/cache/evoext_obshashrange_v2.sqlite: size=?* (glob) server/.hg/cache/evoext_stablerange_v2.sqlite: size=?* (glob) -client cash is warm +client cache is warm $ f -s main/.hg/cache/evoext* main/.hg/cache/evoext-depthcache-00: size=88 @@ -128,7 +124,7 @@ no changes found OBSEXC: looking for common markers in 8 nodes -client cash is warm +client cache is warm $ f -s main/.hg/cache/evoext* main/.hg/cache/evoext-depthcache-00: size=88 @@ -156,7 +152,7 @@ no changes found [1] -client cash is warm +client cache is warm $ f -s main/.hg/cache/evoext* main/.hg/cache/evoext-depthcache-00: size=88 @@ -165,3 +161,39 @@ main/.hg/cache/evoext-stablesortcache-00: size=92 main/.hg/cache/evoext_obshashrange_v2.sqlite: size=?* (glob) main/.hg/cache/evoext_stablerange_v2.sqlite: size=?* (glob) + +let's look at the contents of the caches + +the reason we're doing this is to make sure our serialization works the same +way on all platforms, see https://bz.mercurial-scm.org/show_bug.cgi?id=6354 + +we don't need to check sqlite caches + + $ f -H main/.hg/cache/evoext-* + main/.hg/cache/evoext-depthcache-00: + 0000: 00 00 00 07 4d e3 2a 90 b6 6c d0 83 eb f3 c0 0b |....M.*..l......| + 0010: 41 27 7a a7 ab ca 51 dd 01 00 00 00 00 00 00 00 |A'z...Q.........| + 0020: 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 |................| + 0030: 04 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 |................| + 0040: 06 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 |................| + 0050: 08 00 00 00 00 00 00 00 |........| + main/.hg/cache/evoext-firstmerge-00: + 0000: 00 00 00 07 4d e3 2a 90 b6 6c d0 83 eb f3 c0 0b |....M.*..l......| + 0010: 41 27 7a a7 ab ca 51 dd ff ff ff ff ff ff ff ff |A'z...Q.........| + 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0030: ff ff ff ff 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 |........| + main/.hg/cache/evoext-obscache-00: + 0000: 00 00 00 00 00 00 00 07 4d e3 2a 90 b6 6c d0 83 |........M.*..l..| + 0010: eb f3 c0 0b 41 27 7a a7 ab ca 51 dd 00 00 00 00 |....A'z...Q.....| + 0020: 00 00 00 08 00 00 00 00 00 00 02 29 4c 16 b4 10 |...........)L...| + 0030: 03 f6 c1 57 8d 58 25 ef c7 73 cd 79 03 4b fb 46 |...W.X%..s.y.K.F| + 0040: 00 00 00 00 00 00 00 00 |........| + main/.hg/cache/evoext-stablesortcache-00: + 0000: 00 00 00 07 4d e3 2a 90 b6 6c d0 83 eb f3 c0 0b |....M.*..l......| + 0010: 41 27 7a a7 ab ca 51 dd 00 00 00 40 00 00 00 00 |A'z...Q....@....| + 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0050: 00 00 00 00 00 00 00 00 00 00 00 00 |............|
--- a/tests/test-discovery-obshashrange.t Thu Mar 11 14:48:12 2021 +0800 +++ b/tests/test-discovery-obshashrange.t Sun Apr 25 13:21:56 2021 +0800 @@ -5,7 +5,7 @@ $ cat << EOF >> $HGRCPATH > [extensions] - > hgext3rd.evolve = + > evolve = > blackbox = > [defaults] > blackbox = -l 100 @@ -18,8 +18,6 @@ > [ui] > logtemplate = "{rev} {node|short} {desc} {tags}\n" > ssh = "$PYTHON" "$RUNTESTDIR/dummyssh" - > [alias] - > debugobsolete=debugobsolete -d '0 0' > EOF $ getid() { @@ -79,27 +77,21 @@ * @0000000000000000000000000000000000000000 (*)> writing .hg/cache/tags2-visible with 0 tags (glob) * @0000000000000000000000000000000000000000 (*)> log -G exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 --config *experimental.obshashrange.max-revs=1* (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 --config *experimental.obshashrange.max-revs=1* exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 --config *experimental.obshashrange.warm-cache=0* (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 --config *experimental.obshashrange.warm-cache=0* exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 4de32a90b66cd083ebf3c00b41277aa7abca51dd (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 4de32a90b66cd083ebf3c00b41277aa7abca51dd exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> blackbox (glob) $ rm .hg/blackbox.log @@ -137,14 +129,10 @@ (run 'hg update' to get a working copy) $ hg -R ../server blackbox * @0000000000000000000000000000000000000000 (*)> debugobshashrange --subranges --rev tip (glob) - * @0000000000000000000000000000000000000000 (*)> strip detected, evo-ext-stablerange-mergepoint cache reset (glob) - * @0000000000000000000000000000000000000000 (*)> strip detected, evo-ext-depthcache cache reset (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-depthcache in *.???? seconds (8r) (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-stablerange-mergepoint in *.???? seconds (8r) (glob) 1970/01/01 00:00:00 * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (8r, 5o) (glob) - 1970/01/01 00:00:00 * @0000000000000000000000000000000000000000 (*)> strip detected, evo-ext-stablesort cache reset (glob) 1970/01/01 00:00:00 * @0000000000000000000000000000000000000000 (*)> updated evo-ext-stablesort in *.???? seconds (8r) (glob) - 1970/01/01 00:00:00 * @0000000000000000000000000000000000000000 (*)> strip detected, evo-ext-firstmerge cache reset (glob) 1970/01/01 00:00:00 * @0000000000000000000000000000000000000000 (*)> updated evo-ext-firstmerge in *.???? seconds (8r) (glob) * @0000000000000000000000000000000000000000 (*)> debugobshashrange --subranges --rev tip exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> -R server serve --stdio (glob) @@ -292,7 +280,6 @@ ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} $ hg blackbox * @0000000000000000000000000000000000000000 (*)> debugobsolete (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> debugobsolete exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> up (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> up exited 0 after *.?? seconds (glob) @@ -303,7 +290,6 @@ * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (1r, 0o) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> commit -m foo exited 0 after *.?? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e (glob) - * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e exited 0 after *.?? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> push -f --debug (glob) @@ -327,17 +313,13 @@ * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> preparing listkeys for "namespaces" (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> sending listkeys command (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> received listkey for "namespaces": 40 bytes (glob) - * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-stablerange-mergepoint cache reset (glob) - * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-depthcache cache reset (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-depthcache in *.???? seconds (6r) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-stablerange-mergepoint in *.???? seconds (6r) (glob) 1970/01/01 00:00:00 * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (6r, 4o) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> query 0; add more sample (target 100, current 1) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> query 0; sample size is 9, largest range 5 (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> sending evoext_obshashrange_v1 command (glob) - 1970/01/01 00:00:00 * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-stablesort cache reset (glob) 1970/01/01 00:00:00 * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-stablesort in *.???? seconds (6r) (glob) - 1970/01/01 00:00:00 * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-firstmerge cache reset (glob) 1970/01/01 00:00:00 * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-firstmerge in *.???? seconds (6r) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 0/5 mismatch - 1 obshashrange queries in *.???? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 0/5 mismatch - 1 obshashrange queries in *.???? seconds (glob) @@ -365,11 +347,9 @@ * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> writing .hg/cache/tags2-visible with 0 tags (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> log -G exited 0 after *.?? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete 111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd (glob) - * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete 111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd exited 0 after *.?? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete 22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 (glob) - * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete 22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 exited 0 after *.?? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> push (glob) @@ -421,16 +401,13 @@ $ hg -R ../server blackbox * @0000000000000000000000000000000000000000 (*)> -R ../server/ debugobsolete --rev '::tip' (glob) (no-windows !) * @0000000000000000000000000000000000000000 (*)> -R ../server/ debugobsolete --rev ::tip (glob) (windows !) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> writing .hg/cache/tags2-visible with 0 tags (glob) * @0000000000000000000000000000000000000000 (*)> -R ../server/ debugobsolete --rev '::tip' exited 0 after *.?? seconds (glob) (no-windows !) * @0000000000000000000000000000000000000000 (*)> -R ../server/ debugobsolete --rev ::tip exited 0 after *.?? seconds (glob) (windows !) * @0000000000000000000000000000000000000000 (*)> -R ../server debugobsolete aaaaaaa11111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @0000000000000000000000000000000000000000 (*)> -R ../server debugobsolete aaaaaaa11111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> -R ../server debugobsolete bbbbbbb2222222222bbbbbbbbbbbbb2222222222 bebd167eb94d257ace0e814aeb98e6972ed2970d (glob) - * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob) * @0000000000000000000000000000000000000000 (*)> -R ../server debugobsolete bbbbbbb2222222222bbbbbbbbbbbbb2222222222 bebd167eb94d257ace0e814aeb98e6972ed2970d exited 0 after *.?? seconds (glob) * @0000000000000000000000000000000000000000 (*)> -R server serve --stdio (glob) @@ -450,7 +427,6 @@ dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} $ hg blackbox * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete (glob) - * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete exited 0 after *.?? seconds (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> log -G (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> log -G exited 0 after *.?? seconds (glob) @@ -524,7 +500,6 @@ $ hg blackbox * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete --rev '::6' (glob) (no-windows !) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete --rev ::6 (glob) (windows !) - * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> writing .hg/cache/tags2-visible with 0 tags (glob) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete --rev '::6' exited 0 after *.?? seconds (glob) (no-windows !) * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete --rev ::6 exited 0 after *.?? seconds (glob) (windows !) @@ -1063,7 +1038,6 @@ * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> writing .hg/cache/tags2-visible with 0 tags (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> log -G exited 0 after *.?? seconds (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> pull (glob) - * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> strip detected, evo-ext-stablerange-mergepoint cache reset (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> strip detected, evo-ext-depthcache cache reset (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-depthcache in *.???? seconds (8r) (glob) * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-stablerange-mergepoint in *.???? seconds (8r) (glob)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-topic-prev-next.t Sun Apr 25 13:21:56 2021 +0800 @@ -0,0 +1,226 @@ + $ . "$TESTDIR/testlib/topic_setup.sh" + $ . "$TESTDIR/testlib/common.sh" + + $ cat << EOF >> $HGRCPATH + > [extensions] + > evolve = + > [ui] + > logtemplate = '{rev} [{topic}] {desc}\n' + > EOF + +Checking target ambiguity in hg next + + $ hg init ambiguous-next + $ cd ambiguous-next + + $ mkcommit root + $ hg topic A + marked working directory as topic: A + $ mkcommit A1 + active topic 'A' grew its first changeset + (see 'hg help topics' for more information) + $ mkcommit A2 + $ mkcommit A3 + $ mkcommit A4 + $ hg up 'desc("A3")' + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ mkcommit A5 + $ hg up 'desc("A2")' + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ hg topic B + $ mkcommit B1 + active topic 'B' grew its first changeset + (see 'hg help topics' for more information) + $ mkcommit B2 + + $ hg log -G + @ 7 [B] B2 + | + o 6 [B] B1 + | + | o 5 [A] A5 + | | + | | o 4 [A] A4 + | |/ + | o 3 [A] A3 + |/ + o 2 [A] A2 + | + o 1 [A] A1 + | + o 0 [] root + + +Quick sanity check + + $ hg up 'desc("A1")' + switching to topic A + 0 files updated, 0 files merged, 3 files removed, 0 files unresolved + $ hg next + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [s2] A2 + $ hg stack + ### topic: A (2 heads) + ### target: default (branch) + s5: A4 + s3^ A3 (base) + s4: A5 + s3: A3 + s2@ A2 (current) + s1: A1 + s0^ root (base) + $ hg next + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [s3] A3 + $ hg log -G + o 7 [B] B2 + | + o 6 [B] B1 + | + | o 5 [A] A5 + | | + | | o 4 [A] A4 + | |/ + | @ 3 [A] A3 + |/ + o 2 [A] A2 + | + o 1 [A] A1 + | + o 0 [] root + + $ hg next + ambiguous next changeset: + [s5] A4 + [s4] A5 + explicitly update to one of them + [1] + +Let's make some changesets unstable + + $ hg up 'desc("A2")' + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo foo > A2 + $ hg amend + 5 new orphan changesets + $ hg stack + ### topic: A (2 heads) + ### target: default (branch) + s5$ A4 (orphan) + s3^ A3 (base orphan) + s4$ A5 (orphan) + s3$ A3 (orphan) + s2@ A2 (current) + s1: A1 + s0^ root (base) + $ hg log -G + @ 8 [A] A2 + | + | * 7 [B] B2 + | | + | * 6 [B] B1 + | | + | | * 5 [A] A5 + | | | + | | | * 4 [A] A4 + | | |/ + | | * 3 [A] A3 + | |/ + | x 2 [A] A2 + |/ + o 1 [A] A1 + | + o 0 [] root + + +B1 shouldn't be considered a target, orphan or not + + $ hg next + move:[s3] A3 + atop:[s2] A2 + working directory is now at 2b67b6a6cae1 + +B1 is not considered a target when it's been stabilized + + $ hg up 'desc("A2")' + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg evolve --rev 'desc("B1")' + move:[6] B1 + atop:[8] A2 + switching to topic A + $ hg next + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [s3] A3 + +A4 and A5 should be ambiguous for hg next even if A5 is an orphan and A4 is not + + $ hg evolve --rev 'desc("A3") + desc("A4")' + move:[s5] A4 + atop:[s3] A3 + $ hg up 'desc("A3")' + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg stack + ### topic: A (2 heads) + ### target: default (branch) + s5: A4 + s3^ A3 (base current) + s4$ A5 (orphan) + s3@ A3 (current) + s2: A2 + s1: A1 + s0^ root (base) + $ hg next --no-evolve --dry-run + hg update 51d70e81d730; + [s5] A4 + $ hg next + ambiguous next changeset: + [s5] A4 + [s4] A5 + explicitly update to one of them + [1] + + $ cd .. + +Making sure plain hg next sticks to topic when target is unstable + + $ hg init next-unstable-topic + $ cd next-unstable-topic + + $ mkcommit ROOT + $ hg topics topic-a + marked working directory as topic: topic-a + $ mkcommit A + active topic 'topic-a' grew its first changeset + (see 'hg help topics' for more information) + $ hg topics topic-b + $ mkcommit B + active topic 'topic-b' grew its first changeset + (see 'hg help topics' for more information) + $ hg up 'topic("topic-a")' + switching to topic topic-a + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo foo > foo + $ hg ci -A --amend + adding foo + 1 new orphan changesets + $ hg log -G + @ 3 [topic-a] A + | + | * 2 [topic-b] B + | | + | x 1 [topic-a] A + |/ + o 0 [] ROOT + + + $ hg next + no children on topic "topic-a" + do you want --no-topic + [1] + + $ hg next --no-topic + move:[2] B + atop:[3] A + working directory is now at 53f8332d648f + + $ cd ..
--- a/tests/test-topic-server.t Thu Mar 11 14:48:12 2021 +0800 +++ b/tests/test-topic-server.t Sun Apr 25 13:21:56 2021 +0800 @@ -48,7 +48,7 @@ Mercurial Distributed SCM (*) (glob) (see https://mercurial-scm.org for more information) - Copyright (C) 2005-* Matt Mackall and others (glob) + Copyright (C) 2005-* (glob) This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -75,7 +75,7 @@ Mercurial Distributed SCM (*) (glob) (see https://mercurial-scm.org for more information) - Copyright (C) 2005-* Matt Mackall and others (glob) + Copyright (C) 2005-* (glob) This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--- a/tests/test-version-install.t Thu Mar 11 14:48:12 2021 +0800 +++ b/tests/test-version-install.t Sun Apr 25 13:21:56 2021 +0800 @@ -9,7 +9,7 @@ Mercurial Distributed SCM (version *) (glob) (see https://mercurial-scm.org for more information) - Copyright (C) 2005-* Matt Mackall and others (glob) + Copyright (C) 2005-* (glob) This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.