[PATCH STABLE] help: unjumble the list of default config values for `internals.config`
# HG changeset patch # User Matt Harbison # Date 1541725447 18000 # Thu Nov 08 20:04:07 2018 -0500 # Branch stable # Node ID 5b530d767e6726374382a7bde932bcc528568b85 # Parent 8239d4e5d05f5452d66e4ae1ffc2f58e0d0fbd0d help: unjumble the list of default config values for `internals.config` diff --git a/mercurial/help/internals/config.txt b/mercurial/help/internals/config.txt --- a/mercurial/help/internals/config.txt +++ b/mercurial/help/internals/config.txt @@ -99,10 +99,11 @@ requiring a default value. The existing then stay in use until compatibility with Mercurial 4.2 is dropped. As reminder, here are the default values for each config type: -- config: None -- configbool: False -- configbytes: 0 -- configdate: None -- configint: None -- configlist: [] -- configpath: None + +- config: None +- configbool: False +- configbytes: 0 +- configdate: None +- configint: None +- configlist: [] +- configpath: None ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5245: fix: add extra field to fixed revisions to avoid creating obsolescence cycles
hooper created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY The extra field prevents sequential invocations of fix from producing the same hash twice. Previously, this could cause problems because it would create an obsolescence cycle instead of the expected new successor. This change also adds an explicit check for whether a new revision should be committed. Until now, the code relied on memctx.commit() to quietly do nothing if the node already exists. Because of the new extra field, this no longer covers the case where we don't want to replace an unchanged node. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5245 AFFECTED FILES hgext/fix.py tests/test-fix.t CHANGE DETAILS diff --git a/tests/test-fix.t b/tests/test-fix.t --- a/tests/test-fix.t +++ b/tests/test-fix.t @@ -1195,3 +1195,37 @@ 8 $ cd .. + +It's possible for repeated applications of a fixer tool to create cycles in the +generated content of a file. For example, two users with different versions of +a code formatter might fight over the formatting when they run hg fix. In the +absence of other changes, this means we could produce commits with the same +hash in subsequent runs of hg fix. This is a problem unless we support +obsolescence cycles well. We avoid this by adding an extra field to the +successor which forces it to have a new hash. That's why this test creates +three revisions instead of two. + + $ hg init cyclictool + $ cd cyclictool + + $ cat >> .hg/hgrc < [fix] + > swapletters:command = tr ab ba + > swapletters:pattern = foo + > EOF + + $ echo ab > foo + $ hg commit -Aqm foo + + $ hg fix -r 0 + $ hg fix -r 1 + + $ hg cat -r 0 foo --hidden + ab + $ hg cat -r 1 foo --hidden + ba + $ hg cat -r 2 foo + ab + + $ cd .. + diff --git a/hgext/fix.py b/hgext/fix.py --- a/hgext/fix.py +++ b/hgext/fix.py @@ -586,6 +586,17 @@ newp1node = replacements.get(p1ctx.node(), p1ctx.node()) newp2node = replacements.get(p2ctx.node(), p2ctx.node()) +# We don't want to create a revision that has no changes from the original, +# but we should if the original revision's parent has been replaced. +# Otherwise, we would produce an orphan that needs no actual human +# intervention to evolve. We can't rely on commit() to avoid creating the +# un-needed revision because the extra field added below produces a new hash +# regardless of file content changes. +if (not filedata and +p1ctx.node() not in replacements and +p2ctx.node() not in replacements): +return + def filectxfn(repo, memctx, path): if path not in ctx: return None @@ -602,15 +613,18 @@ isexec=fctx.isexec(), copied=copied) +extra = ctx.extra().copy() +extra['fix_source'] = ctx.hex() + memctx = context.memctx( repo, parents=(newp1node, newp2node), text=ctx.description(), files=set(ctx.files()) | set(filedata.keys()), filectxfn=filectxfn, user=ctx.user(), date=ctx.date(), -extra=ctx.extra(), +extra=extra, branch=ctx.branch(), editor=None) sucnode = memctx.commit() To: hooper, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5244: cleanup: use revision numbers instead of hashes in test output
hooper created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY This allows changes to the hashes produced by fix to not needlessly modify this area of the test. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5244 AFFECTED FILES tests/test-fix.t CHANGE DETAILS diff --git a/tests/test-fix.t b/tests/test-fix.t --- a/tests/test-fix.t +++ b/tests/test-fix.t @@ -893,24 +893,24 @@ $ printf "BAR\n" > bar.whole $ hg commit -Aqm "add bar" - $ hg log --graph --template '{node|shortest} {files}' - @ bc05 bar.whole + $ hg log --graph --template '{rev} {files}' + @ 2 bar.whole | - o 4fd2 foo.whole + o 1 foo.whole | - o f9ac foo.whole + o 0 foo.whole $ hg fix -r 0:2 - $ hg log --graph --template '{node|shortest} {files}' - o b4e2 bar.whole + $ hg log --graph --template '{rev} {files}' + o 4 bar.whole | - o 59f4 + o 3 | - | @ bc05 bar.whole + | @ 2 bar.whole | | - | x 4fd2 foo.whole + | x 1 foo.whole |/ - o f9ac foo.whole + o 0 foo.whole $ cd .. To: hooper, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 8 of 8] commandserver: send raw progress information to message channel
# HG changeset patch # User Yuya Nishihara # Date 1541303474 -32400 # Sun Nov 04 12:51:14 2018 +0900 # Node ID c116648678800a03858bfd3f5c2798335392034b # Parent b7781ccecdcdf9021ea3e6cadf6039be2f8c613e commandserver: send raw progress information to message channel This is pretty basic implementation to support GUI progress bar. diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py --- a/mercurial/commandserver.py +++ b/mercurial/commandserver.py @@ -93,7 +93,8 @@ class channeledmessage(object): def write(self, data, **opts): opts = pycompat.byteskwargs(opts) -opts[b'data'] = data +if data is not None: +opts[b'data'] = data self._cout.write(self._encodefn(opts)) def __getattr__(self, attr): diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -1678,7 +1678,15 @@ class ui(object): All topics should be marked closed by setting pos to None at termination. ''' -if self._progbar is not None: +if getattr(self._fmsgerr, 'structured', False): +# channel for machine-readable output with metadata, just send +# raw information +# TODO: consider porting some useful information (e.g. estimated +# time) from progbar. we might want to support update delay to +# reduce the cost of transferring progress messages. +self._fmsgerr.write(None, type=b'progress', topic=topic, pos=pos, +item=item, unit=unit, total=total) +elif self._progbar is not None: self._progbar.progress(topic, pos, item=item, unit=unit, total=total) if pos is None or not self.configbool('progress', 'debug'): diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t --- a/tests/test-commandserver.t +++ b/tests/test-commandserver.t @@ -750,9 +750,13 @@ structured message channel: pgid: * (glob) *** runcommand -R repo2 verify message: '\xa2DdataTchecking changesets\nDtypeFstatus' + message: '\xa6Ditem@Cpos\xf6EtopicHcheckingEtotal\xf6DtypeHprogressDunit@' message: '\xa2DdataSchecking manifests\nDtypeFstatus' + message: '\xa6Ditem@Cpos\xf6EtopicHcheckingEtotal\xf6DtypeHprogressDunit@' message: '\xa2DdataX0crosschecking files in changesets and manifests\nDtypeFstatus' + message: '\xa6Ditem@Cpos\xf6EtopicMcrosscheckingEtotal\xf6DtypeHprogressDunit@' message: '\xa2DdataOchecking files\nDtypeFstatus' + message: '\xa6Ditem@Cpos\xf6EtopicHcheckingEtotal\xf6DtypeHprogressDunit@' message: '\xa2DdataX/checked 0 changesets with 0 changes to 0 files\nDtypeFstatus' >>> from hgclient import checkwith, readchannel, runcommand, stringio ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 7 of 8] commandserver: make getpass() request distinct from normal prompt
# HG changeset patch # User Yuya Nishihara # Date 1541302729 -32400 # Sun Nov 04 12:38:49 2018 +0900 # Node ID b7781ccecdcdf9021ea3e6cadf6039be2f8c613e # Parent ae086b413ab2bdf76d3207d9b6250f145a65eaf3 commandserver: make getpass() request distinct from normal prompt Otherwise, GUI clients would have to parse the prompt text. diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -1467,7 +1467,7 @@ class ui(object): return default try: self._writemsg(self._fmsgerr, prompt or _('password: '), - type='prompt') + type='prompt', password=True) # disable getpass() only if explicitly specified. it's still valid # to interact with tty even if fin is not a tty. with self.timeblockedsection('stdio'): diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t --- a/tests/test-commandserver.t +++ b/tests/test-commandserver.t @@ -762,10 +762,15 @@ structured message channel: ... def prompt(server): ... readchannel(server) ... interactive = [b'--config', b'ui.interactive=True'] + ... runcommand(server, [b'debuggetpass'] + interactive, + ...input=stringio(b'1234\n')) ... runcommand(server, [b'debugprompt'] + interactive, ...input=stringio(b'5678\n')) ... runcommand(server, [b'debugpromptchoice'] + interactive, ...input=stringio(b'n\n')) + *** runcommand debuggetpass --config ui.interactive=True + message: '\xa3DdataJpassword: Hpassword\xf5DtypeFprompt' + 1234 *** runcommand debugprompt --config ui.interactive=True message: '\xa3DdataGprompt:GdefaultAyDtypeFprompt' 5678 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 6 of 8] commandserver: attach prompt default and choices to message
# HG changeset patch # User Yuya Nishihara # Date 1541301440 -32400 # Sun Nov 04 12:17:20 2018 +0900 # Node ID ae086b413ab2bdf76d3207d9b6250f145a65eaf3 # Parent 601786ab02a1925a42bf63fac605322a135b040b commandserver: attach prompt default and choices to message These attributes are important to provide a GUI prompt to user. diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -1393,12 +1393,16 @@ class ui(object): """Prompt user with msg, read response. If ui is not interactive, the default is returned. """ +return self._prompt(msg, default=default) + +def _prompt(self, msg, **opts): +default = opts[r'default'] if not self.interactive(): -self._writemsg(self._fmsgout, msg, ' ', type='prompt') +self._writemsg(self._fmsgout, msg, ' ', type='prompt', **opts) self._writemsg(self._fmsgout, default or '', "\n", type='promptecho') return default -self._writemsgnobuf(self._fmsgout, msg, type='prompt') +self._writemsgnobuf(self._fmsgout, msg, type='prompt', **opts) self.flush() try: r = self._readline() @@ -1452,7 +1456,7 @@ class ui(object): msg, choices = self.extractchoices(prompt) resps = [r for r, t in choices] while True: -r = self.prompt(msg, resps[default]) +r = self._prompt(msg, default=resps[default], choices=choices) if r.lower() in resps: return resps.index(r.lower()) # TODO: shouldn't it be a warning? diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t --- a/tests/test-commandserver.t +++ b/tests/test-commandserver.t @@ -619,6 +619,10 @@ changelog and manifest would have invali > @command(b"debugprompt", norepo=True) > def debugprompt(ui): > ui.write(b"%s\n" % ui.prompt(b"prompt:")) + > @command(b"debugpromptchoice", norepo=True) + > def debugpromptchoice(ui): + > msg = b"promptchoice (y/n)? $$ $$ " + > ui.write(b"%d\n" % ui.promptchoice(msg)) > @command(b"debugreadstdin", norepo=True) > def debugreadstdin(ui): > ui.write(b"read: %r\n" % sys.stdin.read(1)) @@ -751,6 +755,24 @@ structured message channel: message: '\xa2DdataOchecking files\nDtypeFstatus' message: '\xa2DdataX/checked 0 changesets with 0 changes to 0 files\nDtypeFstatus' + >>> from hgclient import checkwith, readchannel, runcommand, stringio + >>> @checkwith(extraargs=[b'--config', b'ui.message-output=channel', + ... b'--config', b'cmdserver.message-encodings=cbor', + ... b'--config', b'extensions.dbgui=dbgui.py']) + ... def prompt(server): + ... readchannel(server) + ... interactive = [b'--config', b'ui.interactive=True'] + ... runcommand(server, [b'debugprompt'] + interactive, + ...input=stringio(b'5678\n')) + ... runcommand(server, [b'debugpromptchoice'] + interactive, + ...input=stringio(b'n\n')) + *** runcommand debugprompt --config ui.interactive=True + message: '\xa3DdataGprompt:GdefaultAyDtypeFprompt' + 5678 + *** runcommand debugpromptchoice --config ui.interactive=True + message: '\xa4Gchoices\x82\x82AyCYes\x82AnBNoDdataTpromptchoice (y/n)? GdefaultAyDtypeFprompt' + 1 + bad message encoding: $ hg serve --cmdserver pipe --config ui.message-output=channel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 5 of 8] test-commandserver: clean up quoting and location of dbgui extension
# HG changeset patch # User Yuya Nishihara # Date 1541683504 -32400 # Thu Nov 08 22:25:04 2018 +0900 # Node ID 601786ab02a1925a42bf63fac605322a135b040b # Parent c03e57f814d840dd97eb5e88b4534250456a2db6 test-commandserver: clean up quoting and location of dbgui extension This helps embedding '$' in the script. diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t --- a/tests/test-commandserver.t +++ b/tests/test-commandserver.t @@ -607,7 +607,7 @@ changelog and manifest would have invali *** runcommand qqueue --active foo - $ cat < dbgui.py + $ cat <<'EOF' > ../dbgui.py > import os > import sys > from mercurial import commands, registrar @@ -615,10 +615,10 @@ changelog and manifest would have invali > command = registrar.command(cmdtable) > @command(b"debuggetpass", norepo=True) > def debuggetpass(ui): - > ui.write(b"%s\\n" % ui.getpass()) + > ui.write(b"%s\n" % ui.getpass()) > @command(b"debugprompt", norepo=True) > def debugprompt(ui): - > ui.write(b"%s\\n" % ui.prompt(b"prompt:")) + > ui.write(b"%s\n" % ui.prompt(b"prompt:")) > @command(b"debugreadstdin", norepo=True) > def debugreadstdin(ui): > ui.write(b"read: %r\n" % sys.stdin.read(1)) @@ -630,7 +630,7 @@ changelog and manifest would have invali > EOF $ cat <> .hg/hgrc > [extensions] - > dbgui = dbgui.py + > dbgui = ../dbgui.py > EOF >>> from hgclient import check, readchannel, runcommand, stringio ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 8] ui: extract helpers to write message with type or label
# HG changeset patch # User Yuya Nishihara # Date 1421571328 -32400 # Sun Jan 18 17:55:28 2015 +0900 # Node ID c03e57f814d840dd97eb5e88b4534250456a2db6 # Parent 6a4ccc024119f3bd983ab2cdf6337396a7bcab7e ui: extract helpers to write message with type or label This provides a 'type' attribute to command-server clients, which seems more solid than relying on 'ui.' labels. In future patches, type='progress' will be added to send raw progress information. diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py --- a/mercurial/commandserver.py +++ b/mercurial/commandserver.py @@ -78,6 +78,9 @@ class channeledmessage(object): data length (unsigned int), encoded message and metadata, as a flat key-value dict. + +Each message should have 'type' attribute. Messages of unknown type +should be ignored. """ # teach ui that write() can take **opts diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -1042,6 +1042,12 @@ class ui(object): self._blockedtimes['stdio_blocked'] += \ (util.timer() - starttime) * 1000 +def _writemsg(self, dest, *args, **opts): +_writemsgwith(self._write, dest, *args, **opts) + +def _writemsgnobuf(self, dest, *args, **opts): +_writemsgwith(self._writenobuf, dest, *args, **opts) + def flush(self): # opencode timeblockedsection because this is a critical path starttime = util.timer() @@ -1388,18 +1394,18 @@ class ui(object): If ui is not interactive, the default is returned. """ if not self.interactive(): -self._write(self._fmsgout, msg, ' ', label='ui.prompt') -self._write(self._fmsgout, default or '', "\n", -label='ui.promptecho') +self._writemsg(self._fmsgout, msg, ' ', type='prompt') +self._writemsg(self._fmsgout, default or '', "\n", + type='promptecho') return default -self._writenobuf(self._fmsgout, msg, label='ui.prompt') +self._writemsgnobuf(self._fmsgout, msg, type='prompt') self.flush() try: r = self._readline() if not r: r = default if self.configbool('ui', 'promptecho'): -self._write(self._fmsgout, r, "\n", label='ui.promptecho') +self._writemsg(self._fmsgout, r, "\n", type='promptecho') return r except EOFError: raise error.ResponseExpected() @@ -1450,14 +1456,14 @@ class ui(object): if r.lower() in resps: return resps.index(r.lower()) # TODO: shouldn't it be a warning? -self._write(self._fmsgout, _("unrecognized response\n")) +self._writemsg(self._fmsgout, _("unrecognized response\n")) def getpass(self, prompt=None, default=None): if not self.interactive(): return default try: -self._write(self._fmsgerr, prompt or _('password: '), -label='ui.prompt') +self._writemsg(self._fmsgerr, prompt or _('password: '), + type='prompt') # disable getpass() only if explicitly specified. it's still valid # to interact with tty even if fin is not a tty. with self.timeblockedsection('stdio'): @@ -1477,24 +1483,21 @@ class ui(object): This adds an output label of "ui.status". ''' if not self.quiet: -opts[r'label'] = opts.get(r'label', '') + ' ui.status' -self._write(self._fmsgout, *msg, **opts) +self._writemsg(self._fmsgout, type='status', *msg, **opts) def warn(self, *msg, **opts): '''write warning message to output (stderr) This adds an output label of "ui.warning". ''' -opts[r'label'] = opts.get(r'label', '') + ' ui.warning' -self._write(self._fmsgerr, *msg, **opts) +self._writemsg(self._fmsgerr, type='warning', *msg, **opts) def error(self, *msg, **opts): '''write error message to output (stderr) This adds an output label of "ui.error". ''' -opts[r'label'] = opts.get(r'label', '') + ' ui.error' -self._write(self._fmsgerr, *msg, **opts) +self._writemsg(self._fmsgerr, type='error', *msg, **opts) def note(self, *msg, **opts): '''write note to output (if ui.verbose is True) @@ -1502,8 +1505,7 @@ class ui(object): This adds an output label of "ui.note". ''' if self.verbose: -opts[r'label'] = opts.get(r'label', '') + ' ui.note' -self._write(self._fmsgout, *msg, **opts) +self._writemsg(self._fmsgout, type='note', *msg, **opts) def debug(self, *msg, **opts): '''write debug message to output (if ui.debugflag is True) @@ -1511,8 +1513,7 @@ class ui(object):
[PATCH 3 of 8] commandserver: add experimental option to use separate message channel
# HG changeset patch # User Yuya Nishihara # Date 1421574599 -32400 # Sun Jan 18 18:49:59 2015 +0900 # Node ID 6a4ccc024119f3bd983ab2cdf6337396a7bcab7e # Parent 30c0af95d4461ad1da70ce0e0ad8a65ff367c128 commandserver: add experimental option to use separate message channel This is loosely based on the idea of the TortoiseHg's pipeui extension, which attaches ui.label to message text so the command-server client can capture prompt text, for example. https://bitbucket.org/tortoisehg/thg/src/4.7.2/tortoisehg/util/pipeui.py I was thinking that this functionality could be generalized to templating, but changed mind as doing template stuff would be unnecessarily complex. It's merely a status message, a simple serialization option should suffice. Since this slightly changes the command-server protocol, it's gated by a config knob. If the config is enabled, and if it's supported by the server, "message-encoding: " is advertised so the client can stop parsing 'o'/'e' channel data and read encoded messages from the 'm' channel. As we might add new message encodings in future releases, client can specify a list of encoding names in preferred order. This patch includes 'cbor' encoding as example. Perhaps, 'json' should be supported as well. diff --git a/contrib/hgclient.py b/contrib/hgclient.py --- a/contrib/hgclient.py +++ b/contrib/hgclient.py @@ -27,10 +27,11 @@ else: stringio = cStringIO.StringIO bprint = print -def connectpipe(path=None): +def connectpipe(path=None, extraargs=()): cmdline = [b'hg', b'serve', b'--cmdserver', b'pipe'] if path: cmdline += [b'-R', path] +cmdline.extend(extraargs) server = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE) @@ -114,6 +115,8 @@ def runcommand(server, args, output=stdo writeblock(server, input.read(data)) elif ch == b'L': writeblock(server, input.readline(data)) +elif ch == b'm': +bprint(b"message: %r" % data) elif ch == b'r': ret, = struct.unpack('>i', data) if ret != 0: @@ -132,3 +135,8 @@ def check(func, connect=connectpipe): finally: server.stdin.close() server.wait() + +def checkwith(connect=connectpipe, **kwargs): +def wrap(func): +return check(func, lambda: connect(**kwargs)) +return wrap diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py --- a/mercurial/commandserver.py +++ b/mercurial/commandserver.py @@ -26,9 +26,11 @@ from .i18n import _ from . import ( encoding, error, +pycompat, util, ) from .utils import ( +cborutil, procutil, ) @@ -70,6 +72,30 @@ class channeledoutput(object): raise AttributeError(attr) return getattr(self.out, attr) +class channeledmessage(object): +""" +Write encoded message and metadata to out in the following format: + +data length (unsigned int), +encoded message and metadata, as a flat key-value dict. +""" + +# teach ui that write() can take **opts +structured = True + +def __init__(self, out, channel, encodename, encodefn): +self._cout = channeledoutput(out, channel) +self.encoding = encodename +self._encodefn = encodefn + +def write(self, data, **opts): +opts = pycompat.byteskwargs(opts) +opts[b'data'] = data +self._cout.write(self._encodefn(opts)) + +def __getattr__(self, attr): +return getattr(self._cout, attr) + class channeledinput(object): """ Read data from in_. @@ -156,6 +182,20 @@ class channeledinput(object): raise AttributeError(attr) return getattr(self.in_, attr) +_messageencoders = { +b'cbor': lambda v: b''.join(cborutil.streamencode(v)), +} + +def _selectmessageencoder(ui): +# experimental config: cmdserver.message-encodings +encnames = ui.configlist(b'cmdserver', b'message-encodings') +for n in encnames: +f = _messageencoders.get(n) +if f: +return n, f +raise error.Abort(b'no supported message encodings: %s' + % b' '.join(encnames)) + class server(object): """ Listens for commands on fin, runs them and writes the output on a channel @@ -189,6 +229,14 @@ class server(object): self.cin = channeledinput(fin, fout, 'I') self.cresult = channeledoutput(fout, 'r') +# TODO: add this to help/config.txt when stabilized +# ``channel`` +# Use separate channel for structured output. (Command-server only) +self.cmsg = None +if ui.config(b'ui', b'message-output') == b'channel': +encname, encfn = _selectmessageencoder(ui) +self.cmsg = channeledmessage(fout, b'm', encname, encfn) + self.client = fin def cleanup(self): @@ -254,7 +302,7 @@ class server(object): ui.setconfig('ui', 'nontty', 'true',
[PATCH 2 of 8] commandserver: fix reference before assignment error in pipeservice cleanup
# HG changeset patch # User Yuya Nishihara # Date 1541597871 -32400 # Wed Nov 07 22:37:51 2018 +0900 # Node ID 30c0af95d4461ad1da70ce0e0ad8a65ff367c128 # Parent bd8ab1b84b2a778ea30e61a2386d2824c9a20750 commandserver: fix reference before assignment error in pipeservice cleanup Spotted by the next patch. diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py --- a/mercurial/commandserver.py +++ b/mercurial/commandserver.py @@ -320,8 +320,8 @@ class pipeservice(object): # redirect stdio to null device so that broken extensions or in-process # hooks will never cause corruption of channel protocol. with procutil.protectedstdio(ui.fin, ui.fout) as (fin, fout): +sv = server(ui, self.repo, fin, fout) try: -sv = server(ui, self.repo, fin, fout) return sv.serve() finally: sv.cleanup() ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 8] dispatch: pass around ui.fmsg channel
# HG changeset patch # User Yuya Nishihara # Date 1421574203 -32400 # Sun Jan 18 18:43:23 2015 +0900 # Node ID bd8ab1b84b2a778ea30e61a2386d2824c9a20750 # Parent b93157f69f46a1359726be32bde4afb1e5af4384 dispatch: pass around ui.fmsg channel This will be set by the command server. See the next patch. diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py --- a/mercurial/dispatch.py +++ b/mercurial/dispatch.py @@ -50,7 +50,7 @@ from .utils import ( class request(object): def __init__(self, args, ui=None, repo=None, fin=None, fout=None, - ferr=None, prereposetups=None): + ferr=None, fmsg=None, prereposetups=None): self.args = args self.ui = ui self.repo = repo @@ -59,6 +59,8 @@ class request(object): self.fin = fin self.fout = fout self.ferr = ferr +# separate stream for status/error messages +self.fmsg = fmsg # remember options pre-parsed by _earlyparseopts() self.earlyoptions = {} @@ -205,6 +207,8 @@ def dispatch(req): req.ui.fout = req.fout if req.ferr: req.ui.ferr = req.ferr +if req.fmsg: +req.ui.fmsg = req.fmsg except error.Abort as inst: ferr.write(_("abort: %s\n") % inst) if inst.hint: @@ -955,6 +959,7 @@ def _dispatch(req): repo.ui.fin = ui.fin repo.ui.fout = ui.fout repo.ui.ferr = ui.ferr +repo.ui.fmsg = ui.fmsg else: try: repo = hg.repository(ui, path=path, diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -234,6 +234,7 @@ class ui(object): self._fout = src._fout self._ferr = src._ferr self._fin = src._fin +self._fmsg = src._fmsg self._fmsgout = src._fmsgout self._fmsgerr = src._fmsgerr self._finoutredirected = src._finoutredirected @@ -261,6 +262,7 @@ class ui(object): self._fout = procutil.stdout self._ferr = procutil.stderr self._fin = procutil.stdin +self._fmsg = None self._fmsgout = self.fout # configurable self._fmsgerr = self.ferr # configurable self._finoutredirected = False @@ -915,6 +917,17 @@ class ui(object): def fin(self, f): self._fin = f +@property +def fmsg(self): +"""Stream dedicated for status/error messages; may be None if +fout/ferr are used""" +return self._fmsg + +@fmsg.setter +def fmsg(self, f): +self._fmsg = f +self._fmsgout, self._fmsgerr = _selectmsgdests(self) + def pushbuffer(self, error=False, subproc=False, labeled=False): """install a buffer to capture standard output of the ui object ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5139: store: introduce _matchtrackedpath() and use it to filter store files
yuja added a comment. Can you add the following tests? - encoded filename differs from the original name (e.g. uppercase letter) - fncache disabled, but encodedstore is used > def datafiles(self, matcher=None): > for a, b, size in super(encodedstore, self).datafiles(): > > +if not _matchtrackedpath(a, matcher): > +continue > > try: > a = decodefilename(a) I'm pretty sure it's wrong to pass in an encoded filename to matcher. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5139 To: pulkit, durin42, #hg-reviewers Cc: yuja, mjpieters, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D5139: store: introduce _matchtrackedpath() and use it to filter store files
Can you add the following tests? - encoded filename differs from the original name (e.g. uppercase letter) - fncache disabled, but encodedstore is used > def datafiles(self, matcher=None): > for a, b, size in super(encodedstore, self).datafiles(): > +if not _matchtrackedpath(a, matcher): > +continue > try: > a = decodefilename(a) I'm pretty sure it's wrong to pass in an encoded filename to matcher. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5237: fix: add suboption for configuring execution order of tools
This revision was automatically updated to reflect the committed changes. Closed by commit rHGb9557567cc3f: fix: add suboption for configuring execution order of tools (authored by hooper, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D5237?vs=12473=12477 REVISION DETAIL https://phab.mercurial-scm.org/D5237 AFFECTED FILES hgext/fix.py tests/test-fix.t CHANGE DETAILS diff --git a/tests/test-fix.t b/tests/test-fix.t --- a/tests/test-fix.t +++ b/tests/test-fix.t @@ -165,6 +165,26 @@ [fix] failure = abort + When multiple tools are configured to affect a file, they execute in an order + defined by the :priority suboption. The priority suboption has a default value + of zero for each tool. Tools are executed in order of descending priority. The + execution order of tools with equal priority is unspecified. For example, you + could use the 'sort' and 'head' utilities to keep only the 10 smallest numbers + in a text file by ensuring that 'sort' runs before 'head': + +[fix] +sort:command = sort --numeric-sort +head:command = head --lines=10 +sort:pattern = numbers.txt +head:pattern = numbers.txt +sort:priority = 2 +head:priority = 1 + + To account for changes made by each tool, the line numbers used for + incremental formatting are recomputed before executing the next tool. So, each + tool may see different values for the arguments added by the :linerange + suboption. + list of commands: fix rewrite file content in changesets or working directory @@ -1127,3 +1147,51 @@ first $ cd .. + +The execution order of tools can be controlled. This example doesn't work if +you sort after truncating, but the config defines the correct order while the +definitions are out of order (which might imply the incorrect order given the +implementation of fix). The goal is to use multiple tools to select the lowest +5 numbers in the file. + + $ hg init priorityexample + $ cd priorityexample + + $ cat >> .hg/hgrc < [fix] + > head:command = head --lines=5 + > head:pattern = numbers.txt + > head:priority = 1 + > sort:command = sort --numeric-sort + > sort:pattern = numbers.txt + > sort:priority = 2 + > EOF + + $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt + $ hg add -q + $ hg fix -w + $ cat numbers.txt + 0 + 1 + 2 + 3 + 4 + +And of course we should be able to break this by reversing the execution order. +Test negative priorities while we're at it. + + $ cat >> .hg/hgrc < [fix] + > head:priority = -1 + > sort:priority = -2 + > EOF + $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt + $ hg fix -w + $ cat numbers.txt + 2 + 3 + 6 + 7 + 8 + + $ cd .. diff --git a/hgext/fix.py b/hgext/fix.py --- a/hgext/fix.py +++ b/hgext/fix.py @@ -54,6 +54,24 @@ [fix] failure = abort +When multiple tools are configured to affect a file, they execute in an order +defined by the :priority suboption. The priority suboption has a default value +of zero for each tool. Tools are executed in order of descending priority. The +execution order of tools with equal priority is unspecified. For example, you +could use the 'sort' and 'head' utilities to keep only the 10 smallest numbers +in a text file by ensuring that 'sort' runs before 'head':: + + [fix] + sort:command = sort --numeric-sort + head:command = head --lines=10 + sort:pattern = numbers.txt + head:pattern = numbers.txt + sort:priority = 2 + head:priority = 1 + +To account for changes made by each tool, the line numbers used for incremental +formatting are recomputed before executing the next tool. So, each tool may see +different values for the arguments added by the :linerange suboption. """ from __future__ import absolute_import @@ -100,10 +118,16 @@ configitem = registrar.configitem(configtable) # Register the suboptions allowed for each configured fixer. -FIXER_ATTRS = ('command', 'linerange', 'fileset', 'pattern') +FIXER_ATTRS = { +'command': None, +'linerange': None, +'fileset': None, +'pattern': None, +'priority': 0, +} -for key in FIXER_ATTRS: -configitem('fix', '.*(:%s)?' % key, default=None, generic=True) +for key, default in FIXER_ATTRS.items(): +configitem('fix', '.*(:%s)?' % key, default=default, generic=True) # A good default size allows most source code files to be fixed, but avoids # letting fixer tools choke on huge inputs, which could be surprising to the @@ -602,18 +626,21 @@ Each value is a Fixer object with methods that implement the behavior of the fixer's config suboptions. Does not validate the config values. """ -result = {} +fixers = {} for name in fixernames(ui): -result[name] = Fixer() +fixers[name] = Fixer() attrs = ui.configsuboptions('fix', name)[1] if 'fileset' in attrs and 'pattern' not in attrs: ui.warn(_('the fix.tool:fileset config name
D5242: tests: make the commands.resolve.confirm tests not pollute the test-wide hgrc
This revision was automatically updated to reflect the committed changes. Closed by commit rHGb93157f69f46: tests: make the commands.resolve.confirm tests not pollute the test-wide hgrc (authored by spectral, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D5242?vs=12475=12479 REVISION DETAIL https://phab.mercurial-scm.org/D5242 AFFECTED FILES tests/test-resolve.t CHANGE DETAILS diff --git a/tests/test-resolve.t b/tests/test-resolve.t --- a/tests/test-resolve.t +++ b/tests/test-resolve.t @@ -525,7 +525,7 @@ Test when config option is set: == - $ cat >> $HGRCPATH << EOF + $ cat >> .hg/hgrc << EOF > [ui] > interactive = True > [commands] To: spectral, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5241: tests: fix a couple typos in test-resolve.t comments and add a comment
This revision was automatically updated to reflect the committed changes. Closed by commit rHG8785d66edd6e: tests: fix a couple typos in test-resolve.t comments and add a comment (authored by spectral, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D5241?vs=12474=12478 REVISION DETAIL https://phab.mercurial-scm.org/D5241 AFFECTED FILES tests/test-resolve.t CHANGE DETAILS diff --git a/tests/test-resolve.t b/tests/test-resolve.t --- a/tests/test-resolve.t +++ b/tests/test-resolve.t @@ -435,7 +435,7 @@ $ hg resolve -l R file1 R file2 -Test explicitly setting the otion to 'none' +Test explicitly setting the option to 'none' $ hg resolve --unmark $ hg resolve -l U file1 @@ -583,7 +583,7 @@ R emp3 Test that commands.resolve.confirm respect --unmark option (only when no patterns args are given): -=== += $ hg resolve -u emp1 @@ -613,4 +613,6 @@ $ hg rebase --abort rebase aborted + +Done with commands.resolve.confirm tests: $ cd .. To: spectral, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5243: resolve: fix mark-check when a file was deleted on one side (issue6020)
yuja added a comment. > - with repo.wvfs(f) as fobj: > - fdata = fobj.read() +try: + with repo.wvfs(f) as fobj: +fdata = fobj.read() + except (IOError, OSError) as inst: +if inst.errno != errno.ENOENT: +raise 'fdata' can be undefined here. Appears that the test doesn't go through this case. Perhaps, `wvfs.tryread()` can be used instead. > if filemerge.hasconflictmarkers(fdata) and \ > ms[f] != mergemod.MERGE_RECORD_RESOLVED: > hasconflictmarkers.append(f) REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5243 To: spectral, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D5243: resolve: fix mark-check when a file was deleted on one side (issue6020)
> -with repo.wvfs(f) as fobj: > -fdata = fobj.read() > +try: > +with repo.wvfs(f) as fobj: > +fdata = fobj.read() > +except (IOError, OSError) as inst: > +if inst.errno != errno.ENOENT: > +raise 'fdata' can be undefined here. Appears that the test doesn't go through this case. Perhaps, `wvfs.tryread()` can be used instead. > if filemerge.hasconflictmarkers(fdata) and \ > ms[f] != mergemod.MERGE_RECORD_RESOLVED: > hasconflictmarkers.append(f) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5235: revlog: replace PyInt_AS_LONG with a more portable helper function
yuja added a comment. > @@ -464,7 +470,9 @@ > > if (iter == NULL) > return -2; > while ((iter_item = PyIter_Next(iter))) { > > - iter_item_long = PyInt_AS_LONG(iter_item); + if (!pylong_to_long(iter_item, _item_long)) { + return -1; `Py_DECREF(iter_item)` and `return -2`. I didn't notice it last time, sorry. > + } > > Py_DECREF(iter_item); > if (iter_item_long < min_idx) > min_idx = iter_item_long; REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5235 To: durin42, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D5235: revlog: replace PyInt_AS_LONG with a more portable helper function
> @@ -464,7 +470,9 @@ > if (iter == NULL) > return -2; > while ((iter_item = PyIter_Next(iter))) { > - iter_item_long = PyInt_AS_LONG(iter_item); > + if (!pylong_to_long(iter_item, _item_long)) { > + return -1; `Py_DECREF(iter_item)` and `return -2`. I didn't notice it last time, sorry. > + } > Py_DECREF(iter_item); > if (iter_item_long < min_idx) > min_idx = iter_item_long; ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel