[Bug 5782] New: rebase complains about divergence when rebasing commit with hidden successor

2018-02-06 Thread mercurial-bugs
https://bz.mercurial-scm.org/show_bug.cgi?id=5782

Bug ID: 5782
   Summary: rebase complains about divergence when rebasing commit
with hidden successor
   Product: Mercurial
   Version: default branch
  Hardware: PC
OS: Mac OS
Status: UNCONFIRMED
  Severity: feature
  Priority: wish
 Component: rebase
  Assignee: bugzi...@mercurial-scm.org
  Reporter: martinv...@google.com
CC: mercurial-devel@mercurial-scm.org

$ hg --hidden log -G -T '{rev} {desc}'
x 4 foo successor
|
| o 3 bar
| |
| x 2 foo
|/
o 1
|
o 0
$ hg rebase -d 0 -r 2
abort: this rebase will cause divergences from: 2 <- actually a hash

This error message seems misleading since rebasing 2 would not lead to
divergence.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH STABLE] fileset: don't abort when running copied() on a revision with a removed file

2018-02-06 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1517979217 18000
#  Tue Feb 06 23:53:37 2018 -0500
# Branch stable
# Node ID 7b2b82f891bf6355ed87c06ed9198bfcd033fe7d
# Parent  1d60ad093792706e1dc7a52b20942593f2c19655
fileset: don't abort when running copied() on a revision with a removed file

It looks like AND with any status-y fileset would trigger this, as added() and
removed() also failed.  The 4.5-rc revision is a convenient test case, but the
merge isn't necessary.

diff --git a/mercurial/fileset.py b/mercurial/fileset.py
--- a/mercurial/fileset.py
+++ b/mercurial/fileset.py
@@ -464,9 +464,10 @@
 getargs(x, 0, 0, _("copied takes no arguments"))
 s = []
 for f in mctx.subset:
-p = mctx.ctx[f].parents()
-if p and p[0].path() != f:
-s.append(f)
+if f in mctx.ctx:
+p = mctx.ctx[f].parents()
+if p and p[0].path() != f:
+s.append(f)
 return s
 
 @predicate('revs(revs, pattern)')
diff --git a/tests/test-fileset.t b/tests/test-fileset.t
--- a/tests/test-fileset.t
+++ b/tests/test-fileset.t
@@ -249,6 +249,8 @@
 Test merge states
 
   $ hg ci -m manychanges
+  $ hg file -r . 'set:copied() & modified()'
+  [1]
   $ hg up -C 0
   * files updated, 0 files merged, * files removed, 0 files unresolved (glob)
   $ echo c >> b2
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D2066: lfs: add a test showing bundle application could be broken

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5275.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2066?vs=5272=5275

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

AFFECTED FILES
  tests/drawdag.py
  tests/test-lfs-bundle.t

CHANGE DETAILS

diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
new file mode 100644
--- /dev/null
+++ b/tests/test-lfs-bundle.t
@@ -0,0 +1,100 @@
+In this test, we want to test LFS bundle application on both LFS and non-LFS
+repos.
+
+To make it more interesting, the file revisions will contain hg filelog
+metadata ('\1\n'). The bundle will have 1 file revision overlapping with the
+destination repo.
+
+#  rev  1  2 3
+#  repo:yesyes   no
+#  bundle:  no (base)  yes   yes (deltabase: 2 if possible)
+
+It is interesting because rev 2 could have been stored as LFS in the repo, and
+non-LFS in the bundle; or vice-versa.
+
+Init:
+
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > lfs=
+  > drawdag=$TESTDIR/drawdag.py
+  > [lfs]
+  > url=file://$TESTTMP/lfs-remote
+  > EOF
+
+Helper functions to create commits:
+
+  $ commitxy() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Y  # Y/X=\1\n\nE\nF
+  >  |  # Y/Y=\1\n\nG\nH
+  >  X  # X/X=\1\n\nC\n
+  > # X/Y=\1\n\nD\n
+  > EOS
+  > }
+
+  $ commitz() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Z  # Z/X=\1\n\nI\n
+  >  |  # Z/Y=\1\n\nJ\n
+  >  |  # Z/Z=\1\nZ
+  >  Y
+  > EOS
+  > }
+
+  $ enablelfs() {
+  >   cat >> .hg/hgrc < [lfs]
+  > track=all()
+  > EOF
+  > }
+
+Generate bundles
+
+  $ for i in normal lfs; do
+  >   NAME=src-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   commitz
+  >   hg bundle -q --base X -r Y+Z $TESTTMP/$NAME.bundle
+  >   SRCNAMES="$SRCNAMES $NAME"
+  > done
+
+Prepare destination repos
+
+  $ for i in normal lfs; do
+  >   NAME=dst-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   DSTNAMES="$DSTNAMES $NAME"
+  > done
+
+Apply bundles
+
+  $ for i in $SRCNAMES; do
+  >   for j in $DSTNAMES; do
+  > echo  Applying $i.bundle to $j 
+  > cp -R $TESTTMP/$j $TESTTMP/tmp-$i-$j
+  > cd $TESTTMP/tmp-$i-$j
+  > if hg unbundle $TESTTMP/$i.bundle -q 2>/dev/null; then
+  >   hg verify -q && echo OK
+  > else
+  >   echo CRASHED
+  > fi
+  >   done
+  > done
+   Applying src-normal.bundle to dst-normal 
+  OK
+   Applying src-normal.bundle to dst-lfs 
+   X@2: unpacking bcc7d23fa6b7: integrity check failed on data/X.i:2
+   Y@2: unpacking 46017a6640e7: integrity check failed on data/Y.i:2
+  2 integrity errors encountered!
+  (first damaged changeset appears to be 2)
+   Applying src-lfs.bundle to dst-normal 
+  CRASHED
+   Applying src-lfs.bundle to dst-lfs 
+  OK
diff --git a/tests/drawdag.py b/tests/drawdag.py
--- a/tests/drawdag.py
+++ b/tests/drawdag.py
@@ -371,7 +371,8 @@
 comments = list(_getcomments(text))
 filere = re.compile(br'^(\w+)/([\w/]+)\s*=\s*(.*)$', re.M)
 for name, path, content in filere.findall(b'\n'.join(comments)):
-files[name][path] = content.replace(br'\n', b'\n')
+content = content.replace(br'\n', b'\n').replace(br'\1', b'\1')
+files[name][path] = content
 
 committed = {None: node.nullid}  # {name: node}
 



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


D2067: changegroup: do not delta lfs revisions

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5273.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2067?vs=5269=5273

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

AFFECTED FILES
  mercurial/changegroup.py
  mercurial/revlog.py
  tests/test-lfs-bundle.t
  tests/test-lfs.t

CHANGE DETAILS

diff --git a/tests/test-lfs.t b/tests/test-lfs.t
--- a/tests/test-lfs.t
+++ b/tests/test-lfs.t
@@ -349,7 +349,7 @@
   uncompressed size of bundle content:
* (changelog) (glob)
* (manifests) (glob)
-   *  a (glob)
+  * a (glob)
   $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
   $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
   5 branching
diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -95,6 +95,6 @@
   2 integrity errors encountered!
   (first damaged changeset appears to be 2)
    Applying src-lfs.bundle to dst-normal 
-  CRASHED
+  OK
    Applying src-lfs.bundle to dst-lfs 
   OK
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -713,6 +713,13 @@
 except KeyError:
 return False
 
+def candelta(self, baserev, rev):
+"""whether two revisions (prev, rev) can be delta-ed or not"""
+# disable delta if either rev uses non-default flag (ex. LFS)
+if self.flags(baserev) or self.flags(rev):
+return False
+return True
+
 def clearcaches(self):
 self._cache = None
 self._chainbasecache.clear()
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -770,6 +770,8 @@
 progress(msgbundling, None)
 
 def deltaparent(self, revlog, rev, p1, p2, prev):
+if not revlog.candelta(prev, rev):
+raise error.ProgrammingError('cg1 should not be used in this case')
 return prev
 
 def revchunk(self, revlog, rev, prev, linknode):
@@ -829,16 +831,19 @@
 # expensive. The revlog caches should have prev cached, meaning
 # less CPU for changegroup generation. There is likely room to add
 # a flag and/or config option to control this behavior.
-return prev
+base = prev
 elif dp == nullrev:
 # revlog is configured to use full snapshot for a reason,
 # stick to full snapshot.
-return nullrev
+base = nullrev
 elif dp not in (p1, p2, prev):
 # Pick prev when we can't be sure remote has the base revision.
 return prev
 else:
-return dp
+base = dp
+if base != nullrev and not revlog.candelta(base, rev):
+base = nullrev
+return base
 
 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
 # Do nothing with flags, it is implicitly 0 in cg1 and cg2



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


D2068: revlog: do not use delta for lfs revisions

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5274.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2068?vs=5270=5274

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

AFFECTED FILES
  mercurial/revlog.py
  tests/test-lfs-bundle.t
  tests/test-revlog-raw.py

CHANGE DETAILS

diff --git a/tests/test-revlog-raw.py b/tests/test-revlog-raw.py
--- a/tests/test-revlog-raw.py
+++ b/tests/test-revlog-raw.py
@@ -114,6 +114,8 @@
 else:
 # suboptimal deltaparent
 deltaparent = min(0, parentrev)
+if not rlog.candelta(deltaparent, r):
+deltaparent = -1
 return {'node': rlog.node(r), 'p1': pnode, 'p2': node.nullid,
 'cs': rlog.node(rlog.linkrev(r)), 'flags': rlog.flags(r),
 'deltabase': rlog.node(deltaparent),
@@ -151,12 +153,12 @@
 for r in rlog:
 p1 = rlog.node(r - 1)
 p2 = node.nullid
-if r == 0:
+if r == 0 or rlog.flags(r):
 text = rlog.revision(r, raw=True)
 cachedelta = None
 else:
-# deltaparent is more interesting if it has the EXTSTORED flag.
-deltaparent = max([0] + [p for p in range(r - 2) if rlog.flags(p)])
+# deltaparent cannot have EXTSTORED flag.
+deltaparent = max([-1] + [p for p in range(r) if not 
rlog.flags(p)])
 text = None
 cachedelta = (deltaparent, rlog.revdiff(deltaparent, r))
 flags = rlog.flags(r)
@@ -262,8 +264,9 @@
 result.append((text, rawtext))
 
 # Verify flags like isdelta, isext work as expected
-if bool(rlog.deltaparent(rev) > -1) != isdelta:
-abort('rev %d: isdelta is ineffective' % rev)
+# isdelta can be overridden to False if this or p1 has isext set
+if bool(rlog.deltaparent(rev) > -1) and not isdelta:
+abort('rev %d: isdelta is unexpected' % rev)
 if bool(rlog.flags(rev)) != isext:
 abort('rev %d: isext is ineffective' % rev)
 return result
diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -90,10 +90,7 @@
    Applying src-normal.bundle to dst-normal 
   OK
    Applying src-normal.bundle to dst-lfs 
-   X@2: unpacking bcc7d23fa6b7: integrity check failed on data/X.i:2
-   Y@2: unpacking 46017a6640e7: integrity check failed on data/Y.i:2
-  2 integrity errors encountered!
-  (first damaged changeset appears to be 2)
+  CRASHED
    Applying src-lfs.bundle to dst-normal 
   OK
    Applying src-lfs.bundle to dst-lfs 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -404,6 +404,9 @@
 for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
 nominateddeltas = []
 for candidaterev in candidaterevs:
+# do not use flags != 0 (ex. LFS) revision as delta base
+if revlog.flags(candidaterev) != REVIDX_DEFAULT_FLAGS:
+continue
 candidatedelta = self._builddeltainfo(revinfo, candidaterev, 
fh)
 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
 nominateddeltas.append(candidatedelta)
@@ -2082,7 +2085,12 @@
 deltacomputer = _deltacomputer(self)
 
 revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, 
flags)
-deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+
+# do not use delta for flags != 0 (ex. LFS) revisions
+if flags == REVIDX_DEFAULT_FLAGS:
+deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+else:
+deltainfo = None
 
 if deltainfo is not None:
 base = deltainfo.base



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


D2066: lfs: add a test showing bundle application could be broken

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5272.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2066?vs=5268=5272

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

AFFECTED FILES
  tests/drawdag.py
  tests/test-lfs-bundle.t

CHANGE DETAILS

diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
new file mode 100644
--- /dev/null
+++ b/tests/test-lfs-bundle.t
@@ -0,0 +1,100 @@
+In this test, we want to test LFS bundle application on both LFS and non-LFS
+repos.
+
+To make it more interesting, the file revisions will contain hg filelog
+metadata ('\1\n'). The bundle will have 1 file revision overlapping with the
+destination repo.
+
+#  rev  1  2 3
+#  repo:yesyes   no
+#  bundle:  no (base)  yes   yes (deltabase: 2 if possible)
+
+It is interesting because rev 2 could have been stored as LFS in the repo, and
+non-LFS in the bundle; or vice-versa.
+
+Init:
+
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > lfs=
+  > drawdag=$TESTDIR/drawdag.py
+  > [lfs]
+  > url=file://$TESTTMP/lfs-remote
+  > EOF
+
+Helper functions to create commits:
+
+  $ commitxy() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Y  # Y/X=\1\n\nE\nF
+  >  |  # Y/Y=\1\n\nG\nH
+  >  X  # X/X=\1\n\nC\n
+  > # X/Y=\1\n\nD\n
+  > EOS
+  > }
+
+  $ commitz() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Z  # Z/X=\1\n\nI\n
+  >  |  # Z/Y=\1\n\nJ\n
+  >  |  # Z/Z=\1\nZ
+  >  Y
+  > EOS
+  > }
+
+  $ enablelfs() {
+  >   cat >> .hg/hgrc < [lfs]
+  > threshold=1
+  > EOF
+  > }
+
+Generate bundles
+
+  $ for i in normal lfs; do
+  >   NAME=src-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   commitz
+  >   hg bundle -q --base X -r Y+Z $TESTTMP/$NAME.bundle
+  >   SRCNAMES="$SRCNAMES $NAME"
+  > done
+
+Prepare destination repos
+
+  $ for i in normal lfs; do
+  >   NAME=dst-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   DSTNAMES="$DSTNAMES $NAME"
+  > done
+
+Apply bundles
+
+  $ for i in $SRCNAMES; do
+  >   for j in $DSTNAMES; do
+  > echo  Applying $i.bundle to $j 
+  > cp -R $TESTTMP/$j $TESTTMP/tmp-$i-$j
+  > cd $TESTTMP/tmp-$i-$j
+  > if hg unbundle $TESTTMP/$i.bundle -q 2>/dev/null; then
+  >   hg verify -q && echo OK
+  > else
+  >   echo CRASHED
+  > fi
+  >   done
+  > done
+   Applying src-normal.bundle to dst-normal 
+  OK
+   Applying src-normal.bundle to dst-lfs 
+   X@2: unpacking bcc7d23fa6b7: integrity check failed on data/X.i:2
+   Y@2: unpacking 46017a6640e7: integrity check failed on data/Y.i:2
+  2 integrity errors encountered!
+  (first damaged changeset appears to be 2)
+   Applying src-lfs.bundle to dst-normal 
+  CRASHED
+   Applying src-lfs.bundle to dst-lfs 
+  OK
diff --git a/tests/drawdag.py b/tests/drawdag.py
--- a/tests/drawdag.py
+++ b/tests/drawdag.py
@@ -371,7 +371,8 @@
 comments = list(_getcomments(text))
 filere = re.compile(br'^(\w+)/([\w/]+)\s*=\s*(.*)$', re.M)
 for name, path, content in filere.findall(b'\n'.join(comments)):
-files[name][path] = content.replace(br'\n', b'\n')
+content = content.replace(br'\n', b'\n').replace(br'\1', b'\1')
+files[name][path] = content
 
 committed = {None: node.nullid}  # {name: node}
 



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


D2057: translate base85.c into rust code

2018-02-06 Thread Ivzhh (Sheng Mao)
Ivzhh added a comment.


  Thank you @indygreg for your detailed explanation!
  
  I understand the process now, and I will go back reading the developer's 
guide thoroughly again. I will try my best to provide a relatively clean stack 
of patches.
  
  Thank you for you time!

REPOSITORY
  rHG Mercurial

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

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


D2061: sshpeer: initial definition and implementation of new SSH protocol

2018-02-06 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  I want to emphasize that I'm not committed to any implementation detail at 
this point in time. I've very opened minded about alternatives and making 
backwards incompatible changes throughout the 4.6 release cycle.
  
  That being said, I am trying to make forward progress on a ton of wire 
protocol changes. These are blocking my planned work for shallow clone this 
release cycle. (I don't want to deploy shallow clone on the existing wire 
protocol for various reasons.) So, I would prefer we //fall forward// and take 
commits even if there are open bikesheds. I'm more than happy to rework the 
protocol later. I just don't want my local work to be dozens of changesets 
ahead of what's reviewed and have to spend hours reworking my code because of a 
bikeshed. I'd rather commit the flawed work, fix it at the head of my local 
queue, and move forward. If nothing else, this approach will lead to a more 
feature complete protocol landing sooner. And only once it is feature complete 
will we all have the full perspective to bikeshed the protocol.

INLINE COMMENTS

> wireprotocol.txt:241-243
> +The transport capabilities string is a URL/percent encoded string
> +containing key-value pairs defining the client's transport-level
> +capabilities. The following capabilities are defined:

I chose the //query string// format here because I don't like reinventing 
wheels. However, if we wanted to make it a list of space delimited atoms (like 
the existing capabilities string), I'd be OK with that.

We can always change this later, since we're not locked into any BC guarantees 
at this juncture.

> wireprotocol.txt:245-247
> +proto
> +   A comma-delimited list of transport protocol versions the client
> +   supports. e.g. ``ssh-v2``.

In the future, I want to advertise:

- compression engine support
- compression engine settings (e.g. max window size for zstandard so a server 
won't choose a compression level that will result in excessive memory usage for 
client)
- max concurrent responses limit (in the future, the protocol will gain the 
ability to stream multiple responses for a single request concurrently)

REPOSITORY
  rHG Mercurial

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

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


D2057: translate base85.c into rust code

2018-02-06 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  We generally prefer that patches to Mercurial be small and do a single thing. 
This makes it easier to review and understand changes, since each change can be 
evaluated in isolation. If you submit changesets together using `hg phabsend`, 
they automatically show up as a //stack// in Phabricator. And if changesets at 
the bottom of the stack are ready to land, we generally land those without 
waiting for the entire stack to land. This enables forward progress to be made 
and this is generally better for everyone than waiting until a series of 
commits is perfect before adding any of them.
  
  What that means is you should ideally split this work into smaller parts. For 
example:
  
  1. Add the pure Rust code/crate
  2. Add the Python Rust code/crate
  3. Build system / module policy changes
  
  I'm not sure of the order of things though. Since this is the first Rust 
extension, it's not clear what needs to be implemented in what order. I'm fine 
looking at a large commit if things are too tightly coupled to separate. But 
you should strive to make smaller commits.

REPOSITORY
  rHG Mercurial

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

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


D2057: translate base85.c into rust code

2018-02-06 Thread Ivzhh (Sheng Mao)
Ivzhh added a comment.


  Sure, thank you for the comments! I can definitely prepare makefile and 
setup.py to make the building process work with rust part. I am planning to 
change the policy.py module to support and try to load rust modules and run all 
the tests. I will submit a new patch after finishing these two tasks.
  
  After reading wiki/OxidationPlan again, I plan to change to cffi for better 
compatibility (pypy and others), and try to build algorithms in pure rust. 
Shall I wait till migrating to cffi based solution now and resubmit this patch 
with all three changes (building, testing, and cffi)?
  
  Thank you!

REPOSITORY
  rHG Mercurial

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

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


D2069: revlog: resolve lfs rawtext to vanilla rawtext before applying delta

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5271.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2069?vs=5267=5271

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

AFFECTED FILES
  mercurial/revlog.py
  tests/test-lfs-bundle.t

CHANGE DETAILS

diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -90,7 +90,7 @@
    Applying src-normal.bundle to dst-normal 
   OK
    Applying src-normal.bundle to dst-lfs 
-  CRASHED
+  OK
    Applying src-lfs.bundle to dst-normal 
   OK
    Applying src-lfs.bundle to dst-lfs 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -333,7 +333,8 @@
len(delta) - hlen):
 btext[0] = delta[hlen:]
 else:
-basetext = revlog.revision(baserev, _df=fh, raw=True)
+# deltabase is flags=0 rawtext, equivalent to non-raw text
+basetext = revlog.revision(baserev, _df=fh, raw=False)
 btext[0] = mdiff.patch(basetext, delta)
 
 try:
@@ -2076,7 +2077,9 @@
 # full versions are inserted when the needed deltas
 # become comparable to the uncompressed text
 if rawtext is None:
-textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
+# need flags=0 rawtext size, which is the non-raw size
+# use revlog explicitly to avoid filelog's metadata handling
+textlen = mdiff.patchedsize(revlog.size(self, cachedelta[0]),
 cachedelta[1])
 else:
 textlen = len(rawtext)



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


D2067: changegroup: do not delta lfs revisions

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5269.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2067?vs=5264=5269

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

AFFECTED FILES
  mercurial/changegroup.py
  mercurial/revlog.py
  tests/test-lfs-bundle.t
  tests/test-lfs.t

CHANGE DETAILS

diff --git a/tests/test-lfs.t b/tests/test-lfs.t
--- a/tests/test-lfs.t
+++ b/tests/test-lfs.t
@@ -349,7 +349,7 @@
   uncompressed size of bundle content:
* (changelog) (glob)
* (manifests) (glob)
-   *  a (glob)
+  * a (glob)
   $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
   $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
   5 branching
diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -95,6 +95,6 @@
   2 integrity errors encountered!
   (first damaged changeset appears to be 2)
    Applying src-lfs.bundle to dst-normal 
-  CRASHED
+  OK
    Applying src-lfs.bundle to dst-lfs 
   OK
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -713,6 +713,13 @@
 except KeyError:
 return False
 
+def candelta(self, baserev, rev):
+"""whether two revisions (prev, rev) can be delta-ed or not"""
+# disable delta if either rev uses non-default flag (ex. LFS)
+if self.flags(baserev) or self.flags(rev):
+return False
+return True
+
 def clearcaches(self):
 self._cache = None
 self._chainbasecache.clear()
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -770,6 +770,8 @@
 progress(msgbundling, None)
 
 def deltaparent(self, revlog, rev, p1, p2, prev):
+if not revlog.candelta(prev, rev):
+raise error.ProgrammingError('cg1 should not be used in this case')
 return prev
 
 def revchunk(self, revlog, rev, prev, linknode):
@@ -829,16 +831,19 @@
 # expensive. The revlog caches should have prev cached, meaning
 # less CPU for changegroup generation. There is likely room to add
 # a flag and/or config option to control this behavior.
-return prev
+base = prev
 elif dp == nullrev:
 # revlog is configured to use full snapshot for a reason,
 # stick to full snapshot.
-return nullrev
+base = nullrev
 elif dp not in (p1, p2, prev):
 # Pick prev when we can't be sure remote has the base revision.
 return prev
 else:
-return dp
+base = dp
+if base != nullrev and not revlog.candelta(base, rev):
+base = nullrev
+return base
 
 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
 # Do nothing with flags, it is implicitly 0 in cg1 and cg2



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


D2068: revlog: do not use delta for lfs revisions

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5270.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2068?vs=5265=5270

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

AFFECTED FILES
  mercurial/revlog.py
  tests/test-lfs-bundle.t
  tests/test-revlog-raw.py

CHANGE DETAILS

diff --git a/tests/test-revlog-raw.py b/tests/test-revlog-raw.py
--- a/tests/test-revlog-raw.py
+++ b/tests/test-revlog-raw.py
@@ -114,6 +114,8 @@
 else:
 # suboptimal deltaparent
 deltaparent = min(0, parentrev)
+if not rlog.candelta(deltaparent, r):
+deltaparent = -1
 return {'node': rlog.node(r), 'p1': pnode, 'p2': node.nullid,
 'cs': rlog.node(rlog.linkrev(r)), 'flags': rlog.flags(r),
 'deltabase': rlog.node(deltaparent),
@@ -151,12 +153,12 @@
 for r in rlog:
 p1 = rlog.node(r - 1)
 p2 = node.nullid
-if r == 0:
+if r == 0 or rlog.flags(r):
 text = rlog.revision(r, raw=True)
 cachedelta = None
 else:
-# deltaparent is more interesting if it has the EXTSTORED flag.
-deltaparent = max([0] + [p for p in range(r - 2) if rlog.flags(p)])
+# deltaparent cannot have EXTSTORED flag.
+deltaparent = max([-1] + [p for p in range(r) if not 
rlog.flags(p)])
 text = None
 cachedelta = (deltaparent, rlog.revdiff(deltaparent, r))
 flags = rlog.flags(r)
@@ -262,8 +264,9 @@
 result.append((text, rawtext))
 
 # Verify flags like isdelta, isext work as expected
-if bool(rlog.deltaparent(rev) > -1) != isdelta:
-abort('rev %d: isdelta is ineffective' % rev)
+# isdelta can be overridden to False if this or p1 has isext set
+if bool(rlog.deltaparent(rev) > -1) and not isdelta:
+abort('rev %d: isdelta is unexpected' % rev)
 if bool(rlog.flags(rev)) != isext:
 abort('rev %d: isext is ineffective' % rev)
 return result
diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -90,10 +90,7 @@
    Applying src-normal.bundle to dst-normal 
   OK
    Applying src-normal.bundle to dst-lfs 
-   X@2: unpacking 0609652b7877: integrity check failed on data/X.i:2
-   Y@2: unpacking e384812cdeb9: integrity check failed on data/Y.i:2
-  2 integrity errors encountered!
-  (first damaged changeset appears to be 2)
+  CRASHED
    Applying src-lfs.bundle to dst-normal 
   OK
    Applying src-lfs.bundle to dst-lfs 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -404,6 +404,9 @@
 for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
 nominateddeltas = []
 for candidaterev in candidaterevs:
+# do not use flags != 0 (ex. LFS) revision as delta base
+if revlog.flags(candidaterev) != REVIDX_DEFAULT_FLAGS:
+continue
 candidatedelta = self._builddeltainfo(revinfo, candidaterev, 
fh)
 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
 nominateddeltas.append(candidatedelta)
@@ -2082,7 +2085,12 @@
 deltacomputer = _deltacomputer(self)
 
 revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, 
flags)
-deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+
+# do not use delta for flags != 0 (ex. LFS) revisions
+if flags == REVIDX_DEFAULT_FLAGS:
+deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+else:
+deltainfo = None
 
 if deltainfo is not None:
 base = deltainfo.base



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


D2066: lfs: add a test showing bundle application could be broken

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5268.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2066?vs=5263=5268

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

AFFECTED FILES
  tests/test-lfs-bundle.t

CHANGE DETAILS

diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
new file mode 100644
--- /dev/null
+++ b/tests/test-lfs-bundle.t
@@ -0,0 +1,100 @@
+In this test, we want to test LFS bundle application on both LFS and non-LFS
+repos.
+
+To make it more interesting, the file revisions will contain hg filelog
+metadata ('\1\n'). The bundle will have 1 file revision overlapping with the
+destination repo.
+
+#  rev  1  2 3
+#  repo:yesyes   no
+#  bundle:  no (base)  yes   yes (deltabase: 2 if possible)
+
+It is interesting because rev 2 could have been stored as LFS in the repo, and
+non-LFS in the bundle; or vice-versa.
+
+Init:
+
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > lfs=
+  > drawdag=$TESTDIR/drawdag.py
+  > [lfs]
+  > url=file://$TESTTMP/lfs-remote
+  > EOF
+
+Helper functions to create commits:
+
+  $ commitxy() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Y  # Y/X=\1\n\nE\nF
+  >  |  # Y/Y=\1\n\nG\nH
+  >  X  # X/X=\1\n\nC\n
+  > # X/Y=\1\n\nD\n
+  > EOS
+  > }
+
+  $ commitz() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Z  # Z/X=\1\n\nI\n
+  >  |  # Z/Y=\1\n\nJ\n
+  >  |  # Z/Z=\1\nZ
+  >  Y
+  > EOS
+  > }
+
+  $ enablelfs() {
+  >   cat >> .hg/hgrc < [lfs]
+  > threshold=1
+  > EOF
+  > }
+
+Generate bundles
+
+  $ for i in normal lfs; do
+  >   NAME=src-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   commitz
+  >   hg bundle -q --base X -r Y+Z $TESTTMP/$NAME.bundle
+  >   SRCNAMES="$SRCNAMES $NAME"
+  > done
+
+Prepare destination repos
+
+  $ for i in normal lfs; do
+  >   NAME=dst-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   DSTNAMES="$DSTNAMES $NAME"
+  > done
+
+Apply bundles
+
+  $ for i in $SRCNAMES; do
+  >   for j in $DSTNAMES; do
+  > echo  Applying $i.bundle to $j 
+  > cp -R $TESTTMP/$j $TESTTMP/tmp-$i-$j
+  > cd $TESTTMP/tmp-$i-$j
+  > if hg unbundle $TESTTMP/$i.bundle -q 2>/dev/null; then
+  >   hg verify -q && echo OK
+  > else
+  >   echo CRASHED
+  > fi
+  >   done
+  > done
+   Applying src-normal.bundle to dst-normal 
+  OK
+   Applying src-normal.bundle to dst-lfs 
+   X@2: unpacking 0609652b7877: integrity check failed on data/X.i:2
+   Y@2: unpacking e384812cdeb9: integrity check failed on data/Y.i:2
+  2 integrity errors encountered!
+  (first damaged changeset appears to be 2)
+   Applying src-lfs.bundle to dst-normal 
+  CRASHED
+   Applying src-lfs.bundle to dst-lfs 
+  OK



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


D2069: revlog: resolve lfs rawtext to vanilla rawtext before applying delta

2018-02-06 Thread quark (Jun Wu)
quark updated this revision to Diff 5267.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2069?vs=5266=5267

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

AFFECTED FILES
  mercurial/revlog.py
  tests/test-lfs-bundle.t

CHANGE DETAILS

diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -91,7 +91,7 @@
    Applying src-normal.bundle to dst-normal 
   OK
    Applying src-normal.bundle to dst-lfs 
-  CRASHED
+  OK
    Applying src-lfs.bundle to dst-normal 
   OK
    Applying src-lfs.bundle to dst-lfs 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -333,7 +333,8 @@
len(delta) - hlen):
 btext[0] = delta[hlen:]
 else:
-basetext = revlog.revision(baserev, _df=fh, raw=True)
+# deltabase is flags=0 rawtext, equivalent to non-raw text
+basetext = revlog.revision(baserev, _df=fh, raw=False)
 btext[0] = mdiff.patch(basetext, delta)
 
 try:
@@ -2076,8 +2077,8 @@
 # full versions are inserted when the needed deltas
 # become comparable to the uncompressed text
 if rawtext is None:
-textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
-cachedelta[1])
+# need flags=0 rawtext size, which is the non-raw size
+textlen = mdiff.patchedsize(self.size(cachedelta[0]), 
cachedelta[1])
 else:
 textlen = len(rawtext)
 



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


D2067: changegroup: do not delta lfs revisions

2018-02-06 Thread quark (Jun Wu)
quark created this revision.
Herald added a reviewer: indygreg.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  There is no way to distinguish whether a delta base is LFS or non-LFS.
  
  If the delta is against LFS rawtext, and the client trying to apply it has
  the base revision stored as fulltext, the delta (aka. bundle) will fail to
  apply.
  
  This patch forbids using delta for LFS revisions in changegroup so bad
  deltas won't be transmitted.
  
  Note: this does not solve the problem entirely. It solves LFS delta applying
  to non-LFS base. But the other direction: non-LFS delta applying to LFS base
  is not solved yet.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/changegroup.py
  mercurial/revlog.py
  tests/test-lfs-bundle.t
  tests/test-lfs.t

CHANGE DETAILS

diff --git a/tests/test-lfs.t b/tests/test-lfs.t
--- a/tests/test-lfs.t
+++ b/tests/test-lfs.t
@@ -349,7 +349,7 @@
   uncompressed size of bundle content:
* (changelog) (glob)
* (manifests) (glob)
-   *  a (glob)
+  * a (glob)
   $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
   $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
   5 branching
diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -96,6 +96,6 @@
   2 integrity errors encountered!
   (first damaged changeset appears to be 2)
    Applying src-lfs.bundle to dst-normal 
-  CRASHED
+  OK
    Applying src-lfs.bundle to dst-lfs 
   OK
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -713,6 +713,13 @@
 except KeyError:
 return False
 
+def candelta(self, baserev, rev):
+"""whether two revisions (prev, rev) can be delta-ed or not"""
+# disable delta if either rev uses non-default flag (ex. LFS)
+if self.flags(baserev) or self.flags(rev):
+return False
+return True
+
 def clearcaches(self):
 self._cache = None
 self._chainbasecache.clear()
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -770,6 +770,8 @@
 progress(msgbundling, None)
 
 def deltaparent(self, revlog, rev, p1, p2, prev):
+if not revlog.candelta(prev, rev):
+raise error.ProgrammingError('cg1 should not be used in this case')
 return prev
 
 def revchunk(self, revlog, rev, prev, linknode):
@@ -829,16 +831,19 @@
 # expensive. The revlog caches should have prev cached, meaning
 # less CPU for changegroup generation. There is likely room to add
 # a flag and/or config option to control this behavior.
-return prev
+base = prev
 elif dp == nullrev:
 # revlog is configured to use full snapshot for a reason,
 # stick to full snapshot.
-return nullrev
+base = nullrev
 elif dp not in (p1, p2, prev):
 # Pick prev when we can't be sure remote has the base revision.
 return prev
 else:
-return dp
+base = dp
+if base != nullrev and not revlog.candelta(base, rev):
+base = nullrev
+return base
 
 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
 # Do nothing with flags, it is implicitly 0 in cg1 and cg2



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


D2066: lfs: add a test showing bundle application could be broken

2018-02-06 Thread quark (Jun Wu)
quark created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  When a bundle containing LFS delta uses non-LFS delta-base, or vice-versa,
  the bundle will fail to apply.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  tests/test-lfs-bundle.t

CHANGE DETAILS

diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
new file mode 100644
--- /dev/null
+++ b/tests/test-lfs-bundle.t
@@ -0,0 +1,101 @@
+In this test, we want to test LFS bundle application on both LFS and non-LFS
+repos.
+
+To make it more interesting, the file revisions will contain hg filelog
+metadata ('\1\n'). The bundle will have 1 file revision overlapping with the
+destination repo.
+
+#  rev  1  2 3
+#  repo:yesyes   no
+#  bundle:  no (base)  yes   yes (deltabase: 2 if possible)
+
+It is interesting because rev 2 could have been stored as LFS in the repo, and
+non-LFS in the bundle; or vice-versa.
+
+Init:
+
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > lfs=
+  > drawdag=$TESTDIR/drawdag.py
+  > [lfs]
+  > url=file://$TESTTMP/lfs-remote
+  > EOF
+
+Helper functions to create commits:
+
+  $ commitxy() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Y  # Y/X=\1\n\nE\nF
+  >  |  # Y/Y=\1\n\nG\nH
+  >  X  # X/X=\1\n\nC\n
+  > # X/Y=\1\n\nD\n
+  > EOS
+  > }
+
+  $ commitz() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Z  # Z/X=\1\n\nI\n
+  >  |  # Z/Y=\1\n\nJ\n
+  >  |  # Z/Z=\1\nZ
+  >  Y
+  > EOS
+  > }
+
+  $ enablelfs() {
+  >   cat >> .hg/hgrc < [lfs]
+  > threshold=1
+  > EOF
+  > }
+
+Generate bundles
+
+  $ for i in normal lfs; do
+  >   NAME=src-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   commitz
+  >   hg bundle -q --base X -r Y+Z $TESTTMP/$NAME.bundle
+  >   SRCNAMES="$SRCNAMES $NAME"
+  > done
+
+Prepare destination repos
+
+  $ for i in normal lfs; do
+  >   NAME=dst-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   DSTNAMES="$DSTNAMES $NAME"
+  > done
+
+Apply bundles
+
+  $ cd $TESTTMP
+  $ for i in $SRCNAMES; do
+  >   for j in $DSTNAMES; do
+  > echo  Applying $i.bundle to $j 
+  > cp -R $TESTTMP/$j $TESTTMP/tmp-$i-$j
+  > cd $TESTTMP/tmp-$i-$j
+  > if hg unbundle $TESTTMP/$i.bundle -q 2>/dev/null; then
+  >   hg verify -q && echo OK
+  > else
+  >   echo CRASHED
+  > fi
+  >   done
+  > done
+   Applying src-normal.bundle to dst-normal 
+  OK
+   Applying src-normal.bundle to dst-lfs 
+   X@2: unpacking 0609652b7877: integrity check failed on data/X.i:2
+   Y@2: unpacking e384812cdeb9: integrity check failed on data/Y.i:2
+  2 integrity errors encountered!
+  (first damaged changeset appears to be 2)
+   Applying src-lfs.bundle to dst-normal 
+  CRASHED
+   Applying src-lfs.bundle to dst-lfs 
+  OK



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


D2069: revlog: resolve lfs rawtext to vanilla rawtext before applying delta

2018-02-06 Thread quark (Jun Wu)
quark created this revision.
Herald added a reviewer: indygreg.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This happens when a LFS delta base gets a non-LFS delta from another client.
  In that case, the LFS delta base needs to be converted to non-LFS version
  before applying the delta.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/revlog.py
  tests/test-lfs-bundle.t

CHANGE DETAILS

diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -91,7 +91,7 @@
    Applying src-normal.bundle to dst-normal 
   OK
    Applying src-normal.bundle to dst-lfs 
-  CRASHED
+  OK
    Applying src-lfs.bundle to dst-normal 
   OK
    Applying src-lfs.bundle to dst-lfs 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -333,7 +333,9 @@
len(delta) - hlen):
 btext[0] = delta[hlen:]
 else:
-basetext = revlog.revision(baserev, _df=fh, raw=True)
+# Deltas are against "flags=0 rawtext".Need "flags=0" rawtext
+# here, which is equivalent to non-raw text.
+basetext = revlog.revision(baserev, _df=fh, raw=False)
 btext[0] = mdiff.patch(basetext, delta)
 
 try:
@@ -2076,8 +2078,8 @@
 # full versions are inserted when the needed deltas
 # become comparable to the uncompressed text
 if rawtext is None:
-textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
-cachedelta[1])
+# need flags=0 rawtext size, which is the non-raw size
+textlen = mdiff.patchedsize(self.size(cachedelta[0]), 
cachedelta[1])
 else:
 textlen = len(rawtext)
 



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


D2068: revlog: do not use delta for lfs revisions

2018-02-06 Thread quark (Jun Wu)
quark created this revision.
Herald added a reviewer: indygreg.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This is similar to what we have done for changegroups. It is needed to make
  sure the delta application code path can assume deltas are always against
  vanilla (ex. non-LFS) rawtext so the next fix becomes possible.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/revlog.py
  tests/test-lfs-bundle.t
  tests/test-revlog-raw.py

CHANGE DETAILS

diff --git a/tests/test-revlog-raw.py b/tests/test-revlog-raw.py
--- a/tests/test-revlog-raw.py
+++ b/tests/test-revlog-raw.py
@@ -114,6 +114,8 @@
 else:
 # suboptimal deltaparent
 deltaparent = min(0, parentrev)
+if not rlog.candelta(deltaparent, r):
+deltaparent = -1
 return {'node': rlog.node(r), 'p1': pnode, 'p2': node.nullid,
 'cs': rlog.node(rlog.linkrev(r)), 'flags': rlog.flags(r),
 'deltabase': rlog.node(deltaparent),
@@ -151,12 +153,12 @@
 for r in rlog:
 p1 = rlog.node(r - 1)
 p2 = node.nullid
-if r == 0:
+if r == 0 or rlog.flags(r):
 text = rlog.revision(r, raw=True)
 cachedelta = None
 else:
-# deltaparent is more interesting if it has the EXTSTORED flag.
-deltaparent = max([0] + [p for p in range(r - 2) if rlog.flags(p)])
+# deltaparent cannot have EXTSTORED flag.
+deltaparent = max([-1] + [p for p in range(r) if not 
rlog.flags(p)])
 text = None
 cachedelta = (deltaparent, rlog.revdiff(deltaparent, r))
 flags = rlog.flags(r)
@@ -262,8 +264,9 @@
 result.append((text, rawtext))
 
 # Verify flags like isdelta, isext work as expected
-if bool(rlog.deltaparent(rev) > -1) != isdelta:
-abort('rev %d: isdelta is ineffective' % rev)
+# isdelta can be overridden to False if this or p1 has isext set
+if bool(rlog.deltaparent(rev) > -1) and not isdelta:
+abort('rev %d: isdelta is unexpected' % rev)
 if bool(rlog.flags(rev)) != isext:
 abort('rev %d: isext is ineffective' % rev)
 return result
diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t
--- a/tests/test-lfs-bundle.t
+++ b/tests/test-lfs-bundle.t
@@ -91,10 +91,7 @@
    Applying src-normal.bundle to dst-normal 
   OK
    Applying src-normal.bundle to dst-lfs 
-   X@2: unpacking 0609652b7877: integrity check failed on data/X.i:2
-   Y@2: unpacking e384812cdeb9: integrity check failed on data/Y.i:2
-  2 integrity errors encountered!
-  (first damaged changeset appears to be 2)
+  CRASHED
    Applying src-lfs.bundle to dst-normal 
   OK
    Applying src-lfs.bundle to dst-lfs 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -404,6 +404,9 @@
 for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
 nominateddeltas = []
 for candidaterev in candidaterevs:
+# do not use flags != 0 (ex. LFS) revision as delta base
+if revlog.flags(candidaterev) != REVIDX_DEFAULT_FLAGS:
+continue
 candidatedelta = self._builddeltainfo(revinfo, candidaterev, 
fh)
 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
 nominateddeltas.append(candidatedelta)
@@ -2082,7 +2085,12 @@
 deltacomputer = _deltacomputer(self)
 
 revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, 
flags)
-deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+
+# do not use delta for flags != 0 (ex. LFS) revisions
+if flags == REVIDX_DEFAULT_FLAGS:
+deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+else:
+deltainfo = None
 
 if deltainfo is not None:
 base = deltainfo.base



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


D375: simplemerge: write merge result to the localctx, if passed

2018-02-06 Thread quark (Jun Wu)
quark added a comment.


  https://bz.mercurial-scm.org/5743 bisects to this change.

REPOSITORY
  rHG Mercurial

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

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


D2013: commit: allow --no-secret to override phases.new-commit setting

2018-02-06 Thread martinvonz (Martin von Zweigbergk)
martinvonz added a comment.


  In https://phab.mercurial-scm.org/D2013#34320, @spectral wrote:
  
  > In https://phab.mercurial-scm.org/D2013#33867, @martinvonz wrote:
  >
  > > I wonder if we should instead have a --draft option for this. Reasons:
  > >
  > > - If we ever add a fourth phase (like Jun's proposed "archived" phase), 
then --no-secret doesn't clearly indicate "draft", it could just as well be 
"archived".
  > > - Actually, we of course already do have a third phase. One could imagine 
a "hg commit --public", although that's probably not useful enough to warrant 
its own option, but it seems to suggest that "--no-secret" doesn't necessarily 
mean "draft".
  > > - I find this tri-state boolean weird. "--secret" kind of defaults to 
off, but it can be made "more off" with "--no-secret".
  >
  >
  > Yeah, I wasn't sure I liked it when writing it, and I'm fine with changing 
it, but do we really want a proliferation of flags?  Perhaps we want a generic 
'phase' flag, so one can specify -s or --secret (BC and it's the "most common" 
case), and --phase  for more advanced use-cases?  
This runs into a couple small problems, specifically that there's now "more 
than one way to do it [specify secret]", it's a lot of typing, and I don't 
think we should abbreviate it `-p` (it just doesn't feel like it's going to be 
common enough to warrant any abbreviation, let alone 'p', which could stand for 
phase, or patch, or path, or a number of other words that we might eventually 
add to `commit` and be sad about not being able to abbreviate in the obvious 
fashion)
  
  
  I think "--phase " makes sense, but it is a little long as you said. 
Since the real goal of this series is to preserve the phase on `hg split`, I'll 
see if I can do that by adding general support to scmutil.cleanupnodes() 
instead (Kyle and I already talked about this offline).

REPOSITORY
  rHG Mercurial

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

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


Re: [PATCH 1 of 2] patches: move assignment outside the conditional

2018-02-06 Thread Gregory Szorc
On Tue, Feb 6, 2018 at 6:28 AM, Boris Feld  wrote:

> # HG changeset patch
> # User Boris Feld 
> # Date 1517923456 -3600
> #  Tue Feb 06 14:24:16 2018 +0100
> # Node ID eee9cca843bc557274945688ea52e16539d45e67
> # Parent  1a3e6239a2eb841a5dce5e1cf8212c54bf33
> # EXP-Topic parallel-patching
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r
> eee9cca843bc
> patches: move assignment outside the conditional
>
> Having this movement in its own patch will make the next patch clearer.
>

Queued part 1.


>
> diff --git a/mercurial/cext/mpatch.c b/mercurial/cext/mpatch.c
> --- a/mercurial/cext/mpatch.c
> +++ b/mercurial/cext/mpatch.c
> @@ -110,7 +110,8 @@ patches(PyObject *self, PyObject *args)
> goto cleanup;
> }
> out = PyBytes_AsString(result);
> -   if ((r = mpatch_apply(out, in, inlen, patch)) < 0) {
> +   r = mpatch_apply(out, in, inlen, patch);
> +   if (r < 0) {
> Py_DECREF(result);
> result = NULL;
> }
> ___
> 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 2] patches: release the GIL while applying the patch

2018-02-06 Thread Gregory Szorc
On Tue, Feb 6, 2018 at 6:28 AM, Boris Feld  wrote:

> # HG changeset patch
> # User Boris Feld 
> # Date 1517839431 -3600
> #  Mon Feb 05 15:03:51 2018 +0100
> # Node ID 345f1c897538cd2b0a5a2fd3952b880206fd9339
> # Parent  eee9cca843bc557274945688ea52e16539d45e67
> # EXP-Topic parallel-patching
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r
> 345f1c897538
> patches: release the GIL while applying the patch
>
> This will allow multiple threads to apply patches at the same time.
>

Please use Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS macros, as that
is what the Python docs recommend. I'm not sure why we don't do this
consistently in our code today. IMO we should port existing code to these
macros.


>
> diff --git a/mercurial/cext/mpatch.c b/mercurial/cext/mpatch.c
> --- a/mercurial/cext/mpatch.c
> +++ b/mercurial/cext/mpatch.c
> @@ -77,6 +77,7 @@ patches(PyObject *self, PyObject *args)
> int r = 0;
> char *out;
> Py_ssize_t len, outlen, inlen;
> +   PyThreadState *_save;
>
> if (!PyArg_ParseTuple(args, "OO:mpatch", , ))
> return NULL;
> @@ -110,7 +111,9 @@ patches(PyObject *self, PyObject *args)
> goto cleanup;
> }
> out = PyBytes_AsString(result);
> +   _save = PyEval_SaveThread();
> r = mpatch_apply(out, in, inlen, patch);
> +   PyEval_RestoreThread(_save);
> if (r < 0) {
> Py_DECREF(result);
> result = NULL;
> ___
> 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


D2065: wireprotoserver: rename abstractserverproto and improve docstring

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

REVISION SUMMARY
  The docstring isn't completely accurate for the current state
  of the world. But it does describe the direction future patches
  will be taking things.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/wireprotoserver.py

CHANGE DETAILS

diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -32,10 +32,13 @@
 HGTYPE2 = 'application/mercurial-0.2'
 HGERRTYPE = 'application/hg-error'
 
-class abstractserverproto(object):
-"""abstract class that summarizes the protocol API
+class baseprotocolhandler(object):
+"""Abstract base class for wire protocol handlers.
 
-Used as reference and documentation.
+A wire protocol handler serves as an interface between protocol command
+handlers and the wire protocol transport layer. Protocol handlers provide
+methods to read command arguments, redirect stdio for the duration of
+the request, handle response types, etc.
 """
 
 __metaclass__ = abc.ABCMeta
@@ -98,7 +101,7 @@
 
 return ''.join(chunks)
 
-class webproto(abstractserverproto):
+class webproto(baseprotocolhandler):
 def __init__(self, req, ui):
 self._req = req
 self._ui = ui
@@ -327,7 +330,7 @@
 
 return ''
 
-class sshserver(abstractserverproto):
+class sshserver(baseprotocolhandler):
 def __init__(self, ui, repo):
 self._ui = ui
 self._repo = repo



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


D2064: wireprotoserver: document and improve the httplib workaround

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

REVISION SUMMARY
  This workaround dates all the way back to 
https://phab.mercurial-scm.org/rHGa42d27bc809dda4939c5b3807b397bcc811ebbe0 in 
2008.
  The code is esoteric enough to warrant an inline explanation.
  So I've added one.
  
  At the time the code was written, the only wire protocol command
  that accepted an HTTP request body was "unbundle." In the years
  since, we've grown the ability to accept command arguments via
  HTTP POST requests. So, the code has been changed to apply the
  httplib workaround to all HTTP POST requests.
  
  While staring at this code, I realized that the HTTP response
  body in case of error is always the same. And, it appears to
  mimic the behavior of a failed call to the "unbundle" command.
  Since we can hit this code path on theoretically any protocol
  request (since self.check_perm accepts custom auth checking
  functions which may raise), I'm having a hard time believing
  that clients react well to an "unbundle" response payload on
  any wire protocol command. I wouldn't be surprised if our test
  coverage for this feature only covers HTTP POST calls to
  "unbundle." In other words, the experimental support for sending
  arguments via HTTP POST request bodies may result in badness on
  the client. Something to investigate another time perhaps...

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/wireprotoserver.py

CHANGE DETAILS

diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -286,8 +286,9 @@
 req.respond(HTTP_OK, HGTYPE, body=rsp)
 return []
 elif isinstance(rsp, wireproto.pusherr):
-# drain the incoming bundle
+# This is the httplib workaround documented in _handlehttperror().
 req.drain()
+
 proto.restore()
 rsp = '0\n%s\n' % rsp.res
 req.respond(HTTP_OK, HGTYPE, body=rsp)
@@ -300,16 +301,28 @@
 
 def _handlehttperror(e, req, cmd):
 """Called when an ErrorResponse is raised during HTTP request 
processing."""
-# A client that sends unbundle without 100-continue will
-# break if we respond early.
-if (cmd == 'unbundle' and
+
+# Clients using Python's httplib are stateful: the HTTP client
+# won't process an HTTP response until all request data is
+# sent to the server. The intent of this code is to ensure
+# we always read HTTP request data from the client, thus
+# ensuring httplib transitions to a state that allows it to read
+# the HTTP response. In other words, it helps prevent deadlocks
+# on clients using httplib.
+
+if (req.env[r'REQUEST_METHOD'] == r'POST' and
+# But not if Expect: 100-continue is being used.
 (req.env.get('HTTP_EXPECT',
  '').lower() != '100-continue') or
+# Or the non-httplib HTTP library is being advertised by
+# the client.
 req.env.get('X-HgHttp2', '')):
 req.drain()
 else:
 req.headers.append((r'Connection', r'Close'))
 
+# TODO This response body assumes the failed command was
+# "unbundle." That assumption is not always valid.
 req.respond(e, HGTYPE, body='0\n%s\n' % e)
 
 return ''



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


D2021: wireprotoserver: move error response handling out of hgweb

2018-02-06 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 5260.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2021?vs=5175=5260

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

AFFECTED FILES
  mercurial/hgweb/hgweb_mod.py
  mercurial/wireprotoserver.py

CHANGE DETAILS

diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -236,6 +236,7 @@
 'cmd': cmd,
 'proto': proto,
 'dispatch': lambda: _callhttp(repo, req, proto, cmd),
+'handleerror': lambda ex: _handlehttperror(ex, req, cmd),
 }
 
 def _callhttp(repo, req, proto, cmd):
@@ -297,6 +298,22 @@
 return []
 raise error.ProgrammingError('hgweb.protocol internal failure', rsp)
 
+def _handlehttperror(e, req, cmd):
+"""Called when an ErrorResponse is raised during HTTP request 
processing."""
+# A client that sends unbundle without 100-continue will
+# break if we respond early.
+if (cmd == 'unbundle' and
+(req.env.get('HTTP_EXPECT',
+ '').lower() != '100-continue') or
+req.env.get('X-HgHttp2', '')):
+req.drain()
+else:
+req.headers.append((r'Connection', r'Close'))
+
+req.respond(e, HGTYPE, body='0\n%s\n' % e)
+
+return ''
+
 class sshserver(abstractserverproto):
 def __init__(self, ui, repo):
 self._ui = ui
diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -369,18 +369,7 @@
 if cmd in perms:
 self.check_perm(rctx, req, perms[cmd])
 except ErrorResponse as inst:
-# A client that sends unbundle without 100-continue will
-# break if we respond early.
-if (cmd == 'unbundle' and
-(req.env.get('HTTP_EXPECT',
- '').lower() != '100-continue') or
-req.env.get('X-HgHttp2', '')):
-req.drain()
-else:
-req.headers.append((r'Connection', r'Close'))
-req.respond(inst, wireprotoserver.HGTYPE,
-body='0\n%s\n' % inst)
-return ''
+return protohandler['handleerror'](inst)
 
 return protohandler['dispatch']()
 



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


D2019: wireprotoserver: move protocol parsing and dispatch out of hgweb

2018-02-06 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 5259.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2019?vs=5173=5259

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

AFFECTED FILES
  mercurial/hgweb/hgweb_mod.py
  mercurial/wireprotoserver.py

CHANGE DETAILS

diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -202,9 +202,43 @@
 def iscmd(cmd):
 return cmd in wireproto.commands
 
-def callhttp(repo, req, cmd):
+def parsehttprequest(repo, req, query):
+"""Parse the HTTP request for a wire protocol request.
+
+If the current request appears to be a wire protocol request, this
+function returns a dict with details about that request, including
+an ``abstractprotocolserver`` instance suitable for handling the
+request. Otherwise, ``None`` is returned.
+
+``req`` is a ``wsgirequest`` instance.
+"""
+# HTTP version 1 wire protocol requests are denoted by a "cmd" query
+# string parameter. If it isn't present, this isn't a wire protocol
+# request.
+if r'cmd' not in req.form:
+return None
+
+cmd = pycompat.sysbytes(req.form[r'cmd'][0])
+
+# The "cmd" request parameter is used by both the wire protocol and hgweb.
+# While not all wire protocol commands are available for all transports,
+# if we see a "cmd" value that resembles a known wire protocol command, we
+# route it to a protocol handler. This is better than routing possible
+# wire protocol requests to hgweb because it prevents hgweb from using
+# known wire protocol commands and it is less confusing for machine
+# clients.
+if cmd not in wireproto.commands:
+return None
+
 proto = webproto(req, repo.ui)
 
+return {
+'cmd': cmd,
+'proto': proto,
+'dispatch': lambda: _callhttp(repo, req, proto, cmd),
+}
+
+def _callhttp(repo, req, proto, cmd):
 def genversion2(gen, engine, engineopts):
 # application/mercurial-0.2 always sends a payload header
 # identifying the compression engine.
diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -357,26 +357,18 @@
 query = req.env[r'QUERY_STRING'].partition(r'&')[0]
 query = query.partition(r';')[0]
 
-# The ``cmd`` request parameter is used by both the wire protocol
-# and hgweb. We route all known wire protocol commands to the
-# wire protocol handler, even if the command isn't available for
-# this transport. That's better for machine clients in the case
-# of an errant request to an unavailable protocol command. And it
-# prevents hgweb from accidentally using ``cmd`` values used by
-# the wire protocol.
+# Route it to a wire protocol handler if it looks like a wire protocol
+# request.
+protohandler = wireprotoserver.parsehttprequest(rctx.repo, req, query)
 
-# process this if it's a protocol request
-# protocol bits don't need to create any URLs
-# and the clients always use the old URL structure
-
-cmd = pycompat.sysbytes(req.form.get(r'cmd', [r''])[0])
-if wireprotoserver.iscmd(cmd):
+if protohandler:
+cmd = protohandler['cmd']
 try:
 if query:
 raise ErrorResponse(HTTP_NOT_FOUND)
 if cmd in perms:
 self.check_perm(rctx, req, perms[cmd])
-return wireprotoserver.callhttp(rctx.repo, req, cmd)
+return protohandler['dispatch']()
 except ErrorResponse as inst:
 # A client that sends unbundle without 100-continue will
 # break if we respond early.
@@ -425,6 +417,8 @@
 if fn.endswith(ext):
 req.form['node'] = [fn[:-len(ext)]]
 req.form['type'] = [type_]
+else:
+cmd = pycompat.sysbytes(req.form.get(r'cmd', [r''])[0])
 
 # process the web interface request
 



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


D1999: wireproto: function for testing if wire protocol command is available

2018-02-06 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 5258.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1999?vs=5138=5258

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

AFFECTED FILES
  mercurial/hgweb/hgweb_mod.py
  mercurial/wireproto.py
  mercurial/wireprotoserver.py

CHANGE DETAILS

diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -217,6 +217,13 @@
 yield chunk
 
 rsp = wireproto.dispatch(repo, proto, cmd)
+
+if not wireproto.commands.commandavailable(cmd, proto):
+req.respond(HTTP_OK, HGERRTYPE,
+body=_('requested wire protocol command is not available '
+   'over HTTP'))
+return []
+
 if isinstance(rsp, bytes):
 req.respond(HTTP_OK, HGTYPE, body=rsp)
 return []
@@ -345,7 +352,7 @@
 
 def serve_one(self):
 cmd = self._fin.readline()[:-1]
-if cmd and cmd in wireproto.commands:
+if cmd and wireproto.commands.commandavailable(cmd, self):
 rsp = wireproto.dispatch(self._repo, self, cmd)
 self._handlers[rsp.__class__](self, rsp)
 elif cmd:
diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py
--- a/mercurial/wireproto.py
+++ b/mercurial/wireproto.py
@@ -691,6 +691,12 @@
 
 return super(commanddict, self).__setitem__(k, v)
 
+def commandavailable(self, command, proto):
+"""Determine if a command is available for the requested protocol."""
+# For now, commands are available for all protocols. So do a simple
+# membership test.
+return command in self
+
 commands = commanddict()
 
 def wireprotocommand(name, args=''):
diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -357,6 +357,14 @@
 query = req.env[r'QUERY_STRING'].partition(r'&')[0]
 query = query.partition(r';')[0]
 
+# The ``cmd`` request parameter is used by both the wire protocol
+# and hgweb. We route all known wire protocol commands to the
+# wire protocol handler, even if the command isn't available for
+# this transport. That's better for machine clients in the case
+# of an errant request to an unavailable protocol command. And it
+# prevents hgweb from accidentally using ``cmd`` values used by
+# the wire protocol.
+
 # process this if it's a protocol request
 # protocol bits don't need to create any URLs
 # and the clients always use the old URL structure



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


D2057: translate base85.c into rust code

2018-02-06 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  Yes, we should definitely split things into multiple crates. Small, 
narrowly-focused crates does seem to be the Rust way, after all.
  
  `hgcli` should be for things specific to the Rust implementation of `hg`. I 
think this can also include the feature set of `chg` (once we've ported `chg` 
to Rust).
  
  I definitely support separating the "pure Rust" from the "Python Rust" via a 
crate boundary. It is generally useful to have Rust that isn't bound to Python 
because it will facilitate reuse outside of Python contexts. For example, 
someone could implement a Mercurial wire protocol server in pure Rust without 
needing to worry about Python. Of course, we're likely to encounter areas where 
we really want tight coupling in order to achieve optimal performance in 
Python. So we may have to design APIs on the pure Rust side to facilitate 
CPython use. I'm OK with that.
  
  As for how many crates to have, I don't have super strong opinions. I could 
see us putting every little component/subsystem in its own crate. I could also 
see us putting everything in one large crate. I don't think it is worth 
deciding at this early juncture. API design and ability to be reused outside 
its originally intended purpose is the important property to strive for. I 
think that has more to do with how the code is authored rather than which 
crates things are in.
  
  A missing piece of this patch is the build system and module loader 
integration. We have a //module policy// that dictates which implementation of 
a Python module we use. We probably want to introduce a `rust` policy that uses 
Rust-based modules where available and falls back to the `cext` modules/policy 
if a Rust module isn't available. We also need to figure out how to integrate 
Rust into `setup.py`. But I think the build system bit can be deferred until 
we're actually ready to ship Rust, which is still a bit of ways off. I'm happy 
for the workflow to be //run cargo in order to load Rust modules// for the time 
being. But if you can implement `Makefile` and/or `setup.py` integration to 
build these Rust extensions, that would be awesome.

REPOSITORY
  rHG Mercurial

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

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


D2061: sshpeer: initial definition and implementation of new SSH protocol

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

REVISION SUMMARY
  The existing SSH protocol has several design flaws. Future commits
  will elaborate on these flaws as new features are introduced
  to combat these flaws. For now, hopefully you can take me for my
  word that a ground up rewrite of the SSH protocol is needed.
  
  This commit lays the foundation for a new SSH protocol by defining
  a mechanism to upgrade the SSH transport channel away from the
  default (version 1) protocol to something modern (which we'll call
  "version 2" for now).
  
  This upgrade process is detailed in the internals documentation
  for the wire protocol. The gist of it is the client sends a
  request line preceding the "hello" command/line which basically
  says "I'm requesting an upgrade: here's what I support." If the
  server recognizes that line, it processes the upgrade request and
  the transport channel is switched to use the new version of the
  protocol. If not, it sends an empty response, which is how all
  Mercurial SSH servers from the beginning of time reacted to unknown
  commands. The upgrade request is effectively ignored and the client
  continues to use the existing version of the protocol as if nothing
  happened.
  
  The new version of the SSH protocol is completely identical to
  version 1 aside from the upgrade dance and the bytes that follow.
  The immediate bytes that follow the protocol switch are defined to
  be a length framed "capabilities: " line containing the remote's
  advertised capabilities. In reality, this looks very similar to
  what the "hello" response would look like. But it will evolve
  quickly.
  
  The methodology by which the protocol will evolve is important.
  
  I'm not going to introduce the new protocol all at once. That would
  likely lead to endless bike shedding and forward progress would
  stall. Instead, I intend to tricle out new features and diversions
  from the existing protocol in small, incremental changes.
  
  To support the gradual evolution of the protocol, the on-the-wire
  advertised protocol name contains an "exp" to denote "experimental"
  and a 4 digit field to capture the sub-version of the protocol.
  Whenever we make a BC change to the wire protocol, we can increment
  this version and lock out all older clients because it will appear
  as a completely different protocol version. This means we can incur
  as many breaking changes as we want. We don't have to commit to
  supporting any one feature or idea for a long period of time. We
  can even evolve the handshake mechanism, because that is defined
  as being an implementation detail of the negotiated protocol version!
  Hopefully this lowers the barrier to accepting changes to the
  protocol and for experimenting with "radical" ideas during its
  development.
  
  In core, sshpeer received most of the attention. We haven't even
  implemented the server bits for the new protocol in core yet.
  Instead, we add very primitive support to our test server, mainly
  just to exercise the added code paths in sshpeer.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/configitems.py
  mercurial/help/internals/wireprotocol.txt
  mercurial/sshpeer.py
  mercurial/wireprotoserver.py
  tests/sshprotoext.py
  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
@@ -388,3 +388,107 @@
   0
   0
   0
+
+Send an upgrade request to a server that doesn't support that command
+
+  $ hg -R server serve --stdio << EOF
+  > upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a 
proto=irrelevant1%2Cirrelevant2
+  > hello
+  > between
+  > pairs 81
+  > 
-
+  > EOF
+  0
+  384
+  capabilities: lookup changegroupsubset branchmap pushkey known getbundle 
unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ 
unbundle=HG10GZ,HG10BZ,HG10UN
+  1
+  
+
+  $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer 
ssh://user@dummy/server
+  running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
+  sending upgrade request: * proto=exp-ssh-v2-0001 (glob)
+  devel-peer-request: hello
+  sending hello command
+  devel-peer-request: between
+  devel-peer-request:   pairs: 81 bytes
+  sending between command
+  remote: 0
+  remote: 384
+  remote: capabilities: lookup changegroupsubset branchmap pushkey known 
getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 
$USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  remote: 1
+  url: ssh://user@dummy/server
+  local: no
+  pushable: yes
+
+Send an upgrade request to a server that supports upgrade
+
+  $ SSHSERVERMODE=upgradev2 hg -R server serve --stdio << EOF
+  > upgrade this-is-some-token 

D2062: sshpeer: rename sshpeer class to sshv1peer (API)

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

REVISION SUMMARY
  With the introduction of version 2 of the SSH wire protocol,
  we will need a new peer class to speak that protocol because
  it will be too difficult to shoehorn a single class to speak
  two protocols. We rename sshpeer.sshpeer to sshpeer.sshv1peer
  to reflect the fact that there will be multiple versions of
  the peer depending on the negotiated protocol.
  
  .. api::
  
sshpeer.sshpeer renamed to sshpeer.sshv1peer.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  hgext/largefiles/uisetup.py
  mercurial/sshpeer.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
@@ -65,8 +65,8 @@
 checkobject(badpeer())
 checkobject(httppeer.httppeer(ui, 'http://localhost'))
 checkobject(localrepo.localpeer(dummyrepo()))
-checkobject(sshpeer.sshpeer(ui, 'ssh://localhost/foo', None, None, None,
-   None, None))
+checkobject(sshpeer.sshv1peer(ui, 'ssh://localhost/foo', None, None, None,
+  None, None))
 checkobject(bundlerepo.bundlepeer(dummyrepo()))
 checkobject(statichttprepo.statichttppeer(dummyrepo()))
 checkobject(unionrepo.unionpeer(dummyrepo()))
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -328,7 +328,7 @@
 
 return caps
 
-class sshpeer(wireproto.wirepeer):
+class sshv1peer(wireproto.wirepeer):
 def __init__(self, ui, url, proc, stdin, stdout, stderr, caps):
 """Create a peer from an existing SSH connection.
 
@@ -537,4 +537,4 @@
 _cleanuppipes(ui, stdout, stdin, stderr)
 raise
 
-return sshpeer(ui, path, proc, stdin, stdout, stderr, caps)
+return sshv1peer(ui, path, proc, stdin, stdout, stderr, caps)
diff --git a/hgext/largefiles/uisetup.py b/hgext/largefiles/uisetup.py
--- a/hgext/largefiles/uisetup.py
+++ b/hgext/largefiles/uisetup.py
@@ -185,9 +185,9 @@
 
 # can't do this in reposetup because it needs to have happened before
 # wirerepo.__init__ is called
-proto.ssholdcallstream = sshpeer.sshpeer._callstream
+proto.ssholdcallstream = sshpeer.sshv1peer._callstream
 proto.httpoldcallstream = httppeer.httppeer._callstream
-sshpeer.sshpeer._callstream = proto.sshrepocallstream
+sshpeer.sshv1peer._callstream = proto.sshrepocallstream
 httppeer.httppeer._callstream = proto.httprepocallstream
 
 # override some extensions' stuff as well



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


D2060: internals: refactor wire protocol documentation

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

REVISION SUMMARY
  Upcoming work will introduce a new version of the HTTP and SSH
  transports. The differences will be significant enough to consider
  them new transports. So, we now attach a version number to each
  transport.
  
  In addition, having the handshake documented after the transport
  and in a single shared section made it harder to follow the flow
  of the connection. The handshake documentation is now moved to the
  protocol section it describes. We now have a generic section about
  the purpose of the handshake, which was rewritten significantly.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/help/internals/wireprotocol.txt

CHANGE DETAILS

diff --git a/mercurial/help/internals/wireprotocol.txt 
b/mercurial/help/internals/wireprotocol.txt
--- a/mercurial/help/internals/wireprotocol.txt
+++ b/mercurial/help/internals/wireprotocol.txt
@@ -10,11 +10,43 @@
 The protocol is synchronous and does not support multiplexing (concurrent
 commands).
 
-Transport Protocols
-===
+Handshake
+=
+
+It is required or common for clients to perform a *handshake* when connecting
+to a server. The handshake serves the following purposes:
+
+* Negotiating protocol/transport level options
+* Allows the client to learn about server capabilities to influence
+  future requests
+* Ensures the underlying transport channel is in a *clean* state
 
-HTTP Transport
---
+An important goal of the handshake is to allow clients to use more modern
+wire protocol features. By default, clients must assume they are talking
+to an old version of Mercurial server (possibly even the very first
+implementation). So, clients should not attempt to call or utilize modern
+wire protocol features until they have confirmation that the server
+supports them. The handshake implementation is designed to allow both
+ends to utilize the latest set of features and capabilities with as
+few round trips as possible.
+
+The handshake mechanism varies by transport and protocol and is documented
+in the sections below.
+
+HTTP Protocol
+=
+
+Handshake
+-
+
+The client sends a ``capabilities`` command request (``?cmd=capabilities``)
+as soon as HTTP requests may be issued.
+
+The server responds with a capabilities string, which the client parses to
+learn about the server's abilities.
+
+HTTP Version 1 Transport
+
 
 Commands are issued as HTTP/1.0 or HTTP/1.1 requests. Commands are
 sent to the base URL of the repository with the command name sent in
@@ -112,11 +144,86 @@
 ``application/mercurial-0.*`` media type and the HTTP response is typically
 using *chunked transfer* (``Transfer-Encoding: chunked``).
 
-SSH Transport
-=
+SSH Protocol
+
+
+Handshake
+-
+
+For all clients, the handshake consists of the client sending 1 or more
+commands to the server using version 1 of the transport. Servers respond
+to commands they know how to respond to and send an empty response (``0\n``)
+for unknown commands (per standard behavior of version 1 of the transport).
+Clients then typically look for a response to the newest sent command to
+determine which transport version to use and what the available features for
+the connection and server are.
+
+Preceding any response from client-issued commands, the server may print
+non-protocol output. It is common for SSH servers to print banners, message
+of the day announcements, etc when clients connect. It is assumed that any
+such *banner* output will precede any Mercurial server output. So clients
+must be prepared to handle server output on initial connect that isn't
+in response to any client-issued command and doesn't conform to Mercurial's
+wire protocol. This *banner* output should only be on stdout. However,
+some servers may send output on stderr.
+
+Pre 0.9.1 clients issue a ``between`` command with the ``pairs`` argument
+having the value
+``-``.
+
+The ``between`` command has been supported since the original Mercurial
+SSH server. Requesting the empty range will return a ``\n`` string response,
+which will be encoded as ``1\n\n`` (value length of ``1`` followed by a newline
+followed by the value, which happens to be a newline).
+
+For pre 0.9.1 clients and all servers, the exchange looks like::
+
+   c: between\n
+   c: pairs 81\n
+   c: 
-
+   s: 1\n
+   s: \n
 
-The SSH transport is a custom text-based protocol suitable for use over any
-bi-directional stream transport. It is most commonly used with SSH.
+0.9.1+ clients send a ``hello`` command (with no arguments) before the
+``between`` command. The response to this command allows clients to

D2063: sshpeer: implement peer for version 2 of wire protocol

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

REVISION SUMMARY
  Since the protocol is now negotiated before we construct a
  peer instance, we can return the negotiated protocol from the
  handshake function and instantiate an appropriate peer class
  for the protocol.
  
  Version 2 of the SSH protocol is currently identical to version
  1 post handshake. So our sshv2peer class just inherits from
  sshv1peer for the time being. This will obviously change
  over time.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/sshpeer.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
@@ -67,6 +67,8 @@
 checkobject(localrepo.localpeer(dummyrepo()))
 checkobject(sshpeer.sshv1peer(ui, 'ssh://localhost/foo', None, None, None,
   None, None))
+checkobject(sshpeer.sshv2peer(ui, 'ssh://localhost/foo', None, None, None,
+  None, None))
 checkobject(bundlerepo.bundlepeer(dummyrepo()))
 checkobject(statichttprepo.statichttppeer(dummyrepo()))
 checkobject(unionrepo.unionpeer(dummyrepo()))
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -326,7 +326,7 @@
 if not caps:
 badresponse()
 
-return caps
+return protoname, caps
 
 class sshv1peer(wireproto.wirepeer):
 def __init__(self, ui, url, proc, stdin, stdout, stderr, caps):
@@ -497,6 +497,12 @@
 self._pipeo.flush()
 self._readerr()
 
+class sshv2peer(sshv1peer):
+"""A peer that speakers version 2 of the transport protocol."""
+# Currently version 2 is identical to version 1 post handshake.
+# And handshake is performed before the peer is instantiated. So
+# we need no custom code.
+
 def instance(ui, path, create):
 """Create an SSH peer.
 
@@ -532,9 +538,16 @@
   remotepath, sshenv)
 
 try:
-caps = _performhandshake(ui, stdin, stdout, stderr)
+protoname, caps = _performhandshake(ui, stdin, stdout, stderr)
 except Exception:
 _cleanuppipes(ui, stdout, stdin, stderr)
 raise
 
-return sshv1peer(ui, path, proc, stdin, stdout, stderr, caps)
+if protoname == wireprotoserver.SSHV1:
+return sshv1peer(ui, path, proc, stdin, stdout, stderr, caps)
+elif protoname == wireprotoserver.SSHV2:
+return sshv2peer(ui, path, proc, stdin, stdout, stderr, caps)
+else:
+_cleanuppipes(ui, stdout, stdin, stderr)
+raise error.RepoError(_('unknown version of SSH protocol: %s') %
+  protoname)



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


D1808: debugcommands: print out the editor that was searched for (post shlexsplit)

2018-02-06 Thread krbullock (Kevin Bullock)
krbullock accepted this revision as: krbullock.
krbullock added a comment.


  This LGTM now. I think the executable as interpreted by shlex, but without 
the added flags, gives enough signal for the user to figure out what might be 
wrong without confusing things.

REPOSITORY
  rHG Mercurial

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

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


D1808: debugcommands: print out the editor that was searched for (post shlexsplit)

2018-02-06 Thread spectral (Kyle Lippincott)
spectral marked an inline comment as done.
spectral added a comment.


  Sorry, I forgot about this, can you take another look?  I believe I addressed 
your most recent comment.

REPOSITORY
  rHG Mercurial

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

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


mercurial@35920: 6 new changesets

2018-02-06 Thread Mercurial Commits
6 new changesets in mercurial:

https://www.mercurial-scm.org/repo/hg/rev/83b9f96ce20f
changeset:   35915:83b9f96ce20f
user:Pulkit Goyal <7895pul...@gmail.com>
date:Mon Feb 05 13:01:35 2018 +0530
summary: py3: use "%d" to convert integer to bytes

https://www.mercurial-scm.org/repo/hg/rev/d41e41d11574
changeset:   35916:d41e41d11574
user:Pulkit Goyal <7895pul...@gmail.com>
date:Mon Feb 05 13:10:33 2018 +0530
summary: py3: add __bytes__() for mq.patchheader and make sure __str__ 
returns str

https://www.mercurial-scm.org/repo/hg/rev/3d8b0020f470
changeset:   35917:3d8b0020f470
user:Pulkit Goyal <7895pul...@gmail.com>
date:Mon Feb 05 13:12:01 2018 +0530
summary: py3: use pycompat.strkwargs() to convert kwargs' key to str

https://www.mercurial-scm.org/repo/hg/rev/e35616bb6ede
changeset:   35918:e35616bb6ede
user:Pulkit Goyal <7895pul...@gmail.com>
date:Mon Feb 05 13:12:36 2018 +0530
summary: py3: use open() instead of file()

https://www.mercurial-scm.org/repo/hg/rev/143d7b27b09c
changeset:   35919:143d7b27b09c
user:Pulkit Goyal <7895pul...@gmail.com>
date:Fri Dec 29 05:40:49 2017 +0530
summary: check-config: specify the mode 'rb' to open the file

https://www.mercurial-scm.org/repo/hg/rev/2912bed9b0c7
changeset:   35920:2912bed9b0c7
bookmark:@
tag: tip
user:Pulkit Goyal <7895pul...@gmail.com>
date:Mon Feb 05 13:24:02 2018 +0530
summary: py3: add b'' to literals in check-config.py

-- 
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


FYI: Mercurial 4.6 sprint is March 2nd-4th at Google's Cambridge, MA office

2018-02-06 Thread Augie Fackler
https://www.mercurial-scm.org/wiki/4.6sprint has all the details, and I'll fill 
in more as I have them.

Sorry for not doing the usual planning routine on this, but time got away from 
us and we decided to make some decisions quickly rather than waiting for the 
usual date-picking routine.

See (some) of you next month!

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


D2057: translate base85.c into rust code

2018-02-06 Thread Ivzhh (Sheng Mao)
Ivzhh added a comment.


  I am open to the three-crates plan. Oirginally I have hgcli and hgext 
separately, and I was planning to replace CFFI. I am a pypy user too, so I will 
be willing to provide a python C API free crate for pypy and others.

REPOSITORY
  rHG Mercurial

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

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


Re: [PATCH] makefile: remove Ubuntu Yakkety and Zesty docker targets

2018-02-06 Thread Yuya Nishihara
On Mon, 5 Feb 2018 09:22:02 -0800, Gregory Szorc wrote:
> On Mon, Feb 5, 2018 at 5:23 AM, Yuya Nishihara  wrote:
> 
> > On Mon, 05 Feb 2018 18:48:00 +0800, Anton Shestakov wrote:
> > > # HG changeset patch
> > > # User Anton Shestakov 
> > > # Date 1517827181 -28800
> > > #  Mon Feb 05 18:39:41 2018 +0800
> > > # Node ID d5509e242b927dbee808e4d62a7f10b3a5c406cf
> > > # Parent  ed3a7300b7b5a427bdcffefd0c80aab65824bf4b
> > > makefile: remove Ubuntu Yakkety and Zesty docker targets
> >
> > Queued, thanks.
> >
> 
> In the past, I've had to restore support for some old distros in order to
> build modern Mercurial packages for some older distros that still had
> limited use in the wild. So there is value to keeping these targets around
> even if the distro is no longer supported upstream. It's only a minor
> inconvenience for me. I just thought I'd raise the concern in case it
> influences our decision making on patches like this.

I have no preference. It's just a make rule kicking one command. It could
even be "make docker-ubuntu CODENAME=yakkety" so we don't have to update
our Makefile per Ubuntu release.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 2] patches: move assignment outside the conditional

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517923456 -3600
#  Tue Feb 06 14:24:16 2018 +0100
# Node ID eee9cca843bc557274945688ea52e16539d45e67
# Parent  1a3e6239a2eb841a5dce5e1cf8212c54bf33
# EXP-Topic parallel-patching
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
eee9cca843bc
patches: move assignment outside the conditional

Having this movement in its own patch will make the next patch clearer.

diff --git a/mercurial/cext/mpatch.c b/mercurial/cext/mpatch.c
--- a/mercurial/cext/mpatch.c
+++ b/mercurial/cext/mpatch.c
@@ -110,7 +110,8 @@ patches(PyObject *self, PyObject *args)
goto cleanup;
}
out = PyBytes_AsString(result);
-   if ((r = mpatch_apply(out, in, inlen, patch)) < 0) {
+   r = mpatch_apply(out, in, inlen, patch);
+   if (r < 0) {
Py_DECREF(result);
result = NULL;
}
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 2] patches: release the GIL while applying the patch

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517839431 -3600
#  Mon Feb 05 15:03:51 2018 +0100
# Node ID 345f1c897538cd2b0a5a2fd3952b880206fd9339
# Parent  eee9cca843bc557274945688ea52e16539d45e67
# EXP-Topic parallel-patching
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
345f1c897538
patches: release the GIL while applying the patch

This will allow multiple threads to apply patches at the same time.

diff --git a/mercurial/cext/mpatch.c b/mercurial/cext/mpatch.c
--- a/mercurial/cext/mpatch.c
+++ b/mercurial/cext/mpatch.c
@@ -77,6 +77,7 @@ patches(PyObject *self, PyObject *args)
int r = 0;
char *out;
Py_ssize_t len, outlen, inlen;
+   PyThreadState *_save;
 
if (!PyArg_ParseTuple(args, "OO:mpatch", , ))
return NULL;
@@ -110,7 +111,9 @@ patches(PyObject *self, PyObject *args)
goto cleanup;
}
out = PyBytes_AsString(result);
+   _save = PyEval_SaveThread();
r = mpatch_apply(out, in, inlen, patch);
+   PyEval_RestoreThread(_save);
if (r < 0) {
Py_DECREF(result);
result = NULL;
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 3 of 7 V2] cmdutil: convert _revertprefetch() to a generic stored file hook (API)

2018-02-06 Thread Yuya Nishihara
On Tue, 6 Feb 2018 08:02:30 -0500, Matt Harbison wrote:
> > On Feb 6, 2018, at 7:20 AM, Yuya Nishihara  wrote:
> > - prefetchfiles() could be hosted by mergemod so lfs won't need to wrap
> >   applyupdates().
> 
> Would it be better to keep it in cmdutil, and call it  just before calling 
> applyupdates()?

That wouldn't be possible because the actions are calculated in merge.py.

> Calling mergemod.prefetchfiles() from archive, for example, seems weird, 
> doesn’t it?  Or am I misunderstanding?

Another option would be repo.prefetchfiles(), but I'm not sure if it's a
good idea.

> > - it could be a list of callback functions, instead of carefully wrapping
> >   the function itself
> 
> Just a raw list that everything can access, or should it have add/remove 
> methods too?  I’ve seen both patterns with hook registration, IIRC.

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


D2025: debugcommands: introduce debugpeer command

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG5f029d03cf71: debugcommands: introduce debugpeer command 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2025?vs=5183=5242

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

AFFECTED FILES
  mercurial/debugcommands.py
  tests/test-completion.t
  tests/test-debugcommands.t
  tests/test-help.t

CHANGE DETAILS

diff --git a/tests/test-help.t b/tests/test-help.t
--- a/tests/test-help.t
+++ b/tests/test-help.t
@@ -948,6 +948,7 @@
debugoptEXP   (no help text available)
debugpathcomplete
  complete part or all of a tracked path
+   debugpeer establish a connection to a peer repository
debugpickmergetool
  examine which merge tool is chosen for specified file
debugpushkey  access the pushkey key/value protocol
diff --git a/tests/test-debugcommands.t b/tests/test-debugcommands.t
--- a/tests/test-debugcommands.t
+++ b/tests/test-debugcommands.t
@@ -381,3 +381,24 @@
   https
 stream
   v2
+
+Test debugpeer
+
+  $ hg --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" debugpeer 
ssh://user@dummy/debugrevlog
+  url: ssh://user@dummy/debugrevlog
+  local: no
+  pushable: yes
+
+  $ hg --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" --debug debugpeer 
ssh://user@dummy/debugrevlog
+  running "*" "*/tests/dummyssh" 'user@dummy' 'hg -R debugrevlog serve 
--stdio' (glob)
+  devel-peer-request: hello
+  sending hello command
+  devel-peer-request: between
+  devel-peer-request:   pairs: 81 bytes
+  sending between command
+  remote: 384
+  remote: capabilities: lookup changegroupsubset branchmap pushkey known 
getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 
$USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  remote: 1
+  url: ssh://user@dummy/debugrevlog
+  local: no
+  pushable: yes
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -102,6 +102,7 @@
   debugnamecomplete
   debugobsolete
   debugpathcomplete
+  debugpeer
   debugpickmergetool
   debugpushkey
   debugpvec
@@ -281,6 +282,7 @@
   debugnamecomplete: 
   debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, 
user, template
   debugpathcomplete: full, normal, added, removed
+  debugpeer: 
   debugpickmergetool: rev, changedelete, include, exclude, tool
   debugpushkey: 
   debugpvec: 
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -1693,6 +1693,25 @@
 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
 ui.write('\n')
 
+@command('debugpeer', [], _('PATH'), norepo=True)
+def debugpeer(ui, path):
+"""establish a connection to a peer repository"""
+# Always enable peer request logging. Requires --debug to display
+# though.
+overrides = {
+('devel', 'debug.peer-request'): True,
+}
+
+with ui.configoverride(overrides):
+peer = hg.peer(ui, {}, path)
+
+local = peer.local() is not None
+canpush = peer.canpush()
+
+ui.write(_('url: %s\n') % peer.url())
+ui.write(_('local: %s\n') % (_('yes') if local else _('no')))
+ui.write(_('pushable: %s\n') % (_('yes') if canpush else _('no')))
+
 @command('debugpickmergetool',
 [('r', 'rev', '', _('check for files in this revision'), _('REV')),
  ('', 'changedelete', None, _('emulate merging change and delete')),



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


D2036: sshpeer: remove support for connecting to <0.9.1 servers (BC)

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG556218e08e25: sshpeer: remove support for connecting to 
0.9.1 servers (BC) (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2036?vs=5237=5253

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

AFFECTED FILES
  mercurial/sshpeer.py
  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
@@ -109,7 +109,9 @@
   1
   
 
-Connecting to a <0.9.1 server that doesn't support the hello command
+Connecting to a <0.9.1 server that doesn't support the hello command.
+The client should refuse, as we dropped support for connecting to such
+servers.
 
   $ SSHSERVERMODE=no-hello hg --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
@@ -120,14 +122,8 @@
   sending between command
   remote: 0
   remote: 1
-  url: ssh://user@dummy/server
-  local: no
-  pushable: yes
-
-The client should interpret this as no capabilities
-
-  $ SSHSERVERMODE=no-hello hg debugcapabilities ssh://user@dummy/server
-  Main capabilities:
+  abort: no suitable response from remote hg!
+  [255]
 
 Sending an unknown command to the server results in an empty response to that 
command
 
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -242,6 +242,16 @@
 caps.update(l[:-1].split(':')[1].split())
 break
 
+# Error if we couldn't find a response to ``hello``. This could
+# mean:
+#
+# 1. Remote isn't a Mercurial server
+# 2. Remote is a <0.9.1 Mercurial server
+# 3. Remote is a future Mercurial server that dropped ``hello``
+#support.
+if not caps:
+badresponse()
+
 return caps
 
 class sshpeer(wireproto.wirepeer):



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


D2034: sshpeer: move handshake outside of sshpeer

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG80a2b8ae42a1: sshpeer: move handshake outside of sshpeer 
(authored by indygreg, committed by ).

CHANGED PRIOR TO COMMIT
  https://phab.mercurial-scm.org/D2034?vs=5235=5251#toc

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2034?vs=5235=5251

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

AFFECTED FILES
  mercurial/sshpeer.py
  tests/sshprotoext.py
  tests/test-check-interfaces.py
  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
@@ -146,7 +146,6 @@
 
   $ hg --config sshpeer.mode=extra-handshake-commands --config 
sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
-  devel-peer-request: no-args
   sending no-args command
   devel-peer-request: hello
   sending hello command
@@ -182,11 +181,8 @@
 
   $ hg --config sshpeer.mode=extra-handshake-commands --config 
sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer 
ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
-  devel-peer-request: unknown1
   sending unknown1 command
-  devel-peer-request: unknown2
   sending unknown2 command
-  devel-peer-request: unknown3
   sending unknown3 command
   devel-peer-request: hello
   sending hello command
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
@@ -51,10 +51,6 @@
 pass
 
 # Facilitates testing sshpeer without requiring an SSH server.
-class testingsshpeer(sshpeer.sshpeer):
-def _validaterepo(self, *args, **kwargs):
-pass
-
 class badpeer(httppeer.httppeer):
 def __init__(self):
 super(badpeer, self).__init__(uimod.ui(), 'http://localhost')
@@ -69,8 +65,8 @@
 checkobject(badpeer())
 checkobject(httppeer.httppeer(ui, 'http://localhost'))
 checkobject(localrepo.localpeer(dummyrepo()))
-checkobject(testingsshpeer(ui, 'ssh://localhost/foo', None, None, None,
-   None))
+checkobject(sshpeer.sshpeer(ui, 'ssh://localhost/foo', None, None, None,
+   None, None))
 checkobject(bundlerepo.bundlepeer(dummyrepo()))
 checkobject(statichttprepo.statichttppeer(dummyrepo()))
 checkobject(unionrepo.unionpeer(dummyrepo()))
diff --git a/tests/sshprotoext.py b/tests/sshprotoext.py
--- a/tests/sshprotoext.py
+++ b/tests/sshprotoext.py
@@ -12,6 +12,7 @@
 
 from mercurial import (
 error,
+extensions,
 registrar,
 sshpeer,
 wireproto,
@@ -52,30 +53,26 @@
 
 super(prehelloserver, self).serve_forever()
 
-class extrahandshakecommandspeer(sshpeer.sshpeer):
-"""An ssh peer that sends extra commands as part of initial handshake."""
-def _validaterepo(self):
-mode = self._ui.config(b'sshpeer', b'handshake-mode')
-if mode == b'pre-no-args':
-self._callstream(b'no-args')
-return super(extrahandshakecommandspeer, self)._validaterepo()
-elif mode == b'pre-multiple-no-args':
-self._callstream(b'unknown1')
-self._callstream(b'unknown2')
-self._callstream(b'unknown3')
-return super(extrahandshakecommandspeer, self)._validaterepo()
-else:
-raise error.ProgrammingError(b'unknown HANDSHAKECOMMANDMODE: %s' %
- mode)
-
-def registercommands():
-def dummycommand(repo, proto):
-raise error.ProgrammingError('this should never be called')
-
-wireproto.wireprotocommand(b'no-args', b'')(dummycommand)
-wireproto.wireprotocommand(b'unknown1', b'')(dummycommand)
-wireproto.wireprotocommand(b'unknown2', b'')(dummycommand)
-wireproto.wireprotocommand(b'unknown3', b'')(dummycommand)
+def performhandshake(orig, ui, stdin, stdout, stderr):
+"""Wrapped version of sshpeer._performhandshake to send extra commands."""
+mode = ui.config(b'sshpeer', b'handshake-mode')
+if mode == b'pre-no-args':
+ui.debug(b'sending no-args command\n')
+stdin.write(b'no-args\n')
+stdin.flush()
+return orig(ui, stdin, stdout, stderr)
+elif mode == b'pre-multiple-no-args':
+ui.debug(b'sending unknown1 command\n')
+stdin.write(b'unknown1\n')
+ui.debug(b'sending unknown2 command\n')
+stdin.write(b'unknown2\n')
+ui.debug(b'sending unknown3 command\n')
+stdin.write(b'unknown3\n')
+stdin.flush()
+return orig(ui, stdin, stdout, stderr)
+else:
+raise error.ProgrammingError(b'unknown HANDSHAKECOMMANDMODE: %s' %
+ mode)
 
 def extsetup(ui):
 # It's easier for tests to define the server 

D2035: sshpeer: document the handshake mechanism

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGa622a927fe03: sshpeer: document the handshake mechanism 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2035?vs=5236=5252

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

AFFECTED FILES
  mercurial/sshpeer.py

CHANGE DETAILS

diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -162,6 +162,37 @@
 hint = ui.config('ui', 'ssherrorhint')
 raise error.RepoError(msg, hint=hint)
 
+# The handshake consists of sending 2 wire protocol commands:
+# ``hello`` and ``between``.
+#
+# The ``hello`` command (which was introduced in Mercurial 0.9.1)
+# instructs the server to advertise its capabilities.
+#
+# The ``between`` command (which has existed in all Mercurial servers
+# for as long as SSH support has existed), asks for the set of revisions
+# between a pair of revisions.
+#
+# The ``between`` command is issued with a request for the null
+# range. If the remote is a Mercurial server, this request will
+# generate a specific response: ``1\n\n``. This represents the
+# wire protocol encoded value for ``\n``. We look for ``1\n\n``
+# in the output stream and know this is the response to ``between``
+# and we're at the end of our handshake reply.
+#
+# The response to the ``hello`` command will be a line with the
+# length of the value returned by that command followed by that
+# value. If the server doesn't support ``hello`` (which should be
+# rare), that line will be ``0\n``. Otherwise, the value will contain
+# RFC 822 like lines. Of these, the ``capabilities:`` line contains
+# the capabilities of the server.
+#
+# In addition to the responses to our command requests, the server
+# may emit "banner" output on stdout. SSH servers are allowed to
+# print messages to stdout on login. Issuing commands on connection
+# allows us to flush this banner output from the server by scanning
+# for output to our well-known ``between`` command. Of course, if
+# the banner contains ``1\n\n``, this will throw off our detection.
+
 requestlog = ui.configbool('devel', 'debug.peer-request')
 
 try:
@@ -205,6 +236,8 @@
 
 caps = set()
 for l in reversed(lines):
+# Look for response to ``hello`` command. Scan from the back so
+# we don't misinterpret banner output as the command reply.
 if l.startswith('capabilities:'):
 caps.update(l[:-1].split(':')[1].split())
 break



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


D2032: sshpeer: clean up API for sshpeer.__init__ (API)

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGf8f034344b39: sshpeer: clean up API for sshpeer.__init__ 
(API) (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2032?vs=5233=5249

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

AFFECTED FILES
  mercurial/sshpeer.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
@@ -69,8 +69,8 @@
 checkobject(badpeer())
 checkobject(httppeer.httppeer(ui, 'http://localhost'))
 checkobject(localrepo.localpeer(dummyrepo()))
-checkobject(testingsshpeer(ui, 'ssh://localhost/foo', False,
-   (None, None, None, None)))
+checkobject(testingsshpeer(ui, 'ssh://localhost/foo', None, None, None,
+   None))
 checkobject(bundlerepo.bundlepeer(dummyrepo()))
 checkobject(statichttprepo.statichttppeer(dummyrepo()))
 checkobject(unionrepo.unionpeer(dummyrepo()))
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -157,12 +157,21 @@
 return proc, stdin, stdout, stderr
 
 class sshpeer(wireproto.wirepeer):
-def __init__(self, ui, path, create=False, sshstate=None):
-self._url = path
+def __init__(self, ui, url, proc, stdin, stdout, stderr):
+"""Create a peer from an existing SSH connection.
+
+``proc`` is a handle on the underlying SSH process.
+``stdin``, ``stdout``, and ``stderr`` are handles on the stdio
+pipes for that process.
+"""
+self._url = url
 self._ui = ui
 # self._subprocess is unused. Keeping a handle on the process
 # holds a reference and prevents it from being garbage collected.
-self._subprocess, self._pipei, self._pipeo, self._pipee = sshstate
+self._subprocess = proc
+self._pipeo = stdin
+self._pipei = stdout
+self._pipee = stderr
 
 self._validaterepo()
 
@@ -386,6 +395,4 @@
 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd,
   remotepath, sshenv)
 
-sshstate = (proc, stdout, stdin, stderr)
-
-return sshpeer(ui, path, create=create, sshstate=sshstate)
+return sshpeer(ui, path, proc, stdin, stdout, stderr)



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


D2033: sshpeer: inline I/O into _validaterepo()

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGa9cffd14aa04: sshpeer: inline I/O into _validaterepo() 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2033?vs=5234=5250

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

AFFECTED FILES
  mercurial/sshpeer.py
  tests/sshprotoext.py

CHANGE DETAILS

diff --git a/tests/sshprotoext.py b/tests/sshprotoext.py
--- a/tests/sshprotoext.py
+++ b/tests/sshprotoext.py
@@ -54,24 +54,16 @@
 
 class extrahandshakecommandspeer(sshpeer.sshpeer):
 """An ssh peer that sends extra commands as part of initial handshake."""
-# There isn't a good hook point. So we wrap _callstream() and inject
-# logic when the peer says "hello".
-def _callstream(self, cmd, **args):
-if cmd != b'hello':
-return super(extrahandshakecommandspeer, self)._callstream(cmd,
-   **args)
-
+def _validaterepo(self):
 mode = self._ui.config(b'sshpeer', b'handshake-mode')
 if mode == b'pre-no-args':
 self._callstream(b'no-args')
-return super(extrahandshakecommandspeer, self)._callstream(
-cmd, **args)
+return super(extrahandshakecommandspeer, self)._validaterepo()
 elif mode == b'pre-multiple-no-args':
 self._callstream(b'unknown1')
 self._callstream(b'unknown2')
 self._callstream(b'unknown3')
-return super(extrahandshakecommandspeer, self)._callstream(
-cmd, **args)
+return super(extrahandshakecommandspeer, self)._validaterepo()
 else:
 raise error.ProgrammingError(b'unknown HANDSHAKECOMMANDMODE: %s' %
  mode)
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -212,18 +212,37 @@
 self._abort(error.RepoError(msg, hint=hint))
 
 try:
-# skip any noise generated by remote shell
-self._callstream("hello")
-r = self._callstream("between", pairs=("%s-%s" % ("0"*40, "0"*40)))
+pairsarg = '%s-%s' % ('0' * 40, '0' * 40)
+
+handshake = [
+'hello\n',
+'between\n',
+'pairs %d\n' % len(pairsarg),
+pairsarg,
+]
+
+requestlog = self.ui.configbool('devel', 'debug.peer-request')
+
+if requestlog:
+self.ui.debug('devel-peer-request: hello\n')
+self.ui.debug('sending hello command\n')
+if requestlog:
+self.ui.debug('devel-peer-request: between\n')
+self.ui.debug('devel-peer-request:   pairs: %d bytes\n' %
+  len(pairsarg))
+self.ui.debug('sending between command\n')
+
+self._pipeo.write(''.join(handshake))
+self._pipeo.flush()
 except IOError:
 badresponse()
 
 lines = ["", "dummy"]
 max_noise = 500
 while lines[-1] and max_noise:
 try:
-l = r.readline()
-self._readerr()
+l = self._pipei.readline()
+_forwardoutput(self.ui, self._pipee)
 if lines[-1] == "1\n" and l == "\n":
 break
 if l:



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


D2027: sshpeer: move URL validation out of sshpeer.__init__

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGb202d360d2a4: sshpeer: move URL validation out of 
sshpeer.__init__ (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2027?vs=5185=5244

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

AFFECTED FILES
  mercurial/sshpeer.py

CHANGE DETAILS

diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -121,13 +121,6 @@
 self._pipeo = self._pipei = self._pipee = None
 
 u = util.url(path, parsequery=False, parsefragment=False)
-if u.scheme != 'ssh' or not u.host or u.path is None:
-self._abort(error.RepoError(_("couldn't parse location %s") % 
path))
-
-util.checksafessh(path)
-
-if u.passwd is not None:
-self._abort(error.RepoError(_("password in URL not supported")))
 
 self._user = u.user
 self._host = u.host
@@ -371,4 +364,17 @@
 self._readerr()
 
 def instance(ui, path, create):
+"""Create an SSH peer.
+
+The returned object conforms to the ``wireproto.wirepeer`` interface.
+"""
+u = util.url(path, parsequery=False, parsefragment=False)
+if u.scheme != 'ssh' or not u.host or u.path is None:
+raise error.RepoError(_("couldn't parse location %s") % path)
+
+util.checksafessh(path)
+
+if u.passwd is not None:
+raise error.RepoError(_('password in URL not supported'))
+
 return sshpeer(ui, path, create=create)



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


D2031: sshpeer: establish SSH connection before class instantiation

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG00b9e26d727b: sshpeer: establish SSH connection before 
class instantiation (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2031?vs=5232=5248

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

AFFECTED FILES
  mercurial/sshpeer.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
@@ -69,7 +69,8 @@
 checkobject(badpeer())
 checkobject(httppeer.httppeer(ui, 'http://localhost'))
 checkobject(localrepo.localpeer(dummyrepo()))
-checkobject(testingsshpeer(ui, 'ssh://localhost/foo', False, ()))
+checkobject(testingsshpeer(ui, 'ssh://localhost/foo', False,
+   (None, None, None, None)))
 checkobject(bundlerepo.bundlepeer(dummyrepo()))
 checkobject(statichttprepo.statichttppeer(dummyrepo()))
 checkobject(unionrepo.unionpeer(dummyrepo()))
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -131,16 +131,40 @@
 
 pipee.close()
 
+def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None):
+"""Create an SSH connection to a server.
+
+Returns a tuple of (process, stdin, stdout, stderr) for the
+spawned process.
+"""
+cmd = '%s %s %s' % (
+sshcmd,
+args,
+util.shellquote('%s -R %s serve --stdio' % (
+_serverquote(remotecmd), _serverquote(path
+
+ui.debug('running %s\n' % cmd)
+cmd = util.quotecommand(cmd)
+
+# no buffer allow the use of 'select'
+# feel free to remove buffering and select usage when we ultimately
+# move to threading.
+stdin, stdout, stderr, proc = util.popen4(cmd, bufsize=0, env=sshenv)
+
+stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr)
+stdin = doublepipe(ui, stdin, stderr)
+
+return proc, stdin, stdout, stderr
+
 class sshpeer(wireproto.wirepeer):
 def __init__(self, ui, path, create=False, sshstate=None):
 self._url = path
 self._ui = ui
-self._pipeo = self._pipei = self._pipee = None
+# self._subprocess is unused. Keeping a handle on the process
+# holds a reference and prevents it from being garbage collected.
+self._subprocess, self._pipei, self._pipeo, self._pipee = sshstate
 
-u = util.url(path, parsequery=False, parsefragment=False)
-self._path = u.path or '.'
-
-self._validaterepo(*sshstate)
+self._validaterepo()
 
 # Begin of _basepeer interface.
 
@@ -172,28 +196,7 @@
 
 # End of _basewirecommands interface.
 
-def _validaterepo(self, sshcmd, args, remotecmd, sshenv=None):
-assert self._pipei is None
-
-cmd = '%s %s %s' % (sshcmd, args,
-util.shellquote("%s -R %s serve --stdio" %
-(_serverquote(remotecmd), _serverquote(self._path
-self.ui.debug('running %s\n' % cmd)
-cmd = util.quotecommand(cmd)
-
-# while self._subprocess isn't used, having it allows the subprocess to
-# to clean up correctly later
-#
-# no buffer allow the use of 'select'
-# feel free to remove buffering and select usage when we ultimately
-# move to threading.
-sub = util.popen4(cmd, bufsize=0, env=sshenv)
-self._pipeo, self._pipei, self._pipee, self._subprocess = sub
-
-self._pipei = util.bufferedinputpipe(self._pipei)
-self._pipei = doublepipe(self.ui, self._pipei, self._pipee)
-self._pipeo = doublepipe(self.ui, self._pipeo, self._pipee)
-
+def _validaterepo(self):
 def badresponse():
 msg = _("no suitable response from remote hg")
 hint = self.ui.config("ui", "ssherrorhint")
@@ -380,6 +383,9 @@
 if res != 0:
 raise error.RepoError(_('could not create remote repo'))
 
-sshstate = (sshcmd, args, remotecmd, sshenv)
+proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd,
+  remotepath, sshenv)
+
+sshstate = (proc, stdout, stdin, stderr)
 
 return sshpeer(ui, path, create=create, sshstate=sshstate)



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


D2030: sshpeer: remove frivolous call to _cleanup()

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG94ba29934f00: sshpeer: remove frivolous call to _cleanup() 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2030?vs=5188=5247

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

AFFECTED FILES
  mercurial/sshpeer.py

CHANGE DETAILS

diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -173,8 +173,7 @@
 # End of _basewirecommands interface.
 
 def _validaterepo(self, sshcmd, args, remotecmd, sshenv=None):
-# cleanup up previous run
-self._cleanup()
+assert self._pipei is None
 
 cmd = '%s %s %s' % (sshcmd, args,
 util.shellquote("%s -R %s serve --stdio" %



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


D2029: sshpeer: extract pipe cleanup logic to own function

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG805edf16e8e0: sshpeer: extract pipe cleanup logic to own 
function (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2029?vs=5187=5246

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

AFFECTED FILES
  mercurial/sshpeer.py

CHANGE DETAILS

diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -114,6 +114,23 @@
 def flush(self):
 return self._main.flush()
 
+def _cleanuppipes(ui, pipei, pipeo, pipee):
+"""Clean up pipes used by an SSH connection."""
+if pipeo:
+pipeo.close()
+if pipei:
+pipei.close()
+
+if pipee:
+# Try to read from the err descriptor until EOF.
+try:
+for l in pipee:
+ui.status(_('remote: '), l)
+except (IOError, ValueError):
+pass
+
+pipee.close()
+
 class sshpeer(wireproto.wirepeer):
 def __init__(self, ui, path, create=False, sshstate=None):
 self._url = path
@@ -221,17 +238,7 @@
 raise exception
 
 def _cleanup(self):
-if self._pipeo is None:
-return
-self._pipeo.close()
-self._pipei.close()
-try:
-# read the error descriptor until EOF
-for l in self._pipee:
-self.ui.status(_("remote: "), l)
-except (IOError, ValueError):
-pass
-self._pipee.close()
+_cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee)
 
 __del__ = _cleanup
 



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


D2028: sshpeer: move ssh command and repo creation logic out of __init__

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG31449baf0936: sshpeer: move ssh command and repo creation 
logic out of __init__ (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2028?vs=5186=5245

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

AFFECTED FILES
  mercurial/sshpeer.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
@@ -69,7 +69,7 @@
 checkobject(badpeer())
 checkobject(httppeer.httppeer(ui, 'http://localhost'))
 checkobject(localrepo.localpeer(dummyrepo()))
-checkobject(testingsshpeer(ui, 'ssh://localhost/foo'))
+checkobject(testingsshpeer(ui, 'ssh://localhost/foo', False, ()))
 checkobject(bundlerepo.bundlepeer(dummyrepo()))
 checkobject(statichttprepo.statichttppeer(dummyrepo()))
 checkobject(unionrepo.unionpeer(dummyrepo()))
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -115,35 +115,15 @@
 return self._main.flush()
 
 class sshpeer(wireproto.wirepeer):
-def __init__(self, ui, path, create=False):
+def __init__(self, ui, path, create=False, sshstate=None):
 self._url = path
 self._ui = ui
 self._pipeo = self._pipei = self._pipee = None
 
 u = util.url(path, parsequery=False, parsefragment=False)
-
-self._user = u.user
-self._host = u.host
-self._port = u.port
 self._path = u.path or '.'
 
-sshcmd = self.ui.config("ui", "ssh")
-remotecmd = self.ui.config("ui", "remotecmd")
-sshaddenv = dict(self.ui.configitems("sshenv"))
-sshenv = util.shellenviron(sshaddenv)
-
-args = util.sshargs(sshcmd, self._host, self._user, self._port)
-
-if create:
-cmd = '%s %s %s' % (sshcmd, args,
-util.shellquote("%s init %s" %
-(_serverquote(remotecmd), _serverquote(self._path
-ui.debug('running %s\n' % cmd)
-res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv)
-if res != 0:
-self._abort(error.RepoError(_("could not create remote repo")))
-
-self._validaterepo(sshcmd, args, remotecmd, sshenv)
+self._validaterepo(*sshstate)
 
 # Begin of _basepeer interface.
 
@@ -377,4 +357,23 @@
 if u.passwd is not None:
 raise error.RepoError(_('password in URL not supported'))
 
-return sshpeer(ui, path, create=create)
+sshcmd = ui.config('ui', 'ssh')
+remotecmd = ui.config('ui', 'remotecmd')
+sshaddenv = dict(ui.configitems('sshenv'))
+sshenv = util.shellenviron(sshaddenv)
+remotepath = u.path or '.'
+
+args = util.sshargs(sshcmd, u.host, u.user, u.port)
+
+if create:
+cmd = '%s %s %s' % (sshcmd, args,
+util.shellquote('%s init %s' %
+(_serverquote(remotecmd), _serverquote(remotepath
+ui.debug('running %s\n' % cmd)
+res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv)
+if res != 0:
+raise error.RepoError(_('could not create remote repo'))
+
+sshstate = (sshcmd, args, remotecmd, sshenv)
+
+return sshpeer(ui, path, create=create, sshstate=sshstate)



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


D2026: tests: add low-level SSH protocol tests

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG83d67257ba90: tests: add low-level SSH protocol tests 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2026?vs=5227=5243

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

AFFECTED FILES
  tests/sshprotoext.py
  tests/test-ssh-proto.t

CHANGE DETAILS

diff --git a/tests/test-ssh-proto.t b/tests/test-ssh-proto.t
new file mode 100644
--- /dev/null
+++ b/tests/test-ssh-proto.t
@@ -0,0 +1,398 @@
+  $ cat >> $HGRCPATH << EOF
+  > [ui]
+  > ssh = $PYTHON "$TESTDIR/dummyssh"
+  > [devel]
+  > debug.peer-request = true
+  > [extensions]
+  > sshprotoext = $TESTDIR/sshprotoext.py
+  > EOF
+
+  $ hg init server
+  $ cd server
+  $ echo 0 > foo
+  $ hg -q add foo
+  $ hg commit -m initial
+  $ cd ..
+
+Test a normal behaving server, for sanity
+
+  $ hg --debug debugpeer ssh://user@dummy/server
+  running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
+  devel-peer-request: hello
+  sending hello command
+  devel-peer-request: between
+  devel-peer-request:   pairs: 81 bytes
+  sending between command
+  remote: 384
+  remote: capabilities: lookup changegroupsubset branchmap pushkey known 
getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 
$USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  remote: 1
+  url: ssh://user@dummy/server
+  local: no
+  pushable: yes
+
+Server should answer the "hello" command in isolation
+
+  $ hg -R server serve --stdio << EOF
+  > hello
+  > EOF
+  384
+  capabilities: lookup changegroupsubset branchmap pushkey known getbundle 
unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ 
unbundle=HG10GZ,HG10BZ,HG10UN
+
+>=0.9.1 clients send a "hello" + "between" for the null range as part of 
handshake.
+Server should reply with capabilities and should send "1\n\n" as a successful
+reply with empty response to the "between".
+
+  $ hg -R server serve --stdio << EOF
+  > hello
+  > between
+  > pairs 81
+  > 
-
+  > EOF
+  384
+  capabilities: lookup changegroupsubset branchmap pushkey known getbundle 
unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ 
unbundle=HG10GZ,HG10BZ,HG10UN
+  1
+  
+
+SSH banner is not printed by default, ignored by clients
+
+  $ SSHSERVERMODE=banner hg debugpeer ssh://user@dummy/server
+  url: ssh://user@dummy/server
+  local: no
+  pushable: yes
+
+--debug will print the banner
+
+  $ SSHSERVERMODE=banner hg --debug debugpeer ssh://user@dummy/server
+  running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
+  devel-peer-request: hello
+  sending hello command
+  devel-peer-request: between
+  devel-peer-request:   pairs: 81 bytes
+  sending between command
+  remote: banner: line 0
+  remote: banner: line 1
+  remote: banner: line 2
+  remote: banner: line 3
+  remote: banner: line 4
+  remote: banner: line 5
+  remote: banner: line 6
+  remote: banner: line 7
+  remote: banner: line 8
+  remote: banner: line 9
+  remote: 384
+  remote: capabilities: lookup changegroupsubset branchmap pushkey known 
getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 
$USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  remote: 1
+  url: ssh://user@dummy/server
+  local: no
+  pushable: yes
+
+And test the banner with the raw protocol
+
+  $ SSHSERVERMODE=banner hg -R server serve --stdio << EOF
+  > hello
+  > between
+  > pairs 81
+  > 
-
+  > EOF
+  banner: line 0
+  banner: line 1
+  banner: line 2
+  banner: line 3
+  banner: line 4
+  banner: line 5
+  banner: line 6
+  banner: line 7
+  banner: line 8
+  banner: line 9
+  384
+  capabilities: lookup changegroupsubset branchmap pushkey known getbundle 
unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ 
unbundle=HG10GZ,HG10BZ,HG10UN
+  1
+  
+
+Connecting to a <0.9.1 server that doesn't support the hello command
+
+  $ SSHSERVERMODE=no-hello hg --debug debugpeer ssh://user@dummy/server
+  running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
+  devel-peer-request: hello
+  sending hello command
+  devel-peer-request: between
+  devel-peer-request:   pairs: 81 bytes
+  sending between command
+  remote: 0
+  remote: 1
+  url: ssh://user@dummy/server
+  local: no
+  pushable: yes
+
+The client should interpret this as no capabilities
+
+  $ SSHSERVERMODE=no-hello hg debugcapabilities ssh://user@dummy/server
+  Main capabilities:
+
+Sending an unknown command to the server results in an empty response to that 
command
+
+  $ hg -R server serve --stdio << EOF
+  > pre-hello
+  > hello
+  > between
+  > pairs 81
+  > 
-
+  > 

D2024: sshpeer: make "instance" a function

2018-02-06 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGb0d2885c5945: sshpeer: make instance a function 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2024?vs=5182=5241

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

AFFECTED FILES
  mercurial/sshpeer.py

CHANGE DETAILS

diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -370,4 +370,5 @@
 self._pipeo.flush()
 self._readerr()
 
-instance = sshpeer
+def instance(ui, path, create):
+return sshpeer(ui, path, create=create)



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


[PATCH 09 of 13] revlog: use context manager for data file lifetime in checkinlinesize

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517848487 -3600
#  Mon Feb 05 17:34:47 2018 +0100
# Node ID c4015bae897ca99b12933bf74a176fa6a349681b
# Parent  da0b895c385747d820294509d102d633419f8036
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
c4015bae897c
revlog: use context manager for data file lifetime in checkinlinesize

This is clearer, safer and more modern.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1859,12 +1859,9 @@ class revlog(object):
 fp.flush()
 fp.close()
 
-df = self._datafp('w')
-try:
+with self._datafp('w') as df:
 for r in self:
 df.write(self._getsegmentforrevs(r, r)[1])
-finally:
-df.close()
 
 fp = self._indexfp('w')
 self.version &= ~FLAG_INLINE_DATA
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 10 of 13] revlog: use context manager for index file lifetime in checkinlinesize

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517848497 -3600
#  Mon Feb 05 17:34:57 2018 +0100
# Node ID 1a212682563740e031380befc949167e73b476bd
# Parent  c4015bae897ca99b12933bf74a176fa6a349681b
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
1a2126825637
revlog: use context manager for index file lifetime in checkinlinesize

This is clearer, safer and more modern.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1863,16 +1863,16 @@ class revlog(object):
 for r in self:
 df.write(self._getsegmentforrevs(r, r)[1])
 
-fp = self._indexfp('w')
-self.version &= ~FLAG_INLINE_DATA
-self._inline = False
-for i in self:
-e = self._io.packentry(self.index[i], self.node, self.version, i)
-fp.write(e)
+with self._indexfp('w') as fp:
+self.version &= ~FLAG_INLINE_DATA
+self._inline = False
+io = self._io
+for i in self:
+e = io.packentry(self.index[i], self.node, self.version, i)
+fp.write(e)
 
-# if we don't call close, the temp file will never replace the
-# real index
-fp.close()
+# the temp file replace the real index when we exit the context
+# manager
 
 tr.replace(self.indexfile, trindex * self._io.size)
 self._chunkclear()
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 07 of 13] revlog: move index file opening in a method

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517847733 -3600
#  Mon Feb 05 17:22:13 2018 +0100
# Node ID d238ec45ba25f7c1ea9ec22aa11a4ec699c72740
# Parent  b192ee27b376523292ec1cf52c49c9382a870658
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
d238ec45ba25
revlog: move index file opening in a method

Having file operation centralized into a single spot help to factor common
logic out (eg: special flag handling according to the mode).

It is also the first step to simplify file handling during batch operation
(eg: revlog cloning). However, that part does not seems to be a hotspot yet.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -621,7 +621,7 @@ class revlog(object):
 indexdata = ''
 self._initempty = True
 try:
-f = self.opener(self.indexfile)
+f = self._indexfp()
 if (mmapindexthreshold is not None and
 self.opener.fstat(f).st_size >= mmapindexthreshold):
 indexdata = util.buffer(util.mmapread(f))
@@ -682,6 +682,15 @@ class revlog(object):
 def _compressor(self):
 return util.compengines[self._compengine].revlogcompressor()
 
+def _indexfp(self, mode='r'):
+"""file object for the revlog's index file"""
+args = {'mode': mode}
+if mode != 'r':
+args['checkambig'] = self._checkambig
+if mode == 'w':
+args['atomictemp'] = True
+return self.opener(self.indexfile, **args)
+
 def _datafp(self, mode='r'):
 """file object for the revlog's data file"""
 return self.opener(self.datafile, mode=mode)
@@ -1498,7 +1507,7 @@ class revlog(object):
 closehandle = False
 else:
 if self._inline:
-df = self.opener(self.indexfile)
+df = self._indexfp()
 else:
 df = self._datafp()
 closehandle = True
@@ -1858,8 +1867,7 @@ class revlog(object):
 finally:
 df.close()
 
-fp = self.opener(self.indexfile, 'w', atomictemp=True,
- checkambig=self._checkambig)
+fp = self._indexfp('w')
 self.version &= ~FLAG_INLINE_DATA
 self._inline = False
 for i in self:
@@ -1928,7 +1936,7 @@ class revlog(object):
 dfh = None
 if not self._inline:
 dfh = self._datafp("a+")
-ifh = self.opener(self.indexfile, "a+", checkambig=self._checkambig)
+ifh = self._indexfp("a+")
 try:
 return self._addrevision(node, rawtext, transaction, link, p1, p2,
  flags, cachedelta, ifh, dfh,
@@ -2157,7 +2165,7 @@ class revlog(object):
 end = 0
 if r:
 end = self.end(r - 1)
-ifh = self.opener(self.indexfile, "a+", checkambig=self._checkambig)
+ifh = self._indexfp("a+")
 isize = r * self._io.size
 if self._inline:
 transaction.add(self.indexfile, end + isize, r)
@@ -2229,8 +2237,7 @@ class revlog(object):
 # reopen the index
 ifh.close()
 dfh = self._datafp("a+")
-ifh = self.opener(self.indexfile, "a+",
-  checkambig=self._checkambig)
+ifh = self._indexfp("a+")
 finally:
 if dfh:
 dfh.close()
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 13 of 13] revlog: rename 'self.checkinlinesize' into '_enforceinlinesize'

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517850280 -3600
#  Mon Feb 05 18:04:40 2018 +0100
# Node ID 70bf9e3148bf504164f1e5c3a40c92ced158e921
# Parent  6e3ed0354bf4f160bb7e1402ca1548282ba8b772
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
70bf9e3148bf
revlog: rename 'self.checkinlinesize' into '_enforceinlinesize'

The name change has two motivations:

1) The function has no external caller, so we move it to protected space.
2) the function does more than checking it also split the data if we have more
   data than 'inline' supports.

diff --git a/mercurial/changelog.py b/mercurial/changelog.py
--- a/mercurial/changelog.py
+++ b/mercurial/changelog.py
@@ -432,7 +432,7 @@ class changelog(revlog.revlog):
 self._delaybuf = None
 self._divert = False
 # split when we're done
-self.checkinlinesize(tr)
+self._enforceinlinesize(tr)
 
 def _writepending(self, tr):
 "create a file containing the unfinalized state for pretxnchangegroup"
@@ -458,9 +458,9 @@ class changelog(revlog.revlog):
 
 return False
 
-def checkinlinesize(self, tr, fp=None):
+def _enforceinlinesize(self, tr, fp=None):
 if not self._delayed:
-revlog.revlog.checkinlinesize(self, tr, fp)
+revlog.revlog._enforceinlinesize(self, tr, fp)
 
 def read(self, node):
 """Obtain data from a parsed changelog revision.
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1834,7 +1834,7 @@ class revlog(object):
 raise RevlogError(_("integrity check failed on %s:%s")
 % (self.indexfile, pycompat.bytestr(revornode)))
 
-def checkinlinesize(self, tr, fp=None):
+def _enforceinlinesize(self, tr, fp=None):
 """Check if the revlog is too big for inline and convert if so.
 
 This should be called after revisions are added to the revlog. If the
@@ -2145,7 +2145,7 @@ class revlog(object):
 ifh.write(entry)
 ifh.write(data[0])
 ifh.write(data[1])
-self.checkinlinesize(transaction, ifh)
+self._enforceinlinesize(transaction, ifh)
 
 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
 """
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 12 of 13] revlog: add a _datareadfp context manager for data access needs

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517849849 -3600
#  Mon Feb 05 17:57:29 2018 +0100
# Node ID 6e3ed0354bf4f160bb7e1402ca1548282ba8b772
# Parent  9073bbc68cb1ccc5685c78dbe837f31406324028
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
6e3ed0354bf4
revlog: add a _datareadfp context manager for data access needs

The helper handles:
1) is there a file handle already open that we shall just reuse,
2) is the revlog inlined or not.

Using a context manager for all read access will help setting up file pointer
caching in later changesets.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -15,6 +15,7 @@ from __future__ import absolute_import
 
 import binascii
 import collections
+import contextlib
 import errno
 import hashlib
 import heapq
@@ -694,6 +695,19 @@ class revlog(object):
 """file object for the revlog's data file"""
 return self.opener(self.datafile, mode=mode)
 
+@contextlib.contextmanager
+def _datareadfp(self, existingfp=None):
+"""file object suitable to read data"""
+if existingfp is not None:
+yield existingfp
+else:
+if self._inline:
+func = self._indexfp
+else:
+func = self._datafp
+with func() as fp:
+yield fp
+
 def tip(self):
 return self.node(len(self.index) - 2)
 def __contains__(self, rev):
@@ -1502,15 +1516,6 @@ class revlog(object):
 
 Returns a str or buffer of raw byte data.
 """
-if df is not None:
-closehandle = False
-else:
-if self._inline:
-df = self._indexfp()
-else:
-df = self._datafp()
-closehandle = True
-
 # Cache data both forward and backward around the requested
 # data, in a fixed size window. This helps speed up operations
 # involving reading the revlog backwards.
@@ -1518,10 +1523,9 @@ class revlog(object):
 realoffset = offset & ~(cachesize - 1)
 reallength = (((offset + length + cachesize) & ~(cachesize - 1))
   - realoffset)
-df.seek(realoffset)
-d = df.read(reallength)
-if closehandle:
-df.close()
+with self._datareadfp(df) as df:
+df.seek(realoffset)
+d = df.read(reallength)
 self._cachesegment(realoffset, d)
 if offset != realoffset or reallength != length:
 return util.buffer(d, offset - realoffset, length)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 08 of 13] revlog: use context manager for index file life time in __init__

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517848459 -3600
#  Mon Feb 05 17:34:19 2018 +0100
# Node ID da0b895c385747d820294509d102d633419f8036
# Parent  d238ec45ba25f7c1ea9ec22aa11a4ec699c72740
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
da0b895c3857
revlog: use context manager for index file life time in __init__

This is clearer, safer and more modern.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -621,13 +621,12 @@ class revlog(object):
 indexdata = ''
 self._initempty = True
 try:
-f = self._indexfp()
-if (mmapindexthreshold is not None and
-self.opener.fstat(f).st_size >= mmapindexthreshold):
-indexdata = util.buffer(util.mmapread(f))
-else:
-indexdata = f.read()
-f.close()
+with self._indexfp() as f:
+if (mmapindexthreshold is not None and
+self.opener.fstat(f).st_size >= mmapindexthreshold):
+indexdata = util.buffer(util.mmapread(f))
+else:
+indexdata = f.read()
 if len(indexdata) > 0:
 v = versionformat_unpack(indexdata[:4])[0]
 self._initempty = False
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 11 of 13] revlog: use context manager for data file lifetime in checksize

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517848514 -3600
#  Mon Feb 05 17:35:14 2018 +0100
# Node ID 9073bbc68cb1ccc5685c78dbe837f31406324028
# Parent  1a212682563740e031380befc949167e73b476bd
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
9073bbc68cb1
revlog: use context manager for data file lifetime in checksize

This is clearer, safer and more modern.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -2335,10 +2335,9 @@ class revlog(object):
 expected = max(0, self.end(len(self) - 1))
 
 try:
-f = self._datafp()
-f.seek(0, 2)
-actual = f.tell()
-f.close()
+with self._datafp() as f:
+f.seek(0, 2)
+actual = f.tell()
 dd = actual - expected
 except IOError as inst:
 if inst.errno != errno.ENOENT:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 06 of 13] revlog: move datafile opening in a method

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517846636 -3600
#  Mon Feb 05 17:03:56 2018 +0100
# Node ID b192ee27b376523292ec1cf52c49c9382a870658
# Parent  dddbb1b848527a89ca887fdbec25725241efa376
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
b192ee27b376
revlog: move datafile opening in a method

Having file operation centralized into a single spot help to factor common
logic out.

It is also the first step to simplify file handling during batch operation
(eg: revlog cloning). However, that part does not seems to be a hotspot yet.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -682,6 +682,10 @@ class revlog(object):
 def _compressor(self):
 return util.compengines[self._compengine].revlogcompressor()
 
+def _datafp(self, mode='r'):
+"""file object for the revlog's data file"""
+return self.opener(self.datafile, mode=mode)
+
 def tip(self):
 return self.node(len(self.index) - 2)
 def __contains__(self, rev):
@@ -1496,7 +1500,7 @@ class revlog(object):
 if self._inline:
 df = self.opener(self.indexfile)
 else:
-df = self.opener(self.datafile)
+df = self._datafp()
 closehandle = True
 
 # Cache data both forward and backward around the requested
@@ -1847,7 +1851,7 @@ class revlog(object):
 fp.flush()
 fp.close()
 
-df = self.opener(self.datafile, 'w')
+df = self._datafp('w')
 try:
 for r in self:
 df.write(self._getsegmentforrevs(r, r)[1])
@@ -1923,7 +1927,7 @@ class revlog(object):
 """
 dfh = None
 if not self._inline:
-dfh = self.opener(self.datafile, "a+")
+dfh = self._datafp("a+")
 ifh = self.opener(self.indexfile, "a+", checkambig=self._checkambig)
 try:
 return self._addrevision(node, rawtext, transaction, link, p1, p2,
@@ -2161,7 +2165,7 @@ class revlog(object):
 else:
 transaction.add(self.indexfile, isize, r)
 transaction.add(self.datafile, end)
-dfh = self.opener(self.datafile, "a+")
+dfh = self._datafp("a+")
 def flush():
 if dfh:
 dfh.flush()
@@ -2224,7 +2228,7 @@ class revlog(object):
 # addrevision switched from inline to conventional
 # reopen the index
 ifh.close()
-dfh = self.opener(self.datafile, "a+")
+dfh = self._datafp("a+")
 ifh = self.opener(self.indexfile, "a+",
   checkambig=self._checkambig)
 finally:
@@ -2328,7 +2332,7 @@ class revlog(object):
 expected = max(0, self.end(len(self) - 1))
 
 try:
-f = self.opener(self.datafile)
+f = self._datafp()
 f.seek(0, 2)
 actual = f.tell()
 f.close()
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 05 of 13] parseindex: implement context manager method on the wrapper

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517916311 -3600
#  Tue Feb 06 12:25:11 2018 +0100
# Node ID dddbb1b848527a89ca887fdbec25725241efa376
# Parent  53534aa0676becd566238ce945274853526e9823
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
dddbb1b84852
parseindex: implement context manager method on the wrapper

This is needed for incoming cleanups.

diff --git a/tests/test-parseindex.t b/tests/test-parseindex.t
--- a/tests/test-parseindex.t
+++ b/tests/test-parseindex.t
@@ -41,6 +41,13 @@ We approximate that by reducing the read
   > def __getattr__(self, key):
   > return getattr(self.real, key)
   > 
+  > def __enter__(self):
+  > self.real.__enter__()
+  > return self
+  > 
+  > def __exit__(self, *args, **kwargs):
+  > return self.real.__exit__(*args, **kwargs)
+  > 
   > def opener(*args):
   > o = vfs.vfs(*args)
   > def wrapper(*a, **kwargs):
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 02 of 13] changelog: add the missing 'closed' property on 'appender' object

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517911721 -3600
#  Tue Feb 06 11:08:41 2018 +0100
# Node ID b9d09ad843263f81e9d561d76e65671af864cc6f
# Parent  cc2e588940df0435bf0e3013ebd45013a22fa8fe
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
b9d09ad84326
changelog: add the missing 'closed' property on 'appender' object

This mimic file object further.

diff --git a/mercurial/changelog.py b/mercurial/changelog.py
--- a/mercurial/changelog.py
+++ b/mercurial/changelog.py
@@ -90,6 +90,11 @@ class appender(object):
 return self.offset
 def flush(self):
 pass
+
+@property
+def closed(self):
+return self.fp.closed
+
 def close(self):
 self.fp.close()
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 04 of 13] parseindex: also forward keyword argument in a debug wrapper

2018-02-06 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1517914357 -3600
#  Tue Feb 06 11:52:37 2018 +0100
# Node ID 53534aa0676becd566238ce945274853526e9823
# Parent  4cd271a9bd82ddca149a0dd5a2ae819a4c1db8ef
# EXP-Topic revlog-fp
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
53534aa0676b
parseindex: also forward keyword argument in a debug wrapper

Otherwise, it gets in the way of a coming refactoring.

diff --git a/tests/test-parseindex.t b/tests/test-parseindex.t
--- a/tests/test-parseindex.t
+++ b/tests/test-parseindex.t
@@ -43,8 +43,8 @@ We approximate that by reducing the read
   > 
   > def opener(*args):
   > o = vfs.vfs(*args)
-  > def wrapper(*a):
-  > f = o(*a)
+  > def wrapper(*a, **kwargs):
+  > f = o(*a, **kwargs)
   > return singlebyteread(f)
   > return wrapper
   > 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 3 of 7 V2] cmdutil: convert _revertprefetch() to a generic stored file hook (API)

2018-02-06 Thread Matt Harbison

> On Feb 6, 2018, at 7:20 AM, Yuya Nishihara  wrote:
> 
>> On Tue, 06 Feb 2018 00:29:06 -0500, Matt Harbison wrote:
>> # HG changeset patch
>> # User Matt Harbison 
>> # Date 1517771668 18000
>> #  Sun Feb 04 14:14:28 2018 -0500
>> # Node ID ab23d9644edaf62b2c3927b735d2170fc76ca711
>> # Parent  94d427f881cfca5cae792c5eac4bf00e942106ec
>> cmdutil: convert _revertprefetch() to a generic stored file hook (API)
>> 
>> +"""Stub method for detecting extension wrapping of _revertprefetch(), to
>> +issue a deprecation warning."""
>> +
>> +_revertprefetch = _revertprefetchstub
>> +
>> +def _prefetchfiles(repo, ctx, files):
>> +"""Let extensions changing the storage layer prefetch content for any 
>> non
>> +merge based command."""
> 
> Random ideas:
> 
> - prefetchfiles() could be hosted by mergemod so lfs won't need to wrap
>   applyupdates().

Would it be better to keep it in cmdutil, and call it  just before calling 
applyupdates()?  Calling mergemod.prefetchfiles() from archive, for example, 
seems weird, doesn’t it?  Or am I misunderstanding?

> - it could be a list of callback functions, instead of carefully wrapping
>   the function itself

Just a raw list that everything can access, or should it have add/remove 
methods too?  I’ve seen both patterns with hook registration, IIRC.

> - should be a public function as archival.py depends on it for example?

Good idea

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


Re: [PATCH 3 of 7 V2] cmdutil: convert _revertprefetch() to a generic stored file hook (API)

2018-02-06 Thread Yuya Nishihara
On Tue, 06 Feb 2018 00:29:06 -0500, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison 
> # Date 1517771668 18000
> #  Sun Feb 04 14:14:28 2018 -0500
> # Node ID ab23d9644edaf62b2c3927b735d2170fc76ca711
> # Parent  94d427f881cfca5cae792c5eac4bf00e942106ec
> cmdutil: convert _revertprefetch() to a generic stored file hook (API)

> --- a/mercurial/cmdutil.py
> +++ b/mercurial/cmdutil.py
> @@ -2862,7 +2862,14 @@
>  
>  if not opts.get('dry_run'):
>  needdata = ('revert', 'add', 'undelete')
> -_revertprefetch(repo, ctx, *[actions[name][0] for name in 
> needdata])
> +if _revertprefetch is not _revertprefetchstub:
> +ui.deprecwarn("'cmdutil._revertprefetch' is deprecated, use "
> +  "'cmdutil._prefetchfiles'", '4.6', 
> stacklevel=1)
> +_revertprefetch(repo, ctx,
> +*[actions[name][0] for name in needdata])
> +oplist = [actions[name][0] for name in needdata]
> +_prefetchfiles(repo, ctx,
> +   [f for sublist in oplist for f in sublist])
>  _performrevert(repo, parents, ctx, actions, interactive, 
> tobackup)
>  
>  if targetsubs:
> @@ -2875,8 +2882,15 @@
>  raise error.Abort("subrepository '%s' does not exist in 
> %s!"
>% (sub, short(ctx.node(
>  
> -def _revertprefetch(repo, ctx, *files):
> -"""Let extension changing the storage layer prefetch content"""
> +def _revertprefetchstub():

Restored the original arguments in case it's called by wrapper.

> +"""Stub method for detecting extension wrapping of _revertprefetch(), to
> +issue a deprecation warning."""
> +
> +_revertprefetch = _revertprefetchstub
> +
> +def _prefetchfiles(repo, ctx, files):
> +"""Let extensions changing the storage layer prefetch content for any non
> +merge based command."""

Random ideas:

 - prefetchfiles() could be hosted by mergemod so lfs won't need to wrap
   applyupdates().
 - it could be a list of callback functions, instead of carefully wrapping
   the function itself
 - should be a public function as archival.py depends on it for example?
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 7 V2] lfs: factor out a method for extracting the pointer of a single file

2018-02-06 Thread Yuya Nishihara
On Tue, 06 Feb 2018 00:29:04 -0500, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison 
> # Date 1517082796 18000
> #  Sat Jan 27 14:53:16 2018 -0500
> # Node ID ae7b40a6cb0863e26e245966388d766adf065bac
> # Parent  2912bed9b0c7d02a1cac6f56584c0c0a2f9debe4
> lfs: factor out a method for extracting the pointer of a single file

Queued the series, thanks.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D2057: translate base85.c into rust code

2018-02-06 Thread durin42 (Augie Fackler)
durin42 added a subscriber: indygreg.
durin42 added a comment.


  I'd be curious to see what @indygreg has to say about this, maybe wait on his 
input before doing any work in response to my feedback?
  
  I do wonder if we should have at least three crates:
  
  1. hgcli
  2. libmercurial
  3. hgcext
  
  The first one would be the command-line entry point, the last could use the 
cpython API, and libmercurial would be "pure rust" and open the door to 
eventually having a libhg or something that exports C functions and would be 
suitable for cffi and linking into other binaries?

INLINE COMMENTS

> base85.rs:22
> +
> +pub fn b85encode(py: Python, text: , pad: i32) -> PyResult {
> +let text = text.as_bytes();

I think I'd like to separate things a bit more and have a Python-free module, 
and then a glue module that we can use to call into the pure Rust. Part of the 
reason is that in my perfect world we won't use the cpython crate for speedups 
so they can be used from pypy as well. Separating them at least makes it easier 
to have an extern "C" version of the method that can be used from cffi instead 
of only through the CPython API.

(Not sure what opinions others have. It's likely that I'll attempt this 
approach in the near future as part of a continued attempt to speed up `hg 
diff`.)

REPOSITORY
  rHG Mercurial

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

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


D2059: hgsh: enable clang-format

2018-02-06 Thread durin42 (Augie Fackler)
durin42 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Nothing looks awful, so we can just turn it on.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  contrib/clang-format-blacklist
  contrib/hgsh/hgsh.c

CHANGE DETAILS

diff --git a/contrib/hgsh/hgsh.c b/contrib/hgsh/hgsh.c
--- a/contrib/hgsh/hgsh.c
+++ b/contrib/hgsh/hgsh.c
@@ -48,65 +48,65 @@
  * have such machine, set to NULL.
  */
 #ifndef HG_GATEWAY
-#define HG_GATEWAY "gateway"
+#define HG_GATEWAY "gateway"
 #endif
 
 /*
  * HG_HOST: hostname of mercurial server. if any machine is allowed, set to
  * NULL.
  */
 #ifndef HG_HOST
-#define HG_HOST "mercurial"
+#define HG_HOST "mercurial"
 #endif
 
 /*
  * HG_USER: username to log in from HG_GATEWAY to HG_HOST. if gateway and
  * host username are same, set to NULL.
  */
 #ifndef HG_USER
-#define HG_USER "hg"
+#define HG_USER "hg"
 #endif
 
 /*
  * HG_ROOT: root of tree full of mercurial repos. if you do not want to
  * validate location of repo when someone is try to access, set to NULL.
  */
 #ifndef HG_ROOT
-#define HG_ROOT "/home/hg/repos"
+#define HG_ROOT "/home/hg/repos"
 #endif
 
 /*
  * HG: path to the mercurial executable to run.
  */
 #ifndef HG
-#define HG  "/home/hg/bin/hg"
+#define HG "/home/hg/bin/hg"
 #endif
 
 /*
  * HG_SHELL: shell to use for actions like "sudo" and "su" access to
  * mercurial user, and cron jobs. if you want to make these things
  * impossible, set to NULL.
  */
 #ifndef HG_SHELL
-#define HG_SHELLNULL
+#define HG_SHELL NULL
 /* #define HG_SHELL"/bin/bash" */
 #endif
 
 /*
  * HG_HELP: some way for users to get support if they have problem. if they
  * should not get helpful message, set to NULL.
  */
 #ifndef HG_HELP
-#define HG_HELP "please contact supp...@example.com for help."
+#define HG_HELP "please contact supp...@example.com for help."
 #endif
 
 /*
  * SSH: path to ssh executable to run, if forwarding from HG_GATEWAY to
  * HG_HOST. if you want to use rsh instead (why?), you need to modify
  * arguments it is called with. see forward_through_gateway.
  */
 #ifndef SSH
-#define SSH "/usr/bin/ssh"
+#define SSH "/usr/bin/ssh"
 #endif
 
 /*
@@ -249,7 +249,6 @@
hg_serve,
 };
 
-
 /*
  * attempt to verify that a directory is really a hg repo, by testing
  * for the existence of a subdirectory.
@@ -310,8 +309,7 @@
 
if (sscanf(argv[2], "hg init %as", ) == 1) {
cmd = hg_init;
-   }
-   else if (sscanf(argv[2], "hg -R %as serve --stdio", ) == 1) {
+   } else if (sscanf(argv[2], "hg -R %as serve --stdio", ) == 1) {
cmd = hg_serve;
} else {
goto badargs;
diff --git a/contrib/clang-format-blacklist b/contrib/clang-format-blacklist
--- a/contrib/clang-format-blacklist
+++ b/contrib/clang-format-blacklist
@@ -1,6 +1,5 @@
 # Files that just need to be migrated to the formatter.
 # Do not add new files here!
-contrib/hgsh/hgsh.c
 mercurial/cext/base85.c
 mercurial/cext/bdiff.c
 mercurial/cext/charencode.c



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


D2058: chg: enable clang-format on all .c and .h files

2018-02-06 Thread durin42 (Augie Fackler)
durin42 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Nothing in here looks awful, so I think we may as well just do it.
  
  1. skip-blame because it's just reformatting with no functionality change

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  contrib/chg/chg.c
  contrib/chg/hgclient.c
  contrib/chg/hgclient.h
  contrib/chg/procutil.c
  contrib/chg/util.c
  contrib/chg/util.h
  contrib/clang-format-blacklist

CHANGE DETAILS

diff --git a/contrib/clang-format-blacklist b/contrib/clang-format-blacklist
--- a/contrib/clang-format-blacklist
+++ b/contrib/clang-format-blacklist
@@ -1,12 +1,5 @@
 # Files that just need to be migrated to the formatter.
 # Do not add new files here!
-contrib/chg/chg.c
-contrib/chg/hgclient.c
-contrib/chg/hgclient.h
-contrib/chg/procutil.c
-contrib/chg/procutil.h
-contrib/chg/util.c
-contrib/chg/util.h
 contrib/hgsh/hgsh.c
 mercurial/cext/base85.c
 mercurial/cext/bdiff.c
diff --git a/contrib/chg/util.h b/contrib/chg/util.h
--- a/contrib/chg/util.h
+++ b/contrib/chg/util.h
@@ -32,4 +32,4 @@
 
 int runshellcmd(const char *cmd, const char *envp[], const char *cwd);
 
-#endif  /* UTIL_H_ */
+#endif /* UTIL_H_ */
diff --git a/contrib/chg/util.c b/contrib/chg/util.c
--- a/contrib/chg/util.c
+++ b/contrib/chg/util.c
@@ -62,7 +62,8 @@
 static int debugmsgenabled = 0;
 static double debugstart = 0;
 
-static double now() {
+static double now()
+{
struct timeval t;
gettimeofday(, NULL);
return t.tv_usec / 1e6 + t.tv_sec;
diff --git a/contrib/chg/procutil.c b/contrib/chg/procutil.c
--- a/contrib/chg/procutil.c
+++ b/contrib/chg/procutil.c
@@ -54,7 +54,7 @@
goto error;
 
forwardsignal(sig);
-   if (raise(sig) < 0)  /* resend to self */
+   if (raise(sig) < 0) /* resend to self */
goto error;
if (sigaction(sig, , ) < 0)
goto error;
@@ -205,8 +205,8 @@
close(pipefds[0]);
close(pipefds[1]);
 
-   int r = execle("/bin/sh", "/bin/sh", "-c", pagercmd, NULL,
-   envp);
+   int r =
+   execle("/bin/sh", "/bin/sh", "-c", pagercmd, NULL, envp);
if (r < 0) {
abortmsgerrno("cannot start pager '%s'", pagercmd);
}
diff --git a/contrib/chg/hgclient.h b/contrib/chg/hgclient.h
--- a/contrib/chg/hgclient.h
+++ b/contrib/chg/hgclient.h
@@ -22,9 +22,9 @@
 pid_t hgc_peerpid(const hgclient_t *hgc);
 
 const char **hgc_validate(hgclient_t *hgc, const char *const args[],
- size_t argsize);
+  size_t argsize);
 int hgc_runcommand(hgclient_t *hgc, const char *const args[], size_t argsize);
 void hgc_attachio(hgclient_t *hgc);
 void hgc_setenv(hgclient_t *hgc, const char *const envp[]);
 
-#endif  /* HGCLIENT_H_ */
+#endif /* HGCLIENT_H_ */
diff --git a/contrib/chg/hgclient.c b/contrib/chg/hgclient.c
--- a/contrib/chg/hgclient.c
+++ b/contrib/chg/hgclient.c
@@ -7,7 +7,7 @@
  * GNU General Public License version 2 or any later version.
  */
 
-#include   /* for ntohl(), htonl() */
+#include  /* for ntohl(), htonl() */
 #include 
 #include 
 #include 
@@ -26,33 +26,32 @@
 #include "procutil.h"
 #include "util.h"
 
-enum {
-   CAP_GETENCODING = 0x0001,
-   CAP_RUNCOMMAND = 0x0002,
-   /* cHg extension: */
-   CAP_ATTACHIO = 0x0100,
-   CAP_CHDIR = 0x0200,
-   CAP_SETENV = 0x0800,
-   CAP_SETUMASK = 0x1000,
-   CAP_VALIDATE = 0x2000,
-   CAP_SETPROCNAME = 0x4000,
+enum { CAP_GETENCODING = 0x0001,
+   CAP_RUNCOMMAND = 0x0002,
+   /* cHg extension: */
+   CAP_ATTACHIO = 0x0100,
+   CAP_CHDIR = 0x0200,
+   CAP_SETENV = 0x0800,
+   CAP_SETUMASK = 0x1000,
+   CAP_VALIDATE = 0x2000,
+   CAP_SETPROCNAME = 0x4000,
 };
 
 typedef struct {
const char *name;
unsigned int flag;
 } cappair_t;
 
 static const cappair_t captable[] = {
-   {"getencoding", CAP_GETENCODING},
-   {"runcommand", CAP_RUNCOMMAND},
-   {"attachio", CAP_ATTACHIO},
-   {"chdir", CAP_CHDIR},
-   {"setenv", CAP_SETENV},
-   {"setumask", CAP_SETUMASK},
-   {"validate", CAP_VALIDATE},
-   {"setprocname", CAP_SETPROCNAME},
-   {NULL, 0},  /* terminator */
+{"getencoding", CAP_GETENCODING},
+{"runcommand", CAP_RUNCOMMAND},
+{"attachio", CAP_ATTACHIO},
+{"chdir", CAP_CHDIR},
+{"setenv", CAP_SETENV},
+{"setumask", CAP_SETUMASK},
+{"validate", CAP_VALIDATE},
+{"setprocname", CAP_SETPROCNAME},
+{NULL, 0}, /* terminator */
 };
 
 typedef struct {
@@ -88,8 +87,8 @@
if (newsize <= ctx->maxdatasize)
return;
 
-   newsize = defaultdatasize
-   * ((newsize + defaultdatasize - 1) / defaultdatasize);
+   newsize = defaultdatasize *
+