--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hg-format-source Fri Sep 27 13:03:14 2019 +0200
@@ -0,0 +1,1 @@
+{"pattern": "glob:hgext3rd/**/*.py", "tool": "byteify-strings"}
--- a/.hgtags Mon Jul 29 14:43:10 2019 +0200
+++ b/.hgtags Fri Sep 27 13:03:14 2019 +0200
@@ -80,3 +80,4 @@
33c617626fd90a0a00e831b4762f64fecb609317 8.5.0
05c9dcf5512ed77490a35b4d6b1c3fe860259f48 8.5.1
756db65030c64b22836fe236d1db3b95477e3ef7 9.0.0
+6f37fdad7ac123ca0a76872ac4639bd1f3c248f7 9.1.0
--- a/CHANGELOG Mon Jul 29 14:43:10 2019 +0200
+++ b/CHANGELOG Fri Sep 27 13:03:14 2019 +0200
@@ -1,27 +1,53 @@
Changelog
=========
-9.1.0 - in progress
+9.2.0 -- 2019-09-28
+-------------------
+
+ * evolve: check that relocating makes sense in _solvedivergent() (issue5958)
+ * evolve: test that target is not orig in _solveunstable() (issue6097)
+ * fold: check allowdivergence before folding obsolete changesets (issue5817)
+ * obslog: correct spacing of patch output with word-diff=yes (issue6175)
+ * stack: make sure to preserve dependencies, fixes certain complex cases
+ * prune: improve documentation for `--pair`
+
+ * python3: beta support for Python 3.6+
+ (thanks to ludovicchabant, martinvonz and rgomes for their hard work)
+ * prune: clarify error message when no revision were passed,
+ * evolve: avoid possible race conditions bu locking earlier
+ * abort: add support for `evolve` and `pick` to `hg abort` (hg-5.1+)
+ * rewind: add --keep flag to preserve working copy
+
+9.1.0 -- 2019-07-29
-------------------
- * evolve: use the same wording as core in case of unresolved conflict
- * evolve: minor output message improvements
- * evolve: improve `hg evolve --all` behavior when "." is obsolete
- * topic: fix confusion in branch heads checking logic
- * touch: now works on merge commit too
- * rewind: fix behavior for merge commit
- * fold: allow fold with merge commit
- * metaedit: now also operates on merge commit
+ * compatibility with upcoming Mercurial 5.1,
+
+ * pick: no longer forget file in case of conflict (issue6037),
+ * pick: properly report and cleanup "unfinished state",
+
+ * prune: don't update wcp if pruned revision are unrelated (issue6137),
+ * prune: spell --successor flag without any unnecessary shortcuts,
+ * prune: update to the successor of wdir also with --pair/--biject (issue6142)
+
+ * evolve: properly prune changeset with no change in case of conflict (issue5967),
+ * evolve: use the same wording as core in case of unresolved conflict,
+ * evolve: minor output message improvements,
+ * evolve: improve `hg evolve --all` behavior when "." is obsolete,
-9.0.1 - in progress
--------------------
+ * touch: detect resulting divergence in more cases (issue6107),
+ * touch: now works on merge commit too,
+
+ * rewind: fix behavior for merge commit,
+
+ * fold: allow fold with merge commit
- * pick: no longer forget file in case of conflict (issue6037)
- * pick: properly report and cleanup "unfinished state"
- * prune: don't update wcp if pruned revision are unrelated (issue6137)
- * prune: spell --successor flag without any unnecessary shortcuts
- * evolve: properly prune changeset with no change in case of conflict (issue5967)
- * touch: detect resulting divergence in more cases (issue6107)
+ * metaedit: now also operates on merge commit.
+
+(topic 0.16.0)
+
+ * topic: fix confusion in branch heads checking logic.
+
9.0.0 -- 2019-06-06
-------------------
--- a/MANIFEST.in Mon Jul 29 14:43:10 2019 +0200
+++ b/MANIFEST.in Fri Sep 27 13:03:14 2019 +0200
@@ -1,4 +1,5 @@
exclude contrib
+exclude .hg-format-source
recursive-exclude contrib *
exclude hgext3rd/evolve/hack
recursive-exclude hgext3rd/evolve/hack *
--- a/README Mon Jul 29 14:43:10 2019 +0200
+++ b/README Fri Sep 27 13:03:14 2019 +0200
@@ -96,6 +96,15 @@
needed. During the upstreaming process, we can use this clearer picture to
clean up the code and upgrade it to an appropriate quality for Mercurial core.
+Python 3 support
+================
+
+Mercurial announced beta support for Python 3 starting with its 5.0 release.
+Since 9.1.0, ``evolve`` has beta support for Python 3.6+.
+
+Support will stay in beta while Mercurial's support for Python 3 remains in
+beta and until it is a bit more battle-tested.
+
How to Contribute
=================
@@ -145,3 +154,23 @@
test output change from a changeset in core should adds the following line to their description:
CORE-TEST-OUTPUT-UPDATE: <CORE-NODE-ID>
+
+
+Format-source config
+====================
+
+Format source helps smooth out the pain of merging after auto-formatting.
+Follow the instructions for install here:
+
+.. _`format-source`: https://bitbucket.org/octobus/format-source
+
+Then update both your global and repo config files::
+
+ $ hg config -l # add the lines below
+ [extensions]
+ formatsource =
+
+ [format-source]
+ byteify-strings = python3 ~/workspace/octobus/mercurial-devel/contrib/byteify-strings.py --dictiter --treat-as-kwargs kwargs opts commitopts TROUBLES --allow-attr-methods
+ byteify-strings:mode.input = file
+ byteify-strings:mode.output = pipe
--- a/contrib/hammerclient.py Mon Jul 29 14:43:10 2019 +0200
+++ b/contrib/hammerclient.py Fri Sep 27 13:03:14 2019 +0200
@@ -5,7 +5,7 @@
if len(sys.argv) < 2:
execname = os.path.basename(sys.argv[0])
- print >> sys.stderr, "usage: %s CLIENT_ID" % execname
+ sys.stderr.write("usage: %s CLIENT_ID\n" % execname)
client_id = sys.argv[1]
--- a/debian/changelog Mon Jul 29 14:43:10 2019 +0200
+++ b/debian/changelog Fri Sep 27 13:03:14 2019 +0200
@@ -1,3 +1,15 @@
+mercurial-evolve (9.2.0-1) unstable; urgency=medium
+
+ * new upstream release
+
+ -- Pierre-Yves David <pierre-yves.david@ens-lyon.org> Sat, 28 Sep 2019 12:49:41 +0200
+
+mercurial-evolve (9.1.0-1) unstable; urgency=medium
+
+ * new upstream release
+
+ -- Pierre-Yves David <pierre-yves.david@ens-lyon.org> Mon, 29 Jul 2019 16:46:26 +0200
+
mercurial-evolve (9.0.0-1) unstable; urgency=medium
* new upstream release
--- a/docs/test2rst.py Mon Jul 29 14:43:10 2019 +0200
+++ b/docs/test2rst.py Fri Sep 27 13:03:14 2019 +0200
@@ -14,10 +14,10 @@
'''
ignored_patterns = [
- re.compile('^#if'),
- re.compile('^#else'),
- re.compile('^#endif'),
- re.compile('#rest-ignore$'),
+ re.compile(r'^#if'),
+ re.compile(r'^#else'),
+ re.compile(r'^#endif'),
+ re.compile(r'#rest-ignore$'),
]
--- a/hgext3rd/evolve/__init__.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/__init__.py Fri Sep 27 13:03:14 2019 +0200
@@ -184,7 +184,7 @@
- "markers" the raw list of changesets.
"""
-evolutionhelptext = """
+evolutionhelptext = b"""
Obsolescence markers make it possible to mark changesets that have been
deleted or superset in a new version of the changeset.
@@ -258,7 +258,7 @@
registrar.templatekeyword # new in hg-3.8
except ImportError:
from . import metadata
- raise ImportError('evolve needs Mercurial version %s or above' %
+ raise ImportError(b'evolve needs Mercurial version %s or above' %
min(metadata.testedwith.split()))
import mercurial
@@ -311,19 +311,19 @@
buglink = metadata.buglink
# Flags for enabling optional parts of evolve
-commandopt = 'allnewcommands'
+commandopt = b'allnewcommands'
obsexcmsg = utility.obsexcmsg
shorttemplate = utility.shorttemplate
-colortable = {'evolve.node': 'yellow',
- 'evolve.user': 'green',
- 'evolve.rev': 'blue',
- 'evolve.short_description': '',
- 'evolve.date': 'cyan',
- 'evolve.current_rev': 'bold',
- 'evolve.verb': '',
- 'evolve.operation': 'bold'
+colortable = {b'evolve.node': b'yellow',
+ b'evolve.user': b'green',
+ b'evolve.rev': b'blue',
+ b'evolve.short_description': b'',
+ b'evolve.date': b'cyan',
+ b'evolve.current_rev': b'bold',
+ b'evolve.verb': b'',
+ b'evolve.operation': b'bold'
}
_pack = struct.pack
@@ -359,9 +359,9 @@
templatekeyword = eh.templatekeyword
# Configuration
-eh.configitem('experimental', 'evolutioncommands', [])
-eh.configitem('experimental', 'evolution.allnewcommands', None)
-eh.configitem('experimental', 'prunestrip', False)
+eh.configitem(b'experimental', b'evolutioncommands', [])
+eh.configitem(b'experimental', b'evolution.allnewcommands', None)
+eh.configitem(b'experimental', b'prunestrip', False)
# pre hg 4.0 compat
@@ -394,14 +394,14 @@
def _configureoptions(ui, repo):
# If no capabilities are specified, enable everything.
# This is so existing evolve users don't need to change their config.
- evolveopts = repo.ui.configlist('experimental', 'evolution')
+ evolveopts = repo.ui.configlist(b'experimental', b'evolution')
if not evolveopts:
- evolveopts = ['all']
- repo.ui.setconfig('experimental', 'evolution', evolveopts, 'evolve')
- if obsolete.isenabled(repo, 'exchange'):
+ evolveopts = [b'all']
+ repo.ui.setconfig(b'experimental', b'evolution', evolveopts, b'evolve')
+ if obsolete.isenabled(repo, b'exchange'):
# if no config explicitly set, disable bundle1
- if not isinstance(repo.ui.config('server', 'bundle1'), bytes):
- repo.ui.setconfig('server', 'bundle1', False)
+ if not isinstance(repo.ui.config(b'server', b'bundle1'), bytes):
+ repo.ui.setconfig(b'server', b'bundle1', False)
class trdescrepo(repo.__class__):
@@ -419,19 +419,19 @@
# This must be in the same function as the option configuration above to
# guarantee it happens after the above configuration, but before the
# extsetup functions.
- evolvecommands = ui.configlist('experimental', 'evolutioncommands')
- evolveopts = ui.configlist('experimental', 'evolution')
+ evolvecommands = ui.configlist(b'experimental', b'evolutioncommands')
+ evolveopts = ui.configlist(b'experimental', b'evolution')
if evolveopts and (commandopt not in evolveopts
- and 'all' not in evolveopts):
+ and b'all' not in evolveopts):
# We build whitelist containing the commands we want to enable
whitelist = set()
for cmd in evolvecommands:
matchingevolvecommands = [e for e in cmdtable.keys() if cmd in e]
if not matchingevolvecommands:
- raise error.Abort(_('unknown command: %s') % cmd)
+ raise error.Abort(_(b'unknown command: %s') % cmd)
elif len(matchingevolvecommands) > 1:
- matchstr = ', '.join(matchingevolvecommands)
- msg = _("ambiguous command specification: '%s' matches [%s]")
+ matchstr = b', '.join(matchingevolvecommands)
+ msg = _(b"ambiguous command specification: '%s' matches [%s]")
raise error.Abort(msg % (cmd, matchstr))
else:
whitelist.add(matchingevolvecommands[0])
@@ -462,8 +462,8 @@
@eh.uisetup
def setupparentcommand(ui):
- _alias, statuscmd = cmdutil.findcmd('status', commands.table)
- pstatusopts = [o for o in statuscmd[1] if o[1] != 'rev']
+ _alias, statuscmd = cmdutil.findcmd(b'status', commands.table)
+ pstatusopts = [o for o in statuscmd[1] if o[1] != b'rev']
@eh.command(b'pstatus', pstatusopts)
def pstatus(ui, repo, *args, **kwargs):
@@ -474,11 +474,11 @@
match the content of the commit that a bare :hg:`amend` will creates.
See :hg:`help status` for details."""
- kwargs['rev'] = ['.^']
+ kwargs['rev'] = [b'.^']
return statuscmd[0](ui, repo, *args, **kwargs)
- _alias, diffcmd = cmdutil.findcmd('diff', commands.table)
- pdiffopts = [o for o in diffcmd[1] if o[1] != 'rev']
+ _alias, diffcmd = cmdutil.findcmd(b'diff', commands.table)
+ pdiffopts = [o for o in diffcmd[1] if o[1] != b'rev']
@eh.command(b'pdiff', pdiffopts)
def pdiff(ui, repo, *args, **kwargs):
@@ -489,15 +489,15 @@
match the content of the commit that a bare :hg:`amend` will creates.
See :hg:`help diff` for details."""
- kwargs['rev'] = ['.^']
+ kwargs['rev'] = [b'.^']
return diffcmd[0](ui, repo, *args, **kwargs)
@eh.uisetup
def _installalias(ui):
- if ui.config('alias', 'odiff', None) is None:
- ui.setconfig('alias', 'odiff',
- "diff --hidden --rev 'limit(predecessors(.),1)' --rev .",
- 'evolve')
+ if ui.config(b'alias', b'odiff', None) is None:
+ ui.setconfig(b'alias', b'odiff',
+ b"diff --hidden --rev 'limit(predecessors(.),1)' --rev .",
+ b'evolve')
### Unstable revset symbol
@@ -505,11 +505,11 @@
def revsetunstable(repo, subset, x):
"""Changesets with instabilities.
"""
- revset.getargs(x, 0, 0, 'unstable takes no arguments')
+ revset.getargs(x, 0, 0, b'unstable takes no arguments')
troubled = set()
- troubled.update(getrevs(repo, 'orphan'))
- troubled.update(getrevs(repo, 'phasedivergent'))
- troubled.update(getrevs(repo, 'contentdivergent'))
+ troubled.update(getrevs(repo, b'orphan'))
+ troubled.update(getrevs(repo, b'phasedivergent'))
+ troubled.update(getrevs(repo, b'contentdivergent'))
troubled = revset.baseset(troubled)
troubled.sort() # set is non-ordered, enforce order
return subset & troubled
@@ -617,8 +617,8 @@
def revsetsuspended(repo, subset, x):
"""Obsolete changesets with non-obsolete descendants.
"""
- revset.getargs(x, 0, 0, 'suspended takes no arguments')
- suspended = revset.baseset(getrevs(repo, 'suspended'))
+ revset.getargs(x, 0, 0, b'suspended takes no arguments')
+ suspended = revset.baseset(getrevs(repo, b'suspended'))
suspended.sort()
return subset & suspended
@@ -679,49 +679,49 @@
# This section take care of issue warning to the user when troubles appear
def _warnobsoletewc(ui, repo, prevnode=None, wasobs=None):
- rev = repo['.']
+ rev = repo[b'.']
if not rev.obsolete():
return
if rev.node() == prevnode and wasobs:
return
- msg = _("working directory parent is obsolete! (%s)\n")
+ msg = _(b"working directory parent is obsolete! (%s)\n")
shortnode = node.short(rev.node())
ui.warn(msg % shortnode)
# Check that evolve is activated for performance reasons
- evolvecommandenabled = any('evolve' in e for e in cmdtable)
+ evolvecommandenabled = any(b'evolve' in e for e in cmdtable)
if ui.quiet or not evolvecommandenabled:
return
# Show a warning for helping the user to solve the issue
reason, successors = obshistory._getobsfateandsuccs(repo, rev.node())
- if reason == 'pruned':
- solvemsg = _("use 'hg evolve' to update to its parent successor")
- elif reason == 'diverged':
- debugcommand = "hg evolve --list --content-divergent"
- basemsg = _("%s has diverged, use '%s' to resolve the issue")
+ if reason == b'pruned':
+ solvemsg = _(b"use 'hg evolve' to update to its parent successor")
+ elif reason == b'diverged':
+ debugcommand = b"hg evolve --list --content-divergent"
+ basemsg = _(b"%s has diverged, use '%s' to resolve the issue")
solvemsg = basemsg % (shortnode, debugcommand)
- elif reason == 'superseed':
- msg = _("use 'hg evolve' to update to its successor: %s")
+ elif reason == b'superseed':
+ msg = _(b"use 'hg evolve' to update to its successor: %s")
solvemsg = msg % successors[0]
- elif reason == 'superseed_split':
- msg = _("use 'hg evolve' to update to its tipmost successor: %s")
+ elif reason == b'superseed_split':
+ msg = _(b"use 'hg evolve' to update to its tipmost successor: %s")
if len(successors) <= 2:
- solvemsg = msg % ", ".join(successors)
+ solvemsg = msg % b", ".join(successors)
else:
- firstsuccessors = ", ".join(successors[:2])
+ firstsuccessors = b", ".join(successors[:2])
remainingnumber = len(successors) - 2
- successorsmsg = _("%s and %d more") % (firstsuccessors, remainingnumber)
+ successorsmsg = _(b"%s and %d more") % (firstsuccessors, remainingnumber)
solvemsg = msg % successorsmsg
else:
raise ValueError(reason)
- ui.warn("(%s)\n" % solvemsg)
+ ui.warn(b"(%s)\n" % solvemsg)
if util.safehasattr(context, '_filterederror'): # <= hg-4.5
@eh.wrapfunction(context, '_filterederror')
@@ -730,36 +730,36 @@
This is extracted in a function to help extensions (eg: evolve) to
experiment with various message variants."""
- if repo.filtername.startswith('visible'):
+ if repo.filtername.startswith(b'visible'):
unfilteredrepo = repo.unfiltered()
rev = repo[scmutil.revsingle(unfilteredrepo, changeid)]
reason, successors = obshistory._getobsfateandsuccs(unfilteredrepo, rev.node())
# Be more precise in case the revision is superseed
- if reason == 'superseed':
- reason = _("successor: %s") % successors[0]
- elif reason == 'superseed_split':
+ if reason == b'superseed':
+ reason = _(b"successor: %s") % successors[0]
+ elif reason == b'superseed_split':
if len(successors) <= 2:
- reason = _("successors: %s") % ", ".join(successors)
+ reason = _(b"successors: %s") % b", ".join(successors)
else:
- firstsuccessors = ", ".join(successors[:2])
+ firstsuccessors = b", ".join(successors[:2])
remainingnumber = len(successors) - 2
- successorsmsg = _("%s and %d more") % (firstsuccessors, remainingnumber)
- reason = _("successors: %s") % successorsmsg
+ successorsmsg = _(b"%s and %d more") % (firstsuccessors, remainingnumber)
+ reason = _(b"successors: %s") % successorsmsg
- msg = _("hidden revision '%s'") % changeid
- hint = _('use --hidden to access hidden revisions; %s') % reason
+ msg = _(b"hidden revision '%s'") % changeid
+ hint = _(b'use --hidden to access hidden revisions; %s') % reason
return error.FilteredRepoLookupError(msg, hint=hint)
- msg = _("filtered revision '%s' (not in '%s' subset)")
+ msg = _(b"filtered revision '%s' (not in '%s' subset)")
msg %= (changeid, repo.filtername)
return error.FilteredRepoLookupError(msg)
-@eh.wrapcommand("update")
-@eh.wrapcommand("pull")
+@eh.wrapcommand(b"update")
+@eh.wrapcommand(b"pull")
def wrapmayobsoletewc(origfn, ui, repo, *args, **opts):
"""Warn that the working directory parent is an obsolete changeset"""
- ctx = repo['.']
+ ctx = repo[b'.']
node = ctx.node()
isobs = ctx.obsolete()
@@ -774,7 +774,7 @@
lockmod.release(wlock)
return res
-@eh.wrapcommand("parents")
+@eh.wrapcommand(b"parents")
def wrapparents(origfn, ui, repo, *args, **opts):
res = origfn(ui, repo, *args, **opts)
_warnobsoletewc(ui, repo)
@@ -787,10 +787,10 @@
try:
return orig(repo, *args, **opts)
except error.Abort as ex:
- hint = _("use 'hg evolve' to get a stable history "
- "or --force to ignore warnings")
+ hint = _(b"use 'hg evolve' to get a stable history "
+ b"or --force to ignore warnings")
if (len(ex.args) >= 1
- and ex.args[0].startswith('push includes ')
+ and ex.args[0].startswith(b'push includes ')
and ex.hint is None):
ex.hint = hint
raise
@@ -799,11 +799,11 @@
evolvestate = state.cmdstate(repo)
if evolvestate:
# i18n: column positioning for "hg summary"
- ui.status(_('evolve: (evolve --continue)\n'))
+ ui.status(_(b'evolve: (evolve --continue)\n'))
@eh.extsetup
def obssummarysetup(ui):
- cmdutil.summaryhooks.add('evolve', summaryhook)
+ cmdutil.summaryhooks.add(b'evolve', summaryhook)
#####################################################################
### Old Evolve extension content ###
@@ -814,19 +814,19 @@
@eh.uisetup
def _installimportobsolete(ui):
- entry = cmdutil.findcmd('import', commands.table)[1]
- entry[1].append(('', 'obsolete', False,
- _('mark the old node as obsoleted by '
- 'the created commit')))
+ entry = cmdutil.findcmd(b'import', commands.table)[1]
+ entry[1].append((b'', b'obsolete', False,
+ _(b'mark the old node as obsoleted by '
+ b'the created commit')))
def _getnodefrompatch(patch, dest):
- patchnode = patch.get('nodeid')
+ patchnode = patch.get(b'nodeid')
if patchnode is not None:
- dest['node'] = node.bin(patchnode)
+ dest[b'node'] = node.bin(patchnode)
@eh.wrapfunction(mercurial.cmdutil, 'tryimportone')
def tryimportone(orig, ui, repo, hunk, parents, opts, *args, **kwargs):
- expected = {'node': None}
+ expected = {b'node': None}
if not util.safehasattr(hunk, 'get'): # hg < 4.6
oldextract = patch.extract
@@ -843,12 +843,12 @@
_getnodefrompatch(hunk, expected)
ret = orig(ui, repo, hunk, parents, opts, *args, **kwargs)
created = ret[1]
- if (opts['obsolete'] and None not in (created, expected['node'])
- and created != expected['node']):
- tr = repo.transaction('import-obs')
+ if (opts[b'obsolete'] and None not in (created, expected[b'node'])
+ and created != expected[b'node']):
+ tr = repo.transaction(b'import-obs')
try:
- metadata = {'user': ui.username()}
- repo.obsstore.create(tr, expected['node'], (created,),
+ metadata = {b'user': ui.username()}
+ repo.obsstore.create(tr, expected[b'node'], (created,),
metadata=metadata)
tr.close()
finally:
@@ -876,62 +876,62 @@
if e is entry:
break
- synopsis = '(DEPRECATED)'
+ synopsis = b'(DEPRECATED)'
if len(entry) > 2:
fn, opts, _syn = entry
else:
fn, opts, = entry
- deprecationwarning = _('%s have been deprecated in favor of %s\n') % (
+ deprecationwarning = _(b'%s have been deprecated in favor of %s\n') % (
oldalias, newalias)
def newfn(*args, **kwargs):
ui = args[0]
ui.warn(deprecationwarning)
util.checksignature(fn)(*args, **kwargs)
- newfn.__doc__ = pycompat.sysstr(deprecationwarning + ' (DEPRECATED)')
+ newfn.__doc__ = pycompat.sysstr(deprecationwarning + b' (DEPRECATED)')
cmdwrapper = eh.command(oldalias, opts, synopsis)
cmdwrapper(newfn)
@eh.extsetup
def deprecatealiases(ui):
- _deprecatealias('gup', 'next')
- _deprecatealias('gdown', 'previous')
+ _deprecatealias(b'gup', b'next')
+ _deprecatealias(b'gdown', b'previous')
def _gettopic(ctx):
"""handle topic fetching with or without the extension"""
- return getattr(ctx, 'topic', lambda: '')()
+ return getattr(ctx, 'topic', lambda: b'')()
def _gettopicidx(ctx):
"""handle topic fetching with or without the extension"""
return getattr(ctx, 'topicidx', lambda: None)()
def _getcurrenttopic(repo):
- return getattr(repo, 'currenttopic', '')
+ return getattr(repo, 'currenttopic', b'')
def _prevupdate(repo, displayer, target, bookmark, dryrun, mergeopt):
if dryrun:
- repo.ui.write(_('hg update %s;\n') % target)
+ repo.ui.write(_(b'hg update %s;\n') % target)
if bookmark is not None:
- repo.ui.write(_('hg bookmark %s -r %s;\n')
+ repo.ui.write(_(b'hg bookmark %s -r %s;\n')
% (bookmark, target))
else:
updatecheck = None
# --merge is passed, we don't need to care about commands.update.check
# config option
if mergeopt:
- updatecheck = 'none'
+ updatecheck = b'none'
try:
ret = hg.updatetotally(repo.ui, repo, target.node(), None,
updatecheck=updatecheck)
except error.Abort as exc:
# replace the hint to mention about --merge option
- exc.hint = _('do you want --merge?')
+ exc.hint = _(b'do you want --merge?')
raise
if not ret:
tr = lock = None
try:
lock = repo.lock()
- tr = repo.transaction('previous')
+ tr = repo.transaction(b'previous')
if bookmark is not None:
bmchanges = [(bookmark, target.node())]
repo._bookmarks.applychanges(repo, tr, bmchanges)
@@ -959,23 +959,23 @@
# issue message for the various case
if p1.node() == node.nullid:
- repo.ui.warn(_('already at repository root\n'))
+ repo.ui.warn(_(b'already at repository root\n'))
elif not parents and currenttopic:
- repo.ui.warn(_('no parent in topic "%s"\n') % currenttopic)
- repo.ui.warn(_('(do you want --no-topic)\n'))
+ repo.ui.warn(_(b'no parent in topic "%s"\n') % currenttopic)
+ repo.ui.warn(_(b'(do you want --no-topic)\n'))
elif len(parents) == 1:
target = parents[0]
bookmark = None
if movebookmark:
bookmark = repo._activebookmark
else:
- header = _("multiple parents, choose one to update:")
+ 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:
for p in parents:
displayer.show(p)
- repo.ui.warn(_('multiple parents, explicitly update to one\n'))
+ repo.ui.warn(_(b'multiple parents, explicitly update to one\n'))
else:
target = repo[choosedrev]
return target, bookmark
@@ -1003,13 +1003,13 @@
wkctx = repo[None]
wparents = wkctx.parents()
if len(wparents) != 1:
- raise error.Abort(_('merge in progress'))
+ raise error.Abort(_(b'merge in progress'))
if not mergeopt:
# we only skip the check if noconflict is set
- if ui.config('commands', 'update.check') == 'noconflict':
+ if ui.config(b'commands', b'update.check') == b'noconflict':
pass
else:
- cmdutil.bailifchanged(repo, hint=_('do you want --merge?'))
+ cmdutil.bailifchanged(repo, hint=_(b'do you want --merge?'))
topic = not opts.get("no_topic", False)
hastopic = bool(_getcurrenttopic(repo))
@@ -1018,16 +1018,16 @@
if topic and hastopic:
template = utility.stacktemplate
- displayer = compat.changesetdisplayer(ui, repo, {'template': template})
+ displayer = compat.changesetdisplayer(ui, repo, {b'template': template})
target, bookmark = _findprevtarget(repo, displayer,
opts.get('move_bookmark'), topic)
if target is not None:
- backup = repo.ui.backupconfig('_internal', 'keep-topic')
+ backup = repo.ui.backupconfig(b'_internal', b'keep-topic')
try:
if topic and _getcurrenttopic(repo) != _gettopic(target):
- repo.ui.setconfig('_internal', 'keep-topic', 'yes',
- source='topic-extension')
+ repo.ui.setconfig(b'_internal', b'keep-topic', b'yes',
+ source=b'topic-extension')
_prevupdate(repo, displayer, target, bookmark, dryrunopt,
mergeopt)
finally:
@@ -1065,7 +1065,7 @@
wkctx = repo[None]
wparents = wkctx.parents()
if len(wparents) != 1:
- raise error.Abort(_('merge in progress'))
+ raise error.Abort(_(b'merge in progress'))
children = [ctx for ctx in wparents[0].children() if not ctx.obsolete()]
topic = _getcurrenttopic(repo)
@@ -1076,11 +1076,11 @@
children = [ctx for ctx in children if ctx not in filtered]
template = utility.stacktemplate
opts['stacktemplate'] = True
- displayer = compat.changesetdisplayer(ui, repo, {'template': template})
+ displayer = compat.changesetdisplayer(ui, repo, {b'template': template})
# check if we need to evolve while updating to the next child revision
needevolve = False
- aspchildren = evolvecmd._aspiringchildren(repo, [repo['.'].rev()])
+ aspchildren = evolvecmd._aspiringchildren(repo, [repo[b'.'].rev()])
if topic:
filtered.update(repo[c] for c in aspchildren
if repo[c].topic() != topic)
@@ -1100,53 +1100,53 @@
# check if working directory is clean before we evolve the next cset
if needevolve and opts['evolve']:
- hint = _('use `hg amend`, `hg revert` or `hg shelve`')
+ hint = _(b'use `hg amend`, `hg revert` or `hg shelve`')
cmdutil.bailifchanged(repo, hint=hint)
if not (opts['merge'] or (needevolve and opts['evolve'])):
# we only skip the check if noconflict is set
- if ui.config('commands', 'update.check') == 'noconflict':
+ if ui.config(b'commands', b'update.check') == b'noconflict':
pass
else:
- cmdutil.bailifchanged(repo, hint=_('do you want --merge?'))
+ cmdutil.bailifchanged(repo, hint=_(b'do you want --merge?'))
if len(children) == 1:
c = children[0]
return _updatetonext(ui, repo, c, displayer, opts)
elif children:
- cheader = _("ambiguous next changeset, choose one to update:")
+ 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:
- ui.warn(_("ambiguous next changeset:\n"))
+ ui.warn(_(b"ambiguous next changeset:\n"))
for c in children:
displayer.show(c)
- ui.warn(_("explicitly update to one of them\n"))
+ ui.warn(_(b"explicitly update to one of them\n"))
return 1
else:
return _updatetonext(ui, repo, repo[choosedrev], displayer, opts)
else:
if not opts['evolve'] or not aspchildren:
if filtered:
- ui.warn(_('no children on topic "%s"\n') % topic)
- ui.warn(_('do you want --no-topic\n'))
+ ui.warn(_(b'no children on topic "%s"\n') % topic)
+ ui.warn(_(b'do you want --no-topic\n'))
else:
- ui.warn(_('no children\n'))
+ ui.warn(_(b'no children\n'))
if aspchildren:
- msg = _('(%i unstable changesets to be evolved here, '
- 'do you want --evolve?)\n')
+ msg = _(b'(%i unstable changesets to be evolved here, '
+ b'do you want --evolve?)\n')
ui.warn(msg % len(aspchildren))
return 1
elif len(aspchildren) > 1:
- cheader = _("ambiguous next (unstable) changeset, choose one to"
- " evolve and update:")
+ cheader = _(b"ambiguous next (unstable) changeset, choose one to"
+ b" evolve and update:")
choosedrev = utility.revselectionprompt(ui, repo,
aspchildren, cheader)
if choosedrev is None:
- ui.warn(_("ambiguous next (unstable) changeset:\n"))
+ ui.warn(_(b"ambiguous next (unstable) changeset:\n"))
for c in aspchildren:
displayer.show(repo[c])
- ui.warn(_("(run 'hg evolve --rev REV' on one of them)\n"))
+ ui.warn(_(b"(run 'hg evolve --rev REV' on one of them)\n"))
return 1
else:
return _nextevolve(ui, repo, repo[choosedrev], opts)
@@ -1159,21 +1159,21 @@
"""logic for hg next command to evolve and update to an aspiring children"""
cmdutil.bailifchanged(repo)
- evolvestate = state.cmdstate(repo, opts={'command': 'next',
- 'bookmarkchanges': []})
+ evolvestate = state.cmdstate(repo, opts={b'command': b'next',
+ b'bookmarkchanges': []})
with repo.wlock(), repo.lock():
- tr = repo.transaction("evolve")
+ tr = repo.transaction(b"evolve")
with util.acceptintervention(tr):
result = evolvecmd._solveone(ui, repo, repo[aspchildren],
evolvestate, opts.get('dry_run'),
False,
- lambda: None, category='orphan',
+ lambda: None, category=b'orphan',
stacktmplt=opts.get('stacktemplate',
False))
# making sure a next commit is formed
if result[0] and result[1]:
- ui.status(_('working directory is now at %s\n')
- % ui.label(bytes(repo['.']), 'evolve.node'))
+ ui.status(_(b'working directory is now at %s\n')
+ % ui.label(bytes(repo[b'.']), b'evolve.node'))
return 0
def _updatetonext(ui, repo, child, displayer, opts):
@@ -1182,28 +1182,28 @@
bm = repo._activebookmark
shouldmove = opts.get('move_bookmark') and bm is not None
if opts.get('dry_run'):
- ui.write(_('hg update %s;\n') % child)
+ ui.write(_(b'hg update %s;\n') % child)
if shouldmove:
- ui.write(_('hg bookmark %s -r %s;\n') % (bm, child))
+ ui.write(_(b'hg bookmark %s -r %s;\n') % (bm, child))
else:
updatecheck = None
# --merge is passed, we don't need to care about commands.update.check
# config option
if opts['merge']:
- updatecheck = 'none'
+ updatecheck = b'none'
try:
ret = hg.updatetotally(ui, repo, child.node(), None,
updatecheck=updatecheck)
except error.Abort as exc:
# replace the hint to mention about --merge option
- exc.hint = _('do you want --merge?')
+ exc.hint = _(b'do you want --merge?')
raise
if not ret:
lock = tr = None
try:
lock = repo.lock()
- tr = repo.transaction('next')
+ tr = repo.transaction(b'next')
if shouldmove:
bmchanges = [(bm, child.node())]
repo._bookmarks.applychanges(repo, tr, bmchanges)
@@ -1216,7 +1216,7 @@
displayer.show(child)
return 0
-@eh.wrapcommand('commit')
+@eh.wrapcommand(b'commit')
def commitwrapper(orig, ui, repo, *arg, **kwargs):
tr = None
if kwargs.get('amend', False):
@@ -1227,17 +1227,17 @@
try:
obsoleted = kwargs.get('obsolete', [])
if obsoleted:
- obsoleted = repo.set('%lr', obsoleted)
+ obsoleted = repo.set(b'%lr', obsoleted)
result = orig(ui, repo, *arg, **kwargs)
if not result: # commit succeeded
- new = repo['tip']
+ new = repo[b'tip']
oldbookmarks = []
markers = []
for old in obsoleted:
oldbookmarks.extend(repo.nodebookmarks(old.node()))
markers.append((old, (new,)))
if markers:
- obsolete.createmarkers(repo, markers, operation="amend")
+ obsolete.createmarkers(repo, markers, operation=b"amend")
bmchanges = []
for book in oldbookmarks:
bmchanges.append((book, new.node()))
@@ -1246,32 +1246,32 @@
wlock = repo.wlock()
if not lock:
lock = repo.lock()
- tr = repo.transaction('commit')
+ tr = repo.transaction(b'commit')
repo._bookmarks.applychanges(repo, tr, bmchanges)
tr.close()
return result
finally:
lockmod.release(tr, lock, wlock)
-@eh.wrapcommand('strip', extension='strip', opts=[
- ('', 'bundle', None, _("delete the commit entirely and move it to a "
- "backup bundle")),
+@eh.wrapcommand(b'strip', extension=b'strip', opts=[
+ (b'', b'bundle', None, _(b"delete the commit entirely and move it to a "
+ b"backup bundle")),
])
def stripwrapper(orig, ui, repo, *revs, **kwargs):
- if (not ui.configbool('experimental', 'prunestrip')
+ if (not ui.configbool(b'experimental', b'prunestrip')
or kwargs.get('bundle', False)):
return orig(ui, repo, *revs, **kwargs)
if kwargs.get('force'):
- ui.warn(_("warning: --force has no effect during strip with evolve "
- "enabled\n"))
+ ui.warn(_(b"warning: --force has no effect during strip with evolve "
+ b"enabled\n"))
if kwargs.get('no_backup', False):
- ui.warn(_("warning: --no-backup has no effect during strips with "
- "evolve enabled\n"))
+ ui.warn(_(b"warning: --no-backup has no effect during strips with "
+ b"evolve enabled\n"))
revs = list(revs) + kwargs.pop('rev', [])
revs = set(scmutil.revrange(repo, revs))
- revs = repo.revs("(%ld)::", revs)
+ revs = repo.revs(b"(%ld)::", revs)
kwargs['rev'] = []
kwargs['new'] = []
kwargs['successor'] = []
@@ -1280,9 +1280,9 @@
@eh.extsetup
def oldevolveextsetup(ui):
- entry = cmdutil.findcmd('commit', commands.table)[1]
- entry[1].append(('o', 'obsolete', [],
- _("make commit obsolete this revision (DEPRECATED)")))
+ entry = cmdutil.findcmd(b'commit', commands.table)[1]
+ entry[1].append((b'o', b'obsolete', [],
+ _(b"make commit obsolete this revision (DEPRECATED)")))
@eh.wrapfunction(obsolete, '_checkinvalidmarkers')
def _checkinvalidmarkers(orig, markers):
@@ -1291,12 +1291,12 @@
Exist as a separated function to allow the evolve extension for a more
subtle handling.
"""
- if 'debugobsconvert' in sys.argv:
+ if r'debugobsconvert' in sys.argv:
return
for mark in markers:
if node.nullid in mark[1]:
- msg = _('bad obsolescence marker detected: invalid successors nullid')
- hint = _('You should run `hg debugobsconvert`')
+ msg = _(b'bad obsolescence marker detected: invalid successors nullid')
+ hint = _(b'You should run `hg debugobsconvert`')
raise error.Abort(msg, hint=hint)
@eh.command(
@@ -1306,10 +1306,10 @@
def debugobsconvert(ui, repo, new_format):
origmarkers = repo.obsstore._all # settle version
if new_format == repo.obsstore._version:
- msg = _('New format is the same as the old format, not upgrading!')
+ msg = _(b'New format is the same as the old format, not upgrading!')
raise error.Abort(msg)
with repo.lock():
- f = repo.svfs('obsstore', 'wb', atomictemp=True)
+ f = repo.svfs(b'obsstore', b'wb', atomictemp=True)
known = set()
markers = []
for m in origmarkers:
@@ -1322,12 +1322,12 @@
continue
known.add(m)
markers.append(m)
- ui.write(_('Old store is version %d, will rewrite in version %d\n') % (
+ ui.write(_(b'Old store is version %d, will rewrite in version %d\n') % (
repo.obsstore._version, new_format))
for data in obsolete.encodemarkers(markers, True, new_format):
f.write(data)
f.close()
- ui.write(_('Done!\n'))
+ ui.write(_(b'Done!\n'))
def _helploader(ui):
@@ -1336,55 +1336,57 @@
@eh.uisetup
def _setuphelp(ui):
for entry in help.helptable:
- if entry[0] == "evolution":
+ if entry[0] == b"evolution":
break
else:
- help.helptable.append((["evolution"], _("Safely Rewriting History"),
- _helploader))
+ help.helptable.append(([b"evolution"], _(b"Safely Rewriting History"),
+ _helploader))
help.helptable.sort()
evolvestateversion = 0
def _evolvemessage():
- _msg = _('To continue: hg evolve --continue\n'
- 'To abort: hg evolve --abort\n'
- 'To stop: hg evolve --stop\n'
- '(also see `hg help evolve.interrupted`)')
+ _msg = _(b'To continue: hg evolve --continue\n'
+ b'To abort: hg evolve --abort\n'
+ b'To stop: hg evolve --stop\n'
+ b'(also see `hg help evolve.interrupted`)')
return cmdutil._commentlines(_msg)
@eh.uisetup
def setupevolveunfinished(ui):
if not util.safehasattr(cmdutil, 'unfinishedstates'):
from mercurial import state as statemod
- _msg = _('To continue: hg evolve --continue\n'
- 'To abort: hg evolve --abort\n'
- 'To stop: hg evolve --stop\n'
- '(also see `hg help evolve.interrupted`)')
- statemod.addunfinished('evolve', fname='evolvestate',
+ _msg = _(b'To continue: hg evolve --continue\n'
+ b'To abort: hg evolve --abort\n'
+ b'To stop: hg evolve --stop\n'
+ b'(also see `hg help evolve.interrupted`)')
+ statemod.addunfinished(b'evolve', fname=b'evolvestate',
continueflag=True, stopflag=True,
- statushint=_msg)
- statemod.addunfinished('pick', fname='pickstate', continueflag=True)
+ statushint=_msg,
+ abortfunc=evolvecmd.hgabortevolve)
+ statemod.addunfinished(b'pick', fname=b'pickstate', continueflag=True,
+ abortfunc=cmdrewrite.hgabortpick)
else:
# compat <= hg-5.0 (5f2f6912c9e6)
- estate = ('evolvestate', False, False, _('evolve in progress'),
- _("use 'hg evolve --continue' or 'hg evolve --abort' to abort"))
+ estate = (b'evolvestate', False, False, _(b'evolve in progress'),
+ _(b"use 'hg evolve --continue' or 'hg evolve --abort' to abort"))
cmdutil.unfinishedstates.append(estate)
- pstate = ('pickstate', False, False, _('pick in progress'),
- _("use 'hg pick --continue' or 'hg pick --abort' to abort"))
+ pstate = (b'pickstate', False, False, _(b'pick in progress'),
+ _(b"use 'hg pick --continue' or 'hg pick --abort' to abort"))
cmdutil.unfinishedstates.append(pstate)
- afterresolved = ('evolvestate', _('hg evolve --continue'))
- pickresolved = ('pickstate', _('hg pick --continue'))
+ afterresolved = (b'evolvestate', _(b'hg evolve --continue'))
+ pickresolved = (b'pickstate', _(b'hg pick --continue'))
cmdutil.afterresolvedstates.append(afterresolved)
cmdutil.afterresolvedstates.append(pickresolved)
if util.safehasattr(cmdutil, 'STATES'):
- statedata = ('evolve', cmdutil.fileexistspredicate('evolvestate'),
+ statedata = (b'evolve', cmdutil.fileexistspredicate(b'evolvestate'),
_evolvemessage)
cmdutil.STATES = (statedata, ) + cmdutil.STATES
@eh.wrapfunction(hg, 'clean')
def clean(orig, repo, *args, **kwargs):
ret = orig(repo, *args, **kwargs)
- util.unlinkpath(repo.vfs.join('evolvestate'), ignoremissing=True)
+ util.unlinkpath(repo.vfs.join(b'evolvestate'), ignoremissing=True)
return ret
--- a/hgext3rd/evolve/cmdrewrite.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/cmdrewrite.py Fri Sep 27 13:03:14 2019 +0200
@@ -67,12 +67,12 @@
return
if not compat.isobsnotesupported():
- ui.warn(_("current hg version does not support storing"
- " note in obsmarker\n"))
+ ui.warn(_(b"current hg version does not support storing"
+ b" note in obsmarker\n"))
if len(note) > 255:
- raise error.Abort(_("cannot store a note of more than 255 bytes"))
- if '\n' in note:
- raise error.Abort(_("note cannot contain a newline"))
+ raise error.Abort(_(b"cannot store a note of more than 255 bytes"))
+ if b'\n' in note:
+ raise error.Abort(_(b"note cannot contain a newline"))
def _resolveoptions(ui, opts):
"""modify commit options dict to handle related options
@@ -82,7 +82,7 @@
"""
# N.B. this is extremely similar to setupheaderopts() in mq.py
if not opts.get('date') and opts.get('current_date'):
- opts['date'] = '%d %d' % compat.makedate()
+ opts['date'] = b'%d %d' % compat.makedate()
if not opts.get('user') and opts.get('current_user'):
opts['user'] = ui.username()
@@ -136,26 +136,26 @@
if opts.pop('all', False):
# add an include for all
include = list(opts.get('include'))
- include.append('re:.*')
+ include.append(b're:.*')
edit = opts.pop('edit', False)
log = opts.get('logfile')
opts['amend'] = True
_resolveoptions(ui, opts)
- _alias, commitcmd = cmdutil.findcmd('commit', commands.table)
+ _alias, commitcmd = cmdutil.findcmd(b'commit', commands.table)
with repo.wlock(), repo.lock():
if not (edit or opts['message'] or log):
- opts['message'] = repo['.'].description()
- rewriteutil.precheck(repo, [repo['.'].rev()], action='amend')
+ opts['message'] = repo[b'.'].description()
+ rewriteutil.precheck(repo, [repo[b'.'].rev()], action=b'amend')
return commitcmd[0](ui, repo, *pats, **opts)
def amendpatch(ui, repo, *pats, **opts):
"""logic for --patch flag of `hg amend` command."""
- with repo.wlock(), repo.lock(), repo.transaction('amend') as tr:
+ with repo.wlock(), repo.lock(), repo.transaction(b'amend') as tr:
cmdutil.bailifchanged(repo)
# first get the patch
- old = repo['.']
+ old = repo[b'.']
p1 = old.p1()
- rewriteutil.precheck(repo, [old.rev()], 'amend')
+ rewriteutil.precheck(repo, [old.rev()], b'amend')
diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
diffopts.nodates = True
diffopts.git = True
@@ -168,12 +168,12 @@
fp.write(chunk)
newnode = _editandapply(ui, repo, pats, old, p1, fp, diffopts)
if newnode == old.node():
- raise error.Abort(_("nothing changed"))
+ raise error.Abort(_(b"nothing changed"))
metadata = {}
if opts.get('note'):
- metadata['note'] = opts['note']
+ metadata[b'note'] = opts['note']
replacements = {old.node(): [newnode]}
- scmutil.cleanupnodes(repo, replacements, operation='amend',
+ scmutil.cleanupnodes(repo, replacements, operation=b'amend',
metadata=metadata)
phases.retractboundary(repo, tr, old.phase(), [newnode])
hg.updaterepo(repo, newnode, True)
@@ -183,13 +183,13 @@
while newnode is None:
fp.seek(0)
previous_patch = fp.getvalue()
- newpatch = ui.edit(fp.getvalue(), old.user(), action="diff")
+ newpatch = ui.edit(fp.getvalue(), old.user(), action=b"diff")
afp = stringio()
afp.write(newpatch)
if pats:
# write rest of the files in the patch
- restmatcher = scmutil.match(old, [], opts={'exclude': pats})
+ restmatcher = scmutil.match(old, [], opts={b'exclude': pats})
for chunk, label in patch.diffui(repo, p1.node(), old.node(),
match=restmatcher,
opts=diffopts):
@@ -197,21 +197,21 @@
user_patch = afp.getvalue()
if not user_patch:
- raise error.Abort(_("empty patch file, amend aborted"))
+ raise error.Abort(_(b"empty patch file, amend aborted"))
if user_patch == previous_patch:
- raise error.Abort(_("patch unchanged"))
+ raise error.Abort(_(b"patch unchanged"))
afp.seek(0)
# write the patch to repo and get the newnode
try:
newnode = _writepatch(ui, repo, old, afp)
except patch.PatchError as err:
- ui.write_err(_("failed to apply edited patch: %s\n") % err)
+ ui.write_err(_(b"failed to apply edited patch: %s\n") % err)
defaultchoice = 0 # yes
if not ui.interactive:
defaultchoice = 1 # no
- retrychoice = _('try to fix the patch (yn)?$$ &Yes $$ &No')
+ retrychoice = _(b'try to fix the patch (yn)?$$ &Yes $$ &No')
if ui.promptchoice(retrychoice, default=defaultchoice):
- raise error.Abort(_("Could not apply amended path"))
+ raise error.Abort(_(b"Could not apply amended path"))
else:
# consider a third choice where we restore the original patch
fp = stringio()
@@ -233,20 +233,20 @@
with patchcontext as metadata:
# store the metadata from the patch to variables
- parents = (metadata.get('p1'), metadata.get('p2'))
- date = metadata.get('date') or old.date()
- branch = metadata.get('branch') or old.branch()
- user = metadata.get('user') or old.user()
+ parents = (metadata.get(b'p1'), metadata.get(b'p2'))
+ date = metadata.get(b'date') or old.date()
+ branch = metadata.get(b'branch') or old.branch()
+ user = metadata.get(b'user') or old.user()
# XXX: we must extract extras from the patchfile too
extra = old.extra()
- message = metadata.get('message') or old.description()
+ message = metadata.get(b'message') or old.description()
store = patch.filestore()
fp.seek(0)
try:
files = set()
# beware: next line may raise a PatchError to be handled by the caller
# of this function
- patch.patchrepo(ui, repo, pold, store, fp, 1, '',
+ patch.patchrepo(ui, repo, pold, store, fp, 1, b'',
files=files, eolmode=None)
memctx = context.memctx(repo, parents, message, files=files,
@@ -269,23 +269,23 @@
else:
prev = node.nullid
- fp.write("# HG changeset patch\n")
- fp.write("# User %s\n" % ctx.user())
- fp.write("# Date %d %d\n" % ctx.date())
- fp.write("# %s\n" % datestr(ctx.date()))
- if branch and branch != 'default':
- fp.write("# Branch %s\n" % branch)
- fp.write("# Node ID %s\n" % node.hex(nodeval))
- fp.write("# Parent %s\n" % node.hex(prev))
+ fp.write(b"# HG changeset patch\n")
+ fp.write(b"# User %s\n" % ctx.user())
+ fp.write(b"# Date %d %d\n" % ctx.date())
+ fp.write(b"# %s\n" % datestr(ctx.date()))
+ if branch and branch != b'default':
+ fp.write(b"# Branch %s\n" % branch)
+ fp.write(b"# Node ID %s\n" % node.hex(nodeval))
+ fp.write(b"# Parent %s\n" % node.hex(prev))
if len(parents) > 1:
- fp.write("# Parent %s\n" % node.hex(parents[1]))
+ fp.write(b"# Parent %s\n" % node.hex(parents[1]))
for headerid in cmdutil.extraexport:
header = cmdutil.extraexportmap[headerid](1, ctx)
if header is not None:
- fp.write('# %s\n' % header)
+ fp.write(b'# %s\n' % header)
fp.write(ctx.description().rstrip())
- fp.write("\n\n")
+ fp.write(b"\n\n")
def _touchedbetween(repo, source, dest, match=None):
touched = set()
@@ -354,7 +354,7 @@
oldctx to a copy of oldctx not containing changed files matched by
match.
"""
- ctx = repo['.']
+ ctx = repo[b'.']
ds = repo.dirstate
copies = dict(ds.copies())
if interactive:
@@ -373,7 +373,7 @@
# Also any modifications to a removed file will result the status as
# added, so we have only two cases. So in either of the cases, the
# resulting status can be modified or clean.
- if ds[f] == 'r':
+ if ds[f] == b'r':
# But the file is removed in the working directory, leaving that
# as removed
continue
@@ -387,7 +387,7 @@
# does not adds it back. If it's adds it back, we do a normallookup.
# The file can't be removed in working directory, because it was
# removed in oldctx
- if ds[f] == 'a':
+ if ds[f] == b'a':
ds.normallookup(f)
continue
ds.remove(f)
@@ -399,7 +399,7 @@
# would have resulted in modified status, not removed.
# So a file added in a commit, and uncommitting that addition must
# result in file being stated as unknown.
- if ds[f] == 'r':
+ if ds[f] == b'r':
# The working directory say it's removed, so lets make the file
# unknown
ds.drop(f)
@@ -408,23 +408,23 @@
else:
m, a, r = repo.status(oldctx.p1(), oldctx, match=match)[:3]
for f in m:
- if ds[f] == 'r':
+ if ds[f] == b'r':
# modified + removed -> removed
continue
ds.normallookup(f)
for f in a:
- if ds[f] == 'r':
+ if ds[f] == b'r':
# added + removed -> unknown
ds.drop(f)
- elif ds[f] != 'a':
+ elif ds[f] != b'a':
ds.add(f)
for f in r:
- if ds[f] == 'a':
+ if ds[f] == b'a':
# removed + added -> normal
ds.normallookup(f)
- elif ds[f] != 'r':
+ elif ds[f] != b'r':
ds.remove(f)
# Merge old parent and old working dir copies
@@ -442,7 +442,7 @@
for dst, src in oldcopies.items())
# Adjust the dirstate copies
for dst, src in copies.items():
- if (src not in ctx or dst in ctx or ds[dst] != 'a'):
+ if (src not in ctx or dst in ctx or ds[dst] != b'a'):
src = None
ds.copy(src, dst)
@@ -487,13 +487,13 @@
lock = repo.lock()
wctx = repo[None]
if len(wctx.parents()) <= 0:
- raise error.Abort(_("cannot uncommit null changeset"))
+ raise error.Abort(_(b"cannot uncommit null changeset"))
if len(wctx.parents()) > 1:
- raise error.Abort(_("cannot uncommit while merging"))
- old = repo['.']
- rewriteutil.precheck(repo, [repo['.'].rev()], action='uncommit')
+ raise error.Abort(_(b"cannot uncommit while merging"))
+ old = repo[b'.']
+ rewriteutil.precheck(repo, [repo[b'.'].rev()], action=b'uncommit')
if len(old.parents()) > 1:
- raise error.Abort(_("cannot uncommit merge changeset"))
+ raise error.Abort(_(b"cannot uncommit merge changeset"))
oldphase = old.phase()
rev = None
@@ -501,13 +501,13 @@
rev = scmutil.revsingle(repo, opts.get('rev'))
ctx = repo[None]
if ctx.p1() == rev or ctx.p2() == rev:
- raise error.Abort(_("cannot uncommit to parent changeset"))
+ raise error.Abort(_(b"cannot uncommit to parent changeset"))
onahead = old.rev() in repo.changelog.headrevs()
disallowunstable = not obsolete.isenabled(repo,
obsolete.allowunstableopt)
if disallowunstable and not onahead:
- raise error.Abort(_("cannot uncommit in the middle of a stack"))
+ raise error.Abort(_(b"cannot uncommit in the middle of a stack"))
match = scmutil.match(old, pats, pycompat.byteskwargs(opts))
@@ -542,7 +542,7 @@
% uipathfn(f), hint=hint)
# Recommit the filtered changeset
- tr = repo.transaction('uncommit')
+ tr = repo.transaction(b'uncommit')
if interactive:
opts['all'] = True
newid = _interactiveuncommit(ui, repo, old, match)
@@ -557,16 +557,16 @@
message=message, user=opts.get('user'),
date=opts.get('date'))
if newid is None:
- raise error.Abort(_('nothing to uncommit'),
- hint=_("use --all to uncommit all files"))
+ raise error.Abort(_(b'nothing to uncommit'),
+ hint=_(b"use --all to uncommit all files"))
# metadata to be stored in obsmarker
metadata = {}
if opts.get('note'):
- metadata['note'] = opts['note']
+ metadata[b'note'] = opts['note']
replacements = {old.node(): [newid]}
- scmutil.cleanupnodes(repo, replacements, operation="uncommit",
+ scmutil.cleanupnodes(repo, replacements, operation=b"uncommit",
metadata=metadata)
phases.retractboundary(repo, tr, oldphase, [newid])
if opts.get('revert'):
@@ -576,8 +576,8 @@
repo.dirstate.setparents(newid, node.nullid)
_uncommitdirstate(repo, old, match, interactive)
if not repo[newid].files():
- ui.warn(_("new changeset is empty\n"))
- ui.status(_("(use 'hg prune .' to remove it)\n"))
+ ui.warn(_(b"new changeset is empty\n"))
+ ui.status(_(b"(use 'hg prune .' to remove it)\n"))
tr.close()
finally:
lockmod.release(tr, lock, wlock)
@@ -604,7 +604,7 @@
fp.seek(0)
newnode = _patchtocommit(ui, repo, old, fp)
# creating obs marker temp -> ()
- obsolete.createmarkers(repo, [(repo[tempnode], ())], operation="uncommit")
+ obsolete.createmarkers(repo, [(repo[tempnode], ())], operation=b"uncommit")
return newnode
def _createtempcommit(ui, repo, old, match):
@@ -626,20 +626,20 @@
# to add uncommit as an operation taking care of BC.
try:
chunks, opts = cmdutil.recordfilter(repo.ui, originalchunks, match,
- operation='discard')
+ operation=b'discard')
except TypeError:
# hg <= 4.9 (db72f9f6580e)
chunks, opts = cmdutil.recordfilter(repo.ui, originalchunks,
- operation='discard')
+ operation=b'discard')
if not chunks:
- raise error.Abort(_("nothing selected to uncommit"))
+ raise error.Abort(_(b"nothing selected to uncommit"))
fp = stringio()
for c in chunks:
c.write(fp)
fp.seek(0)
oldnode = node.hex(old.node())[:12]
- message = 'temporary commit for uncommiting %s' % oldnode
+ message = b'temporary commit for uncommiting %s' % oldnode
tempnode = _patchtocommit(ui, repo, old, fp, message, oldnode)
return tempnode
@@ -656,14 +656,14 @@
user = old.user()
extra = old.extra()
if extras:
- extra['uncommit_source'] = extras
+ extra[b'uncommit_source'] = extras
if not message:
message = old.description()
store = patch.filestore()
try:
files = set()
try:
- patch.patchrepo(ui, repo, pold, store, fp, 1, '',
+ patch.patchrepo(ui, repo, pold, store, fp, 1, b'',
files=files, eolmode=None)
except patch.PatchError as err:
raise error.Abort(pycompat.bytestr(err))
@@ -733,33 +733,33 @@
revs = list(revs)
revs.extend(opts['rev'])
if not revs:
- raise error.Abort(_('no revisions specified'))
+ raise error.Abort(_(b'no revisions specified'))
revs = scmutil.revrange(repo, revs)
if opts['from'] and opts['exact']:
- raise error.Abort(_('cannot use both --from and --exact'))
+ raise error.Abort(_(b'cannot use both --from and --exact'))
elif opts['from']:
# Try to extend given revision starting from the working directory
- extrevs = repo.revs('(%ld::.) or (.::%ld)', revs, revs)
+ extrevs = repo.revs(b'(%ld::.) or (.::%ld)', revs, revs)
discardedrevs = [r for r in revs if r not in extrevs]
if discardedrevs:
- msg = _("cannot fold non-linear revisions")
- hint = _("given revisions are unrelated to parent of working"
- " directory")
+ msg = _(b"cannot fold non-linear revisions")
+ hint = _(b"given revisions are unrelated to parent of working"
+ b" directory")
raise error.Abort(msg, hint=hint)
revs = extrevs
elif opts['exact']:
# Nothing to do; "revs" is already set correctly
pass
else:
- raise error.Abort(_('must specify either --from or --exact'))
+ raise error.Abort(_(b'must specify either --from or --exact'))
if not revs:
- raise error.Abort(_('specified revisions evaluate to an empty set'),
- hint=_('use different revision arguments'))
+ raise error.Abort(_(b'specified revisions evaluate to an empty set'),
+ hint=_(b'use different revision arguments'))
elif len(revs) == 1:
- ui.write_err(_('single revision specified, nothing to fold\n'))
+ ui.write_err(_(b'single revision specified, nothing to fold\n'))
return 1
# Sort so combined commit message of `hg fold --exact -r . -r .^` is
@@ -773,7 +773,7 @@
root, head, p2 = rewriteutil.foldcheck(repo, revs)
- tr = repo.transaction('fold')
+ tr = repo.transaction(b'fold')
try:
commitopts = opts.copy()
allctx = [repo[r] for r in revs]
@@ -782,15 +782,15 @@
if commitopts.get('message') or commitopts.get('logfile'):
commitopts['edit'] = False
else:
- msgs = ["HG: This is a fold of %d changesets." % len(allctx)]
- msgs += ["HG: Commit message of changeset %d.\n\n%s\n" %
+ msgs = [b"HG: This is a fold of %d changesets." % len(allctx)]
+ msgs += [b"HG: Commit message of changeset %d.\n\n%s\n" %
(c.rev(), c.description()) for c in allctx]
- commitopts['message'] = "\n".join(msgs)
+ commitopts['message'] = b"\n".join(msgs)
commitopts['edit'] = True
metadata = {}
if opts.get('note'):
- metadata['note'] = opts['note']
+ metadata[b'note'] = opts['note']
updates = allctx[:]
if p2 is not None and root.p2() != p2:
@@ -803,13 +803,13 @@
commitopts=commitopts)
phases.retractboundary(repo, tr, targetphase, [newid])
replacements = {ctx.node(): [newid] for ctx in allctx}
- scmutil.cleanupnodes(repo, replacements, operation="fold",
+ scmutil.cleanupnodes(repo, replacements, operation=b"fold",
metadata=metadata)
tr.close()
finally:
tr.release()
- ui.status('%i changesets folded\n' % len(revs))
- if repo['.'].rev() in revs:
+ ui.status(b'%i changesets folded\n' % len(revs))
+ if repo[b'.'].rev() in revs:
hg.update(repo, newid)
finally:
lockmod.release(lock, wlock)
@@ -856,8 +856,8 @@
revs.extend(opts['rev'])
if not revs:
if opts['fold']:
- raise error.Abort(_('revisions must be specified with --fold'))
- revs = ['.']
+ raise error.Abort(_(b'revisions must be specified with --fold'))
+ revs = [b'.']
with repo.wlock(), repo.lock():
revs = scmutil.revrange(repo, revs)
@@ -870,21 +870,21 @@
# we need to rewrite a first, then directly rewrite b on top of the
# new a, then rewrite c on top of the new b. So we need to handle
# revisions in topological order.
- raise error.Abort(_('editing multiple revisions without --fold is '
- 'not currently supported'))
+ raise error.Abort(_(b'editing multiple revisions without --fold is '
+ b'not currently supported'))
if opts['fold']:
root, head, p2 = rewriteutil.foldcheck(repo, revs)
else:
- if repo.revs("%ld and public()", revs):
- raise error.Abort(_('cannot edit commit information for public '
- 'revisions'))
+ if repo.revs(b"%ld and public()", revs):
+ raise error.Abort(_(b'cannot edit commit information for public '
+ b'revisions'))
newunstable = rewriteutil.disallowednewunstable(repo, revs)
if newunstable:
- msg = _('cannot edit commit information in the middle'
- ' of a stack')
- hint = _('%s will become unstable and new unstable changes'
- ' are not allowed')
+ msg = _(b'cannot edit commit information in the middle'
+ b' of a stack')
+ hint = _(b'%s will become unstable and new unstable changes'
+ b' are not allowed')
hint %= repo[newunstable.first()]
raise error.Abort(msg, hint=hint)
root = head = repo[revs.first()]
@@ -892,7 +892,7 @@
wctx = repo[None]
p1 = wctx.p1()
- tr = repo.transaction('metaedit')
+ tr = repo.transaction(b'metaedit')
newp1 = None
try:
commitopts = opts.copy()
@@ -903,12 +903,12 @@
commitopts['edit'] = False
else:
if opts['fold']:
- msgs = ["HG: This is a fold of %d changesets." % len(allctx)]
- msgs += ["HG: Commit message of changeset %d.\n\n%s\n" %
+ msgs = [b"HG: This is a fold of %d changesets." % len(allctx)]
+ msgs += [b"HG: Commit message of changeset %d.\n\n%s\n" %
(c.rev(), c.description()) for c in allctx]
else:
msgs = [head.description()]
- commitopts['message'] = "\n".join(msgs)
+ commitopts['message'] = b"\n".join(msgs)
commitopts['edit'] = True
updates = allctx[:]
@@ -928,20 +928,20 @@
# metadata to be stored on obsmarker
metadata = {}
if opts.get('note'):
- metadata['note'] = opts['note']
+ metadata[b'note'] = opts['note']
phases.retractboundary(repo, tr, targetphase, [newid])
obsolete.createmarkers(repo, [(ctx, (repo[newid],))
for ctx in allctx],
- metadata=metadata, operation="metaedit")
+ metadata=metadata, operation=b"metaedit")
else:
- ui.status(_("nothing changed\n"))
+ ui.status(_(b"nothing changed\n"))
tr.close()
finally:
tr.release()
if opts['fold']:
- ui.status('%i changesets folded\n' % len(revs))
+ ui.status(b'%i changesets folded\n' % len(revs))
if newp1 is not None:
hg.update(repo, newp1)
@@ -957,9 +957,9 @@
date = opts.get('date')
user = opts.get('user')
if date:
- metadata['date'] = '%i %i' % compat.parsedate(date)
+ metadata[b'date'] = b'%i %i' % compat.parsedate(date)
if user:
- metadata['user'] = user
+ metadata[b'user'] = user
return metadata
@eh.command(
@@ -1005,6 +1005,12 @@
``--pair`` option to pair the pruned precursor and successor changesets.
This is commonly useful for resolving history divergence, or when someone
else edits history without obsolescence enabled.
+
+ .. container:: verbose
+
+ ``hg prune A::B -s C::D --pair`` will mark all revisions in the A::B
+ range as superseded by the revisions in C::D. Both revsets need to have
+ the same number of changesets.
"""
_checknotesize(ui, opts)
revs = scmutil.revrange(repo, list(revs) + opts.get('rev'))
@@ -1015,10 +1021,10 @@
fold = opts.get('fold')
split = opts.get('split')
- options = [o for o in ('pair', 'fold', 'split') if opts.get(o)]
+ options = [o for o in (r'pair', r'fold', r'split') if opts.get(o)]
if 1 < len(options):
- _opts = pycompat.sysbytes(', '.join(options))
- raise error.Abort(_("can only specify one of %s") % _opts)
+ _opts = pycompat.sysbytes(r', '.join(options))
+ raise error.Abort(_(b"can only specify one of %s") % _opts)
if bookmarks:
reachablefrombookmark = rewriteutil.reachablefrombookmark
@@ -1028,14 +1034,14 @@
rewriteutil.deletebookmark(repo, repomarks, bookmarks)
if not revs:
- raise error.Abort(_('nothing to prune'))
+ raise error.Abort(_(b'no revisions specified to prune'))
wlock = lock = tr = None
try:
wlock = repo.wlock()
lock = repo.lock()
- rewriteutil.precheck(repo, revs, 'prune')
- tr = repo.transaction('prune')
+ rewriteutil.precheck(repo, revs, b'prune')
+ tr = repo.transaction(b'prune')
# defines pruned changesets
precs = []
revs.sort()
@@ -1043,33 +1049,33 @@
cp = repo[p]
precs.append(cp)
if not precs:
- raise error.Abort('nothing to prune')
+ raise error.Abort(b'nothing to prune')
# defines successors changesets
sucs = scmutil.revrange(repo, succs)
sucs.sort()
sucs = tuple(repo[n] for n in sucs)
if not biject and len(sucs) > 1 and len(precs) > 1:
- msg = "Can't use multiple successors for multiple precursors"
- hint = _("use --pair to mark a series as a replacement"
- " for another")
+ msg = b"Can't use multiple successors for multiple precursors"
+ hint = _(b"use --pair to mark a series as a replacement"
+ b" for another")
raise error.Abort(msg, hint=hint)
elif biject and len(sucs) != len(precs):
- msg = "Can't use %d successors for %d precursors" \
+ msg = b"Can't use %d successors for %d precursors"\
% (len(sucs), len(precs))
raise error.Abort(msg)
elif (len(precs) == 1 and len(sucs) > 1) and not split:
- msg = "please add --split if you want to do a split"
+ msg = b"please add --split if you want to do a split"
raise error.Abort(msg)
elif len(sucs) == 1 and len(precs) > 1 and not fold:
- msg = "please add --fold if you want to do a fold"
+ msg = b"please add --fold if you want to do a fold"
raise error.Abort(msg)
elif biject:
replacements = {p.node(): [s.node()] for p, s in zip(precs, sucs)}
else:
replacements = {p.node(): [s.node() for s in sucs] for p in precs}
- wdp = repo['.']
+ wdp = repo[b'.']
if wdp in precs:
if len(sucs) == 1 and len(precs) == 1:
@@ -1097,7 +1103,7 @@
# only reset the dirstate for files that would actually change
# between the working context and uctx
- descendantrevs = repo.revs("%d::." % newnode.rev())
+ descendantrevs = repo.revs(b"%d::." % newnode.rev())
changedfiles = []
for rev in descendantrevs:
# blindly reset the files, regardless of what actually
@@ -1106,7 +1112,7 @@
# reset files that only changed in the dirstate too
dirstate = repo.dirstate
- dirchanges = [f for f in dirstate if dirstate[f] != 'n']
+ dirchanges = [f for f in dirstate if dirstate[f] != b'n']
changedfiles.extend(dirchanges)
repo.dirstate.rebuild(newnode.node(), newnode.manifest(),
changedfiles)
@@ -1122,8 +1128,8 @@
bmchanges = [(bookactive, newnode.node())]
repo._bookmarks.applychanges(repo, tr, bmchanges)
commands.update(ui, repo, newnode.hex())
- ui.status(_('working directory is now at %s\n')
- % ui.label(bytes(newnode), 'evolve.node'))
+ ui.status(_(b'working directory is now at %s\n')
+ % ui.label(bytes(newnode), b'evolve.node'))
if movebookmark:
bookmarksmod.activate(repo, bookactive)
@@ -1133,11 +1139,11 @@
# store note in metadata
if opts.get('note'):
- metadata['note'] = opts['note']
+ metadata[b'note'] = opts['note']
precrevs = (precursor.rev() for precursor in precs)
moves = {}
- for ctx in repo.unfiltered().set('bookmark() and %ld', precrevs):
+ for ctx in repo.unfiltered().set(b'bookmark() and %ld', precrevs):
# used to be:
#
# ldest = list(repo.set('max((::%d) - obsolete())', ctx))
@@ -1150,11 +1156,11 @@
if not dest.obsolete() and dest.node() not in replacements:
moves[ctx.node()] = dest.node()
break
- scmutil.cleanupnodes(repo, replacements, operation="prune", moves=moves,
+ scmutil.cleanupnodes(repo, replacements, operation=b"prune", moves=moves,
metadata=metadata)
# informs that changeset have been pruned
- ui.status(_('%i changesets pruned\n') % len(precs))
+ ui.status(_(b'%i changesets pruned\n') % len(precs))
tr.close()
finally:
@@ -1188,13 +1194,13 @@
revs = opts.get('rev')
if not revs:
- revarg = '.'
+ revarg = b'.'
elif len(revs) == 1:
revarg = revs[0]
else:
# XXX --rev often accept multiple value, it seems safer to explicitly
# complains here instead of just taking the last value.
- raise error.Abort(_('more than one revset is given'))
+ raise error.Abort(_(b'more than one revset is given'))
# Save the current branch to restore it in the end
savedbranch = repo.dirstate.branch()
@@ -1205,18 +1211,18 @@
ctx = scmutil.revsingle(repo, revarg)
rev = ctx.rev()
cmdutil.bailifchanged(repo)
- rewriteutil.precheck(repo, [rev], action='split')
- tr = repo.transaction('split')
+ rewriteutil.precheck(repo, [rev], action=b'split')
+ tr = repo.transaction(b'split')
# make sure we respect the phase while splitting
- overrides = {('phases', 'new-commit'): ctx.phase()}
+ overrides = {(b'phases', b'new-commit'): ctx.phase()}
if len(ctx.parents()) > 1:
- raise error.Abort(_("cannot split merge commits"))
+ raise error.Abort(_(b"cannot split merge commits"))
prev = ctx.p1()
bmupdate = rewriteutil.bookmarksupdater(repo, ctx.node(), tr)
bookactive = repo._activebookmark
if bookactive is not None:
- repo.ui.status(_("(leaving bookmark %s)\n") % repo._activebookmark)
+ repo.ui.status(_(b"(leaving bookmark %s)\n") % repo._activebookmark)
bookmarksmod.deactivate(repo)
# Prepare the working directory
@@ -1225,8 +1231,8 @@
def haschanges(matcher=None):
modified, added, removed, deleted = repo.status(match=matcher)[:4]
return modified or added or removed or deleted
- msg = ("HG: This is the original pre-split commit message. "
- "Edit it as appropriate.\n\n")
+ msg = (b"HG: This is the original pre-split commit message. "
+ b"Edit it as appropriate.\n\n")
msg += ctx.description()
opts['message'] = msg
opts['edit'] = True
@@ -1247,21 +1253,21 @@
if haschanges(matcher):
if iselect:
- with repo.ui.configoverride(overrides, 'split'):
- cmdutil.dorecord(ui, repo, commands.commit, 'commit',
+ with repo.ui.configoverride(overrides, b'split'):
+ cmdutil.dorecord(ui, repo, commands.commit, b'commit',
False, cmdutil.recordfilter, *pats,
**opts)
# TODO: Does no seem like the best way to do this
# We should make dorecord return the newly created commit
- newcommits.append(repo['.'])
+ newcommits.append(repo[b'.'])
elif not pats:
- msg = _("no files of directories specified")
- hint = _("do you want --interactive")
+ msg = _(b"no files of directories specified")
+ hint = _(b"do you want --interactive")
raise error.Abort(msg, hint=hint)
else:
- with repo.ui.configoverride(overrides, 'split'):
+ with repo.ui.configoverride(overrides, b'split'):
commands.commit(ui, repo, *pats, **opts)
- newcommits.append(repo['.'])
+ newcommits.append(repo[b'.'])
if pats:
# refresh the wctx used for the matcher
matcher = scmutil.match(repo[None], pats)
@@ -1271,20 +1277,20 @@
if haschanges(matcher):
nextaction = None
while nextaction is None:
- nextaction = ui.prompt('continue splitting? [Ycdq?]', default='y')
- if nextaction == 'c':
- with repo.ui.configoverride(overrides, 'split'):
+ nextaction = ui.prompt(b'continue splitting? [Ycdq?]', default=b'y')
+ if nextaction == b'c':
+ with repo.ui.configoverride(overrides, b'split'):
commands.commit(ui, repo, **opts)
- newcommits.append(repo['.'])
+ newcommits.append(repo[b'.'])
break
- elif nextaction == 'q':
- raise error.Abort(_('user quit'))
- elif nextaction == 'd':
+ elif nextaction == b'q':
+ raise error.Abort(_(b'user quit'))
+ elif nextaction == b'd':
# TODO: We should offer a way for the user to confirm
# what is the remaining changes, either via a separate
# diff action or by showing the remaining and
# prompting for confirmation
- ui.status(_('discarding remaining changes\n'))
+ ui.status(_(b'discarding remaining changes\n'))
target = newcommits[0]
if pats:
status = repo.status(match=matcher)[:4]
@@ -1297,24 +1303,24 @@
else:
cmdutil.revert(ui, repo, repo[target],
(target, node.nullid), all=True)
- elif nextaction == '?':
+ elif nextaction == b'?':
nextaction = None
- ui.write(_("y - yes, continue selection\n"))
- ui.write(_("c - commit, select all remaining changes\n"))
- ui.write(_("d - discard, discard remaining changes\n"))
- ui.write(_("q - quit, abort the split\n"))
- ui.write(_("? - ?, display help\n"))
+ ui.write(_(b"y - yes, continue selection\n"))
+ ui.write(_(b"c - commit, select all remaining changes\n"))
+ ui.write(_(b"d - discard, discard remaining changes\n"))
+ ui.write(_(b"q - quit, abort the split\n"))
+ ui.write(_(b"? - ?, display help\n"))
else:
continue
break # propagate the previous break
else:
- ui.status(_("no more change to split\n"))
+ ui.status(_(b"no more change to split\n"))
if haschanges():
# XXX: Should we show a message for informing the user
# that we create another commit with remaining changes?
- with repo.ui.configoverride(overrides, 'split'):
+ with repo.ui.configoverride(overrides, b'split'):
commands.commit(ui, repo, **opts)
- newcommits.append(repo['.'])
+ newcommits.append(repo[b'.'])
if newcommits:
tip = repo[newcommits[-1]]
bmupdate(tip.node())
@@ -1322,9 +1328,9 @@
bookmarksmod.activate(repo, bookactive)
metadata = {}
if opts.get('note'):
- metadata['note'] = opts['note']
+ metadata[b'note'] = opts['note']
obsolete.createmarkers(repo, [(repo[rev], newcommits)],
- metadata=metadata, operation="split")
+ metadata=metadata, operation=b"split")
tr.close()
finally:
# Restore the old branch
@@ -1342,7 +1348,7 @@
b'mark the new revision as successor of the old one potentially creating '
b'divergence')],
# allow to choose the seed ?
- _('[-r] revs'))
+ _(b'[-r] revs'))
def touch(ui, repo, *revs, **opts):
"""create successors identical to their predecessors but the changeset ID
@@ -1352,18 +1358,18 @@
revs = list(revs)
revs.extend(opts['rev'])
if not revs:
- revs = ['.']
+ revs = [b'.']
revs = scmutil.revrange(repo, revs)
if not revs:
- ui.write_err('no revision to touch\n')
+ ui.write_err(b'no revision to touch\n')
return 1
duplicate = opts['duplicate']
if not duplicate:
- rewriteutil.precheck(repo, revs, 'touch')
+ rewriteutil.precheck(repo, revs, b'touch')
tmpl = utility.shorttemplate
- displayer = compat.changesetdisplayer(ui, repo, {'template': tmpl})
- with repo.wlock(), repo.lock(), repo.transaction('touch'):
+ displayer = compat.changesetdisplayer(ui, repo, {b'template': tmpl})
+ with repo.wlock(), repo.lock(), repo.transaction(b'touch'):
touchnodes(ui, repo, revs, displayer, **opts)
def touchnodes(ui, repo, revs, displayer, **opts):
@@ -1374,7 +1380,7 @@
for r in revs:
ctx = repo[r]
extra = ctx.extra().copy()
- extra['__touch-noise__'] = random.randint(0, 0xffffffff)
+ extra[b'__touch-noise__'] = random.randint(0, 0xffffffff)
# search for touched parent
p1 = ctx.p1().node()
p2 = ctx.p2().node()
@@ -1405,12 +1411,12 @@
else:
displayer.show(ctx)
index = ui.promptchoice(
- _("reviving this changeset will create divergence"
- " unless you make a duplicate.\n(a)llow divergence or"
- " (d)uplicate the changeset? $$ &Allowdivergence $$ "
- "&Duplicate"), 0)
- choice = ['allowdivergence', 'duplicate'][index]
- if choice == 'allowdivergence':
+ _(b"reviving this changeset will create divergence"
+ b" unless you make a duplicate.\n(a)llow divergence or"
+ b" (d)uplicate the changeset? $$ &Allowdivergence $$ "
+ b"&Duplicate"), 0)
+ choice = [b'allowdivergence', b'duplicate'][index]
+ if choice == b'allowdivergence':
duplicate = False
else:
duplicate = True
@@ -1418,7 +1424,7 @@
updates = []
if len(ctx.parents()) > 1:
updates = ctx.parents()
- extradict = {'extra': extra}
+ extradict = {b'extra': extra}
new, unusedvariable = rewriteutil.rewrite(repo, ctx, updates, ctx,
[p1, p2],
commitopts=extradict)
@@ -1428,9 +1434,9 @@
if not duplicate:
metadata = {}
if opts.get('note'):
- metadata['note'] = opts['note']
+ metadata[b'note'] = opts['note']
obsolete.createmarkers(repo, [(ctx, (repo[new],))],
- metadata=metadata, operation="touch")
+ metadata=metadata, operation=b"touch")
tr = repo.currenttransaction()
phases.retractboundary(repo, tr, ctx.phase(), [new])
if ctx in repo[None].parents():
@@ -1442,7 +1448,7 @@
[(b'r', b'rev', b'', _(b'revision to pick'), _(b'REV')),
(b'c', b'continue', False, b'continue interrupted pick'),
(b'a', b'abort', False, b'abort interrupted pick'),
- ] + mergetoolopts,
+ ] + mergetoolopts,
_(b'[-r] rev'))
def cmdpick(ui, repo, *revs, **opts):
"""move a commit on the top of working directory parent and updates to it."""
@@ -1451,69 +1457,61 @@
abort = opts.get('abort')
if cont and abort:
- raise error.Abort(_("cannot specify both --continue and --abort"))
+ raise error.Abort(_(b"cannot specify both --continue and --abort"))
revs = list(revs)
if opts.get('rev'):
revs.append(opts['rev'])
with repo.wlock(), repo.lock():
- pickstate = state.cmdstate(repo, path='pickstate')
- pctx = repo['.']
+ pickstate = state.cmdstate(repo, path=b'pickstate')
+ pctx = repo[b'.']
if not cont and not abort:
cmdutil.bailifchanged(repo)
revs = scmutil.revrange(repo, revs)
if len(revs) > 1:
- raise error.Abort(_("specify just one revision"))
+ raise error.Abort(_(b"specify just one revision"))
elif not revs:
- raise error.Abort(_("empty revision set"))
+ raise error.Abort(_(b"empty revision set"))
origctx = repo[revs.first()]
if origctx in pctx.ancestors() or origctx.node() == pctx.node():
- raise error.Abort(_("cannot pick an ancestor revision"))
+ raise error.Abort(_(b"cannot pick an ancestor revision"))
- rewriteutil.precheck(repo, [origctx.rev()], 'pick')
+ rewriteutil.precheck(repo, [origctx.rev()], b'pick')
- ui.status(_('picking %d:%s "%s"\n') %
+ ui.status(_(b'picking %d:%s "%s"\n') %
(origctx.rev(), origctx,
- origctx.description().split("\n", 1)[0]))
- overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
- with ui.configoverride(overrides, 'pick'):
+ origctx.description().split(b"\n", 1)[0]))
+ overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
+ with ui.configoverride(overrides, b'pick'):
stats = merge.graft(repo, origctx, origctx.p1(),
- ['local', 'destination'])
+ [b'local', b'destination'])
if compat.hasconflict(stats):
- pickstate.addopts({'orignode': origctx.node(),
- 'oldpctx': pctx.node()})
+ pickstate.addopts({b'orignode': origctx.node(),
+ b'oldpctx': pctx.node()})
pickstate.save()
- raise error.InterventionRequired(_("unresolved merge conflicts"
- " (see hg help resolve)"))
+ raise error.InterventionRequired(_(b"unresolved merge conflicts"
+ b" (see hg help resolve)"))
elif abort:
- if not pickstate:
- raise error.Abort(_("no interrupted pick state exists"))
- pickstate.load()
- pctxnode = pickstate['oldpctx']
- ui.status(_("aborting pick, updating to %s\n") %
- node.hex(pctxnode)[:12])
- hg.updaterepo(repo, pctxnode, True)
- pickstate.delete()
- return 0
+ return abortpick(ui, repo, pickstate)
else:
if revs:
- raise error.Abort(_("cannot specify both --continue and "
- "revision"))
+ raise error.Abort(_(b"cannot specify both --continue and "
+ b"revision"))
if not pickstate:
- raise error.Abort(_("no interrupted pick state exists"))
+ raise error.Abort(_(b"no interrupted pick state exists"))
pickstate.load()
- orignode = pickstate['orignode']
+ orignode = pickstate[b'orignode']
origctx = repo[orignode]
- overrides = {('phases', 'new-commit'): origctx.phase()}
- with repo.ui.configoverride(overrides, 'pick'):
+ overrides = {(b'phases', b'new-commit'): origctx.phase()}
+ with repo.ui.configoverride(overrides, b'pick'):
newnode = repo.commit(text=origctx.description(),
user=origctx.user(),
date=origctx.date(), extra=origctx.extra())
@@ -1523,11 +1521,29 @@
pickstate.delete()
newctx = repo[newnode] if newnode else pctx
replacements = {origctx.node(): [newctx.node()]}
- scmutil.cleanupnodes(repo, replacements, operation="pick")
+ scmutil.cleanupnodes(repo, replacements, operation=b"pick")
if newnode is None:
- ui.warn(_("note: picking %d:%s created no changes to commit\n") %
+ ui.warn(_(b"note: picking %d:%s created no changes to commit\n") %
(origctx.rev(), origctx))
return 0
return 0
+
+def abortpick(ui, repo, pickstate, abortcmd=False):
+ """logic to abort pick"""
+ if not pickstate and not abortcmd:
+ raise error.Abort(_(b"no interrupted pick state exists"))
+ pickstate.load()
+ pctxnode = pickstate[b'oldpctx']
+ ui.status(_(b"aborting pick, updating to %s\n") %
+ node.hex(pctxnode)[:12])
+ hg.updaterepo(repo, pctxnode, True)
+ pickstate.delete()
+ return 0
+
+def hgabortpick(ui, repo):
+ """logic to abort pick using 'hg abort'"""
+ with repo.wlock(), repo.lock():
+ pickstate = state.cmdstate(repo, path=b'pickstate')
+ return abortpick(ui, repo, pickstate, abortcmd=True)
--- a/hgext3rd/evolve/compat.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/compat.py Fri Sep 27 13:03:14 2019 +0200
@@ -62,24 +62,24 @@
# Evolution renaming compat
TROUBLES = {
- 'ORPHAN': 'orphan',
- 'CONTENTDIVERGENT': 'content-divergent',
- 'PHASEDIVERGENT': 'phase-divergent',
+ r'ORPHAN': b'orphan',
+ r'CONTENTDIVERGENT': b'content-divergent',
+ r'PHASEDIVERGENT': b'phase-divergent',
}
if util.safehasattr(uimod.ui, 'makeprogress'):
- def progress(ui, topic, pos, item="", unit="", total=None):
+ def progress(ui, topic, pos, item=b"", unit=b"", total=None):
progress = ui.makeprogress(topic, unit, total)
if pos is not None:
progress.update(pos, item=item)
else:
progress.complete()
else:
- def progress(ui, topic, pos, item="", unit="", total=None):
+ def progress(ui, topic, pos, item=b"", unit=b"", total=None):
ui.progress(topic, pos, item, unit, total)
# XXX: Better detection of property cache
-if 'predecessors' not in dir(obsolete.obsstore):
+if r'predecessors' not in dir(obsolete.obsstore):
@property
def predecessors(self):
return self.precursors
@@ -90,36 +90,36 @@
# XXX Would it be better at the module level?
varnames = context.memfilectx.__init__.__code__.co_varnames
- if "copysource" in varnames:
+ if r"copysource" in varnames:
mctx = context.memfilectx(repo, ctx, fctx.path(), fctx.data(),
- islink='l' in flags,
- isexec='x' in flags,
+ islink=b'l' in flags,
+ isexec=b'x' in flags,
copysource=copied.get(path))
# compat with hg <- 4.9
- elif varnames[2] == "changectx":
+ elif varnames[2] == r"changectx":
mctx = context.memfilectx(repo, ctx, fctx.path(), fctx.data(),
- islink='l' in flags,
- isexec='x' in flags,
+ islink=b'l' in flags,
+ isexec=b'x' in flags,
copied=copied.get(path))
else:
mctx = context.memfilectx(repo, fctx.path(), fctx.data(),
- islink='l' in flags,
- isexec='x' in flags,
+ islink=b'l' in flags,
+ isexec=b'x' in flags,
copied=copied.get(path))
return mctx
def strdiff(a, b, fn1, fn2):
""" A version of mdiff.unidiff for comparing two strings
"""
- args = [a, '', b, '', fn1, fn2]
+ args = [a, b'', b, b'', fn1, fn2]
# hg < 4.6 compat 8b6dd3922f70
if util.safehasattr(inspect, 'signature'):
signature = inspect.signature(mdiff.unidiff)
- needsbinary = 'binary' in signature.parameters
+ needsbinary = r'binary' in signature.parameters
else:
argspec = inspect.getargspec(mdiff.unidiff)
- needsbinary = 'binary' in argspec.args
+ needsbinary = r'binary' in argspec.args
if needsbinary:
args.append(False)
@@ -218,7 +218,7 @@
if limit is None:
# no common ancestor, no copies
return {}, {}, {}, {}, {}
- repo.ui.debug(" searching for copies back to rev %d\n" % limit)
+ repo.ui.debug(b" searching for copies back to rev %d\n" % limit)
m1 = c1.manifest()
m2 = c2.manifest()
@@ -232,18 +232,18 @@
# - incompletediverge = record divergent partial copies here
diverge = {} # divergence data is shared
incompletediverge = {}
- data1 = {'copy': {},
- 'fullcopy': {},
- 'incomplete': {},
- 'diverge': diverge,
- 'incompletediverge': incompletediverge,
- }
- data2 = {'copy': {},
- 'fullcopy': {},
- 'incomplete': {},
- 'diverge': diverge,
- 'incompletediverge': incompletediverge,
- }
+ data1 = {b'copy': {},
+ b'fullcopy': {},
+ b'incomplete': {},
+ b'diverge': diverge,
+ b'incompletediverge': incompletediverge,
+ }
+ data2 = {b'copy': {},
+ b'fullcopy': {},
+ b'incomplete': {},
+ b'diverge': diverge,
+ b'incompletediverge': incompletediverge,
+ }
# find interesting file sets from manifests
if hg48:
@@ -260,20 +260,20 @@
else:
# unmatched file from base (DAG rotation in the graft case)
u1r, u2r = copies._computenonoverlap(repo, c1, c2, addedinm1, addedinm2,
- baselabel='base')
+ baselabel=b'base')
# unmatched file from topological common ancestors (no DAG rotation)
# need to recompute this for directory move handling when grafting
mta = tca.manifest()
if hg48:
m1f = m1.filesnotin(mta, repo.narrowmatch())
m2f = m2.filesnotin(mta, repo.narrowmatch())
- baselabel = 'topological common ancestor'
+ baselabel = b'topological common ancestor'
u1u, u2u = copies._computenonoverlap(repo, c1, c2, m1f, m2f,
baselabel=baselabel)
else:
u1u, u2u = copies._computenonoverlap(repo, c1, c2, m1.filesnotin(mta),
m2.filesnotin(mta),
- baselabel='topological common ancestor')
+ baselabel=b'topological common ancestor')
for f in u1u:
copies._checkcopies(c1, c2, f, base, tca, dirtyc1, limit, data1)
@@ -281,16 +281,16 @@
for f in u2u:
copies._checkcopies(c2, c1, f, base, tca, dirtyc2, limit, data2)
- copy = dict(data1['copy'])
- copy.update(data2['copy'])
- fullcopy = dict(data1['fullcopy'])
- fullcopy.update(data2['fullcopy'])
+ copy = dict(data1[b'copy'])
+ copy.update(data2[b'copy'])
+ fullcopy = dict(data1[b'fullcopy'])
+ fullcopy.update(data2[b'fullcopy'])
if dirtyc1:
- copies._combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
+ copies._combinecopies(data2[b'incomplete'], data1[b'incomplete'], copy, diverge,
incompletediverge)
else:
- copies._combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
+ copies._combinecopies(data1[b'incomplete'], data2[b'incomplete'], copy, diverge,
incompletediverge)
renamedelete = {}
@@ -308,23 +308,23 @@
divergeset.update(fl) # reverse map for below
if bothnew:
- repo.ui.debug(" unmatched files new in both:\n %s\n"
- % "\n ".join(bothnew))
+ repo.ui.debug(b" unmatched files new in both:\n %s\n"
+ % b"\n ".join(bothnew))
bothdiverge = {}
bothincompletediverge = {}
remainder = {}
- both1 = {'copy': {},
- 'fullcopy': {},
- 'incomplete': {},
- 'diverge': bothdiverge,
- 'incompletediverge': bothincompletediverge
- }
- both2 = {'copy': {},
- 'fullcopy': {},
- 'incomplete': {},
- 'diverge': bothdiverge,
- 'incompletediverge': bothincompletediverge
- }
+ both1 = {b'copy': {},
+ b'fullcopy': {},
+ b'incomplete': {},
+ b'diverge': bothdiverge,
+ b'incompletediverge': bothincompletediverge
+ }
+ both2 = {b'copy': {},
+ b'fullcopy': {},
+ b'incomplete': {},
+ b'diverge': bothdiverge,
+ b'incompletediverge': bothincompletediverge
+ }
for f in bothnew:
copies._checkcopies(c1, c2, f, base, tca, dirtyc1, limit, both1)
copies._checkcopies(c2, c1, f, base, tca, dirtyc2, limit, both2)
@@ -333,17 +333,17 @@
pass
elif dirtyc1:
# incomplete copies may only be found on the "dirty" side for bothnew
- assert not both2['incomplete']
- remainder = copies._combinecopies({}, both1['incomplete'], copy, bothdiverge,
+ assert not both2[b'incomplete']
+ remainder = copies._combinecopies({}, both1[b'incomplete'], copy, bothdiverge,
bothincompletediverge)
elif dirtyc2:
- assert not both1['incomplete']
- remainder = copies._combinecopies({}, both2['incomplete'], copy, bothdiverge,
+ assert not both1[b'incomplete']
+ remainder = copies._combinecopies({}, both2[b'incomplete'], copy, bothdiverge,
bothincompletediverge)
else:
# incomplete copies and divergences can't happen outside grafts
- assert not both1['incomplete']
- assert not both2['incomplete']
+ assert not both1[b'incomplete']
+ assert not both2[b'incomplete']
assert not bothincompletediverge
for f in remainder:
assert f not in bothdiverge
@@ -356,30 +356,30 @@
copy[fl[0]] = of # not actually divergent, just matching renames
if fullcopy and repo.ui.debugflag:
- repo.ui.debug(" all copies found (* = to merge, ! = divergent, "
- "% = renamed and deleted):\n")
+ repo.ui.debug(b" all copies found (* = to merge, ! = divergent, "
+ b"% = renamed and deleted):\n")
for f in sorted(fullcopy):
- note = ""
+ note = b""
if f in copy:
- note += "*"
+ note += b"*"
if f in divergeset:
- note += "!"
+ note += b"!"
if f in renamedeleteset:
- note += "%"
- repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
- note))
+ note += b"%"
+ repo.ui.debug(b" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
+ note))
del divergeset
if not fullcopy:
return copy, {}, diverge, renamedelete, {}
- repo.ui.debug(" checking for directory renames\n")
+ repo.ui.debug(b" checking for directory renames\n")
# generate a directory move map
d1, d2 = c1.dirs(), c2.dirs()
# Hack for adding '', which is not otherwise added, to d1 and d2
- d1.addpath('/')
- d2.addpath('/')
+ d1.addpath(b'/')
+ d2.addpath(b'/')
invalid = set()
dirmove = {}
@@ -392,16 +392,16 @@
continue
elif dsrc in d1 and ddst in d1:
# directory wasn't entirely moved locally
- invalid.add(dsrc + "/")
+ invalid.add(dsrc + b"/")
elif dsrc in d2 and ddst in d2:
# directory wasn't entirely moved remotely
- invalid.add(dsrc + "/")
- elif dsrc + "/" in dirmove and dirmove[dsrc + "/"] != ddst + "/":
+ invalid.add(dsrc + b"/")
+ elif dsrc + b"/" in dirmove and dirmove[dsrc + b"/"] != ddst + b"/":
# files from the same directory moved to two different places
- invalid.add(dsrc + "/")
+ invalid.add(dsrc + b"/")
else:
# looks good so far
- dirmove[dsrc + "/"] = ddst + "/"
+ dirmove[dsrc + b"/"] = ddst + b"/"
for i in invalid:
if i in dirmove:
@@ -412,7 +412,7 @@
return copy, {}, diverge, renamedelete, {}
for d in dirmove:
- repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
+ repo.ui.debug(b" discovered dir src: '%s' -> dst: '%s'\n" %
(d, dirmove[d]))
movewithdir = {}
@@ -425,8 +425,8 @@
df = dirmove[d] + f[len(d):]
if df not in copy:
movewithdir[f] = df
- repo.ui.debug((" pending file src: '%s' -> "
- "dst: '%s'\n") % (f, df))
+ repo.ui.debug((b" pending file src: '%s' -> "
+ b"dst: '%s'\n") % (f, df))
break
return copy, movewithdir, diverge, renamedelete, dirmove
@@ -494,8 +494,8 @@
return obsutil.markersusers(markers)
markersmeta = [dict(m[3]) for m in markers]
- users = set(encoding.tolocal(meta['user']) for meta in markersmeta
- if meta.get('user'))
+ users = set(encoding.tolocal(meta[b'user']) for meta in markersmeta
+ if meta.get(b'user'))
return sorted(users)
@@ -511,7 +511,7 @@
return obsutil.markersoperations(markers)
markersmeta = [dict(m[3]) for m in markers]
- operations = set(meta.get('operation') for meta in markersmeta
- if meta.get('operation'))
+ operations = set(meta.get(b'operation') for meta in markersmeta
+ if meta.get(b'operation'))
return sorted(operations)
--- a/hgext3rd/evolve/dagutil.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/dagutil.py Fri Sep 27 13:03:14 2019 +0200
@@ -140,7 +140,7 @@
def _internalize(self, id):
ix = self._revlog.rev(id)
if ix == nullrev:
- raise LookupError(id, self._revlog.indexfile, _('nullid'))
+ raise LookupError(id, self._revlog.indexfile, _(b'nullid'))
return ix
def _internalizeall(self, ids, filterunknown):
--- a/hgext3rd/evolve/debugcmd.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/debugcmd.py Fri Sep 27 13:03:14 2019 +0200
@@ -45,7 +45,7 @@
unfi = repo.unfiltered()
nm = unfi.changelog.nodemap
nbmarkers = len(store._all)
- ui.write(_('markers total: %9i\n') % nbmarkers)
+ ui.write(_(b'markers total: %9i\n') % nbmarkers)
sucscount = [0, 0, 0, 0]
known = 0
parentsdata = 0
@@ -67,7 +67,7 @@
metakeys.setdefault(key, 0)
metakeys[key] += 1
meta = dict(meta)
- parents = [meta.get('p1'), meta.get('p2')]
+ parents = [meta.get(b'p1'), meta.get(b'p2')]
parents = [node.bin(p) for p in parents if p is not None]
if parents:
parentsdata += 1
@@ -91,71 +91,71 @@
fc = (frozenset(c[0]), frozenset(c[1]))
for n in fc[0]:
pclustersmap[n] = fc
- numobs = len(unfi.revs('obsolete()'))
+ numobs = len(unfi.revs(b'obsolete()'))
numtotal = len(unfi)
- ui.write((' for known precursors: %9i' % known))
- ui.write((' (%i/%i obsolete changesets)\n' % (numobs, numtotal)))
- ui.write((' with parents data: %9i\n' % parentsdata))
+ ui.write((b' for known precursors: %9i' % known))
+ ui.write((b' (%i/%i obsolete changesets)\n' % (numobs, numtotal)))
+ ui.write((b' with parents data: %9i\n' % parentsdata))
# successors data
- ui.write(('markers with no successors: %9i\n' % sucscount[0]))
- ui.write((' 1 successors: %9i\n' % sucscount[1]))
- ui.write((' 2 successors: %9i\n' % sucscount[2]))
- ui.write((' more than 2 successors: %9i\n' % sucscount[3]))
+ ui.write((b'markers with no successors: %9i\n' % sucscount[0]))
+ ui.write((b' 1 successors: %9i\n' % sucscount[1]))
+ ui.write((b' 2 successors: %9i\n' % sucscount[2]))
+ ui.write((b' more than 2 successors: %9i\n' % sucscount[3]))
# meta data info
- ui.write((' available keys:\n'))
+ ui.write((b' available keys:\n'))
for key in sorted(metakeys):
- ui.write((' %15s: %9i\n' % (key, metakeys[key])))
+ ui.write((b' %15s: %9i\n' % (key, metakeys[key])))
size_v0.sort()
size_v1.sort()
if size_v0:
- ui.write('marker size:\n')
+ ui.write(b'marker size:\n')
# format v1
- ui.write(' format v1:\n')
- ui.write((' smallest length: %9i\n' % size_v1[0]))
- ui.write((' longer length: %9i\n' % size_v1[-1]))
+ ui.write(b' format v1:\n')
+ ui.write((b' smallest length: %9i\n' % size_v1[0]))
+ ui.write((b' longer length: %9i\n' % size_v1[-1]))
median = size_v1[nbmarkers // 2]
- ui.write((' median length: %9i\n' % median))
+ ui.write((b' median length: %9i\n' % median))
mean = sum(size_v1) // nbmarkers
- ui.write((' mean length: %9i\n' % mean))
+ ui.write((b' mean length: %9i\n' % mean))
# format v0
- ui.write(' format v0:\n')
- ui.write((' smallest length: %9i\n' % size_v0[0]))
- ui.write((' longer length: %9i\n' % size_v0[-1]))
+ ui.write(b' format v0:\n')
+ ui.write((b' smallest length: %9i\n' % size_v0[0]))
+ ui.write((b' longer length: %9i\n' % size_v0[-1]))
median = size_v0[nbmarkers // 2]
- ui.write((' median length: %9i\n' % median))
+ ui.write((b' median length: %9i\n' % median))
mean = sum(size_v0) // nbmarkers
- ui.write((' mean length: %9i\n' % mean))
+ ui.write((b' mean length: %9i\n' % mean))
allclusters = list(set(clustersmap.values()))
allclusters.sort(key=lambda x: len(x[1]))
- ui.write(('disconnected clusters: %9i\n' % len(allclusters)))
+ ui.write((b'disconnected clusters: %9i\n' % len(allclusters)))
- ui.write(' any known node: %9i\n'
+ ui.write(b' any known node: %9i\n'
% len([c for c in allclusters
if [n for n in c[0] if nm.get(n) is not None]]))
if allclusters:
nbcluster = len(allclusters)
- ui.write((' smallest length: %9i\n' % len(allclusters[0][1])))
- ui.write((' longer length: %9i\n'
- % len(allclusters[-1][1])))
+ ui.write((b' smallest length: %9i\n' % len(allclusters[0][1])))
+ ui.write((b' longer length: %9i\n'
+ % len(allclusters[-1][1])))
median = len(allclusters[nbcluster // 2][1])
- ui.write((' median length: %9i\n' % median))
+ ui.write((b' median length: %9i\n' % median))
mean = sum(len(x[1]) for x in allclusters) // nbcluster
- ui.write((' mean length: %9i\n' % mean))
+ ui.write((b' mean length: %9i\n' % mean))
allpclusters = list(set(pclustersmap.values()))
allpclusters.sort(key=lambda x: len(x[1]))
- ui.write((' using parents data: %9i\n' % len(allpclusters)))
- ui.write(' any known node: %9i\n'
+ ui.write((b' using parents data: %9i\n' % len(allpclusters)))
+ ui.write(b' any known node: %9i\n'
% len([c for c in allclusters
if [n for n in c[0] if nm.get(n) is not None]]))
if allpclusters:
nbcluster = len(allpclusters)
- ui.write((' smallest length: %9i\n'
- % len(allpclusters[0][1])))
- ui.write((' longer length: %9i\n'
- % len(allpclusters[-1][1])))
+ ui.write((b' smallest length: %9i\n'
+ % len(allpclusters[0][1])))
+ ui.write((b' longer length: %9i\n'
+ % len(allpclusters[-1][1])))
median = len(allpclusters[nbcluster // 2][1])
- ui.write((' median length: %9i\n' % median))
+ ui.write((b' median length: %9i\n' % median))
mean = sum(len(x[1]) for x in allpclusters) // nbcluster
- ui.write((' mean length: %9i\n' % mean))
+ ui.write((b' mean length: %9i\n' % mean))
--- a/hgext3rd/evolve/depthcache.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/depthcache.py Fri Sep 27 13:03:14 2019 +0200
@@ -32,7 +32,7 @@
def simpledepth(repo, rev):
"""simple but obviously right implementation of depth"""
- return len(repo.revs('::%d', rev))
+ return len(repo.revs(b'::%d', rev))
@eh.command(
b'debugdepth',
@@ -46,25 +46,25 @@
"""
revs = scmutil.revrange(repo, opts['rev'])
method = opts['method']
- if method in ('cached', 'compare'):
+ if method in (b'cached', b'compare'):
cache = repo.depthcache
cache.save(repo)
for r in revs:
ctx = repo[r]
- if method == 'simple':
+ if method == b'simple':
depth = simpledepth(repo, r)
- elif method == 'cached':
+ elif method == b'cached':
depth = cache.get(r)
- elif method == 'compare':
+ elif method == b'compare':
simple = simpledepth(repo, r)
cached = cache.get(r)
if simple != cached:
- raise error.Abort('depth differ for revision %s: %d != %d'
+ raise error.Abort(b'depth differ for revision %s: %d != %d'
% (ctx, simple, cached))
depth = simple
else:
- raise error.Abort('unknown method "%s"' % method)
- ui.write('%s %d\n' % (ctx, depth))
+ raise error.Abort(b'unknown method "%s"' % method)
+ ui.write(b'%s %d\n' % (ctx, depth))
@eh.reposetup
def setupcache(ui, repo):
@@ -79,7 +79,7 @@
@localrepo.unfilteredmethod
def destroyed(self):
- if 'depthcache' in vars(self):
+ if r'depthcache' in vars(self):
self.depthcache.clear()
super(depthcacherepo, self).destroyed()
@@ -94,16 +94,16 @@
class depthcache(genericcaches.changelogsourcebase):
- _filepath = 'evoext-depthcache-00'
- _cachename = 'evo-ext-depthcache'
+ _filepath = b'evoext-depthcache-00'
+ _cachename = b'evo-ext-depthcache'
def __init__(self):
super(depthcache, self).__init__()
- self._data = array.array('l')
+ self._data = array.array(r'l')
def get(self, rev):
if len(self._data) <= rev:
- raise error.ProgrammingError('depthcache must be warmed before use')
+ raise error.ProgrammingError(b'depthcache must be warmed before use')
return self._data[rev]
def _updatefrom(self, repo, data):
@@ -113,9 +113,9 @@
total = len(data)
def progress(pos, rev=None):
- revstr = '' if rev is None else ('rev %d' % rev)
- compat.progress(repo.ui, 'updating depth cache',
- pos, revstr, unit='revision', total=total)
+ 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)
progress(0)
for idx, rev in enumerate(data, 1):
assert rev == len(self._data), (rev, len(self._data))
@@ -171,7 +171,7 @@
Subclasses MUST overide this method to actually affect the cache data.
"""
super(depthcache, self).clear()
- self._data = array.array('l')
+ self._data = array.array(r'l')
# crude version of a cache, to show the kind of information we have to store
@@ -180,7 +180,7 @@
assert repo.filtername is None
data = repo.cachevfs.tryread(self._filepath)
- self._data = array.array('l')
+ self._data = array.array(r'l')
if not data:
self._cachekey = self.emptykey
else:
@@ -199,12 +199,12 @@
return
try:
- cachefile = repo.cachevfs(self._filepath, 'w', atomictemp=True)
+ cachefile = repo.cachevfs(self._filepath, b'w', atomictemp=True)
headerdata = self._serializecachekey()
cachefile.write(headerdata)
cachefile.write(compat.arraytobytes(self._data))
cachefile.close()
self._ondiskkey = self._cachekey
except (IOError, OSError) as exc:
- repo.ui.log('depthcache', 'could not write update %s\n' % exc)
- repo.ui.debug('depthcache: could not write update %s\n' % exc)
+ repo.ui.log(b'depthcache', b'could not write update %s\n' % exc)
+ repo.ui.debug(b'depthcache: could not write update %s\n' % exc)
--- a/hgext3rd/evolve/evolvecmd.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/evolvecmd.py Fri Sep 27 13:03:14 2019 +0200
@@ -48,12 +48,12 @@
shorttemplate = utility.shorttemplate
stacktemplate = utility.stacktemplate
_bookmarksupdater = rewriteutil.bookmarksupdater
-sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
+sha1re = re.compile(br'\b[0-9a-f]{6,40}\b')
eh = exthelper.exthelper()
mergetoolopts = commands.mergetoolopts
-abortmessage = _("see `hg help evolve.interrupted`\n")
+abortmessage = _(b"see `hg help evolve.interrupted`\n")
def _solveone(ui, repo, ctx, evolvestate, dryrun, confirm,
progresscb, category, lastsolved=None, stacktmplt=False):
@@ -70,23 +70,23 @@
displayer = None
if stacktmplt:
displayer = compat.changesetdisplayer(ui, repo,
- {'template': stacktemplate})
+ {b'template': stacktemplate})
else:
displayer = compat.changesetdisplayer(ui, repo,
- {'template': shorttemplate})
- if 'orphan' == category:
+ {b'template': shorttemplate})
+ if b'orphan' == category:
result = _solveunstable(ui, repo, ctx, evolvestate, displayer,
dryrun, confirm, progresscb,
lastsolved=lastsolved)
- elif 'phasedivergent' == category:
+ elif b'phasedivergent' == category:
result = _solvephasedivergence(ui, repo, ctx, evolvestate,
displayer, dryrun, confirm,
progresscb)
- elif 'contentdivergent' == category:
+ elif b'contentdivergent' == category:
result = _solvedivergent(ui, repo, ctx, evolvestate, displayer,
dryrun, confirm, progresscb)
else:
- assert False, "unknown trouble category: %s" % (category)
+ assert False, b"unknown trouble category: %s" % (category)
return result
def _solveunstable(ui, repo, orig, evolvestate, displayer, dryrun=False,
@@ -112,7 +112,7 @@
else:
# store that we are resolving an orphan merge with both parents
# obsolete and proceed with first parent
- evolvestate['orphanmerge'] = True
+ evolvestate[b'orphanmerge'] = True
# we should process the second parent first, so that in case of
# no-conflicts the first parent is processed later and preserved as
# first parent
@@ -120,40 +120,40 @@
keepbranch = orig.p2().branch() != orig.branch()
if not pctx.obsolete():
- ui.warn(_("cannot solve instability of %s, skipping\n") % orig)
- return (False, ".")
+ ui.warn(_(b"cannot solve instability of %s, skipping\n") % orig)
+ return (False, b".")
obs = pctx
newer = obsutil.successorssets(repo, obs.node())
- # search of a parent which is not killed
- while not newer or newer == [()]:
- ui.debug("stabilize target %s is plain dead,"
- " trying to stabilize on its parent\n" %
+ # search of a parent which is not killed, but also isn't the orig
+ while not newer or newer == [()] or newer[0][0] == orig.node():
+ ui.debug(b"stabilize target %s is plain dead,"
+ b" trying to stabilize on its parent\n" %
obs)
obs = obs.parents()[0]
newer = obsutil.successorssets(repo, obs.node())
if len(newer) > 1:
- msg = _("skipping %s: divergent rewriting. can't choose "
- "destination\n") % obs
+ msg = _(b"skipping %s: divergent rewriting. can't choose "
+ b"destination\n") % obs
ui.write_err(msg)
- return (False, ".")
+ return (False, b".")
targets = newer[0]
assert targets
if len(targets) > 1:
# split target, figure out which one to pick, are they all in line?
targetrevs = [repo[r].rev() for r in targets]
- roots = repo.revs('roots(%ld)', targetrevs)
- heads = repo.revs('heads(%ld)', targetrevs)
+ roots = repo.revs(b'roots(%ld)', targetrevs)
+ heads = repo.revs(b'heads(%ld)', targetrevs)
if len(roots) > 1 or len(heads) > 1:
- cheader = _("ancestor '%s' split over multiple topological"
- " branches.\nchoose an evolve destination:") % orig
+ cheader = _(b"ancestor '%s' split over multiple topological"
+ b" branches.\nchoose an evolve destination:") % orig
selectedrev = utility.revselectionprompt(ui, repo, list(heads),
cheader)
if selectedrev is None:
- msg = _("could not solve instability, "
- "ambiguous destination: "
- "parent split across two branches\n")
+ msg = _(b"could not solve instability, "
+ b"ambiguous destination: "
+ b"parent split across two branches\n")
ui.write_err(msg)
- return (False, ".")
+ return (False, b".")
target = repo[selectedrev]
else:
target = repo[heads.first()]
@@ -161,32 +161,27 @@
target = targets[0]
target = repo[target]
if not ui.quiet or confirm:
- repo.ui.write(_('move:'), label='evolve.operation')
+ repo.ui.write(_(b'move:'), label=b'evolve.operation')
displayer.show(orig)
if lastsolved is None or target != repo[lastsolved]:
- repo.ui.write(_('atop:'))
+ repo.ui.write(_(b'atop:'))
displayer.show(target)
- if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y':
- raise error.Abort(_('evolve aborted by user'))
- todo = 'hg rebase -r %s -d %s\n' % (orig, target)
+ if confirm and ui.prompt(b'perform evolve? [Ny]', b'n') != b'y':
+ raise error.Abort(_(b'evolve aborted by user'))
+ todo = b'hg rebase -r %s -d %s\n' % (orig, target)
if dryrun:
if progresscb:
progresscb()
repo.ui.write(todo)
- return (False, ".")
+ return (False, b".")
else:
repo.ui.note(todo)
if progresscb:
progresscb()
- try:
+ with state.saver(evolvestate, {b'current': orig.node()}):
newid = relocate(repo, orig, target, evolvestate, pctx,
- keepbranch, 'orphan')
+ keepbranch, b'orphan')
return (True, newid)
- except error.InterventionRequired:
- ops = {'current': orig.node()}
- evolvestate.addopts(ops)
- evolvestate.save()
- raise
def _solvephasedivergence(ui, repo, bumped, evolvestate, displayer,
dryrun=False, confirm=False, progresscb=None):
@@ -202,32 +197,32 @@
bumped = repo[bumped.rev()]
# For now we deny bumped merge
if len(bumped.parents()) > 1:
- msg = _('skipping %s : we do not handle merge yet\n') % bumped
+ msg = _(b'skipping %s : we do not handle merge yet\n') % bumped
ui.write_err(msg)
- return (False, ".")
- prec = next(repo.set('last(allpredecessors(%d) and public())', bumped.rev()))
+ return (False, b".")
+ prec = next(repo.set(b'last(allpredecessors(%d) and public())', bumped.rev()))
# For now we deny target merge
if len(prec.parents()) > 1:
- msg = _('skipping: %s: public version is a merge, '
- 'this is not handled yet\n') % prec
+ msg = _(b'skipping: %s: public version is a merge, '
+ b'this is not handled yet\n') % prec
ui.write_err(msg)
- return (False, ".")
+ return (False, b".")
if not ui.quiet or confirm:
- repo.ui.write(_('recreate:'), label='evolve.operation')
+ repo.ui.write(_(b'recreate:'), label=b'evolve.operation')
displayer.show(bumped)
- repo.ui.write(_('atop:'))
+ repo.ui.write(_(b'atop:'))
displayer.show(prec)
- if confirm and ui.prompt(_('perform evolve? [Ny]'), 'n') != 'y':
- raise error.Abort(_('evolve aborted by user'))
+ if confirm and ui.prompt(_(b'perform evolve? [Ny]'), b'n') != b'y':
+ raise error.Abort(_(b'evolve aborted by user'))
if dryrun:
- todo = 'hg rebase --rev %s --dest %s;\n' % (bumped, prec.p1())
+ todo = b'hg rebase --rev %s --dest %s;\n' % (bumped, prec.p1())
repo.ui.write(todo)
- repo.ui.write(('hg update %s;\n' % prec))
- repo.ui.write(('hg revert --all --rev %s;\n' % bumped))
- repo.ui.write(('hg commit --msg "%s update to %s"\n' %
+ repo.ui.write((b'hg update %s;\n' % prec))
+ repo.ui.write((b'hg revert --all --rev %s;\n' % bumped))
+ repo.ui.write((b'hg commit --msg "%s update to %s"\n' %
(TROUBLES['PHASEDIVERGENT'], bumped)))
- return (False, ".")
+ return (False, b".")
if progresscb:
progresscb()
@@ -237,24 +232,20 @@
# evolved or any other operation which can change parent. In such cases,
# when parents are not same, we first rebase the divergent changeset onto
# parent or precursor and then perform later steps
- if not list(repo.set('parents(%d) and parents(%d)', bumped.rev(), prec.rev())):
+ if not list(repo.set(b'parents(%d) and parents(%d)', bumped.rev(), prec.rev())):
# Need to rebase the changeset at the right place
repo.ui.status(
- _('rebasing to destination parent: %s\n') % prec.p1())
- try:
+ _(b'rebasing to destination parent: %s\n') % prec.p1())
+ with state.saver(evolvestate, {b'current': bumped.hex(),
+ b'precursor': prec.hex()}):
newnode = relocate(repo, bumped, prec.p1(), evolvestate,
- category='phasedivergent')
+ category=b'phasedivergent')
if newnode is not None:
new = repo[newnode]
obsolete.createmarkers(repo, [(bumped, (new,))],
- operation='evolve')
+ operation=b'evolve')
bumped = new
- evolvestate['temprevs'].append(newnode)
- except error.InterventionRequired:
- evolvestate['current'] = bumped.hex()
- evolvestate['precursor'] = prec.hex()
- evolvestate.save()
- raise
+ evolvestate[b'temprevs'].append(newnode)
return _resolvephasedivergent(ui, repo, prec, bumped)
@@ -284,7 +275,7 @@
merge.update(repo, bumped.node(), ancestor=prec, mergeancestor=True,
branchmerge=True, force=False, wc=wctx)
if not wctx.isempty():
- text = '%s update to %s:\n\n' % (TROUBLES['PHASEDIVERGENT'], prec)
+ text = b'%s update to %s:\n\n' % (TROUBLES['PHASEDIVERGENT'], prec)
text += bumped.description()
memctx = wctx.tomemctx(text,
parents=(prec.node(), nodemod.nullid),
@@ -294,14 +285,14 @@
newid = repo.commitctx(memctx)
replacementnode = newid
if newid is None:
- repo.ui.status(_('no changes to commit\n'))
- obsolete.createmarkers(repo, [(bumped, ())], operation='evolve')
+ repo.ui.status(_(b'no changes to commit\n'))
+ obsolete.createmarkers(repo, [(bumped, ())], operation=b'evolve')
newid = prec.node()
else:
- repo.ui.status(_('committed as %s\n') % nodemod.short(newid))
+ repo.ui.status(_(b'committed as %s\n') % nodemod.short(newid))
phases.retractboundary(repo, tr, bumped.phase(), [newid])
obsolete.createmarkers(repo, [(bumped, (repo[newid],))],
- flag=obsolete.bumpedfix, operation='evolve')
+ flag=obsolete.bumpedfix, operation=b'evolve')
bmupdate(newid)
# reroute the working copy parent to the new changeset
with repo.dirstate.parentchange():
@@ -320,45 +311,45 @@
"""
repo = repo.unfiltered()
divergent = repo[divergent.rev()]
- evolvestate['divergent'] = divergent.node()
- evolvestate['orig-divergent'] = divergent.node()
+ evolvestate[b'divergent'] = divergent.node()
+ evolvestate[b'orig-divergent'] = divergent.node()
# sometimes we will relocate a node in case of different parents and we can
# encounter conflicts after relocation is done while solving
# content-divergence and if the user calls `hg evolve --stop`, we need to
# strip that relocated commit. However if `--all` is passed, we need to
# reset this value for each content-divergence resolution which we are doing
# below.
- evolvestate['relocated'] = None
- evolvestate['relocating'] = False
+ evolvestate[b'relocated'] = None
+ evolvestate[b'relocating'] = False
# in case or relocation we get a new other node, we need to store the old
# other for purposes like `--abort` or `--stop`
- evolvestate['old-other'] = None
+ evolvestate[b'old-other'] = None
base, others = divergentdata(divergent)
# we don't handle split in content-divergence yet
if len(others) > 1:
- othersstr = "[%s]" % (','.join([bytes(i) for i in others]))
- msg = _("skipping %s: %s with a changeset that got split"
- " into multiple ones:\n"
- "|[%s]\n"
- "| This is not handled by automatic evolution yet\n"
- "| You have to fallback to manual handling with commands "
- "such as:\n"
- "| - hg touch -D\n"
- "| - hg prune\n"
- "| \n"
- "| You should contact your local evolution Guru for help.\n"
+ othersstr = b"[%s]" % (b','.join([bytes(i) for i in others]))
+ msg = _(b"skipping %s: %s with a changeset that got split"
+ b" into multiple ones:\n"
+ b"|[%s]\n"
+ b"| This is not handled by automatic evolution yet\n"
+ b"| You have to fallback to manual handling with commands "
+ b"such as:\n"
+ b"| - hg touch -D\n"
+ b"| - hg prune\n"
+ b"| \n"
+ b"| You should contact your local evolution Guru for help.\n"
) % (divergent, TROUBLES['CONTENTDIVERGENT'], othersstr)
ui.write_err(msg)
- return (False, ".")
+ return (False, b".")
other = others[0]
- evolvestate['other-divergent'] = other.node()
- evolvestate['base'] = base.node()
+ evolvestate[b'other-divergent'] = other.node()
+ evolvestate[b'base'] = base.node()
def swapnodes(div, other):
div, other = other, div
- evolvestate['divergent'] = div.node()
- evolvestate['other-divergent'] = other.node()
+ evolvestate[b'divergent'] = div.node()
+ evolvestate[b'other-divergent'] = other.node()
return div, other
# haspubdiv: to keep track if we are solving public content-divergence
haspubdiv = False
@@ -371,17 +362,17 @@
divergent, other = swapnodes(divergent, other)
else:
publicdiv = divergent
- evolvestate['public-divergent'] = publicdiv.node()
+ evolvestate[b'public-divergent'] = publicdiv.node()
# we don't handle merge content-divergent changesets yet
if len(other.parents()) > 1:
- msg = _("skipping %s: %s changeset can't be "
- "a merge (yet)\n") % (divergent, TROUBLES['CONTENTDIVERGENT'])
+ msg = _(b"skipping %s: %s changeset can't be "
+ b"a merge (yet)\n") % (divergent, TROUBLES['CONTENTDIVERGENT'])
ui.write_err(msg)
- hint = _("You have to fallback to solving this by hand...\n"
- "| This probably means redoing the merge and using \n"
- "| `hg prune` to kill older version.\n")
+ hint = _(b"You have to fallback to solving this by hand...\n"
+ b"| This probably means redoing the merge and using \n"
+ b"| `hg prune` to kill older version.\n")
ui.write_err(hint)
- return (False, ".")
+ return (False, b".")
otherp1 = other.p1().rev()
divp1 = divergent.p1().rev()
@@ -400,15 +391,15 @@
# the changeset on which resolution changeset will be based on
resolutionparent = repo[divp1].node()
- gca = repo.revs("ancestor(%d, %d)" % (otherp1, divp1))
+ gca = repo.revs(b"ancestor(%d, %d)" % (otherp1, divp1))
# divonly: non-obsolete csets which are topological ancestor of "divergent"
# but not "other"
- divonly = repo.revs("only(%d, %d) - obsolete()" % (divergent.rev(),
- other.rev()))
+ divonly = repo.revs(b"only(%d, %d) - obsolete()" % (divergent.rev(),
+ other.rev()))
# otheronly: non-obsolete csets which are topological ancestor of "other"
# but not "div"
- otheronly = repo.revs("only(%d, %d) - obsolete()" % (other.rev(),
- divergent.rev()))
+ otheronly = repo.revs(b"only(%d, %d) - obsolete()" % (other.rev(),
+ divergent.rev()))
# make it exclusive set
divonly = set(divonly) - {divergent.rev()}
otheronly = set(otheronly) - {other.rev()}
@@ -468,62 +459,62 @@
divergent, other = swapnodes(divergent, other)
resolutionparent = divergent.p1().node()
else:
- msg = _("skipping %s: have a different parent than %s "
- "(not handled yet)\n") % (divergent, other)
- hint = _("| %(d)s, %(o)s are not based on the same changeset.\n"
- "| With the current state of its implementation, \n"
- "| evolve does not work in that case.\n"
- "| rebase one of them next to the other and run \n"
- "| this command again.\n"
- "| - either: hg rebase --dest 'p1(%(d)s)' -r %(o)s\n"
- "| - or: hg rebase --dest 'p1(%(o)s)' -r %(d)s\n"
- ) % {'d': divergent, 'o': other}
+ msg = _(b"skipping %s: have a different parent than %s "
+ b"(not handled yet)\n") % (divergent, other)
+ hint = _(b"| %(d)s, %(o)s are not based on the same changeset.\n"
+ b"| With the current state of its implementation, \n"
+ b"| evolve does not work in that case.\n"
+ b"| rebase one of them next to the other and run \n"
+ b"| this command again.\n"
+ b"| - either: hg rebase --dest 'p1(%(d)s)' -r %(o)s\n"
+ b"| - or: hg rebase --dest 'p1(%(o)s)' -r %(d)s\n"
+ ) % {b'd': divergent, b'o': other}
ui.write_err(msg)
ui.write_err(hint)
- return (False, ".")
+ return (False, b".")
if not ui.quiet or confirm:
- ui.write(_('merge:'), label='evolve.operation')
+ ui.write(_(b'merge:'), label=b'evolve.operation')
displayer.show(divergent)
- ui.write(_('with: '))
+ ui.write(_(b'with: '))
displayer.show(other)
- ui.write(_('base: '))
+ ui.write(_(b'base: '))
displayer.show(base)
- if confirm and ui.prompt(_('perform evolve? [Ny]'), 'n') != 'y':
- raise error.Abort(_('evolve aborted by user'))
+ if confirm and ui.prompt(_(b'perform evolve? [Ny]'), b'n') != b'y':
+ raise error.Abort(_(b'evolve aborted by user'))
if dryrun:
- ui.write(('hg update -c %s &&\n' % divergent))
- ui.write(('hg merge %s &&\n' % other))
- ui.write(('hg commit -m "auto merge resolving conflict between '
- '%s and %s"&&\n' % (divergent, other)))
- ui.write(('hg up -C %s &&\n' % base))
- ui.write(('hg revert --all --rev tip &&\n'))
- ui.write(('hg commit -m "`hg log -r %s --template={desc}`";\n'
- % divergent))
- return (False, ".")
+ ui.write((b'hg update -c %s &&\n' % divergent))
+ ui.write((b'hg merge %s &&\n' % other))
+ ui.write((b'hg commit -m "auto merge resolving conflict between '
+ b'%s and %s"&&\n' % (divergent, other)))
+ ui.write((b'hg up -C %s &&\n' % base))
+ ui.write((b'hg revert --all --rev tip &&\n'))
+ ui.write((b'hg commit -m "`hg log -r %s --template={desc}`";\n'
+ % divergent))
+ return (False, b".")
- evolvestate['resolutionparent'] = resolutionparent
+ # Sometimes we already have the other cset where we want it
+ if relocatereq and other == divergent.p1():
+ relocatereq = False
+
+ evolvestate[b'resolutionparent'] = resolutionparent
# relocate the other divergent if required
if relocatereq:
# relocating will help us understand during the time of conflicts that
# whether conflicts occur at reloacting or they occured at merging
# content divergent changesets
- evolvestate['relocating'] = True
- ui.status(_('rebasing "other" content-divergent changeset %s on'
- ' %s\n' % (other, divergent.p1())))
- try:
+ evolvestate[b'relocating'] = True
+ ui.status(_(b'rebasing "other" content-divergent changeset %s on'
+ b' %s\n' % (other, divergent.p1())))
+ with state.saver(evolvestate, {b'current': other.node()}):
newother = relocate(repo, other, divergent.p1(), evolvestate,
keepbranch=True)
- except error.InterventionRequired:
- evolvestate['current'] = other.node()
- evolvestate.save()
- raise
- evolvestate['old-other'] = other.node()
+ evolvestate[b'old-other'] = other.node()
other = repo[newother]
- evolvestate['relocating'] = False
- evolvestate['relocated'] = other.node()
- evolvestate['temprevs'].append(other.node())
- evolvestate['other-divergent'] = other.node()
+ evolvestate[b'relocating'] = False
+ evolvestate[b'relocated'] = other.node()
+ evolvestate[b'temprevs'].append(other.node())
+ evolvestate[b'other-divergent'] = other.node()
_mergecontentdivergents(repo, progresscb, divergent, other, base,
evolvestate)
@@ -545,9 +536,9 @@
# case 2)
pubstr = bytes(publicdiv)
othstr = bytes(other)
- msg = _('content divergence resolution between %s '
- '(public) and %s has same content as %s, '
- 'discarding %s\n')
+ msg = _(b'content divergence resolution between %s '
+ b'(public) and %s has same content as %s, '
+ b'discarding %s\n')
msg %= (pubstr, othstr, pubstr, othstr)
repo.ui.status(msg)
return (res, newnode)
@@ -559,29 +550,30 @@
def _mergecontentdivergents(repo, progresscb, divergent, other, base,
evolvestate):
if divergent not in repo[None].parents():
- repo.ui.note(_("updating to \"local\" side of the conflict: %s\n") %
+ repo.ui.note(_(b"updating to \"local\" side of the conflict: %s\n") %
divergent.hex()[:12])
hg.updaterepo(repo, divergent.node(), False)
# merging the two content-divergent changesets
- repo.ui.note(_("merging \"other\" %s changeset '%s'\n") %
+ repo.ui.note(_(b"merging \"other\" %s changeset '%s'\n") %
(TROUBLES['CONTENTDIVERGENT'], other.hex()[:12]))
if progresscb:
progresscb()
- mergeancestor = repo.changelog.isancestor(divergent.node(), other.node())
- stats = merge.update(repo,
- other.node(),
- branchmerge=True,
- force=False,
- ancestor=base.node(),
- mergeancestor=mergeancestor)
- hg._showstats(repo, stats)
+ with state.saver(evolvestate):
+ mergeancestor = repo.changelog.isancestor(divergent.node(),
+ other.node())
+ stats = merge.update(repo,
+ other.node(),
+ branchmerge=True,
+ force=False,
+ ancestor=base.node(),
+ mergeancestor=mergeancestor)
+ hg._showstats(repo, stats)
- # conflicts while merging content-divergent changesets
- if compat.hasconflict(stats):
- evolvestate.save()
- hint = _("see 'hg help evolve.interrupted'")
- raise error.InterventionRequired(_("unresolved merge conflicts"),
- hint=hint)
+ # conflicts while merging content-divergent changesets
+ if compat.hasconflict(stats):
+ hint = _(b"see 'hg help evolve.interrupted'")
+ raise error.InterventionRequired(_(b"unresolved merge conflicts"),
+ hint=hint)
def _completecontentdivergent(ui, repo, progresscb, divergent, other,
base, evolvestate):
@@ -590,20 +582,20 @@
# resume resolution
if progresscb:
progresscb()
- emtpycommitallowed = repo.ui.backupconfig('ui', 'allowemptycommit')
+ emtpycommitallowed = repo.ui.backupconfig(b'ui', b'allowemptycommit')
tr = repo.currenttransaction()
assert tr is not None
# whether to store the obsmarker in the evolvestate
storemarker = False
- resparent = evolvestate['resolutionparent']
+ resparent = evolvestate[b'resolutionparent']
# whether we are solving public divergence
haspubdiv = False
- if evolvestate.get('public-divergent'):
+ if evolvestate.get(b'public-divergent'):
haspubdiv = True
- publicnode = evolvestate['public-divergent']
+ publicnode = evolvestate[b'public-divergent']
publicdiv = repo[publicnode]
- othernode = evolvestate['other-divergent']
+ othernode = evolvestate[b'other-divergent']
otherdiv = repo[othernode]
with repo.dirstate.parentchange():
@@ -616,7 +608,7 @@
warnmetadataloss(repo, publicdiv, otherdiv)
# no changes, create markers to resolve divergence
obsolete.createmarkers(repo, [(otherdiv, (publicdiv,))],
- operation='evolve')
+ operation=b'evolve')
return (True, publicnode)
try:
with repo.dirstate.parentchange():
@@ -642,29 +634,29 @@
# no changes
new = divergent
storemarker = True
- repo.ui.status(_("nothing changed\n"))
+ repo.ui.status(_(b"nothing changed\n"))
hg.updaterepo(repo, divergent.rev(), False)
else:
new = repo[newnode]
newnode = new.node()
hg.updaterepo(repo, new.rev(), False)
if haspubdiv and publicdiv == divergent:
- bypassphase(repo, (divergent, new), operation='evolve')
+ bypassphase(repo, (divergent, new), operation=b'evolve')
else:
obsolete.createmarkers(repo, [(divergent, (new,))],
- operation='evolve')
+ operation=b'evolve')
# creating markers and moving phases post-resolution
if haspubdiv and publicdiv == other:
- bypassphase(repo, (other, new), operation='evolve')
+ bypassphase(repo, (other, new), operation=b'evolve')
else:
- obsolete.createmarkers(repo, [(other, (new,))], operation='evolve')
+ obsolete.createmarkers(repo, [(other, (new,))], operation=b'evolve')
if storemarker:
# storing the marker in the evolvestate
# we just store the precursors and successor pair for now, we might
# want to store more data and serialize obsmarker in a better way in
# future
- evolvestate['obsmarkers'].append((other.node(), new.node()))
+ evolvestate[b'obsmarkers'].append((other.node(), new.node()))
phases.retractboundary(repo, tr, other.phase(), [new.node()])
return (True, newnode)
@@ -676,7 +668,7 @@
public content-divergence"""
# needtowarn: aspects where we need to warn user
- needtowarn = ['branch', 'topic', 'close']
+ needtowarn = [b'branch', b'topic', b'close']
aspects = set()
localextra = local.extra()
otherextra = other.extra()
@@ -688,48 +680,48 @@
aspects.add(asp)
if other.description() != local.description():
- aspects.add('description')
+ aspects.add(b'description')
if aspects:
# warn user
locstr = bytes(local)
othstr = bytes(other)
- if 'close' in aspects:
- filteredasp = aspects - {'close'}
+ if b'close' in aspects:
+ filteredasp = aspects - {b'close'}
if filteredasp:
- msg = _('other divergent changeset %s is a closed branch head '
- 'and differs from local %s by "%s" only,' %
- (othstr, locstr, ', '.join(sorted(filteredasp))))
+ msg = _(b'other divergent changeset %s is a closed branch head '
+ b'and differs from local %s by "%s" only,' %
+ (othstr, locstr, b', '.join(sorted(filteredasp))))
else:
- msg = _('other divergent changeset %s is a closed branch head '
- 'and has same content as local %s,' % (othstr, locstr))
+ msg = _(b'other divergent changeset %s is a closed branch head '
+ b'and has same content as local %s,' % (othstr, locstr))
else:
- msg = _('other divergent changeset %s has same content as local %s'
- ' and differs by "%s" only,' %
- (othstr, locstr, ', '.join(sorted(aspects))))
- msg += _(' discarding %s\n' % othstr)
+ msg = _(b'other divergent changeset %s has same content as local %s'
+ b' and differs by "%s" only,' %
+ (othstr, locstr, b', '.join(sorted(aspects))))
+ msg += _(b' discarding %s\n' % othstr)
repo.ui.warn(msg)
-def bypassphase(repo, relation, flag=0, metadata=None, operation='evolve'):
+def bypassphase(repo, relation, flag=0, metadata=None, operation=b'evolve'):
"""function to create a single obsmarker relation even for public csets
where relation should be a single pair (prec, succ)"""
# prepare metadata
if metadata is None:
metadata = {}
- if 'user' not in metadata:
- luser = repo.ui.config('devel', 'user.obsmarker') or repo.ui.username()
- metadata['user'] = encoding.fromlocal(luser)
+ if b'user' not in metadata:
+ luser = repo.ui.config(b'devel', b'user.obsmarker') or repo.ui.username()
+ metadata[b'user'] = encoding.fromlocal(luser)
# Operation metadata handling
- useoperation = repo.ui.configbool('experimental',
- 'evolution.track-operation')
+ useoperation = repo.ui.configbool(b'experimental',
+ b'evolution.track-operation')
if useoperation and operation:
- metadata['operation'] = operation
+ metadata[b'operation'] = operation
# Effect flag metadata handling
- saveeffectflag = repo.ui.configbool('experimental',
- 'evolution.effect-flags')
- with repo.transaction('add-obsolescence-marker') as tr:
+ saveeffectflag = repo.ui.configbool(b'experimental',
+ b'evolution.effect-flags')
+ with repo.transaction(b'add-obsolescence-marker') as tr:
prec, succ = relation
nprec = prec.node()
npare = None
@@ -737,7 +729,7 @@
if not nsucs:
npare = tuple(p.node() for p in prec.parents())
if nprec in nsucs:
- raise error.Abort(_("changeset %s cannot obsolete itself") % prec)
+ raise error.Abort(_(b"changeset %s cannot obsolete itself") % prec)
if saveeffectflag:
# The effect flag is saved in a versioned field name for
@@ -747,7 +739,7 @@
except TypeError:
# hg <= 4.7
effectflag = obsutil.geteffectflag((prec, (succ,)))
- metadata[obsutil.EFFECTFLAGFIELD] = "%d" % effectflag
+ metadata[obsutil.EFFECTFLAGFIELD] = b"%d" % effectflag
# create markers
repo.obsstore.create(tr, nprec, nsucs, flag, parents=npare,
@@ -849,11 +841,11 @@
repo.dirstate.setbranch(othbranch)
else:
# all the three branches are different
- index = repo.ui.promptchoice(_("content divergent changesets on "
- "different branches.\nchoose branch"
- " for the resolution changeset. (a) "
- "%s or (b) %s or (c) %s? $$ &a $$ &b"
- " $$ &c") %
+ index = repo.ui.promptchoice(_(b"content divergent changesets on "
+ b"different branches.\nchoose branch"
+ b" for the resolution changeset. (a) "
+ b"%s or (b) %s or (c) %s? $$ &a $$ &b"
+ b" $$ &c") %
(basebranch, divbranch, othbranch), 0)
if index == 0:
@@ -870,20 +862,20 @@
merger = simplemerge.Merge3Text(basedesc, divdesc, othdesc)
mdesc = []
kwargs = {}
- kwargs['name_base'] = 'base'
- kwargs['base_marker'] = '|||||||'
- for line in merger.merge_lines(name_a='divergent', name_b='other',
+ kwargs['name_base'] = b'base'
+ kwargs['base_marker'] = b'|||||||'
+ for line in merger.merge_lines(name_a=b'divergent', name_b=b'other',
**kwargs):
mdesc.append(line)
- desc = ''.join(mdesc)
+ desc = b''.join(mdesc)
if merger.conflicts:
- prefixes = ("HG: Conflicts while merging changeset description of"
- " content-divergent changesets.\nHG: Resolve conflicts"
- " in commit messages to continue.\n\n")
+ prefixes = (b"HG: Conflicts while merging changeset description of"
+ b" content-divergent changesets.\nHG: Resolve conflicts"
+ b" in commit messages to continue.\n\n")
- resolveddesc = ui.edit(prefixes + desc, ui.username(), action='desc')
+ resolveddesc = ui.edit(prefixes + desc, ui.username(), action=b'desc')
# make sure we remove the prefixes part from final commit message
if prefixes in resolveddesc:
# hack, we should find something better
@@ -934,17 +926,17 @@
returns the node of new commit which is formed
"""
if orig.rev() == dest.rev():
- msg = _('tried to relocate a node on top of itself')
- hint = _("This shouldn't happen. If you still need to move changesets, "
- "please do so manually with nothing to rebase - working "
- "directory parent is also destination")
+ msg = _(b'tried to relocate a node on top of itself')
+ hint = _(b"This shouldn't happen. If you still need to move changesets, "
+ b"please do so manually with nothing to rebase - working "
+ b"directory parent is also destination")
raise error.ProgrammingError(msg, hint=hint)
if pctx is None:
if len(orig.parents()) == 2:
- msg = _("tried to relocate a merge commit without specifying which "
- "parent should be moved")
- hint = _("Specify the parent by passing in pctx")
+ msg = _(b"tried to relocate a merge commit without specifying which "
+ b"parent should be moved")
+ hint = _(b"Specify the parent by passing in pctx")
raise error.ProgrammingError(msg, hint)
pctx = orig.p1()
@@ -972,8 +964,8 @@
newsha1 = nodemod.hex(successors[0][0])
commitmsg = commitmsg.replace(sha1, newsha1[:len(sha1)])
else:
- repo.ui.note(_('The stale commit message reference to %s could '
- 'not be updated\n') % sha1)
+ repo.ui.note(_(b'The stale commit message reference to %s could '
+ b'not be updated\n') % sha1)
tr = repo.currenttransaction()
assert tr is not None
@@ -986,8 +978,8 @@
copies.duplicatecopies(repo, repo[None], dest.rev(),
orig.p1().rev())
dirstatedance(repo, dest, orig.node(), None)
- hint = _("see 'hg help evolve.interrupted'")
- raise error.InterventionRequired(_("unresolved merge conflicts"),
+ hint = _(b"see 'hg help evolve.interrupted'")
+ raise error.InterventionRequired(_(b"unresolved merge conflicts"),
hint=hint)
nodenew = _relocatecommit(repo, orig, commitmsg)
_finalizerelocate(repo, orig, dest, nodenew, tr, category, evolvestate)
@@ -997,14 +989,14 @@
if commitmsg is None:
commitmsg = orig.description()
extra = dict(orig.extra())
- if 'branch' in extra:
- del extra['branch']
- extra['rebase_source'] = orig.hex()
+ if b'branch' in extra:
+ del extra[b'branch']
+ extra[b'rebase_source'] = orig.hex()
- backup = repo.ui.backupconfig('phases', 'new-commit')
+ backup = repo.ui.backupconfig(b'phases', b'new-commit')
try:
targetphase = max(orig.phase(), phases.draft)
- repo.ui.setconfig('phases', 'new-commit', targetphase, 'evolve')
+ repo.ui.setconfig(b'phases', b'new-commit', targetphase, b'evolve')
# Commit might fail if unresolved files exist
nodenew = repo.commit(text=commitmsg, user=orig.user(),
date=orig.date(), extra=extra)
@@ -1020,18 +1012,18 @@
if nodenew is not None:
obsolete.createmarkers(repo, [(repo[nodesrc], (repo[nodenew],))],
- operation='evolve')
+ operation=b'evolve')
for book in oldbookmarks:
bmchanges.append((book, nodenew))
- evolvestate['bookmarkchanges'].append((book, nodesrc))
+ evolvestate[b'bookmarkchanges'].append((book, nodesrc))
else:
- if category == 'orphan':
- repo.ui.status(_("evolution of %d:%s created no changes "
- "to commit\n") % (orig.rev(), orig))
- obsolete.createmarkers(repo, [(repo[nodesrc], ())], operation='evolve')
+ if category == b'orphan':
+ repo.ui.status(_(b"evolution of %d:%s created no changes "
+ b"to commit\n") % (orig.rev(), orig))
+ obsolete.createmarkers(repo, [(repo[nodesrc], ())], operation=b'evolve')
# Behave like rebase, move bookmarks to dest
for book in oldbookmarks:
- evolvestate['bookmarkchanges'].append((book, nodesrc))
+ evolvestate[b'bookmarkchanges'].append((book, nodesrc))
bmchanges.append((book, dest.node()))
for book in destbookmarks: # restore bookmark that rebase move
bmchanges.append((book, dest.node()))
@@ -1041,61 +1033,61 @@
def _evolvemerge(repo, orig, dest, pctx, keepbranch):
"""Used by the evolve function to merge dest on top of pctx.
return the same tuple as merge.graft"""
- if repo['.'].rev() != dest.rev():
+ if repo[b'.'].rev() != dest.rev():
merge.update(repo,
dest,
branchmerge=False,
force=True)
if repo._activebookmark:
- repo.ui.status(_("(leaving bookmark %s)\n") % repo._activebookmark)
+ repo.ui.status(_(b"(leaving bookmark %s)\n") % repo._activebookmark)
bookmarksmod.deactivate(repo)
if keepbranch:
repo.dirstate.setbranch(orig.branch())
if util.safehasattr(repo, 'currenttopic'):
# uurrgs
# there no other topic setter yet
- if not orig.topic() and repo.vfs.exists('topic'):
- repo.vfs.unlink('topic')
+ if not orig.topic() and repo.vfs.exists(b'topic'):
+ repo.vfs.unlink(b'topic')
else:
- with repo.vfs.open('topic', 'w') as f:
+ with repo.vfs.open(b'topic', b'w') as f:
f.write(orig.topic())
- return merge.graft(repo, orig, pctx, ['destination', 'evolving'], True)
+ return merge.graft(repo, orig, pctx, [b'destination', b'evolving'], True)
instabilities_map = {
- 'contentdivergent': "content-divergent",
- 'phasedivergent': "phase-divergent"
+ b'contentdivergent': b"content-divergent",
+ b'phasedivergent': b"phase-divergent"
}
def _selectrevs(repo, allopt, revopt, anyopt, targetcat):
"""select troubles in repo matching according to given options"""
revs = set()
if allopt or revopt:
- revs = repo.revs("%s()" % targetcat)
+ revs = repo.revs(b"%s()" % targetcat)
if revopt:
revs = scmutil.revrange(repo, revopt) & revs
elif not anyopt:
- topic = getattr(repo, 'currenttopic', '')
+ topic = getattr(repo, 'currenttopic', b'')
if topic:
- revs = repo.revs('topic(%s)', topic) & revs
- elif targetcat == 'orphan':
+ revs = repo.revs(b'topic(%s)', topic) & revs
+ elif targetcat == b'orphan':
revs = _aspiringdescendant(repo,
- repo.revs('(.::) - obsolete()::'))
+ repo.revs(b'(.::) - obsolete()::'))
revs = set(revs)
- if targetcat == 'contentdivergent':
+ if targetcat == b'contentdivergent':
# Pick one divergent per group of divergents
revs = _dedupedivergents(repo, revs)
elif anyopt:
- revs = repo.revs('first(%s())' % (targetcat))
- elif targetcat == 'orphan':
- revs = set(_aspiringchildren(repo, repo.revs('(.::) - obsolete()::')))
+ revs = repo.revs(b'first(%s())' % (targetcat))
+ elif targetcat == b'orphan':
+ revs = set(_aspiringchildren(repo, repo.revs(b'(.::) - obsolete()::')))
if 1 < len(revs):
- msg = "multiple evolve candidates"
- hint = (_("select one of %s with --rev")
- % ', '.join([bytes(repo[r]) for r in sorted(revs)]))
+ msg = b"multiple evolve candidates"
+ hint = (_(b"select one of %s with --rev")
+ % b', '.join([bytes(repo[r]) for r in sorted(revs)]))
raise error.Abort(msg, hint=hint)
- elif instabilities_map.get(targetcat, targetcat) in repo['.'].instabilities():
- revs = set([repo['.'].rev()])
+ elif instabilities_map.get(targetcat, targetcat) in repo[b'.'].instabilities():
+ revs = set([repo[b'.'].rev()])
return revs
def _dedupedivergents(repo, revs):
@@ -1124,14 +1116,14 @@
XXX this woobly function won't survive XXX
"""
repo = ctx._repo.unfiltered()
- for base in repo.set('reverse(allpredecessors(%d))', ctx.rev()):
+ for base in repo.set(b'reverse(allpredecessors(%d))', ctx.rev()):
newer = obsutil.successorssets(ctx._repo, base.node())
# drop filter and solution including the original ctx
newer = [n for n in newer if n and ctx.node() not in n]
if newer:
return base, tuple(ctx._repo[o] for o in newer[0])
- raise error.Abort(_("base of divergent changeset %s not found") % ctx,
- hint=_('this case is not yet handled'))
+ raise error.Abort(_(b"base of divergent changeset %s not found") % ctx,
+ hint=_(b'this case is not yet handled'))
def _aspiringdescendant(repo, revs):
"""Return a list of changectx which can be stabilized on top of pctx or
@@ -1139,7 +1131,7 @@
target = set(revs)
result = set(target)
paths = collections.defaultdict(set)
- for r in repo.revs('orphan() - %ld', revs):
+ for r in repo.revs(b'orphan() - %ld', revs):
for d in _possibledestination(repo, r):
paths[d].add(r)
@@ -1158,7 +1150,7 @@
one of its descendants. Empty list if none can be found."""
target = set(revs)
result = []
- for r in repo.revs('orphan() - %ld', revs):
+ for r in repo.revs(b'orphan() - %ld', revs):
dest = _possibledestination(repo, r)
if target & dest:
result.append(r)
@@ -1191,104 +1183,104 @@
def _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat):
"""Used by the evolve function to display an error message when
no troubles can be resolved"""
- troublecategories = ['phasedivergent', 'contentdivergent', 'orphan']
+ troublecategories = [b'phasedivergent', b'contentdivergent', b'orphan']
unselectedcategories = [c for c in troublecategories if c != targetcat]
msg = None
hint = None
retoverride = None
troubled = {
- "orphan": repo.revs("orphan()"),
- "contentdivergent": repo.revs("contentdivergent()"),
- "phasedivergent": repo.revs("phasedivergent()"),
- "all": repo.revs("unstable()"),
+ b"orphan": repo.revs(b"orphan()"),
+ b"contentdivergent": repo.revs(b"contentdivergent()"),
+ b"phasedivergent": repo.revs(b"phasedivergent()"),
+ b"all": repo.revs(b"unstable()"),
}
hintmap = {
- 'phasedivergent': _("do you want to use --phase-divergent"),
- 'phasedivergent+contentdivergent': _("do you want to use "
- "--phase-divergent or"
- " --content-divergent"),
- 'phasedivergent+orphan': _("do you want to use --phase-divergent"
- " or --orphan"),
- 'contentdivergent': _("do you want to use --content-divergent"),
- 'contentdivergent+orphan': _("do you want to use --content-divergent"
- " or --orphan"),
- 'orphan': _("do you want to use --orphan"),
- 'any+phasedivergent': _("do you want to use --any (or --rev) and"
- " --phase-divergent"),
- 'any+phasedivergent+contentdivergent': _("do you want to use --any"
- " (or --rev) and"
- " --phase-divergent or"
- " --content-divergent"),
- 'any+phasedivergent+orphan': _("do you want to use --any (or --rev)"
- " and --phase-divergent or --orphan"),
- 'any+contentdivergent': _("do you want to use --any (or --rev) and"
- " --content-divergent"),
- 'any+contentdivergent+orphan': _("do you want to use --any (or --rev)"
- " and --content-divergent or "
- "--orphan"),
- 'any+orphan': _("do you want to use --any (or --rev)"
- "and --orphan"),
+ b'phasedivergent': _(b"do you want to use --phase-divergent"),
+ b'phasedivergent+contentdivergent': _(b"do you want to use "
+ b"--phase-divergent or"
+ b" --content-divergent"),
+ b'phasedivergent+orphan': _(b"do you want to use --phase-divergent"
+ b" or --orphan"),
+ b'contentdivergent': _(b"do you want to use --content-divergent"),
+ b'contentdivergent+orphan': _(b"do you want to use --content-divergent"
+ b" or --orphan"),
+ b'orphan': _(b"do you want to use --orphan"),
+ b'any+phasedivergent': _(b"do you want to use --any (or --rev) and"
+ b" --phase-divergent"),
+ b'any+phasedivergent+contentdivergent': _(b"do you want to use --any"
+ b" (or --rev) and"
+ b" --phase-divergent or"
+ b" --content-divergent"),
+ b'any+phasedivergent+orphan': _(b"do you want to use --any (or --rev)"
+ b" and --phase-divergent or --orphan"),
+ b'any+contentdivergent': _(b"do you want to use --any (or --rev) and"
+ b" --content-divergent"),
+ b'any+contentdivergent+orphan': _(b"do you want to use --any (or --rev)"
+ b" and --content-divergent or "
+ b"--orphan"),
+ b'any+orphan': _(b"do you want to use --any (or --rev)"
+ b"and --orphan"),
}
if revopt:
revs = scmutil.revrange(repo, revopt)
if not revs:
- msg = _("set of specified revisions is empty")
+ msg = _(b"set of specified revisions is empty")
else:
- msg = _("no %s changesets in specified revisions") % targetcat
+ msg = _(b"no %s changesets in specified revisions") % targetcat
othertroubles = []
for cat in unselectedcategories:
if revs & troubled[cat]:
othertroubles.append(cat)
if othertroubles:
- hint = hintmap['+'.join(othertroubles)]
+ hint = hintmap[b'+'.join(othertroubles)]
elif anyopt:
- msg = _("no %s changesets to evolve") % targetcat
+ msg = _(b"no %s changesets to evolve") % targetcat
othertroubles = []
for cat in unselectedcategories:
if troubled[cat]:
othertroubles.append(cat)
if othertroubles:
- hint = hintmap['+'.join(othertroubles)]
+ hint = hintmap[b'+'.join(othertroubles)]
else:
# evolve without any option = relative to the current wdir
- if targetcat == 'orphan':
- msg = _("nothing to evolve on current working copy parent")
+ if targetcat == b'orphan':
+ msg = _(b"nothing to evolve on current working copy parent")
else:
- msg = _("current working copy parent is not %s") % targetcat
+ msg = _(b"current working copy parent is not %s") % targetcat
- p1 = repo['.'].rev()
+ p1 = repo[b'.'].rev()
othertroubles = []
for cat in unselectedcategories:
if p1 in troubled[cat]:
othertroubles.append(cat)
if othertroubles:
- hint = hintmap['+'.join(othertroubles)]
+ hint = hintmap[b'+'.join(othertroubles)]
else:
length = len(troubled[targetcat])
if length:
- hint = _("%d other %s in the repository, do you want --any "
- "or --rev") % (length, targetcat)
+ hint = _(b"%d other %s in the repository, do you want --any "
+ b"or --rev") % (length, targetcat)
else:
othertroubles = []
for cat in unselectedcategories:
if troubled[cat]:
othertroubles.append(cat)
if othertroubles:
- hint = hintmap['any+' + ('+'.join(othertroubles))]
+ hint = hintmap[b'any+' + (b'+'.join(othertroubles))]
else:
- msg = _("no troubled changesets")
+ msg = _(b"no troubled changesets")
# Exit with a 0 (success) status in this case.
retoverride = 0
assert msg is not None
- ui.write_err("%s\n" % msg)
+ ui.write_err(b"%s\n" % msg)
if hint:
- ui.write_err("(%s)\n" % hint)
+ ui.write_err(b"(%s)\n" % hint)
ret = 2
else:
ret = 1
@@ -1308,21 +1300,21 @@
def listtroubles(ui, repo, troublecategories, **opts):
"""Print all the troubles for the repo (or given revset)"""
- troublecategories = troublecategories or ['contentdivergent', 'orphan', 'phasedivergent']
- showunstable = 'orphan' in troublecategories
- showbumped = 'phasedivergent' in troublecategories
- showdivergent = 'contentdivergent' in troublecategories
+ troublecategories = troublecategories or [b'contentdivergent', b'orphan', b'phasedivergent']
+ showunstable = b'orphan' in troublecategories
+ showbumped = b'phasedivergent' in troublecategories
+ showdivergent = b'contentdivergent' in troublecategories
- revs = repo.revs('+'.join("%s()" % t for t in troublecategories))
+ revs = repo.revs(b'+'.join(b"%s()" % t for t in troublecategories))
if opts.get('rev'):
revs = scmutil.revrange(repo, opts.get('rev'))
- fm = ui.formatter('evolvelist', pycompat.byteskwargs(opts))
+ fm = ui.formatter(b'evolvelist', pycompat.byteskwargs(opts))
for rev in revs:
ctx = repo[rev]
unpars = _preparelistctxs(ctx.parents(), lambda p: p.orphan())
obspars = _preparelistctxs(ctx.parents(), lambda p: p.obsolete())
- imprecs = _preparelistctxs(repo.set("allpredecessors(%n)", ctx.node()),
+ imprecs = _preparelistctxs(repo.set(b"allpredecessors(%n)", ctx.node()),
lambda p: not p.mutable())
dsets = divergentsets(repo, ctx)
@@ -1332,55 +1324,55 @@
desc = ctx.description()
if desc:
desc = desc.splitlines()[0]
- desc = (desc[:desclen] + '...') if len(desc) > desclen else desc
- fm.plain('%s: ' % ctx.hex()[:hashlen])
- fm.plain('%s\n' % desc)
+ desc = (desc[:desclen] + b'...') if len(desc) > desclen else desc
+ fm.plain(b'%s: ' % ctx.hex()[:hashlen])
+ fm.plain(b'%s\n' % desc)
fm.data(node=ctx.hex(), rev=ctx.rev(), desc=desc, phase=ctx.phasestr())
for unpar in unpars if showunstable else []:
- fm.plain(' %s: %s (%s parent)\n' % (TROUBLES['ORPHAN'],
- unpar[:hashlen],
- TROUBLES['ORPHAN']))
+ fm.plain(b' %s: %s (%s parent)\n' % (TROUBLES['ORPHAN'],
+ unpar[:hashlen],
+ TROUBLES['ORPHAN']))
for obspar in obspars if showunstable else []:
- fm.plain(' %s: %s (obsolete parent)\n' % (TROUBLES['ORPHAN'],
- obspar[:hashlen]))
+ fm.plain(b' %s: %s (obsolete parent)\n' % (TROUBLES['ORPHAN'],
+ obspar[:hashlen]))
for imprec in imprecs if showbumped else []:
- fm.plain(' %s: %s (immutable precursor)\n' %
+ fm.plain(b' %s: %s (immutable precursor)\n' %
(TROUBLES['PHASEDIVERGENT'], imprec[:hashlen]))
if dsets and showdivergent:
for dset in dsets:
- fm.plain(' %s: ' % TROUBLES['CONTENTDIVERGENT'])
+ fm.plain(b' %s: ' % TROUBLES['CONTENTDIVERGENT'])
first = True
- for n in dset['divergentnodes']:
- t = "%s (%s)" if first else " %s (%s)"
+ for n in dset[b'divergentnodes']:
+ t = b"%s (%s)" if first else b" %s (%s)"
first = False
fm.plain(t % (nodemod.hex(n)[:hashlen], repo[n].phasestr()))
- comprec = nodemod.hex(dset['commonprecursor'])[:hashlen]
- fm.plain(" (precursor %s)\n" % comprec)
- fm.plain("\n")
+ comprec = nodemod.hex(dset[b'commonprecursor'])[:hashlen]
+ fm.plain(b" (precursor %s)\n" % comprec)
+ fm.plain(b"\n")
# templater-friendly section
_formatctx(fm, ctx)
troubles = []
for unpar in unpars:
- troubles.append({'troubletype': TROUBLES['ORPHAN'],
- 'sourcenode': unpar, 'sourcetype': 'orphanparent'})
+ troubles.append({b'troubletype': TROUBLES['ORPHAN'],
+ b'sourcenode': unpar, b'sourcetype': b'orphanparent'})
for obspar in obspars:
- troubles.append({'troubletype': TROUBLES['ORPHAN'],
- 'sourcenode': obspar,
- 'sourcetype': 'obsoleteparent'})
+ troubles.append({b'troubletype': TROUBLES['ORPHAN'],
+ b'sourcenode': obspar,
+ b'sourcetype': b'obsoleteparent'})
for imprec in imprecs:
- troubles.append({'troubletype': TROUBLES['PHASEDIVERGENT'],
- 'sourcenode': imprec,
- 'sourcetype': 'immutableprecursor'})
+ troubles.append({b'troubletype': TROUBLES['PHASEDIVERGENT'],
+ b'sourcenode': imprec,
+ b'sourcetype': b'immutableprecursor'})
for dset in dsets:
- divnodes = [{'node': nodemod.hex(n),
- 'phase': repo[n].phasestr(),
- } for n in dset['divergentnodes']]
- troubles.append({'troubletype': TROUBLES['CONTENTDIVERGENT'],
- 'commonprecursor': nodemod.hex(dset['commonprecursor']),
- 'divergentnodes': divnodes})
+ divnodes = [{b'node': nodemod.hex(n),
+ b'phase': repo[n].phasestr(),
+ } for n in dset[b'divergentnodes']]
+ troubles.append({b'troubletype': TROUBLES['CONTENTDIVERGENT'],
+ b'commonprecursor': nodemod.hex(dset[b'commonprecursor']),
+ b'divergentnodes': divnodes})
fm.data(troubles=troubles)
fm.end()
@@ -1391,61 +1383,61 @@
if opts['continue']:
if opts['any']:
- raise error.Abort(_('cannot specify both "--any" and "--continue"'))
+ raise error.Abort(_(b'cannot specify both "--any" and "--continue"'))
if opts['all']:
- raise error.Abort(_('cannot specify both "--all" and "--continue"'))
+ raise error.Abort(_(b'cannot specify both "--all" and "--continue"'))
if opts['rev']:
- raise error.Abort(_('cannot specify both "--rev" and "--continue"'))
+ raise error.Abort(_(b'cannot specify both "--rev" and "--continue"'))
if opts['stop']:
- raise error.Abort(_('cannot specify both "--stop" and'
- ' "--continue"'))
+ raise error.Abort(_(b'cannot specify both "--stop" and'
+ b' "--continue"'))
if opts['abort']:
- raise error.Abort(_('cannot specify both "--abort" and'
- ' "--continue"'))
+ raise error.Abort(_(b'cannot specify both "--abort" and'
+ b' "--continue"'))
if opts['stop']:
if opts['any']:
- raise error.Abort(_('cannot specify both "--any" and "--stop"'))
+ raise error.Abort(_(b'cannot specify both "--any" and "--stop"'))
if opts['all']:
- raise error.Abort(_('cannot specify both "--all" and "--stop"'))
+ raise error.Abort(_(b'cannot specify both "--all" and "--stop"'))
if opts['rev']:
- raise error.Abort(_('cannot specify both "--rev" and "--stop"'))
+ raise error.Abort(_(b'cannot specify both "--rev" and "--stop"'))
if opts['abort']:
- raise error.Abort(_('cannot specify both "--abort" and "--stop"'))
+ raise error.Abort(_(b'cannot specify both "--abort" and "--stop"'))
if opts['abort']:
if opts['any']:
- raise error.Abort(_('cannot specify both "--any" and "--abort"'))
+ raise error.Abort(_(b'cannot specify both "--any" and "--abort"'))
if opts['all']:
- raise error.Abort(_('cannot specify both "--all" and "--abort"'))
+ raise error.Abort(_(b'cannot specify both "--all" and "--abort"'))
if opts['rev']:
- raise error.Abort(_('cannot specify both "--rev" and "--abort"'))
+ raise error.Abort(_(b'cannot specify both "--rev" and "--abort"'))
if opts['rev']:
if opts['any']:
- raise error.Abort(_('cannot specify both "--rev" and "--any"'))
+ raise error.Abort(_(b'cannot specify both "--rev" and "--any"'))
if opts['all']:
- raise error.Abort(_('cannot specify both "--rev" and "--all"'))
+ raise error.Abort(_(b'cannot specify both "--rev" and "--all"'))
# Backward compatibility
if opts['unstable']:
- msg = ("'evolve --unstable' is deprecated, "
- "use 'evolve --orphan'")
- repo.ui.deprecwarn(msg, '4.4')
+ msg = (b"'evolve --unstable' is deprecated, "
+ b"use 'evolve --orphan'")
+ repo.ui.deprecwarn(msg, b'4.4')
opts['orphan'] = opts['divergent']
if opts['divergent']:
- msg = ("'evolve --divergent' is deprecated, "
- "use 'evolve --content-divergent'")
- repo.ui.deprecwarn(msg, '4.4')
+ msg = (b"'evolve --divergent' is deprecated, "
+ b"use 'evolve --content-divergent'")
+ repo.ui.deprecwarn(msg, b'4.4')
opts['content_divergent'] = opts['divergent']
if opts['bumped']:
- msg = ("'evolve --bumped' is deprecated, "
- "use 'evolve --phase-divergent'")
- repo.ui.deprecwarn(msg, '4.4')
+ msg = (b"'evolve --bumped' is deprecated, "
+ b"use 'evolve --phase-divergent'")
+ repo.ui.deprecwarn(msg, b'4.4')
opts['phase_divergent'] = opts['bumped']
@@ -1458,8 +1450,8 @@
unfi = repo.unfiltered()
succ = utility._singlesuccessor(repo, unfi[startnode])
hg.updaterepo(repo, repo[succ].node(), False)
- if repo['.'].node() != startnode:
- ui.status(_('working directory is now at %s\n') % repo['.'])
+ if repo[b'.'].node() != startnode:
+ ui.status(_(b'working directory is now at %s\n') % repo[b'.'])
def divergentsets(repo, ctx):
"""Compute sets of commits divergent with a given one"""
@@ -1481,38 +1473,38 @@
divergence = []
for divset, b in base.items():
divergence.append({
- 'divergentnodes': divset,
- 'commonprecursor': b
+ b'divergentnodes': divset,
+ b'commonprecursor': b
})
return divergence
@eh.command(
- 'evolve|stabilize|solve',
- [('n', 'dry-run', False,
- _('do not perform actions, just print what would be done')),
- ('', 'confirm', False,
- _('ask for confirmation before performing the action')),
- ('A', 'any', False,
- _('also consider troubled changesets unrelated to current working '
- 'directory')),
- ('r', 'rev', [], _('solves troubles of these revisions'), _('REV')),
- ('', 'bumped', False, _('solves only bumped changesets (DEPRECATED)')),
- ('', 'phase-divergent', False, _('solves only phase-divergent changesets')),
- ('', 'divergent', False, _('solves only divergent changesets (DEPRECATED)')),
- ('', 'content-divergent', False, _('solves only content-divergent changesets')),
- ('', 'unstable', False, _('solves only unstable changesets (DEPRECATED)')),
- ('', 'orphan', False, _('solves only orphan changesets (default)')),
- ('a', 'all', None, _('evolve all troubled changesets related to the current'
- ' working directory and its descendants (default)')),
- ('', 'update', False, _('update to the head of evolved changesets')),
- ('c', 'continue', False, _('continue an interrupted evolution')),
- ('', 'stop', False, _('stop the interrupted evolution')),
- ('', 'abort', False, _('abort the interrupted evolution')),
- ('l', 'list', False, _('provide details on troubled changesets'
- ' in the repo')),
- ] + mergetoolopts,
- _('[OPTIONS]...'),
+ b'evolve|stabilize|solve',
+ [(b'n', b'dry-run', False,
+ _(b'do not perform actions, just print what would be done')),
+ (b'', b'confirm', False,
+ _(b'ask for confirmation before performing the action')),
+ (b'A', b'any', False,
+ _(b'also consider troubled changesets unrelated to current working '
+ b'directory')),
+ (b'r', b'rev', [], _(b'solves troubles of these revisions'), _(b'REV')),
+ (b'', b'bumped', False, _(b'solves only bumped changesets (DEPRECATED)')),
+ (b'', b'phase-divergent', False, _(b'solves only phase-divergent changesets')),
+ (b'', b'divergent', False, _(b'solves only divergent changesets (DEPRECATED)')),
+ (b'', b'content-divergent', False, _(b'solves only content-divergent changesets')),
+ (b'', b'unstable', False, _(b'solves only unstable changesets (DEPRECATED)')),
+ (b'', b'orphan', False, _(b'solves only orphan changesets (default)')),
+ (b'a', b'all', None, _(b'evolve all troubled changesets related to the current'
+ b' working directory and its descendants (default)')),
+ (b'', b'update', False, _(b'update to the head of evolved changesets')),
+ (b'c', b'continue', False, _(b'continue an interrupted evolution')),
+ (b'', b'stop', False, _(b'stop the interrupted evolution')),
+ (b'', b'abort', False, _(b'abort the interrupted evolution')),
+ (b'l', b'list', False, _(b'provide details on troubled changesets'
+ b' in the repo')),
+ ] + mergetoolopts,
+ _(b'[OPTIONS]...'),
helpbasic=True
)
def evolve(ui, repo, **opts):
@@ -1607,7 +1599,10 @@
aborts the interrupted evolve and undoes all the resolution which have
happened
"""
+ with repo.wlock(), repo.lock():
+ return _performevolve(ui, repo, **opts)
+def _performevolve(ui, repo, **opts):
opts = _checkevolveopts(repo, opts)
# Options
contopt = opts['continue']
@@ -1615,7 +1610,7 @@
allopt = opts['all']
if allopt is None:
allopt = True
- startnode = repo['.'].node()
+ startnode = repo[b'.'].node()
dryrunopt = opts['dry_run']
confirmopt = opts['confirm']
revopt = opts['rev']
@@ -1624,56 +1619,56 @@
shouldupdate = opts['update']
troublecategories = {
- 'phasedivergent': 'phase_divergent',
- 'contentdivergent': 'content_divergent',
- 'orphan': 'orphan',
+ b'phasedivergent': r'phase_divergent',
+ b'contentdivergent': r'content_divergent',
+ b'orphan': r'orphan',
}
specifiedcategories = [k for k, v in troublecategories.items() if opts[v]]
if opts['list']:
- ui.pager('evolve')
+ ui.pager(b'evolve')
listtroubles(ui, repo, specifiedcategories, **opts)
return
- targetcat = 'orphan'
+ targetcat = b'orphan'
if 1 < len(specifiedcategories):
- msg = _('cannot specify more than one trouble category to solve (yet)')
+ msg = _(b'cannot specify more than one trouble category to solve (yet)')
raise error.Abort(msg)
elif len(specifiedcategories) == 1:
targetcat = specifiedcategories[0]
- ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve')
+ ui.setconfig(b'ui', b'forcemerge', opts.get('tool', r''), b'evolve')
evolvestate = state.cmdstate(repo)
# Continuation handling
if contopt:
if not evolvestate:
- raise error.Abort(_('no interrupted evolve to continue'))
+ raise error.Abort(_(b'no interrupted evolve to continue'))
evolvestate.load()
continueevolve(ui, repo, evolvestate)
- if evolvestate['command'] != 'evolve':
+ if evolvestate[b'command'] != b'evolve':
evolvestate.delete()
return
- startnode = repo.unfiltered()[evolvestate['startnode']]
- if 'update' in evolvestate:
- shouldupdate = evolvestate['update']
+ startnode = repo.unfiltered()[evolvestate[b'startnode']]
+ if b'update' in evolvestate:
+ shouldupdate = evolvestate[b'update']
evolvestate.delete()
elif stopopt:
if not evolvestate:
- raise error.Abort(_('no interrupted evolve to stop'))
+ raise error.Abort(_(b'no interrupted evolve to stop'))
evolvestate.load()
stopevolve(ui, repo, evolvestate)
evolvestate.delete()
return
elif abortopt:
if not evolvestate:
- raise error.Abort(_('no interrupted evolve to abort'))
+ raise error.Abort(_(b'no interrupted evolve to abort'))
evolvestate.load()
# `hg next --evolve` in play
- if evolvestate['command'] != 'evolve':
- pctx = repo['.']
+ if evolvestate[b'command'] != b'evolve':
+ pctx = repo[b'.']
hg.updaterepo(repo, pctx.node(), True)
- ui.status(_('evolve aborted\n'))
- ui.status(_('working directory is now at %s\n')
+ ui.status(_(b'evolve aborted\n'))
+ ui.status(_(b'working directory is now at %s\n')
% pctx.hex()[:12])
evolvestate.delete()
return 0
@@ -1681,7 +1676,7 @@
else:
cmdutil.bailifchanged(repo)
- obswdir = repo['.'].obsolete()
+ obswdir = repo[b'.'].obsolete()
revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat)
if not (revs or obswdir):
@@ -1703,37 +1698,36 @@
def progresscb():
if showprogress:
- compat.progress(ui, _('evolve'), seen, unit=_('changesets'),
+ compat.progress(ui, _(b'evolve'), seen, unit=_(b'changesets'),
total=count)
# Order the revisions
revs = _orderrevs(repo, revs)
# cbor does not know how to serialize sets, using list for skippedrevs
- stateopts = {'category': targetcat, 'replacements': {},
- 'revs': list(revs), 'confirm': confirmopt,
- 'startnode': startnode, 'skippedrevs': [],
- 'command': 'evolve', 'orphanmerge': False,
- 'bookmarkchanges': [], 'temprevs': [], 'obsmarkers': [],
- 'update': shouldupdate}
+ stateopts = {b'category': targetcat, b'replacements': {},
+ b'revs': list(revs), b'confirm': confirmopt,
+ b'startnode': startnode, b'skippedrevs': [],
+ b'command': b'evolve', b'orphanmerge': False,
+ b'bookmarkchanges': [], b'temprevs': [], b'obsmarkers': [],
+ b'update': shouldupdate}
evolvestate.addopts(stateopts)
# lastsolved: keep track of successor of last troubled cset we evolved
# to confirm that if atop msg should be suppressed to remove redundancy
lastsolved = None
- activetopic = getattr(repo, 'currenttopic', '')
- with repo.wlock(), repo.lock():
- tr = repo.transaction("evolve")
- with util.acceptintervention(tr):
- for rev in revs:
- lastsolved = _solveonerev(ui, repo, rev, evolvestate,
- activetopic, dryrunopt,
- confirmopt, progresscb,
- targetcat, lastsolved)
- seen += 1
+ activetopic = getattr(repo, 'currenttopic', b'')
+ tr = repo.transaction(b"evolve")
+ with util.acceptintervention(tr):
+ for rev in revs:
+ lastsolved = _solveonerev(ui, repo, rev, evolvestate,
+ activetopic, dryrunopt,
+ confirmopt, progresscb,
+ targetcat, lastsolved)
+ seen += 1
if showprogress:
- compat.progress(ui, _('evolve'), None)
+ compat.progress(ui, _(b'evolve'), None)
_cleanup(ui, repo, startnode, shouldupdate)
@@ -1745,7 +1739,7 @@
stabilizes for both parents of orphan merges.
"""
curctx = repo[rev]
- revtopic = getattr(curctx, 'topic', lambda: '')()
+ revtopic = getattr(curctx, 'topic', lambda: b'')()
topicidx = getattr(curctx, 'topicidx', lambda: None)()
stacktmplt = False
# check if revision being evolved is in active topic to make sure
@@ -1757,44 +1751,44 @@
confirmopt, progresscb, targetcat,
lastsolved=lastsolved, stacktmplt=stacktmplt)
if ret[0]:
- evolvestate['replacements'][curctx.node()] = ret[1]
+ evolvestate[b'replacements'][curctx.node()] = ret[1]
lastsolved = ret[1]
else:
- evolvestate['skippedrevs'].append(curctx.node())
+ evolvestate[b'skippedrevs'].append(curctx.node())
- if evolvestate['orphanmerge']:
+ if evolvestate[b'orphanmerge']:
# we were processing an orphan merge with both parents obsolete,
# stabilized for second parent, re-stabilize for the first parent
ret = _solveone(ui, repo, repo[ret[1]], evolvestate, dryrunopt,
confirmopt, progresscb, targetcat,
stacktmplt=stacktmplt)
if ret[0]:
- evolvestate['replacements'][curctx.node()] = ret[1]
+ evolvestate[b'replacements'][curctx.node()] = ret[1]
lastsolved = ret[1]
else:
- evolvestate['skippedrevs'].append(curctx.node())
+ evolvestate[b'skippedrevs'].append(curctx.node())
- evolvestate['orphanmerge'] = False
+ evolvestate[b'orphanmerge'] = False
return lastsolved
def solveobswdp(ui, repo, opts):
"""this function updates to the successor of obsolete wdir parent"""
- oldid = repo['.'].node()
- startctx = repo['.']
+ oldid = repo[b'.'].node()
+ startctx = repo[b'.']
dryrunopt = opts.get('dry_run', False)
displayer = compat.changesetdisplayer(ui, repo,
- {'template': shorttemplate})
+ {b'template': shorttemplate})
try:
- ctx = repo[utility._singlesuccessor(repo, repo['.'])]
+ ctx = repo[utility._singlesuccessor(repo, repo[b'.'])]
except utility.MultipleSuccessorsError as exc:
- repo.ui.write_err(_('parent is obsolete with multiple'
- ' successors:\n'))
+ repo.ui.write_err(_(b'parent is obsolete with multiple'
+ b' successors:\n'))
for ln in exc.successorssets:
for n in ln:
displayer.show(repo[n])
return 2
- ui.status(_('update:'))
+ ui.status(_(b'update:'))
if not ui.quiet:
displayer.show(ctx)
@@ -1804,33 +1798,33 @@
newid = ctx.node()
if ctx != startctx:
- with repo.wlock(), repo.lock(), repo.transaction('evolve') as tr:
+ with repo.wlock(), repo.lock(), repo.transaction(b'evolve') as tr:
bmupdater = rewriteutil.bookmarksupdater(repo, oldid, tr)
bmupdater(newid)
- ui.status(_('working directory is now at %s\n') % ctx)
+ ui.status(_(b'working directory is now at %s\n') % ctx)
return res
def stopevolve(ui, repo, evolvestate):
"""logic for handling of `hg evolve --stop`"""
updated = False
pctx = None
- if (evolvestate['command'] == 'evolve'
- and evolvestate['category'] == 'contentdivergent'
- and evolvestate['relocated']):
- oldother = evolvestate['old-other']
+ if (evolvestate[b'command'] == b'evolve'
+ and evolvestate[b'category'] == b'contentdivergent'
+ and evolvestate[b'relocated']):
+ oldother = evolvestate[b'old-other']
if oldother:
with repo.wlock(), repo.lock():
repo = repo.unfiltered()
hg.updaterepo(repo, oldother, True)
- strips = [evolvestate['relocated']]
+ strips = [evolvestate[b'relocated']]
repair.strip(ui, repo, strips, False)
updated = True
pctx = repo[oldother]
if not updated:
- pctx = repo['.']
+ pctx = repo[b'.']
hg.updaterepo(repo, pctx.node(), True)
- ui.status(_('stopped the interrupted evolve\n'))
- ui.status(_('working directory is now at %s\n') % pctx)
+ ui.status(_(b'stopped the interrupted evolve\n'))
+ ui.status(_(b'working directory is now at %s\n') % pctx)
def abortevolve(ui, repo, evolvestate):
""" logic for handling of `hg evolve --abort`"""
@@ -1840,11 +1834,11 @@
evolvedctx = []
# boolean value to say whether we should strip or not
cleanup = True
- startnode = evolvestate['startnode']
- for old, new in evolvestate['replacements'].items():
+ startnode = evolvestate[b'startnode']
+ for old, new in evolvestate[b'replacements'].items():
if new:
evolvedctx.append(repo[new])
- for temp in evolvestate['temprevs']:
+ for temp in evolvestate[b'temprevs']:
if temp:
evolvedctx.append(repo[temp])
evolvedrevs = [c.rev() for c in evolvedctx]
@@ -1852,145 +1846,159 @@
# checking if phase changed of any of the evolved rev
immutable = [c for c in evolvedctx if not c.mutable()]
if immutable:
- repo.ui.warn(_("cannot clean up public changesets: %s\n")
- % ', '.join(bytes(c) for c in immutable),
- hint=_("see 'hg help phases' for details"))
- cleanup = False
-
- # checking no new changesets are created on evolved revs
- descendants = set()
- if evolvedrevs:
- descendants = set(repo.changelog.descendants(evolvedrevs))
- if descendants - set(evolvedrevs):
- repo.ui.warn(_("warning: new changesets detected on destination "
- "branch\n"))
+ repo.ui.warn(_(b"cannot clean up public changesets: %s\n")
+ % b', '.join(bytes(c) for c in immutable),
+ hint=_(b"see 'hg help phases' for details"))
cleanup = False
- # finding the indices of the obsmarkers to be stripped and stripping
- # them
- if evolvestate['obsmarkers']:
- stripmarkers = set()
- for m in evolvestate['obsmarkers']:
- m = (m[0], m[1])
- stripmarkers.add(m)
- indices = []
- allmarkers = obsutil.getmarkers(repo)
- for i, m in enumerate(allmarkers):
- marker = (m.prednode(), m.succnodes()[0])
- if marker in stripmarkers:
- indices.append(i)
+ # checking no new changesets are created on evolved revs
+ descendants = set()
+ if evolvedrevs:
+ descendants = set(repo.changelog.descendants(evolvedrevs))
+ if descendants - set(evolvedrevs):
+ repo.ui.warn(_(b"warning: new changesets detected on destination "
+ b"branch\n"))
+ cleanup = False
- repair.deleteobsmarkers(repo.obsstore, indices)
- repo.ui.debug('deleted %d obsmarkers\n' % len(indices))
+ # finding the indices of the obsmarkers to be stripped and stripping
+ # them
+ if evolvestate[b'obsmarkers']:
+ stripmarkers = set()
+ for m in evolvestate[b'obsmarkers']:
+ m = (m[0], m[1])
+ stripmarkers.add(m)
+ indices = []
+ allmarkers = obsutil.getmarkers(repo)
+ for i, m in enumerate(allmarkers):
+ marker = (m.prednode(), m.succnodes()[0])
+ if marker in stripmarkers:
+ indices.append(i)
- if cleanup:
- if evolvedrevs:
- strippoints = [c.node()
- for c in repo.set('roots(%ld)', evolvedrevs)]
+ repair.deleteobsmarkers(repo.obsstore, indices)
+ repo.ui.debug(b'deleted %d obsmarkers\n' % len(indices))
+
+ if cleanup:
+ if evolvedrevs:
+ strippoints = [c.node()
+ for c in repo.set(b'roots(%ld)', evolvedrevs)]
+
+ # updating the working directory
+ hg.updaterepo(repo, startnode, True)
- # updating the working directory
- hg.updaterepo(repo, startnode, True)
+ # Strip from the first evolved revision
+ if evolvedrevs:
+ # no backup of evolved cset versions needed
+ repair.strip(repo.ui, repo, strippoints, False)
- # Strip from the first evolved revision
- if evolvedrevs:
- # no backup of evolved cset versions needed
- repair.strip(repo.ui, repo, strippoints, False)
+ with repo.transaction(b'evolve') as tr:
+ # restoring bookmarks at there original place
+ bmchanges = evolvestate[b'bookmarkchanges']
+ if bmchanges:
+ repo._bookmarks.applychanges(repo, tr, bmchanges)
- with repo.transaction('evolve') as tr:
- # restoring bookmarks at there original place
- bmchanges = evolvestate['bookmarkchanges']
- if bmchanges:
- repo._bookmarks.applychanges(repo, tr, bmchanges)
+ evolvestate.delete()
+ ui.status(_(b'evolve aborted\n'))
+ ui.status(_(b'working directory is now at %s\n')
+ % nodemod.hex(startnode)[:12])
+ else:
+ raise error.Abort(_(b"unable to abort interrupted evolve, use 'hg "
+ b"evolve --stop' to stop evolve"))
+def hgabortevolve(ui, repo):
+ """logic for aborting evolve using 'hg abort'"""
+ with repo.wlock(), repo.lock():
+ evolvestate = state.cmdstate(repo)
+ evolvestate.load()
+ if evolvestate[b'command'] != b'evolve':
+ pctx = repo[b'.']
+ hg.updaterepo(repo, pctx.node(), True)
+ ui.status(_(b'evolve aborted\n'))
+ ui.status(_(b'working directory is now at %s\n')
+ % pctx.hex()[:12])
evolvestate.delete()
- ui.status(_('evolve aborted\n'))
- ui.status(_('working directory is now at %s\n')
- % nodemod.hex(startnode)[:12])
- else:
- raise error.Abort(_("unable to abort interrupted evolve, use 'hg "
- "evolve --stop' to stop evolve"))
+ return 0
+ return abortevolve(ui, repo, evolvestate)
def continueevolve(ui, repo, evolvestate):
"""logic for handling of `hg evolve --continue`"""
- with repo.wlock(), repo.lock():
- ms = merge.mergestate.read(repo)
- mergeutil.checkunresolved(ms)
- if (evolvestate['command'] == 'next'
- or evolvestate['category'] == 'orphan'):
- _completeorphan(ui, repo, evolvestate)
- elif evolvestate['category'] == 'phasedivergent':
- _completephasedivergent(ui, repo, evolvestate)
- elif evolvestate['category'] == 'contentdivergent':
- _continuecontentdivergent(ui, repo, evolvestate, None)
- else:
- repo.ui.status(_("continuing interrupted '%s' resolution is not yet"
- " supported\n") % evolvestate['category'])
- return
+ ms = merge.mergestate.read(repo)
+ mergeutil.checkunresolved(ms)
+ if (evolvestate[b'command'] == b'next'
+ or evolvestate[b'category'] == b'orphan'):
+ _completeorphan(ui, repo, evolvestate)
+ elif evolvestate[b'category'] == b'phasedivergent':
+ _completephasedivergent(ui, repo, evolvestate)
+ elif evolvestate[b'category'] == b'contentdivergent':
+ _continuecontentdivergent(ui, repo, evolvestate, None)
+ else:
+ repo.ui.status(_(b"continuing interrupted '%s' resolution is not yet"
+ b" supported\n") % evolvestate[b'category'])
+ return
- # make sure we are continuing evolve and not `hg next --evolve`
- if evolvestate['command'] != 'evolve':
- return
+ # make sure we are continuing evolve and not `hg next --evolve`
+ if evolvestate[b'command'] != b'evolve':
+ return
- # Progress handling
- seen = 1
- count = len(evolvestate['revs'])
+ # Progress handling
+ seen = 1
+ count = len(evolvestate[b'revs'])
- def progresscb():
- compat.progress(ui, _('evolve'), seen, unit=_('changesets'),
- total=count)
+ def progresscb():
+ compat.progress(ui, _(b'evolve'), seen, unit=_(b'changesets'),
+ total=count)
- category = evolvestate['category']
- confirm = evolvestate['confirm']
- unfi = repo.unfiltered()
- # lastsolved: keep track of successor of last troubled cset we
- # evolved to confirm that if atop msg should be suppressed to remove
- # redundancy
- lastsolved = None
- activetopic = getattr(repo, 'currenttopic', '')
- tr = repo.transaction("evolve")
- with util.acceptintervention(tr):
- for rev in evolvestate['revs']:
- # XXX: prevent this lookup by storing nodes instead of revnums
- curctx = unfi[rev]
+ category = evolvestate[b'category']
+ confirm = evolvestate[b'confirm']
+ unfi = repo.unfiltered()
+ # lastsolved: keep track of successor of last troubled cset we
+ # evolved to confirm that if atop msg should be suppressed to remove
+ # redundancy
+ lastsolved = None
+ activetopic = getattr(repo, 'currenttopic', b'')
+ tr = repo.transaction(b"evolve")
+ with util.acceptintervention(tr):
+ for rev in evolvestate[b'revs']:
+ # XXX: prevent this lookup by storing nodes instead of revnums
+ curctx = unfi[rev]
- # check if we can use stack template
- revtopic = getattr(curctx, 'topic', lambda: '')()
- topicidx = getattr(curctx, 'topicidx', lambda: None)()
- stacktmplt = False
- if (activetopic and (activetopic == revtopic)
- and topicidx is not None):
- stacktmplt = True
+ # check if we can use stack template
+ revtopic = getattr(curctx, 'topic', lambda: b'')()
+ topicidx = getattr(curctx, 'topicidx', lambda: None)()
+ stacktmplt = False
+ if (activetopic and (activetopic == revtopic)
+ and topicidx is not None):
+ stacktmplt = True
- if (curctx.node() not in evolvestate['replacements']
- and curctx.node() not in evolvestate['skippedrevs']):
- newnode = _solveone(ui, repo, curctx, evolvestate, False,
- confirm, progresscb, category,
- lastsolved=lastsolved,
- stacktmplt=stacktmplt)
- if newnode[0]:
- evolvestate['replacements'][curctx.node()] = newnode[1]
- lastsolved = newnode[1]
- else:
- evolvestate['skippedrevs'].append(curctx.node())
- seen += 1
+ if (curctx.node() not in evolvestate[b'replacements']
+ and curctx.node() not in evolvestate[b'skippedrevs']):
+ newnode = _solveone(ui, repo, curctx, evolvestate, False,
+ confirm, progresscb, category,
+ lastsolved=lastsolved,
+ stacktmplt=stacktmplt)
+ if newnode[0]:
+ evolvestate[b'replacements'][curctx.node()] = newnode[1]
+ lastsolved = newnode[1]
+ else:
+ evolvestate[b'skippedrevs'].append(curctx.node())
+ seen += 1
def _continuecontentdivergent(ui, repo, evolvestate, progresscb):
"""function to continue the interrupted content-divergence resolution."""
- tr = repo.transaction('evolve')
+ tr = repo.transaction(b'evolve')
with util.acceptintervention(tr):
- divergent = evolvestate['divergent']
- base = evolvestate['base']
+ divergent = evolvestate[b'divergent']
+ base = evolvestate[b'base']
repo = repo.unfiltered()
- if evolvestate['relocating']:
+ if evolvestate[b'relocating']:
newother = _completerelocation(ui, repo, evolvestate)
- current = repo[evolvestate['current']]
+ current = repo[evolvestate[b'current']]
obsolete.createmarkers(repo, [(current, (repo[newother],))],
- operation='evolve')
- evolvestate['relocating'] = False
- evolvestate['relocated'] = newother
- evolvestate['temprevs'].append(newother)
- evolvestate['other-divergent'] = newother
+ operation=b'evolve')
+ evolvestate[b'relocating'] = False
+ evolvestate[b'relocated'] = newother
+ evolvestate[b'temprevs'].append(newother)
+ evolvestate[b'other-divergent'] = newother
# continue the resolution by merging the content-divergence
_mergecontentdivergents(repo, progresscb,
repo[divergent],
@@ -1998,16 +2006,16 @@
repo[base],
evolvestate)
- other = evolvestate['other-divergent']
+ other = evolvestate[b'other-divergent']
ret = _completecontentdivergent(ui, repo, progresscb,
repo[divergent],
repo[other],
repo[base],
evolvestate)
- origdivergent = evolvestate['orig-divergent']
- evolvestate['replacements'][origdivergent] = ret[1]
+ origdivergent = evolvestate[b'orig-divergent']
+ evolvestate[b'replacements'][origdivergent] = ret[1]
# logic to continue the public content-divergent
- publicnode = evolvestate.get('public-divergent')
+ publicnode = evolvestate.get(b'public-divergent')
if publicnode:
res, newnode = ret
if not res:
@@ -2030,19 +2038,19 @@
phase-divergence"""
# need to start transaction for bookmark changes
- with repo.transaction('evolve'):
+ with repo.transaction(b'evolve'):
node = _completerelocation(ui, repo, evolvestate)
- evolvestate['temprevs'].append(node)
+ evolvestate[b'temprevs'].append(node)
# resolving conflicts can lead to empty wdir and node can be None in
# those cases
- ctx = repo[evolvestate['current']]
- newctx = repo[node] if node is not None else repo['.']
- obsolete.createmarkers(repo, [(ctx, (newctx,))], operation='evolve')
+ ctx = repo[evolvestate[b'current']]
+ newctx = repo[node] if node is not None else repo[b'.']
+ obsolete.createmarkers(repo, [(ctx, (newctx,))], operation=b'evolve')
# now continuing the phase-divergence resolution part
- prec = repo[evolvestate['precursor']]
+ prec = repo[evolvestate[b'precursor']]
retvalue = _resolvephasedivergent(ui, repo, prec, newctx)
- evolvestate['replacements'][ctx.node()] = retvalue[1]
+ evolvestate[b'replacements'][ctx.node()] = retvalue[1]
def _completeorphan(ui, repo, evolvestate):
"""function to complete the interrupted orphan resolution"""
@@ -2050,47 +2058,47 @@
node = _completerelocation(ui, repo, evolvestate)
# resolving conflicts can lead to empty wdir and node can be None in
# those cases
- ctx = repo[evolvestate['current']]
+ ctx = repo[evolvestate[b'current']]
if node is None:
- repo.ui.status(_("evolution of %d:%s created no changes"
- " to commit\n") % (ctx.rev(), ctx))
+ repo.ui.status(_(b"evolution of %d:%s created no changes"
+ b" to commit\n") % (ctx.rev(), ctx))
replacement = ()
else:
replacement = (repo[node],)
- obsolete.createmarkers(repo, [(ctx, replacement)], operation='evolve')
+ obsolete.createmarkers(repo, [(ctx, replacement)], operation=b'evolve')
# make sure we are continuing evolve and not `hg next --evolve`
- if evolvestate['command'] == 'evolve':
- evolvestate['replacements'][ctx.node()] = node
- if evolvestate['orphanmerge']:
+ if evolvestate[b'command'] == b'evolve':
+ evolvestate[b'replacements'][ctx.node()] = node
+ if evolvestate[b'orphanmerge']:
# processing a merge changeset with both parents obsoleted,
# stabilized on second parent, insert in front of list to
# re-process to stabilize on first parent
- evolvestate['revs'].insert(0, repo[node].rev())
- evolvestate['orphanmerge'] = False
+ evolvestate[b'revs'].insert(0, repo[node].rev())
+ evolvestate[b'orphanmerge'] = False
def _completerelocation(ui, repo, evolvestate):
"""function to complete the interrupted relocation of a commit
return the new node formed
"""
- orig = repo[evolvestate['current']]
+ orig = repo[evolvestate[b'current']]
ctx = orig
- source = ctx.extra().get('source')
+ source = ctx.extra().get(b'source')
extra = {}
if source:
- extra['source'] = source
- extra['intermediate-source'] = ctx.hex()
+ extra[b'source'] = source
+ extra[b'intermediate-source'] = ctx.hex()
else:
- extra['source'] = ctx.hex()
+ extra[b'source'] = ctx.hex()
user = ctx.user()
date = ctx.date()
message = ctx.description()
- ui.status(_('evolving %d:%s "%s"\n') % (ctx.rev(), ctx,
- message.split('\n', 1)[0]))
+ ui.status(_(b'evolving %d:%s "%s"\n') % (ctx.rev(), ctx,
+ message.split(b'\n', 1)[0]))
targetphase = max(ctx.phase(), phases.draft)
- overrides = {('phases', 'new-commit'): targetphase}
+ overrides = {(b'phases', b'new-commit'): targetphase}
ctxparents = orig.parents()
if len(ctxparents) == 2:
@@ -2117,7 +2125,7 @@
else:
# both the parents were obsoleted, if orphanmerge is set, we
# are processing the second parent first (to keep parent order)
- if evolvestate.get('orphanmerge'):
+ if evolvestate.get(b'orphanmerge'):
with repo.dirstate.parentchange():
repo.dirstate.setparents(ctxparents[0].node(),
currentp1)
@@ -2126,7 +2134,7 @@
with repo.dirstate.parentchange():
repo.dirstate.setparents(repo.dirstate.parents()[0], nodemod.nullid)
- with repo.ui.configoverride(overrides, 'evolve-continue'):
+ with repo.ui.configoverride(overrides, b'evolve-continue'):
node = repo.commit(text=message, user=user,
date=date, extra=extra)
return node
--- a/hgext3rd/evolve/exthelper.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/exthelper.py Fri Sep 27 13:03:14 2019 +0200
@@ -83,12 +83,12 @@
self._duckpunchers = []
self.cmdtable = {}
self.command = registrar.command(self.cmdtable)
- if '^init' in commands.table:
+ if b'^init' in commands.table:
olddoregister = self.command._doregister
def _newdoregister(self, name, *args, **kwargs):
if kwargs.pop('helpbasic', False):
- name = '^' + name
+ name = r'^' + name
return olddoregister(self, name, *args, **kwargs)
self.command._doregister = _newdoregister
@@ -277,9 +277,9 @@
else:
for opt in opts:
if not isinstance(opt, tuple):
- raise error.ProgrammingError('opts must be list of tuples')
+ raise error.ProgrammingError(b'opts must be list of tuples')
if len(opt) not in (4, 5):
- msg = 'each opt tuple must contain 4 or 5 values'
+ msg = b'each opt tuple must contain 4 or 5 values'
raise error.ProgrammingError(msg)
def dec(wrapper):
--- a/hgext3rd/evolve/firstmergecache.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/firstmergecache.py Fri Sep 27 13:03:14 2019 +0200
@@ -41,7 +41,7 @@
@localrepo.unfilteredmethod
def destroyed(self):
- if 'firstmergecach' in vars(self):
+ if r'firstmergecach' in vars(self):
self.firstmergecache.clear()
super(firstmergecacherepo, self).destroyed()
@@ -56,16 +56,16 @@
class firstmergecache(genericcaches.changelogsourcebase):
- _filepath = 'evoext-firstmerge-00'
- _cachename = 'evo-ext-firstmerge'
+ _filepath = b'evoext-firstmerge-00'
+ _cachename = b'evo-ext-firstmerge'
def __init__(self):
super(firstmergecache, self).__init__()
- self._data = array.array('l')
+ self._data = array.array(r'l')
def get(self, rev):
if len(self._data) <= rev:
- raise error.ProgrammingError('firstmergecache must be warmed before use')
+ raise error.ProgrammingError(b'firstmergecache must be warmed before use')
return self._data[rev]
def _updatefrom(self, repo, data):
@@ -75,9 +75,9 @@
total = len(data)
def progress(pos, rev=None):
- revstr = '' if rev is None else ('rev %d' % rev)
- compat.progress(repo.ui, 'updating firstmerge cache',
- pos, revstr, unit='revision', total=total)
+ 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)
progress(0)
for idx, rev in enumerate(data, 1):
assert rev == len(self._data), (rev, len(self._data))
@@ -108,7 +108,7 @@
Subclasses MUST overide this method to actually affect the cache data.
"""
super(firstmergecache, self).clear()
- self._data = array.array('l')
+ self._data = array.array(r'l')
# crude version of a cache, to show the kind of information we have to store
@@ -117,7 +117,7 @@
assert repo.filtername is None
data = repo.cachevfs.tryread(self._filepath)
- self._data = array.array('l')
+ self._data = array.array(r'l')
if not data:
self._cachekey = self.emptykey
else:
@@ -136,12 +136,12 @@
return
try:
- cachefile = repo.cachevfs(self._filepath, 'w', atomictemp=True)
+ cachefile = repo.cachevfs(self._filepath, b'w', atomictemp=True)
headerdata = self._serializecachekey()
cachefile.write(headerdata)
cachefile.write(compat.arraytobytes(self._data))
cachefile.close()
self._ondiskkey = self._cachekey
except (IOError, OSError) as exc:
- repo.ui.log('firstmergecache', 'could not write update %s\n' % exc)
- repo.ui.debug('firstmergecache: could not write update %s\n' % exc)
+ repo.ui.log(b'firstmergecache', b'could not write update %s\n' % exc)
+ repo.ui.debug(b'firstmergecache: could not write update %s\n' % exc)
--- a/hgext3rd/evolve/genericcaches.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/genericcaches.py Fri Sep 27 13:03:14 2019 +0200
@@ -31,7 +31,7 @@
# default key used for an empty cache
emptykey = ()
- _cachekeyspec = '' # used for serialization
+ _cachekeyspec = b'' # used for serialization
_cachename = None # used for debug message
@abc.abstractmethod
@@ -42,7 +42,7 @@
@util.propertycache
def _cachekeystruct(self):
# dynamic property to help subclass to change it
- return struct.Struct('>' + self._cachekeyspec)
+ return struct.Struct(b'>' + self._cachekeyspec)
@util.propertycache
def _cachekeysize(self):
@@ -112,7 +112,7 @@
if newkey == self._cachekey:
return
if reset or self._cachekey is None:
- repo.ui.log('cache', 'strip detected, %s cache reset\n'
+ repo.ui.log(b'cache', b'strip detected, %s cache reset\n'
% self._cachename)
self.clear(reset=True)
@@ -120,7 +120,7 @@
self._updatefrom(repo, data)
duration = util.timer() - starttime
summary = self._updatesummary(data)
- repo.ui.log('cache', 'updated %s in %.4f seconds (%s)\n',
+ repo.ui.log(b'cache', b'updated %s in %.4f seconds (%s)\n',
self._cachename, duration, summary)
self._cachekey = newkey
@@ -144,7 +144,7 @@
# default key used for an empty cache
emptykey = (0, node.nullid)
- _cachekeyspec = 'i20s'
+ _cachekeyspec = b'i20s'
_cachename = None # used for debug message
# Useful "public" function (no need to override them)
@@ -172,4 +172,4 @@
return self._fetchchangelogdata(self._cachekey, repo.changelog)
def _updatesummary(self, data):
- return '%ir' % len(data)
+ return b'%ir' % len(data)
--- a/hgext3rd/evolve/hack/drophack.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/hack/drophack.py Fri Sep 27 13:03:14 2019 +0200
@@ -34,7 +34,7 @@
user = ostop[0] - ostart[0]
sys = ostop[1] - ostart[1]
comb = user + sys
- ui.write("%s: wall %f comb %f user %f sys %f\n"
+ ui.write(b"%s: wall %f comb %f user %f sys %f\n"
% (caption, wall, comb, user, sys))
def obsmarkerchainfrom(obsstore, nodes):
@@ -66,13 +66,13 @@
repo = repo.unfiltered()
repo.destroying()
oldmarkers = list(repo.obsstore._all)
- util.rename(repo.svfs.join('obsstore'),
- repo.vfs.join('obsstore.prestrip'))
+ util.rename(repo.svfs.join(b'obsstore'),
+ repo.vfs.join(b'obsstore.prestrip'))
del repo.obsstore # drop the cache
newstore = repo.obsstore
assert not newstore # should be empty after rename
newmarkers = [m for m in oldmarkers if m not in markers]
- tr = repo.transaction('drophack')
+ tr = repo.transaction(b'drophack')
try:
newstore.add(tr, newmarkers)
tr.close()
@@ -81,7 +81,7 @@
repo.destroyed()
-@command('drop', [('r', 'rev', [], 'revision to update')], _('[-r] revs'))
+@command(b'drop', [(b'r', b'rev', [], b'revision to update')], _(b'[-r] revs'))
def cmddrop(ui, repo, *revs, **opts):
"""I'm hacky do not use me!
@@ -97,11 +97,11 @@
revs = list(revs)
revs.extend(opts['rev'])
if not revs:
- revs = ['.']
+ revs = [b'.']
# get the changeset
revs = scmutil.revrange(repo, revs)
if not revs:
- ui.write_err('no revision to drop\n')
+ ui.write_err(b'no revision to drop\n')
return 1
# lock from the beginning to prevent race
wlock = lock = None
@@ -109,49 +109,49 @@
wlock = repo.wlock()
lock = repo.lock()
# check they have no children
- if repo.revs('%ld and public()', revs):
- ui.write_err('cannot drop public revision')
+ if repo.revs(b'%ld and public()', revs):
+ ui.write_err(b'cannot drop public revision')
return 1
- if repo.revs('children(%ld) - %ld', revs, revs):
- ui.write_err('cannot drop revision with children')
+ if repo.revs(b'children(%ld) - %ld', revs, revs):
+ ui.write_err(b'cannot drop revision with children')
return 1
- if repo.revs('. and %ld', revs):
- newrevs = repo.revs('max(::. - %ld)', revs)
+ if repo.revs(b'. and %ld', revs):
+ newrevs = repo.revs(b'max(::. - %ld)', revs)
if newrevs:
assert len(newrevs) == 1
newrev = newrevs.first()
else:
newrev = -1
commands.update(ui, repo, newrev)
- ui.status(_('working directory now at %s\n') % repo[newrev])
+ ui.status(_(b'working directory now at %s\n') % repo[newrev])
# get all markers and successors up to root
nodes = [repo[r].node() for r in revs]
- with timed(ui, 'search obsmarker'):
+ with timed(ui, b'search obsmarker'):
markers = set(obsmarkerchainfrom(repo.obsstore, nodes))
- ui.write('%i obsmarkers found\n' % len(markers))
+ ui.write(b'%i obsmarkers found\n' % len(markers))
cl = repo.unfiltered().changelog
- with timed(ui, 'search nodes'):
+ with timed(ui, b'search nodes'):
allnodes = set(nodes)
allnodes.update(m[0] for m in markers if cl.hasnode(m[0]))
- ui.write('%i nodes found\n' % len(allnodes))
+ ui.write(b'%i nodes found\n' % len(allnodes))
cl = repo.changelog
visiblenodes = set(n for n in allnodes if cl.hasnode(n))
# check constraint again
- if repo.revs('%ln and public()', visiblenodes):
- ui.write_err('cannot drop public revision')
+ if repo.revs(b'%ln and public()', visiblenodes):
+ ui.write_err(b'cannot drop public revision')
return 1
- if repo.revs('children(%ln) - %ln', visiblenodes, visiblenodes):
- ui.write_err('cannot drop revision with children')
+ if repo.revs(b'children(%ln) - %ln', visiblenodes, visiblenodes):
+ ui.write_err(b'cannot drop revision with children')
return 1
if markers:
# strip them
- with timed(ui, 'strip obsmarker'):
+ with timed(ui, b'strip obsmarker'):
stripmarker(ui, repo, markers)
# strip the changeset
- with timed(ui, 'strip nodes'):
- repair.strip(ui, repo, list(allnodes), backup="all",
- topic='drophack')
+ with timed(ui, b'strip nodes'):
+ repair.strip(ui, repo, list(allnodes), backup=b"all",
+ topic=b'drophack')
finally:
lockmod.release(lock, wlock)
--- a/hgext3rd/evolve/legacy.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/legacy.py Fri Sep 27 13:03:14 2019 +0200
@@ -45,20 +45,20 @@
"""
if not repo.local():
return
- evolveopts = ui.configlist('experimental', 'evolution')
+ evolveopts = ui.configlist(b'experimental', b'evolution')
if not evolveopts:
- evolveopts = 'all'
- ui.setconfig('experimental', 'evolution', evolveopts)
+ evolveopts = b'all'
+ ui.setconfig(b'experimental', b'evolution', evolveopts)
for arg in sys.argv:
- if 'debugc' in arg:
+ if r'debugc' in arg:
break
else:
- data = repo.vfs.tryread('obsolete-relations')
+ data = repo.vfs.tryread(b'obsolete-relations')
if not data:
- data = repo.svfs.tryread('obsoletemarkers')
+ data = repo.svfs.tryread(b'obsoletemarkers')
if data:
- raise error.Abort('old format of obsolete marker detected!\n'
- 'run `hg debugconvertobsolete` once.')
+ raise error.Abort(b'old format of obsolete marker detected!\n'
+ b'run `hg debugconvertobsolete` once.')
def _obsdeserialize(flike):
"""read a file like object serialized with _obsserialize
@@ -77,7 +77,7 @@
cmdtable = {}
command = commandfunc(cmdtable)
-@command('debugconvertobsolete', [], '')
+@command(b'debugconvertobsolete', [], b'')
def cmddebugconvertobsolete(ui, repo):
"""import markers from an .hg/obsolete-relations file"""
cnt = 0
@@ -86,13 +86,13 @@
some = False
try:
unlink = []
- tr = repo.transaction('convert-obsolete')
+ tr = repo.transaction(b'convert-obsolete')
try:
repo._importoldobsolete = True
store = repo.obsstore
### very first format
try:
- f = repo.vfs('obsolete-relations')
+ f = repo.vfs(b'obsolete-relations')
try:
some = True
for line in f:
@@ -101,30 +101,30 @@
prec = bin(objhex)
sucs = (suc == nullid) and [] or [suc]
meta = {
- 'date': '%i %i' % makedate(),
- 'user': ui.username(),
+ b'date': b'%i %i' % makedate(),
+ b'user': ui.username(),
}
try:
store.create(tr, prec, sucs, 0, metadata=meta)
cnt += 1
except ValueError:
- repo.ui.write_err("invalid old marker line: %s"
+ repo.ui.write_err(b"invalid old marker line: %s"
% (line))
err += 1
finally:
f.close()
- unlink.append(repo.vfs.join('obsolete-relations'))
+ unlink.append(repo.vfs.join(b'obsolete-relations'))
except IOError:
pass
### second (json) format
- data = repo.svfs.tryread('obsoletemarkers')
+ data = repo.svfs.tryread(b'obsoletemarkers')
if data:
some = True
for oldmark in json.loads(data):
- del oldmark['id'] # dropped for now
- del oldmark['reason'] # unused until then
- oldobject = str(oldmark.pop('object'))
- oldsubjects = [str(s) for s in oldmark.pop('subjects', [])]
+ del oldmark[r'id'] # dropped for now
+ del oldmark[r'reason'] # unused until then
+ oldobject = str(oldmark.pop(r'object'))
+ oldsubjects = [str(s) for s in oldmark.pop(r'subjects', [])]
lookup_errors = (error.RepoLookupError, error.LookupError)
if len(oldobject) != 40:
try:
@@ -137,7 +137,7 @@
except lookup_errors:
pass
- oldmark['date'] = '%i %i' % tuple(oldmark['date'])
+ oldmark[r'date'] = r'%i %i' % tuple(oldmark[r'date'])
meta = dict((k.encode('utf-8'), v.encode('utf-8'))
for k, v in oldmark.items())
try:
@@ -147,11 +147,11 @@
0, metadata=meta)
cnt += 1
except ValueError:
- msg = "invalid marker %s -> %s\n"
+ msg = b"invalid marker %s -> %s\n"
msg %= (oldobject, oldsubjects)
repo.ui.write_err(msg)
err += 1
- unlink.append(repo.svfs.join('obsoletemarkers'))
+ unlink.append(repo.svfs.join(b'obsoletemarkers'))
tr.close()
for path in unlink:
util.unlink(path)
@@ -161,12 +161,12 @@
del repo._importoldobsolete
lock.release()
if not some:
- ui.warn(_('nothing to do\n'))
- ui.status('%i obsolete marker converted\n' % cnt)
+ ui.warn(_(b'nothing to do\n'))
+ ui.status(b'%i obsolete marker converted\n' % cnt)
if err:
- ui.write_err('%i conversion failed. check you graph!\n' % err)
+ ui.write_err(b'%i conversion failed. check you graph!\n' % err)
-@command('debugrecordpruneparents', [], '')
+@command(b'debugrecordpruneparents', [], b'')
def cmddebugrecordpruneparents(ui, repo):
"""add parent data to prune markers when possible
@@ -174,14 +174,14 @@
If the pruned node is locally known, it creates a new marker with parent
data.
"""
- pgop = 'reading markers'
+ pgop = b'reading markers'
# lock from the beginning to prevent race
wlock = lock = tr = None
try:
wlock = repo.wlock()
lock = repo.lock()
- tr = repo.transaction('recordpruneparents')
+ tr = repo.transaction(b'recordpruneparents')
unfi = repo.unfiltered()
nm = unfi.changelog.nodemap
store = repo.obsstore
@@ -196,7 +196,7 @@
store.create(tr, prec=mark[0], succs=mark[1], flag=mark[2],
metadata=dict(mark[3]), parents=parents)
if len(store._all) - before:
- ui.write(_('created new markers for %i\n') % rev)
+ ui.write(_(b'created new markers for %i\n') % rev)
ui.progress(pgop, idx, total=pgtotal)
tr.close()
ui.progress(pgop, None)
--- a/hgext3rd/evolve/metadata.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/metadata.py Fri Sep 27 13:03:14 2019 +0200
@@ -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'9.1.0.dev'
-testedwith = b'4.5.2 4.6.2 4.7 4.8 4.9 5.0'
+__version__ = b'9.2.0'
+testedwith = b'4.5.2 4.6.2 4.7 4.8 4.9 5.0 5.1'
minimumhgversion = b'4.5'
buglink = b'https://bz.mercurial-scm.org/'
--- a/hgext3rd/evolve/obscache.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/obscache.py Fri Sep 27 13:03:14 2019 +0200
@@ -50,10 +50,10 @@
length, cachekey will be set to None."""
# default value
obsstoresize = 0
- keydata = ''
+ keydata = b''
# try to get actual data from the obsstore
try:
- with self.svfs('obsstore') as obsfile:
+ with self.svfs(b'obsstore') as obsfile:
obsfile.seek(0, 2)
obsstoresize = obsfile.tell()
if index is None:
@@ -82,11 +82,11 @@
def markersfrom(obsstore, byteoffset, firstmarker):
if not firstmarker:
return list(obsstore)
- elif '_all' in vars(obsstore):
+ elif r'_all' in vars(obsstore):
# if the data are in memory, just use that
return obsstore._all[firstmarker:]
else:
- obsdata = obsstore.svfs.tryread('obsstore')
+ obsdata = obsstore.svfs.tryread(b'obsstore')
return obsolete._readmarkers(obsdata, byteoffset)[1]
@@ -178,7 +178,7 @@
reset, revs, obsmarkers, obskeypair = upgrade
if reset or self._cachekey is None:
- repo.ui.log('evoext-cache', 'strip detected, %s cache reset\n' % self._cachename)
+ repo.ui.log(b'evoext-cache', b'strip detected, %s cache reset\n' % self._cachename)
self.clear(reset=True)
starttime = util.timer()
@@ -186,7 +186,7 @@
obsmarkers = list(obsmarkers)
self._updatefrom(repo, revs, obsmarkers)
duration = util.timer() - starttime
- repo.ui.log('evoext-cache', 'updated %s in %.4f seconds (%dr, %do)\n',
+ repo.ui.log(b'evoext-cache', b'updated %s in %.4f seconds (%dr, %do)\n',
self._cachename, duration, len(revs), len(obsmarkers))
# update the key from the new data
@@ -314,10 +314,10 @@
zero. That would be especially useful for the '.pending' overlay.
"""
- _filepath = 'evoext-obscache-00'
- _headerformat = '>q20sQQ20s'
+ _filepath = b'evoext-obscache-00'
+ _headerformat = b'>q20sQQ20s'
- _cachename = 'evo-ext-obscache' # used for error message
+ _cachename = b'evo-ext-obscache' # used for error message
def __init__(self, repo):
super(obscache, self).__init__()
@@ -339,7 +339,7 @@
def _setdata(self, data):
"""set a new bytearray data, invalidating the 'get' shortcut if needed"""
self._data = data
- if 'get' in vars(self):
+ if r'get' in vars(self):
del self.get
def clear(self, reset=False):
@@ -403,15 +403,15 @@
return
try:
- cachefile = repo.cachevfs(self._filepath, 'w', atomictemp=True)
+ cachefile = repo.cachevfs(self._filepath, b'w', atomictemp=True)
headerdata = struct.pack(self._headerformat, *self._cachekey)
cachefile.write(headerdata)
cachefile.write(self._data)
cachefile.close()
self._ondiskkey = self._cachekey
except (IOError, OSError) as exc:
- repo.ui.log('obscache', 'could not write update %s\n' % exc)
- repo.ui.debug('obscache: could not write update %s\n' % exc)
+ repo.ui.log(b'obscache', b'could not write update %s\n' % exc)
+ repo.ui.debug(b'obscache: could not write update %s\n' % exc)
def load(self, repo):
"""load data from disk"""
@@ -447,10 +447,10 @@
# will be about as fast...
if not obscache.uptodate(repo):
if repo.currenttransaction() is None:
- repo.ui.log('evoext-cache',
- 'obscache is out of date, '
- 'falling back to slower obsstore version\n')
- repo.ui.debug('obscache is out of date\n')
+ repo.ui.log(b'evoext-cache',
+ b'obscache is out of date, '
+ b'falling back to slower obsstore version\n')
+ repo.ui.debug(b'obscache is out of date\n')
return orig(repo)
else:
# If a transaction is open, it is worthwhile to update and use
@@ -465,9 +465,9 @@
@eh.uisetup
def cachefuncs(ui):
- orig = obsolete.cachefuncs['obsolete']
+ orig = obsolete.cachefuncs[b'obsolete']
wrapped = lambda repo: _computeobsoleteset(orig, repo)
- obsolete.cachefuncs['obsolete'] = wrapped
+ obsolete.cachefuncs[b'obsolete'] = wrapped
@eh.reposetup
def setupcache(ui, repo):
@@ -476,7 +476,7 @@
@localrepo.unfilteredmethod
def destroyed(self):
- if 'obsstore' in vars(self):
+ if r'obsstore' in vars(self):
self.obsstore.obscache.clear()
super(obscacherepo, self).destroyed()
--- a/hgext3rd/evolve/obsdiscovery.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/obsdiscovery.py Fri Sep 27 13:03:14 2019 +0200
@@ -60,11 +60,11 @@
obsexcmsg = utility.obsexcmsg
# Config
-eh.configitem('experimental', 'evolution.obsdiscovery', True)
-eh.configitem('experimental', 'obshashrange', True)
-eh.configitem('experimental', 'obshashrange.warm-cache', 'auto')
-eh.configitem('experimental', 'obshashrange.max-revs', None)
-eh.configitem('experimental', 'obshashrange.lru-size', 2000)
+eh.configitem(b'experimental', b'evolution.obsdiscovery', True)
+eh.configitem(b'experimental', b'obshashrange', True)
+eh.configitem(b'experimental', b'obshashrange.warm-cache', b'auto')
+eh.configitem(b'experimental', b'obshashrange.max-revs', None)
+eh.configitem(b'experimental', b'obshashrange.lru-size', 2000)
##################################
### Code performing discovery ###
@@ -76,7 +76,7 @@
missing = set()
starttime = util.timer()
- heads = local.revs('heads(%ld)', probeset)
+ heads = local.revs(b'heads(%ld)', probeset)
local.stablerange.warmup(local)
rangelength = local.stablerange.rangelength
@@ -104,8 +104,8 @@
local.obsstore.rangeobshashcache.update(local)
querycount = 0
- compat.progress(ui, _("comparing obsmarker with other"), querycount,
- unit=_("queries"))
+ compat.progress(ui, _(b"comparing obsmarker with other"), querycount,
+ unit=_(b"queries"))
overflow = []
while sample or overflow:
if overflow:
@@ -117,7 +117,7 @@
overflow = sample[samplesize:]
sample = sample[:samplesize]
elif len(sample) < samplesize:
- ui.debug("query %i; add more sample (target %i, current %i)\n"
+ ui.debug(b"query %i; add more sample (target %i, current %i)\n"
% (querycount, samplesize, len(sample)))
# we need more sample !
needed = samplesize - len(sample)
@@ -143,7 +143,7 @@
nbsample = len(sample)
maxsize = max([rangelength(local, r) for r in sample])
- ui.debug("query %i; sample size is %i, largest range %i\n"
+ ui.debug(b"query %i; sample size is %i, largest range %i\n"
% (querycount, nbsample, maxsize))
nbreplies = 0
replies = list(_queryrange(ui, local, remote, sample))
@@ -160,15 +160,15 @@
addentry(new)
assert nbsample == nbreplies
querycount += 1
- compat.progress(ui, _("comparing obsmarker with other"), querycount,
- unit=_("queries"))
- compat.progress(ui, _("comparing obsmarker with other"), None)
+ compat.progress(ui, _(b"comparing obsmarker with other"), querycount,
+ unit=_(b"queries"))
+ compat.progress(ui, _(b"comparing obsmarker with other"), None)
local.obsstore.rangeobshashcache.save(local)
duration = util.timer() - starttime
- logmsg = ('obsdiscovery, %d/%d mismatch'
- ' - %d obshashrange queries in %.4f seconds\n')
+ logmsg = (b'obsdiscovery, %d/%d mismatch'
+ b' - %d obshashrange queries in %.4f seconds\n')
logmsg %= (len(missing), len(probeset), querycount, duration)
- ui.log('evoext-obsdiscovery', logmsg)
+ ui.log(b'evoext-obsdiscovery', logmsg)
ui.debug(logmsg)
return sorted(missing)
@@ -208,9 +208,9 @@
ranges = stablerange.subrangesclosure(repo, repo.stablerange, revs)
else:
ranges = [(r, 0) for r in revs]
- headers = ('rev', 'node', 'index', 'size', 'depth', 'obshash')
- linetemplate = '%12d %12s %12d %12d %12d %12s\n'
- headertemplate = linetemplate.replace('d', 's')
+ headers = (b'rev', b'node', b'index', b'size', b'depth', b'obshash')
+ linetemplate = b'%12d %12s %12d %12d %12d %12s\n'
+ headertemplate = linetemplate.replace(b'd', b's')
ui.status(headertemplate % headers)
repo.obsstore.rangeobshashcache.update(repo)
for r in ranges:
@@ -262,12 +262,12 @@
### sqlite caching
_sqliteschema = [
- """CREATE TABLE obshashrange(rev INTEGER NOT NULL,
+ r"""CREATE TABLE obshashrange(rev INTEGER NOT NULL,
idx INTEGER NOT NULL,
obshash BLOB NOT NULL,
PRIMARY KEY(rev, idx));""",
- "CREATE INDEX range_index ON obshashrange(rev, idx);",
- """CREATE TABLE meta(schemaversion INTEGER NOT NULL,
+ r"CREATE INDEX range_index ON obshashrange(rev, idx);",
+ r"""CREATE TABLE meta(schemaversion INTEGER NOT NULL,
tiprev INTEGER NOT NULL,
tipnode BLOB NOT NULL,
nbobsmarker INTEGER NOT NULL,
@@ -275,17 +275,17 @@
obskey BLOB NOT NULL
);""",
]
-_queryexist = "SELECT name FROM sqlite_master WHERE type='table' AND name='meta';"
-_clearmeta = """DELETE FROM meta;"""
-_newmeta = """INSERT INTO meta (schemaversion, tiprev, tipnode, nbobsmarker, obssize, obskey)
+_queryexist = r"SELECT name FROM sqlite_master WHERE type='table' AND name='meta';"
+_clearmeta = r"""DELETE FROM meta;"""
+_newmeta = r"""INSERT INTO meta (schemaversion, tiprev, tipnode, nbobsmarker, obssize, obskey)
VALUES (?,?,?,?,?,?);"""
-_updateobshash = "INSERT INTO obshashrange(rev, idx, obshash) VALUES (?,?,?);"
-_querymeta = "SELECT schemaversion, tiprev, tipnode, nbobsmarker, obssize, obskey FROM meta;"
-_queryobshash = "SELECT obshash FROM obshashrange WHERE (rev = ? AND idx = ?);"
-_query_max_stored = "SELECT MAX(rev) FROM obshashrange"
+_updateobshash = r"INSERT INTO obshashrange(rev, idx, obshash) VALUES (?,?,?);"
+_querymeta = r"SELECT schemaversion, tiprev, tipnode, nbobsmarker, obssize, obskey FROM meta;"
+_queryobshash = r"SELECT obshash FROM obshashrange WHERE (rev = ? AND idx = ?);"
+_query_max_stored = r"SELECT MAX(rev) FROM obshashrange"
-_reset = "DELETE FROM obshashrange;"
-_delete = "DELETE FROM obshashrange WHERE (rev = ? AND idx = ?);"
+_reset = r"DELETE FROM obshashrange;"
+_delete = r"DELETE FROM obshashrange WHERE (rev = ? AND idx = ?);"
def _affectedby(repo, markers):
"""return all nodes whose relevant set is affected by this changeset
@@ -333,8 +333,8 @@
_schemaversion = 3
- _cachename = 'evo-ext-obshashrange' # used for error message
- _filename = 'evoext_obshashrange_v2.sqlite'
+ _cachename = b'evo-ext-obshashrange' # used for error message
+ _filename = b'evoext_obshashrange_v2.sqlite'
def __init__(self, repo):
super(_obshashcache, self).__init__()
@@ -353,7 +353,7 @@
self._new.clear()
if reset:
self._valid = False
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
def get(self, rangeid):
@@ -362,7 +362,7 @@
# XXX there are issue with cache warming, we hack around it for now
if not getattr(self, '_updating', False):
if self._cachekey[0] < rangeid[0]:
- msg = ('using unwarmed obshashrangecache (%s %s)'
+ msg = (b'using unwarmed obshashrangecache (%s %s)'
% (rangeid[0], self._cachekey[0]))
raise error.ProgrammingError(msg)
@@ -377,7 +377,7 @@
except (sqlite3.DatabaseError, sqlite3.OperationalError):
# something is wrong with the sqlite db
# Since this is a cache, we ignore it.
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
self._new.clear()
return value
@@ -406,8 +406,8 @@
affected = []
if RESET_ABOVE < len(obsmarkers):
# lots of new obsmarkers, probably smarter to reset the cache
- repo.ui.log('evoext-cache', 'obshashcache reset - '
- 'many new markers (%d)\n'
+ repo.ui.log(b'evoext-cache', b'obshashcache reset - '
+ b'many new markers (%d)\n'
% len(obsmarkers))
reset = True
elif obsmarkers:
@@ -420,23 +420,23 @@
if r is not None and r <= max_stored]
if RESET_ABOVE < len(affected):
- repo.ui.log('evoext-cache', 'obshashcache reset - '
- 'new markers affect many changeset (%d)\n'
+ repo.ui.log(b'evoext-cache', b'obshashcache reset - '
+ b'new markers affect many changeset (%d)\n'
% len(affected))
reset = True
if affected or reset:
if not reset:
- repo.ui.log('evoext-cache', 'obshashcache clean - '
- 'new markers affect %d changeset and cached ranges\n'
+ repo.ui.log(b'evoext-cache', b'obshashcache clean - '
+ b'new markers affect %d changeset and cached ranges\n'
% len(affected))
if con is not None:
# always reset for now, the code detecting affect is buggy
# so we need to reset more broadly than we would like.
try:
if repo.stablerange._con is None:
- repo.ui.log('evoext-cache', 'obshashcache reset - '
- 'underlying stablerange cache unavailable\n')
+ repo.ui.log(b'evoext-cache', b'obshashcache reset - '
+ b'underlying stablerange cache unavailable\n')
reset = True
if reset:
con.execute(_reset)
@@ -447,7 +447,7 @@
for r in ranges:
self._data.pop(r, None)
except (sqlite3.DatabaseError, sqlite3.OperationalError) as exc:
- repo.ui.log('evoext-cache', 'error while updating obshashrange cache: %s' % exc)
+ repo.ui.log(b'evoext-cache', b'error while updating obshashrange cache: %s' % exc)
del self._updating
return
@@ -457,7 +457,7 @@
# single revision is quite costly)
newrevs = []
stop = self._cachekey[0] # tiprev
- for h in repo.filtered('immutable').changelog.headrevs():
+ for h in repo.filtered(b'immutable').changelog.headrevs():
if h <= stop and h in affected:
newrevs.append(h)
newrevs.extend(revs)
@@ -467,9 +467,9 @@
total = len(revs)
def progress(pos, rev=None):
- revstr = '' if rev is None else ('rev %d' % rev)
- compat.progress(repo.ui, 'updating obshashrange cache',
- pos, revstr, unit='revision', total=total)
+ 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)
# warm the cache for the new revs
progress(0)
for idx, r in enumerate(revs):
@@ -495,7 +495,7 @@
except OSError:
return None
con = sqlite3.connect(encoding.strfromlocal(self._path), timeout=30,
- isolation_level="IMMEDIATE")
+ isolation_level=r"IMMEDIATE")
con.text_factory = bytes
return con
@@ -528,14 +528,14 @@
repo = repo.unfiltered()
try:
with repo.lock():
- if 'stablerange' in vars(repo):
+ if r'stablerange' in vars(repo):
repo.stablerange.save(repo)
self._save(repo)
except error.LockError:
# Exceptionnally we are noisy about it since performance impact
# is large We should address that before using this more
# widely.
- msg = _('obshashrange cache: skipping save unable to lock repo\n')
+ msg = _(b'obshashrange cache: skipping save unable to lock repo\n')
repo.ui.warn(msg)
def _save(self, repo):
@@ -548,22 +548,22 @@
#
# operational error catch read-only and locked database
# IntegrityError catch Unique constraint error that may arise
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
self._new.clear()
- repo.ui.log('evoext-cache', 'error while saving new data: %s' % exc)
- repo.ui.debug('evoext-cache: error while saving new data: %s' % exc)
+ repo.ui.log(b'evoext-cache', b'error while saving new data: %s' % exc)
+ repo.ui.debug(b'evoext-cache: error while saving new data: %s' % exc)
def _trysave(self, repo):
if self._con is None:
util.unlinkpath(self._path, ignoremissing=True)
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
con = self._db()
if con is None:
- repo.ui.log('evoext-cache', 'unable to write obshashrange cache'
- ' - cannot create database')
+ repo.ui.log(b'evoext-cache', b'unable to write obshashrange cache'
+ b' - cannot create database')
return
with con:
for req in _sqliteschema:
@@ -580,12 +580,12 @@
# drifting is currently an issue because this means another
# process might have already added the cache line we are about
# to add. This will confuse sqlite
- msg = _('obshashrange cache: skipping write, '
- 'database drifted under my feet\n')
+ msg = _(b'obshashrange cache: skipping write, '
+ b'database drifted under my feet\n')
repo.ui.warn(msg)
self._new.clear()
self._valid = False
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
self._valid = False
return
@@ -618,7 +618,7 @@
class obshashrepo(repo.__class__):
@localrepo.unfilteredmethod
def destroyed(self):
- if 'obsstore' in vars(self):
+ if r'obsstore' in vars(self):
self.obsstore.rangeobshashcache.clear()
toplevel = not util.safehasattr(self, '_destroying')
if toplevel:
@@ -667,7 +667,7 @@
return _obshashrange_v0(peer._repo, ranges)
-_indexformat = '>I'
+_indexformat = b'>I'
_indexsize = _calcsize(_indexformat)
def _encrange(node_rangeid):
"""encode a (node) range"""
@@ -685,11 +685,11 @@
def peer_obshashrange_v0(self, ranges):
binranges = [_encrange(r) for r in ranges]
encranges = encodelist(binranges)
- d = self._call("evoext_obshashrange_v1", ranges=encranges)
+ d = self._call(b"evoext_obshashrange_v1", ranges=encranges)
try:
return decodelist(d)
except ValueError:
- self._abort(error.ResponseError(_("unexpected response:"), d))
+ self._abort(error.ResponseError(_(b"unexpected response:"), d))
@compat.wireprotocommand(eh, b'evoext_obshashrange_v1', b'ranges')
def srv_obshashrange_v1(repo, proto, ranges):
@@ -699,16 +699,16 @@
return encodelist(hashes)
def _useobshashrange(repo):
- base = repo.ui.configbool('experimental', 'obshashrange')
+ base = repo.ui.configbool(b'experimental', b'obshashrange')
if base:
- maxrevs = repo.ui.configint('experimental', 'obshashrange.max-revs')
+ maxrevs = repo.ui.configint(b'experimental', b'obshashrange.max-revs')
if maxrevs is not None and maxrevs < len(repo.unfiltered()):
base = False
return base
def _canobshashrange(local, remote):
return (_useobshashrange(local)
- and remote.capable('_evoext_obshashrange_v1'))
+ and remote.capable(b'_evoext_obshashrange_v1'))
def _obshashrange_capabilities(orig, repo, proto):
"""wrapper to advertise new capability"""
@@ -738,11 +738,11 @@
extensions.wrapfunction(wireprotov1server, 'capabilities',
_obshashrange_capabilities)
# wrap command content
- oldcap, args = wireprotov1server.commands['capabilities']
+ oldcap, args = wireprotov1server.commands[b'capabilities']
def newcap(repo, proto):
return _obshashrange_capabilities(oldcap, repo, proto)
- wireprotov1server.commands['capabilities'] = (newcap, args)
+ wireprotov1server.commands[b'capabilities'] = (newcap, args)
##########################################
### trigger discovery during exchange ###
@@ -754,7 +754,7 @@
# exchange of obsmarkers is enabled locally
and obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
# remote server accept markers
- and 'obsolete' in pushop.remote.listkeys('namespaces'))
+ and b'obsolete' in pushop.remote.listkeys(b'namespaces'))
def _pushobshashrange(pushop, commonrevs):
repo = pushop.repo.unfiltered()
@@ -769,21 +769,21 @@
(_canobshashrange, _pushobshashrange),
]
-obsdiscovery_skip_message = """\
+obsdiscovery_skip_message = b"""\
(skipping discovery of obsolescence markers, will exchange everything)
(controled by 'experimental.evolution.obsdiscovery' configuration)
"""
def usediscovery(repo):
- return repo.ui.configbool('experimental', 'evolution.obsdiscovery')
+ return repo.ui.configbool(b'experimental', b'evolution.obsdiscovery')
@eh.wrapfunction(exchange, '_pushdiscoveryobsmarkers')
def _pushdiscoveryobsmarkers(orig, pushop):
if _dopushmarkers(pushop):
repo = pushop.repo
remote = pushop.remote
- obsexcmsg(repo.ui, "computing relevant nodes\n")
- revs = list(repo.revs('::%ln', pushop.futureheads))
+ obsexcmsg(repo.ui, b"computing relevant nodes\n")
+ revs = list(repo.revs(b'::%ln', pushop.futureheads))
unfi = repo.unfiltered()
if not usediscovery(repo):
@@ -803,27 +803,27 @@
# obs markers.
return orig(pushop)
- obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
+ obsexcmsg(repo.ui, b"looking for common markers in %i nodes\n"
% len(revs))
- commonrevs = list(unfi.revs('::%ln', pushop.outgoing.commonheads))
+ commonrevs = list(unfi.revs(b'::%ln', pushop.outgoing.commonheads))
# find the nodes where the relevant obsmarkers mismatches
nodes = discovery(pushop, commonrevs)
if nodes:
- obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
+ obsexcmsg(repo.ui, b"computing markers relevant to %i nodes\n"
% len(nodes))
pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
else:
- obsexcmsg(repo.ui, "markers already in sync\n")
+ obsexcmsg(repo.ui, b"markers already in sync\n")
pushop.outobsmarkers = []
@eh.extsetup
def _installobsmarkersdiscovery(ui):
- olddisco = exchange.pushdiscoverymapping['obsmarker']
+ olddisco = exchange.pushdiscoverymapping[b'obsmarker']
def newdisco(pushop):
_pushdiscoveryobsmarkers(olddisco, pushop)
- exchange.pushdiscoverymapping['obsmarker'] = newdisco
+ exchange.pushdiscoverymapping[b'obsmarker'] = newdisco
def buildpullobsmarkersboundaries(pullop, bundle2=True):
"""small function returning the argument for pull markers call
@@ -833,25 +833,25 @@
repo = pullop.repo
remote = pullop.remote
unfi = repo.unfiltered()
- revs = unfi.revs('::(%ln - null)', pullop.common)
- boundaries = {'heads': pullop.pulledsubset}
+ revs = unfi.revs(b'::(%ln - null)', pullop.common)
+ boundaries = {b'heads': pullop.pulledsubset}
if not revs: # nothing common
- boundaries['common'] = [node.nullid]
+ boundaries[b'common'] = [node.nullid]
return boundaries
if not usediscovery(repo):
# discovery disabled by users.
repo.ui.status(obsdiscovery_skip_message)
- boundaries['common'] = [node.nullid]
+ boundaries[b'common'] = [node.nullid]
return boundaries
if bundle2 and _canobshashrange(repo, remote):
- obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
+ obsexcmsg(repo.ui, b"looking for common markers in %i nodes\n"
% len(revs))
- boundaries['missing'] = findmissingrange(repo.ui, unfi, pullop.remote,
- revs)
+ boundaries[b'missing'] = findmissingrange(repo.ui, unfi, pullop.remote,
+ revs)
else:
- boundaries['common'] = [node.nullid]
+ boundaries[b'common'] = [node.nullid]
return boundaries
# merge later for outer layer wrapping
--- a/hgext3rd/evolve/obsexchange.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/obsexchange.py Fri Sep 27 13:03:14 2019 +0200
@@ -37,7 +37,7 @@
obsexcmsg = utility.obsexcmsg
obsexcprg = utility.obsexcprg
-eh.configitem('experimental', 'verbose-obsolescence-exchange', False)
+eh.configitem(b'experimental', b'verbose-obsolescence-exchange', False)
_bestformat = max(obsolete.formats.keys())
@@ -58,46 +58,46 @@
# <= hg 4.5
from mercurial import wireproto
gboptsmap = wireproto.gboptsmap
- gboptsmap['evo_obscommon'] = 'nodes'
- gboptsmap['evo_missing_nodes'] = 'nodes'
+ gboptsmap[b'evo_obscommon'] = b'nodes'
+ gboptsmap[b'evo_missing_nodes'] = b'nodes'
@eh.wrapfunction(exchange, '_pullbundle2extraprepare')
def _addobscommontob2pull(orig, pullop, kwargs):
ret = orig(pullop, kwargs)
ui = pullop.repo.ui
- if ('obsmarkers' in kwargs
- and pullop.remote.capable('_evoext_getbundle_obscommon')):
+ if (b'obsmarkers' in kwargs
+ and pullop.remote.capable(b'_evoext_getbundle_obscommon')):
boundaries = obsdiscovery.buildpullobsmarkersboundaries(pullop)
- if 'common' in boundaries:
- common = boundaries['common']
+ if b'common' in boundaries:
+ common = boundaries[b'common']
if common != pullop.common:
- obsexcmsg(ui, 'request obsmarkers for some common nodes\n')
+ obsexcmsg(ui, b'request obsmarkers for some common nodes\n')
if common != [node.nullid]:
- kwargs['evo_obscommon'] = common
- elif 'missing' in boundaries:
- missing = boundaries['missing']
+ kwargs[b'evo_obscommon'] = common
+ elif b'missing' in boundaries:
+ missing = boundaries[b'missing']
if missing:
- obsexcmsg(ui, 'request obsmarkers for %d common nodes\n'
+ obsexcmsg(ui, b'request obsmarkers for %d common nodes\n'
% len(missing))
- kwargs['evo_missing_nodes'] = missing
+ kwargs[b'evo_missing_nodes'] = missing
return ret
def _getbundleobsmarkerpart(orig, bundler, repo, source, **kwargs):
- if not (set(['evo_obscommon', 'evo_missing_nodes']) & set(kwargs)):
+ if not (set([r'evo_obscommon', r'evo_missing_nodes']) & set(kwargs)):
return orig(bundler, repo, source, **kwargs)
if kwargs.get('obsmarkers', False):
heads = kwargs.get('heads')
- if 'evo_obscommon' in kwargs:
+ if r'evo_obscommon' in kwargs:
if heads is None:
heads = repo.heads()
obscommon = kwargs.get('evo_obscommon', ())
assert obscommon
- obsset = repo.unfiltered().set('::%ln - ::%ln', heads, obscommon)
+ obsset = repo.unfiltered().set(b'::%ln - ::%ln', heads, obscommon)
subset = [c.node() for c in obsset]
else:
common = kwargs.get('common')
- subset = [c.node() for c in repo.unfiltered().set('only(%ln, %ln)', heads, common)]
+ subset = [c.node() for c in repo.unfiltered().set(b'only(%ln, %ln)', heads, common)]
subset += kwargs['evo_missing_nodes']
markers = repo.obsstore.relevantmarkers(subset)
if util.safehasattr(bundle2, 'buildobsmarkerspart'):
@@ -138,36 +138,36 @@
from mercurial import wireproto
gboptsmap = wireproto.gboptsmap
wireprotov1server = wireproto
- gboptsmap['evo_obscommon'] = 'nodes'
+ gboptsmap[b'evo_obscommon'] = b'nodes'
# wrap module content
- origfunc = exchange.getbundle2partsmapping['obsmarkers']
+ origfunc = exchange.getbundle2partsmapping[b'obsmarkers']
def newfunc(*args, **kwargs):
return _getbundleobsmarkerpart(origfunc, *args, **kwargs)
- exchange.getbundle2partsmapping['obsmarkers'] = newfunc
+ exchange.getbundle2partsmapping[b'obsmarkers'] = newfunc
extensions.wrapfunction(wireprotov1server, 'capabilities',
_obscommon_capabilities)
# wrap command content
- oldcap, args = wireprotov1server.commands['capabilities']
+ oldcap, args = wireprotov1server.commands[b'capabilities']
def newcap(repo, proto):
return _obscommon_capabilities(oldcap, repo, proto)
- wireprotov1server.commands['capabilities'] = (newcap, args)
+ wireprotov1server.commands[b'capabilities'] = (newcap, args)
def _pushobsmarkers(repo, data):
tr = lock = None
try:
lock = repo.lock()
- tr = repo.transaction('pushkey: obsolete markers')
+ tr = repo.transaction(b'pushkey: obsolete markers')
new = repo.obsstore.mergemarkers(tr, data)
if new is not None:
- obsexcmsg(repo.ui, "%i obsolescence markers added\n" % new, True)
+ obsexcmsg(repo.ui, b"%i obsolescence markers added\n" % new, True)
tr.close()
finally:
lockmod.release(tr, lock)
- repo.hook('evolve_pushobsmarkers')
+ repo.hook(b'evolve_pushobsmarkers')
def srv_pushobsmarkers(repo, proto):
"""wireprotocol command"""
@@ -187,18 +187,18 @@
def _getobsmarkersstream(repo, heads=None, common=None):
"""Get a binary stream for all markers relevant to `::<heads> - ::<common>`
"""
- revset = ''
+ revset = b''
args = []
repo = repo.unfiltered()
if heads is None:
- revset = 'all()'
+ revset = b'all()'
elif heads:
- revset += "(::%ln)"
+ revset += b"(::%ln)"
args.append(heads)
else:
- assert False, 'pulling no heads?'
+ assert False, b'pulling no heads?'
if common:
- revset += ' - (::%ln)'
+ revset += b' - (::%ln)'
args.append(common)
nodes = [c.node() for c in repo.set(revset, *args)]
markers = repo.obsstore.relevantmarkers(nodes)
@@ -220,20 +220,20 @@
except (ImportError, AttributeError):
from mercurial import wireproto as wireprototypes
wireprotov1server = wireprototypes
- opts = wireprotov1server.options('', ['heads', 'common'], others)
+ opts = wireprotov1server.options(b'', [b'heads', b'common'], others)
for k, v in opts.items():
- if k in ('heads', 'common'):
+ if k in (b'heads', b'common'):
opts[k] = wireprototypes.decodelist(v)
obsdata = _getobsmarkersstream(repo, **opts)
finaldata = StringIO()
obsdata = obsdata.getvalue()
- finaldata.write('%20i' % len(obsdata))
+ finaldata.write(b'%20i' % len(obsdata))
finaldata.write(obsdata)
finaldata.seek(0)
return wireprototypes.streamres(reader=finaldata, v1compressible=True)
-abortmsg = "won't exchange obsmarkers through pushkey"
-hint = "upgrade your client or server to use the bundle2 protocol"
+abortmsg = b"won't exchange obsmarkers through pushkey"
+hint = b"upgrade your client or server to use the bundle2 protocol"
class HTTPCompatibleAbort(hgwebcommon.ErrorResponse, error.Abort):
def __init__(self, message, code, hint=None):
@@ -256,4 +256,4 @@
@eh.uisetup
def setuppushkeyforbidding(ui):
- pushkey._namespaces['obsolete'] = (forbidpushkey, forbidlistkey)
+ pushkey._namespaces[b'obsolete'] = (forbidpushkey, forbidlistkey)
--- a/hgext3rd/evolve/obshashtree.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/obshashtree.py Fri Sep 27 13:03:14 2019 +0200
@@ -42,14 +42,14 @@
debug command stayed as an inspection tool. It does not seem supseful to
upstream the command with the rest of evolve. We can safely drop it."""
if v0 and v1:
- raise error.Abort('cannot only specify one format')
+ raise error.Abort(b'cannot only specify one format')
elif v0:
treefunc = _obsrelsethashtreefm0
else:
treefunc = _obsrelsethashtreefm1
for chg, obs in treefunc(repo):
- ui.status('%s %s\n' % (node.hex(chg), node.hex(obs)))
+ ui.status(b'%s %s\n' % (node.hex(chg), node.hex(obs)))
def _obsrelsethashtreefm0(repo):
return _obsrelsethashtree(repo, obsolete._fm0encodeonemarker)
@@ -61,8 +61,8 @@
cache = []
unfi = repo.unfiltered()
markercache = {}
- compat.progress(repo.ui, _("preparing locally"), 0, total=len(unfi),
- unit=_("changesets"))
+ compat.progress(repo.ui, _(b"preparing locally"), 0, total=len(unfi),
+ unit=_(b"changesets"))
for i in unfi:
ctx = unfi[i]
entry = 0
@@ -92,7 +92,7 @@
cache.append((ctx.node(), sha.digest()))
else:
cache.append((ctx.node(), node.nullid))
- compat.progress(repo.ui, _("preparing locally"), i, total=len(unfi),
- unit=_("changesets"))
- compat.progress(repo.ui, _("preparing locally"), None)
+ compat.progress(repo.ui, _(b"preparing locally"), i, total=len(unfi),
+ unit=_(b"changesets"))
+ compat.progress(repo.ui, _(b"preparing locally"), None)
return cache
--- a/hgext3rd/evolve/obshistory.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/obshistory.py Fri Sep 27 13:03:14 2019 +0200
@@ -31,13 +31,13 @@
eh = exthelper.exthelper()
# Config
-efd = {'default': True} # pass a default value unless the config is registered
+efd = {b'default': True} # pass a default value unless the config is registered
@eh.extsetup
def enableeffectflags(ui):
item = (getattr(ui, '_knownconfig', {})
- .get('experimental', {})
- .get('evolution.effect-flags'))
+ .get(b'experimental', {})
+ .get(b'evolution.effect-flags'))
if item is not None:
item.default = True
efd.clear()
@@ -79,10 +79,10 @@
Returns 0 on success.
"""
- ui.pager('obslog')
+ ui.pager(b'obslog')
revs = list(revs) + opts['rev']
if not revs:
- revs = ['.']
+ revs = [b'.']
revs = scmutil.revrange(repo, revs)
if opts['graph']:
@@ -131,7 +131,7 @@
values = []
for sset in fullsuccessorsets:
- values.append({'successors': sset, 'markers': sset.markers})
+ values.append({b'successors': sset, b'markers': sset.markers})
return values
@@ -154,10 +154,10 @@
# Compat 4.6
if not util.safehasattr(self, "_includediff"):
- self._includediff = diffopts and diffopts.get('patch')
+ self._includediff = diffopts and diffopts.get(b'patch')
- self.template = diffopts and diffopts.get('template')
- self.filter = diffopts and diffopts.get('filternonlocal')
+ self.template = diffopts and diffopts.get(b'template')
+ self.filter = diffopts and diffopts.get(b'filternonlocal')
def show(self, ctx, copies=None, matchfn=None, **props):
if self.buffered:
@@ -165,12 +165,12 @@
changenode = ctx.node()
- _props = {"template": self.template}
- fm = self.ui.formatter('debugobshistory', _props)
+ _props = {b"template": self.template}
+ fm = self.ui.formatter(b'debugobshistory', _props)
_debugobshistorydisplaynode(fm, self.repo, changenode)
- markerfm = fm.nested("markers")
+ markerfm = fm.nested(b"markers")
# Succs markers
if self.filter is False:
@@ -186,21 +186,21 @@
r = _successorsandmarkers(self.repo, ctx)
for succset in sorted(r):
- markers = succset["markers"]
+ markers = succset[b"markers"]
if not markers:
continue
- successors = succset["successors"]
+ successors = succset[b"successors"]
_debugobshistorydisplaysuccsandmarkers(markerfm, successors, markers, ctx.node(), self.repo, self._includediff)
markerfm.end()
- markerfm.plain('\n')
+ markerfm.plain(b'\n')
fm.end()
self.hunk[ctx.node()] = self.ui.popbuffer()
else:
### graph output is buffered only
- msg = 'cannot be used outside of the graphlog (yet)'
+ msg = b'cannot be used outside of the graphlog (yet)'
raise error.ProgrammingError(msg)
def flush(self, ctx):
@@ -211,43 +211,43 @@
def patchavailable(node, repo, successors):
if node not in repo:
- return False, "context is not local"
+ return False, b"context is not local"
if len(successors) == 0:
- return False, "no successors"
+ return False, b"no successors"
elif len(successors) > 1:
- return False, "too many successors (%d)" % len(successors)
+ return False, b"too many successors (%d)" % len(successors)
succ = successors[0]
if succ not in repo:
- return False, "successor is unknown locally"
+ return False, b"successor is unknown locally"
# Check that both node and succ have the same parents
nodep1, nodep2 = repo[node].p1(), repo[node].p2()
succp1, succp2 = repo[succ].p1(), repo[succ].p2()
if nodep1 != succp1 or nodep2 != succp2:
- return False, "changesets rebased"
+ return False, b"changesets rebased"
return True, succ
def getmarkerdescriptionpatch(repo, basedesc, succdesc):
# description are stored without final new line,
# add one to avoid ugly diff
- basedesc += '\n'
- succdesc += '\n'
+ basedesc += b'\n'
+ succdesc += b'\n'
# fake file name
- basename = "changeset-description"
- succname = "changeset-description"
+ basename = b"changeset-description"
+ succname = b"changeset-description"
d = compat.strdiff(basedesc, succdesc, basename, succname)
uheaders, hunks = d
# Copied from patch.diff
- text = ''.join(sum((list(hlines) for hrange, hlines in hunks), []))
- patch = "\n".join(uheaders + [text])
+ text = b''.join(sum((list(hlines) for hrange, hlines in hunks), []))
+ patch = b"\n".join(uheaders + [text])
return patch
@@ -333,7 +333,7 @@
# Then choose a random node from the cycle
breaknode = sorted(cycle)[0]
# And display it by force
- repo.ui.debug('obs-cycle detected, forcing display of %s\n'
+ repo.ui.debug(b'obs-cycle detected, forcing display of %s\n'
% nodemod.short(breaknode))
validcandidates = [breaknode]
@@ -435,7 +435,7 @@
def _debugobshistoryrevs(ui, repo, revs, opts):
""" Display the obsolescence history for revset
"""
- fm = ui.formatter('debugobshistory', pycompat.byteskwargs(opts))
+ fm = ui.formatter(b'debugobshistory', pycompat.byteskwargs(opts))
precursors = repo.obsstore.predecessors
successors = repo.obsstore.successors
nodec = repo.changelog.node
@@ -451,7 +451,7 @@
succs = successors.get(ctxnode, ())
- markerfm = fm.nested("markers")
+ markerfm = fm.nested(b"markers")
for successor in sorted(succs):
includediff = opts and opts.get("patch")
_debugobshistorydisplaymarker(markerfm, successor, ctxnode, unfi, includediff)
@@ -477,24 +477,24 @@
shortdescription = shortdescription.splitlines()[0]
fm.startitem()
- fm.write('node', '%s', bytes(ctx),
- label="evolve.node")
- fm.plain(' ')
+ fm.write(b'node', b'%s', bytes(ctx),
+ label=b"evolve.node")
+ fm.plain(b' ')
- fm.write('rev', '(%d)', ctx.rev(),
- label="evolve.rev")
- fm.plain(' ')
+ fm.write(b'rev', b'(%d)', ctx.rev(),
+ label=b"evolve.rev")
+ fm.plain(b' ')
- fm.write('shortdescription', '%s', shortdescription,
- label="evolve.short_description")
- fm.plain('\n')
+ fm.write(b'shortdescription', b'%s', shortdescription,
+ label=b"evolve.short_description")
+ fm.plain(b'\n')
def _debugobshistorydisplaymissingctx(fm, nodewithoutctx):
hexnode = nodemod.short(nodewithoutctx)
fm.startitem()
- fm.write('node', '%s', hexnode,
- label="evolve.node evolve.missing_change_ctx")
- fm.plain('\n')
+ fm.write(b'node', b'%s', hexnode,
+ label=b"evolve.node evolve.missing_change_ctx")
+ fm.plain(b'\n')
def _debugobshistorydisplaymarker(fm, marker, node, repo, includediff=False):
succnodes = marker[1]
@@ -502,18 +502,18 @@
metadata = dict(marker[3])
fm.startitem()
- fm.plain(' ')
+ fm.plain(b' ')
# Detect pruned revisions
if len(succnodes) == 0:
- verb = 'pruned'
+ verb = b'pruned'
else:
- verb = 'rewritten'
+ verb = b'rewritten'
- fm.write('verb', '%s', verb,
- label="evolve.verb")
+ fm.write(b'verb', b'%s', verb,
+ label=b"evolve.verb")
- effectflag = metadata.get('ef1')
+ effectflag = metadata.get(b'ef1')
if effectflag is not None:
try:
effectflag = int(effectflag)
@@ -524,50 +524,50 @@
# XXX should be a dict
if effectflag & DESCCHANGED:
- effect.append('description')
+ effect.append(b'description')
if effectflag & METACHANGED:
- effect.append('meta')
+ effect.append(b'meta')
if effectflag & USERCHANGED:
- effect.append('user')
+ effect.append(b'user')
if effectflag & DATECHANGED:
- effect.append('date')
+ effect.append(b'date')
if effectflag & BRANCHCHANGED:
- effect.append('branch')
+ effect.append(b'branch')
if effectflag & PARENTCHANGED:
- effect.append('parent')
+ effect.append(b'parent')
if effectflag & DIFFCHANGED:
- effect.append('content')
+ effect.append(b'content')
if effect:
- fmteffect = fm.formatlist(effect, 'effect', sep=', ')
- fm.write('effect', '(%s)', fmteffect)
+ fmteffect = fm.formatlist(effect, b'effect', sep=b', ')
+ fm.write(b'effect', b'(%s)', fmteffect)
if len(succnodes) > 0:
- fm.plain(' as ')
+ fm.plain(b' as ')
shortsnodes = (nodemod.short(succnode) for succnode in sorted(succnodes))
- nodes = fm.formatlist(shortsnodes, 'succnodes', sep=', ')
- fm.write('succnodes', '%s', nodes,
- label="evolve.node")
+ nodes = fm.formatlist(shortsnodes, b'succnodes', sep=b', ')
+ fm.write(b'succnodes', b'%s', nodes,
+ label=b"evolve.node")
- operation = metadata.get('operation')
+ operation = metadata.get(b'operation')
if operation:
- fm.plain(' using ')
- fm.write('operation', '%s', operation, label="evolve.operation")
+ fm.plain(b' using ')
+ fm.write(b'operation', b'%s', operation, label=b"evolve.operation")
- fm.plain(' by ')
+ fm.plain(b' by ')
- fm.write('user', '%s', metadata['user'],
- label="evolve.user")
- fm.plain(' ')
+ fm.write(b'user', b'%s', metadata[b'user'],
+ label=b"evolve.user")
+ fm.plain(b' ')
- fm.write('date', '(%s)', fm.formatdate(date),
- label="evolve.date")
+ fm.write(b'date', b'(%s)', fm.formatdate(date),
+ label=b"evolve.date")
# initial support for showing note
- if metadata.get('note'):
- fm.plain('\n note: ')
- fm.write('note', "%s", metadata['note'], label="evolve.note")
+ if metadata.get(b'note'):
+ fm.plain(b'\n note: ')
+ fm.write(b'note', b"%s", metadata[b'note'], label=b"evolve.note")
# Patch display
if includediff is True:
@@ -585,40 +585,44 @@
if descriptionpatch:
# add the diffheader
- diffheader = "diff -r %s -r %s changeset-description\n" % \
+ diffheader = b"diff -r %s -r %s changeset-description\n" %\
(basectx, succctx)
descriptionpatch = diffheader + descriptionpatch
def tolist(text):
return [text]
- fm.plain("\n")
+ fm.plain(b"\n")
for chunk, label in patch.difflabel(tolist, descriptionpatch):
- chunk = chunk.strip('\t')
- if chunk and chunk != '\n':
- fm.plain(' ')
- fm.write('desc-diff', '%s', chunk, label=label)
+ chunk = chunk.strip(b'\t')
+ if chunk and chunk != b'\n':
+ fm.plain(b' ')
+ fm.write(b'desc-diff', b'%s', chunk, label=label)
# Content patch
diffopts = patch.diffallopts(repo.ui, {})
matchfn = scmutil.matchall(repo)
firstline = True
+ linestart = True
for chunk, label in patch.diffui(repo, node, succ, matchfn,
opts=diffopts):
if firstline:
- fm.plain('\n')
+ fm.plain(b'\n')
firstline = False
- if chunk and chunk != '\n':
- fm.plain(' ')
- fm.write('patch', '%s', chunk, label=label)
+ if linestart:
+ fm.plain(b' ')
+ linestart = False
+ if chunk == b'\n':
+ linestart = True
+ fm.write(b'patch', b'%s', chunk, label=label)
else:
- nopatch = " (No patch available, %s)" % _patchavailable[1]
- fm.plain("\n")
+ nopatch = b" (No patch available, %s)" % _patchavailable[1]
+ fm.plain(b"\n")
# TODO: should be in json too
fm.plain(nopatch)
- fm.plain("\n")
+ fm.plain(b"\n")
def _debugobshistorydisplaysuccsandmarkers(fm, succnodes, markers, node, repo, includediff=False):
"""
@@ -626,17 +630,17 @@
to accept multiple markers as input.
"""
fm.startitem()
- fm.plain(' ')
+ fm.plain(b' ')
# Detect pruned revisions
- verb = _successorsetverb(succnodes, markers)["verb"]
+ verb = _successorsetverb(succnodes, markers)[b"verb"]
- fm.write('verb', '%s', verb,
- label="evolve.verb")
+ fm.write(b'verb', b'%s', verb,
+ label=b"evolve.verb")
# Effect flag
metadata = [dict(marker[3]) for marker in markers]
- ef1 = [data.get('ef1') for data in metadata]
+ ef1 = [data.get(b'ef1') for data in metadata]
effectflag = 0
for ef in ef1:
@@ -648,45 +652,45 @@
# XXX should be a dict
if effectflag & DESCCHANGED:
- effect.append('description')
+ effect.append(b'description')
if effectflag & METACHANGED:
- effect.append('meta')
+ effect.append(b'meta')
if effectflag & USERCHANGED:
- effect.append('user')
+ effect.append(b'user')
if effectflag & DATECHANGED:
- effect.append('date')
+ effect.append(b'date')
if effectflag & BRANCHCHANGED:
- effect.append('branch')
+ effect.append(b'branch')
if effectflag & PARENTCHANGED:
- effect.append('parent')
+ effect.append(b'parent')
if effectflag & DIFFCHANGED:
- effect.append('content')
+ effect.append(b'content')
if effect:
- fmteffect = fm.formatlist(effect, 'effect', sep=', ')
- fm.write('effect', '(%s)', fmteffect)
+ fmteffect = fm.formatlist(effect, b'effect', sep=b', ')
+ fm.write(b'effect', b'(%s)', fmteffect)
if len(succnodes) > 0:
- fm.plain(' as ')
+ fm.plain(b' as ')
shortsnodes = (nodemod.short(succnode) for succnode in sorted(succnodes))
- nodes = fm.formatlist(shortsnodes, 'succnodes', sep=', ')
- fm.write('succnodes', '%s', nodes,
- label="evolve.node")
+ nodes = fm.formatlist(shortsnodes, b'succnodes', sep=b', ')
+ fm.write(b'succnodes', b'%s', nodes,
+ label=b"evolve.node")
# Operations
operations = compat.markersoperations(markers)
if operations:
- fm.plain(' using ')
- fm.write('operation', '%s', ", ".join(operations), label="evolve.operation")
+ fm.plain(b' using ')
+ fm.write(b'operation', b'%s', b", ".join(operations), label=b"evolve.operation")
- fm.plain(' by ')
+ fm.plain(b' by ')
# Users
users = compat.markersusers(markers)
- fm.write('user', '%s', ", ".join(users),
- label="evolve.user")
- fm.plain(' ')
+ fm.write(b'user', b'%s', b", ".join(users),
+ label=b"evolve.user")
+ fm.plain(b' ')
# Dates
dates = compat.markersdates(markers)
@@ -695,10 +699,10 @@
max_date = max(dates)
if min_date == max_date:
- fm.write("date", "(at %s)", fm.formatdate(min_date), label="evolve.date")
+ fm.write(b"date", b"(at %s)", fm.formatdate(min_date), label=b"evolve.date")
else:
- fm.write("date", "(between %s and %s)", fm.formatdate(min_date),
- fm.formatdate(max_date), label="evolve.date")
+ fm.write(b"date", b"(between %s and %s)", fm.formatdate(min_date),
+ fm.formatdate(max_date), label=b"evolve.date")
# initial support for showing note
# if metadata.get('note'):
@@ -721,40 +725,44 @@
if descriptionpatch:
# add the diffheader
- diffheader = "diff -r %s -r %s changeset-description\n" % \
+ diffheader = b"diff -r %s -r %s changeset-description\n" %\
(basectx, succctx)
descriptionpatch = diffheader + descriptionpatch
def tolist(text):
return [text]
- fm.plain("\n")
+ fm.plain(b"\n")
for chunk, label in patch.difflabel(tolist, descriptionpatch):
- chunk = chunk.strip('\t')
- if chunk and chunk != '\n':
- fm.plain(' ')
- fm.write('desc-diff', '%s', chunk, label=label)
+ chunk = chunk.strip(b'\t')
+ if chunk and chunk != b'\n':
+ fm.plain(b' ')
+ fm.write(b'desc-diff', b'%s', chunk, label=label)
# Content patch
diffopts = patch.diffallopts(repo.ui, {})
matchfn = scmutil.matchall(repo)
firstline = True
+ linestart = True
for chunk, label in patch.diffui(repo, node, succ, matchfn,
opts=diffopts):
if firstline:
- fm.plain('\n')
+ fm.plain(b'\n')
firstline = False
- if chunk and chunk != '\n':
- fm.plain(' ')
- fm.write('patch', '%s', chunk, label=label)
+ if linestart:
+ fm.plain(b' ')
+ linestart = False
+ if chunk == b'\n':
+ linestart = True
+ fm.write(b'patch', b'%s', chunk, label=label)
else:
- nopatch = " (No patch available, %s)" % _patchavailable[1]
- fm.plain("\n")
+ nopatch = b" (No patch available, %s)" % _patchavailable[1]
+ fm.plain(b"\n")
# TODO: should be in json too
fm.plain(nopatch)
- fm.plain("\n")
+ fm.plain(b"\n")
# logic around storing and using effect flags
DESCCHANGED = 1 << 0 # action changed the description
@@ -766,11 +774,11 @@
BRANCHCHANGED = 1 << 6 # the branch changed
METABLACKLIST = [
- re.compile('^__touch-noise__$'),
- re.compile('^branch$'),
- re.compile('^.*-source$'),
- re.compile('^.*_source$'),
- re.compile('^source$'),
+ re.compile(br'^__touch-noise__$'),
+ re.compile(br'^branch$'),
+ re.compile(br'^.*-source$'),
+ re.compile(br'^.*_source$'),
+ re.compile(br'^source$'),
]
def ismetablacklisted(metaitem):
@@ -814,17 +822,17 @@
if len(successorssets) == 0:
# The commit has been pruned
- return 'pruned'
+ return b'pruned'
elif len(successorssets) > 1:
- return 'diverged'
+ return b'diverged'
else:
# No divergence, only one set of successors
successors = successorssets[0]
if len(successors) == 1:
- return 'superseed'
+ return b'superseed'
else:
- return 'superseed_split'
+ return b'superseed_split'
def _getobsfateandsuccs(repo, revnode, successorssets=None):
""" Return a tuple containing:
@@ -857,8 +865,8 @@
dates = [m[4] for m in markers]
return {
- 'min_date': min(dates),
- 'max_date': max(dates)
+ b'min_date': min(dates),
+ b'max_date': max(dates)
}
def _successorsetusers(successorset, markers):
@@ -869,18 +877,18 @@
# Check that user is present in meta
markersmeta = [dict(m[3]) for m in markers]
- users = set(meta.get('user') for meta in markersmeta if meta.get('user'))
+ users = set(meta.get(b'user') for meta in markersmeta if meta.get(b'user'))
- return {'users': sorted(users)}
+ return {b'users': sorted(users)}
VERBMAPPING = {
- DESCCHANGED: "reworded",
- METACHANGED: "meta-changed",
- USERCHANGED: "reauthored",
- DATECHANGED: "date-changed",
- BRANCHCHANGED: "branch-changed",
- PARENTCHANGED: "rebased",
- DIFFCHANGED: "amended"
+ DESCCHANGED: b"reworded",
+ METACHANGED: b"meta-changed",
+ USERCHANGED: b"reauthored",
+ DATECHANGED: b"date-changed",
+ BRANCHCHANGED: b"branch-changed",
+ PARENTCHANGED: b"rebased",
+ DIFFCHANGED: b"amended"
}
def _successorsetverb(successorset, markers):
@@ -888,12 +896,12 @@
"""
verb = None
if not successorset:
- verb = 'pruned'
+ verb = b'pruned'
elif len(successorset) == 1:
# Check for effect flag
metadata = [dict(marker[3]) for marker in markers]
- ef1 = [data.get('ef1') for data in metadata]
+ ef1 = [data.get(b'ef1') for data in metadata]
if all(ef1):
combined = 0
@@ -905,17 +913,17 @@
verb = VERBMAPPING[combined]
if verb is None:
- verb = 'rewritten'
+ verb = b'rewritten'
else:
- verb = 'split'
- return {'verb': verb}
+ verb = b'split'
+ return {b'verb': verb}
# Use a more advanced version of obsfateverb that uses effect-flag
if util.safehasattr(obsutil, 'obsfateverb'):
@eh.wrapfunction(obsutil, 'obsfateverb')
def obsfateverb(orig, *args, **kwargs):
- return _successorsetverb(*args, **kwargs)['verb']
+ return _successorsetverb(*args, **kwargs)[b'verb']
# Hijack callers of successorsetverb
elif util.safehasattr(obsutil, 'obsfateprinter'):
@@ -924,7 +932,7 @@
def obsfateprinter(orig, successors, markers, ui):
def closure(successors):
- return _successorsetverb(successors, markers)['verb']
+ return _successorsetverb(successors, markers)[b'verb']
if not util.safehasattr(obsutil, 'successorsetverb'):
return orig(successors, markers, ui)
@@ -1000,8 +1008,8 @@
# Format basic data
data = {
- "successors": sorted(successorset),
- "markers": sorted(markers)
+ b"successors": sorted(successorset),
+ b"markers": sorted(markers)
}
# Call an extensible list of functions to override or add new data
--- a/hgext3rd/evolve/rewind.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/rewind.py Fri Sep 27 13:03:14 2019 +0200
@@ -32,8 +32,10 @@
(b'', b'exact', None, _(b"only rewind explicitly selected revisions")),
(b'', b'from', [],
_(b"rewind these revisions to their predecessors"), _(b'REV')),
+ (b'k', b'keep', None,
+ _(b"do not modify working directory during rewind")),
],
- _(b''),
+ _(b'[--as-divergence] [--exact] [--keep] [--to REV]... [--from REV]...'),
helpbasic=True)
def rewind(ui, repo, **opts):
"""rewind a stack of changesets to a previous state
@@ -46,7 +48,7 @@
obsolete the changeset you rewind from). Rewinding "to" will restore the
changeset you have selected (and obsolete their latest successors).
- By default, we rewind from the working copy parents, restoring its
+ By default, we rewind from the working directory parents, restoring its
predecessor.
When we rewind to an obsolete version, we also rewind to all its obsolete
@@ -90,15 +92,17 @@
ctx = unfi[rev]
ssets = obsutil.successorssets(repo, ctx.node(), sscache)
if 1 < len(ssets):
- msg = _('rewind confused by divergence on %s') % ctx
- hint = _('solve divergence first or use "--as-divergence"')
+ msg = _(b'rewind confused by divergence on %s') % ctx
+ hint = _(b'solve divergence first or use "--as-divergence"')
raise error.Abort(msg, hint=hint)
if ssets and ssets[0]:
for succ in ssets[0]:
successorsmap[succ].add(ctx.node())
# Check that we can rewind these changesets
- with repo.transaction('rewind'):
+ with repo.transaction(b'rewind'):
+ oldctx = repo[b'.']
+
for rev in sorted(rewinded):
ctx = unfi[rev]
rewindmap[ctx.node()] = _revive_revision(unfi, rev, rewindmap)
@@ -113,15 +117,47 @@
relationships.append(rel)
if wctxp.node() == source:
update_target = newdest[-1]
- obsolete.createmarkers(unfi, relationships, operation='rewind')
+ obsolete.createmarkers(unfi, relationships, operation=b'rewind')
if update_target is not None:
- hg.updaterepo(repo, update_target, False)
+ if opts.get('keep'):
+ hg.updaterepo(repo, oldctx, True)
+
+ # This is largely the same as the implementation in
+ # strip.stripcmd() and cmdrewrite.cmdprune().
+
+ # only reset the dirstate for files that would actually
+ # change between the working context and the revived cset
+ newctx = repo[update_target]
+ changedfiles = []
+ for ctx in [oldctx, newctx]:
+ # blindly reset the files, regardless of what actually
+ # changed
+ changedfiles.extend(ctx.files())
- repo.ui.status(_('rewinded to %d changesets\n') % len(rewinded))
+ # reset files that only changed in the dirstate too
+ dirstate = repo.dirstate
+ dirchanges = [f for f in dirstate if dirstate[f] != 'n']
+ changedfiles.extend(dirchanges)
+ repo.dirstate.rebuild(newctx.node(), newctx.manifest(),
+ changedfiles)
+
+ # TODO: implement restoration of copies/renames
+ # Ideally this step should be handled by dirstate.rebuild
+ # or scmutil.movedirstate, but right now there's no copy
+ # tracing across obsolescence relation (oldctx <-> newctx).
+ revertopts = {'no_backup': True, 'all': True,
+ 'rev': oldctx.node()}
+ with ui.configoverride({(b'ui', b'quiet'): True}):
+ cmdutil.revert(repo.ui, repo, oldctx,
+ repo.dirstate.parents(), **revertopts)
+ else:
+ hg.updaterepo(repo, update_target, False)
+
+ repo.ui.status(_(b'rewinded to %d changesets\n') % len(rewinded))
if relationships:
- repo.ui.status(_('(%d changesets obsoleted)\n') % len(relationships))
- if update_target is not None:
- ui.status(_('working directory is now at %s\n') % repo['.'])
+ repo.ui.status(_(b'(%d changesets obsoleted)\n') % len(relationships))
+ if update_target is not None and not opts.get('keep'):
+ ui.status(_(b'working directory is now at %s\n') % repo[b'.'])
def _select_rewinded(repo, opts):
"""select the revision we shoudl rewind to
@@ -131,18 +167,18 @@
revsto = opts.get('to')
revsfrom = opts.get('from')
if not (revsto or revsfrom):
- revsfrom.append('.')
+ revsfrom.append(b'.')
if revsto:
rewinded.update(scmutil.revrange(repo, revsto))
if revsfrom:
succs = scmutil.revrange(repo, revsfrom)
- rewinded.update(unfi.revs('predecessors(%ld)', succs))
+ rewinded.update(unfi.revs(b'predecessors(%ld)', succs))
if not rewinded:
- raise error.Abort('no revision to rewind to')
+ raise error.Abort(b'no revision to rewind to')
if not opts['exact']:
- rewinded = unfi.revs('obsolete() and ::%ld', rewinded)
+ rewinded = unfi.revs(b'obsolete() and ::%ld', rewinded)
return sorted(rewinded)
@@ -152,14 +188,14 @@
ctx = unfi[rev]
extra = ctx.extra().copy()
# rewind hash should be unique over multiple rewind.
- user = unfi.ui.config('devel', 'user.obsmarker')
+ user = unfi.ui.config(b'devel', b'user.obsmarker')
if not user:
user = unfi.ui.username()
- date = unfi.ui.configdate('devel', 'default-date')
+ date = unfi.ui.configdate(b'devel', b'default-date')
if date is None:
date = compat.makedate()
- noise = "%s\0%s\0%d\0%d" % (ctx.node(), user, date[0], date[1])
- extra['__rewind-hash__'] = hashlib.sha256(noise).hexdigest()
+ noise = b"%s\0%s\0%d\0%d" % (ctx.node(), user, date[0], date[1])
+ extra[b'__rewind-hash__'] = hashlib.sha256(noise).hexdigest()
p1 = ctx.p1().node()
p1 = rewindmap.get(p1, p1)
@@ -169,13 +205,13 @@
updates = []
if len(ctx.parents()) > 1:
updates = ctx.parents()
- extradict = {'extra': extra}
+ extradict = {b'extra': extra}
new, unusedvariable = rewriteutil.rewrite(unfi, ctx, updates, ctx,
[p1, p2],
commitopts=extradict)
obsolete.createmarkers(unfi, [(ctx, (unfi[new],))],
- flag=identicalflag, operation='rewind')
+ flag=identicalflag, operation=b'rewind')
return new
--- a/hgext3rd/evolve/rewriteutil.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/rewriteutil.py Fri Sep 27 13:03:14 2019 +0200
@@ -44,37 +44,37 @@
numrevs = len(revs)
if numrevs < maxrevs:
shorts = [node.short(tonode(r)) for r in revs]
- summary = ', '.join(shorts)
+ summary = b', '.join(shorts)
else:
first = revs.first()
- summary = _('%s and %d others')
+ summary = _(b'%s and %d others')
summary %= (node.short(tonode(first)), numrevs - 1)
return summary
-def precheck(repo, revs, action='rewrite'):
+def precheck(repo, revs, action=b'rewrite'):
"""check if <revs> can be rewritten
<action> can be used to control the commit message.
"""
if node.nullrev in revs:
- msg = _("cannot %s the null revision") % (action)
- hint = _("no changeset checked out")
+ msg = _(b"cannot %s the null revision") % (action)
+ hint = _(b"no changeset checked out")
raise error.Abort(msg, hint=hint)
if any(util.safehasattr(r, 'rev') for r in revs):
- msg = "rewriteutil.precheck called with ctx not revs"
+ msg = b"rewriteutil.precheck called with ctx not revs"
repo.ui.develwarn(msg)
revs = (r.rev() for r in revs)
- publicrevs = repo.revs('%ld and public()', revs)
+ publicrevs = repo.revs(b'%ld and public()', revs)
if publicrevs:
summary = _formatrevs(repo, publicrevs)
- msg = _("cannot %s public changesets: %s") % (action, summary)
- hint = _("see 'hg help phases' for details")
+ msg = _(b"cannot %s public changesets: %s") % (action, summary)
+ hint = _(b"see 'hg help phases' for details")
raise error.Abort(msg, hint=hint)
newunstable = disallowednewunstable(repo, revs)
if newunstable:
- msg = _("%s will orphan %i descendants")
+ msg = _(b"%s will orphan %i descendants")
msg %= (action, len(newunstable))
- hint = _("see 'hg help evolution.instability'")
+ hint = _(b"see 'hg help evolution.instability'")
raise error.Abort(msg, hint=hint)
def bookmarksupdater(repo, oldid, tr):
@@ -96,27 +96,34 @@
allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
if allowunstable:
return revset.baseset()
- return repo.revs("(%ld::) - %ld", revs, revs)
+ return repo.revs(b"(%ld::) - %ld", revs, revs)
def foldcheck(repo, revs):
"""check that <revs> can be folded"""
- precheck(repo, revs, action='fold')
- roots = repo.revs('roots(%ld)', revs)
+ precheck(repo, revs, action=b'fold')
+ roots = repo.revs(b'roots(%ld)', revs)
if len(roots) > 1:
- raise error.Abort(_("cannot fold non-linear revisions "
- "(multiple roots given)"))
+ raise error.Abort(_(b"cannot fold non-linear revisions "
+ b"(multiple roots given)"))
root = repo[roots.first()]
if root.phase() <= phases.public:
- raise error.Abort(_("cannot fold public revisions"))
- heads = repo.revs('heads(%ld)', revs)
+ raise error.Abort(_(b"cannot fold public revisions"))
+ heads = repo.revs(b'heads(%ld)', revs)
if len(heads) > 1:
- raise error.Abort(_("cannot fold non-linear revisions "
- "(multiple heads given)"))
+ raise error.Abort(_(b"cannot fold non-linear revisions "
+ b"(multiple heads given)"))
head = repo[heads.first()]
- baseparents = repo.revs('parents(%ld) - %ld', revs, revs)
+ baseparents = repo.revs(b'parents(%ld) - %ld', revs, revs)
if len(baseparents) > 2:
- raise error.Abort(_("cannot fold revisions that merge with more than "
- "one external changeset (not in revisions)"))
+ raise error.Abort(_(b"cannot fold revisions that merge with more than "
+ b"one external changeset (not in revisions)"))
+ if not repo.ui.configbool(b'experimental', b'evolution.allowdivergence'):
+ obsolete = repo.revs(b'%ld and obsolete()', revs)
+ if obsolete:
+ msg = _(b'folding obsolete revisions may cause divergence')
+ hint = _(b'set experimental.evolution.allowdivergence=yes'
+ b' to allow folding them')
+ raise error.Abort(msg, hint=hint)
# root's p1 is already used as the target ctx p1
baseparents -= {root.p1().rev()}
p2 = repo[baseparents.first()]
@@ -127,14 +134,14 @@
try:
wlock = repo.wlock()
lock = repo.lock()
- tr = repo.transaction('prune')
+ tr = repo.transaction(b'prune')
bmchanges = []
for bookmark in bookmarks:
bmchanges.append((bookmark, None))
repo._bookmarks.applychanges(repo, tr, bmchanges)
tr.close()
for bookmark in sorted(bookmarks):
- repo.ui.write(_("bookmark '%s' deleted\n") % bookmark)
+ repo.ui.write(_(b"bookmark '%s' deleted\n") % bookmark)
finally:
lockmod.release(tr, lock, wlock)
@@ -150,8 +157,8 @@
"""
repomarks = repo._bookmarks
if not bookmarks.issubset(repomarks):
- raise error.Abort(_("bookmark '%s' not found") %
- ','.join(sorted(bookmarks - set(repomarks.keys()))))
+ raise error.Abort(_(b"bookmark '%s' not found") %
+ b','.join(sorted(bookmarks - set(repomarks.keys()))))
# If the requested bookmark is not the only one pointing to a
# a revision we have to only delete the bookmark and not strip
@@ -177,7 +184,7 @@
try:
wlock = repo.wlock()
lock = repo.lock()
- tr = repo.transaction('rewrite')
+ tr = repo.transaction(b'rewrite')
base = old.p1()
updatebookmarks = bookmarksupdater(repo, old.node(), tr)
@@ -218,13 +225,13 @@
if not message:
message = old.description()
- user = commitopts.get('user') or old.user()
+ user = commitopts.get(b'user') or old.user()
# TODO: In case not date is given, we should take the old commit date
# if we are working one one changeset or mimic the fold behavior about
# date
- date = commitopts.get('date') or None
- extra = dict(commitopts.get('extra', old.extra()))
- extra['branch'] = head.branch()
+ date = commitopts.get(b'date') or None
+ extra = dict(commitopts.get(b'extra', old.extra()))
+ extra[b'branch'] = head.branch()
new = context.memctx(repo,
parents=newbases,
@@ -235,7 +242,7 @@
date=date,
extra=extra)
- if commitopts.get('edit'):
+ if commitopts.get(b'edit'):
new._text = cmdutil.commitforceeditor(repo, new, [])
revcount = len(repo)
newid = repo.commitctx(new)
--- a/hgext3rd/evolve/safeguard.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/safeguard.py Fri Sep 27 13:03:14 2019 +0200
@@ -20,9 +20,9 @@
eh = exthelper.exthelper()
# hg <= 4.8
-if 'auto-publish' not in configitems.coreitems.get('experimental', {}):
+if b'auto-publish' not in configitems.coreitems.get(b'experimental', {}):
- eh.configitem('experimental', 'auto-publish', 'publish')
+ eh.configitem(b'experimental', b'auto-publish', b'publish')
@eh.reposetup
def setuppublishprevention(ui, repo):
@@ -31,25 +31,25 @@
def checkpush(self, pushop):
super(noautopublishrepo, self).checkpush(pushop)
- behavior = self.ui.config('experimental', 'auto-publish')
- nocheck = behavior not in ('warn', 'abort')
+ behavior = self.ui.config(b'experimental', b'auto-publish')
+ nocheck = behavior not in (b'warn', b'abort')
if nocheck or getattr(pushop, 'publish', False):
return
- remotephases = pushop.remote.listkeys('phases')
- publishing = remotephases.get('publishing', False)
+ remotephases = pushop.remote.listkeys(b'phases')
+ publishing = remotephases.get(b'publishing', False)
if publishing:
if pushop.revs is None:
- published = self.filtered('served').revs("not public()")
+ published = self.filtered(b'served').revs(b"not public()")
else:
- published = self.revs("::%ln - public()", pushop.revs)
+ published = self.revs(b"::%ln - public()", pushop.revs)
if published:
- if behavior == 'warn':
- self.ui.warn(_('%i changesets about to be published\n')
+ if behavior == b'warn':
+ self.ui.warn(_(b'%i changesets about to be published\n')
% len(published))
- elif behavior == 'abort':
- msg = _('push would publish 1 changesets')
- hint = _("behavior controlled by "
- "'experimental.auto-publish' config")
+ elif behavior == b'abort':
+ msg = _(b'push would publish 1 changesets')
+ hint = _(b"behavior controlled by "
+ b"'experimental.auto-publish' config")
raise error.Abort(msg, hint=hint)
repo.__class__ = noautopublishrepo
--- a/hgext3rd/evolve/serveronly.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/serveronly.py Fri Sep 27 13:03:14 2019 +0200
@@ -25,7 +25,7 @@
)
except (ValueError, ImportError) as exc:
if (isinstance(exc, ValueError)
- and str(exc) != 'Attempted relative import in non-package'):
+ and str(exc) != b'Attempted relative import in non-package'):
raise
# extension imported using direct path
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
@@ -54,11 +54,11 @@
@eh.reposetup
def default2evolution(ui, repo):
- evolveopts = repo.ui.configlist('experimental', 'evolution')
+ evolveopts = repo.ui.configlist(b'experimental', b'evolution')
if not evolveopts:
- evolveopts = 'all'
- repo.ui.setconfig('experimental', 'evolution', evolveopts)
- if obsolete.isenabled(repo, 'exchange'):
+ evolveopts = b'all'
+ repo.ui.setconfig(b'experimental', b'evolution', evolveopts)
+ if obsolete.isenabled(repo, b'exchange'):
# if no config explicitly set, disable bundle1
- if not isinstance(repo.ui.config('server', 'bundle1'), bytes):
- repo.ui.setconfig('server', 'bundle1', False)
+ if not isinstance(repo.ui.config(b'server', b'bundle1'), bytes):
+ repo.ui.setconfig(b'server', b'bundle1', False)
--- a/hgext3rd/evolve/stablerange.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/stablerange.py Fri Sep 27 13:03:14 2019 +0200
@@ -6,6 +6,352 @@
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+r"""stable range
+
+General Goals and Properties
+---------------------------
+
+Stable-ranges get useful when some logic needs a recursive way to slice the
+history of a repository in smaller and smaller group of revisions. Here is
+example of such use cases:
+
+* **bundle caching:**
+ With an easy way to slice any subsets of history into stable-ranges, we
+ can cache a small number of bundles covering these ranges and reuse them for
+ other pull operations. Even if the pull operation have different boudaries.
+
+* **metadata discovery:**
+ With a simple way to recursively look at smaller and smaller ranges, an
+ algorithm can do fine-grained discovery of area of history where some mutable
+ metadata differ from one repository to another. Such meta data can be
+ obsolescence markers, CI status, lightweight stag, etc...
+
+To fix these use cases best, stable-ranges need some important properties:
+
+* the total number of ranges needed to cover a full repository is well bounded.
+* the minimal number of ranges to cover an arbitrary subset of the history is well bounded
+* for the same section of history, the range will be the same on any
+ repositories,
+* the ranges are cheap to compute iteratively, each new revisions re-uses the
+ ranges previous revisions uses.
+
+Simple introduction to the Concepts
+-----------------------------------
+
+To keep things simple, let us look at the issue on a linear history::
+
+ A -> B -> C -> D -> E -> F -> G -> H
+
+To make sure we have range that cover each part of the history with a good
+granularity we use some binary recursion. The standard stable range will be:
+
+ [A -> B -> C -> D -> E -> F -> G -> H] size 8
+ [A -> B -> C -> D] [E -> F -> G -> H] size 4
+ [A -> B] [C -> D] [E -> F] [G -> H] size 2
+ [A] [B] [C] [D] [E] [F] [G] [H] size 1
+
+Well bounded total number of ranges:
+````````````````````````````````````
+
+This binary slicing make sure we keep the total number of stable ranges under control.
+
+As you can see, we have N size 1 ranges. They are trivial and we don't care
+about them. Then we have: N/2 size 2 ranges + N/4 size 4 ranges + N/8 size 8
+ranges, etc... So a total of about "length(repo)" standard ranges.
+
+
+Well bounded number of range to cover a subset:
+```````````````````````````````````````````````
+
+Any subset of the history can be expressed with this standard ranges.
+
+For example, [A, F] subset, can be covered with 2 ranges::
+
+ [A ->[B -> C -> D] [E -> F]
+
+A less strivial example [B, F], still requires a small number of ranges (3)::
+
+ [B] [C -> D] [E -> F]
+
+In practice, any subset can be expressed in at most "2 x log2(length(subset))"
+stable range, well bounded value.
+
+Cheap incremental updates
+`````````````````````````
+
+The scheme describe above result in 2N subranges for a repository is size N. We
+do not want to have to recompute these 2N stable-ranges whenever a new revision
+is added to the repository. To achieve these, the stable-ranges are defined by
+**fixed boundaries** that are independant from the total size of the
+repository. Here is how it looks like in our example.
+
+We start with a repository having only [A, F]. Notice how we still creates
+power of two sized stable range::
+
+ [A -> B -> C -> D]
+ [A -> B] [C -> D] [E -> F]
+ [A] [B] [C] [D] [E] [F]
+
+This we simply adds a new revision G, we reuse more the range we already have::
+
+ [A -> B -> C -> D]
+ [A -> B] [C -> D] [E -> F]
+ [A] [B] [C] [D] [E] [F] [G]
+
+Adding H is a bigger even as we read a new boundary.
+
+ [A -> B -> C -> D -> E -> F -> G -> H]
+ [A -> B -> C -> D] [E -> F -> G -> H]
+ [A -> B] [C -> D] [E -> F] [G -> H]
+ [A] [B] [C] [D] [E] [F] [G] [H]
+
+At most, adding a new revision `R` will introduces `log2(length(::R))` new
+stable ranges.
+
+More advanced elements
+----------------------
+
+Of course, the history of repository is not as simple as our linear example. So
+how do we deal with the branching and merging? To do so, we leverage the
+"stable sort" algorithm defined in the `stablesort.py` module. To define the
+stable range that compose a set of revison `::R`, we linearize the space by
+sorting it. The stable sort algorithm has two important property:
+
+First, it give the same result on different repository. So we can use it to
+algorithm involving multiple peers.
+
+Second, in case of merge, it reuse the same order as the parents as much as possible.
+This is important to keep reusing existing stable range as the repository grow.
+
+How are ranges defined?
+```````````````````````
+
+To keep things small, and simple, a stable range always contains the final part
+of a `stablesort(::R)` set of revision. It is defined by two items:
+
+* its head revision, the R in `stablesort(::R)`
+* the size of that range... well almost, for implementation reason, it uses the
+ index of the first included item. Or in other word, the number of excluded
+ initial item in `stablesort(::R)`.
+
+Lets look at a practical case. In our initial example, `[A, B, C, D, E, F, G,
+H]` is H-0; `[E, F, G, H]` is H-4; `[G, H]` is H-6 and `[H]` is H-7.
+
+Let us look at a non linar graph::
+
+ A - B - C - E
+ | /
+ -D
+
+and assume that `stablesort(::E) = [A, B, C, D, E]`. Then `[A, B, C]` is C-0,
+`[A, B, D]` is D-0; `[D, E]` is E-3, `[E]` is E-4, etc...
+
+Slicing in a non linear context
+```````````````````````````````
+
+Branching can also affect the way we slice things.
+
+The small example above offers a simple example. For a size 5 (starting at the
+root), standard slicing will want a size 4 part and size 1 part. So, in a
+simple linear space `[A, B, C, D, E]` would be sliced as `[A, B, C, D] + [E]`.
+However, in our non-linear case, `[A, B, C, D]` has two heads (C and D) and
+cannot be expressed with a single range. As a result the range will be sliced
+into more sub ranges::
+
+ stdslice(A-0) = [A, B, C] + [D] + [E] = C-0 + D-2 + A-4
+
+Yet, this does not mean ranges containing a merge will always result in slicing
+with many revision. the sub ranges might also silently contains them. Let us
+look at an exemple::
+
+ A - B - C - D - E --- G - H
+ | /
+ ---------- F
+
+with::
+
+ `stablesort(::H) == [A, B, C, D, E, F, G, H]`
+
+then::
+
+ stdslice(H-0) = [A, B, C, D] + [E, F, G, H] = D-0 + H-4
+
+As a result the non linearity will increase the number of subranges involved,
+but in practice the impact stay limited.
+
+The total number of standard subranges stay under control with about
+`O(log2(N))` new stable range introduced for each new revision. In practice the
+total number of stableranges we have is about `O(length(repo))`
+
+In addition, it is worth nothing that the head of the extra ranges we have to
+use will match the destination of the "jump" cached by the stablesort
+algorithm. So, all this slicing can usually be done without iterating over the
+stable sorted revision.
+
+Caching Strategy
+----------------
+
+The current caching strategy use a very space inefficient sqlite database.
+testing show it often take 100x more space than what basic binary storage would
+take. The sqlite storage was very useful at the proof of concept stage.
+
+Since all new stable-ranges introduced by a revision R will be "R headed". So we
+could easily store their standard subranges alongside the revision information
+to reuse the existing revision index.
+
+Subrange information can be efficiently stored, a naive approach storing all
+stable ranges and their subranges would requires just 2 integer per range + 2
+integer for any extra sub-ranges other than the first and last ones.
+
+We can probably push efficiency further by taking advantage of the large
+overlap in subranges for one non-merge revision to the next. This is probably a
+premature optimisation until we start getting actual result for a naive binary
+storage.
+
+To use this at a large scale, it would be important to compute these data at
+commit time and to exchange them alongside the revision over the network. This
+is similar to what we do for other cached data.
+
+It is also important to note that the smaller ranges can probably be computed
+on the fly instead of being cached. The exact tradeoff would requires some
+field testing.
+
+Performance
+-----------
+
+The current implementation has not been especially optimized for performance.
+The goal was mostly to get the order of magnitude of the algorithm complexity.
+The result are convincing: medium repository get a full cache warming in a
+couple of seconds and even very large and branchy repository get a fully warmed
+in the order of tens of minutes. We do not observes a complexity explosion
+making the algorithm unusable of large repositories.
+
+A better cache implementation combined with an optimized version of the
+algorithm should give much faster performance. Combined with commit-time
+computation and exchange over the network, the overall impact of this should be
+invisible to the user.
+
+The stable range is currently successfully used in production for 2 use cases:
+* obsolescence markers discovery,
+* caching precomputed bundle while serving pulls
+
+practical data
+--------------
+
+The evolve repository:
+
+ number of revisions: 4833
+ number of heads: 15
+ number of merge: 612 ( 12%)
+ number of range: 4826
+ with 2 subranges: 4551 ( 94%)
+ with 3 subranges: 255 ( 5%)
+ with 4 subranges: 12 ( 0%)
+ with 5 subranges: 7 ( 0%)
+ with 8 subranges: 1 ( 0%)
+ average range/revs: 0.99
+
+ Estimated approximative size of a naive compact storage:
+ 41 056 bytes
+ Current size of the sqlite cache (for comparison):
+ 5 312 512 bytes
+
+The mercurial repository:
+
+ number of revisions: 42849
+ number of heads: 2
+ number of merge: 2647 ( 6%)
+ number of range: 41279
+ with 2 subranges: 39740 ( 96%)
+ with 3 subranges: 1494 ( 3%)
+ with 4 subranges: 39 ( 0%)
+ with 5 subranges: 5 ( 0%)
+ with 7 subranges: 1 ( 0%)
+ average range/revs: 0.96
+ Estimated approximative size of a naive compact storage:
+ 342 968 bytes
+ Current size of the sqlite cache (for comparison):
+ 62 803 968 bytes
+
+The pypy repository (very brancy history):
+
+ number of revisions: 97409
+ number of heads: 183
+ number of merge: 8371 ( 8%)
+ number of range: 107025
+ with 2 subranges: 100166 ( 93%)
+ with 3 subranges: 5839 ( 5%)
+ with 4 subranges: 605 ( 0%)
+ with 5 subranges: 189 ( 0%)
+ with 6 subranges: 90 ( 0%)
+ with 7 subranges: 38 ( 0%)
+ with 8 subranges: 18 ( 0%)
+ with 9 subranges: 9 ( 0%)
+ with 10 subranges: 15 ( 0%)
+ with 11 subranges: 4 ( 0%)
+ with 12 subranges: 6 ( 0%)
+ with 13 subranges: 7 ( 0%)
+ with 14 subranges: 6 ( 0%)
+ with 15 subranges: 1 ( 0%)
+ with 16 subranges: 2 ( 0%)
+ with 17 subranges: 2 ( 0%)
+ with 18 subranges: 3 ( 0%)
+ with 19 subranges: 2 ( 0%)
+ with 20 subranges: 3 ( 0%)
+ with 25 subranges: 1 ( 0%)
+ with 27 subranges: 1 ( 0%)
+ with 31 subranges: 3 ( 0%)
+ with 32 subranges: 2 ( 0%)
+ with 33 subranges: 1 ( 0%)
+ with 35 subranges: 1 ( 0%)
+ with 43 subranges: 1 ( 0%)
+ with 44 subranges: 1 ( 0%)
+ with 45 subranges: 2 ( 0%)
+ with 47 subranges: 1 ( 0%)
+ with 51 subranges: 1 ( 0%)
+ with 52 subranges: 1 ( 0%)
+ with 57 subranges: 1 ( 0%)
+ with 65 subranges: 1 ( 0%)
+ with 73 subranges: 1 ( 0%)
+ with 79 subranges: 1 ( 0%)
+ average range/revs: 1.10
+ Estimated approximative size of a naive compact storage:
+ 934 176 bytes
+ Current size of the sqlite cache (for comparison):
+ 201 236 480 bytes
+
+A private and branchy repository:
+
+ number of revisions: 605011
+ number of heads: 14061
+ number of merge: 118109 ( 19%)
+ number of range: 747625
+ with 2 subranges: 595985 ( 79%)
+ with 3 subranges: 130196 ( 17%)
+ with 4 subranges: 14093 ( 1%)
+ with 5 subranges: 4090 ( 0%)
+ with 6 subranges: 741 ( 0%)
+ with 7 subranges: 826 ( 0%)
+ with 8 subranges: 1313 ( 0%)
+ with 9 subranges: 83 ( 0%)
+ with 10 subranges: 22 ( 0%)
+ with 11 subranges: 9 ( 0%)
+ with 12 subranges: 26 ( 0%)
+ with 13 subranges: 5 ( 0%)
+ with 14 subranges: 9 ( 0%)
+ with 15 subranges: 3 ( 0%)
+ with 16 subranges: 212 ( 0%)
+ with 18 subranges: 6 ( 0%)
+ with 19 subranges: 3 ( 0%)
+ with 24 subranges: 1 ( 0%)
+ with 27 subranges: 1 ( 0%)
+ with 32 subranges: 1 ( 0%)
+ average range/revs: 1.23
+ Estimated approximative size of a naive compact storage:
+ 7 501 928 bytes
+ Current size of the sqlite cache (for comparison):
+ 1 950 310 400 bytes
+"""
import abc
import functools
@@ -64,11 +410,11 @@
return ranges
_stablerangemethodmap = {
- 'branchpoint': lambda repo: stablerange(),
- 'default': lambda repo: repo.stablerange,
- 'basic-branchpoint': lambda repo: stablerangebasic(),
- 'basic-mergepoint': lambda repo: stablerangedummy_mergepoint(),
- 'mergepoint': lambda repo: stablerange_mergepoint(),
+ b'branchpoint': lambda repo: stablerange(),
+ b'default': lambda repo: repo.stablerange,
+ b'basic-branchpoint': lambda repo: stablerangebasic(),
+ b'basic-mergepoint': lambda repo: stablerangedummy_mergepoint(),
+ b'mergepoint': lambda repo: stablerange_mergepoint(),
}
@eh.command(
@@ -90,9 +436,9 @@
short = nodemod.short
revs = scmutil.revrange(repo, opts['rev'])
if not revs:
- raise error.Abort('no revisions specified')
+ raise error.Abort(b'no revisions specified')
if ui.verbose:
- template = '%s-%d (%d, %d, %d)'
+ template = b'%s-%d (%d, %d, %d)'
def _rangestring(repo, rangeid):
return template % (
@@ -103,7 +449,7 @@
length(unfi, rangeid)
)
else:
- template = '%s-%d'
+ template = b'%s-%d'
def _rangestring(repo, rangeid):
return template % (
@@ -117,7 +463,7 @@
method = opts['method']
getstablerange = _stablerangemethodmap.get(method)
if getstablerange is None:
- raise error.Abort('unknown stable sort method: "%s"' % method)
+ raise error.Abort(b'unknown stable sort method: "%s"' % method)
stablerange = getstablerange(unfi)
depth = stablerange.depthrev
@@ -132,21 +478,21 @@
for r in ranges:
subs = subranges(unfi, r)
- subsstr = ', '.join(_rangestring(unfi, s) for s in subs)
+ subsstr = b', '.join(_rangestring(unfi, s) for s in subs)
rstr = _rangestring(unfi, r)
if opts['verify']:
- status = 'leaf'
+ status = b'leaf'
if 1 < length(unfi, r):
- status = 'complete'
+ status = b'complete'
revs = set(stablerange.revsfromrange(unfi, r))
subrevs = set()
for s in subs:
subrevs.update(stablerange.revsfromrange(unfi, s))
if revs != subrevs:
- status = 'missing'
- ui.status('%s [%s] - %s\n' % (rstr, status, subsstr))
+ status = b'missing'
+ ui.status(b'%s [%s] - %s\n' % (rstr, status, subsstr))
else:
- ui.status('%s - %s\n' % (rstr, subsstr))
+ ui.status(b'%s - %s\n' % (rstr, subsstr))
class abstractstablerange(object):
"""The official API for a stablerange"""
@@ -214,7 +560,7 @@
def depthrev(self, repo, rev):
"""depth a revision"""
- return len(repo.revs('::%d', rev))
+ return len(repo.revs(b'::%d', rev))
def revsfromrange(self, repo, rangeid):
"""return revision contained in a range
@@ -620,12 +966,12 @@
rangeheap = []
for idx, r in enumerate(revs):
if not idx % 1000:
- compat.progress(ui, _("filling depth cache"), idx, total=nbrevs,
- unit=_("changesets"))
+ compat.progress(ui, _(b"filling depth cache"), idx, total=nbrevs,
+ unit=_(b"changesets"))
# warm up depth
self.depthrev(repo, r)
rangeheap.append((-r, (r, 0)))
- compat.progress(ui, _("filling depth cache"), None, total=nbrevs)
+ compat.progress(ui, _(b"filling depth cache"), None, total=nbrevs)
heappop = heapq.heappop
heappush = heapq.heappush
@@ -646,8 +992,8 @@
progress_new = time.time()
if (1 < progress_each) and (0.1 < progress_new - progress_last):
progress_each /= 10
- compat.progress(ui, _("filling stablerange cache"), seen,
- total=nbrevs, unit=_("changesets"))
+ compat.progress(ui, _(b"filling stablerange cache"), seen,
+ total=nbrevs, unit=_(b"changesets"))
progress_last = progress_new
seen += 1
original.remove(value) # might have been added from other source
@@ -656,13 +1002,13 @@
for sub in self.subranges(repo, rangeid):
if self._getsub(sub) is None:
heappush(rangeheap, (-sub[0], sub))
- compat.progress(ui, _("filling stablerange cache"), None, total=nbrevs)
+ compat.progress(ui, _(b"filling stablerange cache"), None, total=nbrevs)
self._tiprev = upto
self._tipnode = cl.node(upto)
duration = util.timer() - starttime
- repo.ui.log('evoext-cache', 'updated stablerange cache in %.4f seconds\n',
+ repo.ui.log(b'evoext-cache', b'updated stablerange cache in %.4f seconds\n',
duration)
def subranges(self, repo, rangeid):
--- a/hgext3rd/evolve/stablerangecache.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/stablerangecache.py Fri Sep 27 13:03:14 2019 +0200
@@ -14,6 +14,7 @@
import time
from mercurial import (
+ commands,
encoding,
error,
localrepo,
@@ -35,7 +36,7 @@
LONG_WARNING_TIME = 60
-LONG_MESSAGE = """Stable range cache is taking a while to load
+LONG_MESSAGE = b"""Stable range cache is taking a while to load
Your repository is probably big.
@@ -99,8 +100,8 @@
warned_long = True
if (1 < progress_each) and (0.1 < progress_new - progress_last):
progress_each /= 10
- compat.progress(ui, _("filling stablerange cache"), seen,
- total=total, unit=_("changesets"))
+ compat.progress(ui, _(b"filling stablerange cache"), seen,
+ total=total, unit=_(b"changesets"))
progress_last = progress_new
seen += 1
original.remove(rangeid) # might have been added from other source
@@ -109,7 +110,7 @@
for sub in self.subranges(repo, rangeid):
if self._getsub(sub) is None:
heappush(rangeheap, sub)
- compat.progress(ui, _("filling stablerange cache"), None, total=total)
+ compat.progress(ui, _(b"filling stablerange cache"), None, total=total)
def clear(self, reset=False):
super(stablerangeondiskbase, self).clear()
@@ -120,10 +121,10 @@
#############################
_sqliteschema = [
- """CREATE TABLE range(rev INTEGER NOT NULL,
+ r"""CREATE TABLE range(rev INTEGER NOT NULL,
idx INTEGER NOT NULL,
PRIMARY KEY(rev, idx));""",
- """CREATE TABLE subranges(listidx INTEGER NOT NULL,
+ r"""CREATE TABLE subranges(listidx INTEGER NOT NULL,
suprev INTEGER NOT NULL,
supidx INTEGER NOT NULL,
subrev INTEGER NOT NULL,
@@ -132,37 +133,37 @@
FOREIGN KEY (suprev, supidx) REFERENCES range(rev, idx),
FOREIGN KEY (subrev, subidx) REFERENCES range(rev, idx)
);""",
- "CREATE INDEX subranges_index ON subranges (suprev, supidx);",
- "CREATE INDEX superranges_index ON subranges (subrev, subidx);",
- "CREATE INDEX range_index ON range (rev, idx);",
- """CREATE TABLE meta(schemaversion INTEGER NOT NULL,
+ r"CREATE INDEX subranges_index ON subranges (suprev, supidx);",
+ r"CREATE INDEX superranges_index ON subranges (subrev, subidx);",
+ r"CREATE INDEX range_index ON range (rev, idx);",
+ r"""CREATE TABLE meta(schemaversion INTEGER NOT NULL,
tiprev INTEGER NOT NULL,
tipnode BLOB NOT NULL
);""",
]
-_newmeta = "INSERT INTO meta (schemaversion, tiprev, tipnode) VALUES (?,?,?);"
-_updatemeta = "UPDATE meta SET tiprev = ?, tipnode = ?;"
-_updaterange = "INSERT INTO range(rev, idx) VALUES (?,?);"
-_updatesubranges = """INSERT
+_newmeta = r"INSERT INTO meta (schemaversion, tiprev, tipnode) VALUES (?,?,?);"
+_updatemeta = r"UPDATE meta SET tiprev = ?, tipnode = ?;"
+_updaterange = r"INSERT INTO range(rev, idx) VALUES (?,?);"
+_updatesubranges = r"""INSERT
INTO subranges(listidx, suprev, supidx, subrev, subidx)
VALUES (?,?,?,?,?);"""
-_queryexist = "SELECT name FROM sqlite_master WHERE type='table' AND name='meta';"
-_querymeta = "SELECT schemaversion, tiprev, tipnode FROM meta;"
-_queryrange = "SELECT * FROM range WHERE (rev = ? AND idx = ?);"
-_querysubranges = """SELECT subrev, subidx
+_queryexist = r"SELECT name FROM sqlite_master WHERE type='table' AND name='meta';"
+_querymeta = r"SELECT schemaversion, tiprev, tipnode FROM meta;"
+_queryrange = r"SELECT * FROM range WHERE (rev = ? AND idx = ?);"
+_querysubranges = r"""SELECT subrev, subidx
FROM subranges
WHERE (suprev = ? AND supidx = ?)
ORDER BY listidx;"""
-_querysuperrangesmain = """SELECT DISTINCT suprev, supidx
+_querysuperrangesmain = r"""SELECT DISTINCT suprev, supidx
FROM subranges
WHERE %s;"""
-_querysuperrangesbody = '(subrev = %d and subidx = %d)'
+_querysuperrangesbody = r'(subrev = %d and subidx = %d)'
def _make_querysuperranges(ranges):
# building a tree of OR would allow for more ranges
- body = ' OR '.join(_querysuperrangesbody % r for r in ranges)
+ body = r' OR '.join(_querysuperrangesbody % r for r in ranges)
return _querysuperrangesmain % body
class stablerangesqlbase(stablerange.stablerangecached):
@@ -223,7 +224,7 @@
except (sqlite3.DatabaseError, sqlite3.OperationalError):
# something is wrong with the sqlite db
# Since this is a cache, we ignore it.
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
self._unsavedsubranges.clear()
@@ -240,7 +241,7 @@
except OSError:
return None
con = sqlite3.connect(encoding.strfromlocal(self._path), timeout=30,
- isolation_level="IMMEDIATE")
+ isolation_level=r"IMMEDIATE")
con.text_factory = bytes
return con
@@ -278,11 +279,11 @@
#
# operational error catch read-only and locked database
# IntegrityError catch Unique constraint error that may arise
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
self._unsavedsubranges.clear()
- repo.ui.log('evoext-cache', 'error while saving new data: %s' % exc)
- repo.ui.debug('evoext-cache: error while saving new data: %s' % exc)
+ repo.ui.log(b'evoext-cache', b'error while saving new data: %s' % exc)
+ repo.ui.debug(b'evoext-cache: error while saving new data: %s' % exc)
def _trysave(self, repo):
repo = repo.unfiltered()
@@ -294,7 +295,7 @@
if self._con is None:
util.unlinkpath(self._path, ignoremissing=True)
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
con = self._db()
@@ -319,9 +320,9 @@
# drifting is currently an issue because this means another
# process might have already added the cache line we are about
# to add. This will confuse sqlite
- msg = _('stable-range cache: skipping write, '
- 'database drifted under my feet\n')
- hint = _('(disk: %s-%s vs mem: %s-%s)\n')
+ msg = _(b'stable-range cache: skipping write, '
+ b'database drifted under my feet\n')
+ hint = _(b'(disk: %s-%s vs mem: %s-%s)\n')
data = (nodemod.hex(meta[2]), meta[1],
nodemod.hex(self._ondisktipnode), self._ondisktiprev)
repo.ui.warn(msg)
@@ -375,7 +376,7 @@
def clear(self, reset=False):
super(stablerangesql, self).clear(reset=reset)
- if '_con' in vars(self):
+ if r'_con' in vars(self):
del self._con
self._subrangescache.clear()
@@ -396,13 +397,13 @@
class mergepointsql(stablerangesql, stablerange.stablerange_mergepoint):
_schemaversion = 3
- _cachefile = 'evoext_stablerange_v2.sqlite'
- _cachename = 'evo-ext-stablerange-mergepoint'
+ _cachefile = b'evoext_stablerange_v2.sqlite'
+ _cachename = b'evo-ext-stablerange-mergepoint'
class sqlstablerange(stablerangesqlbase, stablerange.stablerange):
_schemaversion = 1
- _cachefile = 'evoext_stablerange_v1.sqlite'
+ _cachefile = b'evoext_stablerange_v1.sqlite'
def warmup(self, repo, upto=None):
self._con # make sure the data base is loaded
@@ -419,10 +420,81 @@
except error.LockError:
# Exceptionnally we are noisy about it since performance impact is
# large We should address that before using this more widely.
- repo.ui.warn('stable-range cache: unable to lock repo while warming\n')
- repo.ui.warn('(cache will not be saved)\n')
+ repo.ui.warn(b'stable-range cache: unable to lock repo while warming\n')
+ repo.ui.warn(b'(cache will not be saved)\n')
super(sqlstablerange, self).warmup(repo, upto)
+@eh.command(
+ b'debugstablerangecache',
+ [] + commands.formatteropts,
+ _(b''))
+def debugstablerangecache(ui, repo, **opts):
+ """display data about the stable sort cache of a repository
+ """
+ unfi = repo.unfiltered()
+ revs = unfi.revs('all()')
+ nbrevs = len(revs)
+ ui.write('number of revisions: %12d\n' % nbrevs)
+ heads = unfi.revs('heads(all())')
+ nbheads = len(heads)
+ ui.write('number of heads: %12d\n' % nbheads)
+ merge = unfi.revs('merge()')
+ nbmerge = len(merge)
+ ui.write('number of merge: %12d (%3d%%)\n'
+ % (nbmerge, 100 * nbmerge / nbrevs))
+ cache = unfi.stablerange
+ allsubranges = stablerange.subrangesclosure(unfi, cache, heads)
+ nbsubranges = len(allsubranges) - nbrevs # we remove leafs
+ ui.write('number of range: %12d\n' % nbsubranges)
+ import collections
+ subsizedistrib = collections.defaultdict(lambda: 0)
+
+ def smallsize(r):
+ # This is computing the size it would take to store a range for a
+ # revision
+ #
+ # one int for the initial/top skip
+ # two int per middle ranges
+ # one int for the revision of the bottom part
+ return 4 * (2 + ((len(r) - 2) * 2))
+
+ totalsize = 0
+
+ allmiddleranges = []
+ for s in allsubranges:
+ sr = cache.subranges(repo, s)
+ srl = len(sr)
+ if srl == 0:
+ # leaf range are not interresting
+ continue
+ subsizedistrib[srl] += 1
+ allmiddleranges.append(s)
+ totalsize += smallsize(sr)
+
+ for ss in sorted(subsizedistrib):
+ ssc = subsizedistrib[ss]
+ ssp = ssc * 100 // nbsubranges
+ ui.write(' with %3d subranges: %12d (%3d%%)\n' % (ss, ssc, ssp))
+
+ depth = repo.depthcache.get
+ stdslice = 0
+ oddslice = 0
+
+ for s in allmiddleranges:
+ head, skip = s
+ d = depth(head)
+ k = d - 1
+ if (skip & k) == skip:
+ stdslice += 1
+ else:
+ oddslice += 1
+
+ ui.write('standard slice point cut: %12d (%3d%%)\n'
+ % (stdslice, stdslice * 100 // nbsubranges))
+ ui.write('other slice point cut: %12d (%3d%%)\n'
+ % (oddslice, oddslice * 100 // nbsubranges))
+ ui.write('est. naive compact store: %12d bytes\n' % totalsize)
+
@eh.reposetup
def setupcache(ui, repo):
@@ -436,7 +508,7 @@
@localrepo.unfilteredmethod
def destroyed(self):
- if 'stablerange' in vars(self):
+ if r'stablerange' in vars(self):
self.stablerange.clear()
del self.stablerange
super(stablerangerepo, self).destroyed()
--- a/hgext3rd/evolve/stablesort.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/stablesort.py Fri Sep 27 13:03:14 2019 +0200
@@ -7,6 +7,245 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+r"""Stable sorting for the mercurial graph
+
+The goal is to provided an efficient, revnum independant way, to sort revisions
+in a topologicaly. Having it independant from revnum is important to make it
+stable from one repository to another, unlocking various capabilities. For
+example it can be used for discovery purposes.
+
+This docstring describe the currently preferred solution:
+
+Probleme definition
+-------------------
+
+We want a way to order revision in the graph. For a linear history things are simple::
+
+ A -> B -> C -> D -> E -> F -> G -> H
+
+ stablesort(::H) = [A, B, C, D, E, F, G, H]
+
+However, things become more complicated when the graph is not linear::
+
+ A -> B -> C -> D -> G -> H
+ \ /
+ > E -> F
+
+ stablesort(::A) = [A]
+ stablesort(::B) = [A, B]
+ stablesort(::C) = [A, B, C]
+ stablesort(::D) = [A, B, C, D]
+ stablesort(::E) = [A, B, E]
+ stablesort(::F) = [A, B, E, F]
+ stablesort(::G) = [A, B, C, D, E, F, G]
+ stablesort(::H) = [A, B, C, D, E, F, G, H]
+
+Basic principle:
+----------------
+
+We are always talking about set of revision defined by a single heads
+(eg: `stablesort(::r)`)
+
+For non merge revisions, the definition is simple::
+
+ stablesort(::r) == stablesort(p1(r)) + r
+
+This is visible in some of the example above:
+
+ stablesort(::B) = stablesort(::A) + [B]
+ stablesort(::E) = stablesort(::B) + [E]
+ stablesort(::H) = stablesort(::G) + [H]
+
+For merge revision, we reuse as much as possible of the parents order:
+
+ pl = stablemin(parents(m))
+ ph = stablemax(parents(m))
+ stablesort(::m) == stablesort(pl)
+ + [i for in in stablesort(ph) if in ph % pl]
+ + m
+
+This is visible in the example above:
+
+ stablesort(::G) = stablesort(::D) + [stablesort(::F) - ::D] + [G]
+ stablesort(::G) = [A, B, C, D] + ([A, B, E, F] - [A, B, C ,D]) + [G]
+ stablesort(::G) = [A, B, C, D] + [E, F] + [G]
+
+To decide which parent goes first in the stablesort, we need to order them. The
+`stablemin/stablemax` function express this. The actual order used is an
+implementation details (eg: could be node-order, in the example it is
+alphabetical order)
+
+The `ph % pl` set of revision is called the "exclusive part". It correspond to
+all revisions ancestors of `ph` (`ph` included) that are not ancestors of `pl`
+(`pl` included). In this area we try to reuse as much as the stable-sorted
+order for `ph`. In simple case, the `[i for i in stablesort(ph) if i in ph %
+pl]` is just the contiguous final range of `stablesort(ph)`. This is the case
+in the example we have looked at so far::
+
+ stablesort(::F) - ::D = [A, B, E, F] - [A, B, C ,D] = stablesort(::F)[-2:]
+
+
+However in more advance case, this will not be contiguous and we'll need to
+skip over multiple parts of `stablesort(ph)` to cover `ph % pl`.Let's have a
+look at an example of such case::
+
+ A - B ----- F - H
+ \ \ / /
+ \ E - G
+ \ / /
+ C - D
+
+We have the following stablesort:
+
+ stablesort(::A) = [A]
+ stablesort(::B) = [A, B]
+ stablesort(::C) = [A, C]
+ stablesort(::D) = [A, C, D]
+ stablesort(::E) = [A, B, C, E]
+ stablesort(::F) = [A, B, C, E, F]
+ stablesort(::G) = [A, B, C, D, E, G]
+ stablesort(::H) = [A, B, C, E, F, D, G, H]
+
+The stable order of `stablesort(::H)` match our definition::
+
+
+ stablesort(::H) = [A, B, C, E, F] + [D, G] + [H]
+ stablesort(::F) = [A, B, C, E, F]
+ stablesort(::G) - ::F = [A, B, C, D, E, G] - [A, B, C, E, F] = [D, G]
+
+In this order, we reuse all of `stablesort(::H)`, but the subset of
+`stablesort(::G)` we reuse is not contiguous, we had to skip over 'E' that is
+already contained inside ::F.
+
+Usage
+-----
+
+An important details is that, in practice, the sorted revision are always
+walked backward, from the head of the set of revisions.
+
+preexisting cached data
+-----------------------
+
+The stable sort assume we already have 2 important property cached for each
+changesets:
+
+1) changeset depth == len(::r)
+2) first merge == max(merge() and ::r)
+
+Caching strategy
+----------------
+
+Since we always walk from the head, the iteration mostly have to follow the
+unique parent of non merge revision. For merge revision, we need to iterate
+over the revisions accessible only through one of the parent before coming back
+to the other parent eventually.
+
+To efficiently cache the revision path we need to walk, we records "jumps". A
+jump is a revision where the next revision (in the stable sort) will not be a
+parent of the current revision, but another revision in the graph.
+
+In the first (simple) example above, we had::
+
+ A -> B -> C -> D -> G -> H
+ \ /
+ > E -> F
+
+ stablesort(::D) = [A, B, C, D]
+ stablesort(::F) = [A, B, E, F]
+ stablesort(::G) = [A, B, C, D, E, F, G]
+
+In this case, when caching stable sort data for `G`, we need to record the `E
+-> D` jump. This correspond to point were we are done iterating over the
+revision accessible through `F` and we need to "jump back to the other parent"
+of `G`: `D`.
+
+
+
+In the second (more advance) example above, we had::
+
+ A - B ----- F - H
+ \ \ / /
+ \ E - G
+ \ / /
+ C - D
+
+ stablesort(::F) = [A, B, C, E, F]
+ stablesort(::G) = [A, B, C, D, E, G]
+ stablesort(::H) = [A, B, C, E, F, D, G, H]
+
+In this case, when caching stable sort data for `G`, we need to record the `G
+-> D` and the `D -> F` jumps.
+
+Jumps are recorded using the following formats:
+
+ (jump-point, jump-destination, section-size)
+
+* jump-point is the last revision number we should iterate over before jumping,
+* jump-destination is the next revision we should iterate over after the jump point,
+* section-size is the number of revision to be iterated before reaching jump-point.
+
+the section-size is not directly used when doing a stable-sorted walk. However
+it is useful for higher level piece of code to take decision without having to
+actually walk the graph, (see stable range documentation).
+
+For each merge, we store the set of jumps that cover the exclusive side.
+
+Practical data
+--------------
+
+The mercurial repository has simple branching and few jumps:
+
+ number of revisions: 69771
+ number of merge: 2734
+ number of jumps: 2950
+ average jumps: 1.079
+ median jumps: 1
+ 90% jumps: 1
+ 99% jumps: 3
+ max jumps: 6
+ jump cache size: 35 400 bytes
+
+Mozilla's branching is fairly simple too:
+
+ number of revisions: 435078
+ number of merge: 21035
+ number of jumps: 31434
+ average jumps: 1.494
+ median jumps: 1
+ 90% jumps: 2
+ 99% jumps: 9
+ max jumps: 169
+ jump cache size: 377 208 bytes
+
+Pypy has a more complicated branching history but jumps cache remains reasonable
+
+ number of revisions: 95010
+ number of merge: 7911
+ number of jumps: 24326
+ average jumps: 3.075
+ median jumps: 1
+ 90% jumps: 5
+ 99% jumps: 40
+ max jumps: 329
+ jump cache size: 291 912 bytes
+
+This still apply to larger private project:
+
+ number of revisions: 605011
+ number of merge: 118109
+ number of jumps: 314925
+ average jumps: 2.667
+ median jumps: 1
+ 90% jumps: 3
+ 99% jumps: 34
+ max jumps: 660
+ jump cache size: 3 779 100 bytes
+
+It is worth noting that the last jump could be computed form other information,
+removing one jump storage per merge. However this does not seems to be an issue
+worth the troubles for now.
+"""
+
import array
import collections
import struct
@@ -69,9 +308,9 @@
method = opts['method']
sorting = _methodmap.get(method)
if sorting is None:
- valid_method = ', '.join(sorted(_methodmap))
- raise error.Abort('unknown sorting method: "%s"' % method,
- hint='pick one of: %s' % valid_method)
+ valid_method = b', '.join(sorted(_methodmap))
+ raise error.Abort(b'unknown sorting method: "%s"' % method,
+ hint=b'pick one of: %s' % valid_method)
displayer = compat.changesetdisplayer(ui, repo, pycompat.byteskwargs(opts),
buffered=True)
@@ -84,6 +323,46 @@
displayer.flush(ctx)
displayer.close()
+@eh.command(
+ b'debugstablesortcache',
+ [] + commands.formatteropts,
+ _(b''))
+def debugstablesortcache(ui, repo, **opts):
+ """display data about the stable sort cache of a repository
+ """
+ unfi = repo.unfiltered()
+ revs = unfi.revs('all()')
+ nbrevs = len(revs)
+ ui.write('number of revisions: %12d\n' % nbrevs)
+ merge = unfi.revs('merge()')
+ nbmerge = len(merge)
+ cache = unfi.stablesort
+ ui.write('number of merge: %12d\n' % nbmerge)
+ alljumps = []
+ alljumpssize = []
+ for r in merge:
+ jumps = cache.getjumps(unfi, r)
+ if jumps is None:
+ continue # not a merge
+ jumps = list(jumps)
+ alljumps.append(jumps)
+ alljumpssize.append(len(jumps))
+ nbjumps = sum(alljumpssize)
+ ui.write('number of jumps: %12d\n' % nbjumps)
+ if not nbjumps:
+ return 0
+ avgjumps = nbjumps / float(len(alljumpssize))
+ ui.write('average jumps: %6.3f\n' % avgjumps)
+ alljumpssize.sort()
+ medianjumps = alljumpssize[len(alljumpssize) // 2]
+ ui.write('median jumps: %12d\n' % medianjumps)
+ tensjumps = alljumpssize[len(alljumpssize) * 9 // 10]
+ ui.write('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))
+
def stablesort_branchpoint(repo, revs, mergecallback=None):
"""return '::revs' topologically sorted in "stable" order
@@ -180,7 +459,7 @@
heads = list(sorted(revs))
else:
# keeps heads only
- heads = sorted(repo.revs('sort(heads(%ld::%ld))', revs, revs), key=tiebreaker)
+ heads = sorted(repo.revs(b'sort(heads(%ld::%ld))', revs, revs), key=tiebreaker)
results = []
while heads:
@@ -246,24 +525,24 @@
return result
def stablesort_mergepoint_head_basic(repo, revs, limit=None):
- heads = repo.revs('sort(heads(%ld))', revs)
+ heads = repo.revs(b'sort(heads(%ld))', revs)
if not heads:
return []
elif 2 < len(heads):
- raise error.Abort('cannot use head based merging, %d heads found'
+ raise error.Abort(b'cannot use head based merging, %d heads found'
% len(heads))
head = heads.first()
- revs = stablesort_mergepoint_bounded(repo, head, repo.revs('::%d', head))
+ revs = stablesort_mergepoint_bounded(repo, head, repo.revs(b'::%d', head))
if limit is None:
return revs
return revs[-limit:]
def stablesort_mergepoint_head_debug(repo, revs, limit=None):
- heads = repo.revs('sort(heads(%ld))', revs)
+ heads = repo.revs(b'sort(heads(%ld))', revs)
if not heads:
return []
elif 2 < len(heads):
- raise error.Abort('cannot use head based merging, %d heads found'
+ raise error.Abort(b'cannot use head based merging, %d heads found'
% len(heads))
head = heads.first()
revs = stablesort_mergepoint_head(repo, head)
@@ -294,7 +573,7 @@
ps = sorted(ps, key=tiebreaker)
# get the part from the highest parent. This is the part that changes
- mid_revs = repo.revs('only(%d, %d)', ps[1], ps[0])
+ mid_revs = repo.revs(b'only(%d, %d)', ps[1], ps[0])
if mid_revs:
mid = stablesort_mergepoint_bounded(repo, ps[1], mid_revs)
@@ -304,20 +583,20 @@
return bottom + mid + top
def stablesort_mergepoint_head_cached(repo, revs, limit=None):
- heads = repo.revs('sort(heads(%ld))', revs)
+ heads = repo.revs(b'sort(heads(%ld))', revs)
if not heads:
return []
elif 2 < len(heads):
- raise error.Abort('cannot use head based merging, %d heads found'
+ raise error.Abort(b'cannot use head based merging, %d heads found'
% len(heads))
head = heads.first()
cache = stablesortcache()
first = list(cache.get(repo, head, limit=limit))
second = list(cache.get(repo, head, limit=limit))
if first != second:
- repo.ui.warn('stablesort-cache: initial run different from re-run:\n'
- ' %s\n'
- ' %s\n' % (first, second))
+ repo.ui.warn(b'stablesort-cache: initial run different from re-run:\n'
+ b' %s\n'
+ b' %s\n' % (first, second))
return second
class stablesortcache(object):
@@ -504,11 +783,11 @@
recordjump(previous, lower, size)
def stablesort_mergepoint_head_ondisk(repo, revs, limit=None):
- heads = repo.revs('sort(heads(%ld))', revs)
+ heads = repo.revs(b'sort(heads(%ld))', revs)
if not heads:
return []
elif 2 < len(heads):
- raise error.Abort('cannot use head based merging, %d heads found'
+ raise error.Abort(b'cannot use head based merging, %d heads found'
% len(heads))
head = heads.first()
unfi = repo.unfiltered()
@@ -516,22 +795,22 @@
cache.save(unfi)
return cache.get(repo, head, limit=limit)
-S_INDEXSIZE = struct.Struct('>I')
+S_INDEXSIZE = struct.Struct(b'>I')
class ondiskstablesortcache(stablesortcache, genericcaches.changelogsourcebase):
- _filepath = 'evoext-stablesortcache-00'
- _cachename = 'evo-ext-stablesort'
+ _filepath = b'evoext-stablesortcache-00'
+ _cachename = b'evo-ext-stablesort'
def __init__(self):
super(ondiskstablesortcache, self).__init__()
- self._index = array.array('l')
- self._data = array.array('l')
+ self._index = array.array(r'l')
+ self._data = array.array(r'l')
del self._jumps
def getjumps(self, repo, rev):
if len(self._index) < rev:
- msg = 'stablesortcache must be warmed before use (%d < %d)'
+ msg = b'stablesortcache must be warmed before use (%d < %d)'
msg %= (len(self._index), rev)
raise error.ProgrammingError(msg)
return self._getjumps(rev)
@@ -579,10 +858,11 @@
total = len(data)
def progress(pos, rev=None):
- revstr = '' if rev is None else ('rev %d' % rev)
- compat.progress(repo.ui, 'updating stablesort cache',
- pos, revstr, unit='revision', total=total)
+ 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)
+ progress(0)
for idx, rev in enumerate(data):
parents = filterparents(repo.changelog.parentrevs(rev))
if len(parents) <= 1:
@@ -600,8 +880,8 @@
def clear(self, reset=False):
super(ondiskstablesortcache, self).clear()
- self._index = array.array('l')
- self._data = array.array('l')
+ self._index = array.array(r'l')
+ self._data = array.array(r'l')
def load(self, repo):
"""load data from disk
@@ -611,8 +891,8 @@
assert repo.filtername is None
data = repo.cachevfs.tryread(self._filepath)
- self._index = array.array('l')
- self._data = array.array('l')
+ self._index = array.array(r'l')
+ self._data = array.array(r'l')
if not data:
self._cachekey = self.emptykey
else:
@@ -636,7 +916,7 @@
if self._cachekey is None or self._cachekey == self._ondiskkey:
return
try:
- cachefile = repo.cachevfs(self._filepath, 'w', atomictemp=True)
+ cachefile = repo.cachevfs(self._filepath, b'w', atomictemp=True)
# data to write
headerdata = self._serializecachekey()
@@ -652,8 +932,8 @@
cachefile.close()
self._ondiskkey = self._cachekey
except (IOError, OSError) as exc:
- repo.ui.log('stablesortcache', 'could not write update %s\n' % exc)
- repo.ui.debug('stablesortcache: could not write update %s\n' % exc)
+ repo.ui.log(b'stablesortcache', b'could not write update %s\n' % exc)
+ repo.ui.debug(b'stablesortcache: could not write update %s\n' % exc)
@eh.reposetup
def setupcache(ui, repo):
@@ -668,7 +948,7 @@
@localrepo.unfilteredmethod
def destroyed(self):
- if 'stablesort' in vars(self):
+ if r'stablesort' in vars(self):
self.stablesort.clear()
super(stablesortrepo, self).destroyed()
@@ -682,12 +962,12 @@
repo.__class__ = stablesortrepo
_methodmap = {
- 'branchpoint': stablesort_branchpoint,
- 'basic-mergepoint': stablesort_mergepoint_multirevs,
- 'basic-headstart': stablesort_mergepoint_head_basic,
- 'headstart': stablesort_mergepoint_head_debug,
- 'headcached': stablesort_mergepoint_head_cached,
- 'headondisk': stablesort_mergepoint_head_ondisk,
+ b'branchpoint': stablesort_branchpoint,
+ b'basic-mergepoint': stablesort_mergepoint_multirevs,
+ b'basic-headstart': stablesort_mergepoint_head_basic,
+ b'headstart': stablesort_mergepoint_head_debug,
+ b'headcached': stablesort_mergepoint_head_cached,
+ b'headondisk': stablesort_mergepoint_head_ondisk,
}
# merge last so that repo setup wrap after that one.
--- a/hgext3rd/evolve/state.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/state.py Fri Sep 27 13:03:14 2019 +0200
@@ -15,6 +15,7 @@
from __future__ import absolute_import
+import contextlib
import errno
import struct
@@ -27,7 +28,7 @@
from mercurial.i18n import _
-class cmdstate():
+class cmdstate(object):
"""a wrapper class to store the state of commands like `evolve`, `pick`
All the data for the state is stored in the form of key-value pairs in a
@@ -37,9 +38,11 @@
can populate the object data reading that file
"""
- def __init__(self, repo, path='evolvestate', opts={}):
+ def __init__(self, repo, path=b'evolvestate', opts=None):
self._repo = repo
self.path = path
+ if opts is None:
+ opts = {}
self.opts = opts
def __nonzero__(self):
@@ -65,7 +68,7 @@
op = self._read()
if isinstance(op, dict):
self.opts.update(op)
- elif self.path == 'evolvestate':
+ elif self.path == b'evolvestate':
# it is the old evolvestate file
oldop = _oldevolvestateread(self._repo)
self.opts.update(oldop)
@@ -79,13 +82,13 @@
we use third-party library cbor to serialize data to write in the file.
"""
- with self._repo.vfs(self.path, 'wb', atomictemp=True) as fp:
+ with self._repo.vfs(self.path, b'wb', atomictemp=True) as fp:
cbor.dump(self.opts, fp)
def _read(self):
"""reads the evolvestate file and returns a dictionary which contain
data in the same format as it was before storing"""
- with self._repo.vfs(self.path, 'rb') as fp:
+ with self._repo.vfs(self.path, b'rb') as fp:
return cbor.load(fp)
def delete(self):
@@ -101,20 +104,20 @@
This exists for BC reasons."""
try:
- f = repo.vfs('evolvestate')
+ f = repo.vfs(b'evolvestate')
except IOError as err:
if err.errno != errno.ENOENT:
raise
try:
versionblob = f.read(4)
if len(versionblob) < 4:
- repo.ui.debug('ignoring corrupted evolvestate (file contains %i bits)'
+ repo.ui.debug(b'ignoring corrupted evolvestate (file contains %i bits)'
% len(versionblob))
return None
- version = struct._unpack('>I', versionblob)[0]
+ version = struct._unpack(b'>I', versionblob)[0]
if version != 0:
- msg = _('unknown evolvestate version %i') % version
- raise error.Abort(msg, hint=_('upgrade your evolve'))
+ msg = _(b'unknown evolvestate version %i') % version
+ raise error.Abort(msg, hint=_(b'upgrade your evolve'))
records = []
data = f.read()
off = 0
@@ -122,22 +125,35 @@
while off < end:
rtype = data[off]
off += 1
- length = struct._unpack('>I', data[off:(off + 4)])[0]
+ length = struct._unpack(b'>I', data[off:(off + 4)])[0]
off += 4
record = data[off:(off + length)]
off += length
- if rtype == 't':
+ if rtype == b't':
rtype, record = record[0], record[1:]
records.append((rtype, record))
state = {}
for rtype, rdata in records:
- if rtype == 'C':
- state['current'] = rdata
+ if rtype == b'C':
+ state[b'current'] = rdata
elif rtype.lower():
- repo.ui.debug('ignore evolve state record type %s' % rtype)
+ repo.ui.debug(b'ignore evolve state record type %s' % rtype)
else:
- raise error.Abort(_("unknown evolvestate field type '%s'")
- % rtype, hint=_('upgrade your evolve'))
+ raise error.Abort(_(b"unknown evolvestate field type '%s'")
+ % rtype, hint=_(b'upgrade your evolve'))
return state
finally:
f.close()
+
+@contextlib.contextmanager
+def saver(state, opts=None):
+ """ensure the state is saved on disk during the duration of the context
+
+ The state is preserved if the context is exited through an exception.
+ """
+ if opts:
+ state.addopts(opts)
+ state.save()
+ yield
+ # delete only if no exception where raised
+ state.delete()
--- a/hgext3rd/evolve/templatekw.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/templatekw.py Fri Sep 27 13:03:14 2019 +0200
@@ -28,31 +28,31 @@
def showinstabilities(context, mapping):
"""List of strings. Evolution instabilities affecting the changeset
(zero or more of "orphan", "content-divergent" or "phase-divergent")."""
- ctx = context.resource(mapping, 'ctx')
- return templatekw.compatlist(context, mapping, 'instability',
+ ctx = context.resource(mapping, b'ctx')
+ return templatekw.compatlist(context, mapping, b'instability',
ctx.instabilities(),
- plural='instabilities')
+ plural=b'instabilities')
@eh.templatekeyword(b'troubles', requires=set([b'ctx', b'templ']))
def showtroubles(context, mapping): # legacy name for instabilities
- ctx = context.resource(mapping, 'ctx')
- return templatekw.compatlist(context, mapping, 'trouble',
- ctx.instabilities(), plural='troubles')
+ ctx = context.resource(mapping, b'ctx')
+ return templatekw.compatlist(context, mapping, b'trouble',
+ ctx.instabilities(), plural=b'troubles')
else:
# older template API in hg < 4.6
@eh.templatekeyword(b'instabilities')
def showinstabilities(**args):
"""List of strings. Evolution instabilities affecting the changeset
(zero or more of "orphan", "content-divergent" or "phase-divergent")."""
- ctx = args['ctx']
- return templatekw.showlist('instability', ctx.instabilities(), args,
- plural='instabilities')
+ ctx = args[b'ctx']
+ return templatekw.showlist(b'instability', ctx.instabilities(), args,
+ plural=b'instabilities')
@eh.templatekeyword(b'troubles')
def showtroubles(**args):
- ctx = args['ctx']
- return templatekw.showlist('trouble', ctx.instabilities(), args,
- plural='troubles')
+ ctx = args[b'ctx']
+ return templatekw.showlist(b'trouble', ctx.instabilities(), args,
+ plural=b'troubles')
_sp = templatekw.showpredecessors
if util.safehasattr(_sp, '_requires'):
@@ -91,24 +91,24 @@
""" Returns a dict with the default templates for obs fate
"""
# Prepare templates
- verbtempl = '{verb}'
- usertempl = '{if(users, " by {join(users, ", ")}")}'
- succtempl = '{if(successors, " as ")}{successors}' # Bypass if limitation
- datetempleq = ' (at {min_date|isodate})'
- datetemplnoteq = ' (between {min_date|isodate} and {max_date|isodate})'
- datetempl = '{if(max_date, "{ifeq(min_date, max_date, "%s", "%s")}")}' % (datetempleq, datetemplnoteq)
+ verbtempl = b'{verb}'
+ usertempl = b'{if(users, " by {join(users, ", ")}")}'
+ succtempl = b'{if(successors, " as ")}{successors}' # Bypass if limitation
+ datetempleq = b' (at {min_date|isodate})'
+ datetemplnoteq = b' (between {min_date|isodate} and {max_date|isodate})'
+ datetempl = b'{if(max_date, "{ifeq(min_date, max_date, "%s", "%s")}")}' % (datetempleq, datetemplnoteq)
optionalusertempl = usertempl
username = _getusername(ui)
if username is not None:
- optionalusertempl = ('{ifeq(join(users, "\0"), "%s", "", "%s")}'
+ optionalusertempl = (b'{ifeq(join(users, "\0"), "%s", "", "%s")}'
% (username, usertempl))
# Assemble them
return {
- 'obsfate_quiet': verbtempl + succtempl,
- 'obsfate': verbtempl + succtempl + optionalusertempl,
- 'obsfate_verbose': verbtempl + succtempl + usertempl + datetempl,
+ b'obsfate_quiet': verbtempl + succtempl,
+ b'obsfate': verbtempl + succtempl + optionalusertempl,
+ b'obsfate_verbose': verbtempl + succtempl + usertempl + datetempl,
}
def obsfatedata(repo, ctx):
@@ -158,18 +158,18 @@
line = []
# Verb
- line.append(obsfateline['verb'])
+ line.append(obsfateline[b'verb'])
# Successors
- successors = obsfateline["successors"]
+ successors = obsfateline[b"successors"]
if successors:
fmtsuccessors = map(lambda s: s[:12], successors)
- line.append(" as %s" % ", ".join(fmtsuccessors))
+ line.append(b" as %s" % b", ".join(fmtsuccessors))
# Users
- if (verbose or normal) and 'users' in obsfateline:
- users = obsfateline['users']
+ if (verbose or normal) and b'users' in obsfateline:
+ users = obsfateline[b'users']
if not verbose:
# If current user is the only user, do not show anything if not in
@@ -179,24 +179,24 @@
users = None
if users:
- line.append(" by %s" % ", ".join(users))
+ line.append(b" by %s" % b", ".join(users))
# Date
if verbose:
- min_date = obsfateline['min_date']
- max_date = obsfateline['max_date']
+ min_date = obsfateline[b'min_date']
+ max_date = obsfateline[b'max_date']
if min_date == max_date:
- fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
- line.append(" (at %s)" % fmtmin_date)
+ fmtmin_date = util.datestr(min_date, b'%Y-%m-%d %H:%M %1%2')
+ line.append(b" (at %s)" % fmtmin_date)
else:
- fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
- fmtmax_date = util.datestr(max_date, '%Y-%m-%d %H:%M %1%2')
- line.append(" (between %s and %s)" % (fmtmin_date, fmtmax_date))
+ fmtmin_date = util.datestr(min_date, b'%Y-%m-%d %H:%M %1%2')
+ fmtmax_date = util.datestr(max_date, b'%Y-%m-%d %H:%M %1%2')
+ line.append(b" (between %s and %s)" % (fmtmin_date, fmtmax_date))
- return "".join(line)
+ return b"".join(line)
-def obsfateprinter(obsfate, ui, prefix=""):
+def obsfateprinter(obsfate, ui, prefix=b""):
lines = []
for raw in obsfate:
lines.append(obsfatelineprinter(raw, ui))
@@ -204,7 +204,7 @@
if prefix:
lines = [prefix + line for line in lines]
- return "\n".join(lines)
+ return b"\n".join(lines)
if not util.safehasattr(templatekw, 'obsfateverb'): # <= hg-4.5
@eh.templatekeyword(b"obsfatedata")
@@ -213,7 +213,7 @@
values = obsfatedata(repo, ctx)
if values is None:
- return templatekw.showlist("obsfatedata", [], args)
+ return templatekw.showlist(b"obsfatedata", [], args)
return _showobsfatedata(repo, ctx, values, **args)
@@ -224,36 +224,36 @@
# As we can't do something like
# "{join(map(nodeshort, successors), ', '}" in template, manually
# create a correct textual representation
- gen = ', '.join(n[:12] for n in raw['successors'])
+ gen = b', '.join(n[:12] for n in raw[b'successors'])
- makemap = lambda x: {'successor': x}
- joinfmt = lambda d: "%s" % d['successor']
- raw['successors'] = templatekw._hybrid(gen, raw['successors'], makemap,
- joinfmt)
+ makemap = lambda x: {b'successor': x}
+ joinfmt = lambda d: b"%s" % d[b'successor']
+ raw[b'successors'] = templatekw._hybrid(gen, raw[b'successors'], makemap,
+ joinfmt)
# And then format them
# Insert default obsfate templates
- args['templ'].cache.update(obsfatedefaulttempl(repo.ui))
+ args[b'templ'].cache.update(obsfatedefaulttempl(repo.ui))
if repo.ui.quiet:
- name = "obsfate_quiet"
+ name = b"obsfate_quiet"
elif repo.ui.verbose:
- name = "obsfate_verbose"
+ name = b"obsfate_verbose"
elif repo.ui.debugflag:
- name = "obsfate_debug"
+ name = b"obsfate_debug"
else:
- name = "obsfate"
+ name = b"obsfate"
# Format a single value
def fmt(d):
nargs = args.copy()
nargs.update(d[name])
- templ = args['templ']
+ templ = args[b'templ']
# HG 4.6
if hasattr(templ, "generate"):
return templ.generate(name, nargs)
else:
- return args['templ'](name, **nargs)
+ return args[b'templ'](name, **nargs)
# Generate a good enough string representation using templater
gen = []
@@ -268,8 +268,8 @@
except StopIteration:
pass
- gen.append("".join(chunkstr))
- gen = "; ".join(gen)
+ gen.append(b"".join(chunkstr))
+ gen = b"; ".join(gen)
return templatekw._hybrid(gen, values, lambda x: {name: x}, fmt)
--- a/hgext3rd/evolve/thirdparty/cbor.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/thirdparty/cbor.py Fri Sep 27 13:03:14 2019 +0200
@@ -79,23 +79,23 @@
CBOR_TAG_MIME = 36 # following text is MIME message, headers, separators and all
CBOR_TAG_CBOR_FILEHEADER = 55799 # can open a file with 0xd9d9f7
-_CBOR_TAG_BIGNUM_BYTES = struct.pack('B', CBOR_TAG | CBOR_TAG_BIGNUM)
+_CBOR_TAG_BIGNUM_BYTES = struct.pack(b'B', CBOR_TAG | CBOR_TAG_BIGNUM)
def dumps_int(val):
- "return bytes representing int val in CBOR"
+ b"return bytes representing int val in CBOR"
if val >= 0:
# CBOR_UINT is 0, so I'm lazy/efficient about not OR-ing it in.
if val <= 23:
- return struct.pack('B', val)
+ return struct.pack(b'B', val)
if val <= 0x0ff:
- return struct.pack('BB', CBOR_UINT8_FOLLOWS, val)
+ return struct.pack(b'BB', CBOR_UINT8_FOLLOWS, val)
if val <= 0x0ffff:
- return struct.pack('!BH', CBOR_UINT16_FOLLOWS, val)
+ return struct.pack(b'!BH', CBOR_UINT16_FOLLOWS, val)
if val <= 0x0ffffffff:
- return struct.pack('!BI', CBOR_UINT32_FOLLOWS, val)
+ return struct.pack(b'!BI', CBOR_UINT32_FOLLOWS, val)
if val <= 0x0ffffffffffffffff:
- return struct.pack('!BQ', CBOR_UINT64_FOLLOWS, val)
+ return struct.pack(b'!BQ', CBOR_UINT64_FOLLOWS, val)
outb = _dumps_bignum_to_bytearray(val)
return _CBOR_TAG_BIGNUM_BYTES + _encode_type_num(CBOR_BYTES, len(outb)) + outb
val = -1 - val
@@ -119,28 +119,28 @@
def dumps_float(val):
- return struct.pack("!Bd", CBOR_FLOAT64, val)
+ return struct.pack(b"!Bd", CBOR_FLOAT64, val)
-_CBOR_TAG_NEGBIGNUM_BYTES = struct.pack('B', CBOR_TAG | CBOR_TAG_NEGBIGNUM)
+_CBOR_TAG_NEGBIGNUM_BYTES = struct.pack(b'B', CBOR_TAG | CBOR_TAG_NEGBIGNUM)
def _encode_type_num(cbor_type, val):
"""For some CBOR primary type [0..7] and an auxiliary unsigned number, return CBOR encoded bytes"""
assert val >= 0
if val <= 23:
- return struct.pack('B', cbor_type | val)
+ return struct.pack(b'B', cbor_type | val)
if val <= 0x0ff:
- return struct.pack('BB', cbor_type | CBOR_UINT8_FOLLOWS, val)
+ return struct.pack(b'BB', cbor_type | CBOR_UINT8_FOLLOWS, val)
if val <= 0x0ffff:
- return struct.pack('!BH', cbor_type | CBOR_UINT16_FOLLOWS, val)
+ return struct.pack(b'!BH', cbor_type | CBOR_UINT16_FOLLOWS, val)
if val <= 0x0ffffffff:
- return struct.pack('!BI', cbor_type | CBOR_UINT32_FOLLOWS, val)
+ return struct.pack(b'!BI', cbor_type | CBOR_UINT32_FOLLOWS, val)
if (((cbor_type == CBOR_NEGINT) and (val <= 0x07fffffffffffffff)) or
((cbor_type != CBOR_NEGINT) and (val <= 0x0ffffffffffffffff))):
- return struct.pack('!BQ', cbor_type | CBOR_UINT64_FOLLOWS, val)
+ return struct.pack(b'!BQ', cbor_type | CBOR_UINT64_FOLLOWS, val)
if cbor_type != CBOR_NEGINT:
- raise Exception("value too big for CBOR unsigned number: {0!r}".format(val))
+ raise Exception(b"value too big for CBOR unsigned number: {0!r}".format(val))
outb = _dumps_bignum_to_bytearray(val)
return _CBOR_TAG_NEGBIGNUM_BYTES + _encode_type_num(CBOR_BYTES, len(outb)) + outb
@@ -201,8 +201,8 @@
def dumps_bool(b):
if b:
- return struct.pack('B', CBOR_TRUE)
- return struct.pack('B', CBOR_FALSE)
+ return struct.pack(b'B', CBOR_TRUE)
+ return struct.pack(b'B', CBOR_FALSE)
def dumps_tag(t, sort_keys=False):
@@ -223,7 +223,7 @@
def dumps(ob, sort_keys=False):
if ob is None:
- return struct.pack('B', CBOR_NULL)
+ return struct.pack(b'B', CBOR_NULL)
if isinstance(ob, bool):
return dumps_bool(ob)
if _is_stringish(ob):
@@ -239,7 +239,7 @@
return dumps_int(ob)
if isinstance(ob, Tag):
return dumps_tag(ob, sort_keys=sort_keys)
- raise Exception("don't know how to cbor serialize object of type %s", type(ob))
+ raise Exception(b"don't know how to cbor serialize object of type %s", type(ob))
# same basic signature as json.dump, but with no options (yet)
@@ -260,7 +260,7 @@
self.value = value
def __repr__(self):
- return "Tag({0!r}, {1!r})".format(self.tag, self.value)
+ return b"Tag({0!r}, {1!r})".format(self.tag, self.value)
def __eq__(self, other):
if not isinstance(other, Tag):
@@ -273,7 +273,7 @@
Parse CBOR bytes and return Python objects.
"""
if data is None:
- raise ValueError("got None for buffer to decode in loads")
+ raise ValueError(b"got None for buffer to decode in loads")
fp = StringIO(data)
return _loads(fp)[0]
@@ -296,22 +296,22 @@
aux = tag_aux
elif tag_aux == CBOR_UINT8_FOLLOWS:
data = fp.read(1)
- aux = struct.unpack_from("!B", data, 0)[0]
+ aux = struct.unpack_from(b"!B", data, 0)[0]
bytes_read += 1
elif tag_aux == CBOR_UINT16_FOLLOWS:
data = fp.read(2)
- aux = struct.unpack_from("!H", data, 0)[0]
+ aux = struct.unpack_from(b"!H", data, 0)[0]
bytes_read += 2
elif tag_aux == CBOR_UINT32_FOLLOWS:
data = fp.read(4)
- aux = struct.unpack_from("!I", data, 0)[0]
+ aux = struct.unpack_from(b"!I", data, 0)[0]
bytes_read += 4
elif tag_aux == CBOR_UINT64_FOLLOWS:
data = fp.read(8)
- aux = struct.unpack_from("!Q", data, 0)[0]
+ aux = struct.unpack_from(b"!Q", data, 0)[0]
bytes_read += 8
else:
- assert tag_aux == CBOR_VAR_FOLLOWS, "bogus tag {0:02x}".format(tb)
+ assert tag_aux == CBOR_VAR_FOLLOWS, b"bogus tag {0:02x}".format(tb)
aux = None
return tag, tag_aux, aux, bytes_read
@@ -385,9 +385,9 @@
return ob, bytes_read
def _loads(fp, limit=None, depth=0, returntags=False):
- "return (object, bytes read)"
+ b"return (object, bytes read)"
if depth > _MAX_DEPTH:
- raise Exception("hit CBOR loads recursion depth limit")
+ raise Exception(b"hit CBOR loads recursion depth limit")
tb = _read_byte(fp)
@@ -397,16 +397,16 @@
# Some special cases of CBOR_7 best handled by special struct.unpack logic here
if tb == CBOR_FLOAT16:
data = fp.read(2)
- hibyte, lowbyte = struct.unpack_from("BB", data, 0)
+ hibyte, lowbyte = struct.unpack_from(b"BB", data, 0)
exp = (hibyte >> 2) & 0x1F
mant = ((hibyte & 0x03) << 8) | lowbyte
if exp == 0:
val = mant * (2.0 ** -24)
elif exp == 31:
if mant == 0:
- val = float('Inf')
+ val = float(b'Inf')
else:
- val = float('NaN')
+ val = float(b'NaN')
else:
val = (mant + 1024.0) * (2 ** (exp - 25))
if hibyte & 0x80:
@@ -414,11 +414,11 @@
return (val, 3)
elif tb == CBOR_FLOAT32:
data = fp.read(4)
- pf = struct.unpack_from("!f", data, 0)
+ pf = struct.unpack_from(b"!f", data, 0)
return (pf[0], 5)
elif tb == CBOR_FLOAT64:
data = fp.read(8)
- pf = struct.unpack_from("!d", data, 0)
+ pf = struct.unpack_from(b"!d", data, 0)
return (pf[0], 9)
tag, tag_aux, aux, bytes_read = _tag_aux(fp, tb)
@@ -461,7 +461,7 @@
return (None, bytes_read)
if tb == CBOR_UNDEFINED:
return (None, bytes_read)
- raise ValueError("unknown cbor tag 7 byte: {:02x}".format(tb))
+ raise ValueError(b"unknown cbor tag 7 byte: {:02x}".format(tb))
def loads_bytes(fp, aux, btag=CBOR_BYTES):
@@ -481,7 +481,7 @@
total_bytes_read += 1
break
tag, tag_aux, aux, bytes_read = _tag_aux(fp, tb)
- assert tag == btag, 'variable length value contains unexpected component'
+ assert tag == btag, b'variable length value contains unexpected component'
ob = fp.read(aux)
chunklist.append(ob)
total_bytes_read += bytes_read + aux
--- a/hgext3rd/evolve/utility.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/evolve/utility.py Fri Sep 27 13:03:14 2019 +0200
@@ -17,20 +17,20 @@
compat,
)
-shorttemplate = "[{label('evolve.rev', rev)}] {desc|firstline}\n"
-stacktemplate = """[{label('evolve.rev', if(topicidx, "s{topicidx}", rev))}] {desc|firstline}\n"""
+shorttemplate = b"[{label('evolve.rev', rev)}] {desc|firstline}\n"
+stacktemplate = b"""[{label('evolve.rev', if(topicidx, "s{topicidx}", rev))}] {desc|firstline}\n"""
def obsexcmsg(ui, message, important=False):
- verbose = ui.configbool('experimental', 'verbose-obsolescence-exchange')
+ verbose = ui.configbool(b'experimental', b'verbose-obsolescence-exchange')
if verbose:
- message = 'OBSEXC: ' + message
+ message = b'OBSEXC: ' + message
if important or verbose:
ui.status(message)
def obsexcprg(ui, *args, **kwargs):
- topic = 'obsmarkers exchange'
- if ui.configbool('experimental', 'verbose-obsolescence-exchange'):
- topic = 'OBSEXC'
+ topic = b'obsmarkers exchange'
+ if ui.configbool(b'experimental', b'verbose-obsolescence-exchange'):
+ topic = b'OBSEXC'
compat.progress(ui, topic, *args, **kwargs)
def filterparents(parents):
@@ -50,28 +50,28 @@
def shouldwarmcache(repo, tr):
configbool = repo.ui.configbool
config = repo.ui.config
- desc = getattr(tr, 'desc', '')
+ desc = getattr(tr, 'desc', b'')
autocase = False
if tr is None and not getattr(repo, '_destroying', False):
autocase = True
- elif desc.startswith('serve'):
+ elif desc.startswith(b'serve'):
autocase = True
- elif desc.startswith('push') and not desc.startswith('push-response'):
+ elif desc.startswith(b'push') and not desc.startswith(b'push-response'):
autocase = True
- autocache = config('experimental', 'obshashrange.warm-cache',
- 'auto') == 'auto'
+ autocache = config(b'experimental', b'obshashrange.warm-cache',
+ b'auto') == b'auto'
if autocache:
warm = autocase
else:
# note: we should not get to the default case
- warm = configbool('experimental', 'obshashrange.warm-cache')
- if not configbool('experimental', 'obshashrange'):
+ warm = configbool(b'experimental', b'obshashrange.warm-cache')
+ if not configbool(b'experimental', b'obshashrange'):
return False
if not warm:
return False
- maxrevs = repo.ui.configint('experimental', 'obshashrange.max-revs')
+ maxrevs = repo.ui.configint(b'experimental', b'obshashrange.max-revs')
if maxrevs is not None and maxrevs < len(repo.unfiltered()):
return False
return True
@@ -123,8 +123,8 @@
newer = obsutil.successorssets(repo, obs.node())
# search of a parent which is not killed
while not newer:
- ui.debug("stabilize target %s is plain dead,"
- " trying to stabilize on its parent\n" %
+ ui.debug(b"stabilize target %s is plain dead,"
+ b" trying to stabilize on its parent\n" %
obs)
obs = obs.parents()[0]
newer = obsutil.successorssets(repo, obs.node())
@@ -141,7 +141,7 @@
for successorsset in exc.successorssets
for node in successorsset}
-def revselectionprompt(ui, repo, revs, customheader=""):
+def revselectionprompt(ui, repo, revs, customheader=b""):
"""function to prompt user to choose a revision from all the revs and return
that revision for further tasks
@@ -161,29 +161,29 @@
if not ui.interactive():
return None
- promptmsg = customheader + "\n"
+ promptmsg = customheader + b"\n"
for idx, rev in enumerate(revs):
curctx = repo[rev]
- revmsg = "%d: [%s] %s\n" % (idx + 1, curctx,
- curctx.description().split("\n")[0])
+ revmsg = b"%d: [%s] %s\n" % (idx + 1, curctx,
+ curctx.description().split(b"\n")[0])
promptmsg += revmsg
- promptmsg += _("q: quit the prompt\n")
- promptmsg += _("enter the index of the revision you want to select:")
+ promptmsg += _(b"q: quit the prompt\n")
+ promptmsg += _(b"enter the index of the revision you want to select:")
idxselected = ui.prompt(promptmsg)
intidx = None
try:
intidx = int(idxselected)
except ValueError:
- if idxselected == 'q':
+ if idxselected == b'q':
return None
- ui.write_err(_("invalid value '%s' entered for index\n") % idxselected)
+ ui.write_err(_(b"invalid value '%s' entered for index\n") % idxselected)
return None
if intidx > len(revs) or intidx <= 0:
# we can make this error message better
- ui.write_err(_("invalid value '%d' entered for index\n") % intidx)
+ ui.write_err(_(b"invalid value '%d' entered for index\n") % intidx)
return None
return revs[intidx - 1]
@@ -206,7 +206,7 @@
# all three are different, lets concatenate the two authors
# XXX: should we let the user know about concatenation of authors
# by printing some message (or maybe in verbose mode)
- users = set(divuser.split(', '))
- users.update(othuser.split(', '))
- user = ', '.join(sorted(users))
+ users = set(divuser.split(b', '))
+ users.update(othuser.split(b', '))
+ user = b', '.join(sorted(users))
return user
--- a/hgext3rd/pullbundle.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/pullbundle.py Fri Sep 27 13:03:14 2019 +0200
@@ -92,10 +92,10 @@
from mercurial.i18n import _
-__version__ = '0.1.1'
-testedwith = '4.4 4.5 4.6 4.7.1'
-minimumhgversion = '4.4'
-buglink = 'https://bz.mercurial-scm.org/'
+__version__ = b'0.1.1'
+testedwith = b'4.4 4.5 4.6 4.7.1'
+minimumhgversion = b'4.4'
+buglink = b'https://bz.mercurial-scm.org/'
cmdtable = {}
command = registrar.command(cmdtable)
@@ -103,14 +103,14 @@
configtable = {}
configitem = registrar.configitem(configtable)
-configitem('pullbundle', 'cache-directory',
+configitem(b'pullbundle', b'cache-directory',
default=None,
)
# generic wrapping
def uisetup(ui):
- exchange.getbundle2partsmapping['changegroup'] = _getbundlechangegrouppart
+ exchange.getbundle2partsmapping[b'changegroup'] = _getbundlechangegrouppart
def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
b2caps=None, heads=None, common=None, **kwargs):
@@ -118,13 +118,13 @@
if not kwargs.get(r'cg', True):
return
- version = '01'
- cgversions = b2caps.get('changegroup')
+ version = b'01'
+ cgversions = b2caps.get(b'changegroup')
if cgversions: # 3.1 and 3.2 ship with an empty value
cgversions = [v for v in cgversions
if v in changegroup.supportedoutgoingversions(repo)]
if not cgversions:
- raise ValueError(_('no common changegroup version'))
+ raise ValueError(_(b'no common changegroup version'))
version = max(cgversions)
outgoing = exchange._computeoutgoing(repo, heads, common)
@@ -145,20 +145,20 @@
# END OF ALTERED PART
if kwargs.get(r'narrow', False) and (include or exclude):
- narrowspecpart = bundler.newpart('narrow:spec')
+ narrowspecpart = bundler.newpart(b'narrow:spec')
if include:
narrowspecpart.addparam(
- 'include', '\n'.join(include), mandatory=True)
+ b'include', b'\n'.join(include), mandatory=True)
if exclude:
narrowspecpart.addparam(
- 'exclude', '\n'.join(exclude), mandatory=True)
+ b'exclude', b'\n'.join(exclude), mandatory=True)
def makeallcgpart(newpart, repo, outgoing, version, source,
bundlecaps, filematcher, cgversions):
pullbundle = not filematcher
if pullbundle and not util.safehasattr(repo, 'stablerange'):
- repo.ui.warn('pullbundle: required extension "evolve" are missing, skipping pullbundle\n')
+ repo.ui.warn(b'pullbundle: required extension "evolve" are missing, skipping pullbundle\n')
pullbundle = False
if filematcher:
makeonecgpart(newpart, repo, None, outgoing, version, source, bundlecaps,
@@ -167,8 +167,8 @@
start = util.timer()
slices = sliceoutgoing(repo, outgoing)
end = util.timer()
- msg = _('pullbundle-cache: "missing" set sliced into %d subranges '
- 'in %f seconds\n')
+ msg = _(b'pullbundle-cache: "missing" set sliced into %d subranges '
+ b'in %f seconds\n')
repo.ui.write(msg % (len(slices), end - start))
for sliceid, sliceout in slices:
makeonecgpart(newpart, repo, sliceid, sliceout, version, source, bundlecaps,
@@ -192,7 +192,7 @@
missingheads = [rev(n) for n in sorted(outgoing.missingheads, reverse=True)]
for head in missingheads:
localslices = []
- localmissing = set(repo.revs('%ld and ::%d', missingrevs, head))
+ localmissing = set(repo.revs(b'%ld and ::%d', missingrevs, head))
thisrunmissing = localmissing.copy()
while localmissing:
slicerevs = []
@@ -207,11 +207,11 @@
missingrevs.difference_update(slicerevs)
localmissing.difference_update(slicerevs)
if localmissing:
- heads = list(repo.revs('heads(%ld)', localmissing))
+ heads = list(repo.revs(b'heads(%ld)', localmissing))
heads.sort(key=node)
head = heads.pop()
if heads:
- thisrunmissing = repo.revs('%ld and only(%d, %ld)',
+ thisrunmissing = repo.revs(b'%ld and only(%d, %ld)',
localmissing,
head,
heads)
@@ -220,15 +220,15 @@
if DEBUG:
for s in reversed(ss):
ms -= set(s)
- missingbase = repo.revs('parents(%ld) and %ld', s, ms)
+ missingbase = repo.revs(b'parents(%ld) and %ld', s, ms)
if missingbase:
- repo.ui.write_err('!!! rev bundled while parents missing\n')
- repo.ui.write_err(' parent: %s\n' % list(missingbase))
- pb = repo.revs('%ld and children(%ld)', s, missingbase)
- repo.ui.write_err(' children: %s\n' % list(pb))
- h = repo.revs('heads(%ld)', s)
- repo.ui.write_err(' heads: %s\n' % list(h))
- raise error.ProgrammingError('issuing a range before its parents')
+ repo.ui.write_err(b'!!! rev bundled while parents missing\n')
+ repo.ui.write_err(b' parent: %s\n' % list(missingbase))
+ pb = repo.revs(b'%ld and children(%ld)', s, missingbase)
+ repo.ui.write_err(b' children: %s\n' % list(pb))
+ h = repo.revs(b'heads(%ld)', s)
+ repo.ui.write_err(b' heads: %s\n' % list(h))
+ raise error.ProgrammingError(b'issuing a range before its parents')
for s in reversed(localslices):
allslices.extend(s)
@@ -381,8 +381,8 @@
# changegroup part construction
def _changegroupinfo(repo, nodes, source):
- if repo.ui.verbose or source == 'bundle':
- repo.ui.status(_("%d changesets found\n") % len(nodes))
+ if repo.ui.verbose or source == b'bundle':
+ repo.ui.status(_(b"%d changesets found\n") % len(nodes))
def _makenewstream(newpart, repo, outgoing, version, source,
bundlecaps, filematcher, cgversions):
@@ -408,23 +408,23 @@
def _makepartfromstream(newpart, repo, cgstream, nbchanges, version):
# same as upstream code
- part = newpart('changegroup', data=cgstream)
+ part = newpart(b'changegroup', data=cgstream)
if version:
- part.addparam('version', version)
+ part.addparam(b'version', version)
- part.addparam('nbchanges', '%d' % nbchanges,
+ part.addparam(b'nbchanges', b'%d' % nbchanges,
mandatory=False)
- if 'treemanifest' in repo.requirements:
- part.addparam('treemanifest', '1')
+ if b'treemanifest' in repo.requirements:
+ part.addparam(b'treemanifest', b'1')
# cache management
def cachedir(repo):
- cachedir = repo.ui.config('pullbundle', 'cache-directory')
+ cachedir = repo.ui.config(b'pullbundle', b'cache-directory')
if cachedir is not None:
return cachedir
- return repo.cachevfs.join('pullbundles')
+ return repo.cachevfs.join(b'pullbundles')
def getcache(repo, bundlename):
cdir = cachedir(repo)
@@ -436,7 +436,7 @@
# opening too many file will not work.
def data():
- with open(bundlepath, 'rb') as fd:
+ with open(bundlepath, r'rb') as fd:
for chunk in util.filechunkiter(fd):
yield chunk
return data()
@@ -454,7 +454,7 @@
cachefile.write(chunk)
yield chunk
-BUNDLEMASK = "%s-%s-%010iskip-%010isize.hg"
+BUNDLEMASK = b"%s-%s-%010iskip-%010isize.hg"
def makeonecgpart(newpart, repo, rangeid, outgoing, version, source,
bundlecaps, filematcher, cgversions):
@@ -472,19 +472,19 @@
cgstream = cachewriter(repo, bundlename, partdata[0])
partdata = (cgstream,) + partdata[1:]
else:
- if repo.ui.verbose or source == 'bundle':
- repo.ui.status(_("%d changesets found in caches\n") % nbchanges)
+ if repo.ui.verbose or source == b'bundle':
+ repo.ui.status(_(b"%d changesets found in caches\n") % nbchanges)
pversion = None
if cgversions:
pversion = version
partdata = (cachedata, nbchanges, pversion)
return _makepartfromstream(newpart, repo, *partdata)
-@command('debugpullbundlecacheoverlap',
- [('', 'count', 100, _('of "client" pulling')),
- ('', 'min-cache', 1, _('minimum size of cached bundle')),
- ],
- _('hg debugpullbundlecacheoverlap [--client 100] REVSET'))
+@command(b'debugpullbundlecacheoverlap',
+ [(b'', b'count', 100, _(b'of "client" pulling')),
+ (b'', b'min-cache', 1, _(b'minimum size of cached bundle')),
+ ],
+ _(b'hg debugpullbundlecacheoverlap [--client 100] REVSET'))
def debugpullbundlecacheoverlap(ui, repo, *revs, **opts):
'''Display statistic on bundle cache hit
@@ -494,7 +494,7 @@
'''
actionrevs = scmutil.revrange(repo, revs)
if not revs:
- raise error.Abort('No revision selected')
+ raise error.Abort(b'No revision selected')
count = opts['count']
min_cache = opts['min_cache']
@@ -503,12 +503,12 @@
rlen = lambda rangeid: repo.stablerange.rangelength(repo, rangeid)
- repo.ui.write("gathering %d sample pulls within %d revisions\n"
+ repo.ui.write(b"gathering %d sample pulls within %d revisions\n"
% (count, len(actionrevs)))
if 1 < min_cache:
- repo.ui.write(" not caching ranges smaller than %d changesets\n" % min_cache)
+ repo.ui.write(b" not caching ranges smaller than %d changesets\n" % min_cache)
for i in range(count):
- repo.ui.progress('gathering data', i, total=count)
+ repo.ui.progress(b'gathering data', i, total=count)
outgoing = takeonesample(repo, actionrevs)
ranges = sliceoutgoing(repo, outgoing)
hitranges = 0
@@ -532,7 +532,7 @@
hitranges,
)
pullstats.append(stats)
- repo.ui.progress('gathering data', None)
+ repo.ui.progress(b'gathering data', None)
sizes = []
changesmissing = []
@@ -563,36 +563,36 @@
cachedhits.append(hits)
sizesdist = distribution(sizes)
- repo.ui.write(fmtdist('pull size', sizesdist))
+ repo.ui.write(fmtdist(b'pull size', sizesdist))
changesmissingdist = distribution(changesmissing)
- repo.ui.write(fmtdist('non-cached changesets', changesmissingdist))
+ repo.ui.write(fmtdist(b'non-cached changesets', changesmissingdist))
changesratiodist = distribution(changesratio)
- repo.ui.write(fmtdist('ratio of cached changesets', changesratiodist))
+ repo.ui.write(fmtdist(b'ratio of cached changesets', changesratiodist))
bundlecountdist = distribution(bundlecount)
- repo.ui.write(fmtdist('bundle count', bundlecountdist))
+ repo.ui.write(fmtdist(b'bundle count', bundlecountdist))
rangesratiodist = distribution(rangesratio)
- repo.ui.write(fmtdist('ratio of cached bundles', rangesratiodist))
+ repo.ui.write(fmtdist(b'ratio of cached bundles', rangesratiodist))
- repo.ui.write('changesets served:\n')
- repo.ui.write(' total: %7d\n' % totalchanges)
- repo.ui.write(' from cache: %7d (%2d%%)\n'
+ repo.ui.write(b'changesets served:\n')
+ repo.ui.write(b' total: %7d\n' % totalchanges)
+ repo.ui.write(b' from cache: %7d (%2d%%)\n'
% (totalcached, (totalcached * 100 // totalchanges)))
- repo.ui.write(' bundle: %7d\n' % sum(bundlecount))
+ repo.ui.write(b' bundle: %7d\n' % sum(bundlecount))
cachedsizesdist = distribution(cachedsizes)
- repo.ui.write(fmtdist('size of cached bundles', cachedsizesdist))
+ repo.ui.write(fmtdist(b'size of cached bundles', cachedsizesdist))
cachedhitsdist = distribution(cachedhits)
- repo.ui.write(fmtdist('hit on cached bundles', cachedhitsdist))
+ repo.ui.write(fmtdist(b'hit on cached bundles', cachedhitsdist))
def takeonesample(repo, revs):
node = repo.changelog.node
pulled = random.sample(revs, max(4, len(revs) // 1000))
- pulled = repo.revs('%ld::%ld', pulled, pulled)
+ pulled = repo.revs(b'%ld::%ld', pulled, pulled)
nodes = [node(r) for r in pulled]
return outgoingfromnodes(repo, nodes)
@@ -600,17 +600,17 @@
data.sort()
length = len(data)
return {
- 'min': data[0],
- '10%': data[length // 10],
- '25%': data[length // 4],
- '50%': data[length // 2],
- '75%': data[(length // 4) * 3],
- '90%': data[(length // 10) * 9],
- '95%': data[(length // 20) * 19],
- 'max': data[-1],
+ b'min': data[0],
+ b'10%': data[length // 10],
+ b'25%': data[length // 4],
+ b'50%': data[length // 2],
+ b'75%': data[(length // 4) * 3],
+ b'90%': data[(length // 10) * 9],
+ b'95%': data[(length // 20) * 19],
+ b'max': data[-1],
}
-STATSFORMAT = """{name}:
+STATSFORMAT = b"""{name}:
min: {min}
10%: {10%}
25%: {25%}
--- a/hgext3rd/serverminitopic.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/serverminitopic.py Fri Sep 27 13:03:14 2019 +0200
@@ -33,7 +33,7 @@
configtable = {}
configitem = registrar.configitem(configtable)
- configitem('experimental', 'server-mini-topic',
+ configitem(b'experimental', b'server-mini-topic',
default=False,
)
@@ -44,7 +44,7 @@
"""
enabled = getattr(repo, '_hasminitopic', None)
if enabled is None:
- enabled = (repo.ui.configbool('experimental', 'server-mini-topic')
+ enabled = (repo.ui.configbool(b'experimental', b'server-mini-topic')
and not repo.publishing())
repo._hasminitopic = enabled
return enabled
@@ -54,10 +54,10 @@
def topicbranch(orig, self):
branch = orig(self)
if hasminitopic(self._repo) and self.phase():
- topic = self._changeset.extra.get('topic')
+ topic = self._changeset.extra.get(b'topic')
if topic is not None:
topic = encoding.tolocal(topic)
- branch = '%s:%s' % (branch, topic)
+ branch = b'%s:%s' % (branch, topic)
return branch
### avoid caching topic data in rev-branch-cache
@@ -67,7 +67,7 @@
def _init__(self, *args, **kwargs):
super(revbranchcacheoverlay, self).__init__(*args, **kwargs)
- if 'branchinfo' in vars(self):
+ if r'branchinfo' in vars(self):
del self.branchinfo
def branchinfo(self, rev, changelog=None):
@@ -95,7 +95,7 @@
class topicawarerbc(revbranchcacheoverlay, cache.__class__):
pass
cache.__class__ = topicawarerbc
- if 'branchinfo' in vars(cache):
+ if r'branchinfo' in vars(cache):
del cache.branchinfo
self._revbranchcache = cache
return self._revbranchcache
@@ -120,7 +120,7 @@
if revs:
s = hashlib.sha1()
for rev in revs:
- s.update('%d;' % rev)
+ s.update(b'%d;' % rev)
key = s.digest()
return key
@@ -138,8 +138,8 @@
branchmap.branchcache = previous
_publiconly = set([
- 'base',
- 'immutable',
+ b'base',
+ b'immutable',
])
def mighttopic(repo):
@@ -216,7 +216,7 @@
def wireprotocaps(orig, repo, proto):
caps = orig(repo, proto)
if hasminitopic(repo):
- caps.append('topics')
+ caps.append(b'topics')
return caps
# wrap the necessary bit
--- a/hgext3rd/topic/__init__.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/__init__.py Fri Sep 27 13:03:14 2019 +0200
@@ -160,36 +160,36 @@
cmdtable = {}
command = registrar.command(cmdtable)
-colortable = {'topic.active': 'green',
- 'topic.list.unstablecount': 'red',
- 'topic.list.headcount.multiple': 'yellow',
- 'topic.list.behindcount': 'cyan',
- 'topic.list.behinderror': 'red',
- 'stack.index': 'yellow',
- 'stack.index.base': 'none dim',
- 'stack.desc.base': 'none dim',
- 'stack.shortnode.base': 'none dim',
- 'stack.state.base': 'dim',
- 'stack.state.clean': 'green',
- 'stack.index.current': 'cyan', # random pick
- 'stack.state.current': 'cyan bold', # random pick
- 'stack.desc.current': 'cyan', # random pick
- 'stack.shortnode.current': 'cyan', # random pick
- 'stack.state.orphan': 'red',
- 'stack.state.content-divergent': 'red',
- 'stack.state.phase-divergent': 'red',
- 'stack.summary.behindcount': 'cyan',
- 'stack.summary.behinderror': 'red',
- 'stack.summary.headcount.multiple': 'yellow',
+colortable = {b'topic.active': b'green',
+ b'topic.list.unstablecount': b'red',
+ b'topic.list.headcount.multiple': b'yellow',
+ b'topic.list.behindcount': b'cyan',
+ b'topic.list.behinderror': b'red',
+ b'stack.index': b'yellow',
+ b'stack.index.base': b'none dim',
+ b'stack.desc.base': b'none dim',
+ b'stack.shortnode.base': b'none dim',
+ b'stack.state.base': b'dim',
+ b'stack.state.clean': b'green',
+ b'stack.index.current': b'cyan', # random pick
+ b'stack.state.current': b'cyan bold', # random pick
+ b'stack.desc.current': b'cyan', # random pick
+ b'stack.shortnode.current': b'cyan', # random pick
+ b'stack.state.orphan': b'red',
+ b'stack.state.content-divergent': b'red',
+ b'stack.state.phase-divergent': b'red',
+ b'stack.summary.behindcount': b'cyan',
+ b'stack.summary.behinderror': b'red',
+ b'stack.summary.headcount.multiple': b'yellow',
# default color to help log output and thg
# (first pick I could think off, update as needed
- 'log.topic': 'green_background',
- 'topic.active': 'green',
- }
+ b'log.topic': b'green_background',
+ b'topic.active': b'green',
+ }
-__version__ = b'0.16.0.dev'
+__version__ = b'0.17.0'
-testedwith = b'4.5.2 4.6.2 4.7 4.8 4.9 5.0'
+testedwith = b'4.5.2 4.6.2 4.7 4.8 4.9 5.0 5.1'
minimumhgversion = b'4.5'
buglink = b'https://bz.mercurial-scm.org/'
@@ -200,25 +200,25 @@
configtable = {}
configitem = registrar.configitem(configtable)
- configitem('experimental', 'enforce-topic',
+ configitem(b'experimental', b'enforce-topic',
default=False,
)
- configitem('experimental', 'enforce-single-head',
+ configitem(b'experimental', b'enforce-single-head',
default=False,
)
- configitem('experimental', 'topic-mode',
+ configitem(b'experimental', b'topic-mode',
default=None,
)
- configitem('experimental', 'topic.publish-bare-branch',
+ configitem(b'experimental', b'topic.publish-bare-branch',
default=False,
)
- configitem('experimental', 'topic.allow-publish',
+ configitem(b'experimental', b'topic.allow-publish',
default=configitems.dynamicdefault,
)
- configitem('_internal', 'keep-topic',
+ configitem(b'_internal', b'keep-topic',
default=False,
)
- configitem('experimental', 'topic-mode.server',
+ configitem(b'experimental', b'topic-mode.server',
default=configitems.dynamicdefault,
)
@@ -229,25 +229,25 @@
# nobody else did so far.
from mercurial import configitems
extraitem = functools.partial(configitems._register, ui._knownconfig)
- if ('experimental' not in ui._knownconfig
- or not ui._knownconfig['experimental'].get('thg.displaynames')):
- extraitem('experimental', 'thg.displaynames',
+ if (b'experimental' not in ui._knownconfig
+ or not ui._knownconfig[b'experimental'].get(b'thg.displaynames')):
+ extraitem(b'experimental', b'thg.displaynames',
default=None,
)
- if ('devel' not in ui._knownconfig
- or not ui._knownconfig['devel'].get('random')):
- extraitem('devel', 'randomseed',
+ if (b'devel' not in ui._knownconfig
+ or not ui._knownconfig[b'devel'].get(b'random')):
+ extraitem(b'devel', b'randomseed',
default=None,
)
# we need to do old style declaration for <= 4.5
templatekeyword = registrar.templatekeyword()
-post45template = 'requires=' in templatekeyword.__doc__
+post45template = r'requires=' in templatekeyword.__doc__
def _contexttopic(self, force=False):
if not (force or self.mutable()):
- return ''
- return self.extra().get(constants.extrakey, '')
+ return b''
+ return self.extra().get(constants.extrakey, b'')
context.basectx.topic = _contexttopic
def _contexttopicidx(self):
@@ -264,8 +264,8 @@
return None
context.basectx.topicidx = _contexttopicidx
-stackrev = re.compile(r'^s\d+$')
-topicrev = re.compile(r'^t\d+$')
+stackrev = re.compile(br'^s\d+$')
+topicrev = re.compile(br'^t\d+$')
hastopicext = common.hastopicext
@@ -275,38 +275,38 @@
idx = int(name[1:])
tname = topic = repo.currenttopic
if topic:
- ttype = 'topic'
+ ttype = b'topic'
revs = list(stack.stack(repo, topic=topic))
else:
- ttype = 'branch'
+ ttype = b'branch'
tname = branch = repo[None].branch()
revs = list(stack.stack(repo, branch=branch))
elif topicrev.match(name):
idx = int(name[1:])
- ttype = 'topic'
+ ttype = b'topic'
tname = topic = repo.currenttopic
if not tname:
- raise error.Abort(_('cannot resolve "%s": no active topic') % name)
+ raise error.Abort(_(b'cannot resolve "%s": no active topic') % name)
revs = list(stack.stack(repo, topic=topic))
if revs is not None:
try:
r = revs[idx]
except IndexError:
- if ttype == 'topic':
- msg = _('cannot resolve "%s": %s "%s" has only %d changesets')
- elif ttype == 'branch':
- msg = _('cannot resolve "%s": %s "%s" has only %d non-public changesets')
+ if ttype == b'topic':
+ msg = _(b'cannot resolve "%s": %s "%s" has only %d changesets')
+ elif ttype == b'branch':
+ msg = _(b'cannot resolve "%s": %s "%s" has only %d non-public changesets')
raise error.Abort(msg % (name, ttype, tname, len(revs) - 1))
# t0 or s0 can be None
if r == -1 and idx == 0:
- msg = _('the %s "%s" has no %s')
+ msg = _(b'the %s "%s" has no %s')
raise error.Abort(msg % (ttype, tname, name))
return [repo[r].node()]
if name not in repo.topics:
return []
node = repo.changelog.node
- return [node(rev) for rev in repo.revs('topic(%s)', name)]
+ return [node(rev) for rev in repo.revs(b'topic(%s)', name)]
def _nodemap(repo, node):
ctx = repo[node]
@@ -321,22 +321,22 @@
topicmap.modsetup(ui)
setupimportexport(ui)
- extensions.afterloaded('rebase', _fixrebase)
+ extensions.afterloaded(b'rebase', _fixrebase)
flow.installpushflag(ui)
- entry = extensions.wrapcommand(commands.table, 'commit', commitwrap)
- entry[1].append(('t', 'topic', '',
- _("use specified topic"), _('TOPIC')))
+ entry = extensions.wrapcommand(commands.table, b'commit', commitwrap)
+ entry[1].append((b't', b'topic', b'',
+ _(b"use specified topic"), _(b'TOPIC')))
- entry = extensions.wrapcommand(commands.table, 'push', pushoutgoingwrap)
- entry[1].append(('t', 'topic', '',
- _("topic to push"), _('TOPIC')))
+ entry = extensions.wrapcommand(commands.table, b'push', pushoutgoingwrap)
+ entry[1].append((b't', b'topic', b'',
+ _(b"topic to push"), _(b'TOPIC')))
- entry = extensions.wrapcommand(commands.table, 'outgoing',
+ entry = extensions.wrapcommand(commands.table, b'outgoing',
pushoutgoingwrap)
- entry[1].append(('t', 'topic', '',
- _("topic to push"), _('TOPIC')))
+ entry[1].append((b't', b'topic', b'',
+ _(b"topic to push"), _(b'TOPIC')))
extensions.wrapfunction(cmdutil, 'buildcommittext', committextwrap)
extensions.wrapfunction(merge, 'update', mergeupdatewrap)
@@ -344,20 +344,20 @@
# behaviour of changing topic and I can't find a better way
# to do that as scmutil.revsingle returns the rev number and hence we can't
# plug into logic for this into mergemod.update().
- extensions.wrapcommand(commands.table, 'update', checkt0)
+ extensions.wrapcommand(commands.table, b'update', checkt0)
try:
- evolve = extensions.find('evolve')
+ evolve = extensions.find(b'evolve')
extensions.wrapfunction(evolve.rewriteutil, "presplitupdate",
presplitupdatetopic)
except (KeyError, AttributeError):
pass
- cmdutil.summaryhooks.add('topic', summaryhook)
+ cmdutil.summaryhooks.add(b'topic', summaryhook)
if not post45template:
- templatekw.keywords['topic'] = topickw
- templatekw.keywords['topicidx'] = topicidxkw
+ templatekw.keywords[b'topic'] = topickw
+ templatekw.keywords[b'topicidx'] = topicidxkw
# Wrap workingctx extra to return the topic name
extensions.wrapfunction(context.workingctx, '__init__', wrapinit)
# Wrap changelog.add to drop empty topic
@@ -369,9 +369,9 @@
repo = repo.unfiltered()
- if repo.ui.config('experimental', 'thg.displaynames') is None:
- repo.ui.setconfig('experimental', 'thg.displaynames', 'topics',
- source='topic-extension')
+ if repo.ui.config(b'experimental', b'thg.displaynames') is None:
+ repo.ui.setconfig(b'experimental', b'thg.displaynames', b'topics',
+ source=b'topic-extension')
class topicrepo(repo.__class__):
@@ -380,51 +380,51 @@
def _restrictcapabilities(self, caps):
caps = super(topicrepo, self)._restrictcapabilities(caps)
- caps.add('topics')
+ caps.add(b'topics')
return caps
def commit(self, *args, **kwargs):
- backup = self.ui.backupconfig('ui', 'allowemptycommit')
+ backup = self.ui.backupconfig(b'ui', b'allowemptycommit')
try:
- if self.currenttopic != self['.'].topic():
+ if self.currenttopic != self[b'.'].topic():
# bypass the core "nothing changed" logic
- self.ui.setconfig('ui', 'allowemptycommit', True)
+ self.ui.setconfig(b'ui', b'allowemptycommit', True)
return super(topicrepo, self).commit(*args, **kwargs)
finally:
self.ui.restoreconfig(backup)
- def commitctx(self, ctx, error=None):
+ def commitctx(self, ctx, *args, **kwargs):
topicfilter = topicmap.topicfilter(self.filtername)
if topicfilter != self.filtername:
other = self.filtered(topicmap.topicfilter(self.filtername))
- other.commitctx(ctx, error=error)
+ other.commitctx(ctx, *args, **kwargs)
if isinstance(ctx, context.workingcommitctx):
current = self.currenttopic
if current:
ctx.extra()[constants.extrakey] = current
if (isinstance(ctx, context.memctx)
- and ctx.extra().get('amend_source')
+ and ctx.extra().get(b'amend_source')
and ctx.topic()
and not self.currenttopic):
# we are amending and need to remove a topic
del ctx.extra()[constants.extrakey]
- return super(topicrepo, self).commitctx(ctx, error=error)
+ return super(topicrepo, self).commitctx(ctx, *args, **kwargs)
@property
def topics(self):
if self._topics is not None:
return self._topics
- topics = set(['', self.currenttopic])
- for c in self.set('not public()'):
+ topics = set([b'', self.currenttopic])
+ for c in self.set(b'not public()'):
topics.add(c.topic())
- topics.remove('')
+ topics.remove(b'')
self._topics = topics
return topics
@property
def currenttopic(self):
- return self.vfs.tryread('topic')
+ return self.vfs.tryread(b'topic')
# overwritten at the instance level by topicmap.py
_autobranchmaptopic = True
@@ -441,7 +441,7 @@
if branch is None:
branch = self[None].branch()
if self.currenttopic:
- branch = "%s:%s" % (branch, self.currenttopic)
+ branch = b"%s:%s" % (branch, self.currenttopic)
return super(topicrepo, self).branchheads(branch=branch,
start=start,
closed=closed)
@@ -464,11 +464,11 @@
def transaction(self, desc, *a, **k):
ctr = self.currenttransaction()
tr = super(topicrepo, self).transaction(desc, *a, **k)
- if desc in ('strip', 'repair') or ctr is not None:
+ if desc in (b'strip', b'repair') or ctr is not None:
return tr
reporef = weakref.ref(self)
- if self.ui.configbool('experimental', 'enforce-single-head'):
+ if self.ui.configbool(b'experimental', b'enforce-single-head'):
if util.safehasattr(tr, 'validator'): # hg <= 4.7
origvalidator = tr.validator
else:
@@ -484,10 +484,10 @@
else:
tr._validator = validator
- topicmodeserver = self.ui.config('experimental',
- 'topic-mode.server', 'ignore')
- ispush = (desc.startswith('push') or desc.startswith('serve'))
- if (topicmodeserver != 'ignore' and ispush):
+ topicmodeserver = self.ui.config(b'experimental',
+ b'topic-mode.server', b'ignore')
+ ispush = (desc.startswith(b'push') or desc.startswith(b'serve'))
+ if (topicmodeserver != b'ignore' and ispush):
if util.safehasattr(tr, 'validator'): # hg <= 4.7
origvalidator = tr.validator
else:
@@ -502,9 +502,9 @@
else:
tr._validator = validator
- elif (self.ui.configbool('experimental', 'topic.publish-bare-branch')
- and (desc.startswith('push')
- or desc.startswith('serve'))
+ elif (self.ui.configbool(b'experimental', b'topic.publish-bare-branch')
+ and (desc.startswith(b'push')
+ or desc.startswith(b'serve'))
):
origclose = tr.close
trref = weakref.ref(tr)
@@ -515,8 +515,8 @@
flow.publishbarebranch(repo, tr2)
origclose()
tr.close = close
- allow_publish = self.ui.configbool('experimental',
- 'topic.allow-publish',
+ allow_publish = self.ui.configbool(b'experimental',
+ b'topic.allow-publish',
True)
if not allow_publish:
if util.safehasattr(tr, 'validator'): # hg <= 4.7
@@ -547,62 +547,62 @@
csetcount = stack.stack(repo, topic=ct).changesetcount
empty = csetcount == 0
if empty and not ctwasempty:
- ui.status("active topic '%s' is now empty\n" % ct)
+ ui.status(b"active topic '%s' is now empty\n" % ct)
trnames = getattr(tr, 'names', getattr(tr, '_names', ()))
- if ('phase' in trnames
- or any(n.startswith('push-response')
+ if (b'phase' in trnames
+ or any(n.startswith(b'push-response')
for n in trnames)):
- ui.status(_("(use 'hg topic --clear' to clear it if needed)\n"))
- hint = _("(see 'hg help topics' for more information)\n")
+ ui.status(_(b"(use 'hg topic --clear' to clear it if needed)\n"))
+ hint = _(b"(see 'hg help topics' for more information)\n")
if ctwasempty and not empty:
if csetcount == 1:
- msg = _("active topic '%s' grew its first changeset\n%s")
+ msg = _(b"active topic '%s' grew its first changeset\n%s")
ui.status(msg % (ct, hint))
else:
- msg = _("active topic '%s' grew its %s first changesets\n%s")
+ msg = _(b"active topic '%s' grew its %s first changesets\n%s")
ui.status(msg % (ct, csetcount, hint))
- tr.addpostclose('signalcurrenttopicempty', currenttopicempty)
+ tr.addpostclose(b'signalcurrenttopicempty', currenttopicempty)
return tr
repo.__class__ = topicrepo
repo._topics = None
if util.safehasattr(repo, 'names'):
repo.names.addnamespace(namespaces.namespace(
- 'topics', 'topic', namemap=_namemap, nodemap=_nodemap,
+ b'topics', b'topic', namemap=_namemap, nodemap=_nodemap,
listnames=lambda repo: repo.topics))
if post45template:
@templatekeyword(b'topic', requires={b'ctx'})
def topickw(context, mapping):
""":topic: String. The topic of the changeset"""
- ctx = context.resource(mapping, 'ctx')
+ ctx = context.resource(mapping, b'ctx')
return ctx.topic()
@templatekeyword(b'topicidx', requires={b'ctx'})
def topicidxkw(context, mapping):
""":topicidx: Integer. Index of the changeset as a stack alias"""
- ctx = context.resource(mapping, 'ctx')
+ ctx = context.resource(mapping, b'ctx')
return ctx.topicidx()
else:
def topickw(**args):
""":topic: String. The topic of the changeset"""
- return args['ctx'].topic()
+ return args[b'ctx'].topic()
def topicidxkw(**args):
""":topicidx: Integer. Index of the changeset as a stack alias"""
- return args['ctx'].topicidx()
+ return args[b'ctx'].topicidx()
def wrapinit(orig, self, repo, *args, **kwargs):
orig(self, repo, *args, **kwargs)
if not hastopicext(repo):
return
if constants.extrakey not in self._extra:
- if getattr(repo, 'currenttopic', ''):
+ if getattr(repo, 'currenttopic', b''):
self._extra[constants.extrakey] = repo.currenttopic
else:
# Empty key will be dropped from extra by another hack at the changegroup level
- self._extra[constants.extrakey] = ''
+ self._extra[constants.extrakey] = b''
def wrapadd(orig, cl, manifest, files, desc, transaction, p1, p2, user,
date=None, extra=None, p1copies=None, p2copies=None,
@@ -679,13 +679,13 @@
age = opts.get('age')
if current and topic:
- raise error.Abort(_("cannot use --current when setting a topic"))
+ raise error.Abort(_(b"cannot use --current when setting a topic"))
if current and clear:
- raise error.Abort(_("cannot use --current and --clear"))
+ raise error.Abort(_(b"cannot use --current and --clear"))
if clear and topic:
- raise error.Abort(_("cannot use --clear when setting a topic"))
+ raise error.Abort(_(b"cannot use --clear when setting a topic"))
if age and topic:
- raise error.Abort(_("cannot use --age while setting a topic"))
+ raise error.Abort(_(b"cannot use --age while setting a topic"))
touchedrevs = set()
if rev:
@@ -694,50 +694,50 @@
if topic:
topic = topic.strip()
if not topic:
- raise error.Abort(_("topic name cannot consist entirely of whitespaces"))
+ raise error.Abort(_(b"topic name cannot consist entirely of whitespaces"))
# Have some restrictions on the topic name just like bookmark name
- scmutil.checknewlabel(repo, topic, 'topic')
+ scmutil.checknewlabel(repo, topic, b'topic')
rmatch = re.match(br'[-_.\w]+', topic)
if not rmatch or rmatch.group(0) != topic:
- helptxt = _("topic names can only consist of alphanumeric, '-'"
- " '_' and '.' characters")
- raise error.Abort(_("invalid topic name: '%s'") % topic, hint=helptxt)
+ helptxt = _(b"topic names can only consist of alphanumeric, '-'"
+ b" '_' and '.' characters")
+ raise error.Abort(_(b"invalid topic name: '%s'") % topic, hint=helptxt)
if list:
- ui.pager('topics')
+ ui.pager(b'topics')
if clear or rev:
- raise error.Abort(_("cannot use --clear or --rev with --list"))
+ raise error.Abort(_(b"cannot use --clear or --rev with --list"))
if not topic:
topic = repo.currenttopic
if not topic:
- raise error.Abort(_('no active topic to list'))
+ raise error.Abort(_(b'no active topic to list'))
return stack.showstack(ui, repo, topic=topic,
opts=pycompat.byteskwargs(opts))
if touchedrevs:
if not obsolete.isenabled(repo, obsolete.createmarkersopt):
- raise error.Abort(_('must have obsolete enabled to change topics'))
+ raise error.Abort(_(b'must have obsolete enabled to change topics'))
if clear:
topic = None
elif opts.get('current'):
topic = repo.currenttopic
elif not topic:
- raise error.Abort('changing topic requires a topic name or --clear')
- if repo.revs('%ld and public()', touchedrevs):
- raise error.Abort("can't change topic of a public change")
+ raise error.Abort(b'changing topic requires a topic name or --clear')
+ if repo.revs(b'%ld and public()', touchedrevs):
+ raise error.Abort(b"can't change topic of a public change")
wl = lock = txn = None
try:
wl = repo.wlock()
lock = repo.lock()
- txn = repo.transaction('rewrite-topics')
+ txn = repo.transaction(b'rewrite-topics')
rewrote = _changetopics(ui, repo, touchedrevs, topic)
txn.close()
if topic is None:
- ui.status('cleared topic on %d changesets\n' % rewrote)
+ ui.status(b'cleared topic on %d changesets\n' % rewrote)
else:
- ui.status('changed topic on %d changesets to "%s"\n' % (rewrote,
- topic))
+ ui.status(b'changed topic on %d changesets to "%s"\n' % (rewrote,
+ topic))
finally:
lockmod.release(txn, lock, wl)
repo.invalidate()
@@ -748,37 +748,37 @@
if ct:
st = stack.stack(repo, topic=ct)
if not st:
- ui.status(_('clearing empty topic "%s"\n') % ct)
+ ui.status(_(b'clearing empty topic "%s"\n') % ct)
return _changecurrenttopic(repo, None)
if topic:
if not ct:
- ui.status(_('marked working directory as topic: %s\n') % topic)
+ ui.status(_(b'marked working directory as topic: %s\n') % topic)
return _changecurrenttopic(repo, topic)
- ui.pager('topics')
+ ui.pager(b'topics')
# `hg topic --current`
ret = 0
if current and not ct:
- ui.write_err(_('no active topic\n'))
+ ui.write_err(_(b'no active topic\n'))
ret = 1
elif current:
- fm = ui.formatter('topic', pycompat.byteskwargs(opts))
- namemask = '%s\n'
- label = 'topic.active'
+ fm = ui.formatter(b'topic', pycompat.byteskwargs(opts))
+ namemask = b'%s\n'
+ label = b'topic.active'
fm.startitem()
- fm.write('topic', namemask, ct, label=label)
+ fm.write(b'topic', namemask, ct, label=label)
fm.end()
else:
_listtopics(ui, repo, opts)
return ret
-@command('stack', [
- ('c', 'children', None,
- _('display data about children outside of the stack'))
+@command(b'stack', [
+ (b'c', b'children', None,
+ _(b'display data about children outside of the stack'))
] + commands.formatteropts,
- _('hg stack [TOPIC]'))
-def cmdstack(ui, repo, topic='', **opts):
+ _(b'hg stack [TOPIC]'))
+def cmdstack(ui, repo, topic=b'', **opts):
"""list all changesets in a topic and other information
List the current topic by default.
@@ -792,15 +792,15 @@
topic = repo.currenttopic
if topic is None:
branch = repo[None].branch()
- ui.pager('stack')
+ ui.pager(b'stack')
return stack.showstack(ui, repo, branch=branch, topic=topic,
opts=pycompat.byteskwargs(opts))
-@command('debugcb|debugconvertbookmark', [
- ('b', 'bookmark', '', _('bookmark to convert to topic')),
- ('', 'all', None, _('convert all bookmarks to topics')),
+@command(b'debugcb|debugconvertbookmark', [
+ (b'b', b'bookmark', b'', _(b'bookmark to convert to topic')),
+ (b'', b'all', None, _(b'convert all bookmarks to topics')),
],
- _('[-b BOOKMARK] [--all]'))
+ _(b'[-b BOOKMARK] [--all]'))
def debugconvertbookmark(ui, repo, **opts):
"""Converts a bookmark to a topic with the same name.
"""
@@ -809,9 +809,9 @@
convertall = opts.get('all')
if convertall and bookmark:
- raise error.Abort(_("cannot use '--all' and '-b' together"))
+ raise error.Abort(_(b"cannot use '--all' and '-b' together"))
if not (convertall or bookmark):
- raise error.Abort(_("you must specify either '--all' or '-b'"))
+ raise error.Abort(_(b"you must specify either '--all' or '-b'"))
bmstore = repo._bookmarks
@@ -836,12 +836,12 @@
try:
node = bmstore[bookmark]
except KeyError:
- raise error.Abort(_("no such bookmark exists: '%s'") % bookmark)
+ raise error.Abort(_(b"no such bookmark exists: '%s'") % bookmark)
revnum = repo[node].rev()
if len(nodetobook[node]) > 1:
- ui.status(_("skipping revision '%d' as it has multiple bookmarks "
- "on it\n") % revnum)
+ ui.status(_(b"skipping revision '%d' as it has multiple bookmarks "
+ b"on it\n") % revnum)
return
targetrevs = _findconvertbmarktopic(repo, bookmark)
if targetrevs:
@@ -853,11 +853,11 @@
if revnum in skipped:
continue
if len(nodetobook[revnode]) > 1:
- ui.status(_("skipping '%d' as it has multiple bookmarks on"
- " it\n") % revnum)
+ ui.status(_(b"skipping '%d' as it has multiple bookmarks on"
+ b" it\n") % revnum)
skipped.append(revnum)
continue
- if bmark == '@':
+ if bmark == b'@':
continue
targetrevs = _findconvertbmarktopic(repo, bmark)
if targetrevs:
@@ -865,7 +865,7 @@
if actions:
try:
- tr = repo.transaction('debugconvertbookmark')
+ tr = repo.transaction(b'debugconvertbookmark')
for ((bmark, revnum), targetrevs) in sorted(actions.items()):
_applyconvertbmarktopic(ui, repo, targetrevs, revnum, bmark, tr)
tr.close()
@@ -875,7 +875,7 @@
lockmod.release(lock, wlock)
# inspired from mercurial.repair.stripbmrevset
-CONVERTBOOKREVSET = """
+CONVERTBOOKREVSET = b"""
not public() and (
ancestors(bookmark(%s))
and not ancestors(
@@ -913,9 +913,9 @@
# changeset
if rewrote == 0:
return
- ui.status(_('changed topic to "%s" on %d revisions\n') % (bmark,
+ ui.status(_(b'changed topic to "%s" on %d revisions\n') % (bmark,
rewrote))
- ui.debug('removing bookmark "%s" from "%d"' % (bmark, old))
+ ui.debug(b'removing bookmark "%s" from "%d"' % (bmark, old))
bookmarks.delete(repo, tr, [bmark])
def _changecurrenttopic(repo, newtopic):
@@ -923,11 +923,11 @@
if newtopic:
with repo.wlock():
- with repo.vfs.open('topic', 'w') as f:
+ with repo.vfs.open(b'topic', b'w') as f:
f.write(newtopic)
else:
- if repo.vfs.exists('topic'):
- repo.vfs.unlink('topic')
+ if repo.vfs.exists(b'topic'):
+ repo.vfs.unlink(b'topic')
def _changetopics(ui, repo, revs, newtopic):
""" Changes topic to newtopic of all the revisions in the revset and return
@@ -946,8 +946,8 @@
except error.ManifestLookupError:
return None
fixedextra = dict(c.extra())
- ui.debug('old node id is %s\n' % node.hex(c.node()))
- ui.debug('origextra: %r\n' % fixedextra)
+ ui.debug(b'old node id is %s\n' % node.hex(c.node()))
+ ui.debug(b'origextra: %r\n' % fixedextra)
oldtopic = fixedextra.get(constants.extrakey, None)
if oldtopic == newtopic:
continue
@@ -956,16 +956,16 @@
else:
fixedextra[constants.extrakey] = newtopic
fixedextra[constants.changekey] = c.hex()
- if 'amend_source' in fixedextra:
+ if b'amend_source' in fixedextra:
# TODO: right now the commitctx wrapper in
# topicrepo overwrites the topic in extra if
# amend_source is set to support 'hg commit
# --amend'. Support for amend should be adjusted
# to not be so invasive.
- del fixedextra['amend_source']
- ui.debug('changing topic of %s from %s to %s\n' % (
- c, oldtopic or '<none>', newtopic or '<none>'))
- ui.debug('fixedextra: %r\n' % fixedextra)
+ del fixedextra[b'amend_source']
+ ui.debug(b'changing topic of %s from %s to %s\n' % (
+ c, oldtopic or b'<none>', newtopic or b'<none>'))
+ ui.debug(b'fixedextra: %r\n' % fixedextra)
# While changing topic of set of linear commits, make sure that
# we base our commits on new parent rather than old parent which
# was obsoleted while changing the topic
@@ -986,18 +986,18 @@
# phase handling
commitphase = c.phase()
- overrides = {('phases', 'new-commit'): commitphase}
- with repo.ui.configoverride(overrides, 'changetopic'):
+ overrides = {(b'phases', b'new-commit'): commitphase}
+ with repo.ui.configoverride(overrides, b'changetopic'):
newnode = repo.commitctx(mc)
successors[c.node()] = (newnode,)
- ui.debug('new node id is %s\n' % node.hex(newnode))
+ ui.debug(b'new node id is %s\n' % node.hex(newnode))
rewrote += 1
# create obsmarkers and move bookmarks
# XXX we should be creating marker as we go instead of only at the end,
# this makes the operations more modulars
- scmutil.cleanupnodes(repo, successors, 'changetopics')
+ scmutil.cleanupnodes(repo, successors, b'changetopics')
# move the working copy too
wctx = repo[None]
@@ -1009,12 +1009,12 @@
return rewrote
def _listtopics(ui, repo, opts):
- fm = ui.formatter('topics', pycompat.byteskwargs(opts))
+ fm = ui.formatter(b'topics', pycompat.byteskwargs(opts))
activetopic = repo.currenttopic
- namemask = '%s'
+ namemask = b'%s'
if repo.topics:
maxwidth = max(len(t) for t in repo.topics)
- namemask = '%%-%is' % maxwidth
+ namemask = b'%%-%is' % maxwidth
if opts.get('age'):
# here we sort by age and topic name
topicsdata = sorted(_getlasttouched(repo, repo.topics))
@@ -1026,70 +1026,70 @@
)
for age, topic, date, user in topicsdata:
fm.startitem()
- marker = ' '
- label = 'topic'
+ marker = b' '
+ label = b'topic'
active = (topic == activetopic)
if active:
- marker = '*'
- label = 'topic.active'
+ marker = b'*'
+ label = b'topic.active'
if not ui.quiet:
# registering the active data is made explicitly later
- fm.plain(' %s ' % marker, label=label)
- fm.write('topic', namemask, topic, label=label)
+ fm.plain(b' %s ' % marker, label=label)
+ fm.write(b'topic', namemask, topic, label=label)
fm.data(active=active)
if ui.quiet:
- fm.plain('\n')
+ fm.plain(b'\n')
continue
- fm.plain(' (')
+ fm.plain(b' (')
if date:
if age == -1:
- timestr = 'empty and active'
+ timestr = b'empty and active'
else:
timestr = templatefilters.age(date)
- fm.write('lasttouched', '%s', timestr, label='topic.list.time')
+ fm.write(b'lasttouched', b'%s', timestr, label=b'topic.list.time')
if user:
- fm.write('usertouched', ' by %s', user, label='topic.list.user')
+ fm.write(b'usertouched', b' by %s', user, label=b'topic.list.user')
if date:
- fm.plain(', ')
+ fm.plain(b', ')
data = stack.stack(repo, topic=topic)
if ui.verbose:
- fm.write('branches+', 'on branch: %s',
- '+'.join(data.branches), # XXX use list directly after 4.0 is released
- label='topic.list.branches')
+ fm.write(b'branches+', b'on branch: %s',
+ b'+'.join(data.branches), # XXX use list directly after 4.0 is released
+ label=b'topic.list.branches')
- fm.plain(', ')
- fm.write('changesetcount', '%d changesets', data.changesetcount,
- label='topic.list.changesetcount')
+ fm.plain(b', ')
+ fm.write(b'changesetcount', b'%d changesets', data.changesetcount,
+ label=b'topic.list.changesetcount')
if data.unstablecount:
- fm.plain(', ')
- fm.write('unstablecount', '%d unstable',
+ fm.plain(b', ')
+ fm.write(b'unstablecount', b'%d unstable',
data.unstablecount,
- label='topic.list.unstablecount')
+ label=b'topic.list.unstablecount')
headcount = len(data.heads)
if 1 < headcount:
- fm.plain(', ')
- fm.write('headcount', '%d heads',
+ fm.plain(b', ')
+ fm.write(b'headcount', b'%d heads',
headcount,
- label='topic.list.headcount.multiple')
+ label=b'topic.list.headcount.multiple')
if ui.verbose:
# XXX we should include the data even when not verbose
behindcount = data.behindcount
if 0 < behindcount:
- fm.plain(', ')
- fm.write('behindcount', '%d behind',
+ fm.plain(b', ')
+ fm.write(b'behindcount', b'%d behind',
behindcount,
- label='topic.list.behindcount')
+ label=b'topic.list.behindcount')
elif -1 == behindcount:
- fm.plain(', ')
- fm.write('behinderror', '%s',
- _('ambiguous destination: %s') % data.behinderror,
- label='topic.list.behinderror')
- fm.plain(')\n')
+ fm.plain(b', ')
+ fm.write(b'behinderror', b'%s',
+ _(b'ambiguous destination: %s') % data.behinderror,
+ label=b'topic.list.behinderror')
+ fm.plain(b')\n')
fm.end()
def _getlasttouched(repo, topics):
@@ -1102,7 +1102,7 @@
age = -1
user = None
maxtime = (0, 0)
- trevs = repo.revs("topic(%s)", topic)
+ trevs = repo.revs(b"topic(%s)", topic)
# Need to check for the time of all changesets in the topic, whether
# they are obsolete of non-heads
# XXX: can we just rely on the max rev number for this
@@ -1119,7 +1119,7 @@
for marker in obsmarkers:
rt = marker.date()
if rt[0] > maxtime[0]:
- user = marker.metadata().get('user', user)
+ user = marker.metadata().get(b'user', user)
maxtime = rt
username = stack.parseusername(user)
@@ -1129,31 +1129,31 @@
yield (age, topic, maxtime, username)
def summaryhook(ui, repo):
- t = getattr(repo, 'currenttopic', '')
+ t = getattr(repo, 'currenttopic', b'')
if not t:
return
# i18n: column positioning for "hg summary"
- ui.write(_("topic: %s\n") % ui.label(t, 'topic.active'))
+ ui.write(_(b"topic: %s\n") % ui.label(t, b'topic.active'))
_validmode = [
- 'ignore',
- 'warning',
- 'enforce',
- 'enforce-all',
- 'random',
- 'random-all',
+ b'ignore',
+ b'warning',
+ b'enforce',
+ b'enforce-all',
+ b'random',
+ b'random-all',
]
def _configtopicmode(ui):
""" Parse the config to get the topicmode
"""
- topicmode = ui.config('experimental', 'topic-mode')
+ topicmode = ui.config(b'experimental', b'topic-mode')
# Fallback to read enforce-topic
if topicmode is None:
- enforcetopic = ui.configbool('experimental', 'enforce-topic')
+ enforcetopic = ui.configbool(b'experimental', b'enforce-topic')
if enforcetopic:
- topicmode = "enforce"
+ topicmode = b"enforce"
if topicmode not in _validmode:
topicmode = _validmode[0]
@@ -1167,37 +1167,37 @@
ismergecommit = len(repo[None].parents()) == 2
notopic = not repo.currenttopic
- mayabort = (topicmode == "enforce" and not ismergecommit)
- maywarn = (topicmode == "warning"
- or (topicmode == "enforce" and ismergecommit))
+ mayabort = (topicmode == b"enforce" and not ismergecommit)
+ maywarn = (topicmode == b"warning"
+ or (topicmode == b"enforce" and ismergecommit))
mayrandom = False
- if topicmode == "random":
+ if topicmode == b"random":
mayrandom = not ismergecommit
- elif topicmode == "random-all":
+ elif topicmode == b"random-all":
mayrandom = True
- if topicmode == 'enforce-all':
+ if topicmode == b'enforce-all':
ismergecommit = False
mayabort = True
maywarn = False
- hint = _("see 'hg help -e topic.topic-mode' for details")
+ hint = _(b"see 'hg help -e topic.topic-mode' for details")
if opts.get('topic'):
t = opts['topic']
- with repo.vfs.open('topic', 'w') as f:
+ with repo.vfs.open(b'topic', b'w') as f:
f.write(t)
elif opts.get('amend'):
pass
elif notopic and mayabort:
- msg = _("no active topic")
+ msg = _(b"no active topic")
raise error.Abort(msg, hint=hint)
elif notopic and maywarn:
- ui.warn(_("warning: new draft commit without topic\n"))
+ ui.warn(_(b"warning: new draft commit without topic\n"))
if not ui.quiet:
- ui.warn(("(%s)\n") % hint)
+ ui.warn((b"(%s)\n") % hint)
elif notopic and mayrandom:
- with repo.vfs.open('topic', 'w') as f:
+ with repo.vfs.open(b'topic', b'w') as f:
f.write(randomname.randomtopicname(ui))
return orig(ui, repo, *args, **opts)
@@ -1206,13 +1206,13 @@
if hastopicext(repo):
t = repo.currenttopic
if t:
- ret = ret.replace("\nHG: branch",
- "\nHG: topic '%s'\nHG: branch" % t)
+ ret = ret.replace(b"\nHG: branch",
+ b"\nHG: topic '%s'\nHG: branch" % t)
return ret
def pushoutgoingwrap(orig, ui, repo, *args, **opts):
if opts.get('topic'):
- topicrevs = repo.revs('topic(%s) - obsolete()', opts['topic'])
+ topicrevs = repo.revs(b'topic(%s) - obsolete()', opts['topic'])
opts.setdefault('rev', []).extend(topicrevs)
return orig(ui, repo, *args, **opts)
@@ -1232,37 +1232,37 @@
# rebased commit. We have explicitly stored in config if rebase is
# running.
ot = repo.currenttopic
- if repo.ui.hasconfig('experimental', 'topicrebase'):
+ if repo.ui.hasconfig(b'experimental', b'topicrebase'):
isrebase = True
- if repo.ui.configbool('_internal', 'keep-topic'):
+ if repo.ui.configbool(b'_internal', b'keep-topic'):
ist0 = True
if ((not partial and not branchmerge) or isrebase) and not ist0:
- t = ''
+ t = b''
pctx = repo[node]
if pctx.phase() > phases.public:
t = pctx.topic()
- with repo.vfs.open('topic', 'w') as f:
+ with repo.vfs.open(b'topic', b'w') as f:
f.write(t)
if t and t != ot:
- repo.ui.status(_("switching to topic %s\n") % t)
+ repo.ui.status(_(b"switching to topic %s\n") % t)
if ot and not t:
st = stack.stack(repo, topic=ot)
if not st:
- repo.ui.status(_('clearing empty topic "%s"\n') % ot)
+ repo.ui.status(_(b'clearing empty topic "%s"\n') % ot)
elif ist0:
- repo.ui.status(_("preserving the current topic '%s'\n") % ot)
+ repo.ui.status(_(b"preserving the current topic '%s'\n") % ot)
return ret
finally:
wlock.release()
def checkt0(orig, ui, repo, node=None, rev=None, *args, **kwargs):
- thezeros = set(['t0', 'b0', 's0'])
- backup = repo.ui.backupconfig('_internal', 'keep-topic')
+ thezeros = set([b't0', b'b0', b's0'])
+ backup = repo.ui.backupconfig(b'_internal', b'keep-topic')
try:
if node in thezeros or rev in thezeros:
- repo.ui.setconfig('_internal', 'keep-topic', 'yes',
- source='topic-extension')
+ repo.ui.setconfig(b'_internal', b'keep-topic', b'yes',
+ source=b'topic-extension')
return orig(ui, repo, node=node, rev=rev, *args, **kwargs)
finally:
repo.ui.restoreconfig(backup)
@@ -1276,8 +1276,8 @@
extra[constants.extrakey] = ctx.topic()
def setrebaseconfig(orig, ui, repo, **opts):
- repo.ui.setconfig('experimental', 'topicrebase', 'yes',
- source='topic-extension')
+ repo.ui.setconfig(b'experimental', b'topicrebase', b'yes',
+ source=b'topic-extension')
return orig(ui, repo, **opts)
def new_init(orig, *args, **kwargs):
@@ -1289,12 +1289,12 @@
return runtime
try:
- rebase = extensions.find("rebase")
+ rebase = extensions.find(b"rebase")
extensions.wrapfunction(rebase.rebaseruntime, '__init__', new_init)
# This exists to store in the config that rebase is running so that we can
# update the topic according to rebase. This is a hack and should be removed
# when we have better options.
- extensions.wrapcommand(rebase.cmdtable, 'rebase', setrebaseconfig)
+ extensions.wrapcommand(rebase.cmdtable, b'rebase', setrebaseconfig)
except KeyError:
pass
@@ -1303,20 +1303,20 @@
def _exporttopic(seq, ctx):
topic = ctx.topic()
if topic:
- return 'EXP-Topic %s' % topic
+ return b'EXP-Topic %s' % topic
return None
def _importtopic(repo, patchdata, extra, opts):
- if 'topic' in patchdata:
- extra['topic'] = patchdata['topic']
+ if b'topic' in patchdata:
+ extra[b'topic'] = patchdata[b'topic']
def setupimportexport(ui):
"""run at ui setup time to install import/export logic"""
- cmdutil.extraexport.append('topic')
- cmdutil.extraexportmap['topic'] = _exporttopic
- cmdutil.extrapreimport.append('topic')
- cmdutil.extrapreimportmap['topic'] = _importtopic
- patch.patchheadermap.append(('EXP-Topic', 'topic'))
+ cmdutil.extraexport.append(b'topic')
+ cmdutil.extraexportmap[b'topic'] = _exporttopic
+ cmdutil.extrapreimport.append(b'topic')
+ cmdutil.extrapreimportmap[b'topic'] = _importtopic
+ patch.patchheadermap.append((b'EXP-Topic', b'topic'))
## preserve topic during split
--- a/hgext3rd/topic/compat.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/compat.py Fri Sep 27 13:03:14 2019 +0200
@@ -30,5 +30,7 @@
def branchmapitems(branchmap):
return branchmap.items()
else:
+ # py3-transform: off
def branchmapitems(branchmap):
return branchmap.iteritems()
+ # py3-transform: on
--- a/hgext3rd/topic/constants.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/constants.py Fri Sep 27 13:03:14 2019 +0200
@@ -1,2 +1,2 @@
-extrakey = 'topic'
-changekey = '_rewrite_noise'
+extrakey = b'topic'
+changekey = b'_rewrite_noise'
--- a/hgext3rd/topic/destination.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/destination.py Fri Sep 27 13:03:14 2019 +0200
@@ -13,11 +13,11 @@
)
from .evolvebits import builddependencies
-def _destmergebranch(orig, repo, action='merge', sourceset=None,
+def _destmergebranch(orig, repo, action=b'merge', sourceset=None,
onheadcheck=True, destspace=None):
# XXX: take destspace into account
if sourceset is None:
- p1 = repo['.']
+ p1 = repo[b'.']
else:
# XXX: using only the max here is flacky. That code should eventually
# be updated to take care of the whole sourceset.
@@ -26,11 +26,11 @@
if common.hastopicext(repo):
top = p1.topic()
if top:
- revs = repo.revs('topic(%s) - obsolete()', top)
+ revs = repo.revs(b'topic(%s) - obsolete()', top)
deps, rdeps = builddependencies(repo, revs)
heads = [r for r in revs if not rdeps[r]]
if onheadcheck and p1.rev() not in heads:
- raise error.Abort(_("not at topic head, update or explicit"))
+ raise error.Abort(_(b"not at topic head, update or explicit"))
# prune heads above the source
otherheads = set(heads)
@@ -43,20 +43,20 @@
# nothing to do at the topic level
bhead = ngtip(repo, p1.branch(), all=True)
if not bhead:
- raise error.NoMergeDestAbort(_("nothing to merge"))
+ raise error.NoMergeDestAbort(_(b"nothing to merge"))
elif 1 == len(bhead):
return bhead[0]
else:
- msg = _("branch '%s' has %d heads "
- "- please merge with an explicit rev")
- hint = _("run 'hg heads .' to see heads")
+ msg = _(b"branch '%s' has %d heads "
+ b"- please merge with an explicit rev")
+ hint = _(b"run 'hg heads .' to see heads")
raise error.ManyMergeDestAbort(msg % (p1.branch(), len(bhead)),
hint=hint)
elif len(otherheads) == 1:
return otherheads.pop()
else:
- msg = _("topic '%s' has %d heads "
- "- please merge with an explicit rev") % (top, len(heads))
+ msg = _(b"topic '%s' has %d heads "
+ b"- please merge with an explicit rev") % (top, len(heads))
raise error.ManyMergeDestAbort(msg)
return orig(repo, action, sourceset, onheadcheck, destspace=destspace)
@@ -67,23 +67,23 @@
movemark = node = None
topic = repo.currenttopic
if topic:
- revs = repo.revs('.::topic(%s)', topic)
+ revs = repo.revs(b'.::topic(%s)', topic)
else:
revs = []
if not revs:
return None, None, None
node = revs.last()
if bookmarks.isactivewdirparent(repo):
- movemark = repo['.'].node()
+ movemark = repo[b'.'].node()
return node, movemark, None
def desthistedit(orig, ui, repo):
if not common.hastopicext(repo):
return None
- if not (ui.config('histedit', 'defaultrev', None) is None
+ if not (ui.config(b'histedit', b'defaultrev', None) is None
and repo.currenttopic):
return orig(ui, repo)
- revs = repo.revs('::. and stack()')
+ revs = repo.revs(b'::. and stack()')
if revs:
return revs.min()
return None
@@ -107,7 +107,7 @@
def modsetup(ui):
"""run a uisetup time to install all destinations wrapping"""
extensions.wrapfunction(destutil, '_destmergebranch', _destmergebranch)
- bridx = destutil.destupdatesteps.index('branch')
- destutil.destupdatesteps.insert(bridx, 'topic')
- destutil.destupdatestepmap['topic'] = _destupdatetopic
+ bridx = destutil.destupdatesteps.index(b'branch')
+ destutil.destupdatesteps.insert(bridx, b'topic')
+ destutil.destupdatestepmap[b'topic'] = _destupdatetopic
extensions.wrapfunction(destutil, 'desthistedit', desthistedit)
--- a/hgext3rd/topic/discovery.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/discovery.py Fri Sep 27 13:03:14 2019 +0200
@@ -28,12 +28,12 @@
repo = pushop.repo.unfiltered()
remote = pushop.remote
- publishing = ('phases' not in remote.listkeys('namespaces')
- or bool(remote.listkeys('phases').get('publishing', False)))
+ publishing = (b'phases' not in remote.listkeys(b'namespaces')
+ or bool(remote.listkeys(b'phases').get(b'publishing', False)))
if not common.hastopicext(pushop.repo):
return orig(pushop, *args, **kwargs)
- elif ((publishing or not remote.capable('topics'))
+ elif ((publishing or not remote.capable(b'topics'))
and not getattr(pushop, 'publish', False)):
return orig(pushop, *args, **kwargs)
@@ -41,7 +41,7 @@
remotebranchmap = None
origremotebranchmap = remote.branchmap
publishednode = [c.node() for c in pushop.outdatedphases]
- publishedset = repo.revs('ancestors(%ln + %ln)',
+ publishedset = repo.revs(b'ancestors(%ln + %ln)',
publishednode,
pushop.remotephases.publicheads)
@@ -51,17 +51,17 @@
# drop topic information from changeset about to be published
result = collections.defaultdict(list)
for branch, heads in compat.branchmapitems(origremotebranchmap()):
- if ':' not in branch:
+ if b':' not in branch:
result[branch].extend(heads)
else:
- namedbranch = branch.split(':', 1)[0]
+ namedbranch = branch.split(b':', 1)[0]
for h in heads:
r = rev(h)
if r is not None and r in publishedset:
result[namedbranch].append(h)
else:
result[branch].append(h)
- for heads in result.itervalues():
+ for heads in result.values():
heads.sort()
return result
@@ -78,7 +78,7 @@
return branch
topic = ctx.topic()
if topic:
- branch = "%s:%s" % (branch, topic)
+ branch = b"%s:%s" % (branch, topic)
return branch
ctx.branch = branch
@@ -96,7 +96,7 @@
return branch, close
topic = repo[rev].topic()
if topic:
- branch = "%s:%s" % (branch, topic)
+ branch = b"%s:%s" % (branch, topic)
return branch, close
rbc.branchinfo = branchinfo
@@ -107,17 +107,17 @@
repo.__class__ = repocls
if remotebranchmap is not None:
remote.branchmap = remotebranchmap
- unxx = repo.filtered('unfiltered-topic')
+ unxx = repo.filtered(b'unfiltered-topic')
repo.unfiltered = lambda: unxx
pushop.repo = repo
summary = orig(pushop)
for key, value in summary.items():
- if ':' in key: # This is a topic
+ if b':' in key: # This is a topic
if value[0] is None and value[1]:
summary[key] = ([value[1][0]], ) + value[1:]
return summary
finally:
- if 'unfiltered' in vars(repo):
+ if r'unfiltered' in vars(repo):
del repo.unfiltered
repo.__class__ = oldrepocls
if remotebranchmap is not None:
@@ -147,7 +147,7 @@
def _nbheads(repo):
data = {}
for b in repo.branchmap().iterbranches():
- if ':' in b[0]:
+ if b':' in b[0]:
continue
data[b[0]] = len(b[1])
return data
@@ -158,7 +158,7 @@
if not common.hastopicext(op.repo) or op.repo.publishing():
return
tr = op.gettransaction()
- if tr.hookargs['source'] not in ('push', 'serve'): # not a push
+ if tr.hookargs[b'source'] not in (b'push', b'serve'): # not a push
return
tr._prepushheads = _nbheads(op.repo)
reporef = weakref.ref(op.repo)
@@ -175,11 +175,11 @@
for branch, oldnb in tr._prepushheads.items():
newnb = finalheads.pop(branch, 0)
if oldnb < newnb:
- msg = _('push create a new head on branch "%s"' % branch)
+ msg = _(b'push create a new head on branch "%s"' % branch)
raise error.Abort(msg)
for branch, newnb in finalheads.items():
if 1 < newnb:
- msg = _('push create more than 1 head on new branch "%s"'
+ msg = _(b'push create more than 1 head on new branch "%s"'
% branch)
raise error.Abort(msg)
return oldvalidator(tr)
@@ -191,7 +191,7 @@
def _pushb2phases(orig, pushop, bundler):
if common.hastopicext(pushop.repo):
- checktypes = ('check:heads', 'check:updated-heads')
+ checktypes = (b'check:heads', b'check:updated-heads')
hascheck = any(p.type in checktypes for p in bundler._parts)
if not hascheck and pushop.outdatedphases:
exchange._pushb2ctxcheckheads(pushop, bundler)
@@ -199,8 +199,8 @@
def wireprotocaps(orig, repo, proto):
caps = orig(repo, proto)
- if common.hastopicext(repo) and repo.peer().capable('topics'):
- caps.append('topics')
+ if common.hastopicext(repo) and repo.peer().capable(b'topics'):
+ caps.append(b'topics')
return caps
def modsetup(ui):
@@ -211,11 +211,11 @@
# we need a proper wrap b2 part stuff
extensions.wrapfunction(bundle2, 'handlecheckheads', handlecheckheads)
bundle2.handlecheckheads.params = frozenset()
- bundle2.parthandlermapping['check:heads'] = bundle2.handlecheckheads
+ bundle2.parthandlermapping[b'check:heads'] = bundle2.handlecheckheads
if util.safehasattr(bundle2, 'handlecheckupdatedheads'):
# we still need a proper wrap b2 part stuff
extensions.wrapfunction(bundle2, 'handlecheckupdatedheads', handlecheckheads)
bundle2.handlecheckupdatedheads.params = frozenset()
- bundle2.parthandlermapping['check:updated-heads'] = bundle2.handlecheckupdatedheads
+ bundle2.parthandlermapping[b'check:updated-heads'] = bundle2.handlecheckupdatedheads
extensions.wrapfunction(exchange, '_pushb2phases', _pushb2phases)
- exchange.b2partsgenmapping['phase'] = exchange._pushb2phases
+ exchange.b2partsgenmapping[b'phase'] = exchange._pushb2phases
--- a/hgext3rd/topic/evolvebits.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/evolvebits.py Fri Sep 27 13:03:14 2019 +0200
@@ -78,8 +78,8 @@
newer = obsutil.successorssets(repo, obs.node())
# search of a parent which is not killed
while not newer:
- ui.debug("stabilize target %s is plain dead,"
- " trying to stabilize on its parent\n" %
+ ui.debug(b"stabilize target %s is plain dead,"
+ b" trying to stabilize on its parent\n" %
obs)
obs = obs.parents()[0]
newer = obsutil.successorssets(repo, obs.node())
@@ -88,7 +88,7 @@
# we should pick as arbitrary one
raise MultipleSuccessorsError(newer)
elif 1 < len(newer[0]):
- splitheads = list(repo.revs('heads(%ln::%ln)', newer[0], newer[0]))
+ splitheads = list(repo.revs(b'heads(%ln::%ln)', newer[0], newer[0]))
if 1 < len(splitheads):
# split case, See if we can make sense of it.
raise MultipleSuccessorsError(newer)
--- a/hgext3rd/topic/flow.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/flow.py Fri Sep 27 13:03:14 2019 +0200
@@ -16,19 +16,19 @@
)
def enforcesinglehead(repo, tr):
- branchmap = repo.filtered('visible').branchmap()
+ branchmap = repo.filtered(b'visible').branchmap()
for name, heads in compat.branchmapitems(branchmap):
if len(heads) > 1:
hexs = [node.short(n) for n in heads]
- raise error.Abort(_('%d heads on "%s"') % (len(heads), name),
- hint=(', '.join(hexs)))
+ raise error.Abort(_(b'%d heads on "%s"') % (len(heads), name),
+ hint=(b', '.join(hexs)))
def publishbarebranch(repo, tr):
"""Publish changeset without topic"""
- if 'node' not in tr.hookargs: # no new node
+ if b'node' not in tr.hookargs: # no new node
return
- startnode = node.bin(tr.hookargs['node'])
- topublish = repo.revs('not public() and (%n:) - hidden() - topic()', startnode)
+ startnode = node.bin(tr.hookargs[b'node'])
+ topublish = repo.revs(b'not public() and (%n:) - hidden() - topic()', startnode)
if topublish:
cl = repo.changelog
nodes = [cl.node(r) for r in topublish]
@@ -36,41 +36,41 @@
def rejectuntopicedchangeset(repo, tr):
"""Reject the push if there are changeset without topic"""
- if 'node' not in tr.hookargs: # no new revs
+ if b'node' not in tr.hookargs: # no new revs
return
- startnode = node.bin(tr.hookargs['node'])
+ startnode = node.bin(tr.hookargs[b'node'])
- mode = repo.ui.config('experimental', 'topic-mode.server', 'ignore')
+ mode = repo.ui.config(b'experimental', b'topic-mode.server', b'ignore')
- untopiced = repo.revs('not public() and (%n:) - hidden() - topic()', startnode)
+ untopiced = repo.revs(b'not public() and (%n:) - hidden() - topic()', startnode)
if untopiced:
num = len(untopiced)
fnode = repo[untopiced.first()].hex()[:10]
if num == 1:
- msg = _("%s") % fnode
+ msg = _(b"%s") % fnode
else:
- msg = _("%s and %d more") % (fnode, num - 1)
- if mode == 'warning':
- fullmsg = _("pushed draft changeset without topic: %s\n")
+ msg = _(b"%s and %d more") % (fnode, num - 1)
+ if mode == b'warning':
+ fullmsg = _(b"pushed draft changeset without topic: %s\n")
repo.ui.warn(fullmsg % msg)
- elif mode == 'enforce':
- fullmsg = _("rejecting draft changesets: %s")
+ elif mode == b'enforce':
+ fullmsg = _(b"rejecting draft changesets: %s")
raise error.Abort(fullmsg % msg)
else:
- repo.ui.warn(_("unknown 'topic-mode.server': %s\n" % mode))
+ repo.ui.warn(_(b"unknown 'topic-mode.server': %s\n" % mode))
def reject_publish(repo, tr):
"""prevent a transaction to be publish anything"""
published = set()
- for r, (o, n) in tr.changes['phases'].items():
+ for r, (o, n) in tr.changes[b'phases'].items():
if n == phases.public:
published.add(r)
if published:
r = min(published)
- msg = "rejecting publishing of changeset %s" % repo[r]
+ msg = b"rejecting publishing of changeset %s" % repo[r]
if len(published) > 1:
- msg += ' and %d others' % (len(published) - 1)
+ msg += b' and %d others' % (len(published) - 1)
raise error.Abort(msg)
def wrappush(orig, repo, remote, *args, **kwargs):
@@ -80,8 +80,8 @@
opargs = kwargs.get('opargs')
if opargs is None:
opargs = {}
- newargs['opargs'] = opargs.copy()
- newargs['opargs']['publish'] = True
+ newargs[r'opargs'] = opargs.copy()
+ newargs[r'opargs'][b'publish'] = True
return orig(repo, remote, *args, **newargs)
def extendpushoperation(orig, self, *args, **kwargs):
@@ -95,16 +95,16 @@
if not pushop.remotephases.publishing:
unfi = pushop.repo.unfiltered()
droots = pushop.remotephases.draftroots
- revset = '%ln and (not public() or %ln::)'
+ revset = b'%ln and (not public() or %ln::)'
future = list(unfi.set(revset, pushop.futureheads, droots))
pushop.outdatedphases = future
def installpushflag(ui):
- entry = extensions.wrapcommand(commands.table, 'push', wrappush)
- if not any(opt for opt in entry[1] if opt[1] == 'publish'): # hg <= 4.9
- entry[1].append(('', 'publish', False,
- _('push the changeset as public')))
+ entry = extensions.wrapcommand(commands.table, b'push', wrappush)
+ if not any(opt for opt in entry[1] if opt[1] == b'publish'): # hg <= 4.9
+ entry[1].append((b'', b'publish', False,
+ _(b'push the changeset as public')))
extensions.wrapfunction(exchange.pushoperation, '__init__',
extendpushoperation)
extensions.wrapfunction(exchange, '_pushdiscoveryphase', wrapphasediscovery)
- exchange.pushdiscoverymapping['phase'] = exchange._pushdiscoveryphase
+ exchange.pushdiscoverymapping[b'phase'] = exchange._pushdiscoveryphase
--- a/hgext3rd/topic/randomname.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/randomname.py Fri Sep 27 13:03:14 2019 +0200
@@ -8,1006 +8,1007 @@
import random
animals = [
- 'aardvark',
- 'albatross',
- 'alligator',
- 'alpaca',
- 'ant',
- 'anteater',
- 'antelope',
- 'ape',
- 'armadillo',
- 'baboon',
- 'badger',
- 'barracuda',
- 'bat',
- 'bear',
- 'beaver',
- 'bee',
- 'beetle',
- 'bison',
- 'boar',
- 'buffalo',
- 'bushbaby',
- 'bustard',
- 'butterfly',
- 'camel',
- 'capuchin',
- 'carabao',
- 'caribou',
- 'cat',
- 'caterpillar',
- 'cattle',
- 'chameleon',
- 'chamois',
- 'cheetah',
- 'chicken',
- 'chimpanzee',
- 'chinchilla',
- 'chipmunk',
- 'chough',
- 'cicada',
- 'clam',
- 'cobra',
- 'cockroach',
- 'cod',
- 'cormorant',
- 'coyote',
- 'crab',
- 'crane',
- 'cricket',
- 'crocodile',
- 'crow',
- 'curlew',
- 'deer',
- 'dinosaur',
- 'dog',
- 'dogfish',
- 'dolphin',
- 'donkey',
- 'dotterel',
- 'dove',
- 'dragon',
- 'dragonfly',
- 'duck',
- 'dugong',
- 'dunlin',
- 'eagle',
- 'echidna',
- 'eel',
- 'eland',
- 'elephant',
- 'elk',
- 'emu',
- 'falcon',
- 'ferret',
- 'finch',
- 'fish',
- 'flamingo',
- 'fly',
- 'fox',
- 'frog',
- 'gaur',
- 'gazelle',
- 'gecko',
- 'gerbil',
- 'giraffe',
- 'gnat',
- 'gnu',
- 'goat',
- 'goldfish',
- 'goose',
- 'gorilla',
- 'goshawk',
- 'grasshopper',
- 'grouse',
- 'guanaco',
- 'guinea',
- 'gull',
- 'hamster',
- 'hare',
- 'hawk',
- 'hedgehog',
- 'heron',
- 'herring',
- 'hippopotamus',
- 'hornet',
- 'horse',
- 'horsecrab',
- 'hound',
- 'hummingbird',
- 'hyena',
- 'hyrax',
- 'ibex',
- 'ibis',
- 'iguana',
- 'impala',
- 'insect',
- 'jackal',
- 'jaguar',
- 'jay',
- 'jellyfish',
- 'kangaroo',
- 'koala',
- 'kouprey',
- 'kudu',
- 'lapwing',
- 'lark',
- 'lemming',
- 'lemur',
- 'leopard',
- 'lion',
- 'lizard',
- 'llama',
- 'lobster',
- 'locust',
- 'loris',
- 'louse',
- 'lynx',
- 'lyrebird',
- 'magpie',
- 'mallard',
- 'mammoth',
- 'manatee',
- 'marten',
- 'meerkat',
- 'mink',
- 'minnow',
- 'mole',
- 'mongoose',
- 'monkey',
- 'moose',
- 'mosquito',
- 'mouse',
- 'mule',
- 'muskrat',
- 'narwhal',
- 'newt',
- 'nightingale',
- 'numbat',
- 'octopus',
- 'okapi',
- 'opossum',
- 'oryx',
- 'ostrich',
- 'otter',
- 'owl',
- 'ox',
- 'oyster',
- 'panda',
- 'panther',
- 'parrot',
- 'partridge',
- 'peacock',
- 'peafowl',
- 'pelican',
- 'penguin',
- 'pheasant',
- 'pig',
- 'pigeon',
- 'platypus',
- 'pony',
- 'porcupine',
- 'porpoise',
- 'puffin',
- 'pug',
- 'quagga',
- 'quail',
- 'quelea',
- 'rabbit',
- 'raccoon',
- 'ram',
- 'rat',
- 'raven',
- 'reindeer',
- 'rhea',
- 'rhinoceros',
- 'rook',
- 'ruff',
- 'salamander',
- 'salmon',
- 'sambar',
- 'sandpiper',
- 'sardine',
- 'scorpion',
- 'seahorse',
- 'seal',
- 'serval',
- 'shark',
- 'sheep',
- 'shrew',
- 'shrimp',
- 'skink',
- 'skunk',
- 'snail',
- 'snake',
- 'spider',
- 'squid',
- 'squirrel',
- 'starling',
- 'stinkbug',
- 'stork',
- 'swan',
- 'tapir',
- 'tarsier',
- 'termite',
- 'tern',
- 'tiger',
- 'toad',
- 'trout',
- 'turkey',
- 'turtle',
- 'unicorn',
- 'viper',
- 'vulture',
- 'wallaby',
- 'walrus',
- 'wasp',
- 'weasel',
- 'whale',
- 'wolf',
- 'wolverine',
- 'wombat',
- 'woodchuck',
- 'woodcock',
- 'woodpecker',
- 'worm',
- 'wren',
- 'yak',
- 'zebra',
- 'zorilla'
+ b'aardvark',
+ b'albatross',
+ b'alligator',
+ b'alpaca',
+ b'ant',
+ b'anteater',
+ b'antelope',
+ b'ape',
+ b'armadillo',
+ b'baboon',
+ b'badger',
+ b'barracuda',
+ b'bat',
+ b'bear',
+ b'beaver',
+ b'bee',
+ b'beetle',
+ b'bison',
+ b'boar',
+ b'buffalo',
+ b'bushbaby',
+ b'bustard',
+ b'butterfly',
+ b'camel',
+ b'capuchin',
+ b'carabao',
+ b'caribou',
+ b'cat',
+ b'caterpillar',
+ b'cattle',
+ b'chameleon',
+ b'chamois',
+ b'cheetah',
+ b'chicken',
+ b'chimpanzee',
+ b'chinchilla',
+ b'chipmunk',
+ b'chough',
+ b'cicada',
+ b'clam',
+ b'cobra',
+ b'cockroach',
+ b'cod',
+ b'cormorant',
+ b'coyote',
+ b'crab',
+ b'crane',
+ b'cricket',
+ b'crocodile',
+ b'crow',
+ b'curlew',
+ b'deer',
+ b'dinosaur',
+ b'dog',
+ b'dogfish',
+ b'dolphin',
+ b'donkey',
+ b'dotterel',
+ b'dove',
+ b'dragon',
+ b'dragonfly',
+ b'duck',
+ b'dugong',
+ b'dunlin',
+ b'eagle',
+ b'echidna',
+ b'eel',
+ b'eland',
+ b'elephant',
+ b'elk',
+ b'emu',
+ b'falcon',
+ b'ferret',
+ b'finch',
+ b'fish',
+ b'flamingo',
+ b'fly',
+ b'fox',
+ b'frog',
+ b'gaur',
+ b'gazelle',
+ b'gecko',
+ b'gerbil',
+ b'giraffe',
+ b'gnat',
+ b'gnu',
+ b'goat',
+ b'goldfish',
+ b'goose',
+ b'gorilla',
+ b'goshawk',
+ b'grasshopper',
+ b'grouse',
+ b'guanaco',
+ b'guinea',
+ b'gull',
+ b'hamster',
+ b'hare',
+ b'hawk',
+ b'hedgehog',
+ b'heron',
+ b'herring',
+ b'hippopotamus',
+ b'hornet',
+ b'horse',
+ b'horsecrab',
+ b'hound',
+ b'hummingbird',
+ b'hyena',
+ b'hyrax',
+ b'ibex',
+ b'ibis',
+ b'iguana',
+ b'impala',
+ b'insect',
+ b'jackal',
+ b'jaguar',
+ b'jay',
+ b'jellyfish',
+ b'kangaroo',
+ b'koala',
+ b'kouprey',
+ b'kudu',
+ b'lapwing',
+ b'lark',
+ b'lemming',
+ b'lemur',
+ b'leopard',
+ b'lion',
+ b'lizard',
+ b'llama',
+ b'lobster',
+ b'locust',
+ b'loris',
+ b'louse',
+ b'lynx',
+ b'lyrebird',
+ b'magpie',
+ b'mallard',
+ b'mammoth',
+ b'manatee',
+ b'marten',
+ b'meerkat',
+ b'mink',
+ b'minnow',
+ b'mole',
+ b'mongoose',
+ b'monkey',
+ b'moose',
+ b'mosquito',
+ b'mouse',
+ b'mule',
+ b'muskrat',
+ b'narwhal',
+ b'newt',
+ b'nightingale',
+ b'numbat',
+ b'octopus',
+ b'okapi',
+ b'opossum',
+ b'oryx',
+ b'ostrich',
+ b'otter',
+ b'owl',
+ b'ox',
+ b'oyster',
+ b'panda',
+ b'panther',
+ b'parrot',
+ b'partridge',
+ b'peacock',
+ b'peafowl',
+ b'pelican',
+ b'penguin',
+ b'pheasant',
+ b'pig',
+ b'pigeon',
+ b'platypus',
+ b'pony',
+ b'porcupine',
+ b'porpoise',
+ b'puffin',
+ b'pug',
+ b'quagga',
+ b'quail',
+ b'quelea',
+ b'rabbit',
+ b'raccoon',
+ b'ram',
+ b'rat',
+ b'raven',
+ b'reindeer',
+ b'rhea',
+ b'rhinoceros',
+ b'rook',
+ b'ruff',
+ b'salamander',
+ b'salmon',
+ b'sambar',
+ b'sandpiper',
+ b'sardine',
+ b'scorpion',
+ b'seahorse',
+ b'seal',
+ b'serval',
+ b'shark',
+ b'sheep',
+ b'shrew',
+ b'shrimp',
+ b'skink',
+ b'skunk',
+ b'snail',
+ b'snake',
+ b'spider',
+ b'squid',
+ b'squirrel',
+ b'starling',
+ b'stinkbug',
+ b'stork',
+ b'swan',
+ b'tapir',
+ b'tarsier',
+ b'termite',
+ b'tern',
+ b'tiger',
+ b'toad',
+ b'trout',
+ b'turkey',
+ b'turtle',
+ b'unicorn',
+ b'viper',
+ b'vulture',
+ b'wallaby',
+ b'walrus',
+ b'wasp',
+ b'weasel',
+ b'whale',
+ b'wolf',
+ b'wolverine',
+ b'wombat',
+ b'woodchuck',
+ b'woodcock',
+ b'woodpecker',
+ b'worm',
+ b'wren',
+ b'yak',
+ b'zebra',
+ b'zorilla'
]
adjectives = [
- 'abiding',
- 'abject',
- 'ablaze',
- 'able',
- 'aboard',
- 'abounding',
- 'absorbed',
- 'absorbing',
- 'abstracted',
- 'abundant',
- 'acceptable',
- 'accessible',
- 'accurate',
- 'acoustic',
- 'adamant',
- 'adaptable',
- 'adhesive',
- 'adjoining',
- 'adorable',
- 'adventurous',
- 'affable',
- 'affectionate',
- 'agreeable',
- 'alert',
- 'alive',
- 'alluring',
- 'amazing',
- 'ambiguous',
- 'ambitious',
- 'amiable',
- 'amicable',
- 'amused',
- 'amusing',
- 'ancient',
- 'animated',
- 'apricot',
- 'aquatic',
- 'arctic',
- 'arenaceous',
- 'aromatic',
- 'aspiring',
- 'assiduous',
- 'assorted',
- 'astonishing',
- 'attractive',
- 'auspicious',
- 'automatic',
- 'available',
- 'average',
- 'awake',
- 'aware',
- 'awesome',
- 'axiomatic',
- 'bashful',
- 'bawdy',
- 'beautiful',
- 'beefy',
- 'befitting',
- 'beneficial',
- 'benevolent',
- 'bent',
- 'best',
- 'better',
- 'bewildered',
- 'bewitching',
- 'big',
- 'billowy',
- 'bizarre',
- 'black',
- 'blithe',
- 'blue',
- 'blushing',
- 'bouncy',
- 'boundless',
- 'brainy',
- 'brash',
- 'brave',
- 'brawny',
- 'brazen',
- 'breezy',
- 'brief',
- 'bright',
- 'brilliant',
- 'broad',
- 'brown',
- 'bucolic',
- 'bulky',
- 'bumpy',
- 'burgundy',
- 'burly',
- 'bustling',
- 'busy',
- 'calm',
- 'capable',
- 'capricious',
- 'captivating',
- 'carefree',
- 'careful',
- 'caring',
- 'carrot',
- 'ceaseless',
- 'cerise',
- 'certain',
- 'challenging',
- 'changeable',
- 'charming',
- 'cheerful',
- 'chief',
- 'chilly',
- 'chipper',
- 'classy',
- 'clean',
- 'clear',
- 'clever',
- 'cloudy',
- 'coherent',
- 'colorful',
- 'colossal',
- 'comfortable',
- 'common',
- 'communicative',
- 'compassionate',
- 'complete',
- 'complex',
- 'compulsive',
- 'confused',
- 'conscientious',
- 'conscious',
- 'conservative',
- 'considerate',
- 'convivial',
- 'cooing',
- 'cool',
- 'cooperative',
- 'coordinated',
- 'courageous',
- 'courteous',
- 'crazy',
- 'creative',
- 'crispy',
- 'crooked',
- 'crowded',
- 'cuddly',
- 'cultured',
- 'cunning',
- 'curious',
- 'curly',
- 'curved',
- 'curvy',
- 'cut',
- 'cute',
- 'daily',
- 'damp',
- 'dapper',
- 'dashing',
- 'dazzling',
- 'dear',
- 'debonair',
- 'decisive',
- 'decorous',
- 'deep',
- 'defiant',
- 'delicate',
- 'delicious',
- 'delighted',
- 'delightful',
- 'delirious',
- 'descriptive',
- 'detached',
- 'detailed',
- 'determined',
- 'different',
- 'diligent',
- 'diminutive',
- 'diplomatic',
- 'discreet',
- 'distinct',
- 'distinctive',
- 'dramatic',
- 'dry',
- 'dynamic',
- 'dynamite',
- 'eager',
- 'early',
- 'earthy',
- 'easy',
- 'easygoing',
- 'eatable',
- 'economic',
- 'ecstatic',
- 'educated',
- 'efficacious',
- 'efficient',
- 'effortless',
- 'eight',
- 'elastic',
- 'elated',
- 'electric',
- 'elegant',
- 'elfin',
- 'elite',
- 'eminent',
- 'emotional',
- 'enchanted',
- 'enchanting',
- 'encouraging',
- 'endless',
- 'energetic',
- 'enormous',
- 'entertaining',
- 'enthusiastic',
- 'envious',
- 'epicurean',
- 'equable',
- 'equal',
- 'eternal',
- 'ethereal',
- 'evanescent',
- 'even',
- 'excellent',
- 'excited',
- 'exciting',
- 'exclusive',
- 'exotic',
- 'expensive',
- 'exquisite',
- 'extroverted',
- 'exuberant',
- 'exultant',
- 'fabulous',
- 'fair',
- 'faithful',
- 'familiar',
- 'famous',
- 'fancy',
- 'fantastic',
- 'far',
- 'fascinated',
- 'fast',
- 'fearless',
- 'female',
- 'fertile',
- 'festive',
- 'few',
- 'fine',
- 'first',
- 'five',
- 'fixed',
- 'flamboyant',
- 'flashy',
- 'flat',
- 'flawless',
- 'flirtatious',
- 'florid',
- 'flowery',
- 'fluffy',
- 'fluttering',
- 'foamy',
- 'foolish',
- 'foregoing',
- 'fortunate',
- 'four',
- 'frank',
- 'free',
- 'frequent',
- 'fresh',
- 'friendly',
- 'full',
- 'functional',
- 'funny',
- 'furry',
- 'future',
- 'futuristic',
- 'fuzzy',
- 'gabby',
- 'gainful',
- 'garrulous',
- 'general',
- 'generous',
- 'gentle',
- 'giant',
- 'giddy',
- 'gifted',
- 'gigantic',
- 'gilded',
- 'glamorous',
- 'gleaming',
- 'glorious',
- 'glossy',
- 'glowing',
- 'godly',
- 'good',
- 'goofy',
- 'gorgeous',
- 'graceful',
- 'grandiose',
- 'grateful',
- 'gratis',
- 'gray',
- 'great',
- 'green',
- 'gregarious',
- 'grey',
- 'groovy',
- 'guiltless',
- 'gusty',
- 'guttural',
- 'habitual',
- 'half',
- 'hallowed',
- 'halting',
- 'handsome',
- 'happy',
- 'hard',
- 'hardworking',
- 'harmonious',
- 'heady',
- 'healthy',
- 'heavenly',
- 'helpful',
- 'hilarious',
- 'historical',
- 'holistic',
- 'hollow',
- 'honest',
- 'honorable',
- 'hopeful',
- 'hospitable',
- 'hot',
- 'huge',
- 'humorous',
- 'hungry',
- 'hushed',
- 'hypnotic',
- 'illustrious',
- 'imaginary',
- 'imaginative',
- 'immense',
- 'imminent',
- 'impartial',
- 'important',
- 'imported',
- 'impossible',
- 'incandescent',
- 'inconclusive',
- 'incredible',
- 'independent',
- 'industrious',
- 'inexpensive',
- 'innate',
- 'innocent',
- 'inquisitive',
- 'instinctive',
- 'intellectual',
- 'intelligent',
- 'intense',
- 'interesting',
- 'internal',
- 'intuitive',
- 'inventive',
- 'invincible',
- 'jazzy',
- 'jolly',
- 'joyful',
- 'joyous',
- 'judicious',
- 'juicy',
- 'jumpy',
- 'keen',
- 'kind',
- 'kindhearted',
- 'kindly',
- 'knotty',
- 'knowing',
- 'knowledgeable',
- 'known',
- 'laconic',
- 'large',
- 'lavish',
- 'lean',
- 'learned',
- 'left',
- 'legal',
- 'level',
- 'light',
- 'likeable',
- 'literate',
- 'little',
- 'lively',
- 'living',
- 'long',
- 'longing',
- 'loud',
- 'lovely',
- 'loving',
- 'loyal',
- 'lucky',
- 'luminous',
- 'lush',
- 'luxuriant',
- 'luxurious',
- 'lyrical',
- 'magenta',
- 'magical',
- 'magnificent',
- 'majestic',
- 'male',
- 'mammoth',
- 'many',
- 'marvelous',
- 'massive',
- 'material',
- 'mature',
- 'meandering',
- 'meaty',
- 'medical',
- 'mellow',
- 'melodic',
- 'melted',
- 'merciful',
- 'mighty',
- 'miniature',
- 'miniscule',
- 'minor',
- 'minute',
- 'misty',
- 'modern',
- 'modest',
- 'momentous',
- 'motionless',
- 'mountainous',
- 'mute',
- 'mysterious',
- 'narrow',
- 'natural',
- 'near',
- 'neat',
- 'nebulous',
- 'necessary',
- 'neighborly',
- 'new',
- 'next',
- 'nice',
- 'nifty',
- 'nimble',
- 'nine',
- 'nippy',
- 'noiseless',
- 'noisy',
- 'nonchalant',
- 'normal',
- 'numberless',
- 'numerous',
- 'nutritious',
- 'obedient',
- 'observant',
- 'obtainable',
- 'oceanic',
- 'omniscient',
- 'one',
- 'open',
- 'opposite',
- 'optimal',
- 'optimistic',
- 'opulent',
- 'orange',
- 'ordinary',
- 'organic',
- 'outgoing',
- 'outrageous',
- 'outstanding',
- 'oval',
- 'overjoyed',
- 'overt',
- 'palatial',
- 'panoramic',
- 'parallel',
- 'passionate',
- 'past',
- 'pastoral',
- 'patient',
- 'peaceful',
- 'perfect',
- 'periodic',
- 'permissible',
- 'perpetual',
- 'persistent',
- 'petite',
- 'philosophical',
- 'physical',
- 'picturesque',
- 'pink',
- 'pioneering',
- 'piquant',
- 'plausible',
- 'pleasant',
- 'plucky',
- 'poised',
- 'polite',
- 'possible',
- 'powerful',
- 'practical',
- 'precious',
- 'premium',
- 'present',
- 'pretty',
- 'previous',
- 'private',
- 'probable',
- 'productive',
- 'profound',
- 'profuse',
- 'protective',
- 'proud',
- 'psychedelic',
- 'public',
- 'pumped',
- 'purple',
- 'purring',
- 'puzzled',
- 'puzzling',
- 'quaint',
- 'quick',
- 'quicker',
- 'quickest',
- 'quiet',
- 'quirky',
- 'quixotic',
- 'quizzical',
- 'rainy',
- 'rapid',
- 'rare',
- 'rational',
- 'ready',
- 'real',
- 'rebel',
- 'receptive',
- 'red',
- 'reflective',
- 'regular',
- 'relaxed',
- 'reliable',
- 'relieved',
- 'remarkable',
- 'reminiscent',
- 'reserved',
- 'resolute',
- 'resonant',
- 'resourceful',
- 'responsible',
- 'rich',
- 'ridiculous',
- 'right',
- 'rightful',
- 'ripe',
- 'ritzy',
- 'roasted',
- 'robust',
- 'romantic',
- 'roomy',
- 'round',
- 'royal',
- 'ruddy',
- 'rural',
- 'rustic',
- 'sable',
- 'safe',
- 'salty',
- 'same',
- 'satisfying',
- 'savory',
- 'scientific',
- 'scintillating',
- 'scrumptious',
- 'second',
- 'secret',
- 'secretive',
- 'seemly',
- 'selective',
- 'sensible',
- 'separate',
- 'shaggy',
- 'shaky',
- 'shining',
- 'shiny',
- 'short',
- 'shy',
- 'silent',
- 'silky',
- 'silly',
- 'simple',
- 'simplistic',
- 'sincere',
- 'six',
- 'sizzling',
- 'skillful',
- 'sleepy',
- 'slick',
- 'slim',
- 'smart',
- 'smiling',
- 'smooth',
- 'soaring',
- 'sociable',
- 'soft',
- 'solid',
- 'sophisticated',
- 'sparkling',
- 'special',
- 'spectacular',
- 'speedy',
- 'spicy',
- 'spiffy',
- 'spiritual',
- 'splendid',
- 'spooky',
- 'spotless',
- 'spotted',
- 'square',
- 'standing',
- 'statuesque',
- 'steadfast',
- 'steady',
- 'steep',
- 'stimulating',
- 'straight',
- 'straightforward',
- 'striking',
- 'striped',
- 'strong',
- 'stunning',
- 'stupendous',
- 'sturdy',
- 'subsequent',
- 'substantial',
- 'subtle',
- 'successful',
- 'succinct',
- 'sudden',
- 'super',
- 'superb',
- 'supreme',
- 'swanky',
- 'sweet',
- 'swift',
- 'sympathetic',
- 'synonymous',
- 'talented',
- 'tall',
- 'tame',
- 'tan',
- 'tangible',
- 'tangy',
- 'tasteful',
- 'tasty',
- 'telling',
- 'temporary',
- 'tempting',
- 'ten',
- 'tender',
- 'terrific',
- 'tested',
- 'thankful',
- 'therapeutic',
- 'thin',
- 'thinkable',
- 'third',
- 'thoughtful',
- 'three',
- 'thrifty',
- 'tidy',
- 'tiny',
- 'toothsome',
- 'towering',
- 'tranquil',
- 'tremendous',
- 'tricky',
- 'true',
- 'truthful',
- 'two',
- 'typical',
- 'ubiquitous',
- 'ultra',
- 'unassuming',
- 'unbiased',
- 'uncovered',
- 'understanding',
- 'understood',
- 'unequaled',
- 'unique',
- 'unusual',
- 'unwritten',
- 'upbeat',
- 'useful',
- 'utopian',
- 'utter',
- 'uttermost',
- 'valuable',
- 'various',
- 'vast',
- 'verdant',
- 'vermilion',
- 'versatile',
- 'versed',
- 'victorious',
- 'vigorous',
- 'violet',
- 'vivacious',
- 'voiceless',
- 'voluptuous',
- 'wacky',
- 'waiting',
- 'wakeful',
- 'wandering',
- 'warm',
- 'warmhearted',
- 'wealthy',
- 'whimsical',
- 'whispering',
- 'white',
- 'whole',
- 'wholesale',
- 'whopping',
- 'wide',
- 'wiggly',
- 'wild',
- 'willing',
- 'windy',
- 'winsome',
- 'wiry',
- 'wise',
- 'wistful',
- 'witty',
- 'womanly',
- 'wonderful',
- 'workable',
- 'young',
- 'youthful',
- 'yummy',
- 'zany',
- 'zealous',
- 'zesty',
- 'zippy'
+ b'abiding',
+ b'abject',
+ b'ablaze',
+ b'able',
+ b'aboard',
+ b'abounding',
+ b'absorbed',
+ b'absorbing',
+ b'abstracted',
+ b'abundant',
+ b'acceptable',
+ b'accessible',
+ b'accurate',
+ b'acoustic',
+ b'adamant',
+ b'adaptable',
+ b'adhesive',
+ b'adjoining',
+ b'adorable',
+ b'adventurous',
+ b'affable',
+ b'affectionate',
+ b'agreeable',
+ b'alert',
+ b'alive',
+ b'alluring',
+ b'amazing',
+ b'ambiguous',
+ b'ambitious',
+ b'amiable',
+ b'amicable',
+ b'amused',
+ b'amusing',
+ b'ancient',
+ b'animated',
+ b'apricot',
+ b'appropriate',
+ b'aquatic',
+ b'arctic',
+ b'arenaceous',
+ b'aromatic',
+ b'aspiring',
+ b'assiduous',
+ b'assorted',
+ b'astonishing',
+ b'attractive',
+ b'auspicious',
+ b'automatic',
+ b'available',
+ b'average',
+ b'awake',
+ b'aware',
+ b'awesome',
+ b'axiomatic',
+ b'bashful',
+ b'bawdy',
+ b'beautiful',
+ b'beefy',
+ b'befitting',
+ b'beneficial',
+ b'benevolent',
+ b'bent',
+ b'best',
+ b'better',
+ b'bewildered',
+ b'bewitching',
+ b'big',
+ b'billowy',
+ b'bizarre',
+ b'black',
+ b'blithe',
+ b'blue',
+ b'blushing',
+ b'bouncy',
+ b'boundless',
+ b'brainy',
+ b'brash',
+ b'brave',
+ b'brawny',
+ b'brazen',
+ b'breezy',
+ b'brief',
+ b'bright',
+ b'brilliant',
+ b'broad',
+ b'brown',
+ b'bucolic',
+ b'bulky',
+ b'bumpy',
+ b'burgundy',
+ b'burly',
+ b'bustling',
+ b'busy',
+ b'calm',
+ b'capable',
+ b'capricious',
+ b'captivating',
+ b'carefree',
+ b'careful',
+ b'caring',
+ b'carrot',
+ b'ceaseless',
+ b'cerise',
+ b'certain',
+ b'challenging',
+ b'changeable',
+ b'charming',
+ b'cheerful',
+ b'chief',
+ b'chilly',
+ b'chipper',
+ b'classy',
+ b'clean',
+ b'clear',
+ b'clever',
+ b'cloudy',
+ b'coherent',
+ b'colorful',
+ b'colossal',
+ b'comfortable',
+ b'common',
+ b'communicative',
+ b'compassionate',
+ b'complete',
+ b'complex',
+ b'compulsive',
+ b'confused',
+ b'conscientious',
+ b'conscious',
+ b'conservative',
+ b'considerate',
+ b'convivial',
+ b'cooing',
+ b'cool',
+ b'cooperative',
+ b'coordinated',
+ b'courageous',
+ b'courteous',
+ b'crazy',
+ b'creative',
+ b'crispy',
+ b'crooked',
+ b'crowded',
+ b'cuddly',
+ b'cultured',
+ b'cunning',
+ b'curious',
+ b'curly',
+ b'curved',
+ b'curvy',
+ b'cut',
+ b'cute',
+ b'daily',
+ b'damp',
+ b'dapper',
+ b'dashing',
+ b'dazzling',
+ b'dear',
+ b'debonair',
+ b'decisive',
+ b'decorous',
+ b'deep',
+ b'defiant',
+ b'delicate',
+ b'delicious',
+ b'delighted',
+ b'delightful',
+ b'delirious',
+ b'descriptive',
+ b'detached',
+ b'detailed',
+ b'determined',
+ b'different',
+ b'diligent',
+ b'diminutive',
+ b'diplomatic',
+ b'discreet',
+ b'distinct',
+ b'distinctive',
+ b'dramatic',
+ b'dry',
+ b'dynamic',
+ b'dynamite',
+ b'eager',
+ b'early',
+ b'earthy',
+ b'easy',
+ b'easygoing',
+ b'eatable',
+ b'economic',
+ b'ecstatic',
+ b'educated',
+ b'efficacious',
+ b'efficient',
+ b'effortless',
+ b'eight',
+ b'elastic',
+ b'elated',
+ b'electric',
+ b'elegant',
+ b'elfin',
+ b'elite',
+ b'eminent',
+ b'emotional',
+ b'enchanted',
+ b'enchanting',
+ b'encouraging',
+ b'endless',
+ b'energetic',
+ b'enormous',
+ b'entertaining',
+ b'enthusiastic',
+ b'envious',
+ b'epicurean',
+ b'equable',
+ b'equal',
+ b'eternal',
+ b'ethereal',
+ b'evanescent',
+ b'even',
+ b'excellent',
+ b'excited',
+ b'exciting',
+ b'exclusive',
+ b'exotic',
+ b'expensive',
+ b'exquisite',
+ b'extroverted',
+ b'exuberant',
+ b'exultant',
+ b'fabulous',
+ b'fair',
+ b'faithful',
+ b'familiar',
+ b'famous',
+ b'fancy',
+ b'fantastic',
+ b'far',
+ b'fascinated',
+ b'fast',
+ b'fearless',
+ b'female',
+ b'fertile',
+ b'festive',
+ b'few',
+ b'fine',
+ b'first',
+ b'five',
+ b'fixed',
+ b'flamboyant',
+ b'flashy',
+ b'flat',
+ b'flawless',
+ b'flirtatious',
+ b'florid',
+ b'flowery',
+ b'fluffy',
+ b'fluttering',
+ b'foamy',
+ b'foolish',
+ b'foregoing',
+ b'fortunate',
+ b'four',
+ b'frank',
+ b'free',
+ b'frequent',
+ b'fresh',
+ b'friendly',
+ b'full',
+ b'functional',
+ b'funny',
+ b'furry',
+ b'future',
+ b'futuristic',
+ b'fuzzy',
+ b'gabby',
+ b'gainful',
+ b'garrulous',
+ b'general',
+ b'generous',
+ b'gentle',
+ b'giant',
+ b'giddy',
+ b'gifted',
+ b'gigantic',
+ b'gilded',
+ b'glamorous',
+ b'gleaming',
+ b'glorious',
+ b'glossy',
+ b'glowing',
+ b'godly',
+ b'good',
+ b'goofy',
+ b'gorgeous',
+ b'graceful',
+ b'grandiose',
+ b'grateful',
+ b'gratis',
+ b'gray',
+ b'great',
+ b'green',
+ b'gregarious',
+ b'grey',
+ b'groovy',
+ b'guiltless',
+ b'gusty',
+ b'guttural',
+ b'habitual',
+ b'half',
+ b'hallowed',
+ b'halting',
+ b'handsome',
+ b'happy',
+ b'hard',
+ b'hardworking',
+ b'harmonious',
+ b'heady',
+ b'healthy',
+ b'heavenly',
+ b'helpful',
+ b'hilarious',
+ b'historical',
+ b'holistic',
+ b'hollow',
+ b'honest',
+ b'honorable',
+ b'hopeful',
+ b'hospitable',
+ b'hot',
+ b'huge',
+ b'humorous',
+ b'hungry',
+ b'hushed',
+ b'hypnotic',
+ b'illustrious',
+ b'imaginary',
+ b'imaginative',
+ b'immense',
+ b'imminent',
+ b'impartial',
+ b'important',
+ b'imported',
+ b'impossible',
+ b'incandescent',
+ b'inconclusive',
+ b'incredible',
+ b'independent',
+ b'industrious',
+ b'inexpensive',
+ b'innate',
+ b'innocent',
+ b'inquisitive',
+ b'instinctive',
+ b'intellectual',
+ b'intelligent',
+ b'intense',
+ b'interesting',
+ b'internal',
+ b'intuitive',
+ b'inventive',
+ b'invincible',
+ b'jazzy',
+ b'jolly',
+ b'joyful',
+ b'joyous',
+ b'judicious',
+ b'juicy',
+ b'jumpy',
+ b'keen',
+ b'kind',
+ b'kindhearted',
+ b'kindly',
+ b'knotty',
+ b'knowing',
+ b'knowledgeable',
+ b'known',
+ b'laconic',
+ b'large',
+ b'lavish',
+ b'lean',
+ b'learned',
+ b'left',
+ b'legal',
+ b'level',
+ b'light',
+ b'likeable',
+ b'literate',
+ b'little',
+ b'lively',
+ b'living',
+ b'long',
+ b'longing',
+ b'loud',
+ b'lovely',
+ b'loving',
+ b'loyal',
+ b'lucky',
+ b'luminous',
+ b'lush',
+ b'luxuriant',
+ b'luxurious',
+ b'lyrical',
+ b'magenta',
+ b'magical',
+ b'magnificent',
+ b'majestic',
+ b'male',
+ b'mammoth',
+ b'many',
+ b'marvelous',
+ b'massive',
+ b'material',
+ b'mature',
+ b'meandering',
+ b'meaty',
+ b'medical',
+ b'mellow',
+ b'melodic',
+ b'melted',
+ b'merciful',
+ b'mighty',
+ b'miniature',
+ b'miniscule',
+ b'minor',
+ b'minute',
+ b'misty',
+ b'modern',
+ b'modest',
+ b'momentous',
+ b'motionless',
+ b'mountainous',
+ b'mute',
+ b'mysterious',
+ b'narrow',
+ b'natural',
+ b'near',
+ b'neat',
+ b'nebulous',
+ b'necessary',
+ b'neighborly',
+ b'new',
+ b'next',
+ b'nice',
+ b'nifty',
+ b'nimble',
+ b'nine',
+ b'nippy',
+ b'noiseless',
+ b'noisy',
+ b'nonchalant',
+ b'normal',
+ b'numberless',
+ b'numerous',
+ b'nutritious',
+ b'obedient',
+ b'observant',
+ b'obtainable',
+ b'oceanic',
+ b'omniscient',
+ b'one',
+ b'open',
+ b'opposite',
+ b'optimal',
+ b'optimistic',
+ b'opulent',
+ b'orange',
+ b'ordinary',
+ b'organic',
+ b'outgoing',
+ b'outrageous',
+ b'outstanding',
+ b'oval',
+ b'overjoyed',
+ b'overt',
+ b'palatial',
+ b'panoramic',
+ b'parallel',
+ b'passionate',
+ b'past',
+ b'pastoral',
+ b'patient',
+ b'peaceful',
+ b'perfect',
+ b'periodic',
+ b'permissible',
+ b'perpetual',
+ b'persistent',
+ b'petite',
+ b'philosophical',
+ b'physical',
+ b'picturesque',
+ b'pink',
+ b'pioneering',
+ b'piquant',
+ b'plausible',
+ b'pleasant',
+ b'plucky',
+ b'poised',
+ b'polite',
+ b'possible',
+ b'powerful',
+ b'practical',
+ b'precious',
+ b'premium',
+ b'present',
+ b'pretty',
+ b'previous',
+ b'private',
+ b'probable',
+ b'productive',
+ b'profound',
+ b'profuse',
+ b'protective',
+ b'proud',
+ b'psychedelic',
+ b'public',
+ b'pumped',
+ b'purple',
+ b'purring',
+ b'puzzled',
+ b'puzzling',
+ b'quaint',
+ b'quick',
+ b'quicker',
+ b'quickest',
+ b'quiet',
+ b'quirky',
+ b'quixotic',
+ b'quizzical',
+ b'rainy',
+ b'rapid',
+ b'rare',
+ b'rational',
+ b'ready',
+ b'real',
+ b'rebel',
+ b'receptive',
+ b'red',
+ b'reflective',
+ b'regular',
+ b'relaxed',
+ b'reliable',
+ b'relieved',
+ b'remarkable',
+ b'reminiscent',
+ b'reserved',
+ b'resolute',
+ b'resonant',
+ b'resourceful',
+ b'responsible',
+ b'rich',
+ b'ridiculous',
+ b'right',
+ b'rightful',
+ b'ripe',
+ b'ritzy',
+ b'roasted',
+ b'robust',
+ b'romantic',
+ b'roomy',
+ b'round',
+ b'royal',
+ b'ruddy',
+ b'rural',
+ b'rustic',
+ b'sable',
+ b'safe',
+ b'salty',
+ b'same',
+ b'satisfying',
+ b'savory',
+ b'scientific',
+ b'scintillating',
+ b'scrumptious',
+ b'second',
+ b'secret',
+ b'secretive',
+ b'seemly',
+ b'selective',
+ b'sensible',
+ b'separate',
+ b'shaggy',
+ b'shaky',
+ b'shining',
+ b'shiny',
+ b'short',
+ b'shy',
+ b'silent',
+ b'silky',
+ b'silly',
+ b'simple',
+ b'simplistic',
+ b'sincere',
+ b'six',
+ b'sizzling',
+ b'skillful',
+ b'sleepy',
+ b'slick',
+ b'slim',
+ b'smart',
+ b'smiling',
+ b'smooth',
+ b'soaring',
+ b'sociable',
+ b'soft',
+ b'solid',
+ b'sophisticated',
+ b'sparkling',
+ b'special',
+ b'spectacular',
+ b'speedy',
+ b'spicy',
+ b'spiffy',
+ b'spiritual',
+ b'splendid',
+ b'spooky',
+ b'spotless',
+ b'spotted',
+ b'square',
+ b'standing',
+ b'statuesque',
+ b'steadfast',
+ b'steady',
+ b'steep',
+ b'stimulating',
+ b'straight',
+ b'straightforward',
+ b'striking',
+ b'striped',
+ b'strong',
+ b'stunning',
+ b'stupendous',
+ b'sturdy',
+ b'subsequent',
+ b'substantial',
+ b'subtle',
+ b'successful',
+ b'succinct',
+ b'sudden',
+ b'super',
+ b'superb',
+ b'supreme',
+ b'swanky',
+ b'sweet',
+ b'swift',
+ b'sympathetic',
+ b'synonymous',
+ b'talented',
+ b'tall',
+ b'tame',
+ b'tan',
+ b'tangible',
+ b'tangy',
+ b'tasteful',
+ b'tasty',
+ b'telling',
+ b'temporary',
+ b'tempting',
+ b'ten',
+ b'tender',
+ b'terrific',
+ b'tested',
+ b'thankful',
+ b'therapeutic',
+ b'thin',
+ b'thinkable',
+ b'third',
+ b'thoughtful',
+ b'three',
+ b'thrifty',
+ b'tidy',
+ b'tiny',
+ b'toothsome',
+ b'towering',
+ b'tranquil',
+ b'tremendous',
+ b'tricky',
+ b'true',
+ b'truthful',
+ b'two',
+ b'typical',
+ b'ubiquitous',
+ b'ultra',
+ b'unassuming',
+ b'unbiased',
+ b'uncovered',
+ b'understanding',
+ b'understood',
+ b'unequaled',
+ b'unique',
+ b'unusual',
+ b'unwritten',
+ b'upbeat',
+ b'useful',
+ b'utopian',
+ b'utter',
+ b'uttermost',
+ b'valuable',
+ b'various',
+ b'vast',
+ b'verdant',
+ b'vermilion',
+ b'versatile',
+ b'versed',
+ b'victorious',
+ b'vigorous',
+ b'violet',
+ b'vivacious',
+ b'voiceless',
+ b'voluptuous',
+ b'wacky',
+ b'waiting',
+ b'wakeful',
+ b'wandering',
+ b'warm',
+ b'warmhearted',
+ b'wealthy',
+ b'whimsical',
+ b'whispering',
+ b'white',
+ b'whole',
+ b'wholesale',
+ b'whopping',
+ b'wide',
+ b'wiggly',
+ b'wild',
+ b'willing',
+ b'windy',
+ b'winsome',
+ b'wiry',
+ b'wise',
+ b'wistful',
+ b'witty',
+ b'womanly',
+ b'wonderful',
+ b'workable',
+ b'young',
+ b'youthful',
+ b'yummy',
+ b'zany',
+ b'zealous',
+ b'zesty',
+ b'zippy'
]
def randomtopicname(ui):
# Re-implement random.choice() in the way it was written in Python 2.
def choice(things):
return things[int(len(things) * random.random())]
- if ui.configint("devel", "randomseed"):
- random.seed(ui.configint("devel", "randomseed"))
- return choice(adjectives) + "-" + choice(animals)
+ if ui.configint(b"devel", b"randomseed"):
+ random.seed(ui.configint(b"devel", b"randomseed"))
+ return choice(adjectives) + b"-" + choice(animals)
--- a/hgext3rd/topic/revset.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/revset.py Fri Sep 27 13:03:14 2019 +0200
@@ -24,7 +24,7 @@
revsetpredicate = registrar.revsetpredicate()
def getstringstrict(x, err):
- if x and x[0] == 'string':
+ if x and x[0] == b'string':
return x[1]
raise error.ParseError(err)
@@ -36,7 +36,7 @@
If `string` starts with `re:` the remainder of the name is treated
as a regular expression.
"""
- args = revset.getargs(x, 0, 1, 'topic takes one or no arguments')
+ args = revset.getargs(x, 0, 1, b'topic takes one or no arguments')
mutable = revset._notpublic(repo, revset.fullreposet(repo), ())
@@ -44,15 +44,15 @@
return (subset & mutable).filter(lambda r: bool(repo[r].topic()))
try:
- topic = getstringstrict(args[0], '')
+ topic = getstringstrict(args[0], b'')
except error.ParseError:
# not a string, but another revset
pass
else:
kind, pattern, matcher = mkmatcher(topic)
- if topic.startswith('literal:') and pattern not in repo.topics:
- raise error.RepoLookupError("topic '%s' does not exist" % pattern)
+ if topic.startswith(b'literal:') and pattern not in repo.topics:
+ raise error.RepoLookupError(b"topic '%s' does not exist" % pattern)
def matches(r):
topic = repo[r].topic()
@@ -64,7 +64,7 @@
s = revset.getset(repo, revset.fullreposet(repo), x)
topics = {repo[r].topic() for r in s}
- topics.discard('')
+ topics.discard(b'')
def matches(r):
if r in s:
@@ -82,11 +82,11 @@
Name is horrible so that people change it.
"""
- args = revset.getargs(x, 1, 1, 'ngtip takes one argument')
+ args = revset.getargs(x, 1, 1, b'ngtip takes one argument')
# match a specific topic
- branch = revset.getstring(args[0], 'ngtip requires a string')
- if branch == '.':
- branch = repo['.'].branch()
+ branch = revset.getstring(args[0], b'ngtip requires a string')
+ if branch == b'.':
+ branch = repo[b'.'].branch()
return subset & revset.baseset(destination.ngtip(repo, branch))
@revsetpredicate(b'stack()')
@@ -97,7 +97,7 @@
unstable changeset after there future parent (as if evolve where already
run).
"""
- err = 'stack takes no arguments, it works on current topic'
+ err = b'stack takes no arguments, it works on current topic'
revset.getargs(x, 0, 0, err)
topic = None
branch = None
@@ -120,8 +120,8 @@
if isinstance(z, tuple):
a, b = revset.getintrange(
z,
- 'relation subscript must be an integer or a range',
- 'relation subscript bounds must be integers',
+ b'relation subscript must be an integer or a range',
+ b'relation subscript bounds must be integers',
None, None)
else:
a = b = z
@@ -159,12 +159,12 @@
return subset & revset.baseset(revs)
- revset.subscriptrelations['stack'] = stackrel
- revset.subscriptrelations['s'] = stackrel
+ revset.subscriptrelations[b'stack'] = stackrel
+ revset.subscriptrelations[b's'] = stackrel
def topicrel(repo, subset, x, *args):
subset &= topicset(repo, subset, x)
return revset.generationsrel(repo, subset, x, *args)
- revset.subscriptrelations['topic'] = topicrel
- revset.subscriptrelations['t'] = topicrel
+ revset.subscriptrelations[b'topic'] = topicrel
+ revset.subscriptrelations[b't'] = topicrel
--- a/hgext3rd/topic/stack.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/stack.py Fri Sep 27 13:03:14 2019 +0200
@@ -26,7 +26,7 @@
username = None
if user:
# user is of form "abc <abc@xyz.com>"
- username = user.split('<')[0]
+ username = user.split(b'<')[0]
if not username:
# assuming user is of form "<abc@xyz.com>"
if len(user) > 1:
@@ -45,10 +45,10 @@
"""
phasesets = repo._phasecache._phasesets
if not phasesets or None in phasesets[phases.draft:]:
- return repo.revs('(not public()) - obsolete()')
+ return repo.revs(b'(not public()) - obsolete()')
result = set.union(*phasesets[phases.draft:])
- result -= obsolete.getrevs(repo, 'obsolete')
+ result -= obsolete.getrevs(repo, b'obsolete')
return result
class stack(object):
@@ -63,13 +63,13 @@
subset = _stackcandidates(repo)
if topic is not None and branch is not None:
- raise error.ProgrammingError('both branch and topic specified (not defined yet)')
+ raise error.ProgrammingError(b'both branch and topic specified (not defined yet)')
elif topic is not None:
- trevs = repo.revs("%ld and topic(%s)", subset, topic)
+ trevs = repo.revs(b"%ld and topic(%s)", subset, topic)
elif branch is not None:
- trevs = repo.revs("%ld and branch(%s) - topic()", subset, branch)
+ trevs = repo.revs(b"%ld and branch(%s) - topic()", subset, branch)
else:
- raise error.ProgrammingError('neither branch and topic specified (not defined yet)')
+ raise error.ProgrammingError(b'neither branch and topic specified (not defined yet)')
self._revs = trevs
def __iter__(self):
@@ -143,9 +143,18 @@
# processed dependency graph.
# Step 1: compute relation of revision with each other
- dependencies, rdependencies = self._dependencies
- dependencies = dependencies.copy()
- rdependencies = rdependencies.copy()
+ origdeps, rdependencies = self._dependencies
+ dependencies = {}
+ # Making a deep copy of origdeps because we modify contents of values
+ # later on. Checking for list here only because right now
+ # builddependencies in evolvebits.py can return a list of _succs()
+ # objects. When that will be dealt with, this deep copy code can be
+ # simplified a lot.
+ for k, v in origdeps.items():
+ if isinstance(v, list):
+ dependencies[k] = [i.copy() for i in v]
+ else:
+ dependencies[k] = v.copy()
# Step 2: Build the ordering
# Remove the revisions with no dependency(A) and add them to the ordering.
# Removing these revisions leads to new revisions with no dependency (the
@@ -169,7 +178,7 @@
if revs:
pt1 = self._repo[revs[0]].p1()
else:
- pt1 = self._repo['.']
+ pt1 = self._repo[b'.']
if pt1.obsolete():
pt1 = self._repo[_singlesuccessor(self._repo, pt1)]
@@ -197,15 +206,15 @@
if revs:
minroot = [min(r for r in revs if not deps[r])]
try:
- dest = destutil.destmerge(self._repo, action='rebase',
+ dest = destutil.destmerge(self._repo, action=b'rebase',
sourceset=minroot,
onheadcheck=False)
- return len(self._repo.revs("only(%d, %ld)", dest, minroot))
+ return len(self._repo.revs(b"only(%d, %ld)", dest, minroot))
except error.NoMergeDestAbort:
return 0
except error.ManyMergeDestAbort as exc:
# XXX we should make it easier for upstream to provide the information
- self.behinderror = pycompat.bytestr(exc).split('-', 1)[0].rstrip()
+ self.behinderror = pycompat.bytestr(exc).split(b'-', 1)[0].rstrip()
return -1
return 0
@@ -217,68 +226,68 @@
return branches
def labelsgen(prefix, parts):
- fmt = prefix + '.%s'
- return prefix + ' ' + ' '.join(fmt % p.replace(' ', '-') for p in parts)
+ fmt = prefix + b'.%s'
+ return prefix + b' ' + b' '.join(fmt % p.replace(b' ', b'-') for p in parts)
def showstack(ui, repo, branch=None, topic=None, opts=None):
if opts is None:
opts = {}
if topic is not None and branch is not None:
- msg = 'both branch and topic specified [%s]{%s}(not defined yet)'
+ msg = b'both branch and topic specified [%s]{%s}(not defined yet)'
msg %= (branch, topic)
raise error.ProgrammingError(msg)
elif topic is not None:
- prefix = 's'
+ prefix = b's'
if topic not in repo.topics:
- raise error.Abort(_('cannot resolve "%s": no such topic found') % topic)
+ raise error.Abort(_(b'cannot resolve "%s": no such topic found') % topic)
elif branch is not None:
- prefix = 's'
+ prefix = b's'
else:
- raise error.ProgrammingError('neither branch and topic specified (not defined yet)')
+ raise error.ProgrammingError(b'neither branch and topic specified (not defined yet)')
- fm = ui.formatter('topicstack', opts)
+ fm = ui.formatter(b'topicstack', opts)
prev = None
entries = []
idxmap = {}
- label = 'topic'
+ label = b'topic'
if topic == repo.currenttopic:
- label = 'topic.active'
+ label = b'topic.active'
st = stack(repo, branch, topic)
if topic is not None:
- fm.plain(_('### topic: %s')
+ fm.plain(_(b'### topic: %s')
% ui.label(topic, label),
- label='stack.summary.topic')
+ label=b'stack.summary.topic')
if 1 < len(st.heads):
- fm.plain(' (')
- fm.plain('%d heads' % len(st.heads),
- label='stack.summary.headcount.multiple')
- fm.plain(')')
- fm.plain('\n')
- fm.plain(_('### target: %s (branch)')
- % '+'.join(st.branches), # XXX handle multi branches
- label='stack.summary.branches')
+ fm.plain(b' (')
+ fm.plain(b'%d heads' % len(st.heads),
+ label=b'stack.summary.headcount.multiple')
+ fm.plain(b')')
+ fm.plain(b'\n')
+ fm.plain(_(b'### target: %s (branch)')
+ % b'+'.join(st.branches), # XXX handle multi branches
+ label=b'stack.summary.branches')
if topic is None:
if 1 < len(st.heads):
- fm.plain(' (')
- fm.plain('%d heads' % len(st.heads),
- label='stack.summary.headcount.multiple')
- fm.plain(')')
+ fm.plain(b' (')
+ fm.plain(b'%d heads' % len(st.heads),
+ label=b'stack.summary.headcount.multiple')
+ fm.plain(b')')
else:
if st.behindcount == -1:
- fm.plain(', ')
- fm.plain('ambiguous rebase destination - %s' % st.behinderror,
- label='stack.summary.behinderror')
+ fm.plain(b', ')
+ fm.plain(b'ambiguous rebase destination - %s' % st.behinderror,
+ label=b'stack.summary.behinderror')
elif st.behindcount:
- fm.plain(', ')
- fm.plain('%d behind' % st.behindcount, label='stack.summary.behindcount')
- fm.plain('\n')
+ fm.plain(b', ')
+ fm.plain(b'%d behind' % st.behindcount, label=b'stack.summary.behindcount')
+ fm.plain(b'\n')
if not st:
- fm.plain(_("(stack is empty)\n"))
+ fm.plain(_(b"(stack is empty)\n"))
st = stack(repo, branch=branch, topic=topic)
for idx, r in enumerate(st, 0):
@@ -317,40 +326,40 @@
symbol = None
states = []
- if opts.get('children'):
- expr = 'children(%d) and merge() - %ld'
+ if opts.get(b'children'):
+ expr = b'children(%d) and merge() - %ld'
revisions = repo.revs(expr, ctx.rev(), st._revs)
if len(revisions) > 0:
- states.append('external-children')
+ states.append(b'external-children')
if ctx.orphan():
- symbol = '$'
- states.append('orphan')
+ symbol = b'$'
+ states.append(b'orphan')
if ctx.contentdivergent():
- symbol = '$'
- states.append('content divergent')
+ symbol = b'$'
+ states.append(b'content divergent')
if ctx.phasedivergent():
- symbol = '$'
- states.append('phase divergent')
+ symbol = b'$'
+ states.append(b'phase divergent')
- iscurrentrevision = repo.revs('%d and parents()', ctx.rev())
+ iscurrentrevision = repo.revs(b'%d and parents()', ctx.rev())
if iscurrentrevision:
- symbol = '@'
- states.append('current')
+ symbol = b'@'
+ states.append(b'current')
if not isentry:
- symbol = '^'
+ symbol = b'^'
# "base" is kind of a "ghost" entry
- states.append('base')
+ states.append(b'base')
# none of the above if statments get executed
if not symbol:
- symbol = ':'
+ symbol = b':'
if not states:
- states.append('clean')
+ states.append(b'clean')
states.sort()
@@ -368,22 +377,22 @@
spacewidth = 2 + 40
# s# alias width
spacewidth += 2
- fm.plain(' ' * spacewidth)
+ fm.plain(b' ' * spacewidth)
else:
- fm.write('stack_index', '%s%%d' % prefix, idx,
- label=labelsgen('stack.index', states))
+ fm.write(b'stack_index', b'%s%%d' % prefix, idx,
+ label=labelsgen(b'stack.index', states))
if ui.verbose:
- fm.write('node', '(%s)', fm.hexfunc(ctx.node()),
- label=labelsgen('stack.shortnode', states))
+ fm.write(b'node', b'(%s)', fm.hexfunc(ctx.node()),
+ label=labelsgen(b'stack.shortnode', states))
else:
fm.data(node=fm.hexfunc(ctx.node()))
- fm.write('symbol', '%s', symbol,
- label=labelsgen('stack.state', states))
- fm.plain(' ')
- fm.write('desc', '%s', ctx.description().splitlines()[0],
- label=labelsgen('stack.desc', states))
- fm.condwrite(states != ['clean'] and idx is not None, 'state',
- ' (%s)', fm.formatlist(states, 'stack.state'),
- label=labelsgen('stack.state', states))
- fm.plain('\n')
+ fm.write(b'symbol', b'%s', symbol,
+ label=labelsgen(b'stack.state', states))
+ fm.plain(b' ')
+ fm.write(b'desc', b'%s', ctx.description().splitlines()[0],
+ label=labelsgen(b'stack.desc', states))
+ fm.condwrite(states != [b'clean'] and idx is not None, b'state',
+ b' (%s)', fm.formatlist(states, b'stack.state'),
+ label=labelsgen(b'stack.state', states))
+ fm.plain(b'\n')
fm.end()
--- a/hgext3rd/topic/topicmap.py Mon Jul 29 14:43:10 2019 +0200
+++ b/hgext3rd/topic/topicmap.py Fri Sep 27 13:03:14 2019 +0200
@@ -16,22 +16,22 @@
common,
)
-basefilter = set(['base', 'immutable'])
+basefilter = set([b'base', b'immutable'])
def topicfilter(name):
"""return a "topic" version of a filter level"""
if name in basefilter:
return name
elif name is None:
return None
- elif name.endswith('-topic'):
+ elif name.endswith(b'-topic'):
return name
else:
- return name + '-topic'
+ return name + b'-topic'
def istopicfilter(filtername):
if filtername is None:
return False
- return filtername.endswith('-topic')
+ return filtername.endswith(b'-topic')
def gettopicrepo(repo):
if not common.hastopicext(repo):
@@ -61,8 +61,8 @@
if newfilter not in funcmap:
funcmap[newfilter] = revsfunc
partialmap[newfilter] = base
- funcmap['unfiltered-topic'] = lambda repo: frozenset()
- partialmap['unfiltered-topic'] = 'visible-topic'
+ funcmap[b'unfiltered-topic'] = lambda repo: frozenset()
+ partialmap[b'unfiltered-topic'] = b'visible-topic'
def _phaseshash(repo, maxrev):
"""uniq ID for a phase matching a set of rev"""
@@ -80,7 +80,7 @@
if revs:
s = hashlib.sha1()
for rev in revs:
- s.update('%d;' % rev)
+ s.update(b'%d;' % rev)
key = s.digest()
return key
@@ -100,7 +100,7 @@
# wrap commit status use the topic branch heads
ctx = repo[node]
if ctx.topic() and ctx.branch() == branch:
- bheads = repo.branchheads("%s:%s" % (branch, ctx.topic()))
+ bheads = repo.branchheads(b"%s:%s" % (branch, ctx.topic()))
ret = orig(repo, node, branch, bheads=bheads, opts=opts)
@@ -111,10 +111,10 @@
return ret
parents = ctx.parents()
- if (not opts.get('amend') and bheads and node not in bheads and not
+ if (not opts.get(b'amend') and bheads and node not in bheads and not
[x for x in parents if x.node() in bheads and x.branch() == branch]):
- repo.ui.status(_("(consider using topic for lightweight branches."
- " See 'hg help topic')\n"))
+ repo.ui.status(_(b"(consider using topic for lightweight branches."
+ b" See 'hg help topic')\n"))
return ret
@@ -179,17 +179,17 @@
new.phaseshash = self.phaseshash
return new
- def branchtip(self, branch, topic=''):
+ def branchtip(self, branch, topic=b''):
'''Return the tipmost open head on branch head, otherwise return the
tipmost closed head on branch.
Raise KeyError for unknown branch.'''
if topic:
- branch = '%s:%s' % (branch, topic)
+ branch = b'%s:%s' % (branch, topic)
return super(_topiccache, self).branchtip(branch)
- def branchheads(self, branch, closed=False, topic=''):
+ def branchheads(self, branch, closed=False, topic=b''):
if topic:
- branch = '%s:%s' % (branch, topic)
+ branch = b'%s:%s' % (branch, topic)
return super(_topiccache, self).branchheads(branch, closed=closed)
def validfor(self, repo):
@@ -229,13 +229,13 @@
def branchinfo(r, changelog=None):
info = oldgetbranchinfo(r)
- topic = ''
+ topic = b''
ctx = unfi[r]
if ctx.mutable():
topic = ctx.topic()
branch = info[0]
if topic:
- branch = '%s:%s' % (branch, topic)
+ branch = b'%s:%s' % (branch, topic)
return (branch, info[1])
try:
unfi.revbranchcache().branchinfo = branchinfo
--- a/setup.py Mon Jul 29 14:43:10 2019 +0200
+++ b/setup.py Fri Sep 27 13:03:14 2019 +0200
@@ -7,7 +7,8 @@
def get_metadata():
meta = {}
fullpath = join(dirname(__file__), META_PATH)
- execfile(fullpath, meta)
+ with open(fullpath, 'r') as fp:
+ exec(fp.read(), meta)
return meta
def get_version():
@@ -28,6 +29,8 @@
'hgext3rd.topic',
]
+py_versions = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4'
+
if os.environ.get('INCLUDE_INHIBIT'):
py_modules.append('hgext3rd.evolve.hack.inhibit')
py_modules.append('hgext3rd.evolve.hack.directaccess')
@@ -45,5 +48,6 @@
keywords='hg mercurial',
license='GPLv2+',
py_modules=py_modules,
- packages=py_packages
+ packages=py_packages,
+ python_requires=py_versions
)
--- a/tests/test-evolve-abort-orphan.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-evolve-abort-orphan.t Fri Sep 27 13:03:14 2019 +0200
@@ -19,6 +19,11 @@
> EOF
$ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+ $ cat >> $HGRCPATH <<EOF
+ > [alias]
+ > abort = evolve --abort
+ > EOF
+
$ hg init abortrepo
$ cd abortrepo
$ echo ".*\.orig" > .hgignore
@@ -104,7 +109,7 @@
summary: added d
- $ hg evolve --abort
+ $ hg abort
evolve aborted
working directory is now at e93a9161a274
@@ -199,7 +204,7 @@
o 0:8fa14d15e168 added hgignore
() draft
- $ hg evolve --abort
+ $ hg abort
1 new orphan changesets
evolve aborted
working directory is now at 125af0ed8cae
@@ -299,7 +304,7 @@
o 0:8fa14d15e168 added hgignore
() draft
- $ hg evolve --abort
+ $ hg abort
2 new orphan changesets
evolve aborted
working directory is now at 807e8e2ca559
@@ -395,7 +400,7 @@
adding file changes
added 1 changesets with 1 changes to 1 files
$ cd ../repotwo
- $ hg evolve --abort
+ $ hg abort
warning: new changesets detected on destination branch
abort: unable to abort interrupted evolve, use 'hg evolve --stop' to stop evolve
[255]
@@ -442,7 +447,7 @@
$ hg phase -r 1c476940790a --public
- $ hg evolve --abort
+ $ hg abort
cannot clean up public changesets: 1c476940790a
abort: unable to abort interrupted evolve, use 'hg evolve --stop' to stop evolve
[255]
@@ -510,7 +515,7 @@
o 0:8fa14d15e168 added hgignore
() draft
- $ hg evolve --abort
+ $ hg abort
1 new orphan changesets
evolve aborted
working directory is now at a0086c17bfc7
@@ -543,7 +548,7 @@
(see 'hg help evolve.interrupted')
[1]
- $ hg evolve --abort
+ $ hg abort
evolve aborted
working directory is now at c1f4718020e3
--- a/tests/test-evolve-abort-phasediv.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-evolve-abort-phasediv.t Fri Sep 27 13:03:14 2019 +0200
@@ -19,6 +19,11 @@
> EOF
$ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+ $ cat >> $HGRCPATH <<EOF
+ > [alias]
+ > abort = evolve --abort
+ > EOF
+
$ hg init abortrepo
$ cd abortrepo
$ echo ".*\.orig" > .hgignore
@@ -124,7 +129,7 @@
summary: added d
- $ hg evolve --abort
+ $ hg abort
evolve aborted
working directory is now at ddba58020bc0
@@ -218,7 +223,7 @@
(see 'hg help evolve.interrupted')
[1]
- $ hg evolve --abort
+ $ hg abort
1 new phase-divergent changesets
evolve aborted
working directory is now at 28cd06b3f801
@@ -304,7 +309,7 @@
(see 'hg help evolve.interrupted')
[1]
- $ hg evolve --abort
+ $ hg abort
1 new phase-divergent changesets
evolve aborted
working directory is now at ef9b72b9b42c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-interrupted.t Fri Sep 27 13:03:14 2019 +0200
@@ -0,0 +1,149 @@
+Quitting an evolve in the middle (via ctrl-c or something) can leave things in a
+weird intermediate state where hg thinks we're in the middle of an update
+operation (or even just leave the 'merge' directory around without actually
+indicating we're in the middle of *any* operation).
+
+ $ . $TESTDIR/testlib/common.sh
+
+ $ cat << EOF >> $HGRCPATH
+ > [extensions]
+ > rebase =
+ > evolve =
+ > [alias]
+ > l = log -G -T'{rev} {desc}'
+ > EOF
+
+ $ hg init interrupted-orphan
+ $ cd interrupted-orphan
+
+ $ echo apricot > a
+ $ hg ci -qAm apricot
+
+ $ echo banana > b
+ $ hg ci -qAm banana
+
+Let's go back to amend 0 and make an orphan out of 1 (and a merge conflict to
+test with)
+
+ $ hg up -q 0
+ $ echo blueberry > b
+ $ hg l
+ o 1 banana
+ |
+ @ 0 apricot
+
+ $ hg ci --amend -qAm 'apricot and blueberry'
+ 1 new orphan changesets
+ $ hg l
+ @ 2 apricot and blueberry
+
+ * 1 banana
+ |
+ x 0 apricot
+
+
+ $ hg evolve --update --config hooks.precommit=false --config ui.merge=:other
+ move:[1] banana
+ atop:[2] apricot and blueberry
+ transaction abort!
+ rollback completed
+ abort: precommit hook exited with status 1
+ [255]
+ $ hg l
+ @ 2 apricot and blueberry
+
+ * 1 banana
+ |
+ x 0 apricot
+
+ $ cat b
+ banana
+
+ $ hg status --config commands.status.verbose=True
+ M b
+ # The repository is in an unfinished *evolve* state.
+
+ # No unresolved merge conflicts.
+
+ # To continue: hg evolve --continue
+ # To abort: hg evolve --abort
+ # To stop: hg evolve --stop
+ # (also see `hg help evolve.interrupted`)
+
+
+ $ ls .hg/evolvestate
+ .hg/evolvestate
+
+ $ cat b
+ banana
+
+ $ hg l
+ @ 2 apricot and blueberry
+
+ * 1 banana
+ |
+ x 0 apricot
+
+
+Test various methods of handling that unfinished state
+ $ hg evolve --abort
+ evolve aborted
+ working directory is now at e1989e4b1526
+ $ ls .hg/evolvestate
+ ls: cannot access '?.hg/evolvestate'?: No such file or directory (re)
+ [2]
+ $ cat b
+ blueberry
+ $ hg l
+ @ 2 apricot and blueberry
+
+ * 1 banana
+ |
+ x 0 apricot
+
+
+ $ hg evolve --update --config hooks.precommit=false --config ui.merge=:other
+ move:[1] banana
+ atop:[2] apricot and blueberry
+ transaction abort!
+ rollback completed
+ abort: precommit hook exited with status 1
+ [255]
+ $ cat b
+ banana
+ $ hg evolve --stop
+ stopped the interrupted evolve
+ working directory is now at e1989e4b1526
+ $ cat .hg/evolvestate
+ cat: .hg/evolvestate: No such file or directory
+ [1]
+ $ cat b
+ blueberry
+ $ hg l
+ @ 2 apricot and blueberry
+
+ * 1 banana
+ |
+ x 0 apricot
+
+
+ $ hg evolve --update --config hooks.precommit=false --config ui.merge=:other
+ move:[1] banana
+ atop:[2] apricot and blueberry
+ transaction abort!
+ rollback completed
+ abort: precommit hook exited with status 1
+ [255]
+ $ hg evolve --continue
+ evolving 1:e0486f65907d "banana"
+ working directory is now at bd5ec7dfc2af
+ $ cat .hg/evolvestate
+ cat: .hg/evolvestate: No such file or directory
+ [1]
+ $ cat b
+ banana
+ $ hg l
+ @ 3 banana
+ |
+ o 2 apricot and blueberry
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-issue5958.t Fri Sep 27 13:03:14 2019 +0200
@@ -0,0 +1,88 @@
+Content divergence and trying to relocate a node on top of itself (issue5958)
+https://bz.mercurial-scm.org/show_bug.cgi?id=5958
+
+ $ . $TESTDIR/testlib/common.sh
+
+ $ cat << EOF >> $HGRCPATH
+ > [extensions]
+ > rebase =
+ > evolve =
+ > EOF
+
+ $ hg init issue5958
+ $ cd issue5958
+
+ $ echo hi > r0
+ $ hg ci -qAm 'add r0'
+ $ echo hi > foo.txt
+ $ hg ci -qAm 'add foo.txt'
+ $ hg metaedit -r . -d '0 2'
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+(Make changes in unrelated files so that we don't have any merge conflicts
+during the rebase, but the two touched revisions aren't identical)
+
+ $ echo hi > bar.txt
+ $ hg add -q bar.txt
+ $ hg amend -q
+ $ hg metaedit -r 1 -d '0 1' --hidden
+ 2 new content-divergent changesets
+ $ hg log -r tip
+ changeset: 4:c17bf400a278
+ tag: tip
+ parent: 0:a24ed8ad918c
+ user: test
+ date: Wed Dec 31 23:59:59 1969 -0000
+ instability: content-divergent
+ summary: add foo.txt
+
+ $ echo hi > baz.txt
+ $ hg add -q baz.txt
+ $ hg amend -q
+ $ hg rebase -qr tip -d 4
+ $ hg log -G
+ @ changeset: 6:08bc7ba82799
+ | tag: tip
+ | parent: 4:c17bf400a278
+ | user: test
+ | date: Wed Dec 31 23:59:58 1969 -0000
+ | instability: content-divergent
+ | summary: add foo.txt
+ |
+ * changeset: 4:c17bf400a278
+ | parent: 0:a24ed8ad918c
+ | user: test
+ | date: Wed Dec 31 23:59:59 1969 -0000
+ | instability: content-divergent
+ | summary: add foo.txt
+ |
+ o changeset: 0:a24ed8ad918c
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add r0
+
+ $ hg obslog -a -r .
+ @ 08bc7ba82799 (6) add foo.txt
+ |
+ | * c17bf400a278 (4) add foo.txt
+ | |
+ x | 1d1fc409af98 (5) add foo.txt
+ | | rewritten(parent, content) as 08bc7ba82799 using rebase by test (Thu Jan 01 00:00:00 1970 +0000)
+ | |
+ x | a25dd7af6cf6 (3) add foo.txt
+ | | rewritten(content) as 1d1fc409af98 using amend by test (Thu Jan 01 00:00:00 1970 +0000)
+ | |
+ x | 0065551bd38f (2) add foo.txt
+ |/ rewritten(content) as a25dd7af6cf6 using amend by test (Thu Jan 01 00:00:00 1970 +0000)
+ |
+ x cc71ffbc7c00 (1) add foo.txt
+ rewritten(date) as 0065551bd38f using metaedit by test (Thu Jan 01 00:00:00 1970 +0000)
+ rewritten(date) as c17bf400a278 using metaedit by test (Thu Jan 01 00:00:00 1970 +0000)
+
+ $ hg evolve --content-divergent
+ merge:[6] add foo.txt
+ with: [4] add foo.txt
+ base: [1] add foo.txt
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 1 new orphan changesets
+ working directory is now at 2372e6d39855
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-issue6097.t Fri Sep 27 13:03:14 2019 +0200
@@ -0,0 +1,99 @@
+Orphan changeset and trying to relocate a node on top of itself (issue6097)
+https://bz.mercurial-scm.org/show_bug.cgi?id=6097
+
+ $ . $TESTDIR/testlib/common.sh
+
+ $ cat << EOF >> $HGRCPATH
+ > [extensions]
+ > rebase =
+ > evolve =
+ > EOF
+
+ $ hg init issue6097
+ $ cd issue6097
+
+ $ echo apricot > a
+ $ hg ci -qAm apricot
+
+ $ echo banana > b
+ $ hg ci -qAm banana
+
+Let's go back to amend 0 and make an orphan out of 1
+
+ $ hg up -q 0
+ $ echo coconut > c
+ $ hg add -q c
+ $ hg ci --amend -m 'apricot and coconut'
+ 1 new orphan changesets
+
+Now rebase the successor of 0 on top of 1
+
+ $ hg rebase -r . -d 1
+ rebasing 2:32acf8fb1b23 "apricot and coconut" (tip)
+ 1 new orphan changesets
+
+Pruning 1 just to get it out of the way
+
+ $ hg prune -q 1
+
+Note how both the regular DAG and the obsolescence graph are linear, but the
+paths from 3 to 0 are different: 3-1-0 and 3-2-0
+
+ $ hg log -G
+ @ changeset: 3:2868fe6df617
+ | tag: tip
+ | parent: 1:e0486f65907d
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | instability: orphan
+ | summary: apricot and coconut
+ |
+ x changeset: 1:e0486f65907d
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | obsolete: pruned using prune
+ | summary: banana
+ |
+ x changeset: 0:692cc7b6212c
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ obsolete: rewritten using amend, rebase as 3:2868fe6df617
+ summary: apricot
+
+
+ $ hg obslog
+ @ 2868fe6df617 (3) apricot and coconut
+ |
+ x 32acf8fb1b23 (2) apricot and coconut
+ | rewritten(parent, content) as 2868fe6df617 using rebase by test (Thu Jan 01 00:00:00 1970 +0000)
+ |
+ x 692cc7b6212c (0) apricot
+ rewritten(description, content) as 32acf8fb1b23 using amend by test (Thu Jan 01 00:00:00 1970 +0000)
+
+
+ $ hg evolve -r .
+ move:[3] apricot and coconut
+ atop:[-1]
+ working directory is now at bb847d1d3a5f
+
+ $ hg log -G
+ @ changeset: 4:bb847d1d3a5f
+ tag: tip
+ parent: -1:000000000000
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: apricot and coconut
+
+
+ $ hg obslog
+ @ bb847d1d3a5f (4) apricot and coconut
+ |
+ x 2868fe6df617 (3) apricot and coconut
+ | rewritten(parent) as bb847d1d3a5f using evolve by test (Thu Jan 01 00:00:00 1970 +0000)
+ |
+ x 32acf8fb1b23 (2) apricot and coconut
+ | rewritten(parent, content) as 2868fe6df617 using rebase by test (Thu Jan 01 00:00:00 1970 +0000)
+ |
+ x 692cc7b6212c (0) apricot
+ rewritten(description, content) as 32acf8fb1b23 using amend by test (Thu Jan 01 00:00:00 1970 +0000)
+
--- a/tests/test-evolve-obshistory-amend.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-evolve-obshistory-amend.t Fri Sep 27 13:03:14 2019 +0200
@@ -109,7 +109,7 @@
@@ -1,1 +1,2 @@
A0
+42
-
+
$ hg obslog 4ae3a4151de9 --graph -T'{label("log.summary", shortdescription)} {if(markers, join(markers % "at {date|hgdate} by {user|person} ", " also "))}'
@ A1
--- a/tests/test-evolve-phase-divergence.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-evolve-phase-divergence.t Fri Sep 27 13:03:14 2019 +0200
@@ -1412,6 +1412,10 @@
$ hg init cancelled-changes
$ cd cancelled-changes
+ $ cat << EOF > .hg/hgrc
+ > [diff]
+ > word-diff = yes
+ > EOF
$ cat << EOF > numbers
> 1
> 2
--- a/tests/test-fold.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-fold.t Fri Sep 27 13:03:14 2019 +0200
@@ -254,7 +254,8 @@
Test order of proposed commit message
- $ hg fold --exact --hidden -r 4 -r 5 -r 6
+ $ hg fold --exact --hidden -r 4 -r 5 -r 6 \
+ > --config experimental.evolution.allowdivergence=yes
2 new content-divergent changesets
3 changesets folded
$ hg log -r tip -T '{desc}'
@@ -265,7 +266,8 @@
r6 (no-eol)
- $ hg fold --exact --hidden -r 6 -r 4 -r 5
+ $ hg fold --exact --hidden -r 6 -r 4 -r 5 \
+ > --config experimental.evolution.allowdivergence=yes
3 changesets folded
$ hg log -r tip -T '{desc}'
r4
@@ -381,3 +383,37 @@
o 0: r0
$ cd ..
+
+Fold should respect experimental.evolution.allowdivergence option
+https://bz.mercurial-scm.org/show_bug.cgi?id=5817
+
+ $ hg init issue5817
+ $ cd issue5817
+
+ $ echo A > foo
+ $ hg ci -qAm A
+ $ echo B > foo
+ $ hg ci -m B
+ $ echo C > foo
+ $ hg ci -m C
+
+ $ hg fold --exact -r 'desc("A")::desc("B")' -m 'first fold'
+ 1 new orphan changesets
+ 2 changesets folded
+
+fold aborts here because divergence is not allowed
+
+ $ hg fold --exact -r 'desc("A")::desc("B")' -m 'second fold' \
+ > --config experimental.evolution.allowdivergence=no
+ abort: folding obsolete revisions may cause divergence
+ (set experimental.evolution.allowdivergence=yes to allow folding them)
+ [255]
+
+but if we allow divergence, this should work and should create new content-divergent changesets
+
+ $ hg fold --exact -r 'desc("A")::desc("B")' -m 'second fold' \
+ > --config experimental.evolution.allowdivergence=yes
+ 2 new content-divergent changesets
+ 2 changesets folded
+
+ $ cd ..
--- a/tests/test-issue-6028.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-issue-6028.t Fri Sep 27 13:03:14 2019 +0200
@@ -25,10 +25,12 @@
$ cd $TESTTMP/issue-6028
create initial commit
+
$ echo "0" > 0
$ hg ci -Am 0
adding 0
+start new topics "a" and "b" both from 0
$ hg up default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -40,7 +42,6 @@
active topic 'a' grew its first changeset
(see 'hg help topics' for more information)
-
$ hg up default
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg topics b
@@ -51,6 +52,8 @@
active topic 'b' grew its first changeset
(see 'hg help topics' for more information)
+create branch "integration" from 0, merge topics "a" and "b" into it
+
$ hg up default
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg branch integration
@@ -66,6 +69,8 @@
(branch merge, don't forget to commit)
$ hg ci -m "merged b"
+commit a bad file on topic "a", merge it into "integration"
+
$ hg up a
switching to topic a
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -79,6 +84,8 @@
(branch merge, don't forget to commit)
$ hg ci -m "merged a bad commit"
+add more commits on both topics and merge them into "integration"
+
$ hg up a
switching to topic a
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -103,7 +110,12 @@
(branch merge, don't forget to commit)
$ hg ci -m "merged bb"
-create instability by pruning two changesets, one in a topic, one in a merge
+create instability by pruning two changesets, one in a topic, one a merge
+
+ $ hg log -r 5:6 -T '{rev}: {desc}\n'
+ 5: a bad commit
+ 6: merged a bad commit
+
$ hg prune -r 5:6
2 changesets pruned
3 new orphan changesets
@@ -112,12 +124,47 @@
2 files updated, 0 files merged, 1 files removed, 0 files unresolved
start the evolve
+
$ hg evolve --update --no-all
move:[8] merged aa
atop:[4] merged b
working directory is now at c920dd828523
+casually checking issue6141: position of p2 is not changed
+
+ $ hg log -r 'predecessors(.) + .'
+ changeset: 8:3f6f25057afb
+ branch: integration
+ parent: 6:cfc4c333724f
+ parent: 7:61eff7f7bb6c
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ obsolete: rebased using evolve as 11:c920dd828523
+ summary: merged aa
+
+ changeset: 11:c920dd828523
+ branch: integration
+ tag: tip
+ parent: 4:e33aee2c715e
+ parent: 7:61eff7f7bb6c
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ instability: orphan
+ summary: merged aa
+
+
+test that we successfully got rid of the bad file
+
+ $ hg d --git -r 'predecessors(.)' -r '.'
+ diff --git a/a_bad_commit b/a_bad_commit
+ deleted file mode 100644
+ --- a/a_bad_commit
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -a bad commit
+
evolve creates an obsolete changeset above as 11
+
$ hg evolve -r .
cannot solve instability of c920dd828523, skipping
cannot solve instability of c920dd828523, skipping
--- a/tests/test-pick.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-pick.t Fri Sep 27 13:03:14 2019 +0200
@@ -1,3 +1,4 @@
+#testcases abortflag
Test for the pick command
$ cat >> $HGRCPATH <<EOF
@@ -8,6 +9,13 @@
> EOF
$ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+#if abortflag
+ $ cat >> $HGRCPATH <<EOF
+ > [alias]
+ > abort = pick --abort
+ > EOF
+#endif
+
$ mkcommit() {
> echo "$1" > "$1"
> hg add "$1"
@@ -235,7 +243,7 @@
unresolved merge conflicts (see hg help resolve)
[1]
- $ hg pick --abort
+ $ hg abort
aborting pick, updating to c437988de89f
$ hg glog
--- a/tests/test-prune.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-prune.t Fri Sep 27 13:03:14 2019 +0200
@@ -39,7 +39,7 @@
abort: can only specify one of pair, fold
[255]
$ hg prune --fold --biject
- abort: nothing to prune
+ abort: no revisions specified to prune
[255]
$ hg prune --split --fold
abort: can only specify one of fold, split
@@ -307,7 +307,7 @@
(activating bookmark todelete)
$ hg prune -B nostrip
bookmark 'nostrip' deleted
- abort: nothing to prune
+ abort: no revisions specified to prune
[255]
$ hg tag --remove --local a
$ hg prune -B todelete
--- a/tests/test-rewind.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-rewind.t Fri Sep 27 13:03:14 2019 +0200
@@ -921,25 +921,11 @@
$ cd ..
-Check error cases
-=================
-
- $ hg clone rewind-testing-base rewind-testing-error
- updating to branch default
- 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
- $ cd rewind-testing-error
+Merge commits
+=============
-Uncommited changes
-------------------
-
- $ echo C > C
- $ hg add C
- $ hg rewind
- abort: uncommitted changes
- [255]
-
-Merge commits
--------------
+ $ hg clone -q rewind-testing-base rewind-merge
+ $ cd rewind-merge
$ hg up --clean .^
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -962,7 +948,7 @@
$ hg rewind --from .
rewinded to 1 changesets
(1 changesets obsoleted)
- working directory is now at 006fd8c2fed9
+ working directory is now at 9d325190bd87
$ hg st --change .
A B
@@ -973,9 +959,91 @@
| |/
+---x 4: merge ()
| |/
- | o 3: foo (C foo)
+ | o 3: foo (foo)
| |
| ~
o 2: c_B0 (B)
|
~
+
+ $ cd ..
+
+Rewind --keep
+=============
+
+ $ hg init rewind-keep
+ $ cd rewind-keep
+ $ echo root > root
+ $ hg ci -qAm 'root'
+
+ $ echo apple > a
+ $ echo banana > b
+ $ hg ci -qAm initial
+
+ $ hg rm b
+ $ echo apricot > a
+ $ echo coconut > c
+ $ hg add c
+ $ hg status
+ M a
+ A c
+ R b
+ $ hg amend -m amended
+ $ hg glf --hidden
+ @ 2: amended (a c)
+ |
+ | x 1: initial (a b)
+ |/
+ o 0: root (root)
+
+
+Clean wdir
+
+ $ hg rewind --keep --to 'desc("initial")' --hidden
+ rewinded to 1 changesets
+ (1 changesets obsoleted)
+ $ hg obslog
+ @ b4c97fddc16a (3) initial
+ |\
+ x | 2ea5be2f8751 (2) amended
+ |/ rewritten(description, meta, content) as b4c97fddc16a using rewind by test (Thu Jan 01 00:00:06 1970 +0000)
+ |
+ x 30704102d912 (1) initial
+ rewritten(description, content) as 2ea5be2f8751 using amend by test (Thu Jan 01 00:00:06 1970 +0000)
+ rewritten(meta) as b4c97fddc16a using rewind by test (Thu Jan 01 00:00:06 1970 +0000)
+
+ $ hg glf --hidden
+ @ 3: initial (a b)
+ |
+ | x 2: amended (a c)
+ |/
+ | x 1: initial (a b)
+ |/
+ o 0: root (root)
+
+ $ hg st
+ M a
+ A c
+ R b
+
+Making wdir even more dirty
+
+ $ echo avocado > a
+ $ echo durian > d
+ $ hg st
+ M a
+ A c
+ R b
+ ? d
+
+No rewinding without --keep
+
+ $ hg rewind --to 'desc("amended")' --hidden
+ abort: uncommitted changes
+ [255]
+
+XXX: Unfortunately, even with --keep it's not allowed
+
+ $ hg rewind --keep --to 'desc("amended")' --hidden
+ abort: uncommitted changes
+ [255]
--- a/tests/test-topic-mode.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-topic-mode.t Fri Sep 27 13:03:14 2019 +0200
@@ -228,7 +228,7 @@
$ touch A
$ hg add A
$ hg commit -m "Add A" --config devel.randomseed=42
- active topic 'panoramic-antelope' grew its first changeset
+ active topic 'palatial-antelope' grew its first changeset
(see 'hg help topics' for more information)
$ hg up -r "desc(ROOT)"
@@ -256,8 +256,8 @@
| date: Thu Jan 01 00:00:00 1970 +0000
| summary: Add B
|
- | o changeset: 1:d4b548f35972
- |/ topic: panoramic-antelope
+ | o changeset: 1:d502ab6d9d91
+ |/ topic: palatial-antelope
| user: test
| date: Thu Jan 01 00:00:00 1970 +0000
| summary: Add A
@@ -267,7 +267,7 @@
date: Thu Jan 01 00:00:00 1970 +0000
summary: ROOT
- $ hg merge panoramic-antelope
+ $ hg merge palatial-antelope
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m 'merge'
@@ -292,7 +292,7 @@
$ touch A
$ hg add A
$ hg commit -m "Add A" --config devel.randomseed=42
- active topic 'panoramic-antelope' grew its first changeset
+ active topic 'palatial-antelope' grew its first changeset
(see 'hg help topics' for more information)
$ hg up -r "desc(ROOT)"
@@ -320,8 +320,8 @@
| date: Thu Jan 01 00:00:00 1970 +0000
| summary: Add B
|
- | o changeset: 1:d4b548f35972
- |/ topic: panoramic-antelope
+ | o changeset: 1:d502ab6d9d91
+ |/ topic: palatial-antelope
| user: test
| date: Thu Jan 01 00:00:00 1970 +0000
| summary: Add A
@@ -331,7 +331,7 @@
date: Thu Jan 01 00:00:00 1970 +0000
summary: ROOT
- $ hg merge panoramic-antelope
+ $ hg merge palatial-antelope
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m 'merge' --config devel.randomseed=1337
--- a/tests/test-topic-stack.t Mon Jul 29 14:43:10 2019 +0200
+++ b/tests/test-topic-stack.t Fri Sep 27 13:03:14 2019 +0200
@@ -794,7 +794,7 @@
$ hg stack red
### topic: red
- ### target: default (branch), ambiguous rebase destination - topic 'red' has 3 heads
+ ### target: default (branch), 7 behind
s5$ c_H (orphan)
^ c_G
^ c_D
@@ -868,7 +868,7 @@
$ hg stack red
### topic: red
- ### target: default (branch), ambiguous rebase destination - topic 'red' has 3 heads
+ ### target: default (branch), 7 behind
s5$ c_H (orphan)
^ c_G
^ c_D