[PATCH STABLE] help: unjumble the list of default config values for `internals.config`

2018-11-08 Thread Matt Harbison
# 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

2018-11-08 Thread hooper (Danny Hooper)
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

2018-11-08 Thread hooper (Danny Hooper)
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

2018-11-08 Thread Yuya Nishihara
# 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

2018-11-08 Thread Yuya Nishihara
# 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

2018-11-08 Thread Yuya Nishihara
# 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

2018-11-08 Thread Yuya Nishihara
# 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

2018-11-08 Thread Yuya Nishihara
# 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

2018-11-08 Thread Yuya Nishihara
# 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

2018-11-08 Thread Yuya Nishihara
# 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

2018-11-08 Thread Yuya Nishihara
# 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

2018-11-08 Thread yuja (Yuya Nishihara)
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

2018-11-08 Thread Yuya Nishihara
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

2018-11-08 Thread hooper (Danny Hooper)
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

2018-11-08 Thread spectral (Kyle Lippincott)
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

2018-11-08 Thread spectral (Kyle Lippincott)
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)

2018-11-08 Thread yuja (Yuya Nishihara)
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)

2018-11-08 Thread Yuya Nishihara
> -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

2018-11-08 Thread yuja (Yuya Nishihara)
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

2018-11-08 Thread Yuya Nishihara
> @@ -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