D3300: fix: port most of the way to python 3

2018-04-13 Thread durin42 (Augie Fackler)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG1edf3738e000: fix: port most of the way to python 3 
(authored by durin42, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3300?vs=8093&id=8108

REVISION DETAIL
  https://phab.mercurial-scm.org/D3300

AFFECTED FILES
  hgext/fix.py

CHANGE DETAILS

diff --git a/hgext/fix.py b/hgext/fix.py
--- a/hgext/fix.py
+++ b/hgext/fix.py
@@ -66,6 +66,7 @@
 mdiff,
 merge,
 obsolete,
+pycompat,
 registrar,
 scmutil,
 util,
@@ -126,6 +127,7 @@
 revisions are not forgotten in later ones. The --base flag can be used to
 override this default behavior, though it is not usually desirable to do 
so.
 """
+opts = pycompat.byteskwargs(opts)
 if opts['all']:
 if opts['rev']:
 raise error.Abort(_('cannot specify both "--rev" and "--all"'))
@@ -513,7 +515,8 @@
 result[name] = Fixer()
 attrs = ui.configsuboptions('fix', name)[1]
 for key in FIXER_ATTRS:
-setattr(result[name], '_' + key, attrs.get(key, ''))
+setattr(result[name], pycompat.sysstr('_' + key),
+attrs.get(key, ''))
 return result
 
 def fixernames(ui):



To: durin42, #hg-reviewers, pulkit
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3252: tests: use `f --newer` instead of `stat -c` in test-fix.t

2018-04-13 Thread yuja (Yuya Nishihara)
yuja added inline comments.

INLINE COMMENTS

> test-fix.t:495
>adding foo.whole
> -  $ OLD_MTIME=`stat -c %Y foo.whole`
> -  $ sleep 1 # mtime has a resolution of one second.
> +  $ cp foo.whole foo.whole.orig
> +  $ sleep 2 # mtime has a resolution of one or two seconds.

Maybe `cp -p` to not increment a few microseconds?

> test-fix.t:499
> +  $ f foo.whole --newer foo.whole.orig
> +  foo.whole: older than foo.whole.orig
>  

This means `mtime(foo.whole) < mtime(foo.whole.orig)`, but we
need to assert `mtime(foo.whole.orig) >= mtime(foo.whole)`.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3252

To: durin42, #hg-reviewers, indygreg
Cc: yuja, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3303: cborutil: implement support for indefinite length CBOR types

2018-04-13 Thread yuja (Yuya Nishihara)
yuja added inline comments.

INLINE COMMENTS

> cborutil.py:73
> +beginindefinitearray(encoder)
> +yield writeitem
> +encoder.write(BREAK)

I don't think yielding `encoder.encode` would make much sense
because an array item can also be a nested indefinite array, in
which case, we can't use `writeitem()`.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3303

To: indygreg, #hg-reviewers
Cc: yuja, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3305: cmdutil: pass in parsed patch to tryimportone() (API)

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGfd1dd79cff20: cmdutil: pass in parsed patch to 
tryimportone() (API) (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3305?vs=8106&id=8110

REVISION DETAIL
  https://phab.mercurial-scm.org/D3305

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py

CHANGE DETAILS

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -3089,9 +3089,11 @@
 
 haspatch = False
 for hunk in patch.split(patchfile):
-(msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
-parents, opts,
-msgs, hg.clean)
+patchdata = patch.extract(ui, hunk)
+
+msg, node, rej = cmdutil.tryimportone(ui, repo, patchdata,
+  parents, opts,
+  msgs, hg.clean)
 if msg:
 haspatch = True
 ui.note(msg + '\n')
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1343,16 +1343,17 @@
 # - ctx: the changectx created by import.
 extrapostimportmap = {}
 
-def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
+def tryimportone(ui, repo, patchdata, parents, opts, msgs, updatefunc):
 """Utility function used by commands.import to import a single patch
 
 This function is explicitly defined here to help the evolve extension to
 wrap this part of the import logic.
 
 The API is currently a bit ugly because it a simple code translation from
 the import command. Feel free to make it better.
 
-:hunk: a patch (as a binary string)
+:patchdata: a dictionary containing parsed patch data (such as from
+``patch.extract()``)
 :parents: nodes that will be parent of the created commit
 :opts: the full dict of option passed to the import command
 :msgs: list to save commit message to.
@@ -1362,15 +1363,15 @@
 """
 # avoid cycle context -> subrepo -> cmdutil
 from . import context
-extractdata = patch.extract(ui, hunk)
-tmpname = extractdata.get('filename')
-message = extractdata.get('message')
-user = opts.get('user') or extractdata.get('user')
-date = opts.get('date') or extractdata.get('date')
-branch = extractdata.get('branch')
-nodeid = extractdata.get('nodeid')
-p1 = extractdata.get('p1')
-p2 = extractdata.get('p2')
+
+tmpname = patchdata.get('filename')
+message = patchdata.get('message')
+user = opts.get('user') or patchdata.get('user')
+date = opts.get('date') or patchdata.get('date')
+branch = patchdata.get('branch')
+nodeid = patchdata.get('nodeid')
+p1 = patchdata.get('p1')
+p2 = patchdata.get('p2')
 
 nocommit = opts.get('no_commit')
 importbranch = opts.get('import_branch')
@@ -1462,7 +1463,7 @@
  **pycompat.strkwargs(opts))
 extra = {}
 for idfunc in extrapreimport:
-extrapreimportmap[idfunc](repo, extractdata, extra, opts)
+extrapreimportmap[idfunc](repo, patchdata, extra, opts)
 overrides = {}
 if partial:
 overrides[('ui', 'allowemptycommit')] = True



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3302: stringutil: support more types with pprint()

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG68132a95df31: stringutil: support more types with pprint() 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3302?vs=8103&id=8109

REVISION DETAIL
  https://phab.mercurial-scm.org/D3302

AFFECTED FILES
  mercurial/utils/stringutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/stringutil.py b/mercurial/utils/stringutil.py
--- a/mercurial/utils/stringutil.py
+++ b/mercurial/utils/stringutil.py
@@ -25,15 +25,23 @@
 
 def pprint(o):
 """Pretty print an object."""
-if isinstance(o, (bytes, bytearray)):
+if isinstance(o, bytes):
 return "b'%s'" % escapestr(o)
+elif isinstance(o, bytearray):
+# codecs.escape_encode() can't handle bytearray, so escapestr fails
+# without coercion.
+return "bytearray['%s']" % escapestr(bytes(o))
 elif isinstance(o, list):
 return '[%s]' % (b', '.join(pprint(a) for a in o))
 elif isinstance(o, dict):
 return '{%s}' % (b', '.join(
 '%s: %s' % (pprint(k), pprint(v)) for k, v in sorted(o.items(
 elif isinstance(o, bool):
 return b'True' if o else b'False'
+elif isinstance(o, int):
+return '%d' % o
+elif isinstance(o, float):
+return '%f' % o
 else:
 raise error.ProgrammingError('do not know how to format %r' % o)
 



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 7 of 9] export: port _exportsingle() to formatter

2018-04-13 Thread Yuya Nishihara
On Thu, 12 Apr 2018 09:51:53 -0700, Gregory Szorc wrote:
> > +if fm.isplain():
> > +chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
> > +for chunk, label in chunkiter:
> > +fm.plain(chunk, label=label)
> > +else:
> > +chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
> > +# TODO: make it structured?
> > +fm.data(diff=b''.join(chunkiter))
> >
> 
> A concern I have is that we'll want to keep the door open for writing the
> diff chunks in a structured manner. That would seemingly require a
> different key for the templater. But I think "diff" is fine as the key that
> means "a textual diff format recognized by most patch tools." We can
> introduce a "diffparts" (or similar) and make "diff" lazily evaluate as
> follow-ups, when needed.

Yes. Since the key "diff" is used by 'log -Tjson -p', we'll have to leave it
as a textual diff.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3306: patch: make extract() a context manager (API)

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG5537d8f5e989: patch: make extract() a context manager (API) 
(authored by indygreg, committed by ).

CHANGED PRIOR TO COMMIT
  https://phab.mercurial-scm.org/D3306?vs=8107&id=8111#toc

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3306?vs=8107&id=8111

REVISION DETAIL
  https://phab.mercurial-scm.org/D3306

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py
  mercurial/patch.py

CHANGE DETAILS

diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -9,6 +9,7 @@
 from __future__ import absolute_import, print_function
 
 import collections
+import contextlib
 import copy
 import difflib
 import email
@@ -192,6 +193,7 @@
   ('Node ID', 'nodeid'),
  ]
 
+@contextlib.contextmanager
 def extract(ui, fileobj):
 '''extract patch from data read from fileobj.
 
@@ -209,6 +211,16 @@
 Any item can be missing from the dictionary. If filename is missing,
 fileobj did not contain a patch. Caller must unlink filename when done.'''
 
+fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
+tmpfp = os.fdopen(fd, r'wb')
+try:
+yield _extract(ui, fileobj, tmpname, tmpfp)
+finally:
+tmpfp.close()
+os.unlink(tmpname)
+
+def _extract(ui, fileobj, tmpname, tmpfp):
+
 # attempt to detect the start of a patch
 # (this heuristic is borrowed from quilt)
 diffre = re.compile(br'^(?:Index:[ \t]|diff[ \t]-|RCS file: |'
@@ -218,86 +230,80 @@
 re.MULTILINE | re.DOTALL)
 
 data = {}
-fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
-tmpfp = os.fdopen(fd, r'wb')
-try:
-msg = pycompat.emailparser().parse(fileobj)
+
+msg = pycompat.emailparser().parse(fileobj)
 
-subject = msg[r'Subject'] and mail.headdecode(msg[r'Subject'])
-data['user'] = msg[r'From'] and mail.headdecode(msg[r'From'])
-if not subject and not data['user']:
-# Not an email, restore parsed headers if any
-subject = '\n'.join(': '.join(map(encoding.strtolocal, h))
-for h in msg.items()) + '\n'
+subject = msg[r'Subject'] and mail.headdecode(msg[r'Subject'])
+data['user'] = msg[r'From'] and mail.headdecode(msg[r'From'])
+if not subject and not data['user']:
+# Not an email, restore parsed headers if any
+subject = '\n'.join(': '.join(map(encoding.strtolocal, h))
+for h in msg.items()) + '\n'
 
-# should try to parse msg['Date']
-parents = []
+# should try to parse msg['Date']
+parents = []
 
-if subject:
-if subject.startswith('[PATCH'):
-pend = subject.find(']')
-if pend >= 0:
-subject = subject[pend + 1:].lstrip()
-subject = re.sub(br'\n[ \t]+', ' ', subject)
-ui.debug('Subject: %s\n' % subject)
-if data['user']:
-ui.debug('From: %s\n' % data['user'])
-diffs_seen = 0
-ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
-message = ''
-for part in msg.walk():
-content_type = pycompat.bytestr(part.get_content_type())
-ui.debug('Content-Type: %s\n' % content_type)
-if content_type not in ok_types:
-continue
-payload = part.get_payload(decode=True)
-m = diffre.search(payload)
-if m:
-hgpatch = False
-hgpatchheader = False
-ignoretext = False
+if subject:
+if subject.startswith('[PATCH'):
+pend = subject.find(']')
+if pend >= 0:
+subject = subject[pend + 1:].lstrip()
+subject = re.sub(br'\n[ \t]+', ' ', subject)
+ui.debug('Subject: %s\n' % subject)
+if data['user']:
+ui.debug('From: %s\n' % data['user'])
+diffs_seen = 0
+ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
+message = ''
+for part in msg.walk():
+content_type = pycompat.bytestr(part.get_content_type())
+ui.debug('Content-Type: %s\n' % content_type)
+if content_type not in ok_types:
+continue
+payload = part.get_payload(decode=True)
+m = diffre.search(payload)
+if m:
+hgpatch = False
+hgpatchheader = False
+ignoretext = False
 
-ui.debug('found patch at byte %d\n' % m.start(0))
-diffs_seen += 1
-cfp = stringio()
-for line in payload[:m.start(0)].splitlines():
-if line.startswith('# HG changeset patch') and not hgpatch:
-ui.debug('patch generated by hg export\n')
-hgpatch = True
-hgpatchheader = T

D3301: fix: use sysstrs for command template formatting

2018-04-13 Thread yuja (Yuya Nishihara)
yuja requested changes to this revision.
yuja added a comment.
This revision now requires changes to proceed.


  sysstr -> sysbytes can't round trip, and `unicode.format(...=bytes)` wouldn't
  work as expected.
  
  Let me check if we can use templater here.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3301

To: durin42, #hg-reviewers, yuja
Cc: yuja, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 4 V3] revset: disable compat with legacy compat for internal revsets API (API)

2018-04-13 Thread Feld Boris

On 11/04/2018 17:23, Yuya Nishihara wrote:

On Wed, 11 Apr 2018 11:50:15 +0200, Boris Feld wrote:

# HG changeset patch
# User Boris Feld 
# Date 1520412972 18000
#  Wed Mar 07 03:56:12 2018 -0500
# Node ID 00090d394d4e0a7c2637f161493353530dcf739d
# Parent  5c1a0d784a26d4e8659dcec80503c8764432a303
# EXP-Topic noname
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
00090d394d4e
revset: disable compat with legacy compat for internal revsets API (API)

In theory, there should be no user input going directly to "repo.revs" and
"repo.set" so we can adjust the behavior in all cases. Avoiding name lookup
during revsets parsing provide important speedup when some namespaces are slow
to load.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -832,7 +832,7 @@ class localrepository(object):
  that contains integer revisions.
  '''
  expr = revsetlang.formatspec(expr, *args)
-m = revset.match(None, expr)
+m = revset.match(None, expr, legacycompat=False)
  return m(self)
-def matchany(ui, specs, repo=None, localalias=None):
+def matchany(ui, specs, repo=None, localalias=None, legacycompat=True):
  """Create a matcher that will include any revisions matching one of the
  given specs
  
@@ -2191,7 +2191,7 @@ def matchany(ui, specs, repo=None, local

  if not all(specs):
  raise error.ParseError(_("empty query"))
  lookup = None
-if repo:
+if repo and legacycompat:
  lookup = lookupfn(repo)

So legacycompat=False is identical to repo=None?


Almost, there is also the `posttreebuilthook` hook that takes repo as a 
parameter.


It is (was?) used at least by the directaccess extension.

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 4 V3] revset: disable compat with legacy compat for internal revsets API (API)

2018-04-13 Thread Yuya Nishihara
On Fri, 13 Apr 2018 14:53:57 +0200, Feld Boris wrote:
> On 11/04/2018 17:23, Yuya Nishihara wrote:
> > On Wed, 11 Apr 2018 11:50:15 +0200, Boris Feld wrote:
> >> # HG changeset patch
> >> # User Boris Feld 
> >> # Date 1520412972 18000
> >> #  Wed Mar 07 03:56:12 2018 -0500
> >> # Node ID 00090d394d4e0a7c2637f161493353530dcf739d
> >> # Parent  5c1a0d784a26d4e8659dcec80503c8764432a303
> >> # EXP-Topic noname
> >> # Available At https://bitbucket.org/octobus/mercurial-devel/
> >> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
> >> 00090d394d4e
> >> revset: disable compat with legacy compat for internal revsets API (API)
> >>
> >> In theory, there should be no user input going directly to "repo.revs" and
> >> "repo.set" so we can adjust the behavior in all cases. Avoiding name lookup
> >> during revsets parsing provide important speedup when some namespaces are 
> >> slow
> >> to load.
> >>
> >> diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
> >> --- a/mercurial/localrepo.py
> >> +++ b/mercurial/localrepo.py
> >> @@ -832,7 +832,7 @@ class localrepository(object):
> >>   that contains integer revisions.
> >>   '''
> >>   expr = revsetlang.formatspec(expr, *args)
> >> -m = revset.match(None, expr)
> >> +m = revset.match(None, expr, legacycompat=False)
> >>   return m(self)
> >> -def matchany(ui, specs, repo=None, localalias=None):
> >> +def matchany(ui, specs, repo=None, localalias=None, legacycompat=True):
> >>   """Create a matcher that will include any revisions matching one of 
> >> the
> >>   given specs
> >>   
> >> @@ -2191,7 +2191,7 @@ def matchany(ui, specs, repo=None, local
> >>   if not all(specs):
> >>   raise error.ParseError(_("empty query"))
> >>   lookup = None
> >> -if repo:
> >> +if repo and legacycompat:
> >>   lookup = lookupfn(repo)
> > So legacycompat=False is identical to repo=None?
> 
> Almost, there is also the `posttreebuilthook` hook that takes repo as a 
> parameter.

Got it. Then, can you rephrase the commit message? The legacy lookup is
disabled for internal API from the beginning.

> It is (was?) used at least by the directaccess extension.

Pulkit, do we still need the posttreebuildhook? I think the only user was
the directaccess, and it's in core.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] dispatch: add a whitelist map of commands to implicitly loaded extensions

2018-04-13 Thread Yuya Nishihara
On Thu, 12 Apr 2018 13:35:50 -0400, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison 
> # Date 1523332699 14400
> #  Mon Apr 09 23:58:19 2018 -0400
> # Node ID 986b51f15e9bce19b2f67573ff76612540320d1b
> # Parent  2e0e61312a257708a70201427b31deba964e9b05
> dispatch: add a whitelist map of commands to implicitly loaded extensions
> 
> This was Augie's idea[1] (or at least my interpretation of it).  The goal is 
> to
> be able to load the lfs extension without user intervention where it is both
> harmless, and provides a user convenience.  The referenced thread discusses 
> the
> clone command and the cryptic error around that in some cases.  But the 
> obvious
> benefit is to be able transparently support cloning an lfs repository, or the
> sudden transition to lfs on a pull, without bothering the user.  The choice to
> use the lfs extension in the repository has already been made in both cases at
> that point, and neither command can accidentally introduce the feature.
> 
> The implementation is perhaps a bit more than imagined in the thread, because 
> I
> think there may be room to allow extensions like 'share' to force lfs on too, 
> in
> order to make the extension usage more invisible.  The largefiles extension
> could probably be given the same treatment.  For simplicity, I didn't bother
> allowing external extensions to be loadable like this.  The mechanism used 
> here
> was pilfered from acl.ensureenabled().
> 
> [1] 
> https://www.mercurial-scm.org/pipermail/mercurial-devel/2018-January/109851.html
> 
> diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
> --- a/mercurial/dispatch.py
> +++ b/mercurial/dispatch.py
> @@ -48,6 +48,15 @@ from .utils import (
>  
>  unrecoverablewrite = registrar.command.unrecoverablewrite
>  
> +# Map a command to a list of extensions that are forced on prior to running 
> the
> +# command (unless it has been explicitly disabled.)  The idea is to help the
> +# user by enabling extensions implicitly when requirements may be added by a
> +# remote exchange, instead of erroring out after a partial exchange.
> +extensionwhitelist = {
> +commands.clone: ['lfs'],
> +commands.pull: ['lfs'],
> +}

Perhaps we can't use a command function as key since it may be wrapped by
extensions.

>  class request(object):
>  def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
>   ferr=None, prereposetups=None):
> @@ -843,6 +852,20 @@ def _dispatch(req):
>  fullargs = args
>  cmd, func, args, options, cmdoptions = _parse(lui, args)
>  
> +# resolve aliases back to the core function
> +entrypoint = func
> +if isinstance(entrypoint, cmdalias):
> +entrypoint = entrypoint.fn
> +
> +if entrypoint in extensionwhitelist:
> +configured = [ext for (ext, _path) in 
> ui.configitems("extensions")]
> +missing = [ext for ext in extensionwhitelist[entrypoint]
> +   if ext not in configured]
> +for ext in missing:
> +ui.setconfig('extensions', ext, '', source='internal')
> +if missing:
> +extensions.loadall(ui, missing)

I'm -1 on this because loading extra Python module isn't always instant, and
the loaded extension persists forever, which can be a problem for command-server
process.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3279: py3: make sure decode() first argument is str

2018-04-13 Thread pulkit (Pulkit Goyal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGbfdd20d22a86: py3: make sure decode() first argument is str 
(authored by pulkit, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3279?vs=8046&id=8112

REVISION DETAIL
  https://phab.mercurial-scm.org/D3279

AFFECTED FILES
  hgext/convert/common.py

CHANGE DETAILS

diff --git a/hgext/convert/common.py b/hgext/convert/common.py
--- a/hgext/convert/common.py
+++ b/hgext/convert/common.py
@@ -217,12 +217,13 @@
 if isinstance(s, unicode):
 return s.encode("utf-8")
 try:
-return s.decode(encoding).encode("utf-8")
+return s.decode(pycompat.sysstr(encoding)).encode("utf-8")
 except UnicodeError:
 try:
 return s.decode("latin-1").encode("utf-8")
 except UnicodeError:
-return s.decode(encoding, "replace").encode("utf-8")
+return s.decode(pycompat.sysstr(encoding),
+"replace").encode("utf-8")
 
 def getchangedfiles(self, rev, i):
 """Return the files changed by rev compared to parent[i].



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] dispatch: add a whitelist map of commands to implicitly loaded extensions

2018-04-13 Thread Matt Harbison

> On Apr 13, 2018, at 9:11 AM, Yuya Nishihara  wrote:
> 
>> On Thu, 12 Apr 2018 13:35:50 -0400, Matt Harbison wrote:
>> # HG changeset patch
>> # User Matt Harbison 
>> # Date 1523332699 14400
>> #  Mon Apr 09 23:58:19 2018 -0400
>> # Node ID 986b51f15e9bce19b2f67573ff76612540320d1b
>> # Parent  2e0e61312a257708a70201427b31deba964e9b05
>> dispatch: add a whitelist map of commands to implicitly loaded extensions
> 
>> class request(object):
>> def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
>>  ferr=None, prereposetups=None):
>> @@ -843,6 +852,20 @@ def _dispatch(req):
>> fullargs = args
>> cmd, func, args, options, cmdoptions = _parse(lui, args)
>> 
>> +# resolve aliases back to the core function
>> +entrypoint = func
>> +if isinstance(entrypoint, cmdalias):
>> +entrypoint = entrypoint.fn
>> +
>> +if entrypoint in extensionwhitelist:
>> +configured = [ext for (ext, _path) in 
>> ui.configitems("extensions")]
>> +missing = [ext for ext in extensionwhitelist[entrypoint]
>> +   if ext not in configured]
>> +for ext in missing:
>> +ui.setconfig('extensions', ext, '', source='internal')
>> +if missing:
>> +extensions.loadall(ui, missing)
> 
> I'm -1 on this because loading extra Python module isn't always instant, and
> the loaded extension persists forever, which can be a problem for 
> command-server
> process.

Good point. Any alternate ideas?  I wasn’t sure what the bundlepart idea would 
look like, because presumably this needs to be loaded pretty early in the 
startup process.

One thing I like about this is the user doesn’t have to do anything to switch.  
I can send out an email saying “upgrade to 4.6”, convert on the server, and 
nothing changes for the developer. Otherwise, everyone has to enable the 
extension in their user settings, or alias clone and pull to enable it anyway.

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 2 V2] revset: skip old style lookup if external whitespace are detected

2018-04-13 Thread Feld Boris

On 12/04/2018 13:09, Yuya Nishihara wrote:

On Thu, 12 Apr 2018 11:32:23 +0200, Feld Boris wrote:

On 11/04/2018 17:16, Yuya Nishihara wrote:

On Wed, 11 Apr 2018 11:36:05 +0200, Feld Boris wrote:

The proposal here is to define a prefix for which we break backward
compatibility. If we do so, people with a "" label will have to use:

  "":whatever

to get a similar effect.

IIRC x:y was the most important syntax that needed a strong BC guarantee, so
this proposal doesn't sound good.

Indeed, the `x:y` is important and we don't want to break the BC
guarantee of it.

The proposal is less impacting, only people using 'set' as labels and
using it at the beginning of a revsetwould be impacted. This prefix has
the advantage of being concise and coherent with whatfilesetuse.

Doesn't '-r set:foo' look like a range?

I don't like an idea of introducing another ambiguous syntax to resolve
ambiguity, but furthermore "set:foo" seems confusing to humans.

IIUC, we have "set:" for filesets only because that's the syntax to specify
file patterns. If we really want to add something to force revset evaluation,
I think it has to be compatible with the current syntax, such as "(EXPR)" or
"revset(EXPR)".

`(EXPR)` seemtoo likely to introduce a BC breakage, as people are more
likely to have a tag that looks like `(xxx)` than a 'set' tag IMHO.

Ugh, I never assumed that would actually happen, but since you face to more
real users having various backgrounds than me, I might be wrong.


In a previous discussion, you pointed out that `revset(EXPR)` would be
painful because we would have to escape everything within EXPR. What
makes you consider it again? Do you mean that if a revset has this form
`revset((.*))`; we just evaluate the contents inside parenthesis?

My proposal is 'revset(EXPR)', not 'revset("EXPR")'. It's an identity function
similar to present(), but also disables the legacy lookup. I don't wanna add
such magic, but 'revset(EXPR)' seems less bad than 'set:EXPR' or ' EXPR'.


Agreed that `set:foo` looks like a range, maybe we need to use a less
ambiguous operator?

`=foo+bar`
`#foo+bar`
`#revset# foo+bar`

(Nothing really stands out as pretty, but trying to extend our search
area here.)

Yeah, they look weird.

FWIW, I prefer not reviewing this sort of patches just before the freeze.
The patch itself is simple, but we have to carefully think about UX and
syntactic consistency.


We love the 'revset(EXPR)' idea and we have a v4 series that is ready to 
send.


It is okay to send it before the freeze? If not, would it be possible to 
take the first two changesets of the V3 series? They will likely bring 
some speed improvements for big repositories where name lookups are slow 
and for commands that don't need to load them.



___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3307: context: set stack level for deprecation warning

2018-04-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This patch makes the deprecation warning print the caller of
  repo.__getitem__. That's not quite correct, since there could also be
  other callers of changectx.__init__, but it seems like the most
  helpful stack level in practice.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3307

AFFECTED FILES
  mercurial/context.py

CHANGE DETAILS

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -399,7 +399,7 @@
 #  * If "x" can be a mix of the above, you'll have to figure it out
 #yourself
 repo.ui.deprecwarn("changectx.__init__ is getting more limited, see source 
"
-   "for details", "4.6")
+   "for details", "4.6", stacklevel=4)
 
 class changectx(basectx):
 """A changecontext object makes access to data related to a particular



To: martinvonz, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


mercurial@37493: 112 new changesets

2018-04-13 Thread Mercurial Commits
112 new changesets in mercurial:

https://www.mercurial-scm.org/repo/hg/rev/de9f9f888900
changeset:   37382:de9f9f888900
user:Augie Fackler 
date:Thu Apr 05 10:13:01 2018 -0400
summary: util: whitelist apfs for hardlink support

... 110 changesets not listed ...

https://www.mercurial-scm.org/repo/hg/rev/f1413e4a54a6
changeset:   37493:f1413e4a54a6
bookmark:@
tag: tip
user:Anton Shestakov 
date:Wed Apr 04 13:14:48 2018 +0800
summary: paper: make all source lines have the same minimum height

-- 
Repository URL: https://www.mercurial-scm.org/repo/hg
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3267: repository: define new interface for running commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg planned changes to this revision.
indygreg added a comment.


  I'll be making small revisions to the interface docs and implementation.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3267

To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 2 V2] revset: skip old style lookup if external whitespace are detected

2018-04-13 Thread Feld Boris


On 13/04/2018 15:48, Feld Boris wrote:

On 12/04/2018 13:09, Yuya Nishihara wrote:

On Thu, 12 Apr 2018 11:32:23 +0200, Feld Boris wrote:

On 11/04/2018 17:16, Yuya Nishihara wrote:

On Wed, 11 Apr 2018 11:36:05 +0200, Feld Boris wrote:

The proposal here is to define a prefix for which we break backward
compatibility. If we do so, people with a "" label will have to use:

  "":whatever

to get a similar effect.

IIRC x:y was the most important syntax that needed a strong BC guarantee, so
this proposal doesn't sound good.

Indeed, the `x:y` is important and we don't want to break the BC
guarantee of it.

The proposal is less impacting, only people using 'set' as labels and
using it at the beginning of a revsetwould be impacted. This prefix has
the advantage of being concise and coherent with whatfilesetuse.

Doesn't '-r set:foo' look like a range?

I don't like an idea of introducing another ambiguous syntax to resolve
ambiguity, but furthermore "set:foo" seems confusing to humans.

IIUC, we have "set:" for filesets only because that's the syntax to specify
file patterns. If we really want to add something to force revset evaluation,
I think it has to be compatible with the current syntax, such as "(EXPR)" or
"revset(EXPR)".

`(EXPR)` seemtoo likely to introduce a BC breakage, as people are more
likely to have a tag that looks like `(xxx)` than a 'set' tag IMHO.

Ugh, I never assumed that would actually happen, but since you face to more
real users having various backgrounds than me, I might be wrong.


In a previous discussion, you pointed out that `revset(EXPR)` would be
painful because we would have to escape everything within EXPR. What
makes you consider it again? Do you mean that if a revset has this form
`revset((.*))`; we just evaluate the contents inside parenthesis?

My proposal is 'revset(EXPR)', not 'revset("EXPR")'. It's an identity function
similar to present(), but also disables the legacy lookup. I don't wanna add
such magic, but 'revset(EXPR)' seems less bad than 'set:EXPR' or ' EXPR'.


Agreed that `set:foo` looks like a range, maybe we need to use a less
ambiguous operator?

`=foo+bar`
`#foo+bar`
`#revset# foo+bar`

(Nothing really stands out as pretty, but trying to extend our search
area here.)

Yeah, they look weird.

FWIW, I prefer not reviewing this sort of patches just before the freeze.
The patch itself is simple, but we have to carefully think about UX and
syntactic consistency.


We love the 'revset(EXPR)' idea and we have a v4 series that is ready 
to send.


It is okay to send it before the freeze? If not, would it be possible 
to take the first two changesets of the V3 series? They will likely 
bring some speed improvements for big repositories where name lookups 
are slow and for commands that don't need to load them.


By re-reading your comments on the V3 series, I realized that the second 
changeset is not necessary since repo is never passed for internal lookup


I will update the series and prepare a new V4.




___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel




___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3308: scmutil: document that isrevsymbol() raises on ambiguous node prefix

2018-04-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3308

AFFECTED FILES
  mercurial/scmutil.py

CHANGE DETAILS

diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -444,6 +444,11 @@
 return node
 
 def isrevsymbol(repo, symbol):
+"""Checks if a symbol exists in the repo.
+
+   See revsymbol() for details. Raises error.LookupError if the symbol is 
an
+   an ambiguous nodeid prefix.
+"""
 try:
 revsymbol(repo, symbol)
 return True



To: martinvonz, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3310: scmutil: use resolvepartialhexnodeid() from revsymbol()

2018-04-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  I should have copied this from changectx.__init__ into in 
https://phab.mercurial-scm.org/rHG35b34202dd3b2effc6e5ff5a82f911825a9cf532
  (context: handle partial nodeids in revsymbol(), 2018-04-08).

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3310

AFFECTED FILES
  mercurial/scmutil.py

CHANGE DETAILS

diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -503,7 +503,7 @@
 except KeyError:
 pass
 
-node = repo.unfiltered().changelog._partialmatch(symbol)
+node = resolvehexnodeidprefix(repo, symbol)
 if node is not None:
 rev = repo.changelog.rev(node)
 return repo[rev]



To: martinvonz, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3313: scmutil: make shortesthexnodeidprefix() use unfiltered repo

2018-04-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Both callers were doing this, and resolvehexnodeidprefix() was also
  working on the unfiltered repo, so it makes more sense to have it all
  in one place.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3313

AFFECTED FILES
  hgext/show.py
  mercurial/scmutil.py
  mercurial/templatefuncs.py

CHANGE DETAILS

diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py
--- a/mercurial/templatefuncs.py
+++ b/mercurial/templatefuncs.py
@@ -587,11 +587,8 @@
 # i18n: "shortest" is a keyword
 _("shortest() expects an integer minlength"))
 
-# _partialmatch() of filtered changelog could take O(len(repo)) time,
-# which would be unacceptably slow. so we look for hash collision in
-# unfiltered space, which means some hashes may be slightly longer.
 repo = context.resource(mapping, 'ctx')._repo
-return scmutil.shortesthexnodeidprefix(repo.unfiltered(), node, minlength)
+return scmutil.shortesthexnodeidprefix(repo, node, minlength)
 
 @templatefunc('strip(text[, chars])')
 def strip(context, mapping, args):
diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -436,16 +436,19 @@
 
 def resolvehexnodeidprefix(repo, prefix):
 # Uses unfiltered repo because it's faster when prefix is ambiguous/
-# This matches the "shortest" template function.
+# This matches the shortesthexnodeidprefix() function below.
 node = repo.unfiltered().changelog._partialmatch(prefix)
 if node is None:
 return
 repo.changelog.rev(node)  # make sure node isn't filtered
 return node
 
 def shortesthexnodeidprefix(repo, hexnode, minlength=1):
 """Find the shortest unambiguous prefix that matches hexnode."""
-cl = repo.changelog
+# _partialmatch() of filtered changelog could take O(len(repo)) time,
+# which would be unacceptably slow. so we look for hash collision in
+# unfiltered space, which means some hashes may be slightly longer.
+cl = repo.unfiltered().changelog
 def isvalid(test):
 try:
 if cl._partialmatch(test) is None:
diff --git a/hgext/show.py b/hgext/show.py
--- a/hgext/show.py
+++ b/hgext/show.py
@@ -447,10 +447,8 @@
 """
 if not revs:
 return minlen
-# don't use filtered repo because it's slow. see templater.shortest().
 cl = repo.changelog
-return max(len(scmutil.shortesthexnodeidprefix(repo.unfiltered(),
-   hex(cl.node(r)),
+return max(len(scmutil.shortesthexnodeidprefix(repo, hex(cl.node(r)),
minlen)) for r in revs)
 
 # Adjust the docstring of the show command so it shows all registered views.



To: martinvonz, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3311: revset: use resolvehexnodeidprefix() in id() predicate (BC)

2018-04-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  We now have a public method for this purpose, so we don't need to
  access the private revlog._partialmatch(). Also, I'll probably make
  some changes to resolvehexnodeidprefix() later, and I want those to be
  reflected by the id() predicate.
  
  Note that this breaks a test case, because we now resolve the prefix
  in the unfiltered repo and get an ambiguous lookup. The test case was
  already documented to be broken even though it wasn't. The new
  behavior is more consistent: now "hg co ffb" and "hg co 'id(ffb)'"
  behaves the same. We should fix both of them at once later instead.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3311

AFFECTED FILES
  mercurial/revset.py
  tests/test-revset.t

CHANGE DETAILS

diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -1878,7 +1878,8 @@
   [255]
 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
   $ hg debugrevspec '0:wdir() & id(fffb)'
-  2
+  abort: 00changelog.i@fffb: ambiguous identifier!
+  [255]
   $ hg debugrevspec '0:wdir() & 8'
   4
   $ hg debugrevspec '0:wdir() & f'
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1333,7 +1333,7 @@
 else:
 rn = None
 try:
-pm = repo.changelog._partialmatch(n)
+pm = scmutil.resolvehexnodeidprefix(repo, n)
 if pm is not None:
 rn = repo.changelog.rev(pm)
 except error.WdirUnsupported:



To: martinvonz, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3309: scmutil: rename resolvepartialhexnodeid() to resolvehexnodeidprefix()

2018-04-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz created this revision.
Herald added a reviewer: durin42.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  I'm going to move revlog.shortest() to scmutil. I plan on calling it
  shortesthexnodeidprefix(). resolvehexnodeidprefix() matches that
  better. Also, "prefix" carries more information than "partial".

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3309

AFFECTED FILES
  hgext/eol.py
  hgext/histedit.py
  mercurial/context.py
  mercurial/scmutil.py

CHANGE DETAILS

diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -434,8 +434,8 @@
 hexfunc = short
 return '%d:%s' % (rev, hexfunc(node))
 
-def resolvepartialhexnodeid(repo, prefix):
-# Uses unfiltered repo because it's faster when then prefix is ambiguous/
+def resolvehexnodeidprefix(repo, prefix):
+# Uses unfiltered repo because it's faster when prefix is ambiguous/
 # This matches the "shortest" template function.
 node = repo.unfiltered().changelog._partialmatch(prefix)
 if node is None:
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -392,7 +392,7 @@
 #  * If you know that "x" is a branch or in some other namespace,
 #use the appropriate mechanism for that namespace
 #  * If you know that "x" is a hex nodeid prefix, use
-#repo[scmutil.resolvepartialhexnodeid(repo, x)]
+#repo[scmutil.resolvehexnodeidprefix(repo, x)]
 #  * If "x" is a string that can be any of the above, but you don't want
 #to allow general revsets (perhaps because "x" may come from a remote
 #user and the revset may be too costly), use scmutil.revsymbol(repo, x)
@@ -476,7 +476,7 @@
 except KeyError:
 pass
 
-self._node = scmutil.resolvepartialhexnodeid(repo, changeid)
+self._node = scmutil.resolvehexnodeidprefix(repo, changeid)
 if self._node is not None:
 self._rev = repo.changelog.rev(self._node)
 changectxdeprecwarn(repo)
diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -443,7 +443,7 @@
 """ Verifies semantic correctness of the rule"""
 repo = self.repo
 ha = node.hex(self.node)
-self.node = scmutil.resolvepartialhexnodeid(repo, ha)
+self.node = scmutil.resolvehexnodeidprefix(repo, ha)
 if self.node is None:
 raise error.ParseError(_('unknown changeset %s listed') % ha[:12])
 self._verifynodeconstraints(prev, expected, seen)
diff --git a/hgext/eol.py b/hgext/eol.py
--- a/hgext/eol.py
+++ b/hgext/eol.py
@@ -300,7 +300,7 @@
 hook = checkheadshook
 
 def preupdate(ui, repo, hooktype, parent1, parent2):
-p1node = scmutil.resolvepartialhexnodeid(repo, parent1)
+p1node = scmutil.resolvehexnodeidprefix(repo, parent1)
 repo.loadeol([p1node])
 return False
 



To: martinvonz, durin42, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3312: revlog: move shortest() to scmutil.shortesthexnodeidprefix() (API)

2018-04-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz created this revision.
Herald added a reviewer: indygreg.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  I apparently moved this function from templater.py in 
https://phab.mercurial-scm.org/rHG448725a2ef7356524bcc9638a5c5eaaf59f263af
  (templater: extract shortest() logic from template function,
  2017-09-15). Now we have scmutil.resolvehexnodeidprefix(), so it makes
  sense to have this method next to it.
  
  Note that the change in show.py also makes it so the conversion from
  revnum to nodeid is done on the filtered repo, but that should be
  inconsequential since the revs are all from the filtered repo anyway.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3312

AFFECTED FILES
  hgext/show.py
  mercurial/revlog.py
  mercurial/scmutil.py
  mercurial/templatefuncs.py

CHANGE DETAILS

diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py
--- a/mercurial/templatefuncs.py
+++ b/mercurial/templatefuncs.py
@@ -590,8 +590,8 @@
 # _partialmatch() of filtered changelog could take O(len(repo)) time,
 # which would be unacceptably slow. so we look for hash collision in
 # unfiltered space, which means some hashes may be slightly longer.
-cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog
-return cl.shortest(node, minlength)
+repo = context.resource(mapping, 'ctx')._repo
+return scmutil.shortesthexnodeidprefix(repo.unfiltered(), node, minlength)
 
 @templatefunc('strip(text[, chars])')
 def strip(context, mapping, args):
diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -443,6 +443,46 @@
 repo.changelog.rev(node)  # make sure node isn't filtered
 return node
 
+def shortesthexnodeidprefix(repo, hexnode, minlength=1):
+"""Find the shortest unambiguous prefix that matches hexnode."""
+cl = repo.changelog
+def isvalid(test):
+try:
+if cl._partialmatch(test) is None:
+return False
+
+try:
+i = int(test)
+# if we are a pure int, then starting with zero will not be
+# confused as a rev; or, obviously, if the int is larger
+# than the value of the tip rev
+if test[0] == '0' or i > len(cl):
+return True
+return False
+except ValueError:
+return True
+except error.RevlogError:
+return False
+except error.WdirUnsupported:
+# single 'ff...' match
+return True
+
+shortest = hexnode
+startlength = max(6, minlength)
+length = startlength
+while True:
+test = hexnode[:length]
+if isvalid(test):
+shortest = test
+if length == minlength or length > startlength:
+return shortest
+length -= 1
+else:
+length += 1
+if len(shortest) <= length:
+return shortest
+
+
 def isrevsymbol(repo, symbol):
 """Checks if a symbol exists in the repo.
 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1500,44 +1500,6 @@
 
 raise LookupError(id, self.indexfile, _('no match found'))
 
-def shortest(self, hexnode, minlength=1):
-"""Find the shortest unambiguous prefix that matches hexnode."""
-def isvalid(test):
-try:
-if self._partialmatch(test) is None:
-return False
-
-try:
-i = int(test)
-# if we are a pure int, then starting with zero will not be
-# confused as a rev; or, obviously, if the int is larger
-# than the value of the tip rev
-if test[0] == '0' or i > len(self):
-return True
-return False
-except ValueError:
-return True
-except error.RevlogError:
-return False
-except error.WdirUnsupported:
-# single 'ff...' match
-return True
-
-shortest = hexnode
-startlength = max(6, minlength)
-length = startlength
-while True:
-test = hexnode[:length]
-if isvalid(test):
-shortest = test
-if length == minlength or length > startlength:
-return shortest
-length -= 1
-else:
-length += 1
-if len(shortest) <= length:
-return shortest
-
 def cmp(self, node, text):
 """compare text with a given file revision
 
diff --git a/hgext/show.py b/hgext/show.py
--- a/hgext/show.py
+++ b/hgext/show.py
@@ -45,6 +45,7 @@
 registrar,
 revset,
 revset

Re: [PATCH 2 of 4 V3] revset: disable compat with legacy compat for internal revsets API (API)

2018-04-13 Thread Pulkit Goyal
On Fri, Apr 13, 2018 at 6:33 PM, Yuya Nishihara  wrote:

> > It is (was?) used at least by the directaccess extension.
>
> Pulkit, do we still need the posttreebuildhook? I think the only user was
> the directaccess, and it's in core.
>

​Nope, we don't need that as far as directaccess is concerned.​
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3312: revlog: move shortest() to scmutil.shortesthexnodeidprefix() (API)

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  I haven't looked at the patch yet, but I also wrote something like this as 
part of storage refactors. IMO the shortest node logic has no business being on 
the generic revlog implementation. I never submitted that patch since removing 
filelog's inheritance of revlog worked around the problem for me.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3312

To: martinvonz, indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] dispatch: add a whitelist map of commands to implicitly loaded extensions

2018-04-13 Thread Gregory Szorc
On Fri, Apr 13, 2018 at 6:35 AM, Matt Harbison 
wrote:

>
> > On Apr 13, 2018, at 9:11 AM, Yuya Nishihara  wrote:
> >
> >> On Thu, 12 Apr 2018 13:35:50 -0400, Matt Harbison wrote:
> >> # HG changeset patch
> >> # User Matt Harbison 
> >> # Date 1523332699 14400
> >> #  Mon Apr 09 23:58:19 2018 -0400
> >> # Node ID 986b51f15e9bce19b2f67573ff76612540320d1b
> >> # Parent  2e0e61312a257708a70201427b31deba964e9b05
> >> dispatch: add a whitelist map of commands to implicitly loaded
> extensions
> >
> >> class request(object):
> >> def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
> >>  ferr=None, prereposetups=None):
> >> @@ -843,6 +852,20 @@ def _dispatch(req):
> >> fullargs = args
> >> cmd, func, args, options, cmdoptions = _parse(lui, args)
> >>
> >> +# resolve aliases back to the core function
> >> +entrypoint = func
> >> +if isinstance(entrypoint, cmdalias):
> >> +entrypoint = entrypoint.fn
> >> +
> >> +if entrypoint in extensionwhitelist:
> >> +configured = [ext for (ext, _path) in
> ui.configitems("extensions")]
> >> +missing = [ext for ext in extensionwhitelist[entrypoint]
> >> +   if ext not in configured]
> >> +for ext in missing:
> >> +ui.setconfig('extensions', ext, '', source='internal')
> >> +if missing:
> >> +extensions.loadall(ui, missing)
> >
> > I'm -1 on this because loading extra Python module isn't always instant,
> and
> > the loaded extension persists forever, which can be a problem for
> command-server
> > process.
>
> Good point. Any alternate ideas?  I wasn’t sure what the bundlepart idea
> would look like, because presumably this needs to be loaded pretty early in
> the startup process.
>
> One thing I like about this is the user doesn’t have to do anything to
> switch.  I can send out an email saying “upgrade to 4.6”, convert on the
> server, and nothing changes for the developer. Otherwise, everyone has to
> enable the extension in their user settings, or alias clone and pull to
> enable it anyway.
>

I want to add a "capabilities" mechanism to hg.peer() and hg.repository()
that makes the caller declare what features the returned repository must
have. This would allow callers to say things like "I only want a read-only
repo," "I need to be able to speak wire protocol command X," etc. These
capabilities would get passed down to the localrepo or peer layers for
evaluation, where they may result in the constructed instance being a
different type, having a different composition of methods, etc. This may
seem orthogonal to command dispatch. However, I would eventually like
@command's to self-declare what features they need. e.g. `log` would say it
needs a read-only repository. `update` would say it needs a repository with
a working directory. `commit` would say it needs a mutable repository. A
command to update the narrow profile would require a repository type that
can be narrowed. And the list goes on.

For your immediate use case, getting the extension tie-ins could be
difficult. Obviously the extension needs to be loaded in order for the
extension to declare a "capability" for a requested repo/peer instance.

What we may want instead is to key things off .hg/requires or a
to-be-invented supplemental requirements-like file that declares soft
features. localrepository.__init__ could then load trusted extensions at
repo open time if a requirements/capability was present/requested. i.e. if
you talk to an LFS server, write a semaphore somewhere into .hg/ and have
something in core look for that and automatically load lfs if present. This
would get you the "automatically enable LFS when talking to LFS servers"
benefits. Alternatively, you could move the client pieces of LFS into core
so no extension loading is needed. That may still require a semaphore
somewhere. I think that's the best long-term behavior. But I think we
should shore up the storage interfaces and figure out the narrow/partial
clone integration story before we do that. Maybe much of this work has
already been done?
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3267: repository: define new interface for running commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8120.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3267?vs=8033&id=8120

REVISION DETAIL
  https://phab.mercurial-scm.org/D3267

AFFECTED FILES
  mercurial/repository.py

CHANGE DETAILS

diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -196,6 +196,88 @@
 def changegroupsubset(bases, heads, kind):
 pass
 
+class ipeercommandexecutor(zi.Interface):
+"""Represents a mechanism to execute remote commands.
+
+This is the primary interface for requesting that wire protocol commands
+be executed. Instances of this interface are active in a context manager
+and have a well-defined lifetime. When the context manager exits, all
+outstanding requests are waited on.
+"""
+
+def callcommand(name, args):
+"""Request that a named command be executed.
+
+Receives the command name and a dictionary of command arguments.
+
+Returns a ``concurrent.futures.Future`` that will resolve to the
+result of that command request. That exact value is left up to
+the implementation and possibly varies by command.
+
+Not all commands can coexist with other commands in an executor
+instance: it depends on the underlying wire protocol transport being
+used and the command itself.
+
+Implementations MAY call ``sendcommands()`` automatically if the
+requested command can not coexist with other commands in this executor.
+
+Implementations MAY call ``sendcommands()`` automatically when the
+future's ``result()`` is called. So, consumers using multiple
+commands with an executor MUST ensure that ``result()`` is not called
+until all command requests have been issued.
+"""
+
+def sendcommands():
+"""Trigger submission of queued command requests.
+
+Not all transports submit commands as soon as they are requested to
+run. When called, this method forces queued command requests to be
+issued. It will no-op if all commands have already been sent.
+
+When called, no more new commands may be issued with this executor.
+"""
+
+def close():
+"""Signal that this command request is finished.
+
+When called, no more new commands may be issued. All outstanding
+commands that have previously been issued are waited on before
+returning. This not only includes waiting for the futures to resolve,
+but also waiting for all response data to arrive. In other words,
+calling this waits for all on-wire state for issued command requests
+to finish.
+
+When used as a context manager, this method is called when exiting the
+context manager.
+
+This method may call ``sendcommands()`` if there are buffered commands.
+"""
+
+class ipeerrequests(zi.Interface):
+"""Interface for executing commands on a peer."""
+
+def commandexecutor():
+"""A context manager that resolves to an ipeercommandexecutor.
+
+The object this resolves to can be used to issue command requests
+to the peer.
+
+Callers should call its ``callcommand`` method to issue command
+requests.
+
+A new executor should be obtained for each distinct set of commands
+(possibly just a single command) that the consumer wants to execute
+as part of a single operation or round trip. This is because some
+peers are half-duplex and/or don't support persistent connections.
+e.g. in the case of HTTP peers, commands sent to an executor represent
+a single HTTP request. While some peers may support multiple command
+sends over the wire per executor, consumers need to code to the least
+capable peer. So it should be assumed that command executors buffer
+called commands until they are told to send them and that each
+command executor could result in a new connection or wire-level request
+being issued.
+"""
+
 class ipeerbase(ipeerconnection, ipeercapabilities, ipeercommands):
 """Unified interface for peer repositories.
 



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3270: largefiles: use command executor for batch operation

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8123.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3270?vs=8036&id=8123

REVISION DETAIL
  https://phab.mercurial-scm.org/D3270

AFFECTED FILES
  hgext/largefiles/wirestore.py
  tests/test-largefiles-wireproto.t

CHANGE DETAILS

diff --git a/tests/test-largefiles-wireproto.t 
b/tests/test-largefiles-wireproto.t
--- a/tests/test-largefiles-wireproto.t
+++ b/tests/test-largefiles-wireproto.t
@@ -312,7 +312,7 @@
   getting changed largefiles
   using http://localhost:$HGPORT2/
   sending capabilities command
-  sending batch command
+  sending statlfile command
   getting largefiles: 0/1 files (0.00%)
   getting f1:02a439e5c31c526465ab1a0ca1f431f76b827b90
   sending getlfile command
@@ -400,7 +400,7 @@
   searching 3 changesets for largefiles
   verified existence of 3 revisions of 3 largefiles
   $ tail -1 access.log
-  $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - 
x-hgarg-1:cmds=statlfile+sha%3Dc8559c3c9cfb42131794b7d8009230403b9b454c 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=statlfile HTTP/1.1" 200 - 
x-hgarg-1:sha=c8559c3c9cfb42131794b7d8009230403b9b454c x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
 
   $ killdaemons.py
 
diff --git a/hgext/largefiles/wirestore.py b/hgext/largefiles/wirestore.py
--- a/hgext/largefiles/wirestore.py
+++ b/hgext/largefiles/wirestore.py
@@ -32,8 +32,12 @@
 '''For each hash, return 0 if it is available, other values if not.
 It is usually 2 if the largefile is missing, but might be 1 the server
 has a corrupted copy.'''
-batch = self.remote.iterbatch()
-for hash in hashes:
-batch.statlfile(hash)
-batch.submit()
-return dict(zip(hashes, batch.results()))
+
+with self.remote.commandexecutor() as e:
+fs = []
+for hash in hashes:
+fs.append((hash, e.callcommand('statlfile', {
+'sha': hash,
+})))
+
+return {hash: f.result() for hash, f in fs}



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3272: treediscovery: switch to command executor interface

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8125.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3272?vs=8039&id=8125

REVISION DETAIL
  https://phab.mercurial-scm.org/D3272

AFFECTED FILES
  mercurial/treediscovery.py

CHANGE DETAILS

diff --git a/mercurial/treediscovery.py b/mercurial/treediscovery.py
--- a/mercurial/treediscovery.py
+++ b/mercurial/treediscovery.py
@@ -36,7 +36,8 @@
 base = set()
 
 if not heads:
-heads = remote.heads()
+with remote.commandexecutor() as e:
+heads = e.callcommand('heads', {}).result()
 
 if repo.changelog.tip() == nullid:
 base.add(nullid)
@@ -65,7 +66,10 @@
 # a 'branch' here is a linear segment of history, with four parts:
 # head, root, first parent, second parent
 # (a branch always has two parents (or none) by definition)
-unknown = collections.deque(remote.branches(unknown))
+with remote.commandexecutor() as e:
+branches = e.callcommand('branches', {'nodes': unknown}).result()
+
+unknown = collections.deque(branches)
 while unknown:
 r = []
 while unknown:
@@ -107,7 +111,12 @@
 repo.ui.debug("request %d: %s\n" %
 (reqcnt, " ".join(map(short, r
 for p in xrange(0, len(r), 10):
-for b in remote.branches(r[p:p + 10]):
+with remote.commandexecutor() as e:
+branches = e.callcommand('branches', {
+'nodes': r[p:p + 10],
+}).result()
+
+for b in branches:
 repo.ui.debug("received %s:%s\n" %
   (short(b[0]), short(b[1])))
 unknown.append(b)
@@ -117,7 +126,11 @@
 newsearch = []
 reqcnt += 1
 repo.ui.progress(_('searching'), reqcnt, unit=_('queries'))
-for n, l in zip(search, remote.between(search)):
+
+with remote.commandexecutor() as e:
+between = e.callcommand('between', {'pairs': search}).result()
+
+for n, l in zip(search, between):
 l.append(n[1])
 p = n[0]
 f = 1



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3269: wireproto: implement batching on peer executor interface

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8122.
indygreg edited the summary of this revision.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3269?vs=8035&id=8122

REVISION DETAIL
  https://phab.mercurial-scm.org/D3269

AFFECTED FILES
  mercurial/setdiscovery.py
  mercurial/wireprotov1peer.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -9,6 +9,7 @@
 
 import hashlib
 import sys
+import weakref
 
 from .i18n import _
 from .node import (
@@ -180,13 +181,36 @@
 
 return ';'.join(cmds)
 
+class unsentfuture(pycompat.futures.Future):
+"""A Future variation to represent an unsent command.
+
+Because we buffer commands and don't submit them immediately, calling
+``result()`` on an unsent future could deadlock. Futures for buffered
+commands are represented by this type, which wraps ``result()`` to
+call ``sendcommands()``.
+"""
+
+def result(self, timeout=None):
+if self.done():
+return pycompat.futures.Future.result(self, timeout)
+
+self._peerexecutor.sendcommands()
+
+# This looks like it will infinitely recurse. However,
+# sendcommands() should modify __class__. This call serves as a check
+# on that.
+return self.result(timeout)
+
 @zi.implementer(repository.ipeercommandexecutor)
 class peerexecutor(object):
 def __init__(self, peer):
 self._peer = peer
 self._sent = False
 self._closed = False
 self._calls = []
+self._futures = weakref.WeakSet()
+self._responseexecutor = None
+self._responsef = None
 
 def __enter__(self):
 return self
@@ -214,20 +238,35 @@
 # Commands are either batchable or they aren't. If a command
 # isn't batchable, we send it immediately because the executor
 # can no longer accept new commands after a non-batchable command.
-# If a command is batchable, we queue it for later.
+# If a command is batchable, we queue it for later. But we have
+# to account for the case of a non-batchable command arriving after
+# a batchable one and refuse to service it.
+
+def addcall():
+f = pycompat.futures.Future()
+self._futures.add(f)
+self._calls.append((command, args, fn, f))
+return f
 
 if getattr(fn, 'batchable', False):
-pass
+f = addcall()
+
+# But since we don't issue it immediately, we wrap its result()
+# to trigger sending so we avoid deadlocks.
+f.__class__ = unsentfuture
+f._peerexecutor = self
 else:
 if self._calls:
 raise error.ProgrammingError(
 '%s is not batchable and cannot be called on a command '
 'executor along with other commands' % command)
 
-# We don't support batching yet. So resolve it immediately.
-f = pycompat.futures.Future()
-self._calls.append((command, args, fn, f))
-self.sendcommands()
+f = addcall()
+
+# Non-batchable commands can never coexist with another command
+# in this executor. So send the command immediately.
+self.sendcommands()
+
 return f
 
 def sendcommands(self):
@@ -239,10 +278,18 @@
 
 self._sent = True
 
+# Unhack any future types so caller seens a clean type and to break
+# cycle between us and futures.
+for f in self._futures:
+if isinstance(f, unsentfuture):
+f.__class__ = pycompat.futures.Future
+f._peerexecutor = None
+
 calls = self._calls
 # Mainly to destroy references to futures.
 self._calls = None
 
+# Simple case of a single command. We call it synchronously.
 if len(calls) == 1:
 command, args, fn, f = calls[0]
 
@@ -259,14 +306,99 @@
 
 return
 
-raise error.ProgrammingError('support for multiple commands not '
- 'yet implemented')
+# Batch commands are a bit harder. First, we have to deal with the
+# @batchable coroutine. That's a bit annoying. Furthermore, we also
+# need to preserve streaming. i.e. it should be possible for the
+# futures to resolve as data is coming in off the wire without having
+# to wait for the final byte of the final response. We do this by
+# spinning up a thread to read the responses.
+
+requests = []
+states = []
+
+for command, args, fn, f in calls:
+# Future was cancelled. Ignore it.
+if not f.set_running_or_notify_cancel():
+continue
+
+try:
+batchable = fn.batchable(fn.__self__,
+  

D3288: discovery: use command executor interface

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8127.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3288?vs=8081&id=8127

REVISION DETAIL
  https://phab.mercurial-scm.org/D3288

AFFECTED FILES
  mercurial/discovery.py

CHANGE DETAILS

diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -203,7 +203,10 @@
 headssum = {}
 # A. Create set of branches involved in the push.
 branches = set(repo[n].branch() for n in outgoing.missing)
-remotemap = remote.branchmap()
+
+with remote.commandexecutor() as e:
+remotemap = e.callcommand('branchmap', {}).result()
+
 newbranches = branches - set(remotemap)
 branches.difference_update(newbranches)
 
@@ -287,7 +290,12 @@
 repo = pushop.repo.unfiltered()
 remote = pushop.remote
 localbookmarks = repo._bookmarks
-remotebookmarks = remote.listkeys('bookmarks')
+
+with remote.commandexecutor() as e:
+remotebookmarks = e.callcommand('listkeys', {
+'namespace': 'bookmarks',
+}).result()
+
 bookmarkedheads = set()
 
 # internal config: bookmarks.pushing



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3290: logexchange: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8129.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3290?vs=8083&id=8129

REVISION DETAIL
  https://phab.mercurial-scm.org/D3290

AFFECTED FILES
  mercurial/logexchange.py

CHANGE DETAILS

diff --git a/mercurial/logexchange.py b/mercurial/logexchange.py
--- a/mercurial/logexchange.py
+++ b/mercurial/logexchange.py
@@ -127,14 +127,23 @@
 remoterepo is the peer instance
 """
 remotepath = activepath(localrepo, remoterepo)
-bookmarks = remoterepo.listkeys('bookmarks')
+
+with remoterepo.commandexecutor() as e:
+bookmarks = e.callcommand('listkeys', {
+'namespace': 'bookmarks',
+}).result()
+
 # on a push, we don't want to keep obsolete heads since
 # they won't show up as heads on the next pull, so we
 # remove them here otherwise we would require the user
 # to issue a pull to refresh the storage
 bmap = {}
 repo = localrepo.unfiltered()
-for branch, nodes in remoterepo.branchmap().iteritems():
+
+with remoterepo.commandexecutor() as e:
+branchmap = e.callcommand('branchmap', {}).result()
+
+for branch, nodes in branchmap.iteritems():
 bmap[branch] = []
 for node in nodes:
 if node in repo and not repo[node].obsolete():



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3289: streamclone: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8128.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3289?vs=8082&id=8128

REVISION DETAIL
  https://phab.mercurial-scm.org/D3289

AFFECTED FILES
  mercurial/streamclone.py

CHANGE DETAILS

diff --git a/mercurial/streamclone.py b/mercurial/streamclone.py
--- a/mercurial/streamclone.py
+++ b/mercurial/streamclone.py
@@ -126,11 +126,18 @@
 # creation.
 rbranchmap = None
 if remote.capable('branchmap'):
-rbranchmap = remote.branchmap()
+with remote.commandexecutor() as e:
+rbranchmap = e.callcommand('branchmap', {}).result()
 
 repo.ui.status(_('streaming all changes\n'))
 
-fp = remote.stream_out()
+with remote.commandexecutor() as e:
+fp = e.callcommand('stream_out', {}).result()
+
+# TODO strictly speaking, this code should all be inside the context
+# manager because the context manager is supposed to ensure all wire state
+# is flushed when exiting. But the legacy peers don't do this, so it
+# doesn't matter.
 l = fp.readline()
 try:
 resp = int(l)



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3268: wireproto: implement command executor interface for version 1 peers

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8121.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3268?vs=8034&id=8121

REVISION DETAIL
  https://phab.mercurial-scm.org/D3268

AFFECTED FILES
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/setdiscovery.py
  mercurial/wireprotov1peer.py
  tests/test-check-interfaces.py

CHANGE DETAILS

diff --git a/tests/test-check-interfaces.py b/tests/test-check-interfaces.py
--- a/tests/test-check-interfaces.py
+++ b/tests/test-check-interfaces.py
@@ -23,6 +23,7 @@
 vfs as vfsmod,
 wireprotoserver,
 wireprototypes,
+wireprotov1peer,
 wireprotov2server,
 )
 
@@ -102,6 +103,14 @@
  localrepo.localpeer)
 checkzobject(localrepo.localpeer(dummyrepo()))
 
+ziverify.verifyClass(repository.ipeercommandexecutor,
+ localrepo.localcommandexecutor)
+checkzobject(localrepo.localcommandexecutor(None))
+
+ziverify.verifyClass(repository.ipeercommandexecutor,
+ wireprotov1peer.peerexecutor)
+checkzobject(wireprotov1peer.peerexecutor(None))
+
 ziverify.verifyClass(repository.ipeerbaselegacycommands,
  sshpeer.sshv1peer)
 checkzobject(sshpeer.sshv1peer(ui, 'ssh://localhost/foo', None, 
dummypipe(),
diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -8,12 +8,15 @@
 from __future__ import absolute_import
 
 import hashlib
+import sys
 
 from .i18n import _
 from .node import (
 bin,
 )
-
+from .thirdparty.zope import (
+interface as zi,
+)
 from . import (
 bundle2,
 changegroup as changegroupmod,
@@ -177,14 +180,104 @@
 
 return ';'.join(cmds)
 
+@zi.implementer(repository.ipeercommandexecutor)
+class peerexecutor(object):
+def __init__(self, peer):
+self._peer = peer
+self._sent = False
+self._closed = False
+self._calls = []
+
+def __enter__(self):
+return self
+
+def __exit__(self, exctype, excvalee, exctb):
+self.close()
+
+def callcommand(self, command, args):
+if self._sent:
+raise error.ProgrammingError('callcommand() cannot be used '
+ 'after commands are sent')
+
+if self._closed:
+raise error.ProgrammingError('callcommand() cannot be used '
+ 'after close()')
+
+# Commands are dispatched through methods on the peer.
+fn = getattr(self._peer, pycompat.sysstr(command), None)
+
+if not fn:
+raise error.ProgrammingError(
+'cannot call command %s: method of same name not available '
+'on peer' % command)
+
+# Commands are either batchable or they aren't. If a command
+# isn't batchable, we send it immediately because the executor
+# can no longer accept new commands after a non-batchable command.
+# If a command is batchable, we queue it for later.
+
+if getattr(fn, 'batchable', False):
+pass
+else:
+if self._calls:
+raise error.ProgrammingError(
+'%s is not batchable and cannot be called on a command '
+'executor along with other commands' % command)
+
+# We don't support batching yet. So resolve it immediately.
+f = pycompat.futures.Future()
+self._calls.append((command, args, fn, f))
+self.sendcommands()
+return f
+
+def sendcommands(self):
+if self._sent:
+return
+
+if not self._calls:
+return
+
+self._sent = True
+
+calls = self._calls
+# Mainly to destroy references to futures.
+self._calls = None
+
+if len(calls) == 1:
+command, args, fn, f = calls[0]
+
+# Future was cancelled. Ignore it.
+if not f.set_running_or_notify_cancel():
+return
+
+try:
+result = fn(**pycompat.strkwargs(args))
+except Exception:
+f.set_exception_info(*sys.exc_info()[1:])
+else:
+f.set_result(result)
+
+return
+
+raise error.ProgrammingError('support for multiple commands not '
+ 'yet implemented')
+
+def close(self):
+self.sendcommands()
+
+self._closed = True
+
 class wirepeer(repository.legacypeer):
 """Client-side interface for communicating with a peer repository.
 
 Methods commonly call wire protocol commands of the same name.
 
 See also httppeer.py and sshpeer.py for protocol-specific
 implementations of this interface.
 """
+def commandexecutor(self):
+return peerexecutor(self)
+
 # Begin of ipeercommands interface.
 
 def iterbatch(self):
diff --gi

D3292: bookmarks: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8131.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3292?vs=8085&id=8131

REVISION DETAIL
  https://phab.mercurial-scm.org/D3292

AFFECTED FILES
  mercurial/bookmarks.py

CHANGE DETAILS

diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
--- a/mercurial/bookmarks.py
+++ b/mercurial/bookmarks.py
@@ -646,12 +646,16 @@
 writer(msg)
 localmarks.applychanges(repo, tr, changes)
 
-def incoming(ui, repo, other):
+def incoming(ui, repo, peer):
 '''Show bookmarks incoming from other to repo
 '''
 ui.status(_("searching for changed bookmarks\n"))
 
-remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
+with peer.commandexecutor() as e:
+remotemarks = unhexlifybookmarks(e.callcommand('listkeys', {
+'namespace': 'bookmarks',
+}).result())
+
 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
 
@@ -733,12 +737,16 @@
 
 return 0
 
-def summary(repo, other):
+def summary(repo, peer):
 '''Compare bookmarks between repo and other for "hg summary" output
 
 This returns "(# of incoming, # of outgoing)" tuple.
 '''
-remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
+with peer.commandexecutor() as e:
+remotemarks = unhexlifybookmarks(e.callcommand('listkeys', {
+'namespace': 'bookmarks',
+}).result())
+
 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
 return (len(addsrc), len(adddst))



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3291: hg: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8130.
indygreg edited the summary of this revision.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3291?vs=8084&id=8130

REVISION DETAIL
  https://phab.mercurial-scm.org/D3291

AFFECTED FILES
  mercurial/hg.py

CHANGE DETAILS

diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -81,7 +81,9 @@
 raise error.Abort(_("remote branch lookup not supported"))
 revs.append(hashbranch)
 return revs, revs[0]
-branchmap = peer.branchmap()
+
+with peer.commandexecutor() as e:
+branchmap = e.callcommand('branchmap', {}).result()
 
 def primary(branch):
 if branch == '.':
@@ -421,7 +423,15 @@
 raise error.Abort(_("src repository does not support "
"revision lookup and so doesn't "
"support clone by revision"))
-revs = [srcpeer.lookup(r) for r in rev]
+
+# TODO this is batchable.
+remoterevs = []
+for r in rev:
+with srcpeer.commandexecutor() as e:
+remoterevs.append(e.callcommand('lookup', {
+'key': r,
+}).result())
+revs = remoterevs
 
 # Obtain a lock before checking for or cloning the pooled repo otherwise
 # 2 clients may race creating or populating it.
@@ -567,7 +577,11 @@
 # raises RepoLookupError if revision 0 is filtered or otherwise
 # not available. If we fail to resolve, sharing is not enabled.
 try:
-rootnode = srcpeer.lookup('0')
+with srcpeer.commandexecutor() as e:
+rootnode = e.callcommand('lookup', {
+'key': '0',
+}).result()
+
 if rootnode != node.nullid:
 sharepath = os.path.join(sharepool, node.hex(rootnode))
 else:
@@ -663,7 +677,16 @@
 raise error.Abort(_("src repository does not support "
"revision lookup and so doesn't "
"support clone by revision"))
-revs = [srcpeer.lookup(r) for r in revs]
+
+# TODO this is batchable.
+remoterevs = []
+for rev in revs:
+with srcpeer.commandexecutor() as e:
+remoterevs.append(e.callcommand('lookup', {
+'key': rev,
+}).result())
+revs = remoterevs
+
 checkout = revs[0]
 else:
 revs = None
@@ -705,7 +728,11 @@
 
 if update:
 if update is not True:
-checkout = srcpeer.lookup(update)
+with srcpeer.commandexecutor() as e:
+checkout = e.callcommand('lookup', {
+'key': update,
+}).result()
+
 uprev = None
 status = None
 if checkout is not None:



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3293: bundlerepo: rename "other" to "peer"

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8132.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3293?vs=8086&id=8132

REVISION DETAIL
  https://phab.mercurial-scm.org/D3293

AFFECTED FILES
  mercurial/bundlerepo.py

CHANGE DETAILS

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -492,9 +492,9 @@
 def release(self):
 raise NotImplementedError
 
-def getremotechanges(ui, repo, other, onlyheads=None, bundlename=None,
+def getremotechanges(ui, repo, peer, onlyheads=None, bundlename=None,
  force=False):
-'''obtains a bundle of changes incoming from other
+'''obtains a bundle of changes incoming from peer
 
 "onlyheads" restricts the returned changes to those reachable from the
   specified heads.
@@ -507,62 +507,62 @@
 
 "local" is a local repo from which to obtain the actual incoming
   changesets; it is a bundlerepo for the obtained bundle when the
-  original "other" is remote.
+  original "peer" is remote.
 "csets" lists the incoming changeset node ids.
 "cleanupfn" must be called without arguments when you're done processing
-  the changes; it closes both the original "other" and the one returned
+  the changes; it closes both the original "peer" and the one returned
   here.
 '''
-tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
+tmp = discovery.findcommonincoming(repo, peer, heads=onlyheads,
force=force)
 common, incoming, rheads = tmp
 if not incoming:
 try:
 if bundlename:
 os.unlink(bundlename)
 except OSError:
 pass
-return repo, [], other.close
+return repo, [], peer.close
 
 commonset = set(common)
 rheads = [x for x in rheads if x not in commonset]
 
 bundle = None
 bundlerepo = None
-localrepo = other.local()
+localrepo = peer.local()
 if bundlename or not localrepo:
-# create a bundle (uncompressed if other repo is not local)
+# create a bundle (uncompressed if peer repo is not local)
 
 # developer config: devel.legacy.exchange
 legexc = ui.configlist('devel', 'legacy.exchange')
 forcebundle1 = 'bundle2' not in legexc and 'bundle1' in legexc
 canbundle2 = (not forcebundle1
-  and other.capable('getbundle')
-  and other.capable('bundle2'))
+  and peer.capable('getbundle')
+  and peer.capable('bundle2'))
 if canbundle2:
 kwargs = {}
 kwargs[r'common'] = common
 kwargs[r'heads'] = rheads
 kwargs[r'bundlecaps'] = exchange.caps20to10(repo, role='client')
 kwargs[r'cg'] = True
-b2 = other.getbundle('incoming', **kwargs)
+b2 = peer.getbundle('incoming', **kwargs)
 fname = bundle = changegroup.writechunks(ui, b2._forwardchunks(),
  bundlename)
 else:
-if other.capable('getbundle'):
-cg = other.getbundle('incoming', common=common, heads=rheads)
-elif onlyheads is None and not other.capable('changegroupsubset'):
+if peer.capable('getbundle'):
+cg = peer.getbundle('incoming', common=common, heads=rheads)
+elif onlyheads is None and not peer.capable('changegroupsubset'):
 # compat with older servers when pulling all remote heads
 
-with other.commandexecutor() as e:
+with peer.commandexecutor() as e:
 cg = e.callcommand('changegroup', {
 'nodes': incoming,
 'source': 'incoming',
 }).result()
 
 rheads = None
 else:
-with other.commandexecutor() as e:
+with peer.commandexecutor() as e:
 cg = e.callcommand('changegroupsubset', {
 'bases': incoming,
 'heads': rheads,
@@ -582,7 +582,7 @@
 # use the created uncompressed bundlerepo
 localrepo = bundlerepo = bundlerepository(repo.baseui, repo.root,
   fname)
-# this repo contains local and other now, so filter out local again
+# this repo contains local and peer now, so filter out local again
 common = repo.heads()
 if localrepo:
 # Part of common may be remotely filtered
@@ -594,17 +594,17 @@
 
 if bundlerepo:
 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
-remotephases = other.listkeys('phases')
+remotephases = peer.listkeys('phases')
 
-pullop = exchange.pulloperation(bundlerepo, othe

D3294: bundlerepo: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8133.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3294?vs=8087&id=8133

REVISION DETAIL
  https://phab.mercurial-scm.org/D3294

AFFECTED FILES
  mercurial/bundlerepo.py

CHANGE DETAILS

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -540,17 +540,26 @@
   and peer.capable('getbundle')
   and peer.capable('bundle2'))
 if canbundle2:
-kwargs = {}
-kwargs[r'common'] = common
-kwargs[r'heads'] = rheads
-kwargs[r'bundlecaps'] = exchange.caps20to10(repo, role='client')
-kwargs[r'cg'] = True
-b2 = peer.getbundle('incoming', **kwargs)
-fname = bundle = changegroup.writechunks(ui, b2._forwardchunks(),
- bundlename)
+with peer.commandexecutor() as e:
+b2 = e.callcommand('getbundle', {
+'source': 'incoming',
+'common': common,
+'heads': rheads,
+'bundlecaps': exchange.caps20to10(repo, role='client'),
+'cg': True,
+}).result()
+
+fname = bundle = changegroup.writechunks(ui,
+ b2._forwardchunks(),
+ bundlename)
 else:
 if peer.capable('getbundle'):
-cg = peer.getbundle('incoming', common=common, heads=rheads)
+with peer.commandexecutor() as e:
+cg = e.callcommand('getbundle', {
+'source': 'incoming',
+'common': common,
+'heads': rheads,
+}).result()
 elif onlyheads is None and not peer.capable('changegroupsubset'):
 # compat with older servers when pulling all remote heads
 
@@ -594,7 +603,11 @@
 
 if bundlerepo:
 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
-remotephases = peer.listkeys('phases')
+
+with peer.commandexecutor() as e:
+remotephases = e.callcommand('listkeys', {
+'namespace': 'phases',
+}).result()
 
 pullop = exchange.pulloperation(bundlerepo, peer, heads=reponodes)
 pullop.trmanager = bundletransactionmanager()



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3271: wireproto: remove iterbatch() from peer interface (API)

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8124.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3271?vs=8037&id=8124

REVISION DETAIL
  https://phab.mercurial-scm.org/D3271

AFFECTED FILES
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/wireprotov1peer.py
  tests/test-batching.py
  tests/test-batching.py.out
  tests/test-wireproto.py

CHANGE DETAILS

diff --git a/tests/test-wireproto.py b/tests/test-wireproto.py
--- a/tests/test-wireproto.py
+++ b/tests/test-wireproto.py
@@ -93,7 +93,9 @@
 clt = clientpeer(srv, uimod.ui())
 
 print(clt.greet(b"Foobar"))
-b = clt.iterbatch()
-list(map(b.greet, (b'Fo, =;:https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3316: exchange: use command executor for getbundle

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The code consuming the bundle has been moved to inside the
  context manager, as that is supposed to be part of the API.
  (Although it doesn't matter for version 1 peers.)

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3316

AFFECTED FILES
  mercurial/exchange.py

CHANGE DETAILS

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -1648,17 +1648,22 @@
 kwargs['obsmarkers'] = True
 pullop.stepsdone.add('obsmarkers')
 _pullbundle2extraprepare(pullop, kwargs)
-bundle = pullop.remote.getbundle('pull', **pycompat.strkwargs(kwargs))
-try:
-op = bundle2.bundleoperation(pullop.repo, pullop.gettransaction,
- source='pull')
-op.modes['bookmarks'] = 'records'
-bundle2.processbundle(pullop.repo, bundle, op=op)
-except bundle2.AbortFromPart as exc:
-pullop.repo.ui.status(_('remote: abort: %s\n') % exc)
-raise error.Abort(_('pull failed on remote'), hint=exc.hint)
-except error.BundleValueError as exc:
-raise error.Abort(_('missing support for %s') % exc)
+
+with pullop.remote.commandexecutor() as e:
+args = dict(kwargs)
+args['source'] = 'pull'
+bundle = e.callcommand('getbundle', args).result()
+
+try:
+op = bundle2.bundleoperation(pullop.repo, pullop.gettransaction,
+ source='pull')
+op.modes['bookmarks'] = 'records'
+bundle2.processbundle(pullop.repo, bundle, op=op)
+except bundle2.AbortFromPart as exc:
+pullop.repo.ui.status(_('remote: abort: %s\n') % exc)
+raise error.Abort(_('pull failed on remote'), hint=exc.hint)
+except error.BundleValueError as exc:
+raise error.Abort(_('missing support for %s') % exc)
 
 if pullop.fetch:
 pullop.cgresult = bundle2.combinechangegroupresults(op)



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3273: wireproto: convert legacy commands to command executor

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8126.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3273?vs=8040&id=8126

REVISION DETAIL
  https://phab.mercurial-scm.org/D3273

AFFECTED FILES
  mercurial/bundlerepo.py
  mercurial/exchange.py
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/wireprotov1peer.py
  tests/test-check-interfaces.py

CHANGE DETAILS

diff --git a/tests/test-check-interfaces.py b/tests/test-check-interfaces.py
--- a/tests/test-check-interfaces.py
+++ b/tests/test-check-interfaces.py
@@ -89,8 +89,7 @@
 
 checkzobject(badpeer())
 
-ziverify.verifyClass(repository.ipeerbaselegacycommands,
- httppeer.httppeer)
+ziverify.verifyClass(repository.ipeerbase, httppeer.httppeer)
 checkzobject(httppeer.httppeer(None, None, None, dummyopener(), None, 
None))
 
 ziverify.verifyClass(repository.ipeerconnection,
@@ -111,13 +110,11 @@
  wireprotov1peer.peerexecutor)
 checkzobject(wireprotov1peer.peerexecutor(None))
 
-ziverify.verifyClass(repository.ipeerbaselegacycommands,
- sshpeer.sshv1peer)
+ziverify.verifyClass(repository.ipeerbase, sshpeer.sshv1peer)
 checkzobject(sshpeer.sshv1peer(ui, 'ssh://localhost/foo', None, 
dummypipe(),
dummypipe(), None, None))
 
-ziverify.verifyClass(repository.ipeerbaselegacycommands,
- sshpeer.sshv2peer)
+ziverify.verifyClass(repository.ipeerbase, sshpeer.sshv2peer)
 checkzobject(sshpeer.sshv2peer(ui, 'ssh://localhost/foo', None, 
dummypipe(),
dummypipe(), None, None))
 
diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -308,7 +308,8 @@
 else:
 f.set_result(result)
 
-class wirepeer(repository.legacypeer):
+@zi.implementer(repository.ipeerlegacycommands)
+class wirepeer(repository.peer):
 """Client-side interface for communicating with a peer repository.
 
 Methods commonly call wire protocol commands of the same name.
@@ -502,12 +503,12 @@
 self._abort(error.ResponseError(_("unexpected response:"), d))
 return r
 
-def changegroup(self, nodes, kind):
+def changegroup(self, nodes, source):
 n = wireprototypes.encodelist(nodes)
 f = self._callcompressable("changegroup", roots=n)
 return changegroupmod.cg1unpacker(f, 'UN')
 
-def changegroupsubset(self, bases, heads, kind):
+def changegroupsubset(self, bases, heads, source):
 self.requirecap('changegroupsubset', _('look up remote changes'))
 bases = wireprototypes.encodelist(bases)
 heads = wireprototypes.encodelist(heads)
diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -190,10 +190,10 @@
 Returns an iterable of iterables with the resolved values for each 
node.
 """
 
-def changegroup(nodes, kind):
+def changegroup(nodes, source):
 """Obtain a changegroup with data for descendants of specified 
nodes."""
 
-def changegroupsubset(bases, heads, kind):
+def changegroupsubset(bases, heads, source):
 pass
 
 class ipeercommandexecutor(zi.Interface):
@@ -285,9 +285,6 @@
 All peer instances must conform to this interface.
 """
 
-class ipeerbaselegacycommands(ipeerbase, ipeerlegacycommands):
-"""Unified peer interface that supports legacy commands."""
-
 @zi.implementer(ipeerbase)
 class peer(object):
 """Base class for peer repositories."""
@@ -312,10 +309,6 @@
 _('cannot %s; remote repository does not support the %r '
   'capability') % (purpose, name))
 
-@zi.implementer(ipeerbaselegacycommands)
-class legacypeer(peer):
-"""peer but with support for legacy wire protocol commands."""
-
 class ifilerevisionssequence(zi.Interface):
 """Contains index data for all revisions of a file.
 
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -320,7 +320,8 @@
 
 # End of peer interface.
 
-class locallegacypeer(repository.legacypeer, localpeer):
+@zi.implementer(repository.ipeerlegacycommands)
+class locallegacypeer(localpeer):
 '''peer extension which implements legacy methods too; used for tests with
 restricted capabilities'''
 
@@ -335,8 +336,8 @@
 def branches(self, nodes):
 return self._repo.branches(nodes)
 
-def changegroup(self, basenodes, source):
-outgoing = discovery.outgoing(self._repo, missingroots=basenodes,
+def changegroup(self, nodes, source):
+outgoing = discovery.outgoing(self._repo, missingroots=nodes,
   missingheads=self._repo.heads())
 return changegroup.makechangegroup(self._repo, outgoing, '01', sou

D3314: wireproto: use command executor for unbundle

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This also required unifying the name of the argument because the
  new API always passes arguments by keyword. I decided to change
  implementations to "bundle" instead of the interface to "cg"
  because "bundle" is more appropriate in a modern world.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3314

AFFECTED FILES
  mercurial/exchange.py
  mercurial/localrepo.py
  mercurial/wireprotov1peer.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -436,7 +436,7 @@
 else:
 return changegroupmod.cg1unpacker(f, 'UN')
 
-def unbundle(self, cg, heads, url):
+def unbundle(self, bundle, heads, url):
 '''Send cg (a readable file-like object representing the
 changegroup to push, typically a chunkbuffer object) to the
 remote server as a bundle.
@@ -456,9 +456,9 @@
 else:
 heads = wireprototypes.encodelist(heads)
 
-if util.safehasattr(cg, 'deltaheader'):
+if util.safehasattr(bundle, 'deltaheader'):
 # this a bundle10, do the old style call sequence
-ret, output = self._callpush("unbundle", cg, heads=heads)
+ret, output = self._callpush("unbundle", bundle, heads=heads)
 if ret == "":
 raise error.ResponseError(
 _('push failed:'), output)
@@ -472,7 +472,7 @@
 self.ui.status(_('remote: '), l)
 else:
 # bundle2 push. Send a stream, fetch a stream.
-stream = self._calltwowaystream('unbundle', cg, heads=heads)
+stream = self._calltwowaystream('unbundle', bundle, heads=heads)
 ret = bundle2.getunbundler(self.ui, stream)
 return ret
 
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -275,14 +275,14 @@
 raise error.Abort(_('cannot perform stream clone against local '
 'peer'))
 
-def unbundle(self, cg, heads, url):
+def unbundle(self, bundle, heads, url):
 """apply a bundle on a repo
 
 This function handles the repo locking itself."""
 try:
 try:
-cg = exchange.readbundle(self.ui, cg, None)
-ret = exchange.unbundle(self._repo, cg, heads, 'push', url)
+bundle = exchange.readbundle(self.ui, bundle, None)
+ret = exchange.unbundle(self._repo, bundle, heads, 'push', url)
 if util.safehasattr(ret, 'getchunks'):
 # This is a bundle20 object, turn it into an unbundler.
 # This little dance should be dropped eventually when the
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -1096,8 +1096,12 @@
 stream = util.chunkbuffer(bundler.getchunks())
 try:
 try:
-reply = pushop.remote.unbundle(
-stream, ['force'], pushop.remote.url())
+with pushop.remote.commandexecutor() as e:
+reply = e.callcommand('unbundle', {
+'bundle': stream,
+'heads': ['force'],
+'url': pushop.remote.url(),
+}).result()
 except error.BundleValueError as exc:
 raise error.Abort(_('missing support for %s') % exc)
 try:



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3318: repository: remove ipeercommands from ipeerbase

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  AFAICT all callers in core have moved to the commandexecutor
  interface for invoking wire protocol commands. Or at least they
  aren't using the named methods on ipeercommands to invoke them.
  
  This means we can drop ipeercommands from the ipeerbase interface.
  As far as interface based programming goes, it is now illegal to call
  an ipeercommands method for issuing wire protocol commands. However,
  the methods are still there, so they will still work. At some
  point we will want to break that API...

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3318

AFFECTED FILES
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/wireprotov1peer.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -308,7 +308,7 @@
 else:
 f.set_result(result)
 
-@zi.implementer(repository.ipeerlegacycommands)
+@zi.implementer(repository.ipeercommands, repository.ipeerlegacycommands)
 class wirepeer(repository.peer):
 """Client-side interface for communicating with a peer repository.
 
diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -284,8 +284,7 @@
 being issued.
 """
 
-class ipeerbase(ipeerconnection, ipeercapabilities, ipeercommands,
-ipeerrequests):
+class ipeerbase(ipeerconnection, ipeercapabilities, ipeerrequests):
 """Unified interface for peer repositories.
 
 All peer instances must conform to this interface.
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -196,6 +196,7 @@
 def close(self):
 self._closed = True
 
+@zi.implementer(repository.ipeercommands)
 class localpeer(repository.peer):
 '''peer for a local repo; reflects only the most recent API'''
 



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3315: exchange: use command executor for pushkey

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3315

AFFECTED FILES
  mercurial/debugcommands.py
  mercurial/exchange.py

CHANGE DETAILS

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -1212,10 +1212,14 @@
 outdated = [c for c in outdated if c.node() not in pheads]
 # fallback to independent pushkey command
 for newremotehead in outdated:
-r = pushop.remote.pushkey('phases',
-  newremotehead.hex(),
-  ('%d' % phases.draft),
-  ('%d' % phases.public))
+with pushop.remote.commandexecutor() as e:
+r = e.callcommand('pushkey', {
+'namespace': 'phases',
+'key': newremotehead.hex(),
+'old': '%d' % phases.draft,
+'new': '%d' % phases.public
+}).result()
+
 if not r:
 pushop.ui.warn(_('updating %s to public failed!\n')
% newremotehead)
@@ -1270,7 +1274,16 @@
 action = 'export'
 elif not new:
 action = 'delete'
-if remote.pushkey('bookmarks', b, old, new):
+
+with remote.commandexecutor() as e:
+r = e.callcommand('pushkey', {
+'namespace': 'bookmarks',
+'key': b,
+'old': old,
+'new': new,
+}).result()
+
+if r:
 ui.status(bookmsgmap[action][0] % b)
 else:
 ui.warn(bookmsgmap[action][1] % b)
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -1832,7 +1832,14 @@
 target = hg.peer(ui, {}, repopath)
 if keyinfo:
 key, old, new = keyinfo
-r = target.pushkey(namespace, key, old, new)
+with target.commandexecutor() as e:
+r = e.callcommand('pushkey', {
+'namespace': namespace,
+'key': key,
+'old': old,
+'new': new,
+}).result()
+
 ui.status(pycompat.bytestr(r) + '\n')
 return not r
 else:



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3317: wireproto: properly call clonebundles command

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  We should not be using _call() to make wire protocol calls because
  it isn't part of the peer API.
  
  But clonebundles wasn't part of the supported commands in the
  peer API!
  
  So this commit defines that command in the commands interface,
  implements it, and teaches the one caller in core to call it using
  the command executor interface.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3317

AFFECTED FILES
  mercurial/exchange.py
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/wireprotov1peer.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -322,6 +322,10 @@
 
 # Begin of ipeercommands interface.
 
+def clonebundles(self):
+self.requirecap('clonebundles', _('clone bundles'))
+return self._call('clonebundles')
+
 @batchable
 def lookup(self, key):
 self.requirecap('lookup', _('look up remote revision'))
diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -101,6 +101,12 @@
 Returns a set of string capabilities.
 """
 
+def clonebundles():
+"""Obtains the clone bundles manifest for the repo.
+
+Returns the manifest as unparsed bytes.
+"""
+
 def debugwireargs(one, two, three=None, four=None, five=None):
 """Used to facilitate debugging of arguments passed over the wire."""
 
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -235,6 +235,9 @@
 def capabilities(self):
 return self._caps
 
+def clonebundles(self):
+return self._repo.tryread('clonebundles.manifest')
+
 def debugwireargs(self, one, two, three=None, four=None, five=None):
 """Used to test argument passing over the wire"""
 return "%s %s %s %s %s" % (one, two, pycompat.bytestr(three),
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -2170,7 +2170,8 @@
 if not remote.capable('clonebundles'):
 return
 
-res = remote._call('clonebundles')
+with remote.commandexecutor() as e:
+res = e.callcommand('clonebundles', {}).result()
 
 # If we call the wire protocol command, that's good enough to record the
 # attempt.



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3267: repository: define new interface for running commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  We now send non-batchable commands immediately and wrap queued futures so 
`result()` will trigger submission. This improves the end-user experience from:
  
with peer.commandexecutor() as e:
f = e.callcommand(...)

res = f.result()
  
  to
  
with peer.commandexecutor() as e:
res = e.callcommand(...).result()
  
  And in order to preserve streaming on batch responses:
  
with peer.commandexecutor() as e:
fs = []
for x in ...:
fs.append(...)

e.sendcommands()
for f in fs:
result = f.result()
  
  to
  
with peer.commandexecutor() as e:
fs = []
for x in ...:
fs.append(e.callcommand(...))

for f in fs:
result = f.result()
  
  This later improvement is because the first `result()` call on any returned 
future will trigger submission of all queued commands. This also means we can 
iterate or access the futures in any order. Of course, wire protocol version 1 
will resolve them in the order they were issued. But this isn't necessarily 
true about wire protocol version 2 :)

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3267

To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3297: httppeer: implement command executor for version 2 peer

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg planned changes to this revision.
indygreg added a comment.


  This needs some revisions to adapt to the tweaked command executor interface 
semantics.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3297

To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3303: cborutil: implement support for indefinite length CBOR types

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg added inline comments.

INLINE COMMENTS

> yuja wrote in cborutil.py:73
> I don't think yielding `encoder.encode` would make much sense
> because an array item can also be a nested indefinite array, in
> which case, we can't use `writeitem()`.

Indeed.

Proper support for nesting will likely require a whole new high-level encoder 
API. Because state of the nesting needs to be tracked somewhere.

FWIW, the more I'm looking at the CBOR code, the more I'm thinking we will end 
up having to reinvent the full wheel. Not-yet-submitted commits to add wire 
protocol commands to do CBOR things are spending a *ton* of time in cbor2. The 
reason appears to be primarily driven by cbor2's insistence on using `write()`. 
There are a few places where we need to emit a generator of chunks. And the 
overhead from instantiating `io.BytesIO` instances to handle the `write()` from 
cbor2 only to call `getvalue()` to retrieve the data is non-trivial.

The next version of this may just invent a whole new CBOR encoder with only 
limited support for types. Or at least I'll change the API so a streaming array 
doesn't require an encoder be passed in.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3303

To: indygreg, #hg-reviewers
Cc: yuja, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3319: py3: use b"%d" instead of str() to convert integers to bytes

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3319

AFFECTED FILES
  hgext/convert/__init__.py
  hgext/convert/cvs.py
  hgext/convert/cvsps.py
  mercurial/lock.py

CHANGE DETAILS

diff --git a/mercurial/lock.py b/mercurial/lock.py
--- a/mercurial/lock.py
+++ b/mercurial/lock.py
@@ -348,7 +348,7 @@
 if self._parentheld:
 lockname = self.parentlock
 else:
-lockname = '%s:%s' % (lock._host, self.pid)
+lockname = b'%s:%d' % (lock._host, self.pid)
 self._inherited = True
 try:
 yield lockname
diff --git a/hgext/convert/cvsps.py b/hgext/convert/cvsps.py
--- a/hgext/convert/cvsps.py
+++ b/hgext/convert/cvsps.py
@@ -919,7 +919,7 @@
 if opts["parents"] and cs.parents:
 if len(cs.parents) > 1:
 ui.write(('Parents: %s\n' %
- (','.join([str(p.id) for p in cs.parents]
+ (','.join([(b"%d" % p.id) for p in cs.parents]
 else:
 ui.write(('Parent: %d\n' % cs.parents[0].id))
 
@@ -941,18 +941,18 @@
 fn = fn[len(opts["prefix"]):]
 ui.write('\t%s:%s->%s%s \n' % (
 fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL',
-'.'.join([str(x) for x in f.revision]),
+'.'.join([(b"%d" % x) for x in f.revision]),
 ['', '(DEAD)'][f.dead]))
 ui.write('\n')
 
 # have we seen the start tag?
 if revisions and off:
-if revisions[0] == str(cs.id) or \
+if revisions[0] == (b"%d" % cs.id) or \
 revisions[0] in cs.tags:
 off = False
 
 # see if we reached the end tag
 if len(revisions) > 1 and not off:
-if revisions[1] == str(cs.id) or \
+if revisions[1] == (b"%d" % cs.id) or \
 revisions[1] in cs.tags:
 break
diff --git a/hgext/convert/cvs.py b/hgext/convert/cvs.py
--- a/hgext/convert/cvs.py
+++ b/hgext/convert/cvs.py
@@ -91,7 +91,7 @@
 for cs in db:
 if maxrev and cs.id > maxrev:
 break
-id = str(cs.id)
+id = (b"%d" % cs.id)
 cs.author = self.recode(cs.author)
 self.lastbranch[cs.branch] = id
 cs.comment = self.recode(cs.comment)
@@ -102,13 +102,13 @@
 
 files = {}
 for f in cs.entries:
-files[f.file] = "%s%s" % ('.'.join([str(x)
+files[f.file] = "%s%s" % ('.'.join([(b"%d" % x)
 for x in f.revision]),
   ['', '(DEAD)'][f.dead])
 
 # add current commit to set
 c = commit(author=cs.author, date=date,
-   parents=[str(p.id) for p in cs.parents],
+   parents=[(b"%d" % p.id) for p in cs.parents],
desc=cs.comment, branch=cs.branch or '')
 self.changeset[id] = c
 self.files[id] = files
diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py
--- a/hgext/convert/__init__.py
+++ b/hgext/convert/__init__.py
@@ -482,7 +482,7 @@
 rev = ctx.extra().get('convert_revision', '')
 if rev.startswith('svn:'):
 if name == 'svnrev':
-return str(subversion.revsplit(rev)[2])
+return (b"%d" % subversion.revsplit(rev)[2])
 elif name == 'svnpath':
 return subversion.revsplit(rev)[1]
 elif name == 'svnuuid':



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3320: lock: don't use 'file' as a variable name

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3320

AFFECTED FILES
  mercurial/lock.py

CHANGE DETAILS

diff --git a/mercurial/lock.py b/mercurial/lock.py
--- a/mercurial/lock.py
+++ b/mercurial/lock.py
@@ -175,11 +175,11 @@
 
 _host = None
 
-def __init__(self, vfs, file, timeout=-1, releasefn=None, acquirefn=None,
+def __init__(self, vfs, fname, timeout=-1, releasefn=None, acquirefn=None,
  desc=None, inheritchecker=None, parentlock=None,
  dolock=True):
 self.vfs = vfs
-self.f = file
+self.f = fname
 self.held = 0
 self.timeout = timeout
 self.releasefn = releasefn



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3321: py3: add b'' prefixes to tests/test-status-inprocess.py

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  1. skip-blame because just b'' prefixes

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3321

AFFECTED FILES
  tests/test-status-inprocess.py

CHANGE DETAILS

diff --git a/tests/test-status-inprocess.py b/tests/test-status-inprocess.py
--- a/tests/test-status-inprocess.py
+++ b/tests/test-status-inprocess.py
@@ -10,17 +10,17 @@
 u = uimod.ui.load()
 
 print('% creating repo')
-repo = localrepo.localrepository(u, '.', create=True)
+repo = localrepo.localrepository(u, b'.', create=True)
 
 f = open('test.py', 'w')
 try:
 f.write('foo\n')
 finally:
 f.close
 
 print('% add and commit')
-commands.add(u, repo, 'test.py')
-commands.commit(u, repo, message='*')
+commands.add(u, repo, b'test.py')
+commands.commit(u, repo, message=b'*')
 commands.status(u, repo, clean=True)
 
 



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3322: py3: use urllib.parse.unquote_plus instead of urllib.unquote_plus

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a reviewer: durin42.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The later is not present in Python 3.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3322

AFFECTED FILES
  tests/test-narrow-clone-non-narrow-server.t

CHANGE DETAILS

diff --git a/tests/test-narrow-clone-non-narrow-server.t 
b/tests/test-narrow-clone-non-narrow-server.t
--- a/tests/test-narrow-clone-non-narrow-server.t
+++ b/tests/test-narrow-clone-non-narrow-server.t
@@ -18,8 +18,20 @@
   $ cat hg.pid >> "$DAEMON_PIDS"
 
 Verify that narrow is advertised in the bundle2 capabilities:
+
+  $ cat >> unquote.py < from __future__ import print_function
+  > import sys
+  > if sys.version[0] == '3':
+  > import urllib.parse as up
+  > unquote = up.unquote_plus
+  > else:
+  > import urllib
+  > unquote = urllib.unquote_plus
+  > print(unquote(list(sys.stdin)[1]))
+  > EOF
   $ echo hello | hg -R . serve --stdio | \
-  >   $PYTHON -c "from __future__ import print_function; import sys, urllib; 
print(urllib.unquote_plus(list(sys.stdin)[1]))" | grep narrow
+  >   $PYTHON unquote.py | grep narrow
   narrow=v0
 
   $ cd ..



To: pulkit, durin42, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3323: py3: iterate over a copy of dict while changing it

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3323

AFFECTED FILES
  mercurial/color.py

CHANGE DETAILS

diff --git a/mercurial/color.py b/mercurial/color.py
--- a/mercurial/color.py
+++ b/mercurial/color.py
@@ -168,7 +168,7 @@
 ui._terminfoparams.clear()
 return
 
-for key, (b, e, c) in ui._terminfoparams.items():
+for key, (b, e, c) in ui._terminfoparams.copy().items():
 if not b:
 continue
 if not c and not curses.tigetstr(e):



To: pulkit, #hg-reviewers
Cc: mercurial-devel, spectral
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3324: py3: use stringutil.forcebytestr() instead of str()

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  We need to convert errors to bytes using stringutil.forcebytestr()

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3324

AFFECTED FILES
  mercurial/exchange.py

CHANGE DETAILS

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -2257,7 +2257,7 @@
 continue
 
 except error.InvalidBundleSpecification as e:
-repo.ui.debug(str(e) + '\n')
+repo.ui.debug(stringutil.forcebytestr(e) + '\n')
 continue
 except error.UnsupportedBundleSpecification as e:
 repo.ui.debug('filtering %s because unsupported bundle '



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3325: py3: make sure curses.tigetstr() first argument is a str

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3325

AFFECTED FILES
  mercurial/color.py

CHANGE DETAILS

diff --git a/mercurial/color.py b/mercurial/color.py
--- a/mercurial/color.py
+++ b/mercurial/color.py
@@ -171,12 +171,12 @@
 for key, (b, e, c) in ui._terminfoparams.copy().items():
 if not b:
 continue
-if not c and not curses.tigetstr(e):
+if not c and not curses.tigetstr(pycompat.sysstr(e)):
 # Most terminals don't support dim, invis, etc, so don't be
 # noisy and use ui.debug().
 ui.debug("no terminfo entry for %s\n" % e)
 del ui._terminfoparams[key]
-if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
+if not curses.tigetstr(r'setaf') or not curses.tigetstr(r'setab'):
 # Only warn about missing terminfo entries if we explicitly asked for
 # terminfo mode and we're in a formatted terminal.
 if mode == "terminfo" and formatted:
@@ -325,11 +325,11 @@
 if termcode:
 return termcode
 else:
-return curses.tigetstr(val)
+return curses.tigetstr(pycompat.sysstr(val))
 elif bg:
-return curses.tparm(curses.tigetstr('setab'), val)
+return curses.tparm(curses.tigetstr(r'setab'), val)
 else:
-return curses.tparm(curses.tigetstr('setaf'), val)
+return curses.tparm(curses.tigetstr(r'setaf'), val)
 
 def _mergeeffects(text, start, stop):
 """Insert start sequence at every occurrence of stop sequence



To: pulkit, #hg-reviewers
Cc: mercurial-devel, spectral
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3326: py3: use str variables to check keys in request header

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The values in header are of str type.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3326

AFFECTED FILES
  mercurial/keepalive.py

CHANGE DETAILS

diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -318,24 +318,24 @@
 headers.update(sorted(req.unredirected_hdrs.items()))
 headers = util.sortdict((n.lower(), v) for n, v in headers.items())
 skipheaders = {}
-for n in ('host', 'accept-encoding'):
+for n in (r'host', r'accept-encoding'):
 if n in headers:
-skipheaders['skip_' + n.replace('-', '_')] = 1
+skipheaders[r'skip_' + n.replace(r'-', r'_')] = 1
 try:
 if urllibcompat.hasdata(req):
 data = urllibcompat.getdata(req)
 h.putrequest(
 req.get_method(), urllibcompat.getselector(req),
-**pycompat.strkwargs(skipheaders))
+skipheaders)
 if r'content-type' not in headers:
 h.putheader(r'Content-type',
 r'application/x-www-form-urlencoded')
 if r'content-length' not in headers:
 h.putheader(r'Content-length', r'%d' % len(data))
 else:
 h.putrequest(
 req.get_method(), urllibcompat.getselector(req),
-**pycompat.strkwargs(skipheaders))
+skipheaders)
 except socket.error as err:
 raise urlerr.urlerror(err)
 for k, v in headers.items():



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3327: py3: add b'' prefixes to make values bytes

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  1. skip-blame because just b'' prefixes

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3327

AFFECTED FILES
  mercurial/sslutil.py

CHANGE DETAILS

diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py
--- a/mercurial/sslutil.py
+++ b/mercurial/sslutil.py
@@ -621,13 +621,13 @@
 pats.append(re.escape(leftmost))
 else:
 # Otherwise, '*' matches any dotless string, e.g. www*
-pats.append(re.escape(leftmost).replace(r'\*', '[^.]*'))
+pats.append(re.escape(leftmost).replace(br'\*', '[^.]*'))
 
 # add the remaining fragments, ignore any wildcards
 for frag in remainder:
 pats.append(re.escape(frag))
 
-pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
+pat = re.compile(br'\A' + br'\.'.join(pats) + br'\Z', re.IGNORECASE)
 return pat.match(hostname) is not None
 
 def _verifycert(cert, hostname):



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3328: py3: use b"%d" instead of str() to convert int to bytes

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  While I was here, I added 'and None' to suppress return values of .write()
  calls.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3328

AFFECTED FILES
  tests/test-clone-uncompressed.t

CHANGE DETAILS

diff --git a/tests/test-clone-uncompressed.t b/tests/test-clone-uncompressed.t
--- a/tests/test-clone-uncompressed.t
+++ b/tests/test-clone-uncompressed.t
@@ -18,7 +18,7 @@
   $ hg -q commit -A -m initial
   >>> for i in range(1024):
   ... with open(str(i), 'wb') as fh:
-  ... fh.write(str(i))
+  ... fh.write(b"%d" % i) and None
   $ hg -q commit -A -m 'add a lot of files'
   $ hg st
   $ hg --config server.uncompressed=false serve -p $HGPORT -d --pid-file=hg.pid



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3329: py3: add b'' prefixes to make values bytes

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  1. skip-blame beacuse just b'' prefixes

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3329

AFFECTED FILES
  tests/test-clone-cgi.t
  tests/test-clone.t

CHANGE DETAILS

diff --git a/tests/test-clone.t b/tests/test-clone.t
--- a/tests/test-clone.t
+++ b/tests/test-clone.t
@@ -559,8 +559,8 @@
   $ cat < simpleclone.py
   > from mercurial import ui, hg
   > myui = ui.ui.load()
-  > repo = hg.repository(myui, 'a')
-  > hg.clone(myui, {}, repo, dest="ua")
+  > repo = hg.repository(myui, b'a')
+  > hg.clone(myui, {}, repo, dest=b"ua")
   > EOF
 
   $ $PYTHON simpleclone.py
@@ -573,8 +573,8 @@
   > from mercurial import ui, hg, extensions
   > myui = ui.ui.load()
   > extensions.loadall(myui)
-  > repo = hg.repository(myui, 'a')
-  > hg.clone(myui, {}, repo, dest="ua", branch=["stable",])
+  > repo = hg.repository(myui, b'a')
+  > hg.clone(myui, {}, repo, dest=b"ua", branch=[b"stable",])
   > EOF
 
   $ $PYTHON branchclone.py
diff --git a/tests/test-clone-cgi.t b/tests/test-clone-cgi.t
--- a/tests/test-clone-cgi.t
+++ b/tests/test-clone-cgi.t
@@ -17,7 +17,7 @@
   > from mercurial import demandimport; demandimport.enable()
   > from mercurial.hgweb import hgweb
   > from mercurial.hgweb import wsgicgi
-  > application = hgweb("test", "Empty test repository")
+  > application = hgweb(b"test", b"Empty test repository")
   > wsgicgi.launch(application)
   > HGWEB
   $ chmod 755 hgweb.cgi



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3330: py3: make values bytes before passing into server.runservice()

2018-04-13 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The values of opts dict still needed to be converted to bytes.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3330

AFFECTED FILES
  tests/dumbhttp.py

CHANGE DETAILS

diff --git a/tests/dumbhttp.py b/tests/dumbhttp.py
--- a/tests/dumbhttp.py
+++ b/tests/dumbhttp.py
@@ -13,6 +13,7 @@
 import sys
 
 from mercurial import (
+pycompat,
 server,
 util,
 )
@@ -63,10 +64,12 @@
 if options.foreground and options.pid:
 parser.error("options --pid and --foreground are mutually exclusive")
 
-opts = {'pid_file': options.pid,
-'daemon': not options.foreground,
-'daemon_postexec': options.daemon_postexec}
+opts = {b'pid_file': options.pid,
+b'daemon': not options.foreground,
+b'daemon_postexec': options.daemon_postexec}
 service = simplehttpservice(options.host, options.port)
+runargs = [sys.executable, __file__] + sys.argv[1:]
+runargs = [pycompat.fsencode(a) for a in runargs]
 server.runservice(opts, initfn=service.init, runfn=service.run,
   logfile=options.logfile,
-  runargs=[sys.executable, __file__] + sys.argv[1:])
+  runargs=runargs)



To: pulkit, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3303: cborutil: implement support for streaming encoding, bytestring decoding

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8152.
indygreg edited the summary of this revision.
indygreg retitled this revision from "cborutil: implement support for 
indefinite length CBOR types" to "cborutil: implement support for streaming 
encoding, bytestring decoding".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3303?vs=8104&id=8152

REVISION DETAIL
  https://phab.mercurial-scm.org/D3303

AFFECTED FILES
  contrib/import-checker.py
  mercurial/utils/cborutil.py
  tests/test-cbor.py

CHANGE DETAILS

diff --git a/tests/test-cbor.py b/tests/test-cbor.py
new file mode 100644
--- /dev/null
+++ b/tests/test-cbor.py
@@ -0,0 +1,182 @@
+from __future__ import absolute_import
+
+import io
+import unittest
+
+from mercurial.thirdparty import (
+cbor,
+)
+from mercurial.utils import (
+cborutil,
+)
+
+class BytestringTests(unittest.TestCase):
+def testsimple(self):
+self.assertEqual(
+list(cborutil.streamencode(b'foobar')),
+[b'\x46', b'foobar'])
+
+self.assertEqual(
+cbor.loads(b''.join(cborutil.streamencode(b'foobar'))),
+b'foobar')
+
+def testlong(self):
+source = b'x' * 1048576
+
+self.assertEqual(
+cbor.loads(b''.join(cborutil.streamencode(source))),
+source)
+
+def testfromiter(self):
+# This is the example from RFC 7049 Section 2.2.2.
+source = [b'\xaa\xbb\xcc\xdd', b'\xee\xff\x99']
+
+self.assertEqual(
+list(cborutil.streamencodebytestringfromiter(source)),
+[
+b'\x5f',
+b'\x44',
+b'\xaa\xbb\xcc\xdd',
+b'\x43',
+b'\xee\xff\x99',
+b'\xff',
+])
+
+dest = b''.join(cborutil.streamencodebytestringfromiter(source))
+self.assertEqual(cbor.loads(dest), b''.join(source))
+
+def testfromiterlarge(self):
+source = [b'a' * 16, b'b' * 128, b'c' * 1024, b'd' * 1048576]
+
+dest = b''.join(cborutil.streamencodebytestringfromiter(source))
+
+self.assertEqual(cbor.loads(dest), b''.join(source))
+
+def testindefinite(self):
+source = b'\x00\x01\x02\x03' + b'\xff' * 16384
+
+it = cborutil.streamencodeindefinitebytestring(source, chunksize=2)
+
+self.assertEqual(next(it), b'\x5f')
+self.assertEqual(next(it), b'\x42')
+self.assertEqual(next(it), b'\x00\x01')
+self.assertEqual(next(it), b'\x42')
+self.assertEqual(next(it), b'\x02\x03')
+self.assertEqual(next(it), b'\x42')
+self.assertEqual(next(it), b'\xff\xff')
+
+dest = b''.join(cborutil.streamencodeindefinitebytestring(
+source, chunksize=42))
+self.assertEqual(cbor.loads(dest), b''.join(source))
+
+def testreadtoiter(self):
+source = io.BytesIO(b'\x5f\x44\xaa\xbb\xcc\xdd\x43\xee\xff\x99\xff')
+
+it = cborutil.readindefinitebytestringtoiter(source)
+self.assertEqual(next(it), b'\xaa\xbb\xcc\xdd')
+self.assertEqual(next(it), b'\xee\xff\x99')
+
+with self.assertRaises(StopIteration):
+next(it)
+
+class IntTests(unittest.TestCase):
+def testsmall(self):
+self.assertEqual(list(cborutil.streamencode(0)), [b'\x00'])
+self.assertEqual(list(cborutil.streamencode(1)), [b'\x01'])
+self.assertEqual(list(cborutil.streamencode(2)), [b'\x02'])
+self.assertEqual(list(cborutil.streamencode(3)), [b'\x03'])
+self.assertEqual(list(cborutil.streamencode(4)), [b'\x04'])
+
+def testnegativesmall(self):
+self.assertEqual(list(cborutil.streamencode(-1)), [b'\x20'])
+self.assertEqual(list(cborutil.streamencode(-2)), [b'\x21'])
+self.assertEqual(list(cborutil.streamencode(-3)), [b'\x22'])
+self.assertEqual(list(cborutil.streamencode(-4)), [b'\x23'])
+self.assertEqual(list(cborutil.streamencode(-5)), [b'\x24'])
+
+def testrange(self):
+for i in range(-7, 7, 10):
+self.assertEqual(
+b''.join(cborutil.streamencode(i)),
+cbor.dumps(i))
+
+class ArrayTests(unittest.TestCase):
+def testempty(self):
+self.assertEqual(list(cborutil.streamencode([])), [b'\x80'])
+self.assertEqual(cbor.loads(b''.join(cborutil.streamencode([]))), [])
+
+def testbasic(self):
+source = [b'foo', b'bar', 1, -10]
+
+self.assertEqual(list(cborutil.streamencode(source)), [
+b'\x84', b'\x43', b'foo', b'\x43', b'bar', b'\x01', b'\x29'])
+
+def testemptyfromiter(self):
+self.assertEqual(b''.join(cborutil.streamencodearrayfromiter([])),
+ b'\x9f\xff')
+
+def testfromiter1(self):
+source = [b'foo']
+
+self.assertEqual(list(cborutil.streamencodearrayfromiter(source)), [
+b'\x9f',
+b'\x43', b'foo',
+b'\xff',
+])
+
+
+dest

D3331: util: set correct stack level on deprecation warnings

2018-04-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Without this patch, you'll get something like this:
  
/mercurial/util.py:3784: DeprecationWarning: 'util.hgexecutable'
is deprecated, use 'utils.procutil.hgexecutable'
  
  (but on one line)

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3331

AFFECTED FILES
  mercurial/util.py

CHANGE DETAILS

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -3781,7 +3781,7 @@
 fn = pycompat.sysbytes(func.__name__)
 mn = modname or pycompat.sysbytes(func.__module__)[len('mercurial.'):]
 msg = "'util.%s' is deprecated, use '%s.%s'" % (fn, mn, fn)
-nouideprecwarn(msg, version)
+nouideprecwarn(msg, version, stacklevel=2)
 return func(*args, **kwargs)
 wrapped.__name__ = func.__name__
 return wrapped



To: martinvonz, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3303: cborutil: implement support for streaming encoding, bytestring decoding

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  I ended up implementing my own CBOR encoder for a starting subset of types. 
Profiling the wire protocol server inspired me to do this.
  
  I have a future wire protocol command that emits the fulltext data of every 
file in a revision. It was taking ~45s CPU to run. After plugging in the new 
generator based CBOR encoder, that drops to ~31s. All pure Python still too.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3303

To: indygreg, #hg-reviewers
Cc: yuja, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3297: httppeer: implement command executor for version 2 peer

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8153.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3297?vs=8102&id=8153

REVISION DETAIL
  https://phab.mercurial-scm.org/D3297

AFFECTED FILES
  mercurial/httppeer.py

CHANGE DETAILS

diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -13,7 +13,9 @@
 import os
 import socket
 import struct
+import sys
 import tempfile
+import weakref
 
 from .i18n import _
 from .thirdparty import (
@@ -31,7 +33,6 @@
 statichttprepo,
 url as urlmod,
 util,
-wireproto,
 wireprotoframing,
 wireprototypes,
 wireprotov1peer,
@@ -517,8 +518,262 @@
 def _abort(self, exception):
 raise exception
 
+def sendv2request(ui, opener, requestbuilder, apiurl, permission, requests):
+reactor = wireprotoframing.clientreactor(hasmultiplesend=False,
+ buffersends=True)
+
+url = '%s/%s' % (apiurl, permission)
+
+if len(requests) > 1:
+url += '/multirequest'
+else:
+url += '/%s' % requests[0][0]
+
+# Request ID to (request, future)
+requestmap = {}
+
+for command, args, f in requests:
+request, action, meta = reactor.callcommand(command, args)
+assert action == 'noop'
+
+requestmap[request.requestid] = (request, f)
+
+action, meta = reactor.flushcommands()
+assert action == 'sendframes'
+
+# TODO stream this.
+body = b''.join(map(bytes, meta['framegen']))
+
+# TODO modify user-agent to reflect v2
+headers = {
+r'Accept': wireprotov2server.FRAMINGTYPE,
+r'Content-Type': wireprotov2server.FRAMINGTYPE,
+}
+
+req = requestbuilder(pycompat.strurl(url), body, headers)
+req.add_unredirected_header(r'Content-Length', r'%d' % len(body))
+
+try:
+res = opener.open(req)
+except urlerr.httperror as e:
+if e.code == 401:
+raise error.Abort(_('authorization failed'))
+
+raise
+except httplib.HTTPException as e:
+ui.traceback()
+raise IOError(None, e)
+
+return reactor, requestmap, res
+
+class queuedcommandfuture(pycompat.futures.Future):
+"""Wraps result() on command futures to trigger submission on call."""
+
+def result(self, timeout=None):
+if self.done():
+return pycompat.futures.Future.result(self, timeout)
+
+self._peerexecutor.sendcommands()
+
+# sendcommands() will restore the original __class__ and self.result
+# will resolve to Future.result.
+return self.result(timeout)
+
+@zi.implementer(repository.ipeercommandexecutor)
+class httpv2executor(object):
+def __init__(self, ui, opener, requestbuilder, apiurl, descriptor):
+self._ui = ui
+self._opener = opener
+self._requestbuilder = requestbuilder
+self._apiurl = apiurl
+self._descriptor = descriptor
+self._sent = False
+self._closed = False
+self._neededpermissions = set()
+self._calls = []
+self._futures = weakref.WeakSet()
+self._responseexecutor = None
+self._responsef = None
+
+def __enter__(self):
+return self
+
+def __exit__(self, exctype, excvalue, exctb):
+self.close()
+
+def callcommand(self, command, args):
+if self._sent:
+raise error.ProgrammingError('callcommand() cannot be used after '
+ 'commands are sent')
+
+if self._closed:
+raise error.ProgrammingError('callcommand() cannot be used after '
+ 'close()')
+
+# The service advertises which commands are available. So if we attempt
+# to call an unknown command or pass an unknown argument, we can screen
+# for this.
+if command not in self._descriptor['commands']:
+raise error.ProgrammingError(
+'wire protocol command %s is not available' % command)
+
+cmdinfo = self._descriptor['commands'][command]
+unknownargs = set(args.keys()) - set(cmdinfo.get('args', {}))
+
+if unknownargs:
+raise error.ProgrammingError(
+'wire protocol command %s does not accept argument: %s' % (
+command, ', '.join(sorted(unknownargs
+
+self._neededpermissions |= set(cmdinfo['permissions'])
+
+# TODO we /could/ also validate types here, since the API descriptor
+# includes types...
+
+f = pycompat.futures.Future()
+
+# Monkeypatch it so result() triggers sendcommands(), otherwise 
result()
+# could deadlock.
+f.__class__ = queuedcommandfuture
+f._peerexecutor = self
+
+self._futures.add(f)
+self._calls.append((command, args, f))
+
+return f
+
+def sendcommands(self):
+if self._sent:
+return
+
+  

D3332: httppeer: handle error response from client reactor

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  With this in place, we're now seeing useful errors when running
  tests with the new wire protocol enabled!

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3332

AFFECTED FILES
  mercurial/httppeer.py

CHANGE DETAILS

diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -763,6 +763,14 @@
 f.set_result(result)
 del results[request.requestid]
 
+elif action == 'error':
+e = error.RepoError(meta['message'])
+
+if f:
+f.set_exception(e)
+else:
+raise e
+
 else:
 e = error.ProgrammingError('unhandled action: %s' % action)
 



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3298: debugcommands: use command executor for invoking commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 8154.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3298?vs=8091&id=8154

REVISION DETAIL
  https://phab.mercurial-scm.org/D3298

AFFECTED FILES
  mercurial/debugcommands.py
  tests/test-http-protocol.t
  tests/test-ssh-proto.t

CHANGE DETAILS

diff --git a/tests/test-ssh-proto.t b/tests/test-ssh-proto.t
--- a/tests/test-ssh-proto.t
+++ b/tests/test-ssh-proto.t
@@ -1367,7 +1367,7 @@
   o> bookmarks\t\n
   o> namespaces\t\n
   o> phases\t
-  response: b'bookmarks\t\nnamespaces\t\nphases\t'
+  response: {b'bookmarks': b'', b'namespaces': b'', b'phases': b''}
   
   testing ssh2
   creating ssh peer from handshake results
@@ -1398,7 +1398,7 @@
   o> bookmarks\t\n
   o> namespaces\t\n
   o> phases\t
-  response: b'bookmarks\t\nnamespaces\t\nphases\t'
+  response: {b'bookmarks': b'', b'namespaces': b'', b'phases': b''}
 
   $ cd ..
 
@@ -1443,7 +1443,7 @@
   i> flush() -> None
   o> bufferedreadline() -> 2:
   o> 0\n
-  response: b''
+  response: {}
   
   testing ssh2
   creating ssh peer from handshake results
@@ -1470,7 +1470,7 @@
   i> flush() -> None
   o> bufferedreadline() -> 2:
   o> 0\n
-  response: b''
+  response: {}
 
 With a single bookmark set
 
@@ -1505,7 +1505,7 @@
   o> bufferedreadline() -> 3:
   o> 46\n
   o> bufferedread(46) -> 46: bookA\t68986213bd4485ea51533535e3fc9e78007a711f
-  response: b'bookA\t68986213bd4485ea51533535e3fc9e78007a711f'
+  response: {b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f'}
   
   testing ssh2
   creating ssh peer from handshake results
@@ -1533,7 +1533,7 @@
   o> bufferedreadline() -> 3:
   o> 46\n
   o> bufferedread(46) -> 46: bookA\t68986213bd4485ea51533535e3fc9e78007a711f
-  response: b'bookA\t68986213bd4485ea51533535e3fc9e78007a711f'
+  response: {b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f'}
 
 With multiple bookmarks set
 
@@ -1570,7 +1570,7 @@
   o> bufferedread(93) -> 93:
   o> bookA\t68986213bd4485ea51533535e3fc9e78007a711f\n
   o> bookB\t1880f3755e2e52e3199e0ee5638128b08642f34d
-  response: 
b'bookA\t68986213bd4485ea51533535e3fc9e78007a711f\nbookB\t1880f3755e2e52e3199e0ee5638128b08642f34d'
+  response: {b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f', b'bookB': 
b'1880f3755e2e52e3199e0ee5638128b08642f34d'}
   
   testing ssh2
   creating ssh peer from handshake results
@@ -1600,7 +1600,7 @@
   o> bufferedread(93) -> 93:
   o> bookA\t68986213bd4485ea51533535e3fc9e78007a711f\n
   o> bookB\t1880f3755e2e52e3199e0ee5638128b08642f34d
-  response: 
b'bookA\t68986213bd4485ea51533535e3fc9e78007a711f\nbookB\t1880f3755e2e52e3199e0ee5638128b08642f34d'
+  response: {b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f', b'bookB': 
b'1880f3755e2e52e3199e0ee5638128b08642f34d'}
 
 Test pushkey for bookmarks
 
@@ -1646,7 +1646,7 @@
   o> 2\n
   o> bufferedread(2) -> 2:
   o> 1\n
-  response: b'1\n'
+  response: True
   
   testing ssh2
   creating ssh peer from handshake results
@@ -1683,7 +1683,7 @@
   o> 2\n
   o> bufferedread(2) -> 2:
   o> 1\n
-  response: b'1\n'
+  response: True
 
   $ hg bookmarks
  bookA 0:68986213bd44
@@ -1729,7 +1729,7 @@
   o> bufferedreadline() -> 3:
   o> 15\n
   o> bufferedread(15) -> 15: publishing\tTrue
-  response: b'publishing\tTrue'
+  response: {b'publishing': b'True'}
   
   testing ssh2
   creating ssh peer from handshake results
@@ -1757,7 +1757,7 @@
   o> bufferedreadline() -> 3:
   o> 15\n
   o> bufferedread(15) -> 15: publishing\tTrue
-  response: b'publishing\tTrue'
+  response: {b'publishing': b'True'}
 
 Create some commits
 
@@ -1811,7 +1811,7 @@
   o> 20b8a89289d80036e6c4e87c2083e3bea1586637\t1\n
   o> c4750011d906c18ea2f0527419cbc1a544435150\t1\n
   o> publishing\tTrue
-  response: 
b'20b8a89289d80036e6c4e87c2083e3bea1586637\t1\nc4750011d906c18ea2f0527419cbc1a544435150\t1\npublishing\tTrue'
+  response: {b'20b8a89289d80036e6c4e87c2083e3bea1586637': b'1', 
b'c4750011d906c18ea2f0527419cbc1a544435150': b'1', b'publishing': b'True'}
   
   testing ssh2
   creating ssh peer from handshake results
@@ -1842,7 +1842,7 @@
   o> 20b8a89289d80036e6c4e87c2083e3bea1586637\t1\n
   o> c4750011d906c18ea2f0527419cbc1a544435150\t1\n
   o> publishing\tTrue
-  response: 
b'20b8a89289d80036e6c4e87c2083e3bea1586637\t1\nc4750011d906c18ea2f0527419cbc1a544435150\t1\npublishing\tTrue'
+  response: {b'20b8a89289d80036e6c4e87c2083e3bea1586637': b'1', 
b'c4750011d906c18ea2f0527419cbc1a544435150': b'1', b'publishing': b'True'}
 
 Single draft head
 
@@ -1879,7 +1879,7 @@
   o> bufferedread(58) -> 58:
   o> c4750011d906c18ea2f0527419cbc1a544435150\t1\n
   o> publishing\tTrue
-  response: b'c4750011d906c18ea2f0527419cbc1a544435150\t1\npublishing\tTrue'
+  response: {b'c4750011d906c18ea2f0527419cbc1a544435150': b'1', b'publishing': 
b'True'}
   
   testing ssh2
   creating ssh peer from handshake results
@@ -1909,7 +1

D3333: wireprotoframing: use value passed into function

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Oops.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D

AFFECTED FILES
  mercurial/wireprotoframing.py

CHANGE DETAILS

diff --git a/mercurial/wireprotoframing.py b/mercurial/wireprotoframing.py
--- a/mercurial/wireprotoframing.py
+++ b/mercurial/wireprotoframing.py
@@ -464,7 +464,7 @@
 
 def __init__(self, streamid, active=False):
 self.streamid = streamid
-self._active = False
+self._active = active
 
 def makeframe(self, requestid, typeid, flags, payload):
 """Create a frame to be sent out over this stream.



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3334: wireprotoframing: record when new stream is encountered

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Without this, we choke after receiving the 2nd frame in a stream.
  Not sure how we made it this far without finding this bug.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3334

AFFECTED FILES
  mercurial/wireprotoframing.py
  tests/test-wireproto-clientreactor.py

CHANGE DETAILS

diff --git a/tests/test-wireproto-clientreactor.py 
b/tests/test-wireproto-clientreactor.py
--- a/tests/test-wireproto-clientreactor.py
+++ b/tests/test-wireproto-clientreactor.py
@@ -105,6 +105,26 @@
  'unhandled frame type'):
 sendframe(reactor, ffs(b'1 0 stream-begin text-output 0 foo'))
 
+class StreamTests(unittest.TestCase):
+def testmultipleresponseframes(self):
+reactor = framing.clientreactor(buffersends=False)
+
+request, action, meta = reactor.callcommand(b'foo', {})
+
+self.assertEqual(action, 'sendframes')
+for f in meta['framegen']:
+pass
+
+action, meta = sendframe(
+reactor,
+ffs(b'%d 0 stream-begin 4 0 foo' % request.requestid))
+self.assertEqual(action, 'responsedata')
+
+action, meta = sendframe(
+reactor,
+ffs(b'%d 0 0 4 eos bar' % request.requestid))
+self.assertEqual(action, 'responsedata')
+
 if __name__ == '__main__':
 import silenttestrunner
 silenttestrunner.main(__name__)
diff --git a/mercurial/wireprotoframing.py b/mercurial/wireprotoframing.py
--- a/mercurial/wireprotoframing.py
+++ b/mercurial/wireprotoframing.py
@@ -1029,6 +1029,8 @@
  'without beginning of stream flag set'),
 }
 
+self._incomingstreams[frame.streamid] = stream(frame.streamid)
+
 if frame.streamflags & STREAM_FLAG_ENCODING_APPLIED:
 raise error.ProgrammingError('support for decoding stream '
  'payloads not yet implemneted')



To: indygreg, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3335: wireproto: expose repository formats via capabilities

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Servers need to expose their set of repository storage requirements
  in order to facilitate streaming clones (clients need to know
  if they are capable of reading the raw storage files that the
  server exposes).

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3335

AFFECTED FILES
  mercurial/help/internals/wireprotocol.txt
  mercurial/wireprotov2server.py
  tests/test-http-api-httpv2.t
  tests/test-http-protocol.t
  tests/test-wireproto-command-branchmap.t
  tests/test-wireproto-command-capabilities.t
  tests/test-wireproto-command-known.t
  tests/test-wireproto-command-listkeys.t
  tests/test-wireproto-command-lookup.t
  tests/test-wireproto-command-pushkey.t

CHANGE DETAILS

diff --git a/tests/test-wireproto-command-pushkey.t 
b/tests/test-wireproto-command-pushkey.t
--- a/tests/test-wireproto-command-pushkey.t
+++ b/tests/test-wireproto-command-pushkey.t
@@ -45,7 +45,7 @@
   s> Content-Type: application/mercurial-cbor\r\n
   s> Content-Length: *\r\n (glob)
   s> \r\n
-  s> 
\xa3Dapis\xa1Pexp-http-v2-0001\xa3Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0003GapibaseDapi/Nv1capabilitiesY\x01\xcabatch
 branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset 
compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s> 
\xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0003GapibaseDapi/Nv1capabilitiesY\x01\xcabatch
 branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset 
compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   sending pushkey command
   s> *\r\n (glob)
   s> Accept-Encoding: identity\r\n
@@ -93,7 +93,7 @@
   s> Content-Type: application/mercurial-cbor\r\n
   s> Content-Length: *\r\n (glob)
   s> \r\n
-  s> 
\xa3Dapis\xa1Pexp-http-v2-0001\xa3Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0003GapibaseDapi/Nv1capabilitiesY\x01\xcabatch
 branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset 
compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s> 
\xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0003GapibaseDapi/Nv1capabilitiesY\x01\xcabatch
 branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset 
compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   sending listkeys command
   s> POST /api/exp-http-v2-0001/ro/listkeys HTTP/1.1\r\n
   s> Accept-Encoding: identity\r\n
diff --git a/tests/t

D3261: thirdparty: vendor futures 3.2.0

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGeb687c28a915: thirdparty: vendor futures 3.2.0 (authored by 
indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3261?vs=8027&id=8159

REVISION DETAIL
  https://phab.mercurial-scm.org/D3261

AFFECTED FILES
  mercurial/thirdparty/concurrent/LICENSE
  mercurial/thirdparty/concurrent/__init__.py
  mercurial/thirdparty/concurrent/futures/__init__.py
  mercurial/thirdparty/concurrent/futures/_base.py
  mercurial/thirdparty/concurrent/futures/process.py
  mercurial/thirdparty/concurrent/futures/thread.py

CHANGE DETAILS

diff --git a/mercurial/thirdparty/concurrent/futures/thread.py 
b/mercurial/thirdparty/concurrent/futures/thread.py
new file mode 100644
--- /dev/null
+++ b/mercurial/thirdparty/concurrent/futures/thread.py
@@ -0,0 +1,160 @@
+# Copyright 2009 Brian Quinlan. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Implements ThreadPoolExecutor."""
+
+import atexit
+from concurrent.futures import _base
+import itertools
+import Queue as queue
+import threading
+import weakref
+import sys
+
+try:
+from multiprocessing import cpu_count
+except ImportError:
+# some platforms don't have multiprocessing
+def cpu_count():
+return None
+
+__author__ = 'Brian Quinlan (br...@sweetapp.com)'
+
+# Workers are created as daemon threads. This is done to allow the interpreter
+# to exit when there are still idle threads in a ThreadPoolExecutor's thread
+# pool (i.e. shutdown() was not called). However, allowing workers to die with
+# the interpreter has two undesirable properties:
+#   - The workers would still be running during interpretor shutdown,
+# meaning that they would fail in unpredictable ways.
+#   - The workers could be killed while evaluating a work item, which could
+# be bad if the callable being evaluated has external side-effects e.g.
+# writing to a file.
+#
+# To work around this problem, an exit handler is installed which tells the
+# workers to exit when their work queues are empty and then waits until the
+# threads finish.
+
+_threads_queues = weakref.WeakKeyDictionary()
+_shutdown = False
+
+def _python_exit():
+global _shutdown
+_shutdown = True
+items = list(_threads_queues.items()) if _threads_queues else ()
+for t, q in items:
+q.put(None)
+for t, q in items:
+t.join(sys.maxint)
+
+atexit.register(_python_exit)
+
+class _WorkItem(object):
+def __init__(self, future, fn, args, kwargs):
+self.future = future
+self.fn = fn
+self.args = args
+self.kwargs = kwargs
+
+def run(self):
+if not self.future.set_running_or_notify_cancel():
+return
+
+try:
+result = self.fn(*self.args, **self.kwargs)
+except:
+e, tb = sys.exc_info()[1:]
+self.future.set_exception_info(e, tb)
+else:
+self.future.set_result(result)
+
+def _worker(executor_reference, work_queue):
+try:
+while True:
+work_item = work_queue.get(block=True)
+if work_item is not None:
+work_item.run()
+# Delete references to object. See issue16284
+del work_item
+continue
+executor = executor_reference()
+# Exit if:
+#   - The interpreter is shutting down OR
+#   - The executor that owns the worker has been collected OR
+#   - The executor that owns the worker has been shutdown.
+if _shutdown or executor is None or executor._shutdown:
+# Notice other workers
+work_queue.put(None)
+return
+del executor
+except:
+_base.LOGGER.critical('Exception in worker', exc_info=True)
+
+
+class ThreadPoolExecutor(_base.Executor):
+
+# Used to assign unique thread names when thread_name_prefix is not 
supplied.
+_counter = itertools.count().next
+
+def __init__(self, max_workers=None, thread_name_prefix=''):
+"""Initializes a new ThreadPoolExecutor instance.
+
+Args:
+max_workers: The maximum number of threads that can be used to
+execute the given calls.
+thread_name_prefix: An optional name prefix to give our threads.
+"""
+if max_workers is None:
+# Use this number because ThreadPoolExecutor is often
+# used to overlap I/O instead of CPU work.
+max_workers = (cpu_count() or 1) * 5
+if max_workers <= 0:
+raise ValueError("max_workers must be greater than 0")
+
+self._max_workers = max_workers
+self._work_queue = queue.Queue()
+self._threads = set()
+self._shutdown = False
+self._shutdown_lock = threading.Lock()
+self._thread_name_prefix = (thread_name_prefi

D3264: futures: switch to absolute and relative imports

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0a9c0d3480b2: futures: switch to absolute and relative 
imports (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3264?vs=8030&id=8162

REVISION DETAIL
  https://phab.mercurial-scm.org/D3264

AFFECTED FILES
  mercurial/thirdparty/concurrent/futures/__init__.py
  mercurial/thirdparty/concurrent/futures/_base.py
  mercurial/thirdparty/concurrent/futures/process.py
  mercurial/thirdparty/concurrent/futures/thread.py

CHANGE DETAILS

diff --git a/mercurial/thirdparty/concurrent/futures/thread.py 
b/mercurial/thirdparty/concurrent/futures/thread.py
--- a/mercurial/thirdparty/concurrent/futures/thread.py
+++ b/mercurial/thirdparty/concurrent/futures/thread.py
@@ -3,8 +3,10 @@
 
 """Implements ThreadPoolExecutor."""
 
+from __future__ import absolute_import
+
 import atexit
-from concurrent.futures import _base
+from . import _base
 import itertools
 import Queue as queue
 import threading
diff --git a/mercurial/thirdparty/concurrent/futures/process.py 
b/mercurial/thirdparty/concurrent/futures/process.py
--- a/mercurial/thirdparty/concurrent/futures/process.py
+++ b/mercurial/thirdparty/concurrent/futures/process.py
@@ -43,8 +43,10 @@
   _ResultItems in "Request Q"
 """
 
+from __future__ import absolute_import
+
 import atexit
-from concurrent.futures import _base
+from . import _base
 import Queue as queue
 import multiprocessing
 import threading
diff --git a/mercurial/thirdparty/concurrent/futures/_base.py 
b/mercurial/thirdparty/concurrent/futures/_base.py
--- a/mercurial/thirdparty/concurrent/futures/_base.py
+++ b/mercurial/thirdparty/concurrent/futures/_base.py
@@ -1,6 +1,8 @@
 # Copyright 2009 Brian Quinlan. All Rights Reserved.
 # Licensed to PSF under a Contributor Agreement.
 
+from __future__ import absolute_import
+
 import collections
 import logging
 import threading
diff --git a/mercurial/thirdparty/concurrent/futures/__init__.py 
b/mercurial/thirdparty/concurrent/futures/__init__.py
--- a/mercurial/thirdparty/concurrent/futures/__init__.py
+++ b/mercurial/thirdparty/concurrent/futures/__init__.py
@@ -3,21 +3,25 @@
 
 """Execute computations asynchronously using threads or processes."""
 
+from __future__ import absolute_import
+
 __author__ = 'Brian Quinlan (br...@sweetapp.com)'
 
-from concurrent.futures._base import (FIRST_COMPLETED,
-  FIRST_EXCEPTION,
-  ALL_COMPLETED,
-  CancelledError,
-  TimeoutError,
-  Future,
-  Executor,
-  wait,
-  as_completed)
-from concurrent.futures.thread import ThreadPoolExecutor
+from ._base import (
+FIRST_COMPLETED,
+FIRST_EXCEPTION,
+ALL_COMPLETED,
+CancelledError,
+TimeoutError,
+Future,
+Executor,
+wait,
+as_completed,
+)
+from .thread import ThreadPoolExecutor
 
 try:
-from concurrent.futures.process import ProcessPoolExecutor
+from .process import ProcessPoolExecutor
 except ImportError:
 # some platforms don't have multiprocessing
 pass



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3262: futures: get rid of extend_path

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG33db69b6b58b: futures: get rid of extend_path (authored by 
indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3262?vs=8028&id=8160

REVISION DETAIL
  https://phab.mercurial-scm.org/D3262

AFFECTED FILES
  mercurial/thirdparty/concurrent/__init__.py

CHANGE DETAILS

diff --git a/mercurial/thirdparty/concurrent/__init__.py 
b/mercurial/thirdparty/concurrent/__init__.py
--- a/mercurial/thirdparty/concurrent/__init__.py
+++ b/mercurial/thirdparty/concurrent/__init__.py
@@ -1,3 +0,0 @@
-from pkgutil import extend_path
-
-__path__ = extend_path(__path__, __name__)



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3263: tests: silence pyflakes for thirdparty/concurrent

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG3ccaf995f549: tests: silence pyflakes for 
thirdparty/concurrent (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3263?vs=8029&id=8161

REVISION DETAIL
  https://phab.mercurial-scm.org/D3263

AFFECTED FILES
  tests/test-check-pyflakes.t

CHANGE DETAILS

diff --git a/tests/test-check-pyflakes.t b/tests/test-check-pyflakes.t
--- a/tests/test-check-pyflakes.t
+++ b/tests/test-check-pyflakes.t
@@ -17,6 +17,7 @@
   > -X hgext/fsmonitor/pywatchman \
   > -X mercurial/pycompat.py -X contrib/python-zstandard \
   > -X mercurial/thirdparty/cbor \
+  > -X mercurial/thirdparty/concurrent \
   > -X mercurial/thirdparty/zope \
   > 2>/dev/null \
   > | xargs pyflakes 2>/dev/null | "$TESTDIR/filterpyflakes.py"



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3266: pycompat: export a handle on concurrent.futures

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG8da30ceae88f: pycompat: export a handle on 
concurrent.futures (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3266?vs=8032&id=8164

REVISION DETAIL
  https://phab.mercurial-scm.org/D3266

AFFECTED FILES
  mercurial/pycompat.py

CHANGE DETAILS

diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py
--- a/mercurial/pycompat.py
+++ b/mercurial/pycompat.py
@@ -26,7 +26,10 @@
 import Queue as _queue
 import SocketServer as socketserver
 import xmlrpclib
+
+from .thirdparty.concurrent import futures
 else:
+import concurrent.futures as futures
 import http.cookiejar as cookielib
 import http.client as httplib
 import pickle



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3267: repository: define new interface for running commands

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGfa0382088993: repository: define new interface for running 
commands (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3267?vs=8120&id=8165

REVISION DETAIL
  https://phab.mercurial-scm.org/D3267

AFFECTED FILES
  mercurial/repository.py

CHANGE DETAILS

diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -196,6 +196,88 @@
 def changegroupsubset(bases, heads, kind):
 pass
 
+class ipeercommandexecutor(zi.Interface):
+"""Represents a mechanism to execute remote commands.
+
+This is the primary interface for requesting that wire protocol commands
+be executed. Instances of this interface are active in a context manager
+and have a well-defined lifetime. When the context manager exits, all
+outstanding requests are waited on.
+"""
+
+def callcommand(name, args):
+"""Request that a named command be executed.
+
+Receives the command name and a dictionary of command arguments.
+
+Returns a ``concurrent.futures.Future`` that will resolve to the
+result of that command request. That exact value is left up to
+the implementation and possibly varies by command.
+
+Not all commands can coexist with other commands in an executor
+instance: it depends on the underlying wire protocol transport being
+used and the command itself.
+
+Implementations MAY call ``sendcommands()`` automatically if the
+requested command can not coexist with other commands in this executor.
+
+Implementations MAY call ``sendcommands()`` automatically when the
+future's ``result()`` is called. So, consumers using multiple
+commands with an executor MUST ensure that ``result()`` is not called
+until all command requests have been issued.
+"""
+
+def sendcommands():
+"""Trigger submission of queued command requests.
+
+Not all transports submit commands as soon as they are requested to
+run. When called, this method forces queued command requests to be
+issued. It will no-op if all commands have already been sent.
+
+When called, no more new commands may be issued with this executor.
+"""
+
+def close():
+"""Signal that this command request is finished.
+
+When called, no more new commands may be issued. All outstanding
+commands that have previously been issued are waited on before
+returning. This not only includes waiting for the futures to resolve,
+but also waiting for all response data to arrive. In other words,
+calling this waits for all on-wire state for issued command requests
+to finish.
+
+When used as a context manager, this method is called when exiting the
+context manager.
+
+This method may call ``sendcommands()`` if there are buffered commands.
+"""
+
+class ipeerrequests(zi.Interface):
+"""Interface for executing commands on a peer."""
+
+def commandexecutor():
+"""A context manager that resolves to an ipeercommandexecutor.
+
+The object this resolves to can be used to issue command requests
+to the peer.
+
+Callers should call its ``callcommand`` method to issue command
+requests.
+
+A new executor should be obtained for each distinct set of commands
+(possibly just a single command) that the consumer wants to execute
+as part of a single operation or round trip. This is because some
+peers are half-duplex and/or don't support persistent connections.
+e.g. in the case of HTTP peers, commands sent to an executor represent
+a single HTTP request. While some peers may support multiple command
+sends over the wire per executor, consumers need to code to the least
+capable peer. So it should be assumed that command executors buffer
+called commands until they are told to send them and that each
+command executor could result in a new connection or wire-level request
+being issued.
+"""
+
 class ipeerbase(ipeerconnection, ipeercapabilities, ipeercommands):
 """Unified interface for peer repositories.
 



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3265: setup: add packages for concurrent.futures

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGcfb32979abcd: setup: add packages for concurrent.futures 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3265?vs=8031&id=8163

REVISION DETAIL
  https://phab.mercurial-scm.org/D3265

AFFECTED FILES
  setup.py

CHANGE DETAILS

diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -812,6 +812,8 @@
 'mercurial.thirdparty.attr',
 'mercurial.thirdparty.cbor',
 'mercurial.thirdparty.cbor.cbor2',
+'mercurial.thirdparty.concurrent',
+'mercurial.thirdparty.concurrent.futures',
 'mercurial.thirdparty.zope',
 'mercurial.thirdparty.zope.interface',
 'mercurial.utils',



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3270: largefiles: use command executor for batch operation

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG6c55ce51d6c3: largefiles: use command executor for batch 
operation (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3270?vs=8123&id=8168

REVISION DETAIL
  https://phab.mercurial-scm.org/D3270

AFFECTED FILES
  hgext/largefiles/wirestore.py
  tests/test-largefiles-wireproto.t

CHANGE DETAILS

diff --git a/tests/test-largefiles-wireproto.t 
b/tests/test-largefiles-wireproto.t
--- a/tests/test-largefiles-wireproto.t
+++ b/tests/test-largefiles-wireproto.t
@@ -312,7 +312,7 @@
   getting changed largefiles
   using http://localhost:$HGPORT2/
   sending capabilities command
-  sending batch command
+  sending statlfile command
   getting largefiles: 0/1 files (0.00%)
   getting f1:02a439e5c31c526465ab1a0ca1f431f76b827b90
   sending getlfile command
@@ -400,7 +400,7 @@
   searching 3 changesets for largefiles
   verified existence of 3 revisions of 3 largefiles
   $ tail -1 access.log
-  $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - 
x-hgarg-1:cmds=statlfile+sha%3Dc8559c3c9cfb42131794b7d8009230403b9b454c 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=statlfile HTTP/1.1" 200 - 
x-hgarg-1:sha=c8559c3c9cfb42131794b7d8009230403b9b454c x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
 
   $ killdaemons.py
 
diff --git a/hgext/largefiles/wirestore.py b/hgext/largefiles/wirestore.py
--- a/hgext/largefiles/wirestore.py
+++ b/hgext/largefiles/wirestore.py
@@ -32,8 +32,12 @@
 '''For each hash, return 0 if it is available, other values if not.
 It is usually 2 if the largefile is missing, but might be 1 the server
 has a corrupted copy.'''
-batch = self.remote.iterbatch()
-for hash in hashes:
-batch.statlfile(hash)
-batch.submit()
-return dict(zip(hashes, batch.results()))
+
+with self.remote.commandexecutor() as e:
+fs = []
+for hash in hashes:
+fs.append((hash, e.callcommand('statlfile', {
+'sha': hash,
+})))
+
+return {hash: f.result() for hash, f in fs}



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3269: wireproto: implement batching on peer executor interface

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG2f626233859b: wireproto: implement batching on peer 
executor interface (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3269?vs=8122&id=8166

REVISION DETAIL
  https://phab.mercurial-scm.org/D3269

AFFECTED FILES
  mercurial/setdiscovery.py
  mercurial/wireprotov1peer.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -9,6 +9,7 @@
 
 import hashlib
 import sys
+import weakref
 
 from .i18n import _
 from .node import (
@@ -180,13 +181,36 @@
 
 return ';'.join(cmds)
 
+class unsentfuture(pycompat.futures.Future):
+"""A Future variation to represent an unsent command.
+
+Because we buffer commands and don't submit them immediately, calling
+``result()`` on an unsent future could deadlock. Futures for buffered
+commands are represented by this type, which wraps ``result()`` to
+call ``sendcommands()``.
+"""
+
+def result(self, timeout=None):
+if self.done():
+return pycompat.futures.Future.result(self, timeout)
+
+self._peerexecutor.sendcommands()
+
+# This looks like it will infinitely recurse. However,
+# sendcommands() should modify __class__. This call serves as a check
+# on that.
+return self.result(timeout)
+
 @zi.implementer(repository.ipeercommandexecutor)
 class peerexecutor(object):
 def __init__(self, peer):
 self._peer = peer
 self._sent = False
 self._closed = False
 self._calls = []
+self._futures = weakref.WeakSet()
+self._responseexecutor = None
+self._responsef = None
 
 def __enter__(self):
 return self
@@ -214,20 +238,35 @@
 # Commands are either batchable or they aren't. If a command
 # isn't batchable, we send it immediately because the executor
 # can no longer accept new commands after a non-batchable command.
-# If a command is batchable, we queue it for later.
+# If a command is batchable, we queue it for later. But we have
+# to account for the case of a non-batchable command arriving after
+# a batchable one and refuse to service it.
+
+def addcall():
+f = pycompat.futures.Future()
+self._futures.add(f)
+self._calls.append((command, args, fn, f))
+return f
 
 if getattr(fn, 'batchable', False):
-pass
+f = addcall()
+
+# But since we don't issue it immediately, we wrap its result()
+# to trigger sending so we avoid deadlocks.
+f.__class__ = unsentfuture
+f._peerexecutor = self
 else:
 if self._calls:
 raise error.ProgrammingError(
 '%s is not batchable and cannot be called on a command '
 'executor along with other commands' % command)
 
-# We don't support batching yet. So resolve it immediately.
-f = pycompat.futures.Future()
-self._calls.append((command, args, fn, f))
-self.sendcommands()
+f = addcall()
+
+# Non-batchable commands can never coexist with another command
+# in this executor. So send the command immediately.
+self.sendcommands()
+
 return f
 
 def sendcommands(self):
@@ -239,10 +278,18 @@
 
 self._sent = True
 
+# Unhack any future types so caller seens a clean type and to break
+# cycle between us and futures.
+for f in self._futures:
+if isinstance(f, unsentfuture):
+f.__class__ = pycompat.futures.Future
+f._peerexecutor = None
+
 calls = self._calls
 # Mainly to destroy references to futures.
 self._calls = None
 
+# Simple case of a single command. We call it synchronously.
 if len(calls) == 1:
 command, args, fn, f = calls[0]
 
@@ -259,14 +306,99 @@
 
 return
 
-raise error.ProgrammingError('support for multiple commands not '
- 'yet implemented')
+# Batch commands are a bit harder. First, we have to deal with the
+# @batchable coroutine. That's a bit annoying. Furthermore, we also
+# need to preserve streaming. i.e. it should be possible for the
+# futures to resolve as data is coming in off the wire without having
+# to wait for the final byte of the final response. We do this by
+# spinning up a thread to read the responses.
+
+requests = []
+states = []
+
+for command, args, fn, f in calls:
+# Future was cancelled. Ignore it.
+if not f.set_running_or_notify_cancel():
+c

D3268: wireproto: implement command executor interface for version 1 peers

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGe1b32dc4646c: wireproto: implement command executor 
interface for version 1 peers (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3268?vs=8121&id=8167

REVISION DETAIL
  https://phab.mercurial-scm.org/D3268

AFFECTED FILES
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/setdiscovery.py
  mercurial/wireprotov1peer.py
  tests/test-check-interfaces.py

CHANGE DETAILS

diff --git a/tests/test-check-interfaces.py b/tests/test-check-interfaces.py
--- a/tests/test-check-interfaces.py
+++ b/tests/test-check-interfaces.py
@@ -23,6 +23,7 @@
 vfs as vfsmod,
 wireprotoserver,
 wireprototypes,
+wireprotov1peer,
 wireprotov2server,
 )
 
@@ -102,6 +103,14 @@
  localrepo.localpeer)
 checkzobject(localrepo.localpeer(dummyrepo()))
 
+ziverify.verifyClass(repository.ipeercommandexecutor,
+ localrepo.localcommandexecutor)
+checkzobject(localrepo.localcommandexecutor(None))
+
+ziverify.verifyClass(repository.ipeercommandexecutor,
+ wireprotov1peer.peerexecutor)
+checkzobject(wireprotov1peer.peerexecutor(None))
+
 ziverify.verifyClass(repository.ipeerbaselegacycommands,
  sshpeer.sshv1peer)
 checkzobject(sshpeer.sshv1peer(ui, 'ssh://localhost/foo', None, 
dummypipe(),
diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -8,12 +8,15 @@
 from __future__ import absolute_import
 
 import hashlib
+import sys
 
 from .i18n import _
 from .node import (
 bin,
 )
-
+from .thirdparty.zope import (
+interface as zi,
+)
 from . import (
 bundle2,
 changegroup as changegroupmod,
@@ -177,14 +180,104 @@
 
 return ';'.join(cmds)
 
+@zi.implementer(repository.ipeercommandexecutor)
+class peerexecutor(object):
+def __init__(self, peer):
+self._peer = peer
+self._sent = False
+self._closed = False
+self._calls = []
+
+def __enter__(self):
+return self
+
+def __exit__(self, exctype, excvalee, exctb):
+self.close()
+
+def callcommand(self, command, args):
+if self._sent:
+raise error.ProgrammingError('callcommand() cannot be used '
+ 'after commands are sent')
+
+if self._closed:
+raise error.ProgrammingError('callcommand() cannot be used '
+ 'after close()')
+
+# Commands are dispatched through methods on the peer.
+fn = getattr(self._peer, pycompat.sysstr(command), None)
+
+if not fn:
+raise error.ProgrammingError(
+'cannot call command %s: method of same name not available '
+'on peer' % command)
+
+# Commands are either batchable or they aren't. If a command
+# isn't batchable, we send it immediately because the executor
+# can no longer accept new commands after a non-batchable command.
+# If a command is batchable, we queue it for later.
+
+if getattr(fn, 'batchable', False):
+pass
+else:
+if self._calls:
+raise error.ProgrammingError(
+'%s is not batchable and cannot be called on a command '
+'executor along with other commands' % command)
+
+# We don't support batching yet. So resolve it immediately.
+f = pycompat.futures.Future()
+self._calls.append((command, args, fn, f))
+self.sendcommands()
+return f
+
+def sendcommands(self):
+if self._sent:
+return
+
+if not self._calls:
+return
+
+self._sent = True
+
+calls = self._calls
+# Mainly to destroy references to futures.
+self._calls = None
+
+if len(calls) == 1:
+command, args, fn, f = calls[0]
+
+# Future was cancelled. Ignore it.
+if not f.set_running_or_notify_cancel():
+return
+
+try:
+result = fn(**pycompat.strkwargs(args))
+except Exception:
+f.set_exception_info(*sys.exc_info()[1:])
+else:
+f.set_result(result)
+
+return
+
+raise error.ProgrammingError('support for multiple commands not '
+ 'yet implemented')
+
+def close(self):
+self.sendcommands()
+
+self._closed = True
+
 class wirepeer(repository.legacypeer):
 """Client-side interface for communicating with a peer repository.
 
 Methods commonly call wire protocol commands of the same name.
 
 See also httppeer.py and sshpeer.py for protocol-specific
 implementations of t

D3271: wireproto: remove iterbatch() from peer interface (API)

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG33a6eee08db2: wireproto: remove iterbatch() from peer 
interface (API) (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3271?vs=8124&id=8169

REVISION DETAIL
  https://phab.mercurial-scm.org/D3271

AFFECTED FILES
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/wireprotov1peer.py
  tests/test-batching.py
  tests/test-batching.py.out
  tests/test-wireproto.py

CHANGE DETAILS

diff --git a/tests/test-wireproto.py b/tests/test-wireproto.py
--- a/tests/test-wireproto.py
+++ b/tests/test-wireproto.py
@@ -93,7 +93,9 @@
 clt = clientpeer(srv, uimod.ui())
 
 print(clt.greet(b"Foobar"))
-b = clt.iterbatch()
-list(map(b.greet, (b'Fo, =;:https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3292: bookmarks: use command executor for wire protocol commands

2018-04-13 Thread durin42 (Augie Fackler)
durin42 added a comment.


  btw, I don't love how this looks, it feels like we could probably revisit 
letting "normal" function calls work for one-shot requests like this, but let's 
do it later once we map the new wireproto world a little more

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3292

To: indygreg, #hg-reviewers
Cc: durin42, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3318: repository: remove ipeercommands from ipeerbase

2018-04-13 Thread durin42 (Augie Fackler)
durin42 added a comment.


  I think we should probably avoid breaking that API until after we get 
remotefilelog in core? That'd at least be nice for me, because RFL is pretty 
invasive proto-wise. :(

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3318

To: indygreg, #hg-reviewers
Cc: durin42, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 5] lfs: log information about Internal Server Errors reported in the Batch API

2018-04-13 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1523637594 14400
#  Fri Apr 13 12:39:54 2018 -0400
# Node ID 54c1ab20ed7fbf415d087e6e94ca273d172046e8
# Parent  1d394ac0efd4aa4f61f428fbac140fe57398f0b8
lfs: log information about Internal Server Errors reported in the Batch API

Reporting a 500 and then not leaving any traces on the server seems like a
receipe for frustration.  The log writing was cargoculted from do_POST() in
hgweb.server.  That doesn't write directly to the wsgi.errors object, so it
doesn't seem worth trying to refactor.

It does seem like earlier stack frames are missing for some reason.

diff --git a/hgext/lfs/wireprotolfsserver.py b/hgext/lfs/wireprotolfsserver.py
--- a/hgext/lfs/wireprotolfsserver.py
+++ b/hgext/lfs/wireprotolfsserver.py
@@ -10,6 +10,7 @@ from __future__ import absolute_import
 import datetime
 import errno
 import json
+import traceback
 
 from mercurial.hgweb import (
 common as hgwebcommon,
@@ -63,6 +64,23 @@ def _sethttperror(res, code, message=Non
 res.headers[b'Content-Type'] = b'text/plain; charset=utf-8'
 res.setbodybytes(b'')
 
+def _logexception(req):
+"""Write information about the current exception to wsgi.errors."""
+tb = traceback.format_exc()
+# We need a native-string newline to poke in the log
+# message, because we won't get a newline when using an
+# r-string. This is the easy way out.
+newline = chr(10)
+errorlog = req.rawenv[r'wsgi.errors']
+
+uri = ''
+if req.apppath:
+uri += req.apppath
+uri += b'/' + req.dispatchpath
+
+errorlog.write(r"Exception happened while processing request "
+   r"'%s':%s%s" % (uri.decode('latin-1'), newline, tb))
+
 def _processbatchrequest(repo, req, res):
 """Handle a request for the Batch API, which is the gateway to granting 
file
 access.
@@ -179,6 +197,8 @@ def _batchresponseobjects(req, objects, 
 verifies = store.verify(oid)
 except IOError as inst:
 if inst.errno != errno.ENOENT:
+_logexception(req)
+
 rsp['error'] = {
 'code': 500,
 'message': inst.strerror or 'Internal Server Server'
diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t
--- a/tests/test-lfs-serve-access.t
+++ b/tests/test-lfs-serve-access.t
@@ -291,6 +291,18 @@ Test a checksum failure during the proce
   $LOCALIP - - [$LOGDATE$] "GET 
/.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d
 HTTP/1.1" 500 - (glob)
 
   $ grep -v '  File "' $TESTTMP/errors.log
+  $LOCALIP - - [$ERRDATE$] HG error:  Exception happened while processing 
request '/.git/info/lfs/objects/batch': (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  Traceback (most recent call last): (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  verifies = store.verify(oid) (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  raise IOError(errno.EIO, '%s: I/O 
error' % oid) (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  IOError: [Errno 5] 
f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e: I/O error 
(glob)
+  $LOCALIP - - [$ERRDATE$] HG error:   (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  Exception happened while processing 
request '/.git/info/lfs/objects/batch': (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  Traceback (most recent call last): (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  verifies = store.verify(oid) (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  raise IOError(errno.EIO, '%s: I/O 
error' % oid) (glob)
+  $LOCALIP - - [$ERRDATE$] HG error:  IOError: [Errno 5] 
b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c: I/O error 
(glob)
+  $LOCALIP - - [$ERRDATE$] HG error:   (glob)
   $LOCALIP - - [$ERRDATE$] Exception happened during processing request 
'/.hg/lfs/objects/b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c':
 (glob)
   Traceback (most recent call last):
   self.do_write()
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 5] lfs: fix the inferred remote store path when using a --prefix

2018-04-13 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1523643390 14400
#  Fri Apr 13 14:16:30 2018 -0400
# Node ID a4c12789ef4bac6e736681ef8a08ccbe71fb5c41
# Parent  54c1ab20ed7fbf415d087e6e94ca273d172046e8
lfs: fix the inferred remote store path when using a --prefix

This wasn't appending the '.git/info/lfs' path in this case.

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -561,7 +561,7 @@ def remote(repo, remote=None):
 if defaulturl.scheme in (b'http', b'https'):
 if defaulturl.path and defaulturl.path[:-1] != b'/':
 defaulturl.path += b'/'
-defaulturl.path = defaulturl.path or b'' + b'.git/info/lfs'
+defaulturl.path = (defaulturl.path or b'') + b'.git/info/lfs'
 
 url = util.url(bytes(defaulturl))
 repo.ui.note(_('lfs: assuming remote store: %s\n') % url)
diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t
--- a/tests/test-lfs-serve-access.t
+++ b/tests/test-lfs-serve-access.t
@@ -73,8 +73,7 @@ Blob URIs are correct when --prefix is u
   >-A $TESTTMP/access.log -E $TESTTMP/errors.log
   $ cat hg.pid >> $DAEMON_PIDS
 
-  $ hg --config 
lfs.url=http://localhost:$HGPORT/subdir/mount/point/.git/info/lfs \
-  >clone --debug http://localhost:$HGPORT/subdir/mount/point cloned2
+  $ hg clone --debug http://localhost:$HGPORT/subdir/mount/point cloned2
   using http://localhost:$HGPORT/subdir/mount/point
   sending capabilities command
   query 1; heads
@@ -104,6 +103,7 @@ Blob URIs are correct when --prefix is u
   resolving manifests
branchmerge: False, force: False, partial: False
ancestor: , local: +, remote: 525251863cad
+  lfs: assuming remote store: 
http://localhost:$HGPORT/subdir/mount/point/.git/info/lfs
   Status: 200
   Content-Length: 371
   Content-Type: application/vnd.git-lfs+json
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 5] lfs: gracefully handle aborts on the server when corrupt blobs are detected

2018-04-13 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1519585633 18000
#  Sun Feb 25 14:07:13 2018 -0500
# Node ID b795b3f8eca0aa917b10612dc95d46dee8ee7972
# Parent  a4c12789ef4bac6e736681ef8a08ccbe71fb5c41
lfs: gracefully handle aborts on the server when corrupt blobs are detected

The aborts weren't killing the server, but this seems cleaner.  I'm not sure if
it matters to handle the remaining IOError in the test like this, for
consistency.

The error code still feels wrong (especially if the client is trying to download
a corrupt blob) but I don't see anything better in the RFCs, and this is already
used elsewhere because the Batch API spec specifically mentioned this as a
"Validation Error".

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -152,7 +152,8 @@ class local(object):
 
 realoid = sha256.hexdigest()
 if realoid != oid:
-raise error.Abort(_('corrupt remote lfs object: %s') % oid)
+raise LfsCorruptionError(_('corrupt remote lfs object: %s')
+ % oid)
 
 self._linktousercache(oid)
 
@@ -526,8 +527,8 @@ def _deduplicate(pointers):
 def _verify(oid, content):
 realoid = hashlib.sha256(content).hexdigest()
 if realoid != oid:
-raise error.Abort(_('detected corrupt lfs object: %s') % oid,
-  hint=_('run hg verify'))
+raise LfsCorruptionError(_('detected corrupt lfs object: %s') % oid,
+ hint=_('run hg verify'))
 
 def remote(repo, remote=None):
 """remotestore factory. return a store in _storemap depending on config
@@ -573,3 +574,8 @@ def remote(repo, remote=None):
 
 class LfsRemoteError(error.RevlogError):
 pass
+
+class LfsCorruptionError(error.Abort):
+"""Raised when a corrupt blob is detected, aborting an operation
+
+It exists to allow specialized handling on the server side."""
diff --git a/hgext/lfs/wireprotolfsserver.py b/hgext/lfs/wireprotolfsserver.py
--- a/hgext/lfs/wireprotolfsserver.py
+++ b/hgext/lfs/wireprotolfsserver.py
@@ -20,6 +20,8 @@ from mercurial import (
 pycompat,
 )
 
+from . import blobstore
+
 HTTP_OK = hgwebcommon.HTTP_OK
 HTTP_CREATED = hgwebcommon.HTTP_CREATED
 HTTP_BAD_REQUEST = hgwebcommon.HTTP_BAD_REQUEST
@@ -280,13 +282,15 @@ def _processbasictransfer(repo, req, res
 #   Content-Length, but what happens if a client sends less than it
 #   says it will?
 
-# TODO: download() will abort if the checksum fails.  It should raise
-#   something checksum specific that can be caught here, and turned
-#   into an http code.
-localstore.download(oid, req.bodyfh)
+statusmessage = hgwebcommon.statusmessage
+try:
+localstore.download(oid, req.bodyfh)
+res.status = statusmessage(HTTP_OK if existed else HTTP_CREATED)
+except blobstore.LfsCorruptionError:
+_logexception(req)
 
-statusmessage = hgwebcommon.statusmessage
-res.status = statusmessage(HTTP_OK if existed else HTTP_CREATED)
+# XXX: Is this the right code?
+res.status = statusmessage(422, b'corrupt blob')
 
 # There's no payload here, but this is the header that lfs-test-server
 # sends back.  This eliminates some gratuitous test output 
conditionals.
@@ -300,9 +304,18 @@ def _processbasictransfer(repo, req, res
 res.status = hgwebcommon.statusmessage(HTTP_OK)
 res.headers[b'Content-Type'] = b'application/octet-stream'
 
-# TODO: figure out how to send back the file in chunks, instead of
-#   reading the whole thing.
-res.setbodybytes(localstore.read(oid))
+try:
+# TODO: figure out how to send back the file in chunks, instead of
+#   reading the whole thing.  (Also figure out how to send back
+#   an error status if an IOError occurs after a partial write
+#   in that case.  Here, everything is read before starting.)
+res.setbodybytes(localstore.read(oid))
+except blobstore.LfsCorruptionError:
+_logexception(req)
+
+# XXX: Is this the right code?
+res.status = hgwebcommon.statusmessage(422, b'corrupt blob')
+res.setbodybytes(b'')
 
 return True
 else:
diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t
--- a/tests/test-lfs-serve-access.t
+++ b/tests/test-lfs-serve-access.t
@@ -236,7 +236,7 @@ Test a bad checksum sent by the client i
   $ hg -R client push http://localhost:$HGPORT1
   pushing to http://localhost:$HGPORT1/
   searching for changes
-  abort: HTTP error: HTTP Error 500: Internal Server Error 
(oid=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c, 
action=upload)!
+  abort: HTTP error: HTTP Error 422: corrupt blob 
(oid=b5bb9d8014a0f9b

[PATCH 5 of 5] lfs: update the HTTP status codes in error cases

2018-04-13 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1523651553 14400
#  Fri Apr 13 16:32:33 2018 -0400
# Node ID f7f3443324c9ebcb065bebedfd54d4167eb673d4
# Parent  b795b3f8eca0aa917b10612dc95d46dee8ee7972
lfs: update the HTTP status codes in error cases

I'm not bothering with validating PUT requests (for now), because the spec
doesn't explicitly call out a Content-Type (though the example transcript does
use the sensible 'application/octet-stream').

diff --git a/hgext/lfs/wireprotolfsserver.py b/hgext/lfs/wireprotolfsserver.py
--- a/hgext/lfs/wireprotolfsserver.py
+++ b/hgext/lfs/wireprotolfsserver.py
@@ -26,6 +26,9 @@ HTTP_OK = hgwebcommon.HTTP_OK
 HTTP_CREATED = hgwebcommon.HTTP_CREATED
 HTTP_BAD_REQUEST = hgwebcommon.HTTP_BAD_REQUEST
 HTTP_NOT_FOUND = hgwebcommon.HTTP_NOT_FOUND
+HTTP_METHOD_NOT_ALLOWED = hgwebcommon.HTTP_METHOD_NOT_ALLOWED
+HTTP_NOT_ACCEPTABLE = hgwebcommon.HTTP_NOT_ACCEPTABLE
+HTTP_UNSUPPORTED_MEDIA_TYPE = hgwebcommon.HTTP_UNSUPPORTED_MEDIA_TYPE
 
 def handlewsgirequest(orig, rctx, req, res, checkperm):
 """Wrap wireprotoserver.handlewsgirequest() to possibly process an LFS
@@ -109,12 +112,16 @@ def _processbatchrequest(repo, req, res)
 # "operation": "upload"
 #  }
 
-if (req.method != b'POST'
-or req.headers[b'Content-Type'] != b'application/vnd.git-lfs+json'
-or req.headers[b'Accept'] != b'application/vnd.git-lfs+json'):
-# TODO: figure out what the proper handling for a bad request to the
-#   Batch API is.
-_sethttperror(res, HTTP_BAD_REQUEST, b'Invalid Batch API request')
+if req.method != b'POST':
+_sethttperror(res, HTTP_METHOD_NOT_ALLOWED)
+return True
+
+if req.headers[b'Content-Type'] != b'application/vnd.git-lfs+json':
+_sethttperror(res, HTTP_UNSUPPORTED_MEDIA_TYPE)
+return True
+
+if req.headers[b'Accept'] != b'application/vnd.git-lfs+json':
+_sethttperror(res, HTTP_NOT_ACCEPTABLE)
 return True
 
 # XXX: specify an encoding?
@@ -319,6 +326,6 @@ def _processbasictransfer(repo, req, res
 
 return True
 else:
-_sethttperror(res, HTTP_BAD_REQUEST,
+_sethttperror(res, HTTP_METHOD_NOT_ALLOWED,
   message=b'Unsupported LFS transfer method: %s' % method)
 return True
diff --git a/mercurial/hgweb/common.py b/mercurial/hgweb/common.py
--- a/mercurial/hgweb/common.py
+++ b/mercurial/hgweb/common.py
@@ -30,6 +30,8 @@ HTTP_UNAUTHORIZED = 401
 HTTP_FORBIDDEN = 403
 HTTP_NOT_FOUND = 404
 HTTP_METHOD_NOT_ALLOWED = 405
+HTTP_NOT_ACCEPTABLE = 406
+HTTP_UNSUPPORTED_MEDIA_TYPE = 415
 HTTP_SERVER_ERROR = 500
 
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 5] test-lfs: add tests to force server error path coverage

2018-04-13 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1523119701 14400
#  Sat Apr 07 12:48:21 2018 -0400
# Node ID 1d394ac0efd4aa4f61f428fbac140fe57398f0b8
# Parent  bfdd20d22a86edc318493b4da84a1d7ff4ef98f2
test-lfs: add tests to force server error path coverage

The tests are somewhat fragile in that the extension that forces the errors is
counting how many times some of the functions are being called, so it depends
heavily on the content of the repo.  Maybe we can do something clever like load
an extension on the client, and have it send over instructions in the HTTP
header how to fail.  (I'm trying to avoid killing and restarting the server,
because Windows seems to have issues with doing that a lot.)  But I'd rather fix
issues than polish tests before the freeze.

diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t
--- a/tests/test-lfs-serve-access.t
+++ b/tests/test-lfs-serve-access.t
@@ -4,7 +4,6 @@
   > [extensions]
   > lfs=
   > [lfs]
-  > url=http://localhost:$HGPORT/.git/info/lfs
   > track=all()
   > [web]
   > push_ssl = False
@@ -149,3 +148,189 @@ Blob URIs are correct when --prefix is u
   $LOCALIP - - [$LOGDATE$] "GET /subdir/mount/point?cmd=getbundle HTTP/1.1" 
200 - 
x-hgarg-1:bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%252C03%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=&heads=525251863cad618e55d483555f3d00a2ca99597e&listkeys=bookmarks&phases=1
 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
   $LOCALIP - - [$LOGDATE$] "POST 
/subdir/mount/point/.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
   $LOCALIP - - [$LOGDATE$] "GET 
/subdir/mount/point/.hg/lfs/objects/f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e
 HTTP/1.1" 200 - (glob)
+
+  $ cat >> $TESTTMP/lfsstoreerror.py < import errno
+  > from hgext.lfs import blobstore
+  > 
+  > _numverifies = 0
+  > _readerr = True
+  > 
+  > def reposetup(ui, repo):
+  > # Nothing to do with a remote repo
+  > if not repo.local():
+  > return
+  > 
+  > store = repo.svfs.lfslocalblobstore
+  > class badstore(store.__class__):
+  > def download(self, oid, src):
+  > '''Called in the server to handle reading from the client in a
+  > PUT request.'''
+  > origread = src.read
+  > def _badread(nbytes):
+  > # Simulate bad data/checksum failure from the client
+  > return b'0' * len(origread(nbytes))
+  > src.read = _badread
+  > super(badstore, self).download(oid, src)
+  > 
+  > def _read(self, vfs, oid, verify):
+  > '''Called in the server to read data for a GET request, and 
then
+  > calls self._verify() on it before returning.'''
+  > global _readerr
+  > # One time simulation of a read error
+  > if _readerr:
+  > _readerr = False
+  > raise IOError(errno.EIO, '%s: I/O error' % oid)
+  > # Simulate corrupt content on client download
+  > blobstore._verify(oid, 'dummy content')
+  > 
+  > def verify(self, oid):
+  > '''Called in the server to populate the Batch API response,
+  > letting the client re-upload if the file is corrupt.'''
+  > # Fail verify in Batch API for one clone command and one push
+  > # command with an IOError.  Then let it through to access other
+  > # functions.  Checksum failure is tested elsewhere.
+  > global _numverifies
+  > _numverifies += 1
+  > if _numverifies <= 2:
+  > raise IOError(errno.EIO, '%s: I/O error' % oid)
+  > return super(badstore, self).verify(oid)
+  > 
+  > store.__class__ = badstore
+  > EOF
+
+  $ rm -rf `hg config lfs.usercache`
+  $ rm -f $TESTTMP/access.log $TESTTMP/errors.log
+  $ hg --config "lfs.usercache=$TESTTMP/servercache" \
+  >--config extensions.lfsstoreerror=$TESTTMP/lfsstoreerror.py \
+  >-R server serve -d \
+  >-p $HGPORT1 --pid-file=hg.pid -A $TESTTMP/access.log -E 
$TESTTMP/errors.log
+  $ cat hg.pid >> $DAEMON_PIDS
+
+Test an I/O error in localstore.verify() (Batch API) with GET
+
+  $ hg clone http://localhost:$HGPORT1 httpclone2
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  new changesets 525251863cad
+  updating to branch default
+  abort: LFS server error for "lfs.bin": Internal server error!
+  [255]
+
+Test an I/O error in localstore.verify() (Batch API) with PUT
+
+  $ echo foo > client/lfs.bin
+  $ hg -R client ci -

D3318: repository: remove ipeercommands from ipeerbase

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  In https://phab.mercurial-scm.org/D3318#53227, @durin42 wrote:
  
  > I think we should probably avoid breaking that API until after we get 
remotefilelog in core? That'd at least be nice for me, because RFL is pretty 
invasive proto-wise. :(
  
  
  I have little desire to purge this until at least next release. Minimal gains 
from it. Wins come from core and new peers being able to use new API.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3318

To: indygreg, #hg-reviewers, durin42
Cc: durin42, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3288: discovery: use command executor interface

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG1964d2d1f421: discovery: use command executor interface 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3288?vs=8127&id=8173

REVISION DETAIL
  https://phab.mercurial-scm.org/D3288

AFFECTED FILES
  mercurial/discovery.py

CHANGE DETAILS

diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -203,7 +203,10 @@
 headssum = {}
 # A. Create set of branches involved in the push.
 branches = set(repo[n].branch() for n in outgoing.missing)
-remotemap = remote.branchmap()
+
+with remote.commandexecutor() as e:
+remotemap = e.callcommand('branchmap', {}).result()
+
 newbranches = branches - set(remotemap)
 branches.difference_update(newbranches)
 
@@ -287,7 +290,12 @@
 repo = pushop.repo.unfiltered()
 remote = pushop.remote
 localbookmarks = repo._bookmarks
-remotebookmarks = remote.listkeys('bookmarks')
+
+with remote.commandexecutor() as e:
+remotebookmarks = e.callcommand('listkeys', {
+'namespace': 'bookmarks',
+}).result()
+
 bookmarkedheads = set()
 
 # internal config: bookmarks.pushing



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3272: treediscovery: switch to command executor interface

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0ed11f9368fd: treediscovery: switch to command executor 
interface (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3272?vs=8125&id=8170

REVISION DETAIL
  https://phab.mercurial-scm.org/D3272

AFFECTED FILES
  mercurial/treediscovery.py

CHANGE DETAILS

diff --git a/mercurial/treediscovery.py b/mercurial/treediscovery.py
--- a/mercurial/treediscovery.py
+++ b/mercurial/treediscovery.py
@@ -36,7 +36,8 @@
 base = set()
 
 if not heads:
-heads = remote.heads()
+with remote.commandexecutor() as e:
+heads = e.callcommand('heads', {}).result()
 
 if repo.changelog.tip() == nullid:
 base.add(nullid)
@@ -65,7 +66,10 @@
 # a 'branch' here is a linear segment of history, with four parts:
 # head, root, first parent, second parent
 # (a branch always has two parents (or none) by definition)
-unknown = collections.deque(remote.branches(unknown))
+with remote.commandexecutor() as e:
+branches = e.callcommand('branches', {'nodes': unknown}).result()
+
+unknown = collections.deque(branches)
 while unknown:
 r = []
 while unknown:
@@ -107,7 +111,12 @@
 repo.ui.debug("request %d: %s\n" %
 (reqcnt, " ".join(map(short, r
 for p in xrange(0, len(r), 10):
-for b in remote.branches(r[p:p + 10]):
+with remote.commandexecutor() as e:
+branches = e.callcommand('branches', {
+'nodes': r[p:p + 10],
+}).result()
+
+for b in branches:
 repo.ui.debug("received %s:%s\n" %
   (short(b[0]), short(b[1])))
 unknown.append(b)
@@ -117,7 +126,11 @@
 newsearch = []
 reqcnt += 1
 repo.ui.progress(_('searching'), reqcnt, unit=_('queries'))
-for n, l in zip(search, remote.between(search)):
+
+with remote.commandexecutor() as e:
+between = e.callcommand('between', {'pairs': search}).result()
+
+for n, l in zip(search, between):
 l.append(n[1])
 p = n[0]
 f = 1



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3289: streamclone: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG65b86ee69383: streamclone: use command executor for wire 
protocol commands (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3289?vs=8128&id=8174

REVISION DETAIL
  https://phab.mercurial-scm.org/D3289

AFFECTED FILES
  mercurial/streamclone.py

CHANGE DETAILS

diff --git a/mercurial/streamclone.py b/mercurial/streamclone.py
--- a/mercurial/streamclone.py
+++ b/mercurial/streamclone.py
@@ -126,11 +126,18 @@
 # creation.
 rbranchmap = None
 if remote.capable('branchmap'):
-rbranchmap = remote.branchmap()
+with remote.commandexecutor() as e:
+rbranchmap = e.callcommand('branchmap', {}).result()
 
 repo.ui.status(_('streaming all changes\n'))
 
-fp = remote.stream_out()
+with remote.commandexecutor() as e:
+fp = e.callcommand('stream_out', {}).result()
+
+# TODO strictly speaking, this code should all be inside the context
+# manager because the context manager is supposed to ensure all wire state
+# is flushed when exiting. But the legacy peers don't do this, so it
+# doesn't matter.
 l = fp.readline()
 try:
 resp = int(l)



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3290: logexchange: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0e50dda7e9c1: logexchange: use command executor for wire 
protocol commands (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3290?vs=8129&id=8175

REVISION DETAIL
  https://phab.mercurial-scm.org/D3290

AFFECTED FILES
  mercurial/logexchange.py

CHANGE DETAILS

diff --git a/mercurial/logexchange.py b/mercurial/logexchange.py
--- a/mercurial/logexchange.py
+++ b/mercurial/logexchange.py
@@ -127,14 +127,23 @@
 remoterepo is the peer instance
 """
 remotepath = activepath(localrepo, remoterepo)
-bookmarks = remoterepo.listkeys('bookmarks')
+
+with remoterepo.commandexecutor() as e:
+bookmarks = e.callcommand('listkeys', {
+'namespace': 'bookmarks',
+}).result()
+
 # on a push, we don't want to keep obsolete heads since
 # they won't show up as heads on the next pull, so we
 # remove them here otherwise we would require the user
 # to issue a pull to refresh the storage
 bmap = {}
 repo = localrepo.unfiltered()
-for branch, nodes in remoterepo.branchmap().iteritems():
+
+with remoterepo.commandexecutor() as e:
+branchmap = e.callcommand('branchmap', {}).result()
+
+for branch, nodes in branchmap.iteritems():
 bmap[branch] = []
 for node in nodes:
 if node in repo and not repo[node].obsolete():



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3291: hg: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGce8828217369: hg: use command executor for wire protocol 
commands (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3291?vs=8130&id=8176

REVISION DETAIL
  https://phab.mercurial-scm.org/D3291

AFFECTED FILES
  mercurial/hg.py

CHANGE DETAILS

diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -81,7 +81,9 @@
 raise error.Abort(_("remote branch lookup not supported"))
 revs.append(hashbranch)
 return revs, revs[0]
-branchmap = peer.branchmap()
+
+with peer.commandexecutor() as e:
+branchmap = e.callcommand('branchmap', {}).result()
 
 def primary(branch):
 if branch == '.':
@@ -421,7 +423,15 @@
 raise error.Abort(_("src repository does not support "
"revision lookup and so doesn't "
"support clone by revision"))
-revs = [srcpeer.lookup(r) for r in rev]
+
+# TODO this is batchable.
+remoterevs = []
+for r in rev:
+with srcpeer.commandexecutor() as e:
+remoterevs.append(e.callcommand('lookup', {
+'key': r,
+}).result())
+revs = remoterevs
 
 # Obtain a lock before checking for or cloning the pooled repo otherwise
 # 2 clients may race creating or populating it.
@@ -567,7 +577,11 @@
 # raises RepoLookupError if revision 0 is filtered or otherwise
 # not available. If we fail to resolve, sharing is not enabled.
 try:
-rootnode = srcpeer.lookup('0')
+with srcpeer.commandexecutor() as e:
+rootnode = e.callcommand('lookup', {
+'key': '0',
+}).result()
+
 if rootnode != node.nullid:
 sharepath = os.path.join(sharepool, node.hex(rootnode))
 else:
@@ -663,7 +677,16 @@
 raise error.Abort(_("src repository does not support "
"revision lookup and so doesn't "
"support clone by revision"))
-revs = [srcpeer.lookup(r) for r in revs]
+
+# TODO this is batchable.
+remoterevs = []
+for rev in revs:
+with srcpeer.commandexecutor() as e:
+remoterevs.append(e.callcommand('lookup', {
+'key': rev,
+}).result())
+revs = remoterevs
+
 checkout = revs[0]
 else:
 revs = None
@@ -705,7 +728,11 @@
 
 if update:
 if update is not True:
-checkout = srcpeer.lookup(update)
+with srcpeer.commandexecutor() as e:
+checkout = e.callcommand('lookup', {
+'key': update,
+}).result()
+
 uprev = None
 status = None
 if checkout is not None:



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3287: discovery: don't redundantly call branchmap

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG330ada7e8ea5: discovery: don't redundantly call 
branchmap (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3287?vs=8080&id=8172

REVISION DETAIL
  https://phab.mercurial-scm.org/D3287

AFFECTED FILES
  mercurial/discovery.py
  tests/test-http-bundle1.t
  tests/test-http.t
  tests/test-treediscovery.t

CHANGE DETAILS

diff --git a/tests/test-treediscovery.t b/tests/test-treediscovery.t
--- a/tests/test-treediscovery.t
+++ b/tests/test-treediscovery.t
@@ -537,7 +537,6 @@
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull
-  "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "POST /?cmd=unbundle HTTP/1.1" 200 - 
x-hgarg-1:heads=686173686564+1827a5bb63e602382eb89dd58f2ac9f3b007ad91* (glob)
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
diff --git a/tests/test-http.t b/tests/test-http.t
--- a/tests/test-http.t
+++ b/tests/test-http.t
@@ -296,11 +296,6 @@
   devel-peer-request:   Vary X-HgProto-1
   devel-peer-request:   X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ 
partial-pull
   devel-peer-request:   finished in *. seconds (200) (glob)
-  sending branchmap command
-  devel-peer-request: GET http://localhost:$HGPORT2/?cmd=branchmap
-  devel-peer-request:   Vary X-HgProto-1
-  devel-peer-request:   X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ 
partial-pull
-  devel-peer-request:   finished in *. seconds (200) (glob)
   preparing listkeys for "bookmarks"
   sending listkeys command
   devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
@@ -395,7 +390,6 @@
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull
-  "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365* (glob)
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
@@ -405,7 +399,6 @@
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull
-  "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
diff --git a/tests/test-http-bundle1.t b/tests/test-http-bundle1.t
--- a/tests/test-http-bundle1.t
+++ b/tests/test-http-bundle1.t
@@ -316,7 +316,6 @@
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull
-  "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 
comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "POST /?cmd=unbundle HTTP/1.1" 200 - 
x-hgarg-1:heads=686173686564+5eb5abfefeea63c80dd7553bcc3783f37e0c5524* (glob)
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases 
x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -209,7 +209,7 @@
 
 

D3294: bundlerepo: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG1aa4d646d0de: bundlerepo: use command executor for wire 
protocol commands (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3294?vs=8133&id=8179

REVISION DETAIL
  https://phab.mercurial-scm.org/D3294

AFFECTED FILES
  mercurial/bundlerepo.py

CHANGE DETAILS

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -540,17 +540,26 @@
   and peer.capable('getbundle')
   and peer.capable('bundle2'))
 if canbundle2:
-kwargs = {}
-kwargs[r'common'] = common
-kwargs[r'heads'] = rheads
-kwargs[r'bundlecaps'] = exchange.caps20to10(repo, role='client')
-kwargs[r'cg'] = True
-b2 = peer.getbundle('incoming', **kwargs)
-fname = bundle = changegroup.writechunks(ui, b2._forwardchunks(),
- bundlename)
+with peer.commandexecutor() as e:
+b2 = e.callcommand('getbundle', {
+'source': 'incoming',
+'common': common,
+'heads': rheads,
+'bundlecaps': exchange.caps20to10(repo, role='client'),
+'cg': True,
+}).result()
+
+fname = bundle = changegroup.writechunks(ui,
+ b2._forwardchunks(),
+ bundlename)
 else:
 if peer.capable('getbundle'):
-cg = peer.getbundle('incoming', common=common, heads=rheads)
+with peer.commandexecutor() as e:
+cg = e.callcommand('getbundle', {
+'source': 'incoming',
+'common': common,
+'heads': rheads,
+}).result()
 elif onlyheads is None and not peer.capable('changegroupsubset'):
 # compat with older servers when pulling all remote heads
 
@@ -594,7 +603,11 @@
 
 if bundlerepo:
 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
-remotephases = peer.listkeys('phases')
+
+with peer.commandexecutor() as e:
+remotephases = e.callcommand('listkeys', {
+'namespace': 'phases',
+}).result()
 
 pullop = exchange.pulloperation(bundlerepo, peer, heads=reponodes)
 pullop.trmanager = bundletransactionmanager()



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3293: bundlerepo: rename "other" to "peer"

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGd959277ff1b5: bundlerepo: rename "other" to 
"peer" (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3293?vs=8132&id=8178

REVISION DETAIL
  https://phab.mercurial-scm.org/D3293

AFFECTED FILES
  mercurial/bundlerepo.py

CHANGE DETAILS

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -492,9 +492,9 @@
 def release(self):
 raise NotImplementedError
 
-def getremotechanges(ui, repo, other, onlyheads=None, bundlename=None,
+def getremotechanges(ui, repo, peer, onlyheads=None, bundlename=None,
  force=False):
-'''obtains a bundle of changes incoming from other
+'''obtains a bundle of changes incoming from peer
 
 "onlyheads" restricts the returned changes to those reachable from the
   specified heads.
@@ -507,62 +507,62 @@
 
 "local" is a local repo from which to obtain the actual incoming
   changesets; it is a bundlerepo for the obtained bundle when the
-  original "other" is remote.
+  original "peer" is remote.
 "csets" lists the incoming changeset node ids.
 "cleanupfn" must be called without arguments when you're done processing
-  the changes; it closes both the original "other" and the one returned
+  the changes; it closes both the original "peer" and the one returned
   here.
 '''
-tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
+tmp = discovery.findcommonincoming(repo, peer, heads=onlyheads,
force=force)
 common, incoming, rheads = tmp
 if not incoming:
 try:
 if bundlename:
 os.unlink(bundlename)
 except OSError:
 pass
-return repo, [], other.close
+return repo, [], peer.close
 
 commonset = set(common)
 rheads = [x for x in rheads if x not in commonset]
 
 bundle = None
 bundlerepo = None
-localrepo = other.local()
+localrepo = peer.local()
 if bundlename or not localrepo:
-# create a bundle (uncompressed if other repo is not local)
+# create a bundle (uncompressed if peer repo is not local)
 
 # developer config: devel.legacy.exchange
 legexc = ui.configlist('devel', 'legacy.exchange')
 forcebundle1 = 'bundle2' not in legexc and 'bundle1' in legexc
 canbundle2 = (not forcebundle1
-  and other.capable('getbundle')
-  and other.capable('bundle2'))
+  and peer.capable('getbundle')
+  and peer.capable('bundle2'))
 if canbundle2:
 kwargs = {}
 kwargs[r'common'] = common
 kwargs[r'heads'] = rheads
 kwargs[r'bundlecaps'] = exchange.caps20to10(repo, role='client')
 kwargs[r'cg'] = True
-b2 = other.getbundle('incoming', **kwargs)
+b2 = peer.getbundle('incoming', **kwargs)
 fname = bundle = changegroup.writechunks(ui, b2._forwardchunks(),
  bundlename)
 else:
-if other.capable('getbundle'):
-cg = other.getbundle('incoming', common=common, heads=rheads)
-elif onlyheads is None and not other.capable('changegroupsubset'):
+if peer.capable('getbundle'):
+cg = peer.getbundle('incoming', common=common, heads=rheads)
+elif onlyheads is None and not peer.capable('changegroupsubset'):
 # compat with older servers when pulling all remote heads
 
-with other.commandexecutor() as e:
+with peer.commandexecutor() as e:
 cg = e.callcommand('changegroup', {
 'nodes': incoming,
 'source': 'incoming',
 }).result()
 
 rheads = None
 else:
-with other.commandexecutor() as e:
+with peer.commandexecutor() as e:
 cg = e.callcommand('changegroupsubset', {
 'bases': incoming,
 'heads': rheads,
@@ -582,7 +582,7 @@
 # use the created uncompressed bundlerepo
 localrepo = bundlerepo = bundlerepository(repo.baseui, repo.root,
   fname)
-# this repo contains local and other now, so filter out local again
+# this repo contains local and peer now, so filter out local again
 common = repo.heads()
 if localrepo:
 # Part of common may be remotely filtered
@@ -594,17 +594,17 @@
 
 if bundlerepo:
 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
-remotep

D3273: wireproto: convert legacy commands to command executor

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGcc8c06835097: wireproto: convert legacy commands to command 
executor (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3273?vs=8126&id=8171

REVISION DETAIL
  https://phab.mercurial-scm.org/D3273

AFFECTED FILES
  mercurial/bundlerepo.py
  mercurial/exchange.py
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/wireprotov1peer.py
  tests/test-check-interfaces.py

CHANGE DETAILS

diff --git a/tests/test-check-interfaces.py b/tests/test-check-interfaces.py
--- a/tests/test-check-interfaces.py
+++ b/tests/test-check-interfaces.py
@@ -89,8 +89,7 @@
 
 checkzobject(badpeer())
 
-ziverify.verifyClass(repository.ipeerbaselegacycommands,
- httppeer.httppeer)
+ziverify.verifyClass(repository.ipeerbase, httppeer.httppeer)
 checkzobject(httppeer.httppeer(None, None, None, dummyopener(), None, 
None))
 
 ziverify.verifyClass(repository.ipeerconnection,
@@ -111,13 +110,11 @@
  wireprotov1peer.peerexecutor)
 checkzobject(wireprotov1peer.peerexecutor(None))
 
-ziverify.verifyClass(repository.ipeerbaselegacycommands,
- sshpeer.sshv1peer)
+ziverify.verifyClass(repository.ipeerbase, sshpeer.sshv1peer)
 checkzobject(sshpeer.sshv1peer(ui, 'ssh://localhost/foo', None, 
dummypipe(),
dummypipe(), None, None))
 
-ziverify.verifyClass(repository.ipeerbaselegacycommands,
- sshpeer.sshv2peer)
+ziverify.verifyClass(repository.ipeerbase, sshpeer.sshv2peer)
 checkzobject(sshpeer.sshv2peer(ui, 'ssh://localhost/foo', None, 
dummypipe(),
dummypipe(), None, None))
 
diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -308,7 +308,8 @@
 else:
 f.set_result(result)
 
-class wirepeer(repository.legacypeer):
+@zi.implementer(repository.ipeerlegacycommands)
+class wirepeer(repository.peer):
 """Client-side interface for communicating with a peer repository.
 
 Methods commonly call wire protocol commands of the same name.
@@ -502,12 +503,12 @@
 self._abort(error.ResponseError(_("unexpected response:"), d))
 return r
 
-def changegroup(self, nodes, kind):
+def changegroup(self, nodes, source):
 n = wireprototypes.encodelist(nodes)
 f = self._callcompressable("changegroup", roots=n)
 return changegroupmod.cg1unpacker(f, 'UN')
 
-def changegroupsubset(self, bases, heads, kind):
+def changegroupsubset(self, bases, heads, source):
 self.requirecap('changegroupsubset', _('look up remote changes'))
 bases = wireprototypes.encodelist(bases)
 heads = wireprototypes.encodelist(heads)
diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -190,10 +190,10 @@
 Returns an iterable of iterables with the resolved values for each 
node.
 """
 
-def changegroup(nodes, kind):
+def changegroup(nodes, source):
 """Obtain a changegroup with data for descendants of specified 
nodes."""
 
-def changegroupsubset(bases, heads, kind):
+def changegroupsubset(bases, heads, source):
 pass
 
 class ipeercommandexecutor(zi.Interface):
@@ -285,9 +285,6 @@
 All peer instances must conform to this interface.
 """
 
-class ipeerbaselegacycommands(ipeerbase, ipeerlegacycommands):
-"""Unified peer interface that supports legacy commands."""
-
 @zi.implementer(ipeerbase)
 class peer(object):
 """Base class for peer repositories."""
@@ -312,10 +309,6 @@
 _('cannot %s; remote repository does not support the %r '
   'capability') % (purpose, name))
 
-@zi.implementer(ipeerbaselegacycommands)
-class legacypeer(peer):
-"""peer but with support for legacy wire protocol commands."""
-
 class ifilerevisionssequence(zi.Interface):
 """Contains index data for all revisions of a file.
 
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -320,7 +320,8 @@
 
 # End of peer interface.
 
-class locallegacypeer(repository.legacypeer, localpeer):
+@zi.implementer(repository.ipeerlegacycommands)
+class locallegacypeer(localpeer):
 '''peer extension which implements legacy methods too; used for tests with
 restricted capabilities'''
 
@@ -335,8 +336,8 @@
 def branches(self, nodes):
 return self._repo.branches(nodes)
 
-def changegroup(self, basenodes, source):
-outgoing = discovery.outgoing(self._repo, missingroots=basenodes,
+def changegroup(self, nodes, source):
+outgoing = discovery.outgoing(self._repo, missingro

D3292: bookmarks: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGadd129811176: bookmarks: use command executor for wire 
protocol commands (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3292?vs=8131&id=8177

REVISION DETAIL
  https://phab.mercurial-scm.org/D3292

AFFECTED FILES
  mercurial/bookmarks.py

CHANGE DETAILS

diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
--- a/mercurial/bookmarks.py
+++ b/mercurial/bookmarks.py
@@ -646,12 +646,16 @@
 writer(msg)
 localmarks.applychanges(repo, tr, changes)
 
-def incoming(ui, repo, other):
+def incoming(ui, repo, peer):
 '''Show bookmarks incoming from other to repo
 '''
 ui.status(_("searching for changed bookmarks\n"))
 
-remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
+with peer.commandexecutor() as e:
+remotemarks = unhexlifybookmarks(e.callcommand('listkeys', {
+'namespace': 'bookmarks',
+}).result())
+
 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
 
@@ -733,12 +737,16 @@
 
 return 0
 
-def summary(repo, other):
+def summary(repo, peer):
 '''Compare bookmarks between repo and other for "hg summary" output
 
 This returns "(# of incoming, # of outgoing)" tuple.
 '''
-remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
+with peer.commandexecutor() as e:
+remotemarks = unhexlifybookmarks(e.callcommand('listkeys', {
+'namespace': 'bookmarks',
+}).result())
+
 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
 return (len(addsrc), len(adddst))



To: indygreg, #hg-reviewers, durin42
Cc: durin42, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D3292: bookmarks: use command executor for wire protocol commands

2018-04-13 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  In https://phab.mercurial-scm.org/D3292#53207, @durin42 wrote:
  
  > btw, I don't love how this looks, it feels like we could probably revisit 
letting "normal" function calls work for one-shot requests like this, but let's 
do it later once we map the new wireproto world a little more
  
  
  I’m not opposed to providing a helper method that wraps and makes the 
consumer simpler. Where my mind is at is that proto v2 commands will be smaller 
and we’ll issue more of them. I wanted to make batching and transfer semantics 
for half-duplex connections explicit.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3292

To: indygreg, #hg-reviewers, durin42
Cc: durin42, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


  1   2   >