D4820: logtoprocess: sends the canonical command name to the subprocess

2018-10-03 Thread lothiraldan (Boris Feld)
lothiraldan added a comment.


  In https://phab.mercurial-scm.org/D4820#73256, @yuja wrote:
  
  > > +def extsetup():
  > >  +# this is to get the canonical name of the command: "commit", not 
"ci"
  > >  +def wrapdispatch(orig, *args, **kwargs):
  > >  +encoding.environ.pop("LTP_COMMAND", None)
  > >  +return orig(*args, **kwargs)
  > >  +
  > >  +def wrapruncommand(orig, *args, **kwargs):
  > >  +encoding.environ["LTP_COMMAND"] = args[2]
  > >  +return orig(*args, **kwargs)
  > >  +
  > >  +extensions.wrapfunction(dispatch,'dispatch',wrapdispatch)
  > >  +extensions.wrapfunction(dispatch,'runcommand',wrapruncommand)
  >
  > It's scary to update the environment variables globally and pass
  >  `LTP_COMMAND` in to any child processes.
  >
  > Can you add a proper way to teach the command name to the logtoprocess
  >  extension, by `ui.log()` for example?
  >
  > Also, the word `LTP` isn't used anywhere. It'll need a better name, and
  >  should be documented.
  
  
  I tried to pass it to the `ui.log()` but didn't find a clean way to transfer 
it from `dispatch._dispatch` to `dispatch.dispatch`. I tried storing it in the 
ui object but without luck.
  
  Do you think it would be ok to store it in the `request` object?

REPOSITORY
  rHG Mercurial

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

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


[PATCH] lfs: register the flag processors per repository

2018-10-03 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1538626646 14400
#  Thu Oct 04 00:17:26 2018 -0400
# Node ID e010a7be6dc96ea7d48be81a7c5e8a8ed8bf6c31
# Parent  7a347d362a455d84bccf34347171d89724b9c9df
lfs: register the flag processors per repository

Previously, enabling the extension for any repo in commandserver or hgweb would
enable the flags on all repos.  Since localrepo.resolverevlogstorevfsoptions()
is called so early, the svfs option needs to be forced on later in reposetup()
to handle the case where the extension loads, but no lfs requirement has been
set.  That way, the flags processor is enabled when committing or unbundling.
This will also ensure that the flags processor is available on all revlogs in a
long running process.

I'm not sure if we need a formal API to add options like this- narrow doesn't
seem to need it.  I'm also not sure if REPO_FEATURE_LFS should just be added
unconditionally in reposetup()- it's easy enough to check the requirements to
see if a blob was actually committed.

diff --git a/hgext/lfs/__init__.py b/hgext/lfs/__init__.py
--- a/hgext/lfs/__init__.py
+++ b/hgext/lfs/__init__.py
@@ -218,6 +218,7 @@ def reposetup(ui, repo):
 
 repo.svfs.lfslocalblobstore = blobstore.local(repo)
 repo.svfs.lfsremoteblobstore = blobstore.remote(repo)
+repo.svfs.options[b'enableextstored'] = True
 
 class lfsrepo(repo.__class__):
 @localrepo.unfilteredmethod
@@ -334,14 +335,9 @@ def extsetup(ui):
 wrapfunction(context.basefilectx, 'isbinary', wrapper.filectxisbinary)
 context.basefilectx.islfs = wrapper.filectxislfs
 
-revlog.addflagprocessor(
-revlog.REVIDX_EXTSTORED,
-(
-wrapper.readfromstore,
-wrapper.writetostore,
-wrapper.bypasscheckhash,
-),
-)
+wrapfunction(revlog, 'extstoredrawprocessor', wrapper.bypasscheckhash)
+wrapfunction(revlog, 'extstoredreadprocessor', wrapper.readfromstore)
+wrapfunction(revlog, 'extstoredwriteprocessor', wrapper.writetostore)
 
 scmutil.fileprefetchhooks.add('lfs', wrapper._prefetchfiles)
 
diff --git a/hgext/lfs/wrapper.py b/hgext/lfs/wrapper.py
--- a/hgext/lfs/wrapper.py
+++ b/hgext/lfs/wrapper.py
@@ -50,10 +50,10 @@ def _capabilities(orig, repo, proto):
 caps.append('lfs')
 return caps
 
-def bypasscheckhash(self, text):
+def bypasscheckhash(orig, self, text):
 return False
 
-def readfromstore(self, text):
+def readfromstore(orig, self, text):
 """Read filelog content from local blobstore transform for flagprocessor.
 
 Default tranform for flagprocessor, returning contents from blobstore.
@@ -81,7 +81,7 @@ def readfromstore(self, text):
 
 return (text, True)
 
-def writetostore(self, text):
+def writetostore(orig, self, text):
 # hg filelog metadata (includes rename, etc)
 hgmeta, offset = storageutil.parsemeta(text)
 if offset and offset > 0:
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -763,6 +763,9 @@ def resolverevlogstorevfsoptions(ui, req
 if r.startswith(b'exp-compression-'):
 options[b'compengine'] = r[len(b'exp-compression-'):]
 
+if b'lfs' in requirements:
+options[b'enableextstored'] = True
+
 if repository.NARROW_REQUIREMENT in requirements:
 options[b'enableellipsis'] = True
 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -110,6 +110,26 @@ parsers = policy.importmod(r'parsers')
 REVIDX_ISCENSORED: None,
 }
 
+# Flag processors for REVIDX_EXTSTORED.
+def extstoredreadprocessor(rl, text):
+raise error.ProgrammingError(b'extstored flags processor enabled without'
+ b' wrapping processor function')
+
+def extstoredwriteprocessor(rl, text):
+raise error.ProgrammingError(b'extstored flags processor enabled without'
+ b' wrapping processor function')
+
+def extstoredrawprocessor(rl, text):
+raise error.ProgrammingError(b'extstored flags processor enabled without'
+ b' wrapping processor function')
+
+# Lambdas are needed here so that these methods can be wrapped by lfs.
+extstoredprocessor = (
+lambda rl, text: extstoredreadprocessor(rl, text),
+lambda rl, text: extstoredwriteprocessor(rl, text),
+lambda rl, text: extstoredrawprocessor(rl, text),
+)
+
 # Flag processors for REVIDX_ELLIPSIS.
 def ellipsisreadprocessor(rl, text):
 return text, False
@@ -405,6 +425,8 @@ class revlog(object):
 self._srdensitythreshold = 
opts['sparse-read-density-threshold']
 if 'sparse-read-min-gap-size' in opts:
 self._srmingapsize = opts['sparse-read-min-gap-size']
+if opts.get('enableextstored'):
+self._flagprocessors[REVIDX_EXTSTORED] = extstoredprocessor
 if opts.get('enableellipsis'):
 

D4713: largefiles: automatically load largefiles extension when required (BC)

2018-10-03 Thread mharbison72 (Matt Harbison)
mharbison72 added a comment.


  In https://phab.mercurial-scm.org/D4713#73260, @yuja wrote:
  
  > IIUC, we would have to enable the largefiles extension once to clone the
  >  repo, but that's no longer needed. So you can enable the extension without
  >  hearing its name at all.
  >
  > Perhaps, a warning can be displayed when the non-core repository requirement
  >  is added?
  
  
  I'll take a look and see what I can figure out, but it likely won't be until 
next week.  I think it should maybe be limited to a clone/unbundle adding a 
requirement with an implicitly loaded extension.

REPOSITORY
  rHG Mercurial

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

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


D4860: repository: define and use revision flag constants

2018-10-03 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> changegroups.txt:139-142
> +8192
> +   Externally stored. The revision fulltext contains ``key:value`` ``\n``
> +   delimited metadata defining an object stored elsewhere. Used by the LFS
> +   extension.

Add a TODO about removing this flag from the changegroup? Can be done in a 
followup. I'm also not sure if this is the right place for a TODO. Maybe it 
should be in repository.py?

REPOSITORY
  rHG Mercurial

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

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


D4858: httppeer: report http statistics

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG393e44324037: httppeer: report http statistics (authored by 
indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4858?vs=11636=11665

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

AFFECTED FILES
  mercurial/httppeer.py
  mercurial/url.py
  tests/test-clone-uncompressed.t
  tests/test-clonebundles.t
  tests/test-http-api-httpv2.t
  tests/test-http-protocol.t
  tests/test-lfs-serve-access.t
  tests/test-lfs-serve.t
  tests/test-schemes.t
  tests/test-stream-bundle-v2.t
  tests/test-wireproto-caching.t
  tests/test-wireproto-command-branchmap.t
  tests/test-wireproto-command-capabilities.t
  tests/test-wireproto-command-changesetdata.t
  tests/test-wireproto-command-filedata.t
  tests/test-wireproto-command-heads.t
  tests/test-wireproto-command-known.t
  tests/test-wireproto-command-listkeys.t
  tests/test-wireproto-command-lookup.t
  tests/test-wireproto-command-manifestdata.t
  tests/test-wireproto-command-pushkey.t
  tests/test-wireproto-content-redirects.t
  tests/test-wireproto-exchangev2.t

CHANGE DETAILS

diff --git a/tests/test-wireproto-exchangev2.t 
b/tests/test-wireproto-exchangev2.t
--- a/tests/test-wireproto-exchangev2.t
+++ b/tests/test-wireproto-exchangev2.t
@@ -130,6 +130,7 @@
   received frame(size=0; request=3; stream=2; streamflags=; 
type=command-response; flags=eos)
   updating the branch cache
   new changesets 3390ef850073:caa2a465451d (3 drafts)
+  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
 
 All changesets should have been transferred
 
@@ -256,6 +257,7 @@
   received frame(size=0; request=3; stream=2; streamflags=; 
type=command-response; flags=eos)
   updating the branch cache
   new changesets 3390ef850073:4432d83626e8
+  (sent 6 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ cd client-singlehead
 
@@ -369,6 +371,7 @@
   updating the branch cache
   new changesets cd2534766bec:caa2a465451d (3 drafts)
   (run 'hg update' to get a working copy)
+  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ hg log -G -T '{rev} {node} {phase}\n'
   o  4 caa2a465451dd1facda0f5b12312c355584188a1 draft
@@ -439,6 +442,7 @@
   checking for updated bookmarks
   2 local changesets published
   (run 'hg update' to get a working copy)
+  (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ hg log -G -T '{rev} {node} {phase}\n'
   o  4 caa2a465451dd1facda0f5b12312c355584188a1 public
@@ -555,6 +559,7 @@
   received frame(size=0; request=3; stream=2; streamflags=; 
type=command-response; flags=eos)
   updating the branch cache
   new changesets 3390ef850073:caa2a465451d (1 drafts)
+  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ hg -R client-bookmarks bookmarks
  book-10:3390ef850073
@@ -611,6 +616,7 @@
   checking for updated bookmarks
   updating bookmark book-1
   (run 'hg update' to get a working copy)
+  (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ hg -R client-bookmarks bookmarks
  book-12:cd2534766bec
diff --git a/tests/test-wireproto-content-redirects.t 
b/tests/test-wireproto-content-redirects.t
--- a/tests/test-wireproto-content-redirects.t
+++ b/tests/test-wireproto-content-redirects.t
@@ -317,6 +317,7 @@
   }
 }
   ]
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
 Unknown protocol is filtered from compatible targets
 
@@ -610,6 +611,7 @@
   }
 }
   ]
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
 Missing SNI support filters targets that require SNI
 
@@ -901,6 +903,7 @@
   }
 }
   ]
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ cat >> $HGRCPATH << EOF
   > [extensions]
@@ -1191,6 +1194,7 @@
   }
 }
   ]
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
 Set up the server to issue content redirects to its built-in API server.
 
@@ -1279,6 +1283,7 @@
   ]
 }
   ]
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
 Cached entry should be available on server
 
@@ -1381,6 +1386,7 @@
   ]
 }
   ]
+  (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ cat error.log
   $ killdaemons.py
diff --git a/tests/test-wireproto-command-pushkey.t 
b/tests/test-wireproto-command-pushkey.t
--- a/tests/test-wireproto-command-pushkey.t
+++ b/tests/test-wireproto-command-pushkey.t
@@ -63,6 +63,7 @@
   s> \r\n
   received frame(size=0; request=1; stream=2; streamflags=; 
type=command-response; flags=eos)
   response: True
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ sendhttpv2peer << EOF
   > command listkeys
@@ -105,5 +106,6 @@
   response: {
 b'@': 

D4859: exchangev2: add progress bar around manifest scanning

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG7a347d362a45: exchangev2: add progress bar around manifest 
scanning (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4859?vs=11655=11666

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

AFFECTED FILES
  mercurial/exchangev2.py

CHANGE DETAILS

diff --git a/mercurial/exchangev2.py b/mercurial/exchangev2.py
--- a/mercurial/exchangev2.py
+++ b/mercurial/exchangev2.py
@@ -320,19 +320,25 @@
 ml = repo.manifestlog
 fnodes = collections.defaultdict(dict)
 
-for manifestnode in manifestnodes:
-m = ml.get(b'', manifestnode)
+progress = repo.ui.makeprogress(
+_('scanning manifests'), total=len(manifestnodes))
+
+with progress:
+for manifestnode in manifestnodes:
+m = ml.get(b'', manifestnode)
 
-# TODO this will pull in unwanted nodes because it takes the storage
-# delta into consideration. What we really want is something that takes
-# the delta between the manifest's parents. And ideally we would
-# ignore file nodes that are known locally. For now, ignore both
-# these limitations. This will result in incremental fetches requesting
-# data we already have. So this is far from ideal.
-md = m.readfast()
+# TODO this will pull in unwanted nodes because it takes the 
storage
+# delta into consideration. What we really want is something that
+# takes the delta between the manifest's parents. And ideally we
+# would ignore file nodes that are known locally. For now, ignore
+# both these limitations. This will result in incremental fetches
+# requesting data we already have. So this is far from ideal.
+md = m.readfast()
 
-for path, fnode in md.items():
-fnodes[path].setdefault(fnode, manifestnode)
+for path, fnode in md.items():
+fnodes[path].setdefault(fnode, manifestnode)
+
+progress.increment()
 
 return fnodes
 



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


D4857: keepalive: track number of bytes received from an HTTP response

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG5e5b06087ec5: keepalive: track number of bytes received 
from an HTTP response (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4857?vs=11635=11664

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

AFFECTED FILES
  mercurial/keepalive.py

CHANGE DETAILS

diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -392,6 +392,7 @@
   method=method, **extrakw)
 self.fileno = sock.fileno
 self.code = None
+self.receivedbytescount = 0
 self._rbuf = ''
 self._rbufsize = 8096
 self._handler = None # inserted by the handler later
@@ -436,7 +437,16 @@
 # if it's not empty.
 s = self._rbuf
 self._rbuf = ''
-s += self._raw_read(amt)
+data = self._raw_read(amt)
+
+self.receivedbytescount += len(data)
+self._connection.receivedbytescount += len(data)
+try:
+self._handler.parent.receivedbytescount += len(data)
+except AttributeError:
+pass
+
+s += data
 return s
 
 # stolen from Python SVN #68532 to fix issue1088
@@ -512,6 +522,13 @@
 if not new:
 break
 
+self.receivedbytescount += len(new)
+self._connection.receivedbytescount += len(new)
+try:
+self._handler.parent.receivedbytescount += len(new)
+except AttributeError:
+pass
+
 chunks.append(new)
 i = new.find('\n')
 if i >= 0:
@@ -557,6 +574,14 @@
 return total
 mv = memoryview(dest)
 got = self._raw_readinto(mv[have:total])
+
+self.receivedbytescount += got
+self._connection.receivedbytescount += got
+try:
+self._handler.receivedbytescount += got
+except AttributeError:
+pass
+
 dest[0:have] = self._rbuf
 got += len(self._rbuf)
 self._rbuf = ''
@@ -643,6 +668,7 @@
 def __init__(self, *args, **kwargs):
 httplib.HTTPConnection.__init__(self, *args, **kwargs)
 self.sentbytescount = 0
+self.receivedbytescount = 0
 
 #
 #   TEST FUNCTIONS



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


D4856: keepalive: track request count and bytes sent

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGdc82ad1b7f77: keepalive: track request count and bytes sent 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4856?vs=11634=11663

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

AFFECTED FILES
  mercurial/keepalive.py

CHANGE DETAILS

diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -174,6 +174,8 @@
 class KeepAliveHandler(object):
 def __init__(self):
 self._cm = ConnectionManager()
+self.requestscount = 0
+self.sentbytescount = 0
 
  Connection Management
 def open_connections(self):
@@ -312,6 +314,8 @@
 return r
 
 def _start_transaction(self, h, req):
+oldbytescount = h.sentbytescount
+
 # What follows mostly reimplements HTTPConnection.request()
 # except it adds self.parent.addheaders in the mix and sends headers
 # in a deterministic order (to make testing easier).
@@ -346,6 +350,16 @@
 if urllibcompat.hasdata(req):
 h.send(data)
 
+# This will fail to record events in case of I/O failure. That's OK.
+self.requestscount += 1
+self.sentbytescount += h.sentbytescount - oldbytescount
+
+try:
+self.parent.requestscount += 1
+self.parent.sentbytescount += h.sentbytescount - oldbytescount
+except AttributeError:
+pass
+
 class HTTPHandler(KeepAliveHandler, urlreq.httphandler):
 pass
 
@@ -585,9 +599,11 @@
 data = read(blocksize)
 while data:
 self.sock.sendall(data)
+self.sentbytescount += len(data)
 data = read(blocksize)
 else:
 self.sock.sendall(str)
+self.sentbytescount += len(str)
 except socket.error as v:
 reraise = True
 if v[0] == errno.EPIPE:  # Broken pipe
@@ -624,6 +640,9 @@
 send = safesend
 getresponse = wrapgetresponse(httplib.HTTPConnection)
 
+def __init__(self, *args, **kwargs):
+httplib.HTTPConnection.__init__(self, *args, **kwargs)
+self.sentbytescount = 0
 
 #
 #   TEST FUNCTIONS



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


D4855: url: have httpsconnection inherit from our custom HTTPConnection

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGf2dffa1359c6: url: have httpsconnection inherit from our 
custom HTTPConnection (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4855?vs=11633=11662

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

AFFECTED FILES
  mercurial/keepalive.py
  mercurial/url.py

CHANGE DETAILS

diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -339,16 +339,16 @@
 return logginghttpconnection(createconnection, *args, **kwargs)
 
 if has_https:
-class httpsconnection(httplib.HTTPConnection):
+class httpsconnection(keepalive.HTTPConnection):
 response_class = keepalive.HTTPResponse
 default_port = httplib.HTTPS_PORT
 # must be able to send big bundle as stream.
 send = _gen_sendfile(keepalive.safesend)
 getresponse = keepalive.wrapgetresponse(httplib.HTTPConnection)
 
 def __init__(self, host, port=None, key_file=None, cert_file=None,
  *args, **kwargs):
-httplib.HTTPConnection.__init__(self, host, port, *args, **kwargs)
+keepalive.HTTPConnection.__init__(self, host, port, *args, 
**kwargs)
 self.key_file = key_file
 self.cert_file = cert_file
 
diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -615,6 +615,10 @@
 return safegetresponse
 
 class HTTPConnection(httplib.HTTPConnection):
+# url.httpsconnection inherits from this. So when adding/removing
+# attributes, be sure to audit httpsconnection() for unintended
+# consequences.
+
 # use the modified response class
 response_class = HTTPResponse
 send = safesend



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


D4854: cborutil: change buffering strategy

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG62160d3077cd: cborutil: change buffering strategy (authored 
by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4854?vs=11632=11661

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

AFFECTED FILES
  mercurial/utils/cborutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/cborutil.py b/mercurial/utils/cborutil.py
--- a/mercurial/utils/cborutil.py
+++ b/mercurial/utils/cborutil.py
@@ -913,7 +913,8 @@
 """
 def __init__(self):
 self._decoder = sansiodecoder()
-self._leftover = None
+self._chunks = []
+self._wanted = 0
 
 def decode(self, b):
 """Attempt to decode bytes to CBOR values.
@@ -924,19 +925,40 @@
 * Integer number of bytes decoded from the new input.
 * Integer number of bytes wanted to decode the next value.
 """
+# Our strategy for buffering is to aggregate the incoming chunks in a
+# list until we've received enough data to decode the next item.
+# This is slightly more complicated than using an ``io.BytesIO``
+# or continuously concatenating incoming data. However, because it
+# isn't constantly reallocating backing memory for a growing buffer,
+# it prevents excessive memory thrashing and is significantly faster,
+# especially in cases where the percentage of input chunks that don't
+# decode into a full item is high.
 
-if self._leftover:
-oldlen = len(self._leftover)
-b = self._leftover + b
-self._leftover = None
+if self._chunks:
+# A previous call said we needed N bytes to decode the next item.
+# But this call doesn't provide enough data. We buffer the incoming
+# chunk without attempting to decode.
+if len(b) < self._wanted:
+self._chunks.append(b)
+self._wanted -= len(b)
+return False, 0, self._wanted
+
+# Else we may have enough data to decode the next item. Aggregate
+# old data with new and reset the buffer.
+newlen = len(b)
+self._chunks.append(b)
+b = b''.join(self._chunks)
+self._chunks = []
+oldlen = len(b) - newlen
+
 else:
-b = b
 oldlen = 0
 
 available, readcount, wanted = self._decoder.decode(b)
+self._wanted = wanted
 
 if readcount < len(b):
-self._leftover = b[readcount:]
+self._chunks.append(b[readcount:])
 
 return available, readcount - oldlen, wanted
 



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


D4876: amend: add config to skip amend if only date is changed (issue5828)

2018-10-03 Thread Zharaskhan (Zharaskhan)
Zharaskhan created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  When --date flag specified with `hg amend` and working copy is clean,
  `hg amend` amends, which is generally undesirable behavior.
  But it is commonly used to change date on each amend.
  I added experimental.amend.dateonly config option to not amend
  if only thing that changed is date.
  I also added tests for this.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/configitems.py
  tests/test-amend.t

CHANGE DETAILS

diff --git a/tests/test-amend.t b/tests/test-amend.t
--- a/tests/test-amend.t
+++ b/tests/test-amend.t
@@ -365,3 +365,40 @@
   $ hg amend
 
 #endif
+
+  $ hg status
+  $ hg diff
+  $ hg amend --date '1980-1-1 0:1'
+  $ hg export
+  # HG changeset patch
+  # User test
+  # Date 315532860 0
+  #  Tue Jan 01 00:01:00 1980 +
+  # Node ID 67c8ed970566d909b4759ad6db6048ea9080743b
+  # Parent  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+  b
+  
+  diff --git a/b b/b
+  new file mode 100644
+  --- /dev/null
+  +++ b/b
+  @@ -0,0 +1,1 @@
+  +fixed
+  $ hg amend --date '1990-1-1 0:1' --config experimental.amend.dateonly=True
+  nothing changed
+  [1]
+  $ hg export
+  # HG changeset patch
+  # User test
+  # Date 315532860 0
+  #  Tue Jan 01 00:01:00 1980 +
+  # Node ID 67c8ed970566d909b4759ad6db6048ea9080743b
+  # Parent  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+  b
+  
+  diff --git a/b b/b
+  new file mode 100644
+  --- /dev/null
+  +++ b/b
+  @@ -0,0 +1,1 @@
+  +fixed
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -437,6 +437,9 @@
 coreconfigitem('email', 'to',
 default=None,
 )
+coreconfigitem('experimental', 'amend.dateonly',
+default=False,
+)
 coreconfigitem('experimental', 'archivemetatemplate',
 default=dynamicdefault,
 )
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -2558,13 +2558,17 @@
 if ((not changes)
 and newdesc == old.description()
 and user == old.user()
-and date == old.date()
 and pureextra == old.extra()):
-# nothing changed. continuing here would create a new node
-# anyway because of the amend_source noise.
-#
-# This not what we expect from amend.
-return old.node()
+
+# If the date is same or
+# the user doesn't want to create a date only change amend
+if date == old.date() or ui.configbool('experimental',
+   'amend.dateonly'):
+# nothing changed. continuing here would create a new node
+# anyway because of the amend_source noise.
+#
+# This not what we expect from amend.
+return old.node()
 
 commitphase = None
 if opts.get('secret'):



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


D4875: treemanifests: remove _loadalllazy when doing copies

2018-10-03 Thread spectral (Kyle Lippincott)
spectral created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  'before' here is https://phab.mercurial-scm.org/D4845 (not the 
committed/rebased
  version)
  
diff --git:
repo  | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before
--+---+---++---+
m-u   |   |   | 1.329 s +-  0.011 s| 1.320 s +-  0.010 s   |  99.3%
m-u   |   | x | 1.316 s +-  0.005 s| 1.334 s +-  0.018 s   | 101.4%
m-u   | x |   | 1.330 s +-  0.021 s| 1.322 s +-  0.005 s   |  99.4%
m-u   | x | x | 87.2 ms +-   0.7 ms| 86.9 ms +-   1.5 ms   |  99.7%
l-d-r |   |   | 203.3 ms +-   7.8 ms   | 199.4 ms +-   1.8 ms  |  98.1%
l-d-r |   | x | 204.6 ms +-   2.8 ms   | 201.7 ms +-   2.1 ms  |  98.6%
l-d-r | x |   | 90.5 ms +-  11.0 ms| 86.2 ms +-   1.0 ms   |  95.2%
l-d-r | x | x | 66.3 ms +-   2.0 ms| 66.4 ms +-   0.9 ms   | 100.2%

diff -c . --git:
repo  | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before
--+---+---++---+
m-u   |   |   | 239.4 ms +-   2.0 ms   | 241.7 ms +-   4.6 ms  | 101.0%
m-u   |   | x | 128.9 ms +-   1.9 ms   | 130.9 ms +-   7.7 ms  | 101.6%
m-u   | x |   | 241.1 ms +-   1.6 ms   | 240.1 ms +-   1.4 ms  |  99.6%
m-u   | x | x | 133.4 ms +-   1.5 ms   | 133.4 ms +-   1.2 ms  | 100.0%
l-d-r |   |   | 84.3 ms +-   1.5 ms| 83.5 ms +-   1.0 ms   |  99.1%
l-d-r |   | x | 200.9 ms +-   6.3 ms   | 203.0 ms +-   4.4 ms  | 101.0%
l-d-r | x |   | 108.1 ms +-   1.4 ms   | 108.7 ms +-   2.1 ms  | 100.6%
l-d-r | x | x | 190.2 ms +-   4.8 ms   | 191.6 ms +-   2.0 ms  | 100.7%

rebase -r . --keep -d .^^:
repo  | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before
--+---+---++---+
m-u   |   |   | 5.655 s +-  0.029 s| 5.640 s +-  0.036 s   |  99.7%
m-u   |   | x | 5.813 s +-  0.038 s| 5.773 s +-  0.028 s   |  99.3%
m-u   | x |   | 5.593 s +-  0.043 s| 5.589 s +-  0.028 s   |  99.9%
m-u   | x | x | 648.2 ms +-  19.2 ms   | 637.3 ms +-  27.7 ms  |  98.3%
l-d-r |   |   | 673.3 ms +-   8.0 ms   | 673.2 ms +-   6.8 ms  | 100.0%
l-d-r |   | x | 6.583 s +-  0.030 s| 5.721 s +-  0.028 s   |  86.9% <--
l-d-r | x |   | 277.8 ms +-   6.7 ms   | 276.0 ms +-   2.7 ms  |  99.4%
l-d-r | x | x | 1.692 s +-  0.013 s| 720.9 ms +-  13.3 ms  |  42.6% <--

status --change . --copies:
repo  | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before
--+---+---++---+
m-u   |   |   | 220.9 ms +-   1.6 ms   | 219.9 ms +-   2.2 ms  |  99.5%
m-u   |   | x | 109.2 ms +-   1.0 ms   | 109.4 ms +-   0.8 ms  | 100.2%
m-u   | x |   | 222.6 ms +-   1.7 ms   | 221.4 ms +-   2.1 ms  |  99.5%
m-u   | x | x | 113.4 ms +-   0.5 ms   | 113.1 ms +-   1.1 ms  |  99.7%
l-d-r |   |   | 82.1 ms +-   1.7 ms| 82.1 ms +-   1.2 ms   | 100.0%
l-d-r |   | x | 199.8 ms +-   4.0 ms   | 200.7 ms +-   3.6 ms  | 100.5%
l-d-r | x |   | 85.4 ms +-   1.5 ms| 85.2 ms +-   0.3 ms   |  99.8%
l-d-r | x | x | 202.6 ms +-   4.4 ms   | 208.0 ms +-   4.0 ms  | 102.7%

status --copies:
repo  | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before
--+---+---++---+
m-u   |   |   | 1.941 s +-  0.014 s| 1.930 s +-  0.009 s   |  99.4%
m-u   |   | x | 1.924 s +-  0.007 s| 1.950 s +-  0.010 s   | 101.4%
m-u   | x |   | 1.959 s +-  0.085 s| 1.926 s +-  0.009 s   |  98.3%
m-u   | x | x | 96.2 ms +-   1.0 ms| 96.4 ms +-   0.7 ms   | 100.2%
l-d-r |   |   | 604.4 ms +-  10.6 ms   | 602.6 ms +-   7.1 ms  |  99.7%
l-d-r |   | x | 605.7 ms +-   4.1 ms   | 607.4 ms +-   6.1 ms  | 100.3%
l-d-r | x |   | 182.4 ms +-   1.2 ms   | 183.4 ms +-   1.2 ms  | 100.5%
l-d-r | x | x | 150.8 ms +-   2.0 ms   | 150.6 ms +-   1.0 ms  |  99.9%

update $rev^; ~/src/hg/hg{hg}/hg update $rev:
repo  | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before
--+---+---++---+
m-u   |   |   | 3.185 s +-  0.027 s| 3.181 s +-  0.017 s   |  99.9%
m-u   |   | x | 3.028 s +-  0.021 s| 2.954 s +-  0.010 s   |  97.6%
m-u   | x |   | 3.168 s +-  0.010 s| 3.175 s +-  0.023 s   | 100.2%
m-u   | x | x | 317.5 ms +-   3.5 ms   | 313.2 ms +-   2.9 ms  |  98.6%
l-d-r |   |   | 456.2 ms +-  10.6 ms   | 454.4 ms +-   5.8 ms  |  99.6%
l-d-r |   | x | 9.236 s +-  0.063 s| 757.9 ms +-   9.2 ms  |   8.2% <--
l-d-r | x |   | 257.6 ms +-   2.3 ms   | 261.2 ms +-   1.7 ms  | 101.4%
l-d-r | x | 

D4874: treemanifests: store whether a lazydirs entry needs copied after materializing

2018-10-03 Thread spectral (Kyle Lippincott)
spectral created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Due to the way that things like manifestlog.get caches its values, without
  making a copy (if necessary) after calling readsubtree(), we might end up
  adjusting the state of the same object on different contexts, breaking things
  like dirty state tracking (and probably other things).

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/manifest.py

CHANGE DETAILS

diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -701,15 +701,22 @@
 return self._dir + path
 
 def _loadalllazy(self):
-for k, (path, node, readsubtree) in self._lazydirs.iteritems():
-self._dirs[k] = readsubtree(path, node)
+selfdirs = self._dirs
+for d, (path, node, readsubtree, docopy) in self._lazydirs.iteritems():
+if docopy:
+selfdirs[d] = readsubtree(path, node).copy()
+else:
+selfdirs[d] = readsubtree(path, node)
 self._lazydirs = {}
 
 def _loadlazy(self, d):
 v = self._lazydirs.get(d)
 if v:
-path, node, readsubtree = v
-self._dirs[d] = readsubtree(path, node)
+path, node, readsubtree, docopy = v
+if docopy:
+self._dirs[d] = readsubtree(path, node).copy()
+else:
+self._dirs[d] = readsubtree(path, node)
 del self._lazydirs[d]
 
 def _loadchildrensetlazy(self, visit):
@@ -1170,7 +1177,9 @@
 for f, n, fl in _parse(text):
 if fl == 't':
 f = f + '/'
-selflazy[f] = (subpath(f), n, readsubtree)
+# False below means "doesn't need to be copied" and can use the
+# cached value from readsubtree directly.
+selflazy[f] = (subpath(f), n, readsubtree, False)
 elif '/' in f:
 # This is a flat manifest, so use __setitem__ and setflag 
rather
 # than assigning directly to _files and _flags, so we can
@@ -1197,8 +1206,7 @@
 """
 self._load()
 flags = self.flags
-lazydirs = [(d[:-1], node, 't') for
-d, (path, node, readsubtree) in self._lazydirs.iteritems()]
+lazydirs = [(d[:-1], v[1], 't') for d, v in self._lazydirs.iteritems()]
 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
 files = [(f, self._files[f], flags(f)) for f in self._files]
 return _text(sorted(dirs + files + lazydirs))



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


D4873: treemanifests: extract _loaddifflazy from _diff, use in _filesnotin

2018-10-03 Thread spectral (Kyle Lippincott)
spectral created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/manifest.py

CHANGE DETAILS

diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -724,6 +724,28 @@
 loadlazy(k + '/')
 return visit
 
+def _loaddifflazy(self, t1, t2):
+"""load items in t1 and t2 if they're needed for diffing.
+
+The criteria currently is:
+- if it's not present in _lazydirs in either t1 or t2, load it in the
+  other (it may already be loaded or it may not exist, doesn't matter)
+- if it's present in _lazydirs in both, compare the nodeid; if it
+  differs, load it in both
+"""
+toloadlazy = []
+for d, v1 in t1._lazydirs.iteritems():
+v2 = t2._lazydirs.get(d)
+if not v2 or v2[1] != v1[1]:
+toloadlazy.append(d)
+for d, v1 in t2._lazydirs.iteritems():
+if d not in t1._lazydirs:
+toloadlazy.append(d)
+
+for d in toloadlazy:
+t1._loadlazy(d)
+t2._loadlazy(d)
+
 def __len__(self):
 self._load()
 size = len(self._files)
@@ -957,8 +979,7 @@
 return
 t1._load()
 t2._load()
-t1._loadalllazy()
-t2._loadalllazy()
+self._loaddifflazy(t1, t2)
 for d, m1 in t1._dirs.iteritems():
 if d in t2._dirs:
 m2 = t2._dirs[d]
@@ -1113,18 +1134,7 @@
 return
 t1._load()
 t2._load()
-toloadlazy = []
-for d, v1 in t1._lazydirs.iteritems():
-v2 = t2._lazydirs.get(d)
-if not v2 or v2[1] != v1[1]:
-toloadlazy.append(d)
-for d, v1 in t2._lazydirs.iteritems():
-if d not in t1._lazydirs:
-toloadlazy.append(d)
-
-for d in toloadlazy:
-t1._loadlazy(d)
-t2._loadlazy(d)
+self._loaddifflazy(t1, t2)
 
 for d, m1 in t1._dirs.iteritems():
 m2 = t2._dirs.get(d, emptytree)



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


D4872: identify: show remote bookmarks in `hg id url -Tjson -B`

2018-10-03 Thread valentin.gatienbaron (Valentin Gatien-Baron)
valentin.gatienbaron created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  I didn't display bookmarks when `default and not ui.quiet`: it seems
  strange for templates to depend on --id or -q, and it would take more
  code for `hg id url -T {node}` to not request remote bookmarks.
  
  An alternative I thought of was providing lazy data to the formatter,
  `fm.data(bookmarks=lambda: fm.formatlist(getbms(), name='bookmark'))`.
  The plainformatter would naturally not compute it, the
  templateformatter would compute only what it needs, and the other ones
  would compute everything, but that's not supported (or I don't see
  how), so I abandoned this idea.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/commands.py

CHANGE DETAILS

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -3044,7 +3044,7 @@
 output.append(bm)
 else:
 fm.data(node=hex(remoterev))
-if 'bookmarks' in fm.datahint():
+if bookmarks or 'bookmarks' in fm.datahint():
 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
 else:
 if rev:



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


D4859: exchangev2: add progress bar around manifest scanning

2018-10-03 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 11655.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4859?vs=11651=11655

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

AFFECTED FILES
  mercurial/exchangev2.py

CHANGE DETAILS

diff --git a/mercurial/exchangev2.py b/mercurial/exchangev2.py
--- a/mercurial/exchangev2.py
+++ b/mercurial/exchangev2.py
@@ -320,19 +320,25 @@
 ml = repo.manifestlog
 fnodes = collections.defaultdict(dict)
 
-for manifestnode in manifestnodes:
-m = ml.get(b'', manifestnode)
+progress = repo.ui.makeprogress(
+_('scanning manifests'), total=len(manifestnodes))
+
+with progress:
+for manifestnode in manifestnodes:
+m = ml.get(b'', manifestnode)
 
-# TODO this will pull in unwanted nodes because it takes the storage
-# delta into consideration. What we really want is something that takes
-# the delta between the manifest's parents. And ideally we would
-# ignore file nodes that are known locally. For now, ignore both
-# these limitations. This will result in incremental fetches requesting
-# data we already have. So this is far from ideal.
-md = m.readfast()
+# TODO this will pull in unwanted nodes because it takes the 
storage
+# delta into consideration. What we really want is something that
+# takes the delta between the manifest's parents. And ideally we
+# would ignore file nodes that are known locally. For now, ignore
+# both these limitations. This will result in incremental fetches
+# requesting data we already have. So this is far from ideal.
+md = m.readfast()
 
-for path, fnode in md.items():
-fnodes[path].setdefault(fnode, manifestnode)
+for path, fnode in md.items():
+fnodes[path].setdefault(fnode, manifestnode)
+
+progress.increment()
 
 return fnodes
 



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


D4870: showstack: also handle SIGALRM

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

REVISION SUMMARY
  This is looking *very* handy when debugging mysterious hangs in a
  test: you can wrap a hanging invocation in
  
`perl -e 'alarm shift @ARGV; exec @ARGV' 1`
  
  for example, a hanging `hg pull` becomes
  
`perl -e 'alarm shift @ARGV; exec @ARGV' 1 hg pull`
  
  where the `1` is the timeout in seconds before the process will be hit
  with SIGALRM. After making that edit to the test file, you can then
  use --extra-config-opt on run-tests.py to globaly enable showstack
  during the test run, so you'll get full stack traces as you force your
  hg to exit.
  
  I wonder (but only a little, not enough to take action just yet) if we
  should wire up some scaffolding in run-tests itself to automatically
  wrap all commands in alarm(3) somehow to avoid hangs in the future?

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  contrib/showstack.py

CHANGE DETAILS

diff --git a/contrib/showstack.py b/contrib/showstack.py
--- a/contrib/showstack.py
+++ b/contrib/showstack.py
@@ -4,7 +4,7 @@
 """dump stack trace when receiving SIGQUIT (Ctrl-\) and SIGINFO (Ctrl-T on 
BSDs)
 """
 
-from __future__ import absolute_import
+from __future__ import absolute_import, print_function
 import signal
 import sys
 import traceback
@@ -14,8 +14,14 @@
 traceback.print_stack(args[1], limit=10, file=sys.stderr)
 sys.stderr.write("\n")
 
+def sigexit(*args):
+sigshow(*args)
+print('alarm!')
+sys.exit(1)
+
 def extsetup(ui):
 signal.signal(signal.SIGQUIT, sigshow)
+signal.signal(signal.SIGALRM, sigexit)
 try:
 signal.signal(signal.SIGINFO, sigshow)
 except AttributeError:



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


D4860: repository: define and use revision flag constants

2018-10-03 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 11652.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4860?vs=11638=11652

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

AFFECTED FILES
  mercurial/changegroup.py
  mercurial/help/internals/changegroups.txt
  mercurial/repository.py
  mercurial/revlogutils/constants.py
  mercurial/testing/storage.py
  tests/simplestorerepo.py
  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
@@ -1038,8 +1038,8 @@
   
   There are 3 versions of changegroups: "1", "2", and "3". From a high-
   level, versions "1" and "2" are almost exactly the same, with the only
-  difference being an additional item in the *delta header*.  Version "3"
-  adds support for revlog flags in the *delta header* and optionally
+  difference being an additional item in the *delta header*. Version "3"
+  adds support for storage flags in the *delta header* and optionally
   exchanging treemanifests (enabled by setting an option on the
   "changegroup" part in the bundle2).
   
@@ -1162,6 +1162,27 @@
   changegroup. This allows the delta to be expressed against any parent,
   which can result in smaller deltas and more efficient encoding of data.
   
+  The *flags* field holds bitwise flags affecting the processing of 
revision
+  data. The following flags are defined:
+  
+  32768
+ Censored revision. The revision's fulltext has been replaced by censor
+ metadata. May only occur on file revisions.
+  
+  16384
+ Ellipsis revision. Revision hash does not match data (likely due to
+ rewritten parents).
+  
+  8192
+ Externally stored. The revision fulltext contains "key:value" "\n"
+ delimited metadata defining an object stored elsewhere. Used by the 
LFS
+ extension.
+  
+  For historical reasons, the integer values are identical to revlog 
version
+  1 per-revision storage flags and correspond to bits being set in this
+  2-byte field. Bits were allocated starting from the most-significant bit,
+  hence the reverse ordering and allocation of these flags.
+  
   Changeset Segment
   =
   
@@ -3435,8 +3456,8 @@
   
   There are 3 versions of changegroups: 1, 2, and 
3. From a
   high-level, versions 1 and 2 are almost exactly the 
same, with the
-  only difference being an additional item in the *delta header*.  Version
-  3 adds support for revlog flags in the *delta header* and 
optionally
+  only difference being an additional item in the *delta header*. Version
+  3 adds support for storage flags in the *delta header* and 
optionally
   exchanging treemanifests (enabled by setting an option on the
   changegroup part in the bundle2).
   
@@ -3582,6 +3603,24 @@
   changegroup. This allows the delta to be expressed against any parent,
   which can result in smaller deltas and more efficient encoding of data.
   
+  
+  The *flags* field holds bitwise flags affecting the processing of revision
+  data. The following flags are defined:
+  
+  
+   32768
+   Censored revision. The revision's fulltext has been replaced by censor 
metadata. May only occur on file revisions.
+   16384
+   Ellipsis revision. Revision hash does not match data (likely due to 
rewritten parents).
+   8192
+   Externally stored. The revision fulltext contains key:value 
\n delimited metadata defining an object stored elsewhere. Used by 
the LFS extension.
+  
+  
+  For historical reasons, the integer values are identical to revlog version 1
+  per-revision storage flags and correspond to bits being set in this 2-byte
+  field. Bits were allocated starting from the most-significant bit, hence the
+  reverse ordering and allocation of these flags.
+  
   Changeset Segment
   
   The *changeset segment* consists of a single *delta group* holding
diff --git a/tests/simplestorerepo.py b/tests/simplestorerepo.py
--- a/tests/simplestorerepo.py
+++ b/tests/simplestorerepo.py
@@ -371,7 +371,7 @@
 def iscensored(self, rev):
 validaterev(rev)
 
-return self._flags(rev) & revlog.REVIDX_ISCENSORED
+return self._flags(rev) & repository.REVISION_FLAG_CENSORED
 
 def commonancestorsheads(self, a, b):
 validatenode(a)
diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -17,7 +17,7 @@
 from .. import (
 error,
 mdiff,
-revlog,
+repository,
 )
 from ..utils import (
 storageutil,
@@ -874,7 +874,7 @@
 with self._maketransactionfn() as tr:
 node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
 f.addrevision(stored1, tr, 1, node0, nullid,
-  flags=revlog.REVIDX_ISCENSORED)
+  flags=repository.REVISION_FLAG_CENSORED)
 
 

Re: [PATCH 1 of 8 V3] context: refactor introrev to make the next patch easier to read

2018-10-03 Thread Martin von Zweigbergk via Mercurial-devel
Oh, and thanks for splitting this patch up! I find it much easier to see
what's going on now.

On Wed, Oct 3, 2018 at 12:23 PM Martin von Zweigbergk 
wrote:

>
>
> On Wed, Oct 3, 2018 at 12:15 PM Boris Feld  wrote:
>
>> # HG changeset patch
>> # User Boris Feld 
>> # Date 1538554251 -7200
>> #  Wed Oct 03 10:10:51 2018 +0200
>> # Node ID 68ec0cf339c7e65ee4349f543e3024068fbbe591
>> # Parent  1a4c1a3cc3f5b54de7f56753c0ea8b02b4443958
>> # EXP-Topic copy-perf
>> # Available At https://bitbucket.org/octobus/mercurial-devel/
>> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r
>> 68ec0cf339c7
>> context: refactor introrev to make the next patch easier to read
>>
>> We are about to update the logic for checking if the rev is available in
>> an
>> efficient manner. Refactoring introrev will make the next patch easier to
>> read.
>>
>> diff --git a/mercurial/context.py b/mercurial/context.py
>> --- a/mercurial/context.py
>> +++ b/mercurial/context.py
>> @@ -776,10 +776,15 @@ class basefilectx(object):
>>  """
>>  lkr = self.linkrev()
>>  attrs = vars(self)
>> -noctx = not (r'_changeid' in attrs or r'_changectx' in attrs)
>> -if noctx or self.rev() == lkr:
>> -return self.linkrev()
>> -return self._adjustlinkrev(self.rev(), inclusive=True)
>> +lazyavailable = r'_changeid' in attrs or r'_changectx' in attrs
>> +if lazyavailable:
>> +rev = self.rev()
>> +if rev == lkr:
>> +return rev
>> +else:
>> +return self._adjustlinkrev(rev, inclusive=True)
>> +else:
>> +return self.rev()
>>
>
> For this to be a pure refactoring, shouldn't this be "return
> self.linkrev()"? That's what we used to return when noctx was true.
>
>
>>  def introfilectx(self):
>>  """Return filectx having identical contents, but pointing to the
>> ___
>> 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 1 of 8 V3] context: refactor introrev to make the next patch easier to read

2018-10-03 Thread Martin von Zweigbergk via Mercurial-devel
On Wed, Oct 3, 2018 at 12:15 PM Boris Feld  wrote:

> # HG changeset patch
> # User Boris Feld 
> # Date 1538554251 -7200
> #  Wed Oct 03 10:10:51 2018 +0200
> # Node ID 68ec0cf339c7e65ee4349f543e3024068fbbe591
> # Parent  1a4c1a3cc3f5b54de7f56753c0ea8b02b4443958
> # EXP-Topic copy-perf
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r
> 68ec0cf339c7
> context: refactor introrev to make the next patch easier to read
>
> We are about to update the logic for checking if the rev is available in an
> efficient manner. Refactoring introrev will make the next patch easier to
> read.
>
> diff --git a/mercurial/context.py b/mercurial/context.py
> --- a/mercurial/context.py
> +++ b/mercurial/context.py
> @@ -776,10 +776,15 @@ class basefilectx(object):
>  """
>  lkr = self.linkrev()
>  attrs = vars(self)
> -noctx = not (r'_changeid' in attrs or r'_changectx' in attrs)
> -if noctx or self.rev() == lkr:
> -return self.linkrev()
> -return self._adjustlinkrev(self.rev(), inclusive=True)
> +lazyavailable = r'_changeid' in attrs or r'_changectx' in attrs
> +if lazyavailable:
> +rev = self.rev()
> +if rev == lkr:
> +return rev
> +else:
> +return self._adjustlinkrev(rev, inclusive=True)
> +else:
> +return self.rev()
>

For this to be a pure refactoring, shouldn't this be "return
self.linkrev()"? That's what we used to return when noctx was true.


>  def introfilectx(self):
>  """Return filectx having identical contents, but pointing to the
> ___
> 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


[PATCH 8 of 8 V3] copies: add time information to the debug information

2018-10-03 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1536335028 14400
#  Fri Sep 07 11:43:48 2018 -0400
# Node ID 5780db5f3a36b6450899b21c8fd033a348eee7db
# Parent  2b5e633c984e0341b2606e66cfafc92f27c10876
# EXP-Topic copy-perf
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
5780db5f3a36
copies: add time information to the debug information

diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -204,11 +204,16 @@ def _committedforwardcopies(a, b, match)
 fctx = b[f]
 fctx._ancestrycontext = ancestrycontext
 
+if debug:
+start = util.timer()
 ofctx = _tracefile(fctx, am, limit)
 if ofctx:
 if debug:
 dbg('debug.copies:  rename of: %s\n' % ofctx._path)
 cm[f] = ofctx.path()
+if debug:
+dbg('debug.copies:  time: %s seconds\n'
+% (util.timer() - start))
 return cm
 
 def _forwardcopies(a, b, match=None):
diff --git a/tests/test-mv-cp-st-diff.t b/tests/test-mv-cp-st-diff.t
--- a/tests/test-mv-cp-st-diff.t
+++ b/tests/test-mv-cp-st-diff.t
@@ -1676,6 +1676,7 @@ Check debug output for copy tracing
   debug.copies:  missing file to search: 1
   debug.copies:tracing file: renamed
   debug.copies:  rename of: f
+  debug.copies:  time: * seconds (glob)
   A renamed
 f
   R f
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 7 of 8 V3] copies: add a devel debug mode to trace what copy tracing does

2018-10-03 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 153666 14400
#  Fri Sep 07 11:16:06 2018 -0400
# Node ID 2b5e633c984e0341b2606e66cfafc92f27c10876
# Parent  fd0da35824d09d0a0fa66a23627dd24209c6c3b1
# EXP-Topic copy-perf
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
2b5e633c984e
copies: add a devel debug mode to trace what copy tracing does

Mercurial can spend a lot of time finding renames between two commits. Having
more information about that process help (eg: many files vs 1 file, etc...)

diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -377,6 +377,9 @@ coreconfigitem('devel', 'user.obsmarker'
 coreconfigitem('devel', 'warn-config-unknown',
 default=None,
 )
+coreconfigitem('devel', 'debug.copies',
+default=False,
+)
 coreconfigitem('devel', 'debug.extensions',
 default=False,
 )
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -163,9 +163,17 @@ def _committedforwardcopies(a, b, match)
 """Like _forwardcopies(), but b.rev() cannot be None (working copy)"""
 # files might have to be traced back to the fctx parent of the last
 # one-side-only changeset, but not further back than that
-limit = _findlimit(a._repo, a.rev(), b.rev())
+repo = a._repo
+debug = repo.ui.debugflag and repo.ui.configbool('devel', 'debug.copies')
+dbg = repo.ui.debug
+if debug:
+dbg('debug.copies:looking into rename from %s to %s\n'
+% (a, b))
+limit = _findlimit(repo, a.rev(), b.rev())
 if limit is None:
 limit = -1
+if debug:
+dbg('debug.copies:  search limit: %d\n' % limit)
 am = a.manifest()
 
 # find where new files came from
@@ -186,11 +194,20 @@ def _committedforwardcopies(a, b, match)
 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
 
 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
+
+if debug:
+dbg('debug.copies:  missing file to search: %d\n' % len(missing))
+
 for f in missing:
+if debug:
+dbg('debug.copies:tracing file: %s\n' % f)
 fctx = b[f]
 fctx._ancestrycontext = ancestrycontext
+
 ofctx = _tracefile(fctx, am, limit)
 if ofctx:
+if debug:
+dbg('debug.copies:  rename of: %s\n' % ofctx._path)
 cm[f] = ofctx.path()
 return cm
 
@@ -226,13 +243,24 @@ def _backwardrenames(a, b):
 
 def pathcopies(x, y, match=None):
 """find {dst@y: src@x} copy mapping for directed compare"""
+repo = x._repo
+debug = repo.ui.debugflag and repo.ui.configbool('devel', 'debug.copies')
+if debug:
+repo.ui.debug('debug.copies: searching copies from %s to %s\n'
+  % (x, y))
 if x == y or not x or not y:
 return {}
 a = y.ancestor(x)
 if a == x:
+if debug:
+repo.ui.debug('debug.copies: search mode: forward\n')
 return _forwardcopies(x, y, match=match)
 if a == y:
+if debug:
+repo.ui.debug('debug.copies: search mode: backward\n')
 return _backwardrenames(x, y)
+if debug:
+repo.ui.debug('debug.copies: search mode: combined\n')
 return _chain(x, y, _backwardrenames(x, a),
   _forwardcopies(a, y, match=match))
 
diff --git a/tests/test-mv-cp-st-diff.t b/tests/test-mv-cp-st-diff.t
--- a/tests/test-mv-cp-st-diff.t
+++ b/tests/test-mv-cp-st-diff.t
@@ -1666,4 +1666,18 @@ accessing the parent of 4 (renamed) shou
   @@ -0,0 +1,1 @@
   +change
 
+Check debug output for copy tracing
+
+  $ hg status --copies --rev 'desc(dev)' --rev . --config 
devel.debug.copies=yes --debug
+  debug.copies: searching copies from a51f36ab1704 to 7935fd48a8f9
+  debug.copies: search mode: forward
+  debug.copies:looking into rename from a51f36ab1704 to 7935fd48a8f9
+  debug.copies:  search limit: 2
+  debug.copies:  missing file to search: 1
+  debug.copies:tracing file: renamed
+  debug.copies:  rename of: f
+  A renamed
+f
+  R f
+
   $ cd ..
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 6 of 8 V3] context: floor adjustlinkrev graph walk during copy tracing

2018-10-03 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1536255188 14400
#  Thu Sep 06 13:33:08 2018 -0400
# Node ID fd0da35824d09d0a0fa66a23627dd24209c6c3b1
# Parent  964fbe39ab182eb0d65830dc87ef39d0382a41fa
# EXP-Topic copy-perf
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
fd0da35824d0
context: floor adjustlinkrev graph walk during copy tracing

The `_adjustlinkrev` method gains an optional "stoprev" argument. The linkrev
adjustment will give up once this floor is reached. The relevant functions
using `_adjustlinkrev` are updated to pass an appropriate value in the copy
tracing code.

In some private repository, about 10% of the status call triggered
pathological case addressed by this change. The speedup varies from one call
to another, the best-observed win is moving from 170s to 11s.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -569,7 +569,7 @@ class basefilectx(object):
 def _changeid(self):
 return self._findchangerev()
 
-def _findchangerev(self):
+def _findchangerev(self, stoprev=None):
 if r'_changeid' in self.__dict__:
 changeid = self._changeid
 elif r'_changectx' in self.__dict__:
@@ -577,10 +577,11 @@ class basefilectx(object):
 elif r'_descendantrev' in self.__dict__:
 # this file context was created from a revision with a known
 # descendant, we can (lazily) correct for linkrev aliases
-changeid = self._adjustlinkrev(self._descendantrev)
+changeid = self._adjustlinkrev(self._descendantrev, 
stoprev=stoprev)
 else:
 changeid = self._filelog.linkrev(self._filerev)
-self._changeid = changeid
+if changeid is not None:
+self._changeid = changeid
 return changeid
 
 @propertycache
@@ -724,7 +725,7 @@ class basefilectx(object):
 
 return True
 
-def _adjustlinkrev(self, srcrev, inclusive=False):
+def _adjustlinkrev(self, srcrev, inclusive=False, stoprev=None):
 """return the first ancestor of  introducing 
 
 If the linkrev of the file revision does not point to an ancestor of
@@ -733,6 +734,10 @@ class basefilectx(object):
 
 :srcrev: the changeset revision we search ancestors from
 :inclusive: if true, the src revision will also be checked
+:stoprev: an optional revision to stop the walk at. If no introduction
+  of this file content could be found before this floor
+  revision, the function will returns "None" and stops its
+  iteration.
 """
 repo = self._repo
 cl = repo.unfiltered().changelog
@@ -758,6 +763,8 @@ class basefilectx(object):
 fnode = self._filenode
 path = self._path
 for a in iteranc:
+if stoprev is not None and a < stoprev:
+return None
 ac = cl.read(a) # get changeset data (we avoid object creation)
 if path in ac[3]: # checking the 'files' field.
 # The file has been touched, check if the content is
@@ -773,8 +780,12 @@ class basefilectx(object):
 def isintroducedafter(self, changelogrev):
 """True if a filectx have been introduced after a given floor revision
 """
-return (changelogrev <= self.linkrev()
-or changelogrev <= self._introrev())
+if changelogrev <= self.linkrev():
+return True
+introrev = self._introrev(stoprev=changelogrev)
+if introrev is None:
+return False
+return changelogrev <= introrev
 
 def _lazyrevavailable(self):
 """return True if self.rev() is available without computation,
@@ -804,7 +815,15 @@ class basefilectx(object):
 """
 return self._introrev()
 
-def _introrev(self):
+def _introrev(self, stoprev=None):
+"""
+Same as `introrev` but, with an extra argument to limit changelog
+iteration range in some internal usecase.
+
+If `stoprev` is set, the `introrev` will not be searched past that
+`stoprev` revision and "None" might be returned. This is useful to
+limit iteration range.
+"""
 lkr = self.linkrev()
 attrs = vars(self)
 lazyavailable = self._lazyrevavailable()
@@ -813,9 +832,10 @@ class basefilectx(object):
 if rev == lkr:
 return rev
 else:
-return self._adjustlinkrev(rev, inclusive=True)
+return self._adjustlinkrev(rev, inclusive=True,
+   stoprev=stoprev)
 else:
-return self._findchangerev()
+return self._findchangerev(stoprev=stoprev)
 
 def introfilectx(self):
 """Return filectx having identical contents, but 

[PATCH 4 of 8 V3] context: split `introrev` logic in a sub function

2018-10-03 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1536255508 14400
#  Thu Sep 06 13:38:28 2018 -0400
# Node ID 759af590645e2f0cc6fbed2b7b97ed718e277dc5
# Parent  eb46ac11a9a81400e96ab3db00a38944a864100f
# EXP-Topic copy-perf
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
759af590645e
context: split `introrev` logic in a sub function

We want to add a mechanism to stop iteration early associated to intro rev early
in some case. However, it does not make sense to expose it in the public
`filectx` API. So we split the code into an internal method instead.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -769,7 +769,7 @@ class basefilectx(object):
 """True if a filectx have been introduced after a given floor revision
 """
 return (changelogrev <= self.linkrev()
-or changelogrev <= self.introrev())
+or changelogrev <= self._introrev())
 
 def _lazyrevavailable(self):
 """return True if self.rev() is available without computation,
@@ -797,6 +797,9 @@ class basefilectx(object):
 'linkrev-shadowing' when a file revision is used by multiple
 changesets.
 """
+return self._introrev()
+
+def _introrev(self):
 lkr = self.linkrev()
 attrs = vars(self)
 lazyavailable = self._lazyrevavailable()
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 8 V3] context: introduce an `isintroducedafter` method and use it in copies

2018-10-03 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1536252767 14400
#  Thu Sep 06 12:52:47 2018 -0400
# Node ID eb46ac11a9a81400e96ab3db00a38944a864100f
# Parent  355a69e274a2ec851c6d13cfbbac45f5e197294c
# EXP-Topic copy-perf
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
eb46ac11a9a8
context: introduce an `isintroducedafter` method and use it in copies

Right now, copy tracing make effort to not traverse the graph too much to save
performance. It uses a "limit" acting as a floor revision past which data are no
longer relevant to the current copy tracing.

However, to enforce this limit, it uses a call to `filectx.rev()`, that call can
trigger a graph traversal on its own. That extra graph traversal is oblivious of
the current limit and can become very expensive. That cost is increased by the
nature of work done in adjust link rev, we are not only walking down the graph,
we are also checking the affected file for each revision we walk through.
Something significantly more expensive than the walk itself.

To work around this we need to make the `filectx` operation aware of the current
limit. The first step is to introduce a dedicated method: `isintroducedafter`.
We'll then rework that method logic to stop traversal as soon as possible.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -765,6 +765,12 @@ class basefilectx(object):
 # result is crash somewhere else at to some point.
 return lkr
 
+def isintroducedafter(self, changelogrev):
+"""True if a filectx have been introduced after a given floor revision
+"""
+return (changelogrev <= self.linkrev()
+or changelogrev <= self.introrev())
+
 def _lazyrevavailable(self):
 """return True if self.rev() is available without computation,
 
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -139,7 +139,7 @@ def _tracefile(fctx, am, limit=-1):
 for f in fctx.ancestors():
 if am.get(f.path(), None) == f.filenode():
 return f
-if limit >= 0 and f.linkrev() < limit and f.rev() < limit:
+if limit >= 0 and not f.isintroducedafter(limit):
 return None
 
 def _dirstatecopies(d, match=None):
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 8 V3] context: refactor introrev to make the next patch easier to read

2018-10-03 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1538554251 -7200
#  Wed Oct 03 10:10:51 2018 +0200
# Node ID 68ec0cf339c7e65ee4349f543e3024068fbbe591
# Parent  1a4c1a3cc3f5b54de7f56753c0ea8b02b4443958
# EXP-Topic copy-perf
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
68ec0cf339c7
context: refactor introrev to make the next patch easier to read

We are about to update the logic for checking if the rev is available in an
efficient manner. Refactoring introrev will make the next patch easier to
read.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -776,10 +776,15 @@ class basefilectx(object):
 """
 lkr = self.linkrev()
 attrs = vars(self)
-noctx = not (r'_changeid' in attrs or r'_changectx' in attrs)
-if noctx or self.rev() == lkr:
-return self.linkrev()
-return self._adjustlinkrev(self.rev(), inclusive=True)
+lazyavailable = r'_changeid' in attrs or r'_changectx' in attrs
+if lazyavailable:
+rev = self.rev()
+if rev == lkr:
+return rev
+else:
+return self._adjustlinkrev(rev, inclusive=True)
+else:
+return self.rev()
 
 def introfilectx(self):
 """Return filectx having identical contents, but pointing to the
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 8 V3] context: fix introrev to avoid computation as initially intended

2018-10-03 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1536254177 14400
#  Thu Sep 06 13:16:17 2018 -0400
# Node ID 355a69e274a2ec851c6d13cfbbac45f5e197294c
# Parent  68ec0cf339c7e65ee4349f543e3024068fbbe591
# EXP-Topic copy-perf
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
355a69e274a2
context: fix introrev to avoid computation as initially intended

The `filerev.introrev()` method has various logic be as efficient as possible.
In particular, it tries to restrict the range covered by the
`ctx._adjustlinkrev(...)` call. However, it does so using the value returned by
`ctx.rev()`. In some case (eg: copy tracing), that `ctx.rev()` call would do an
`_adjustlinkrev(...)` call on its own, defeating the optimization purpose and
doing the computation twice.

We are about to improve graph traversal associated with copy tracing using code
based on `ctx.introrev()`, so we need this fixed before proceeding further.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -765,6 +765,23 @@ class basefilectx(object):
 # result is crash somewhere else at to some point.
 return lkr
 
+def _lazyrevavailable(self):
+"""return True if self.rev() is available without computation,
+
+If finding the rev would trigger a possibly expensive computation, we
+return False."""
+attrs = vars(self)
+if r'_changeid' in attrs:
+# We have a cached value already
+return True
+elif r'_changectx' in attrs:
+# We know which changelog entry we are coming from
+return True
+elif r'_descendantrev' not in attrs:
+# we have no context, so linkrev will be used
+return True
+return False
+
 def introrev(self):
 """return the rev of the changeset which introduced this file revision
 
@@ -776,7 +793,7 @@ class basefilectx(object):
 """
 lkr = self.linkrev()
 attrs = vars(self)
-lazyavailable = r'_changeid' in attrs or r'_changectx' in attrs
+lazyavailable = self._lazyrevavailable()
 if lazyavailable:
 rev = self.rev()
 if rev == lkr:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D4859: exchangev2: add progress bar around manifest scanning

2018-10-03 Thread indygreg (Gregory Szorc)
indygreg updated this revision to Diff 11651.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4859?vs=11637=11651

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

AFFECTED FILES
  mercurial/exchangev2.py

CHANGE DETAILS

diff --git a/mercurial/exchangev2.py b/mercurial/exchangev2.py
--- a/mercurial/exchangev2.py
+++ b/mercurial/exchangev2.py
@@ -320,19 +320,25 @@
 ml = repo.manifestlog
 fnodes = collections.defaultdict(dict)
 
-for manifestnode in manifestnodes:
-m = ml.get(b'', manifestnode)
+progress = repo.ui.makeprogress(
+_('scanning manifests'), total=len(manifestnodes))
+
+with progress:
+for manifestnode in manifestnodes:
+m = ml.get(b'', manifestnode)
 
-# TODO this will pull in unwanted nodes because it takes the storage
-# delta into consideration. What we really want is something that takes
-# the delta between the manifest's parents. And ideally we would
-# ignore file nodes that are known locally. For now, ignore both
-# these limitations. This will result in incremental fetches requesting
-# data we already have. So this is far from ideal.
-md = m.readfast()
+# TODO this will pull in unwanted nodes because it takes the 
storage
+# delta into consideration. What we really want is something that 
takes
+# the delta between the manifest's parents. And ideally we would
+# ignore file nodes that are known locally. For now, ignore both
+# these limitations. This will result in incremental fetches 
requesting
+# data we already have. So this is far from ideal.
+md = m.readfast()
 
-for path, fnode in md.items():
-fnodes[path].setdefault(fnode, manifestnode)
+for path, fnode in md.items():
+fnodes[path].setdefault(fnode, manifestnode)
+
+progress.increment()
 
 return fnodes
 



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


D4859: exchangev2: add progress bar around manifest scanning

2018-10-03 Thread indygreg (Gregory Szorc)
indygreg added inline comments.

INLINE COMMENTS

> martinvonz wrote in exchangev2.py:341
> should call `progress.complete()` here to remove the progress bar (or use it 
> as a context manager)

Yes we should. I'll send an updated patch in a few minutes.

REPOSITORY
  rHG Mercurial

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

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


D4813: narrow: the first version of narrow_widen wireprotocol command

2018-10-03 Thread indygreg (Gregory Szorc)
indygreg added inline comments.

INLINE COMMENTS

> narrowbundle2.py:329
>  getbundleargs['narrow'] = 'boolean'
> -getbundleargs['widen'] = 'boolean'
>  getbundleargs['depth'] = 'plain'

Because of how `wireprotov1server.getbundle()` handles arguments, removing this 
argument from the definition of arguments to the `getbundle` wire protocol 
command means that existing clients attempting to send the argument to the 
`getbundle` wire protocol command will cause a server-side exception.

We need to keep this key around for BC unless we're fine breaking old clients 
or unless there is something that changes server capabilities in a way that 
prevents old clients from calling `getbundle` with this argument. We could 
ignore the argument or nerf the server to error if it is received.

> martinvonz wrote in narrowwirepeer.py:79-82
> That code was added in 
> https://www.mercurial-scm.org/repo/hg/rev/3e7f675628ad. Maybe @indygreg can 
> tell us if he thinks we should support the same values for a new wireprotocol 
> command.

We probably want to extract the argument "parsing" from 
`wireprotov1server.getbundle()` into a standalone function so we can use it for 
this command.

Arguments in wire protocol version 1 are wonky :/

> narrowwirepeer.py:64
> +"""
> +
> +oldincludes = wireprototypes.decodelist(args.get('oldincludes'))

I'm pretty sure we'll want a try..except around this entire command so that 
we'll send a bundle2 error payload on failure. See 
`wireprotov1server.getbundle()` for inspiration. Search for use of the 
`error:abort` bundle2 part. We'll want to do something like that in the except 
block.

Keep in mind exceptions can occur mid stream. In that case, proper error 
handling is a bit harder. But a good start is to put a `try..except` around all 
the code before we `return` the output.

REPOSITORY
  rHG Mercurial

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

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


D4859: exchangev2: add progress bar around manifest scanning

2018-10-03 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> exchangev2.py:341
> +progress.increment()
> +
>  return fnodes

should call `progress.complete()` here to remove the progress bar (or use it as 
a context manager)

REPOSITORY
  rHG Mercurial

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

To: indygreg, #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 3 of 7] context: fix introrev to avoid computation as initially intended

2018-10-03 Thread Martin von Zweigbergk via Mercurial-devel
Btw, just because I found this patch hard to follow doesn't necessarily
mean that others do. I won't mind if someone else understands what it does
and queues it (and a third person adds a second accept stamp).

On Tue, Oct 2, 2018 at 5:46 AM Martin von Zweigbergk 
wrote:

>
>
> On Tue, Oct 2, 2018, 01:58 Boris FELD  wrote:
>
>>
>> On 01/10/2018 18:43, Martin von Zweigbergk via Mercurial-devel wrote:
>>
>>
>>
>> On Mon, Oct 1, 2018 at 9:11 AM Boris FELD  wrote:
>>
>>> On 10/09/2018 18:21, Martin von Zweigbergk via Mercurial-devel wrote:
>>>
>>>
>>>
>>> On Fri, Sep 7, 2018 at 8:09 AM Boris Feld 
>>> wrote:
>>>
 # HG changeset patch
 # User Boris Feld 
 # Date 1536254177 14400
 #  Thu Sep 06 13:16:17 2018 -0400
 # Node ID a4c3eb6c1a36cbbf64fa8930b173154b2e77ef2b
 # Parent  9a18509c522deeb62a7b244dcf4c7b79a8dc1132
 # EXP-Topic copy-perf
 # Available At https://bitbucket.org/octobus/mercurial-devel/
 #  hg pull https://bitbucket.org/octobus/mercurial-devel/
 -r a4c3eb6c1a36
 context: fix introrev to avoid computation as initially intended

 diff --git a/mercurial/context.py b/mercurial/context.py
 --- a/mercurial/context.py
 +++ b/mercurial/context.py
 @@ -829,6 +829,23 @@ class basefilectx(object):
  # result is crash somewhere else at to some point.
  return lkr

 +def _lazyrev(self):

>>>
>>> We usually try to separate refactoring (like extracting a method) from
>>> functional (or performance-related) changes. Could you do that with this
>>> patch or does it not make sense for some reason?
>>>
>>> In this case, the two changes are a bit too interleaved to be easily
>>> split in two. We can't do the special casing until we have the new method
>>> and the new method can't have any caller without changing the conditionals
>>> to include the special casing.
>>>
>>
>> Maybe I missed something, but it looks like _lazyrev() returns either
>> "None" or "self.rev()", even at the end of the series. Did I get that
>> right? Will that change later? If not, it seems like you could instead
>> extract a method that calculates what's currently called "noctx". Even if
>> that's going to change, it might make it easier to understand this patch if
>> you split out a patch that made the structure here more similar to your
>> goal, something like:
>>
>>
>> @@ -837,9 +837,13 @@ class basefilectx(object):
>>  lkr = self.linkrev()
>>  attrs = vars(self)
>>  noctx = not (r'_changeid' in attrs or r'_changectx' in attrs)
>> -if noctx or self.rev() == lkr:
>> +if noctx:
>>  return self.linkrev()
>> -return self._adjustlinkrev(self.rev(), inclusive=True)
>> +else:
>> +if self.rev() == lkr:
>> +return self.linkrev()
>> +else:
>> +return self._adjustlinkrev(self.rev(), inclusive=True)
>>
>> Yes, you are right, we can split the changeset in two.
>>
>> I don't feel that it would help the readability of the series but I'm not
>> the reviewer. Do you think it would help you review the patch?
>>
>>
> Yes, I think it would. I did it myself in order to understand this patch.
> I think it would also help to make that return just a boolean value,
> assuming that will still work with later patches. Thanks.
>
>
>
>>
>>>
>>> ___
>>> Mercurial-devel mailing 
>>> listMercurial-devel@mercurial-scm.orghttps://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>>
>>>
>> ___
>> Mercurial-devel mailing 
>> listMercurial-devel@mercurial-scm.orghttps://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


D4869: revlog: rewrite censoring logic

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

REVISION SUMMARY
  I was able to corrupt a revlog relatively easily with the existing
  censoring code. The underlying problem is that the existing code
  doesn't fully take delta chains into account. When copying revisions
  that occur after the censored revision, the delta base can refer
  to a censored revision. Then at read time, things blow up due to the
  revision data not being a compressed delta.
  
  This commit rewrites the revlog censoring code to take a higher-level
  approach. We now create a new revlog instance pointing at temp files.
  We iterate through each revision in the source revlog and insert
  those revisions into the new revlog, replacing the censored revision's
  data along the way.
  
  The new implementation isn't as efficient as the old one. This is
  because it will fully engage delta computation on insertion. But I
  don't think it matters.
  
  The new implementation is a bit hacky because it attempts to reload
  the revlog instance with a new revlog index/data file. This is fragile.
  But this is needed because the index (which could be backed by C) would
  have a cached copy of the old, possibly changed data and that could
  lead to problems accessing index or revision data later.
  
  One benefit of the new approach is that we integrate with the
  transaction. The old revlog is backed up and if the transaction is
  rolled back, the original revlog is restored.
  
  As part of this, we had to teach the transaction about the store
  vfs. I'm not super keen about this. But this was the easiest way
  to hook things up to the transaction. We /could/ just ignore the
  transaction like we were doing before. But any file mutation should
  be governed by transaction semantics, including undo during rollback.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/filelog.py
  mercurial/localrepo.py
  mercurial/revlog.py
  mercurial/testing/storage.py
  tests/test-storage.py

CHANGE DETAILS

diff --git a/tests/test-storage.py b/tests/test-storage.py
--- a/tests/test-storage.py
+++ b/tests/test-storage.py
@@ -30,7 +30,7 @@
 return fl
 
 def maketransaction(self):
-vfsmap = {'plain': STATE['vfs']}
+vfsmap = {'plain': STATE['vfs'], 'store': STATE['vfs']}
 
 return transaction.transaction(STATE['ui'].warn, STATE['vfs'], vfsmap,
b'journal', b'undo')
diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -1175,14 +1175,9 @@
 self.assertEqual(list(f.revs()), [0, 1, 2])
 
 self.assertEqual(f.read(node0), b'foo\n' * 30)
+self.assertEqual(f.read(node2), b'foo\n' * 32)
 
-# TODO revlog can't resolve revision after censor. Probably due to a
-# cache on the revlog instance.
-with self.assertRaises(error.StorageError):
-self.assertEqual(f.read(node2), b'foo\n' * 32)
-
-# TODO should raise CensoredNodeError, but fallout from above prevents.
-with self.assertRaises(error.StorageError):
+with self.assertRaises(error.CensoredNodeError):
 f.read(node1)
 
 def testgetstrippointnoparents(self):
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -2341,94 +2341,69 @@
 destrevlog._lazydeltabase = oldlazydeltabase
 destrevlog._deltabothparents = oldamd
 
-def censorrevision(self, node, tombstone=b''):
+def censorrevision(self, tr, censornode, tombstone=b''):
 if (self.version & 0x) == REVLOGV0:
 raise error.RevlogError(_('cannot censor with version %d revlogs') 
%
 self.version)
 
-rev = self.rev(node)
+censorrev = self.rev(censornode)
 tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
 
-if len(tombstone) > self.rawsize(rev):
+if len(tombstone) > self.rawsize(censorrev):
 raise error.Abort(_('censor tombstone must be no longer than '
 'censored data'))
 
-# Using two files instead of one makes it easy to rewrite 
entry-by-entry
-idxread = self.opener(self.indexfile, 'r')
-idxwrite = self.opener(self.indexfile, 'wb', atomictemp=True)
-if self.version & FLAG_INLINE_DATA:
-dataread, datawrite = idxread, idxwrite
-else:
-dataread = self.opener(self.datafile, 'r')
-datawrite = self.opener(self.datafile, 'wb', atomictemp=True)
+# Rewriting the revlog in place is hard. Our strategy for censoring is
+# to create a new revlog, copy all revisions to it, then replace the
+# revlogs on transaction close.
 
-# Copy all revlog data up to the entry to be 

D4813: narrow: the first version of narrow_widen wireprotocol command

2018-10-03 Thread martinvonz (Martin von Zweigbergk)
martinvonz added a comment.


  > I need to specify the arguments instead of just specifying "*".
  
  Don't forget this one.

INLINE COMMENTS

> pulkit wrote in narrowcommands.py:293-295
> We can have a 'exp-ellipses-2' which will tell whether the server supports 
> ellipses widening using narrow_widen() wireprotocol command or not. I think 
> that should help in the meantime. Also will a week, or 10-15 days be enough 
> for you? I think it will be better if can prevent releasing this 
> compatibility because exp-ellipses-1 was introduced in this cycle only.

We don't really care whether a version is released or not. It would be nice to 
have a version of the client that would use the new wire protocol with ellipses 
if the server said it supported that but would otherwise fall back to the old 
getbundle-based call.

> pulkit wrote in narrowwirepeer.py:49
> I implemented the peer initially in core only, but while implementing server 
> side, I realized it rely on logic in narrowbundle2.py which also needs to be 
> moved to core. Then I decided to implement it cleanly in the extension and 
> then move it to core.

It seems to depend only on `widen_bundle`, which doesn't seem to depend on 
anything else, so it would probably be easy to move it to core, but I won't 
insist.

> pulkit wrote in narrowwirepeer.py:79-82
> I am not sure, I just copied from getbundle() handling: 
> https://www.mercurial-scm.org/repo/hg/file/1a4c1a3cc3f5/mercurial/wireprotov1server.py#l404

That code was added in https://www.mercurial-scm.org/repo/hg/rev/3e7f675628ad. 
Maybe @indygreg can tell us if he thinks we should support the same values for 
a new wireprotocol command.

REPOSITORY
  rHG Mercurial

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

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


D4867: revlog: clear revision cache on hash verification failure

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

REVISION SUMMARY
  The revision cache is populated after raw revision fulltext is
  retrieved but before hash verification. If hash verification
  fails, the revision cache will be populated and subsequent
  operations to retrieve the invalid fulltext may return the cached
  fulltext instead of raising.
  
  This commit changes hash verification so it will invalidate the
  revision cache if the cached node fails hash verification. The
  side-effect is that subsequent operations to request the revision
  text - even the raw revision text - will always fail.
  
  The new behavior is consistent and is definitely less wrong. There
  is an open question of whether revision(raw=True) should validate
  hashes. But I'm going to punt on this problem. We can always change
  behavior later. And to be honest, I'm not sure we should expose
  raw=True on the storage interface at all. Another day...

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/revlog.py
  mercurial/testing/storage.py

CHANGE DETAILS

diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -881,13 +881,14 @@
 with self.assertRaises(error.StorageError):
 f.revision(node1)
 
-# revision(raw=True) still verifies hashes.
-# TODO this is buggy because of cache interaction.
-self.assertEqual(f.revision(node1, raw=True), fulltext1)
+# raw=True still verifies because there are no special storage
+# settings.
+with self.assertRaises(error.StorageError):
+f.revision(node1, raw=True)
 
 # read() behaves like revision().
-# TODO this is buggy because of cache interaction.
-f.read(node1)
+with self.assertRaises(error.StorageError):
+f.read(node1)
 
 # We can't test renamed() here because some backends may not require
 # reading/validating the fulltext to return rename metadata.
@@ -931,8 +932,8 @@
 with self.assertRaises(error.StorageError):
 f.read(node1)
 
-# TODO this should raise error.StorageError.
-f.read(node1)
+with self.assertRaises(error.StorageError):
+f.read(node1)
 
 def testbadnodedelta(self):
 f = self._makefilefn()
@@ -986,7 +987,8 @@
 with self.assertRaises(error.CensoredNodeError):
 f.revision(1)
 
-self.assertEqual(f.revision(1, raw=True), stored1)
+with self.assertRaises(error.CensoredNodeError):
+f.revision(1, raw=True)
 
 with self.assertRaises(error.CensoredNodeError):
 f.read(1)
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1659,6 +1659,15 @@
 if p1 is None and p2 is None:
 p1, p2 = self.parents(node)
 if node != self.hash(text, p1, p2):
+# Clear the revision cache on hash failure. The revision cache
+# only stores the raw revision and clearing the cache does have
+# the side-effect that we won't have a cache hit when the raw
+# revision data is accessed. But this case should be rare and
+# it is extra work to teach the cache about the hash
+# verification state.
+if self._revisioncache and self._revisioncache[0] == node:
+self._revisioncache = None
+
 revornode = rev
 if revornode is None:
 revornode = templatefilters.short(hex(node))



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


D4868: revlog: move loading of index data into own method

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

REVISION SUMMARY
  This will allow us to "reload" a revlog instance from a rewritten
  index file, which will be used in a subsequent commit.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/revlog.py

CHANGE DETAILS

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -415,12 +415,15 @@
 raise error.RevlogError(_('revlog chunk cache size %r is not a '
   'power of 2') % self._chunkcachesize)
 
+self._loadindex(v, mmapindexthreshold)
+
+def _loadindex(self, v, mmapindexthreshold):
 indexdata = ''
 self._initempty = True
 try:
 with self._indexfp() as f:
 if (mmapindexthreshold is not None and
-self.opener.fstat(f).st_size >= mmapindexthreshold):
+self.opener.fstat(f).st_size >= mmapindexthreshold):
 indexdata = util.buffer(util.mmapread(f))
 else:
 indexdata = f.read()



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


D4866: revlog: rename _cache to _revisioncache

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

REVISION SUMMARY
  "cache" is generic and revlog instances have multiple caches. Let's
  be descriptive about what this is a cache for.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/bundlerepo.py
  mercurial/revlog.py
  mercurial/unionrepo.py

CHANGE DETAILS

diff --git a/mercurial/unionrepo.py b/mercurial/unionrepo.py
--- a/mercurial/unionrepo.py
+++ b/mercurial/unionrepo.py
@@ -110,7 +110,7 @@
 
 if rev > self.repotiprev:
 text = self.revlog2.revision(node)
-self._cache = (node, rev, text)
+self._revisioncache = (node, rev, text)
 else:
 text = self.baserevision(rev)
 # already cached
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -346,7 +346,7 @@
 self._checkambig = checkambig
 self._censorable = censorable
 # 3-tuple of (node, rev, text) for a raw revision.
-self._cache = None
+self._revisioncache = None
 # Maps rev to chain base rev.
 self._chainbasecache = util.lrucachedict(100)
 # 2-tuple of (offset, data) of raw data from the revlog at an offset.
@@ -545,7 +545,7 @@
 return True
 
 def clearcaches(self):
-self._cache = None
+self._revisioncache = None
 self._chainbasecache.clear()
 self._chunkcache = (0, '')
 self._pcache = {}
@@ -1524,35 +1524,35 @@
 rawtext = None
 if node == nullid:
 return ""
-if self._cache:
-if self._cache[0] == node:
+if self._revisioncache:
+if self._revisioncache[0] == node:
 # _cache only stores rawtext
 if raw:
-return self._cache[2]
+return self._revisioncache[2]
 # duplicated, but good for perf
 if rev is None:
 rev = self.rev(node)
 if flags is None:
 flags = self.flags(rev)
 # no extra flags set, no flag processor runs, text = rawtext
 if flags == REVIDX_DEFAULT_FLAGS:
-return self._cache[2]
+return self._revisioncache[2]
 # rawtext is reusable. need to run flag processor
-rawtext = self._cache[2]
+rawtext = self._revisioncache[2]
 
-cachedrev = self._cache[1]
+cachedrev = self._revisioncache[1]
 
 # look up what we need to read
 if rawtext is None:
 if rev is None:
 rev = self.rev(node)
 
 chain, stopped = self._deltachain(rev, stoprev=cachedrev)
 if stopped:
-rawtext = self._cache[2]
+rawtext = self._revisioncache[2]
 
 # drop cache to save memory
-self._cache = None
+self._revisioncache = None
 
 targetsize = None
 rawsize = self.index[rev][2]
@@ -1565,7 +1565,7 @@
 bins = bins[1:]
 
 rawtext = mdiff.patches(rawtext, bins)
-self._cache = (node, rev, rawtext)
+self._revisioncache = (node, rev, rawtext)
 
 if flags is None:
 if rev is None:
@@ -1926,7 +1926,7 @@
 rawtext = deltacomputer.buildtext(revinfo, fh)
 
 if type(rawtext) == bytes: # only accept immutable objects
-self._cache = (node, curr, rawtext)
+self._revisioncache = (node, curr, rawtext)
 self._chainbasecache[curr] = deltainfo.chainbase
 return node
 
@@ -2132,7 +2132,7 @@
 transaction.add(self.indexfile, end)
 
 # then reset internal state in memory to forget those revisions
-self._cache = None
+self._revisioncache = None
 self._chaininfocache = {}
 self._chunkclear()
 for x in pycompat.xrange(rev, len(self)):
diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -127,8 +127,8 @@
 iterrev = rev
 # reconstruct the revision if it is from a changegroup
 while iterrev > self.repotiprev:
-if self._cache and self._cache[1] == iterrev:
-rawtext = self._cache[2]
+if self._revisioncache and self._revisioncache[1] == iterrev:
+rawtext = self._revisioncache[2]
 break
 chain.append(iterrev)
 iterrev = self.index[iterrev][3]
@@ -143,7 +143,7 @@
 'read', raw=raw)
 if validatehash:
 self.checkhash(text, node, rev=rev)
-self._cache = (node, rev, rawtext)
+self._revisioncache = (node, rev, rawtext)
 

D4865: testing: add file storage integration for bad hashes and censoring

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

REVISION SUMMARY
  In order to implement these tests, we need a backdoor to write data
  into storage backends while bypassing normal checks. We invent a
  callable to do that.
  
  As part of writing the tests, I found a bug with censorrevision()
  pretty quickly! After calling censorrevision(), attempting to
  access revision data for an affected node raises a cryptic error
  related to malformed compression. This appears to be due to the
  revlog not adjusting delta chains as part of censoring.
  
  I also found a bug with regards to hash verification and revision
  fulltext caching. Essentially, we cache the fulltext before hash
  verification. If we look up the fulltext after a failed hash
  verification, we don't get a hash verification exception. Furthermore,
  the behavior of revision(raw=True) can be inconsistent depending on
  the order of operations.
  
  I'll be fixing both these bugs in subsequent commits.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/testing/storage.py
  tests/test-storage.py

CHANGE DETAILS

diff --git a/tests/test-storage.py b/tests/test-storage.py
--- a/tests/test-storage.py
+++ b/tests/test-storage.py
@@ -5,7 +5,9 @@
 import silenttestrunner
 
 from mercurial import (
+error,
 filelog,
+revlog,
 transaction,
 ui as uimod,
 vfs as vfsmod,
@@ -33,14 +35,39 @@
 return transaction.transaction(STATE['ui'].warn, STATE['vfs'], vfsmap,
b'journal', b'undo')
 
+def addrawrevision(self, fl, tr, node, p1, p2, linkrev, rawtext=None,
+   delta=None, censored=False, ellipsis=False, 
extstored=False):
+flags = 0
+
+if censored:
+flags |= revlog.REVIDX_ISCENSORED
+if ellipsis:
+flags |= revlog.REVIDX_ELLIPSIS
+if extstored:
+flags |= revlog.REVIDX_EXTSTORED
+
+if rawtext is not None:
+fl._revlog.addrawrevision(rawtext, tr, linkrev, p1, p2, node, flags)
+elif delta is not None:
+raise error.Abort('support for storing raw deltas not yet supported')
+else:
+raise error.Abort('must supply rawtext or delta arguments')
+
+# We may insert bad data. Clear caches to prevent e.g. cache hits to
+# bypass hash verification.
+fl._revlog.clearcaches()
+
 # Assigning module-level attributes that inherit from unittest.TestCase
 # is all that is needed to register tests.
 filelogindextests = storagetesting.makeifileindextests(makefilefn,
-   maketransaction)
+   maketransaction,
+   addrawrevision)
 filelogdatatests = storagetesting.makeifiledatatests(makefilefn,
- maketransaction)
+ maketransaction,
+ addrawrevision)
 filelogmutationtests = storagetesting.makeifilemutationtests(makefilefn,
- maketransaction)
+ maketransaction,
+ addrawrevision)
 
 if __name__ == '__main__':
 silenttestrunner.main(__name__)
diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -861,27 +861,157 @@
 self.assertFalse(f.cmp(node1, fulltext1))
 self.assertTrue(f.cmp(node1, stored0))
 
+def testbadnoderead(self):
+f = self._makefilefn()
+
+fulltext0 = b'foo\n' * 30
+fulltext1 = fulltext0 + b'bar\n'
+
+with self._maketransactionfn() as tr:
+node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
+node1 = b'\xaa' * 20
+
+self._addrawrevisionfn(f, tr, node1, node0, nullid, 1,
+   rawtext=fulltext1)
+
+self.assertEqual(len(f), 2)
+self.assertEqual(f.parents(node1), (node0, nullid))
+
+# revision() raises since it performs hash verification.
+with self.assertRaises(error.StorageError):
+f.revision(node1)
+
+# revision(raw=True) still verifies hashes.
+# TODO this is buggy because of cache interaction.
+self.assertEqual(f.revision(node1, raw=True), fulltext1)
+
+# read() behaves like revision().
+# TODO this is buggy because of cache interaction.
+f.read(node1)
+
+# We can't test renamed() here because some backends may not require
+# reading/validating the fulltext to return rename metadata.
+
+def testbadnoderevisionraw(self):
+# Like above except we test revision(raw=True) 

D4864: testing: add file storage tests for getstrippoint() and strip()

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

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/testing/storage.py

CHANGE DETAILS

diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -1004,6 +1004,123 @@
 self.assertEqual(f.node(1), nodes[1])
 self.assertEqual(f.node(2), nodes[2])
 
+def testgetstrippointnoparents(self):
+# N revisions where none have parents.
+f = self._makefilefn()
+
+with self._maketransactionfn() as tr:
+for rev in range(10):
+f.add(b'%d' % rev, None, tr, rev, nullid, nullid)
+
+for rev in range(10):
+self.assertEqual(f.getstrippoint(rev), (rev, set()))
+
+def testgetstrippointlinear(self):
+# N revisions in a linear chain.
+f = self._makefilefn()
+
+with self._maketransactionfn() as tr:
+p1 = nullid
+
+for rev in range(10):
+f.add(b'%d' % rev, None, tr, rev, p1, nullid)
+
+for rev in range(10):
+self.assertEqual(f.getstrippoint(rev), (rev, set()))
+
+def testgetstrippointmultipleheads(self):
+f = self._makefilefn()
+
+with self._maketransactionfn() as tr:
+node0 = f.add(b'0', None, tr, 0, nullid, nullid)
+node1 = f.add(b'1', None, tr, 1, node0, nullid)
+f.add(b'2', None, tr, 2, node1, nullid)
+f.add(b'3', None, tr, 3, node0, nullid)
+f.add(b'4', None, tr, 4, node0, nullid)
+
+for rev in range(5):
+self.assertEqual(f.getstrippoint(rev), (rev, set()))
+
+def testgetstrippointearlierlinkrevs(self):
+f = self._makefilefn()
+
+with self._maketransactionfn() as tr:
+node0 = f.add(b'0', None, tr, 0, nullid, nullid)
+f.add(b'1', None, tr, 10, node0, nullid)
+f.add(b'2', None, tr, 5, node0, nullid)
+
+self.assertEqual(f.getstrippoint(0), (0, set()))
+self.assertEqual(f.getstrippoint(1), (1, set()))
+self.assertEqual(f.getstrippoint(2), (1, set()))
+self.assertEqual(f.getstrippoint(3), (1, set()))
+self.assertEqual(f.getstrippoint(4), (1, set()))
+self.assertEqual(f.getstrippoint(5), (1, set()))
+self.assertEqual(f.getstrippoint(6), (1, {2}))
+self.assertEqual(f.getstrippoint(7), (1, {2}))
+self.assertEqual(f.getstrippoint(8), (1, {2}))
+self.assertEqual(f.getstrippoint(9), (1, {2}))
+self.assertEqual(f.getstrippoint(10), (1, {2}))
+self.assertEqual(f.getstrippoint(11), (3, set()))
+
+def teststripempty(self):
+f = self._makefilefn()
+
+with self._maketransactionfn() as tr:
+f.strip(0, tr)
+
+self.assertEqual(len(f), 0)
+
+def teststripall(self):
+f = self._makefilefn()
+
+with self._maketransactionfn() as tr:
+p1 = nullid
+for rev in range(10):
+p1 = f.add(b'%d' % rev, None, tr, rev, p1, nullid)
+
+self.assertEqual(len(f), 10)
+
+with self._maketransactionfn() as tr:
+f.strip(0, tr)
+
+self.assertEqual(len(f), 0)
+
+def teststrippartial(self):
+f = self._makefilefn()
+
+with self._maketransactionfn() as tr:
+f.add(b'0', None, tr, 0, nullid, nullid)
+node1 = f.add(b'1', None, tr, 5, nullid, nullid)
+node2 = f.add(b'2', None, tr, 10, nullid, nullid)
+
+self.assertEqual(len(f), 3)
+
+with self._maketransactionfn() as tr:
+f.strip(11, tr)
+
+self.assertEqual(len(f), 3)
+
+with self._maketransactionfn() as tr:
+f.strip(10, tr)
+
+self.assertEqual(len(f), 2)
+
+with self.assertRaises(error.LookupError):
+f.rev(node2)
+
+with self._maketransactionfn() as tr:
+f.strip(6, tr)
+
+self.assertEqual(len(f), 2)
+
+with self._maketransactionfn() as tr:
+f.strip(3, tr)
+
+self.assertEqual(len(f), 1)
+
+with self.assertRaises(error.LookupError):
+f.rev(node1)
+
 def makeifileindextests(makefilefn, maketransactionfn):
 """Create a unittest.TestCase class suitable for testing file storage.
 



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


D4863: wireprotov2: always advertise raw repo requirements

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

REVISION SUMMARY
  I'm pretty sure my original thinking behind making it conditional
  on stream clone support was that the behavior mirrored wire protocol
  version 1.
  
  I don't see a compelling reason for us to not advertise the server's
  storage requirements. The proper way to advertise stream clone support
  in wireprotov2 would be to not advertise the command(s) required to
  perform stream clone or to advertise a separate capability denoting
  stream clone support.
  
  Stream clone isn't yet implemented on wireprotov2, so we can cross
  this bridge later.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/wireprotov2server.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py
--- a/mercurial/wireprotov2server.py
+++ b/mercurial/wireprotov2server.py
@@ -20,7 +20,6 @@
 error,
 narrowspec,
 pycompat,
-streamclone,
 util,
 wireprotoframing,
 wireprototypes,
@@ -522,9 +521,8 @@
 'permissions': [entry.permission],
 }
 
-if streamclone.allowservergeneration(repo):
-caps['rawrepoformats'] = sorted(repo.requirements &
-repo.supportedformats)
+caps['rawrepoformats'] = sorted(repo.requirements &
+repo.supportedformats)
 
 targets = getadvertisedredirecttargets(repo, proto)
 if targets:



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


D4767: exchangev2: recognize narrow patterns when pulling

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


  I'll be rebasing this locally as part of future feature work. I plan to 
resubmit again later.

REPOSITORY
  rHG Mercurial

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

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


D4862: cleanup: some Yoda conditions, this patch removes

2018-10-03 Thread martinvonz (Martin von Zweigbergk)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGe2697acd9381: cleanup: some Yoda conditions, this patch 
removes (authored by martinvonz, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4862?vs=11642=11643

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

AFFECTED FILES
  contrib/revsetbenchmarks.py
  hgext/histedit.py
  hgext/patchbomb.py
  hgext/shelve.py
  mercurial/cmdutil.py
  mercurial/debugcommands.py
  mercurial/obsolete.py
  mercurial/templatefilters.py
  mercurial/util.py

CHANGE DETAILS

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -333,7 +333,7 @@
 return self._frombuffer(min(self._lenbuf, size))
 
 def readline(self, *args, **kwargs):
-if 1 < len(self._buffer):
+if len(self._buffer) > 1:
 # this should not happen because both read and readline end with a
 # _frombuffer call that collapse it.
 self._buffer = [''.join(self._buffer)]
@@ -348,7 +348,7 @@
 size = lfi + 1
 if lfi < 0: # end of file
 size = self._lenbuf
-elif 1 < len(self._buffer):
+elif len(self._buffer) > 1:
 # we need to take previous chunks into account
 size += self._lenbuf - len(self._buffer[-1])
 return self._frombuffer(size)
@@ -360,7 +360,7 @@
 if size == 0 or not self._buffer:
 return ''
 buf = self._buffer[0]
-if 1 < len(self._buffer):
+if len(self._buffer) > 1:
 buf = ''.join(self._buffer)
 
 data = buf[:size]
diff --git a/mercurial/templatefilters.py b/mercurial/templatefilters.py
--- a/mercurial/templatefilters.py
+++ b/mercurial/templatefilters.py
@@ -200,7 +200,7 @@
 if not m:
 uctext = encoding.unifromlocal(text[start:])
 w = len(uctext)
-while 0 < w and uctext[w - 1].isspace():
+while w > 0 and uctext[w - 1].isspace():
 w -= 1
 yield (encoding.unitolocal(uctext[:w]),
encoding.unitolocal(uctext[w:]))
diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -997,13 +997,13 @@
 if not isinstance(predecessors, tuple):
 # preserve compat with old API until all caller are migrated
 predecessors = (predecessors,)
-if 1 < len(predecessors) and len(rel[1]) != 1:
+if len(predecessors) > 1 and len(rel[1]) != 1:
 msg = 'Fold markers can only have 1 successors, not %d'
 raise error.ProgrammingError(msg % len(rel[1]))
 for prec in predecessors:
 sucs = rel[1]
 localmetadata = metadata.copy()
-if 2 < len(rel):
+if len(rel) > 2:
 localmetadata.update(rel[2])
 
 if not prec.mutable():
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -2197,7 +2197,7 @@
 fullsize[2] /= numfull
 semitotal = semisize[2]
 snaptotal = {}
-if 0 < numsemi:
+if numsemi > 0:
 semisize[2] /= numsemi
 for depth in snapsizedepth:
 snaptotal[depth] = snapsizedepth[depth][2]
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -861,7 +861,7 @@
 if isinstance(ctxorbool, bool):
 if ctxorbool:
 return baseformname + ".merge"
-elif 1 < len(ctxorbool.parents()):
+elif len(ctxorbool.parents()) > 1:
 return baseformname + ".merge"
 
 return baseformname + ".normal"
diff --git a/hgext/shelve.py b/hgext/shelve.py
--- a/hgext/shelve.py
+++ b/hgext/shelve.py
@@ -302,7 +302,7 @@
 hgfiles = [f for f in vfs.listdir()
if f.endswith('.' + patchextension)]
 hgfiles = sorted([(vfs.stat(f)[stat.ST_MTIME], f) for f in hgfiles])
-if 0 < maxbackups and maxbackups < len(hgfiles):
+if maxbackups > 0 and maxbackups < len(hgfiles):
 bordermtime = hgfiles[-maxbackups][0]
 else:
 bordermtime = None
diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -187,12 +187,12 @@
 elif introconfig == 'never':
 intro = False
 elif introconfig == 'auto':
-intro = 1 < number
+intro = number > 1
 else:
 ui.write_err(_('warning: invalid patchbomb.intro value "%s"\n')
  % introconfig)
 ui.write_err(_('(should be one of always, never, auto)\n'))
-intro = 1 < number
+intro = number > 1
 return intro
 
 def _formatflags(ui, repo, rev, flags):
@@ -663,7 +663,7 @@
 if not known[idx]:
 

D4862: cleanup: some Yoda conditions, this patch removes

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

REVISION SUMMARY
  It seems the factor 20 is less than the frequency of " < \d" compared
  to " \d > ".

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  contrib/revsetbenchmarks.py
  hgext/histedit.py
  hgext/patchbomb.py
  hgext/shelve.py
  mercurial/cmdutil.py
  mercurial/debugcommands.py
  mercurial/obsolete.py
  mercurial/templatefilters.py
  mercurial/util.py

CHANGE DETAILS

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -333,7 +333,7 @@
 return self._frombuffer(min(self._lenbuf, size))
 
 def readline(self, *args, **kwargs):
-if 1 < len(self._buffer):
+if len(self._buffer) > 1:
 # this should not happen because both read and readline end with a
 # _frombuffer call that collapse it.
 self._buffer = [''.join(self._buffer)]
@@ -348,7 +348,7 @@
 size = lfi + 1
 if lfi < 0: # end of file
 size = self._lenbuf
-elif 1 < len(self._buffer):
+elif len(self._buffer) > 1:
 # we need to take previous chunks into account
 size += self._lenbuf - len(self._buffer[-1])
 return self._frombuffer(size)
@@ -360,7 +360,7 @@
 if size == 0 or not self._buffer:
 return ''
 buf = self._buffer[0]
-if 1 < len(self._buffer):
+if len(self._buffer) > 1:
 buf = ''.join(self._buffer)
 
 data = buf[:size]
diff --git a/mercurial/templatefilters.py b/mercurial/templatefilters.py
--- a/mercurial/templatefilters.py
+++ b/mercurial/templatefilters.py
@@ -200,7 +200,7 @@
 if not m:
 uctext = encoding.unifromlocal(text[start:])
 w = len(uctext)
-while 0 < w and uctext[w - 1].isspace():
+while w > 0 and uctext[w - 1].isspace():
 w -= 1
 yield (encoding.unitolocal(uctext[:w]),
encoding.unitolocal(uctext[w:]))
diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -997,13 +997,13 @@
 if not isinstance(predecessors, tuple):
 # preserve compat with old API until all caller are migrated
 predecessors = (predecessors,)
-if 1 < len(predecessors) and len(rel[1]) != 1:
+if len(predecessors) > 1 and len(rel[1]) != 1:
 msg = 'Fold markers can only have 1 successors, not %d'
 raise error.ProgrammingError(msg % len(rel[1]))
 for prec in predecessors:
 sucs = rel[1]
 localmetadata = metadata.copy()
-if 2 < len(rel):
+if len(rel) > 2:
 localmetadata.update(rel[2])
 
 if not prec.mutable():
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -2197,7 +2197,7 @@
 fullsize[2] /= numfull
 semitotal = semisize[2]
 snaptotal = {}
-if 0 < numsemi:
+if numsemi > 0:
 semisize[2] /= numsemi
 for depth in snapsizedepth:
 snaptotal[depth] = snapsizedepth[depth][2]
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -861,7 +861,7 @@
 if isinstance(ctxorbool, bool):
 if ctxorbool:
 return baseformname + ".merge"
-elif 1 < len(ctxorbool.parents()):
+elif len(ctxorbool.parents()) > 1:
 return baseformname + ".merge"
 
 return baseformname + ".normal"
diff --git a/hgext/shelve.py b/hgext/shelve.py
--- a/hgext/shelve.py
+++ b/hgext/shelve.py
@@ -302,7 +302,7 @@
 hgfiles = [f for f in vfs.listdir()
if f.endswith('.' + patchextension)]
 hgfiles = sorted([(vfs.stat(f)[stat.ST_MTIME], f) for f in hgfiles])
-if 0 < maxbackups and maxbackups < len(hgfiles):
+if maxbackups > 0 and maxbackups < len(hgfiles):
 bordermtime = hgfiles[-maxbackups][0]
 else:
 bordermtime = None
diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -187,12 +187,12 @@
 elif introconfig == 'never':
 intro = False
 elif introconfig == 'auto':
-intro = 1 < number
+intro = number > 1
 else:
 ui.write_err(_('warning: invalid patchbomb.intro value "%s"\n')
  % introconfig)
 ui.write_err(_('(should be one of always, never, auto)\n'))
-intro = 1 < number
+intro = number > 1
 return intro
 
 def _formatflags(ui, repo, rev, flags):
@@ -663,7 +663,7 @@
 if not known[idx]:
 missing.append(h)

D4797: storageutil: implement file identifier resolution method (BC)

2018-10-03 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  In https://phab.mercurial-scm.org/D4797#73451, @martinvonz wrote:
  
  > > with the exception of partial hex node matching, we may want to consider 
changing revlog.lookup() as well
  >
  > Maybe even without the exception? I thought we used partial nodeids only 
for debug commands and maybe we can move the partial matching to a higher level.
  
  
  I support moving partial matching to a higher level. Although some storage 
backends may support a more efficient "native" partial matcher. e.g. SQLite 
could use various string matching functions. But I'm not sure it is worth it 
though: I think I'd rather have a generic object holding DAG/index data [that 
can be shared across all storage backends] and that exposes a partial match 
API. I dunno. I don't plan to do anything in this area at this time. If you 
want to hack on things, go for it.

REPOSITORY
  rHG Mercurial

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

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


mercurial@39994: 28 new changesets

2018-10-03 Thread Mercurial Commits
28 new changesets in mercurial:

https://www.mercurial-scm.org/repo/hg/rev/aab43d5861bb
changeset:   39967:aab43d5861bb
user:Yuya Nishihara 
date:Mon Sep 24 15:54:18 2018 +0900
summary: rust-chg: add project skeleton

https://www.mercurial-scm.org/repo/hg/rev/86acdfe8b018
changeset:   39968:86acdfe8b018
user:Yuya Nishihara 
date:Mon Sep 24 15:57:28 2018 +0900
summary: rust-chg: update dependencies

https://www.mercurial-scm.org/repo/hg/rev/208cb7a9d0fa
changeset:   39969:208cb7a9d0fa
user:Yuya Nishihara 
date:Mon Sep 24 16:14:35 2018 +0900
summary: rust-chg: add function to send fds via domain socket

https://www.mercurial-scm.org/repo/hg/rev/a8be2cff613f
changeset:   39970:a8be2cff613f
user:Yuya Nishihara 
date:Mon Sep 24 16:22:03 2018 +0900
summary: rust-chg: add wrapper around C function

https://www.mercurial-scm.org/repo/hg/rev/b1d8acd82d60
changeset:   39971:b1d8acd82d60
user:Yuya Nishihara 
date:Mon Sep 24 16:33:24 2018 +0900
summary: rust-chg: add parser for request messages sent to "S" channel

https://www.mercurial-scm.org/repo/hg/rev/7a0ffdd4af78
changeset:   39972:7a0ffdd4af78
user:Yuya Nishihara 
date:Mon Sep 24 16:59:12 2018 +0900
summary: rust-chg: add future that handles "attachio" request

https://www.mercurial-scm.org/repo/hg/rev/ba447b83cd56
changeset:   39973:ba447b83cd56
user:Yuya Nishihara 
date:Sat Sep 29 21:59:07 2018 +0900
summary: rust-chg: add low-level function to set pager fd blocking

https://www.mercurial-scm.org/repo/hg/rev/a9c5fc436fd5
changeset:   39974:a9c5fc436fd5
user:Yuya Nishihara 
date:Mon Sep 24 18:18:35 2018 +0900
summary: rust-chg: add callback to handle pager and shell command requests

https://www.mercurial-scm.org/repo/hg/rev/571d8eb39095
changeset:   39975:571d8eb39095
user:Yuya Nishihara 
date:Mon Sep 24 18:21:10 2018 +0900
summary: rust-chg: add state machine to handle "runcommand" request with 
cHg extension

https://www.mercurial-scm.org/repo/hg/rev/44840bcc411a
changeset:   39976:44840bcc411a
user:Yuya Nishihara 
date:Mon Sep 24 18:33:46 2018 +0900
summary: rust-chg: port basic socket path handling from cHg of C

https://www.mercurial-scm.org/repo/hg/rev/74da9d999cd7
changeset:   39977:74da9d999cd7
user:Yuya Nishihara 
date:Mon Sep 24 18:57:54 2018 +0900
summary: rust-chg: add Client extensions to run cHg-specific requests

https://www.mercurial-scm.org/repo/hg/rev/045ea159418d
changeset:   39978:045ea159418d
user:Yuya Nishihara 
date:Mon Sep 24 19:06:30 2018 +0900
summary: rust-chg: add interface to chdir the server

https://www.mercurial-scm.org/repo/hg/rev/6bdee4bc181a
changeset:   39979:6bdee4bc181a
user:Yuya Nishihara 
date:Mon Sep 24 19:23:50 2018 +0900
summary: rust-chg: add main program

https://www.mercurial-scm.org/repo/hg/rev/d71e0ba34d9b
changeset:   39980:d71e0ba34d9b
user:Martin von Zweigbergk 
date:Wed Aug 08 23:17:16 2018 -0700
summary: debugcommands: add a debugindexstats command

https://www.mercurial-scm.org/repo/hg/rev/da0319e024c0
changeset:   39981:da0319e024c0
user:spectral 
date:Tue Oct 02 13:37:12 2018 -0700
summary: treemanifests: make _loadlazy tolerate item not on _lazydirs

https://www.mercurial-scm.org/repo/hg/rev/19103e68a698
changeset:   39982:19103e68a698
user:spectral 
date:Tue Oct 02 13:38:26 2018 -0700
summary: treemanifests: make _loadchildrensetlazy just call _loadlazy

https://www.mercurial-scm.org/repo/hg/rev/3cacb74c3a22
changeset:   39983:3cacb74c3a22
user:spectral 
date:Tue Oct 02 13:41:00 2018 -0700
summary: treemanifests: skip extraneous check for item before calling 
_loadlazy

https://www.mercurial-scm.org/repo/hg/rev/731961d972ba
changeset:   39984:731961d972ba
user:spectral 
date:Thu Sep 27 20:16:48 2018 -0700
summary: treemanifests: remove _loadalllazy in _diff()

https://www.mercurial-scm.org/repo/hg/rev/825a636812a4
changeset:   39985:825a636812a4
user:Martin von Zweigbergk 
date:Tue Oct 02 09:11:18 2018 -0700
summary: narrow: avoid overwriting a variable

https://www.mercurial-scm.org/repo/hg/rev/138e2d6d3b53
changeset:   39986:138e2d6d3b53
user:Matt Harbison 
date:Tue Oct 02 22:40:01 2018 -0400
summary: setup: ignore message about disabling 3rd party extensions because 
of version

https://www.mercurial-scm.org/repo/hg/rev/e22016e83c1e
changeset:   39987:e22016e83c1e
user:Pulkit Goyal 
date:Wed Oct 03 13:55:51 2018 +0300
summary: manifest: remove an unused variable caught by pyflakes

https://www.mercurial-scm.org/repo/hg/rev/a8ec8bce14c6
changeset:   39988:a8ec8bce14c6
user:Pulkit Goyal 
date:Wed Oct 03 13:59:19 2018 +0300
summary: py3: whitelist another passing tests 

D4797: storageutil: implement file identifier resolution method (BC)

2018-10-03 Thread martinvonz (Martin von Zweigbergk)
martinvonz added a comment.


  > "0" on an empty store now raises LookupError instead of returning nullid.
  
  I haven't checked the code, but I suspect this was just a special case of 
interpreting "rl.lookup(len(rl))" as nullid. I thought I had fixed all those 
cases about a month ago when I made the index not behave like that (I made only 
-1 look up the nullid), but maybe I missed a case here.
  
  > with the exception of partial hex node matching, we may want to consider 
changing revlog.lookup() as well
  
  Maybe even without the exception? I thought we used partial nodeids only for 
debug commands and maybe we can move the partial matching to a higher level.

REPOSITORY
  rHG Mercurial

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

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


D4852: localrepo: add repository feature when repo can be stream cloned

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG83146d176c03: localrepo: add repository feature when repo 
can be stream cloned (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4852?vs=11630=11640

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

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

CHANGE DETAILS

diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -27,6 +27,8 @@
 REPO_FEATURE_SHARED_STORAGE = b'sharedstore'
 # LFS supported for backing file storage.
 REPO_FEATURE_LFS = b'lfs'
+# Repository supports being stream cloned.
+REPO_FEATURE_STREAM_CLONE = b'streamclone'
 
 class ipeerconnection(interfaceutil.Interface):
 """Represents a "connection" to a repository.
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -795,6 +795,7 @@
 def makefilestorage(requirements, features, **kwargs):
 """Produce a type conforming to ``ilocalrepositoryfilestorage``."""
 features.add(repository.REPO_FEATURE_REVLOG_FILE_STORAGE)
+features.add(repository.REPO_FEATURE_STREAM_CLONE)
 
 if repository.NARROW_REQUIREMENT in requirements:
 return revlognarrowfilestorage



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


D4853: streamclone: don't support stream clone unless repo feature present

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG51f10e6d66c7: streamclone: dont support stream clone 
unless repo feature present (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4853?vs=11631=11641

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

AFFECTED FILES
  mercurial/streamclone.py

CHANGE DETAILS

diff --git a/mercurial/streamclone.py b/mercurial/streamclone.py
--- a/mercurial/streamclone.py
+++ b/mercurial/streamclone.py
@@ -18,6 +18,7 @@
 error,
 phases,
 pycompat,
+repository,
 store,
 util,
 )
@@ -178,6 +179,9 @@
 
 def allowservergeneration(repo):
 """Whether streaming clones are allowed from the server."""
+if repository.REPO_FEATURE_STREAM_CLONE not in repo.features:
+return False
+
 if not repo.ui.configbool('server', 'uncompressed', untrusted=True):
 return False
 



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


D4858: httppeer: report http statistics

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

REVISION SUMMARY
  Now that keepalive.py records HTTP request count and the
  number of bytes sent and received as part of performing those
  requests, we can easily print a report on the activity when
  closing a peer instance!
  
  Exact byte counts are globbed in tests because they are influenced
  by non-deterministic things, such as hostnames and port numbers.
  Plus, the exact byte count isn't too important anyway.
  
  I feel obliged to note that printing the byte count could have
  security implications. e.g. if sending a password via HTTP basic
  auth, the length of that password will influence the byte count
  and the reporting of the byte count could be a side-channel leak
  of the password length. I /think/ this is beyond our threshold
  for concern. But if we think it poses a problem, we can teach the
  byte count logging code to e.g. ignore sensitive HTTP request
  headers. We could also consider not reporting the byte count of
  request headers altogether. But since the wire protocol uses HTTP
  headers for sending command arguments, it is kind of important to
  report their size.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/httppeer.py
  mercurial/url.py
  tests/test-clone-uncompressed.t
  tests/test-clonebundles.t
  tests/test-http-api-httpv2.t
  tests/test-http-protocol.t
  tests/test-lfs-serve-access.t
  tests/test-lfs-serve.t
  tests/test-schemes.t
  tests/test-stream-bundle-v2.t
  tests/test-wireproto-caching.t
  tests/test-wireproto-command-branchmap.t
  tests/test-wireproto-command-capabilities.t
  tests/test-wireproto-command-changesetdata.t
  tests/test-wireproto-command-filedata.t
  tests/test-wireproto-command-heads.t
  tests/test-wireproto-command-known.t
  tests/test-wireproto-command-listkeys.t
  tests/test-wireproto-command-lookup.t
  tests/test-wireproto-command-manifestdata.t
  tests/test-wireproto-command-pushkey.t
  tests/test-wireproto-content-redirects.t
  tests/test-wireproto-exchangev2.t

CHANGE DETAILS

diff --git a/tests/test-wireproto-exchangev2.t 
b/tests/test-wireproto-exchangev2.t
--- a/tests/test-wireproto-exchangev2.t
+++ b/tests/test-wireproto-exchangev2.t
@@ -130,6 +130,7 @@
   received frame(size=0; request=3; stream=2; streamflags=; 
type=command-response; flags=eos)
   updating the branch cache
   new changesets 3390ef850073:caa2a465451d (3 drafts)
+  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
 
 All changesets should have been transferred
 
@@ -256,6 +257,7 @@
   received frame(size=0; request=3; stream=2; streamflags=; 
type=command-response; flags=eos)
   updating the branch cache
   new changesets 3390ef850073:4432d83626e8
+  (sent 6 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ cd client-singlehead
 
@@ -369,6 +371,7 @@
   updating the branch cache
   new changesets cd2534766bec:caa2a465451d (3 drafts)
   (run 'hg update' to get a working copy)
+  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ hg log -G -T '{rev} {node} {phase}\n'
   o  4 caa2a465451dd1facda0f5b12312c355584188a1 draft
@@ -439,6 +442,7 @@
   checking for updated bookmarks
   2 local changesets published
   (run 'hg update' to get a working copy)
+  (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ hg log -G -T '{rev} {node} {phase}\n'
   o  4 caa2a465451dd1facda0f5b12312c355584188a1 public
@@ -555,6 +559,7 @@
   received frame(size=0; request=3; stream=2; streamflags=; 
type=command-response; flags=eos)
   updating the branch cache
   new changesets 3390ef850073:caa2a465451d (1 drafts)
+  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ hg -R client-bookmarks bookmarks
  book-10:3390ef850073
@@ -611,6 +616,7 @@
   checking for updated bookmarks
   updating bookmark book-1
   (run 'hg update' to get a working copy)
+  (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ hg -R client-bookmarks bookmarks
  book-12:cd2534766bec
diff --git a/tests/test-wireproto-content-redirects.t 
b/tests/test-wireproto-content-redirects.t
--- a/tests/test-wireproto-content-redirects.t
+++ b/tests/test-wireproto-content-redirects.t
@@ -317,6 +317,7 @@
   }
 }
   ]
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
 Unknown protocol is filtered from compatible targets
 
@@ -610,6 +611,7 @@
   }
 }
   ]
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
 Missing SNI support filters targets that require SNI
 
@@ -901,6 +903,7 @@
   }
 }
   ]
+  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
 
   $ cat >> $HGRCPATH << EOF
   > [extensions]
@@ -1191,6 +1194,7 @@
   }
 }
   ]
+  (sent 2 HTTP 

D4860: repository: define and use revision flag constants

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

REVISION SUMMARY
  Revlogs have a per-revision 2 byte field holding integer flags that
  define how revision data should be interpreted. For historical reasons,
  these integer values are sent verbatim on the wire protocol as part of
  changegroup data.
  
  From a semantic standpoint, the flags that go out over the wire are
  different from the flags stored internally by revlogs. Failure to
  establish this semantic distinction creates unwanted strong coupling
  between revlog's internals and the wire protocol.
  
  This commit establishes new constants on the repository module that
  define the revision flags used by the wire protocol (and by some
  internal storage APIs, sadly). The changegroups internals documentation
  has been updated to document them explicitly. Various references
  throughout the repo now use the repository constants instead of the
  revlog constants. This is done to make it clear that we're operating
  on generic revision data and this isn't tied to revlogs.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/changegroup.py
  mercurial/help/internals/changegroups.txt
  mercurial/repository.py
  mercurial/revlogutils/constants.py
  mercurial/testing/storage.py
  tests/simplestorerepo.py
  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
@@ -1038,8 +1038,8 @@
   
   There are 3 versions of changegroups: "1", "2", and "3". From a high-
   level, versions "1" and "2" are almost exactly the same, with the only
-  difference being an additional item in the *delta header*.  Version "3"
-  adds support for revlog flags in the *delta header* and optionally
+  difference being an additional item in the *delta header*. Version "3"
+  adds support for stirage flags in the *delta header* and optionally
   exchanging treemanifests (enabled by setting an option on the
   "changegroup" part in the bundle2).
   
@@ -1162,6 +1162,27 @@
   changegroup. This allows the delta to be expressed against any parent,
   which can result in smaller deltas and more efficient encoding of data.
   
+  The *flags* field holds bitwise flags affecting the processing of 
revision
+  data. The following flags are defined:
+  
+  32768
+ Censored revision. The revision's fulltext has been replaced by censor
+ metadata. May only occur on file revisions.
+  
+  16384
+ Ellipsis revision. Revision hash does not match data (likely due to
+ rewritten parents).
+  
+  8192
+ Externally stored. The revision fulltext contains "key:value" "\n"
+ delimited metadata defining an object stored elsewhere. Used by the 
LFS
+ extension.
+  
+  For historical reasons, the integer values are identical to revlog 
version
+  1 per-revision storage flags and correspond to bits being set in this
+  2-byte field. Bits were allocated starting from the most-significant bit,
+  hence the reverse ordering and allocation of these flags.
+  
   Changeset Segment
   =
   
@@ -3435,8 +3456,8 @@
   
   There are 3 versions of changegroups: 1, 2, and 
3. From a
   high-level, versions 1 and 2 are almost exactly the 
same, with the
-  only difference being an additional item in the *delta header*.  Version
-  3 adds support for revlog flags in the *delta header* and 
optionally
+  only difference being an additional item in the *delta header*. Version
+  3 adds support for stirage flags in the *delta header* and 
optionally
   exchanging treemanifests (enabled by setting an option on the
   changegroup part in the bundle2).
   
@@ -3582,6 +3603,24 @@
   changegroup. This allows the delta to be expressed against any parent,
   which can result in smaller deltas and more efficient encoding of data.
   
+  
+  The *flags* field holds bitwise flags affecting the processing of revision
+  data. The following flags are defined:
+  
+  
+   32768
+   Censored revision. The revision's fulltext has been replaced by censor 
metadata. May only occur on file revisions.
+   16384
+   Ellipsis revision. Revision hash does not match data (likely due to 
rewritten parents).
+   8192
+   Externally stored. The revision fulltext contains key:value 
\n delimited metadata defining an object stored elsewhere. Used by 
the LFS extension.
+  
+  
+  For historical reasons, the integer values are identical to revlog version 1
+  per-revision storage flags and correspond to bits being set in this 2-byte
+  field. Bits were allocated starting from the most-significant bit, hence the
+  reverse ordering and allocation of these flags.
+  
   Changeset Segment
   
   The *changeset segment* consists of a single *delta group* holding
diff --git 

D4859: exchangev2: add progress bar around manifest scanning

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

REVISION SUMMARY
  This can take a long time on large repositories. Let's add a progress
  bar so we don't have long periods where it isn't obvious what is
  going on.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/exchangev2.py

CHANGE DETAILS

diff --git a/mercurial/exchangev2.py b/mercurial/exchangev2.py
--- a/mercurial/exchangev2.py
+++ b/mercurial/exchangev2.py
@@ -320,6 +320,9 @@
 ml = repo.manifestlog
 fnodes = collections.defaultdict(dict)
 
+progress = repo.ui.makeprogress(
+_('scanning manifests'), total=len(manifestnodes))
+
 for manifestnode in manifestnodes:
 m = ml.get(b'', manifestnode)
 
@@ -334,6 +337,8 @@
 for path, fnode in md.items():
 fnodes[path].setdefault(fnode, manifestnode)
 
+progress.increment()
+
 return fnodes
 
 def _fetchfiles(repo, tr, remote, fnodes, linkrevs):



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


D4852: localrepo: add repository feature when repo can be stream cloned

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

REVISION SUMMARY
  Right now, the wire protocol server assumes all repository objects can
  be stream cloned (unless the stream clone feature is disabled via
  config option).
  
  But not all storage backends or repository objects may support stream
  clone.
  
  This commit defines a repository feature denoting whether stream clone
  is supported. The feature is defined for revlog-based repositories,
  which should currently be "all repositories."

REPOSITORY
  rHG Mercurial

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

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

CHANGE DETAILS

diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -27,6 +27,8 @@
 REPO_FEATURE_SHARED_STORAGE = b'sharedstore'
 # LFS supported for backing file storage.
 REPO_FEATURE_LFS = b'lfs'
+# Repository supports being stream cloned.
+REPO_FEATURE_STREAM_CLONE = b'streamclone'
 
 class ipeerconnection(interfaceutil.Interface):
 """Represents a "connection" to a repository.
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -795,6 +795,7 @@
 def makefilestorage(requirements, features, **kwargs):
 """Produce a type conforming to ``ilocalrepositoryfilestorage``."""
 features.add(repository.REPO_FEATURE_REVLOG_FILE_STORAGE)
+features.add(repository.REPO_FEATURE_STREAM_CLONE)
 
 if repository.NARROW_REQUIREMENT in requirements:
 return revlognarrowfilestorage



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


D4857: keepalive: track number of bytes received from an HTTP response

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

REVISION SUMMARY
  We also bubble the byte count up to the HTTPConnection instance and its
  parent opener at read time. Unlike sending, there isn't a clear
  "end of response" signal we can intercept to defer updating the
  accounting.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/keepalive.py

CHANGE DETAILS

diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -392,6 +392,7 @@
   method=method, **extrakw)
 self.fileno = sock.fileno
 self.code = None
+self.receivedbytescount = 0
 self._rbuf = ''
 self._rbufsize = 8096
 self._handler = None # inserted by the handler later
@@ -436,7 +437,16 @@
 # if it's not empty.
 s = self._rbuf
 self._rbuf = ''
-s += self._raw_read(amt)
+data = self._raw_read(amt)
+
+self.receivedbytescount += len(data)
+self._connection.receivedbytescount += len(data)
+try:
+self._handler.parent.receivedbytescount += len(data)
+except AttributeError:
+pass
+
+s += data
 return s
 
 # stolen from Python SVN #68532 to fix issue1088
@@ -512,6 +522,13 @@
 if not new:
 break
 
+self.receivedbytescount += len(new)
+self._connection.receivedbytescount += len(new)
+try:
+self._handler.parent.receivedbytescount += len(new)
+except AttributeError:
+pass
+
 chunks.append(new)
 i = new.find('\n')
 if i >= 0:
@@ -557,6 +574,14 @@
 return total
 mv = memoryview(dest)
 got = self._raw_readinto(mv[have:total])
+
+self.receivedbytescount += got
+self._connection.receivedbytescount += got
+try:
+self._handler.receivedbytescount += got
+except AttributeError:
+pass
+
 dest[0:have] = self._rbuf
 got += len(self._rbuf)
 self._rbuf = ''
@@ -643,6 +668,7 @@
 def __init__(self, *args, **kwargs):
 httplib.HTTPConnection.__init__(self, *args, **kwargs)
 self.sentbytescount = 0
+self.receivedbytescount = 0
 
 #
 #   TEST FUNCTIONS



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


D4855: url: have httpsconnection inherit from our custom HTTPConnection

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

REVISION SUMMARY
  This will ensure that any customizations we perform to HTTPConnection
  will be available to httpsconnection.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/keepalive.py
  mercurial/url.py

CHANGE DETAILS

diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -339,16 +339,16 @@
 return logginghttpconnection(createconnection, *args, **kwargs)
 
 if has_https:
-class httpsconnection(httplib.HTTPConnection):
+class httpsconnection(keepalive.HTTPConnection):
 response_class = keepalive.HTTPResponse
 default_port = httplib.HTTPS_PORT
 # must be able to send big bundle as stream.
 send = _gen_sendfile(keepalive.safesend)
 getresponse = keepalive.wrapgetresponse(httplib.HTTPConnection)
 
 def __init__(self, host, port=None, key_file=None, cert_file=None,
  *args, **kwargs):
-httplib.HTTPConnection.__init__(self, host, port, *args, **kwargs)
+keepalive.HTTPConnection.__init__(self, host, port, *args, 
**kwargs)
 self.key_file = key_file
 self.cert_file = cert_file
 
diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -615,6 +615,10 @@
 return safegetresponse
 
 class HTTPConnection(httplib.HTTPConnection):
+# url.httpsconnection inherits from this. So when adding/removing
+# attributes, be sure to audit httpsconnection() for unintended
+# consequences.
+
 # use the modified response class
 response_class = HTTPResponse
 send = safesend



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


D4856: keepalive: track request count and bytes sent

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

REVISION SUMMARY
  I want wire protocol interactions to report the number of
  requests made and bytes transferred.
  
  This commit teaches the very low-level custom HTTPConnection class
  to track the number of bytes sent to the socket. This may vary from
  the number of bytes that go on the wire due to e.g. TLS. That's OK.
  
  KeepAliveHandler is taught to track the total number of requests
  and total number of bytes sent across all requests.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/keepalive.py

CHANGE DETAILS

diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -174,6 +174,8 @@
 class KeepAliveHandler(object):
 def __init__(self):
 self._cm = ConnectionManager()
+self.requestscount = 0
+self.sentbytescount = 0
 
  Connection Management
 def open_connections(self):
@@ -312,6 +314,8 @@
 return r
 
 def _start_transaction(self, h, req):
+oldbytescount = h.sentbytescount
+
 # What follows mostly reimplements HTTPConnection.request()
 # except it adds self.parent.addheaders in the mix and sends headers
 # in a deterministic order (to make testing easier).
@@ -346,6 +350,16 @@
 if urllibcompat.hasdata(req):
 h.send(data)
 
+# This will fail to record events in case of I/O failure. That's OK.
+self.requestscount += 1
+self.sentbytescount += h.sentbytescount - oldbytescount
+
+try:
+self.parent.requestscount += 1
+self.parent.sentbytescount += h.sentbytescount - oldbytescount
+except AttributeError:
+pass
+
 class HTTPHandler(KeepAliveHandler, urlreq.httphandler):
 pass
 
@@ -585,9 +599,11 @@
 data = read(blocksize)
 while data:
 self.sock.sendall(data)
+self.sentbytescount += len(data)
 data = read(blocksize)
 else:
 self.sock.sendall(str)
+self.sentbytescount += len(str)
 except socket.error as v:
 reraise = True
 if v[0] == errno.EPIPE:  # Broken pipe
@@ -624,6 +640,9 @@
 send = safesend
 getresponse = wrapgetresponse(httplib.HTTPConnection)
 
+def __init__(self, *args, **kwargs):
+httplib.HTTPConnection.__init__(self, *args, **kwargs)
+self.sentbytescount = 0
 
 #
 #   TEST FUNCTIONS



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


D4854: cborutil: change buffering strategy

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

REVISION SUMMARY
  Profiling revealed that we were spending a lot of time on the
  line that was concatenating the old buffer with the incoming data
  when attempting to decode long byte strings, such as manifest
  revisions.
  
  Essentially, we were feeding N chunks of size len(X) << len(Y) into
  decode() and continuously allocating a new, larger buffer to hold
  the undecoded input. This created substantial memory churn and
  slowed down execution.
  
  Changing the code to aggregate pending chunks in a list until we
  have enough data to fully decode the next atom makes things much
  more efficient.
  
  I don't have exact data, but I recall the old code spending >1s
  on manifest fulltexts from the mozilla-unified repo. The new code
  doesn't significantly appear in profile output.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/utils/cborutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/cborutil.py b/mercurial/utils/cborutil.py
--- a/mercurial/utils/cborutil.py
+++ b/mercurial/utils/cborutil.py
@@ -913,7 +913,8 @@
 """
 def __init__(self):
 self._decoder = sansiodecoder()
-self._leftover = None
+self._chunks = []
+self._wanted = 0
 
 def decode(self, b):
 """Attempt to decode bytes to CBOR values.
@@ -924,19 +925,40 @@
 * Integer number of bytes decoded from the new input.
 * Integer number of bytes wanted to decode the next value.
 """
+# Our strategy for buffering is to aggregate the incoming chunks in a
+# list until we've received enough data to decode the next item.
+# This is slightly more complicated than using an ``io.BytesIO``
+# or continuously concatenating incoming data. However, because it
+# isn't constantly reallocating backing memory for a growing buffer,
+# it prevents excessive memory thrashing and is significantly faster,
+# especially in cases where the percentage of input chunks that don't
+# decode into a full item is high.
 
-if self._leftover:
-oldlen = len(self._leftover)
-b = self._leftover + b
-self._leftover = None
+if self._chunks:
+# A previous call said we needed N bytes to decode the next item.
+# But this call doesn't provide enough data. We buffer the incoming
+# chunk without attempting to decode.
+if len(b) < self._wanted:
+self._chunks.append(b)
+self._wanted -= len(b)
+return False, 0, self._wanted
+
+# Else we may have enough data to decode the next item. Aggregate
+# old data with new and reset the buffer.
+newlen = len(b)
+self._chunks.append(b)
+b = b''.join(self._chunks)
+self._chunks = []
+oldlen = len(b) - newlen
+
 else:
-b = b
 oldlen = 0
 
 available, readcount, wanted = self._decoder.decode(b)
+self._wanted = wanted
 
 if readcount < len(b):
-self._leftover = b[readcount:]
+self._chunks.append(b[readcount:])
 
 return available, readcount - oldlen, wanted
 



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


D4853: streamclone: don't support stream clone unless repo feature present

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

REVISION SUMMARY
  This change means custom repository types must opt in to enabling
  stream clone. This seems reasonable, as stream clones are a very
  low-level feature that has historically assumed the use of revlogs
  and the layout of .hg/ that they entail.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/streamclone.py

CHANGE DETAILS

diff --git a/mercurial/streamclone.py b/mercurial/streamclone.py
--- a/mercurial/streamclone.py
+++ b/mercurial/streamclone.py
@@ -18,6 +18,7 @@
 error,
 phases,
 pycompat,
+repository,
 store,
 util,
 )
@@ -178,6 +179,9 @@
 
 def allowservergeneration(repo):
 """Whether streaming clones are allowed from the server."""
+if repository.REPO_FEATURE_STREAM_CLONE not in repo.features:
+return False
+
 if not repo.ui.configbool('server', 'uncompressed', untrusted=True):
 return False
 



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


D2679: [PoC] obsolete: config option to enable local only obsolescence mode

2018-10-03 Thread martinvonz (Martin von Zweigbergk)
martinvonz added a comment.


  Here's a case I just ran into where I would have liked to de-obsolete a 
commit:
  
  1. Someone queues a patch and pushes to central repo. Repo looks like this:
  
o  B
|
o  A
  
  
  
  2. I fix a typo and and amend, but I forget to push.
  3. I build my own commit on top. My repo:
  
o  X
|
o  B'
|
o  A
  
  
  
  4. Someone pushes new patches to central repo. Central repo:
  
o  C
|
o  B
|
o  A
  
  
  
  5. I pull from central repo. My repo:
  
o  C
|
x B
|
| o  X
| |
| o  B'
|/
o  A
  
  
  
  6. I move my change onto the new upstream and prune my local B' that's now 
unwanted:
  
o X'
|
o  C
|
x B
|
| x B'
|/
o  A
  
  If upstream history was really just a single commit (`C` above), then the 
obvious thing to do is to just evolve that commit and push it. However, 
sometimes there is a long chain on top, and in my case there was a separate 
commit upstream that fixed the typo I fixed when I amended `B` and it would be 
a little confusing to explain why someone's fix was "lost".  So I'd prefer to 
mark B as no longer obsolete. I know I can do that with `hg strip B'`, but that 
also strips `X`, which is probably not a big loss, but it's a weird 
side-effect. Perhaps all I'm asking for is a way of dropping the obsmarker 
between `B` and `B'`. I don't know what the best UI for that would be, though. 
For now, I guess I'll use `hg strip`.

REPOSITORY
  rHG Mercurial

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

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


D4803: storageutil: extract most of emitrevisions() to standalone function

2018-10-03 Thread indygreg (Gregory Szorc)
indygreg added a comment.


  FWIW I would like to rewrite all of filelog (and this API) to be in terms of 
nodes. My hands are somewhat tied with this function due to how all the 
functions are implemented in terms of revs today. We'll get there eventually...

REPOSITORY
  rHG Mercurial

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

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


D4777: wireprotov2: server support for sending content redirects

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGb099e6032f38: wireprotov2: server support for sending 
content redirects (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4777?vs=11448=11628

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

AFFECTED FILES
  mercurial/wireprotoframing.py
  mercurial/wireprototypes.py
  mercurial/wireprotov2server.py
  tests/test-http-api-httpv2.t
  tests/test-wireproto-content-redirects.t
  tests/test-wireproto-serverreactor.py
  tests/wireprotosimplecache.py

CHANGE DETAILS

diff --git a/tests/wireprotosimplecache.py b/tests/wireprotosimplecache.py
--- a/tests/wireprotosimplecache.py
+++ b/tests/wireprotosimplecache.py
@@ -12,6 +12,7 @@
 registrar,
 repository,
 util,
+wireprotoserver,
 wireprototypes,
 wireprotov2server,
 )
@@ -25,18 +26,59 @@
 configtable = {}
 configitem = registrar.configitem(configtable)
 
+configitem('simplecache', 'cacheapi',
+   default=False)
 configitem('simplecache', 'cacheobjects',
default=False)
 configitem('simplecache', 'redirectsfile',
default=None)
 
+# API handler that makes cached keys available.
+def handlecacherequest(rctx, req, res, checkperm, urlparts):
+if rctx.repo.ui.configbool('simplecache', 'cacheobjects'):
+res.status = b'500 Internal Server Error'
+res.setbodybytes(b'cacheobjects not supported for api server')
+return
+
+if not urlparts:
+res.status = b'200 OK'
+res.headers[b'Content-Type'] = b'text/plain'
+res.setbodybytes(b'simple cache server')
+return
+
+key = b'/'.join(urlparts)
+
+if key not in CACHE:
+res.status = b'404 Not Found'
+res.headers[b'Content-Type'] = b'text/plain'
+res.setbodybytes(b'key not found in cache')
+return
+
+res.status = b'200 OK'
+res.headers[b'Content-Type'] = b'application/mercurial-cbor'
+res.setbodybytes(CACHE[key])
+
+def cachedescriptor(req, repo):
+return {}
+
+wireprotoserver.API_HANDLERS[b'simplecache'] = {
+'config': (b'simplecache', b'cacheapi'),
+'handler': handlecacherequest,
+'apidescriptor': cachedescriptor,
+}
+
 @interfaceutil.implementer(repository.iwireprotocolcommandcacher)
 class memorycacher(object):
-def __init__(self, ui, command, encodefn):
+def __init__(self, ui, command, encodefn, redirecttargets, redirecthashes,
+ req):
 self.ui = ui
 self.encodefn = encodefn
+self.redirecttargets = redirecttargets
+self.redirecthashes = redirecthashes
+self.req = req
 self.key = None
 self.cacheobjects = ui.configbool('simplecache', 'cacheobjects')
+self.cacheapi = ui.configbool('simplecache', 'cacheapi')
 self.buffered = []
 
 ui.log('simplecache', 'cacher constructed for %s\n', command)
@@ -65,6 +107,37 @@
 entry = CACHE[self.key]
 self.ui.log('simplecache', 'cache hit for %s\n', self.key)
 
+redirectable = True
+
+if not self.cacheapi:
+redirectable = False
+elif not self.redirecttargets:
+redirectable = False
+else:
+clienttargets = set(self.redirecttargets)
+ourtargets = set(t[b'name'] for t in loadredirecttargets(self.ui))
+
+# We only ever redirect to a single target (for now). So we don't
+# need to store which target matched.
+if not clienttargets & ourtargets:
+redirectable = False
+
+if redirectable:
+paths = self.req.dispatchparts[:-3]
+paths.append(b'simplecache')
+paths.append(self.key)
+
+url = b'%s/%s' % (self.req.advertisedbaseurl, b'/'.join(paths))
+
+#url = b'http://example.com/%s' % self.key
+self.ui.log('simplecache', 'sending content redirect for %s to '
+   '%s\n', self.key, url)
+response = wireprototypes.alternatelocationresponse(
+url=url,
+mediatype=b'application/mercurial-cbor')
+
+return {'objs': [response]}
+
 if self.cacheobjects:
 return {
 'objs': entry,
@@ -91,8 +164,10 @@
 
 return []
 
-def makeresponsecacher(orig, repo, proto, command, args, objencoderfn):
-return memorycacher(repo.ui, command, objencoderfn)
+def makeresponsecacher(orig, repo, proto, command, args, objencoderfn,
+   redirecttargets, redirecthashes):
+return memorycacher(repo.ui, command, objencoderfn, redirecttargets,
+redirecthashes, proto._req)
 
 def loadredirecttargets(ui):
 path = ui.config('simplecache', 'redirectsfile')
diff --git a/tests/test-wireproto-serverreactor.py 
b/tests/test-wireproto-serverreactor.py
--- 

D4778: wireprotov2: client support for following content redirects

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG7e807b8a9e56: wireprotov2: client support for following 
content redirects (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4778?vs=11449=11629

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

AFFECTED FILES
  mercurial/httppeer.py
  mercurial/wireprotov2peer.py
  tests/test-wireproto-content-redirects.t

CHANGE DETAILS

diff --git a/tests/test-wireproto-content-redirects.t 
b/tests/test-wireproto-content-redirects.t
--- a/tests/test-wireproto-content-redirects.t
+++ b/tests/test-wireproto-content-redirects.t
@@ -1354,8 +1354,33 @@
   s> 0\r\n
   s> \r\n
   received frame(size=0; request=1; stream=2; streamflags=; 
type=command-response; flags=eos)
-  abort: redirect responses not yet supported
-  [255]
+  (following redirect to 
http://*:$HGPORT/api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0) 
(glob)
+  s> GET /api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0 
HTTP/1.1\r\n
+  s> Accept-Encoding: identity\r\n
+  s> accept: application/mercurial-cbor\r\n
+  s> host: *:$HGPORT\r\n (glob)
+  s> user-agent: Mercurial debugwireproto\r\n
+  s> \r\n
+  s> makefile('rb', None)
+  s> HTTP/1.1 200 OK\r\n
+  s> Server: testing stub value\r\n
+  s> Date: $HTTP_DATE$\r\n
+  s> Content-Type: application/mercurial-cbor\r\n
+  s> Content-Length: 91\r\n
+  s> \r\n
+  s> 
\xa1Jtotalitems\x01\xa2DnodeT\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN\x82T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
+  response: gen[
+{
+  b'totalitems': 1
+},
+{
+  b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN',
+  b'parents': [
+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+  ]
+}
+  ]
 
   $ cat error.log
   $ killdaemons.py
diff --git a/mercurial/wireprotov2peer.py b/mercurial/wireprotov2peer.py
--- a/mercurial/wireprotov2peer.py
+++ b/mercurial/wireprotov2peer.py
@@ -13,8 +13,12 @@
 from . import (
 encoding,
 error,
+pycompat,
 sslutil,
+url as urlmod,
+util,
 wireprotoframing,
+wireprototypes,
 )
 from .utils import (
 cborutil,
@@ -112,9 +116,10 @@
 events occur.
 """
 
-def __init__(self, requestid, command):
+def __init__(self, requestid, command, fromredirect=False):
 self.requestid = requestid
 self.command = command
+self.fromredirect = fromredirect
 
 # Whether all remote input related to this command has been
 # received.
@@ -132,6 +137,7 @@
 self._pendingevents = []
 self._decoder = cborutil.bufferingdecoder()
 self._seeninitial = False
+self._redirect = None
 
 def _oninputcomplete(self):
 with self._lock:
@@ -146,10 +152,19 @@
 
 with self._lock:
 for o in self._decoder.getavailable():
-if not self._seeninitial:
+if not self._seeninitial and not self.fromredirect:
 self._handleinitial(o)
 continue
 
+# We should never see an object after a content redirect,
+# as the spec says the main status object containing the
+# content redirect is the only object in the stream. Fail
+# if we see a misbehaving server.
+if self._redirect:
+raise error.Abort(_('received unexpected response data '
+'after content redirect; the remote is 
'
+'buggy'))
+
 self._pendingevents.append(o)
 
 self._serviceable.set()
@@ -160,7 +175,16 @@
 return
 
 elif o[b'status'] == b'redirect':
-raise error.Abort(_('redirect responses not yet supported'))
+l = o[b'location']
+self._redirect = wireprototypes.alternatelocationresponse(
+url=l[b'url'],
+mediatype=l[b'mediatype'],
+size=l.get(b'size'),
+fullhashes=l.get(b'fullhashes'),
+fullhashseed=l.get(b'fullhashseed'),
+serverdercerts=l.get(b'serverdercerts'),
+servercadercerts=l.get(b'servercadercerts'))
+return
 
 atoms = [{'msg': o[b'error'][b'message']}]
 if b'args' in o[b'error']:
@@ -214,13 +238,17 @@
 with the higher-level peer API.
 """
 
-def __init__(self, ui, clientreactor):
+def __init__(self, ui, clientreactor, opener=None,
+ requestbuilder=util.urlreq.request):
 self._ui = ui
 

D4776: wireprotov2: client support for advertising redirect targets

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG86b22a4cfab1: wireprotov2: client support for advertising 
redirect targets (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4776?vs=11447=11627

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

AFFECTED FILES
  mercurial/httppeer.py
  mercurial/wireprotoframing.py
  mercurial/wireprotov2peer.py
  tests/test-wireproto-clientreactor.py
  tests/test-wireproto-content-redirects.t

CHANGE DETAILS

diff --git a/tests/test-wireproto-content-redirects.t 
b/tests/test-wireproto-content-redirects.t
--- a/tests/test-wireproto-content-redirects.t
+++ b/tests/test-wireproto-content-redirects.t
@@ -57,16 +57,17 @@
   s> Content-Length: 1970\r\n
   s> \r\n
   s> 
\xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd8batch
 branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset 
compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  (remote redirect target target-a is compatible)
   sending capabilities command
   s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
   s> Accept-Encoding: identity\r\n
   s> accept: application/mercurial-exp-framing-0005\r\n
   s> content-type: application/mercurial-exp-framing-0005\r\n
-  s> content-length: 27\r\n
+  s> content-length: 75\r\n
   s> host: $LOCALIP:$HGPORT\r\n (glob)
   s> user-agent: Mercurial debugwireproto\r\n
   s> \r\n
-  s> \x13\x00\x00\x01\x00\x01\x01\x11\xa1DnameLcapabilities
+  s> 
C\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
   s> makefile('rb', None)
   s> HTTP/1.1 200 OK\r\n
   s> Server: testing stub value\r\n
@@ -308,6 +309,8 @@
 }
   ]
 
+Unknown protocol is filtered from compatible targets
+
   $ cat > redirects.py << EOF
   > [
   >   {
@@ -344,16 +347,18 @@
   s> Content-Length: 1997\r\n
   s> \r\n
   s> 

D4775: wireprotov2: advertise redirect targets in capabilities

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG10cf8b116dd8: wireprotov2: advertise redirect targets in 
capabilities (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4775?vs=11446=11626

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

AFFECTED FILES
  mercurial/wireprotov2server.py
  tests/test-wireproto-content-redirects.t
  tests/wireprotosimplecache.py

CHANGE DETAILS

diff --git a/tests/wireprotosimplecache.py b/tests/wireprotosimplecache.py
--- a/tests/wireprotosimplecache.py
+++ b/tests/wireprotosimplecache.py
@@ -17,6 +17,7 @@
 )
 from mercurial.utils import (
 interfaceutil,
+stringutil,
 )
 
 CACHE = None
@@ -26,6 +27,8 @@
 
 configitem('simplecache', 'cacheobjects',
default=False)
+configitem('simplecache', 'redirectsfile',
+   default=None)
 
 @interfaceutil.implementer(repository.iwireprotocolcommandcacher)
 class memorycacher(object):
@@ -91,10 +94,25 @@
 def makeresponsecacher(orig, repo, proto, command, args, objencoderfn):
 return memorycacher(repo.ui, command, objencoderfn)
 
+def loadredirecttargets(ui):
+path = ui.config('simplecache', 'redirectsfile')
+if not path:
+return []
+
+with open(path, 'rb') as fh:
+s = fh.read()
+
+return stringutil.evalpythonliteral(s)
+
+def getadvertisedredirecttargets(orig, repo, proto):
+return loadredirecttargets(repo.ui)
+
 def extsetup(ui):
 global CACHE
 
 CACHE = util.lrucachedict(1)
 
 extensions.wrapfunction(wireprotov2server, 'makeresponsecacher',
 makeresponsecacher)
+extensions.wrapfunction(wireprotov2server, 'getadvertisedredirecttargets',
+getadvertisedredirecttargets)
diff --git a/tests/test-wireproto-content-redirects.t 
b/tests/test-wireproto-content-redirects.t
new file mode 100644
--- /dev/null
+++ b/tests/test-wireproto-content-redirects.t
@@ -0,0 +1,601 @@
+  $ . $TESTDIR/wireprotohelpers.sh
+
+  $ hg init server
+  $ enablehttpv2 server
+  $ cd server
+  $ cat >> .hg/hgrc << EOF
+  > [extensions]
+  > simplecache = $TESTDIR/wireprotosimplecache.py
+  > EOF
+
+  $ echo a0 > a
+  $ echo b0 > b
+  $ hg -q commit -A -m 'commit 0'
+  $ echo a1 > a
+  $ hg commit -m 'commit 1'
+
+  $ hg --debug debugindex -m
+ rev linkrev nodeid   p1   
p2
+   0   0 992f4779029a3df8d0666d00bb924f69634e2641 
 

+   1   1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 
992f4779029a3df8d0666d00bb924f69634e2641 

+
+  $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d 
--pid-file hg.pid -E error.log
+  $ cat hg.pid > $DAEMON_PIDS
+
+  $ cat > redirects.py << EOF
+  > [
+  >   {
+  > b'name': b'target-a',
+  > b'protocol': b'http',
+  > b'snirequired': False,
+  > b'tlsversions': [b'1.2', b'1.3'],
+  > b'uris': [b'http://example.com/'],
+  >   },
+  > ]
+  > EOF
+
+Redirect targets advertised when configured
+
+  $ sendhttpv2peerhandshake << EOF
+  > command capabilities
+  > EOF
+  creating http peer for wire protocol version 2
+  s> GET /?cmd=capabilities HTTP/1.1\r\n
+  s> Accept-Encoding: identity\r\n
+  s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
+  s> x-hgproto-1: cbor\r\n
+  s> x-hgupgrade-1: exp-http-v2-0002\r\n
+  s> accept: application/mercurial-0.1\r\n
+  s> host: $LOCALIP:$HGPORT\r\n (glob)
+  s> user-agent: Mercurial debugwireproto\r\n
+  s> \r\n
+  s> makefile('rb', None)
+  s> HTTP/1.1 200 OK\r\n
+  s> Server: testing stub value\r\n
+  s> Date: $HTTP_DATE$\r\n
+  s> Content-Type: application/mercurial-cbor\r\n
+  s> Content-Length: 1970\r\n
+  s> \r\n
+  s> 

D4773: wireprotov2: support response caching

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGc537144fdbef: wireprotov2: support response caching 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4773?vs=11444=11624

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

AFFECTED FILES
  mercurial/repository.py
  mercurial/wireprototypes.py
  mercurial/wireprotov2server.py
  tests/test-wireproto-caching.t
  tests/wireprotosimplecache.py

CHANGE DETAILS

diff --git a/tests/wireprotosimplecache.py b/tests/wireprotosimplecache.py
new file mode 100644
--- /dev/null
+++ b/tests/wireprotosimplecache.py
@@ -0,0 +1,100 @@
+# wireprotosimplecache.py - Extension providing in-memory wire protocol cache
+#
+# Copyright 2018 Gregory Szorc 
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from __future__ import absolute_import
+
+from mercurial import (
+extensions,
+registrar,
+repository,
+util,
+wireprototypes,
+wireprotov2server,
+)
+from mercurial.utils import (
+interfaceutil,
+)
+
+CACHE = None
+
+configtable = {}
+configitem = registrar.configitem(configtable)
+
+configitem('simplecache', 'cacheobjects',
+   default=False)
+
+@interfaceutil.implementer(repository.iwireprotocolcommandcacher)
+class memorycacher(object):
+def __init__(self, ui, command, encodefn):
+self.ui = ui
+self.encodefn = encodefn
+self.key = None
+self.cacheobjects = ui.configbool('simplecache', 'cacheobjects')
+self.buffered = []
+
+ui.log('simplecache', 'cacher constructed for %s\n', command)
+
+def __enter__(self):
+return self
+
+def __exit__(self, exctype, excvalue, exctb):
+if exctype:
+self.ui.log('simplecache', 'cacher exiting due to error\n')
+
+def adjustcachekeystate(self, state):
+# Needed in order to make tests deterministic. Don't copy this
+# pattern for production caches!
+del state[b'repo']
+
+def setcachekey(self, key):
+self.key = key
+return True
+
+def lookup(self):
+if self.key not in CACHE:
+self.ui.log('simplecache', 'cache miss for %s\n', self.key)
+return None
+
+entry = CACHE[self.key]
+self.ui.log('simplecache', 'cache hit for %s\n', self.key)
+
+if self.cacheobjects:
+return {
+'objs': entry,
+}
+else:
+return {
+'objs': [wireprototypes.encodedresponse(entry)],
+}
+
+def onobject(self, obj):
+if self.cacheobjects:
+self.buffered.append(obj)
+else:
+self.buffered.extend(self.encodefn(obj))
+
+yield obj
+
+def onfinished(self):
+self.ui.log('simplecache', 'storing cache entry for %s\n', self.key)
+if self.cacheobjects:
+CACHE[self.key] = self.buffered
+else:
+CACHE[self.key] = b''.join(self.buffered)
+
+return []
+
+def makeresponsecacher(orig, repo, proto, command, args, objencoderfn):
+return memorycacher(repo.ui, command, objencoderfn)
+
+def extsetup(ui):
+global CACHE
+
+CACHE = util.lrucachedict(1)
+
+extensions.wrapfunction(wireprotov2server, 'makeresponsecacher',
+makeresponsecacher)
diff --git a/tests/test-wireproto-caching.t b/tests/test-wireproto-caching.t
new file mode 100644
--- /dev/null
+++ b/tests/test-wireproto-caching.t
@@ -0,0 +1,645 @@
+  $ . $TESTDIR/wireprotohelpers.sh
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > blackbox =
+  > [blackbox]
+  > track = simplecache
+  > EOF
+  $ hg init server
+  $ enablehttpv2 server
+  $ cd server
+  $ cat >> .hg/hgrc << EOF
+  > [extensions]
+  > simplecache = $TESTDIR/wireprotosimplecache.py
+  > EOF
+
+  $ echo a0 > a
+  $ echo b0 > b
+  $ hg -q commit -A -m 'commit 0'
+  $ echo a1 > a
+  $ hg commit -m 'commit 1'
+  $ echo b1 > b
+  $ hg commit -m 'commit 2'
+  $ echo a2 > a
+  $ echo b2 > b
+  $ hg commit -m 'commit 3'
+
+  $ hg log -G -T '{rev}:{node} {desc}'
+  @  3:50590a86f3ff5d1e9a1624a7a6957884565cc8e8 commit 3
+  |
+  o  2:4d01eda50c6ac5f7e89cbe1880143a32f559c302 commit 2
+  |
+  o  1:4432d83626e8a98655f062ec1f2a43b07f7fbbb0 commit 1
+  |
+  o  0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
+  
+
+  $ hg --debug debugindex -m
+ rev linkrev nodeid   p1   
p2
+   0   0 992f4779029a3df8d0666d00bb924f69634e2641 
 

+   1   1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 
992f4779029a3df8d0666d00bb924f69634e2641 

+   2   2 a8853dafacfca6fc807055a660d8b835141a3bb4 

D4769: debugcommands: print all CBOR objects

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG426cb2859013: debugcommands: print all CBOR objects 
(authored by indygreg, committed by ).

CHANGED PRIOR TO COMMIT
  https://phab.mercurial-scm.org/D4769?vs=11440=11620#toc

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4769?vs=11440=11620

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

AFFECTED FILES
  mercurial/debugcommands.py
  tests/test-wireproto-command-capabilities.t

CHANGE DETAILS

diff --git a/tests/test-wireproto-command-capabilities.t 
b/tests/test-wireproto-command-capabilities.t
--- a/tests/test-wireproto-command-capabilities.t
+++ b/tests/test-wireproto-command-capabilities.t
@@ -146,11 +146,13 @@
   s> Content-Length: *\r\n (glob)
   s> \r\n
   s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xd3batch branchmap 
$USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ 
getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  cbor> {
-b'apibase': b'api/',
-b'apis': {},
-b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ 
changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
-  }
+  cbor> [
+{
+  b'apibase': b'api/',
+  b'apis': {},
+  b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ 
changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
+}
+  ]
 
 Restart server to enable HTTPv2
 
@@ -183,11 +185,13 @@
   s> Content-Length: *\r\n (glob)
   s> \r\n
   s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xd3batch branchmap 
$USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ 
getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  cbor> {
-b'apibase': b'api/',
-b'apis': {},
-b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ 
changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
-  }
+  cbor> [
+{
+  b'apibase': b'api/',
+  b'apis': {},
+  b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ 
changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
+}
+  ]
 
 Request for HTTPv2 service returns information about it
 
@@ -213,204 +217,206 @@
   s> Content-Length: *\r\n (glob)
   s> \r\n
   s> 
\xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch
 branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset 
compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 
httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey 
streamreqs=generaldelta,revlogv1 

D4774: wireprotov2: define semantics for content redirects

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG33eb670e2834: wireprotov2: define semantics for content 
redirects (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4774?vs=11445=11625

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

AFFECTED FILES
  mercurial/help/internals/wireprotocolrpc.txt
  mercurial/help/internals/wireprotocolv2.txt

CHANGE DETAILS

diff --git a/mercurial/help/internals/wireprotocolv2.txt 
b/mercurial/help/internals/wireprotocolv2.txt
--- a/mercurial/help/internals/wireprotocolv2.txt
+++ b/mercurial/help/internals/wireprotocolv2.txt
@@ -111,6 +111,38 @@
requirements can be used to determine whether a client can read a
*raw* copy of file data available.
 
+redirect
+   A map declaring potential *content redirects* that may be used by this
+   server. Contains the following bytestring keys:
+
+   targets
+  (array of maps) Potential redirect targets. Values are maps describing
+  this target in more detail. Each map has the following bytestring keys:
+
+  name
+ (bytestring) Identifier for this target. The identifier will be used
+ by clients to uniquely identify this target.
+
+  protocol
+ (bytestring) High-level network protocol. Values can be
+ ``http``, ```https``, ``ssh``, etc.
+
+  uris
+  (array of bytestrings) Representative URIs for this target.
+
+  snirequired (optional)
+  (boolean) Indicates whether Server Name Indication is required
+  to use this target. Defaults to False.
+
+  tlsversions (optional)
+  (array of bytestring) Indicates which TLS versions are supported by
+  this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
+
+   hashes
+  (array of bytestring) Indicates support for hashing algorithms that are
+  used to ensure content integrity. Values include ``sha1``, ``sha256``,
+  etc.
+
 changesetdata
 -
 
diff --git a/mercurial/help/internals/wireprotocolrpc.txt 
b/mercurial/help/internals/wireprotocolrpc.txt
--- a/mercurial/help/internals/wireprotocolrpc.txt
+++ b/mercurial/help/internals/wireprotocolrpc.txt
@@ -115,6 +115,22 @@
Each command defines its own set of argument names and their expected
types.
 
+redirect (optional)
+   (map) Advertises client support for following response *redirects*.
+
+   This map has the following bytestring keys:
+
+   targets
+  (array of bytestring) List of named redirect targets supported by
+  this client. The names come from the targets advertised by the
+  server's *capabilities* message.
+
+   hashes
+  (array of bytestring) List of preferred hashing algorithms that can
+  be used for content integrity verification.
+
+   See the *Content Redirects* section below for more on content redirects.
+
 This frame type MUST ONLY be sent from clients to servers: it is illegal
 for a server to send this frame to a client.
 
@@ -506,6 +522,9 @@
error
   There was an error processing the command. More details about the
   error are encoded in the ``error`` key.
+   redirect
+  The response for this command is available elsewhere. Details on
+  where are in the ``location`` key.
 
 error (optional)
A map containing information about an encountered error. The map has the
@@ -515,5 +534,116 @@
   (array of maps) A message describing the error. The message uses the
   same format as those in the ``Human Output Side-Channel`` frame.
 
+location (optional)
+   (map) Presence indicates that a *content redirect* has occurred. The map
+   provides the external location of the content.
+
+   This map contains the following bytestring keys:
+
+   url
+  (bytestring) URL from which this content may be requested.
+
+   mediatype
+  (bytestring) The media type for the fetched content. e.g.
+  ``application/mercurial-*``.
+
+  In some transports, this value is also advertised by the transport.
+  e.g. as the ``Content-Type`` HTTP header.
+
+   size (optional)
+  (unsigned integer) Total size of remote object in bytes. This is
+  the raw size of the entity that will be fetched, minus any
+  non-Mercurial protocol encoding (e.g. HTTP content or transfer
+  encoding.)
+
+   fullhashes (optional)
+  (array of arrays) Content hashes for the entire payload. Each entry
+  is an array of bytestrings containing the hash name and the hash value.
+
+   fullhashseed (optional)
+  (bytestring) Optional seed value to feed into hasher for full content
+  hash verification.
+
+   serverdercerts (optional)
+  (array of bytestring) DER encoded x509 certificates for the server. When
+  defined, clients MAY validate that the x509 certificate on the target
+  server exactly matches the certificate used here.
+
+   servercadercerts (optional)
+  (array of bytestring) DER encoded 

D4772: wireprotov2: define type to represent pre-encoded object

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGed919b90acda: wireprotov2: define type to represent 
pre-encoded object (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4772?vs=11443=11623

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

AFFECTED FILES
  mercurial/wireprotoframing.py
  mercurial/wireprototypes.py

CHANGE DETAILS

diff --git a/mercurial/wireprototypes.py b/mercurial/wireprototypes.py
--- a/mercurial/wireprototypes.py
+++ b/mercurial/wireprototypes.py
@@ -10,6 +10,9 @@
 hex,
 )
 from .i18n import _
+from .thirdparty import (
+attr,
+)
 from . import (
 error,
 util,
@@ -352,3 +355,15 @@
   ', '.sorted(validnames))
 
 return compengines
+
+@attr.s
+class encodedresponse(object):
+"""Represents response data that is already content encoded.
+
+Wire protocol version 2 only.
+
+Commands typically emit Python objects that are encoded and sent over the
+wire. If commands emit an object of this type, the encoding step is 
bypassed
+and the content from this object is used instead.
+"""
+data = attr.ib()
diff --git a/mercurial/wireprotoframing.py b/mercurial/wireprotoframing.py
--- a/mercurial/wireprotoframing.py
+++ b/mercurial/wireprotoframing.py
@@ -22,6 +22,7 @@
 encoding,
 error,
 util,
+wireprototypes,
 )
 from .utils import (
 cborutil,
@@ -840,10 +841,22 @@
 yield createcommandresponseokframe(stream, requestid)
 emitted = True
 
-for chunk in cborutil.streamencode(o):
-for frame in emitter.send(chunk):
+# Objects emitted by command functions can be serializable
+# data structures or special types.
+# TODO consider extracting the content normalization to a
+# standalone function, as it may be useful for e.g. 
cachers.
+
+# A pre-encoded object is sent directly to the emitter.
+if isinstance(o, wireprototypes.encodedresponse):
+for frame in emitter.send(o.data):
 yield frame
 
+# A regular object is CBOR encoded.
+else:
+for chunk in cborutil.streamencode(o):
+for frame in emitter.send(chunk):
+yield frame
+
 except Exception as e:
 for frame in createerrorframe(stream, requestid,
   '%s' % e,



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


D4771: wireprotov2: change name and behavior of readframe()

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGf5a05bb48116: wireprotov2: change name and behavior of 
readframe() (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4771?vs=11442=11622

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

AFFECTED FILES
  mercurial/httppeer.py
  mercurial/wireprotov2peer.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov2peer.py b/mercurial/wireprotov2peer.py
--- a/mercurial/wireprotov2peer.py
+++ b/mercurial/wireprotov2peer.py
@@ -148,6 +148,7 @@
 self._requests = {}
 self._futures = {}
 self._responses = {}
+self._frameseof = False
 
 def callcommand(self, command, args, f):
 """Register a request to call a command.
@@ -180,18 +181,23 @@
 
 return meta['framegen']
 
-def readframe(self, fh):
-"""Attempt to read and process a frame.
+def readdata(self, framefh):
+"""Attempt to read data and do work.
 
-Returns None if no frame was read. Presumably this means EOF.
+Returns None if no data was read. Presumably this means we're
+done with all read I/O.
 """
-frame = wireprotoframing.readframe(fh)
-if frame is None:
-# TODO tell reactor?
-return
+if not self._frameseof:
+frame = wireprotoframing.readframe(framefh)
+if frame is None:
+# TODO tell reactor?
+self._frameseof = True
+else:
+self._ui.note(_('received %r\n') % frame)
+self._processframe(frame)
 
-self._ui.note(_('received %r\n') % frame)
-self._processframe(frame)
+if self._frameseof:
+return None
 
 return True
 
diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -712,7 +712,7 @@
 def _handleresponse(self, handler, resp):
 # Called in a thread to read the response.
 
-while handler.readframe(resp):
+while handler.readdata(resp):
 pass
 
 # TODO implement interface for version 2 peers



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


D4770: url: move _wraphttpresponse() from httpeer

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGf80db6adabbe: url: move _wraphttpresponse() from httpeer 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4770?vs=11441=11621

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

AFFECTED FILES
  mercurial/httppeer.py
  mercurial/url.py

CHANGE DETAILS

diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -595,3 +595,39 @@
 url_ = 'file://' + pycompat.bytesurl(urlreq.pathname2url(path))
 authinfo = None
 return opener(ui, authinfo).open(pycompat.strurl(url_), data)
+
+def wrapresponse(resp):
+"""Wrap a response object with common error handlers.
+
+This ensures that any I/O from any consumer raises the appropriate
+error and messaging.
+"""
+origread = resp.read
+
+class readerproxy(resp.__class__):
+def read(self, size=None):
+try:
+return origread(size)
+except httplib.IncompleteRead as e:
+# e.expected is an integer if length known or None otherwise.
+if e.expected:
+got = len(e.partial)
+total = e.expected + got
+msg = _('HTTP request error (incomplete response; '
+'expected %d bytes got %d)') % (total, got)
+else:
+msg = _('HTTP request error (incomplete response)')
+
+raise error.PeerTransportError(
+msg,
+hint=_('this may be an intermittent network failure; '
+   'if the error persists, consider contacting the '
+   'network or server operator'))
+except httplib.HTTPException as e:
+raise error.PeerTransportError(
+_('HTTP request error (%s)') % e,
+hint=_('this may be an intermittent network failure; '
+   'if the error persists, consider contacting the '
+   'network or server operator'))
+
+resp.__class__ = readerproxy
diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -69,42 +69,6 @@
 
 return result
 
-def _wraphttpresponse(resp):
-"""Wrap an HTTPResponse with common error handlers.
-
-This ensures that any I/O from any consumer raises the appropriate
-error and messaging.
-"""
-origread = resp.read
-
-class readerproxy(resp.__class__):
-def read(self, size=None):
-try:
-return origread(size)
-except httplib.IncompleteRead as e:
-# e.expected is an integer if length known or None otherwise.
-if e.expected:
-got = len(e.partial)
-total = e.expected + got
-msg = _('HTTP request error (incomplete response; '
-'expected %d bytes got %d)') % (total, got)
-else:
-msg = _('HTTP request error (incomplete response)')
-
-raise error.PeerTransportError(
-msg,
-hint=_('this may be an intermittent network failure; '
-   'if the error persists, consider contacting the '
-   'network or server operator'))
-except httplib.HTTPException as e:
-raise error.PeerTransportError(
-_('HTTP request error (%s)') % e,
-hint=_('this may be an intermittent network failure; '
-   'if the error persists, consider contacting the '
-   'network or server operator'))
-
-resp.__class__ = readerproxy
-
 class _multifile(object):
 def __init__(self, *fileobjs):
 for f in fileobjs:
@@ -325,7 +289,7 @@
 % (util.timer() - start, code))
 
 # Insert error handlers for common I/O failures.
-_wraphttpresponse(res)
+urlmod.wrapresponse(res)
 
 return res
 



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


D4803: storageutil: extract most of emitrevisions() to standalone function

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG842ffcf1d42f: storageutil: extract most of emitrevisions() 
to standalone function (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4803?vs=11486=11617

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

AFFECTED FILES
  mercurial/revlog.py
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -262,3 +262,149 @@
 futurelargelinkrevs.add(plinkrev)
 
 return strippoint, brokenrevs
+
+def emitrevisions(store, revs, resultcls, deltaparentfn, candeltafn,
+  rawsizefn, revdifffn, flagsfn, sendfulltext=False,
+  revisiondata=False, assumehaveparentrevisions=False,
+  deltaprevious=False):
+"""Generic implementation of ifiledata.emitrevisions().
+
+Emitting revision data is subtly complex. This function attempts to
+encapsulate all the logic for doing so in a backend-agnostic way.
+
+``store``
+   Object conforming to ``ifilestorage`` interface.
+
+``revs``
+   List of integer revision numbers whose data to emit.
+
+``resultcls``
+   A type implementing the ``irevisiondelta`` interface that will be
+   constructed and returned.
+
+``deltaparentfn``
+   Callable receiving a revision number and returning the revision number
+   of a revision that the internal delta is stored against. This delta
+   will be preferred over computing a new arbitrary delta.
+
+``candeltafn``
+   Callable receiving a pair of revision numbers that returns a bool
+   indicating whether a delta between them can be produced.
+
+``rawsizefn``
+   Callable receiving a revision number and returning the length of the
+   ``store.revision(rev, raw=True)``.
+
+``revdifffn``
+   Callable receiving a pair of revision numbers that returns a delta
+   between them.
+
+``flagsfn``
+   Callable receiving a revision number and returns the integer flags
+   value for it.
+
+``sendfulltext``
+   Whether to send fulltext revisions instead of deltas, if allowed.
+
+``revisiondata``
+``assumehaveparentrevisions``
+``deltaprevious``
+   See ``ifiledata.emitrevisions()`` interface documentation.
+"""
+
+fnode = store.node
+
+prevrev = None
+
+if deltaprevious or assumehaveparentrevisions:
+prevrev = store.parentrevs(revs[0])[0]
+
+# Set of revs available to delta against.
+available = set()
+
+for rev in revs:
+if rev == nullrev:
+continue
+
+node = fnode(rev)
+deltaparentrev = deltaparentfn(rev)
+p1rev, p2rev = store.parentrevs(rev)
+
+# Forced delta against previous mode.
+if deltaprevious:
+baserev = prevrev
+
+# We're instructed to send fulltext. Honor that.
+elif sendfulltext:
+baserev = nullrev
+
+# There is a delta in storage. We try to use that because it
+# amounts to effectively copying data from storage and is
+# therefore the fastest.
+elif deltaparentrev != nullrev:
+# Base revision was already emitted in this group. We can
+# always safely use the delta.
+if deltaparentrev in available:
+baserev = deltaparentrev
+
+# Base revision is a parent that hasn't been emitted already.
+# Use it if we can assume the receiver has the parent revision.
+elif (assumehaveparentrevisions
+  and deltaparentrev in (p1rev, p2rev)):
+baserev = deltaparentrev
+
+# No guarantee the receiver has the delta parent. Send delta
+# against last revision (if possible), which in the common case
+# should be similar enough to this revision that the delta is
+# reasonable.
+elif prevrev is not None:
+baserev = prevrev
+else:
+baserev = nullrev
+
+# Storage has a fulltext revision.
+
+# Let's use the previous revision, which is as good a guess as any.
+# There is definitely room to improve this logic.
+elif prevrev is not None:
+baserev = prevrev
+else:
+baserev = nullrev
+
+# But we can't actually use our chosen delta base for whatever
+# reason. Reset to fulltext.
+if baserev != nullrev and not candeltafn(baserev, rev):
+baserev = nullrev
+
+revision = None
+delta = None
+baserevisionsize = None
+
+if revisiondata:
+if store.iscensored(baserev) or store.iscensored(rev):
+try:
+revision = 

D4805: storageutil: pass nodes into emitrevisions()

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGf5d819d84461: storageutil: pass nodes into emitrevisions() 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4805?vs=11488=11619

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

AFFECTED FILES
  mercurial/revlog.py
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -17,6 +17,7 @@
 nullrev,
 )
 from .. import (
+dagop,
 error,
 mdiff,
 pycompat,
@@ -264,8 +265,8 @@
 
 return strippoint, brokenrevs
 
-def emitrevisions(store, revs, resultcls, deltaparentfn=None, candeltafn=None,
-  rawsizefn=None, revdifffn=None, flagsfn=None,
+def emitrevisions(store, nodes, nodesorder, resultcls, deltaparentfn=None,
+  candeltafn=None, rawsizefn=None, revdifffn=None, 
flagsfn=None,
   sendfulltext=False,
   revisiondata=False, assumehaveparentrevisions=False,
   deltaprevious=False):
@@ -277,8 +278,8 @@
 ``store``
Object conforming to ``ifilestorage`` interface.
 
-``revs``
-   List of integer revision numbers whose data to emit.
+``nodes``
+   List of revision nodes whose data to emit.
 
 ``resultcls``
A type implementing the ``irevisiondelta`` interface that will be
@@ -322,13 +323,23 @@
 ``sendfulltext``
Whether to send fulltext revisions instead of deltas, if allowed.
 
+``nodesorder``
 ``revisiondata``
 ``assumehaveparentrevisions``
 ``deltaprevious``
See ``ifiledata.emitrevisions()`` interface documentation.
 """
 
 fnode = store.node
+frev = store.rev
+
+if nodesorder == 'nodes':
+revs = [frev(n) for n in nodes]
+elif nodesorder == 'storage':
+revs = sorted(frev(n) for n in nodes)
+else:
+revs = set(frev(n) for n in nodes)
+revs = dagop.linearize(revs, store.parentrevs)
 
 prevrev = None
 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -2192,19 +2192,8 @@
 if nodesorder is None and not self._generaldelta:
 nodesorder = 'storage'
 
-frev = self.rev
-
-if nodesorder == 'nodes':
-revs = [frev(n) for n in nodes]
-elif nodesorder == 'storage':
-revs = sorted(frev(n) for n in nodes)
-else:
-assert self._generaldelta
-revs = set(frev(n) for n in nodes)
-revs = dagop.linearize(revs, self.parentrevs)
-
 return storageutil.emitrevisions(
-self, revs, revlogrevisiondelta,
+self, nodes, nodesorder, revlogrevisiondelta,
 deltaparentfn=self.deltaparent,
 candeltafn=self.candelta,
 rawsizefn=self.rawsize,



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


D4804: storageutil: make all callables optional

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG631c6f5058b9: storageutil: make all callables optional 
(authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4804?vs=11487=11618

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

AFFECTED FILES
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -18,6 +18,7 @@
 )
 from .. import (
 error,
+mdiff,
 pycompat,
 )
 
@@ -263,8 +264,9 @@
 
 return strippoint, brokenrevs
 
-def emitrevisions(store, revs, resultcls, deltaparentfn, candeltafn,
-  rawsizefn, revdifffn, flagsfn, sendfulltext=False,
+def emitrevisions(store, revs, resultcls, deltaparentfn=None, candeltafn=None,
+  rawsizefn=None, revdifffn=None, flagsfn=None,
+  sendfulltext=False,
   revisiondata=False, assumehaveparentrevisions=False,
   deltaprevious=False):
 """Generic implementation of ifiledata.emitrevisions().
@@ -282,26 +284,40 @@
A type implementing the ``irevisiondelta`` interface that will be
constructed and returned.
 
-``deltaparentfn``
+``deltaparentfn`` (optional)
Callable receiving a revision number and returning the revision number
of a revision that the internal delta is stored against. This delta
will be preferred over computing a new arbitrary delta.
 
-``candeltafn``
+   If not defined, a delta will always be computed from raw revision
+   data.
+
+``candeltafn`` (optional)
Callable receiving a pair of revision numbers that returns a bool
indicating whether a delta between them can be produced.
 
-``rawsizefn``
+   If not defined, it is assumed that any two revisions can delta with
+   each other.
+
+``rawsizefn`` (optional)
Callable receiving a revision number and returning the length of the
``store.revision(rev, raw=True)``.
 
-``revdifffn``
+   If not defined, ``len(store.revision(rev, raw=True))`` will be called.
+
+``revdifffn`` (optional)
Callable receiving a pair of revision numbers that returns a delta
between them.
 
-``flagsfn``
+   If not defined, a delta will be computed by invoking mdiff code
+   on ``store.revision()`` results.
+
+   Defining this function allows a precomputed or stored delta to be
+   used without having to compute on.
+
+``flagsfn`` (optional)
Callable receiving a revision number and returns the integer flags
-   value for it.
+   value for it. If not defined, flags value will be 0.
 
 ``sendfulltext``
Whether to send fulltext revisions instead of deltas, if allowed.
@@ -327,9 +343,13 @@
 continue
 
 node = fnode(rev)
-deltaparentrev = deltaparentfn(rev)
 p1rev, p2rev = store.parentrevs(rev)
 
+if deltaparentfn:
+deltaparentrev = deltaparentfn(rev)
+else:
+deltaparentrev = nullrev
+
 # Forced delta against previous mode.
 if deltaprevious:
 baserev = prevrev
@@ -373,7 +393,7 @@
 
 # But we can't actually use our chosen delta base for whatever
 # reason. Reset to fulltext.
-if baserev != nullrev and not candeltafn(baserev, rev):
+if baserev != nullrev and (candeltafn and not candeltafn(baserev, 
rev)):
 baserev = nullrev
 
 revision = None
@@ -388,21 +408,30 @@
 revision = e.tombstone
 
 if baserev != nullrev:
-baserevisionsize = rawsizefn(baserev)
+if rawsizefn:
+baserevisionsize = rawsizefn(baserev)
+else:
+baserevisionsize = len(store.revision(baserev,
+  raw=True))
 
 elif baserev == nullrev and not deltaprevious:
 revision = store.revision(node, raw=True)
 available.add(rev)
 else:
-delta = revdifffn(baserev, rev)
+if revdifffn:
+delta = revdifffn(baserev, rev)
+else:
+delta = mdiff.textdiff(store.revision(baserev, raw=True),
+   store.revision(rev, raw=True))
+
 available.add(rev)
 
 yield resultcls(
 node=node,
 p1node=fnode(p1rev),
 p2node=fnode(p2rev),
 basenode=fnode(baserev),
-flags=flagsfn(rev),
+flags=flagsfn(rev) if flagsfn else 0,
 baserevisionsize=baserevisionsize,
 revision=revision,
 delta=delta)



To: 

D4799: storageutil: extract functionality for resolving strip revisions

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGfa3dc85a747e: storageutil: extract functionality for 
resolving strip revisions (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4799?vs=11482=11613

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

AFFECTED FILES
  mercurial/revlog.py
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -14,6 +14,7 @@
 from ..node import (
 bin,
 nullid,
+nullrev,
 )
 from .. import (
 error,
@@ -155,3 +156,54 @@
 pass
 
 raise error.LookupError(fileid, identifier, _('no match found'))
+
+def resolvestripinfo(minlinkrev, tiprev, headrevs, linkrevfn, parentrevsfn):
+"""Resolve information needed to strip revisions.
+
+Finds the minimum revision number that must be stripped in order to
+strip ``minlinkrev``.
+
+Returns a 2-tuple of the minimum revision number to do that and a set
+of all revision numbers that have linkrevs that would be broken
+by that strip.
+
+``tiprev`` is the current tip-most revision. It is ``len(store) - 1``.
+``headrevs`` is an iterable of head revisions.
+``linkrevfn`` is a callable that receives a revision and returns a linked
+revision.
+``parentrevsfn`` is a callable that receives a revision number and returns
+an iterable of its parent revision numbers.
+"""
+brokenrevs = set()
+strippoint = tiprev + 1
+
+heads = {}
+futurelargelinkrevs = set()
+for head in headrevs:
+headlinkrev = linkrevfn(head)
+heads[head] = headlinkrev
+if headlinkrev >= minlinkrev:
+futurelargelinkrevs.add(headlinkrev)
+
+# This algorithm involves walking down the rev graph, starting at the
+# heads. Since the revs are topologically sorted according to linkrev,
+# once all head linkrevs are below the minlink, we know there are
+# no more revs that could have a linkrev greater than minlink.
+# So we can stop walking.
+while futurelargelinkrevs:
+strippoint -= 1
+linkrev = heads.pop(strippoint)
+
+if linkrev < minlinkrev:
+brokenrevs.add(strippoint)
+else:
+futurelargelinkrevs.remove(linkrev)
+
+for p in parentrevsfn(strippoint):
+if p != nullrev:
+plinkrev = linkrevfn(p)
+heads[p] = plinkrev
+if plinkrev >= minlinkrev:
+futurelargelinkrevs.add(plinkrev)
+
+return strippoint, brokenrevs
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -2096,39 +2096,9 @@
 Returns a tuple containing the minimum rev and a set of all revs that
 have linkrevs that will be broken by this strip.
 """
-brokenrevs = set()
-strippoint = len(self)
-
-heads = {}
-futurelargelinkrevs = set()
-for head in self.headrevs():
-headlinkrev = self.linkrev(head)
-heads[head] = headlinkrev
-if headlinkrev >= minlink:
-futurelargelinkrevs.add(headlinkrev)
-
-# This algorithm involves walking down the rev graph, starting at the
-# heads. Since the revs are topologically sorted according to linkrev,
-# once all head linkrevs are below the minlink, we know there are
-# no more revs that could have a linkrev greater than minlink.
-# So we can stop walking.
-while futurelargelinkrevs:
-strippoint -= 1
-linkrev = heads.pop(strippoint)
-
-if linkrev < minlink:
-brokenrevs.add(strippoint)
-else:
-futurelargelinkrevs.remove(linkrev)
-
-for p in self.parentrevs(strippoint):
-if p != nullrev:
-plinkrev = self.linkrev(p)
-heads[p] = plinkrev
-if plinkrev >= minlink:
-futurelargelinkrevs.add(plinkrev)
-
-return strippoint, brokenrevs
+return storageutil.resolvestripinfo(minlink, len(self) - 1,
+self.headrevs(),
+self.linkrev, self.parentrevs)
 
 def strip(self, minlink, transaction):
 """truncate the revlog on the first revision with a linkrev >= minlink



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


D4802: storageutil: invert logic of file data comparison

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG1470183068b8: storageutil: invert logic of file data 
comparison (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4802?vs=11485=11616

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

AFFECTED FILES
  mercurial/filelog.py
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -108,8 +108,18 @@
 
 return False
 
-def filerevisiondifferent(store, node, filedata):
-"""Determines whether file data is equivalent to a stored node."""
+def filedataequivalent(store, node, filedata):
+"""Determines whether file data is equivalent to a stored node.
+
+Returns True if the passed file data would hash to the same value
+as a stored revision and False otherwise.
+
+When a stored revision is censored, filedata must be empty to have
+equivalence.
+
+When a stored revision has copy metadata, it is ignored as part
+of the compare.
+"""
 
 if filedata.startswith(b'\x01\n'):
 revisiontext = b'\x01\n\x01\n' + filedata
@@ -121,18 +131,18 @@
 computednode = hashrevisionsha1(revisiontext, p1, p2)
 
 if computednode == node:
-return False
+return True
 
 # Censored files compare against the empty file.
 if store.iscensored(store.rev(node)):
-return filedata != b''
+return filedata == b''
 
 # Renaming a file produces a different hash, even if the data
 # remains unchanged. Check if that's the case.
 if store.renamed(node):
-return store.read(node) != filedata
+return store.read(node) == filedata
 
-return True
+return False
 
 def iterrevs(storelen, start=0, stop=None):
 """Iterate over revision numbers in a store."""
diff --git a/mercurial/filelog.py b/mercurial/filelog.py
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -135,7 +135,7 @@
 
 returns True if text is different than what is stored.
 """
-return storageutil.filerevisiondifferent(self, node, text)
+return not storageutil.filedataequivalent(self, node, text)
 
 def verifyintegrity(self, state):
 return self._revlog.verifyintegrity(state)



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


D4801: storageutil: extract filelog.cmp() to a standalone function

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG422beffd71ba: storageutil: extract filelog.cmp() to a 
standalone function (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4801?vs=11484=11615

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

AFFECTED FILES
  mercurial/filelog.py
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -108,6 +108,32 @@
 
 return False
 
+def filerevisiondifferent(store, node, filedata):
+"""Determines whether file data is equivalent to a stored node."""
+
+if filedata.startswith(b'\x01\n'):
+revisiontext = b'\x01\n\x01\n' + filedata
+else:
+revisiontext = filedata
+
+p1, p2 = store.parents(node)
+
+computednode = hashrevisionsha1(revisiontext, p1, p2)
+
+if computednode == node:
+return False
+
+# Censored files compare against the empty file.
+if store.iscensored(store.rev(node)):
+return filedata != b''
+
+# Renaming a file produces a different hash, even if the data
+# remains unchanged. Check if that's the case.
+if store.renamed(node):
+return store.read(node) != filedata
+
+return True
+
 def iterrevs(storelen, start=0, stop=None):
 """Iterate over revision numbers in a store."""
 step = 1
diff --git a/mercurial/filelog.py b/mercurial/filelog.py
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -135,26 +135,7 @@
 
 returns True if text is different than what is stored.
 """
-
-t = text
-if text.startswith('\1\n'):
-t = '\1\n\1\n' + text
-
-samehashes = not self._revlog.cmp(node, t)
-if samehashes:
-return False
-
-# censored files compare against the empty file
-if self.iscensored(self.rev(node)):
-return text != ''
-
-# renaming a file produces a different hash, even if the data
-# remains unchanged. Check if it's the case (slow):
-if self.renamed(node):
-t2 = self.read(node)
-return t2 != text
-
-return True
+return storageutil.filerevisiondifferent(self, node, text)
 
 def verifyintegrity(self, state):
 return self._revlog.verifyintegrity(state)



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


D4797: storageutil: implement file identifier resolution method (BC)

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0e8836be9541: storageutil: implement file identifier 
resolution method (BC) (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4797?vs=11480=11611

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

AFFECTED FILES
  mercurial/filelog.py
  mercurial/repository.py
  mercurial/testing/storage.py
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -10,10 +10,13 @@
 import hashlib
 import re
 
+from ..i18n import _
 from ..node import (
+bin,
 nullid,
 )
 from .. import (
+error,
 pycompat,
 )
 
@@ -99,3 +102,53 @@
 stop = storelen
 
 return pycompat.xrange(start, stop, step)
+
+def fileidlookup(store, fileid, identifier):
+"""Resolve the file node for a value.
+
+``store`` is an object implementing the ``ifileindex`` interface.
+
+``fileid`` can be:
+
+* A 20 byte binary node.
+* An integer revision number
+* A 40 byte hex node.
+* A bytes that can be parsed as an integer representing a revision number.
+
+``identifier`` is used to populate ``error.LookupError`` with an identifier
+for the store.
+
+Raises ``error.LookupError`` on failure.
+"""
+if isinstance(fileid, int):
+return store.node(fileid)
+
+if len(fileid) == 20:
+try:
+store.rev(fileid)
+return fileid
+except error.LookupError:
+pass
+
+if len(fileid) == 40:
+try:
+rawnode = bin(fileid)
+store.rev(rawnode)
+return rawnode
+except TypeError:
+pass
+
+try:
+rev = int(fileid)
+
+if b'%d' % rev != fileid:
+raise ValueError
+
+try:
+return store.node(rev)
+except (IndexError, TypeError):
+pass
+except (ValueError, OverflowError):
+pass
+
+raise error.LookupError(fileid, identifier, _('no match found'))
diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -85,21 +85,19 @@
 self.assertEqual(f.lookup(nullid), nullid)
 self.assertEqual(f.lookup(nullrev), nullid)
 self.assertEqual(f.lookup(hex(nullid)), nullid)
-
-# String converted to integer doesn't work for nullrev.
-with self.assertRaises(error.LookupError):
-f.lookup(b'%d' % nullrev)
+self.assertEqual(f.lookup(b'%d' % nullrev), nullid)
 
 with self.assertRaises(error.LookupError):
 f.lookup(b'badvalue')
 
-self.assertEqual(f.lookup(hex(nullid)[0:12]), nullid)
+with self.assertRaises(error.LookupError):
+f.lookup(hex(nullid)[0:12])
 
 with self.assertRaises(error.LookupError):
 f.lookup(b'-2')
 
-# TODO this is wonky.
-self.assertEqual(f.lookup(b'0'), nullid)
+with self.assertRaises(error.LookupError):
+f.lookup(b'0')
 
 with self.assertRaises(error.LookupError):
 f.lookup(b'1')
@@ -197,7 +195,9 @@
 self.assertEqual(f.lookup(-1), nullid)
 self.assertEqual(f.lookup(b'0'), node)
 self.assertEqual(f.lookup(hex(node)), node)
-self.assertEqual(f.lookup(hex(node)[0:12]), node)
+
+with self.assertRaises(error.LookupError):
+f.lookup(hex(node)[0:12])
 
 with self.assertRaises(IndexError):
 f.lookup(-2)
diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -1099,9 +1099,6 @@
 that can be converted to an integer.
 
 Raises ``error.LookupError`` if a ndoe could not be resolved.
-
-TODO this is only used by debug* commands and can probably be deleted
-easily.
 """
 
 def parents(node):
diff --git a/mercurial/filelog.py b/mercurial/filelog.py
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -49,7 +49,8 @@
 return self._revlog.node(rev)
 
 def lookup(self, node):
-return self._revlog.lookup(node)
+return storageutil.fileidlookup(self._revlog, node,
+self._revlog.indexfile)
 
 def linkrev(self, rev):
 return self._revlog.linkrev(rev)



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


D4798: storageutil: consistently raise LookupError (API)

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGad8389ecd3f5: storageutil: consistently raise LookupError 
(API) (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4798?vs=11481=11612

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

AFFECTED FILES
  mercurial/testing/storage.py
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -121,7 +121,10 @@
 Raises ``error.LookupError`` on failure.
 """
 if isinstance(fileid, int):
-return store.node(fileid)
+try:
+return store.node(fileid)
+except IndexError:
+raise error.LookupError(fileid, identifier, _('no match found'))
 
 if len(fileid) == 20:
 try:
diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -199,13 +199,13 @@
 with self.assertRaises(error.LookupError):
 f.lookup(hex(node)[0:12])
 
-with self.assertRaises(IndexError):
+with self.assertRaises(error.LookupError):
 f.lookup(-2)
 
 with self.assertRaises(error.LookupError):
 f.lookup(b'-2')
 
-with self.assertRaises(IndexError):
+with self.assertRaises(error.LookupError):
 f.lookup(1)
 
 with self.assertRaises(error.LookupError):



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


D4800: storageutil: extract copy metadata retrieval out of filelog

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG1d97a332c6d9: storageutil: extract copy metadata retrieval 
out of filelog (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4800?vs=11483=11614

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

AFFECTED FILES
  mercurial/filelog.py
  mercurial/utils/storageutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -89,6 +89,25 @@
 offset = text.index(b'\x01\n', 2)
 return text[offset + 2:]
 
+def filerevisioncopied(store, node):
+"""Resolve file revision copy metadata.
+
+Returns ``False`` if the file has no copy metadata. Otherwise a
+2-tuple of the source filename and node.
+"""
+if store.parents(node)[0] != nullid:
+return False
+
+meta = parsemeta(store.revision(node))[0]
+
+# copy and copyrev occur in pairs. In rare cases due to old bugs,
+# one can occur without the other. So ensure both are present to flag
+# as a copy.
+if meta and b'copy' in meta and b'copyrev' in meta:
+return meta[b'copy'], bin(meta[b'copyrev'])
+
+return False
+
 def iterrevs(storelen, start=0, stop=None):
 """Iterate over revision numbers in a store."""
 step = 1
diff --git a/mercurial/filelog.py b/mercurial/filelog.py
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -115,15 +115,7 @@
 return self.addrevision(text, transaction, link, p1, p2)
 
 def renamed(self, node):
-if self.parents(node)[0] != revlog.nullid:
-return False
-t = self.revision(node)
-m = storageutil.parsemeta(t)[0]
-# copy and copyrev occur in pairs. In rare cases due to bugs,
-# one can occur without the other.
-if m and "copy" in m and "copyrev" in m:
-return (m["copy"], revlog.bin(m["copyrev"]))
-return False
+return storageutil.filerevisioncopied(self, node)
 
 def size(self, rev):
 """return the size of a given revision"""



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


D4795: dagop: extract DAG local heads functionality from revlog

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG8af835af0a85: dagop: extract DAG local heads functionality 
from revlog (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4795?vs=11478=11609

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

AFFECTED FILES
  mercurial/dagop.py
  mercurial/revlog.py

CHANGE DETAILS

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1069,25 +1069,16 @@
 return [self.node(r) for r in self.headrevs()]
 
 if start is None:
-start = nullid
-if stop is None:
-stop = []
-stoprevs = set([self.rev(n) for n in stop])
-startrev = self.rev(start)
-reachable = {startrev}
-heads = {startrev}
-
-parentrevs = self.parentrevs
-for r in self.revs(start=startrev + 1):
-for p in parentrevs(r):
-if p in reachable:
-if r not in stoprevs:
-reachable.add(r)
-heads.add(r)
-if p in heads and p not in stoprevs:
-heads.remove(p)
-
-return [self.node(r) for r in heads]
+start = nullrev
+else:
+start = self.rev(start)
+
+stoprevs = set(self.rev(n) for n in stop or [])
+
+revs = dagop.headrevssubset(self.revs, self.parentrevs, startrev=start,
+stoprevs=stoprevs)
+
+return [self.node(rev) for rev in revs]
 
 def children(self, node):
 """find the children of a given node"""
diff --git a/mercurial/dagop.py b/mercurial/dagop.py
--- a/mercurial/dagop.py
+++ b/mercurial/dagop.py
@@ -773,6 +773,42 @@
 
 return headrevs
 
+def headrevssubset(revsfn, parentrevsfn, startrev=None, stoprevs=None):
+"""Returns the set of all revs that have no children with control.
+
+``revsfn`` is a callable that with no arguments returns an iterator over
+all revision numbers in topological order. With a ``start`` argument, it
+returns revision numbers starting at that number.
+
+``parentrevsfn`` is a callable receiving a revision number and returns an
+iterable of parent revision numbers, where values can include nullrev.
+
+``startrev`` is a revision number at which to start the search.
+
+``stoprevs`` is an iterable of revision numbers that, when encountered,
+will stop DAG traversal beyond them. Parents of revisions in this
+collection will be heads.
+"""
+if startrev is None:
+startrev = nullrev
+
+stoprevs = set(stoprevs or [])
+
+reachable = {startrev}
+heads = {startrev}
+
+for rev in revsfn(start=startrev + 1):
+for prev in parentrevsfn(rev):
+if prev in reachable:
+if rev not in stoprevs:
+reachable.add(rev)
+heads.add(rev)
+
+if prev in heads and prev not in stoprevs:
+heads.remove(prev)
+
+return heads
+
 def linearize(revs, parentsfn):
 """Linearize and topologically sort a list of revisions.
 



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


D4794: dagop: extract descendants() from revlog module

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0b24fcd88066: dagop: extract descendants() from revlog 
module (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4794?vs=11477=11608

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

AFFECTED FILES
  mercurial/dagop.py
  mercurial/revlog.py

CHANGE DETAILS

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -748,25 +748,7 @@
   inclusive=inclusive)
 
 def descendants(self, revs):
-"""Generate the descendants of 'revs' in revision order.
-
-Yield a sequence of revision numbers starting with a child of
-some rev in revs, i.e., each revision is *not* considered a
-descendant of itself.  Results are ordered by revision number (a
-topological sort)."""
-first = min(revs)
-if first == nullrev:
-for i in self:
-yield i
-return
-
-seen = set(revs)
-for i in self.revs(start=first + 1):
-for x in self.parentrevs(i):
-if x != nullrev and x in seen:
-seen.add(i)
-yield i
-break
+return dagop.descendantrevs(revs, self.revs, self.parentrevs)
 
 def findcommonmissing(self, common=None, heads=None):
 """Return a tuple of the ancestors of common and the ancestors of heads
diff --git a/mercurial/dagop.py b/mercurial/dagop.py
--- a/mercurial/dagop.py
+++ b/mercurial/dagop.py
@@ -9,6 +9,9 @@
 
 import heapq
 
+from .node import (
+nullrev,
+)
 from .thirdparty import (
 attr,
 )
@@ -225,6 +228,37 @@
 startdepth, stopdepth)
 return generatorset(gen, iterasc=True)
 
+def descendantrevs(revs, revsfn, parentrevsfn):
+"""Generate revision number descendants in revision order.
+
+Yields revision numbers starting with a child of some rev in
+``revs``. Results are ordered by revision number and are
+therefore topological. Each revision is not considered a descendant
+of itself.
+
+``revsfn`` is a callable that with no argument iterates over all
+revision numbers and with a ``start`` argument iterates over revision
+numbers beginning with that value.
+
+``parentrevsfn`` is a callable that receives a revision number and
+returns an iterable of parent revision numbers, whose values may include
+nullrev.
+"""
+first = min(revs)
+
+if first == nullrev:
+for rev in revsfn():
+yield rev
+return
+
+seen = set(revs)
+for rev in revsfn(start=first + 1):
+for prev in parentrevsfn(rev):
+if prev != nullrev and prev in seen:
+seen.add(rev)
+yield rev
+break
+
 def _reachablerootspure(repo, minroot, roots, heads, includepath):
 """return (heads(:: and ::))
 



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


D4796: testing: add more testing for ifileindex.lookup()

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG215fd73cfe52: testing: add more testing for 
ifileindex.lookup() (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4796?vs=11479=11610

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

AFFECTED FILES
  mercurial/testing/storage.py

CHANGE DETAILS

diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -90,6 +90,30 @@
 with self.assertRaises(error.LookupError):
 f.lookup(b'%d' % nullrev)
 
+with self.assertRaises(error.LookupError):
+f.lookup(b'badvalue')
+
+self.assertEqual(f.lookup(hex(nullid)[0:12]), nullid)
+
+with self.assertRaises(error.LookupError):
+f.lookup(b'-2')
+
+# TODO this is wonky.
+self.assertEqual(f.lookup(b'0'), nullid)
+
+with self.assertRaises(error.LookupError):
+f.lookup(b'1')
+
+with self.assertRaises(error.LookupError):
+f.lookup(b'11')
+
+for i in range(-5, 5):
+if i == nullrev:
+continue
+
+with self.assertRaises(LookupError):
+f.lookup(i)
+
 self.assertEqual(f.linkrev(nullrev), nullrev)
 
 for i in range(-5, 5):
@@ -170,8 +194,22 @@
 
 self.assertEqual(f.lookup(node), node)
 self.assertEqual(f.lookup(0), node)
+self.assertEqual(f.lookup(-1), nullid)
 self.assertEqual(f.lookup(b'0'), node)
 self.assertEqual(f.lookup(hex(node)), node)
+self.assertEqual(f.lookup(hex(node)[0:12]), node)
+
+with self.assertRaises(IndexError):
+f.lookup(-2)
+
+with self.assertRaises(error.LookupError):
+f.lookup(b'-2')
+
+with self.assertRaises(IndexError):
+f.lookup(1)
+
+with self.assertRaises(error.LookupError):
+f.lookup(b'1')
 
 self.assertEqual(f.linkrev(0), 0)
 



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


D4791: localrepo: define storage backend in creation options (API)

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGdbcb466d0065: localrepo: define storage backend in creation 
options (API) (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4791?vs=11474=11605

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

AFFECTED FILES
  mercurial/configitems.py
  mercurial/localrepo.py
  mercurial/upgrade.py

CHANGE DETAILS

diff --git a/mercurial/upgrade.py b/mercurial/upgrade.py
--- a/mercurial/upgrade.py
+++ b/mercurial/upgrade.py
@@ -199,7 +199,8 @@
 
 @staticmethod
 def _newreporequirements(ui):
-return localrepo.newreporequirements(ui)
+return localrepo.newreporequirements(
+ui, localrepo.defaultcreateopts(ui))
 
 @classmethod
 def fromrepo(cls, repo):
@@ -747,7 +748,8 @@
 
 # FUTURE there is potentially a need to control the wanted requirements via
 # command arguments or via an extension hook point.
-newreqs = localrepo.newreporequirements(repo.ui)
+newreqs = localrepo.newreporequirements(
+repo.ui, localrepo.defaultcreateopts(repo.ui))
 newreqs.update(preservedrequirements(repo))
 
 noremovereqs = (repo.requirements - newreqs -
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -2808,14 +2808,26 @@
 def islocal(path):
 return True
 
-def newreporequirements(ui, createopts=None):
+def defaultcreateopts(ui, createopts=None):
+"""Populate the default creation options for a repository.
+
+A dictionary of explicitly requested creation options can be passed
+in. Missing keys will be populated.
+"""
+createopts = dict(createopts or {})
+
+if 'backend' not in createopts:
+# experimental config: storage.new-repo-backend
+createopts['backend'] = ui.config('storage', 'new-repo-backend')
+
+return createopts
+
+def newreporequirements(ui, createopts):
 """Determine the set of requirements for a new local repository.
 
 Extensions can wrap this function to specify custom requirements for
 new repositories.
 """
-createopts = createopts or {}
-
 # If the repo is being created from a shared repository, we copy
 # its requirements.
 if 'sharedrepo' in createopts:
@@ -2827,6 +2839,14 @@
 
 return requirements
 
+if 'backend' not in createopts:
+raise error.ProgrammingError('backend key not present in createopts; '
+ 'was defaultcreateopts() called?')
+
+if createopts['backend'] != 'revlogv1':
+raise error.Abort(_('unable to determine repository requirements for '
+'storage backend: %s') % createopts['backend'])
+
 requirements = {'revlogv1'}
 if ui.configbool('format', 'usestore'):
 requirements.add('store')
@@ -2885,6 +2905,7 @@
 they know how to handle.
 """
 known = {
+'backend',
 'narrowfiles',
 'sharedrepo',
 'sharedrelative',
@@ -2901,6 +2922,8 @@
 
 The following keys for ``createopts`` are recognized:
 
+backend
+   The storage backend to use.
 narrowfiles
Set up repository to support narrow file storage.
 sharedrepo
@@ -2912,7 +2935,7 @@
 shareditems
Set of items to share to the new repository (in addition to storage).
 """
-createopts = createopts or {}
+createopts = defaultcreateopts(ui, createopts=createopts)
 
 unknownopts = filterknowncreateopts(ui, createopts)
 
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -941,6 +941,9 @@
 coreconfigitem('push', 'pushvars.server',
 default=False,
 )
+coreconfigitem('storage', 'new-repo-backend',
+default='revlogv1',
+)
 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
 default=True,
 alias=[('format', 'aggressivemergedeltas')],



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


D4793: filelog: remove checkhash() (API)

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG44c98cbc665f: filelog: remove checkhash() (API) (authored 
by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4793?vs=11476=11607

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

AFFECTED FILES
  mercurial/filelog.py
  mercurial/repository.py
  mercurial/testing/storage.py

CHANGE DETAILS

diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -368,12 +368,6 @@
 with self.assertRaises(IndexError):
 f.size(i)
 
-with self.assertRaises(error.StorageError):
-f.checkhash(b'', nullid)
-
-with self.assertRaises(error.LookupError):
-f.checkhash(b'', b'\x01' * 20)
-
 self.assertEqual(f.revision(nullid), b'')
 self.assertEqual(f.revision(nullid, raw=True), b'')
 
@@ -426,18 +420,6 @@
 with self.assertRaises(IndexError):
 f.size(1)
 
-f.checkhash(fulltext, node)
-f.checkhash(fulltext, node, nullid, nullid)
-
-with self.assertRaises(error.StorageError):
-f.checkhash(fulltext + b'extra', node)
-
-with self.assertRaises(error.StorageError):
-f.checkhash(fulltext, node, b'\x01' * 20, nullid)
-
-with self.assertRaises(error.StorageError):
-f.checkhash(fulltext, node, nullid, b'\x01' * 20)
-
 self.assertEqual(f.revision(node), fulltext)
 self.assertEqual(f.revision(node, raw=True), fulltext)
 
@@ -510,20 +492,6 @@
 with self.assertRaises(IndexError):
 f.size(3)
 
-f.checkhash(fulltext0, node0)
-f.checkhash(fulltext1, node1)
-f.checkhash(fulltext1, node1, node0, nullid)
-f.checkhash(fulltext2, node2, node1, nullid)
-
-with self.assertRaises(error.StorageError):
-f.checkhash(fulltext1, b'\x01' * 20)
-
-with self.assertRaises(error.StorageError):
-f.checkhash(fulltext1 + b'extra', node1, node0, nullid)
-
-with self.assertRaises(error.StorageError):
-f.checkhash(fulltext1, node1, node0, node0)
-
 self.assertEqual(f.revision(node0), fulltext0)
 self.assertEqual(f.revision(node0, raw=True), fulltext0)
 self.assertEqual(f.revision(node1), fulltext1)
diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -545,12 +545,6 @@
 Any metadata is excluded from size measurements.
 """
 
-def checkhash(fulltext, node, p1=None, p2=None, rev=None):
-"""Validate the stored hash of a given fulltext and node.
-
-Raises ``error.StorageError`` is hash validation fails.
-"""
-
 def revision(node, raw=False):
 Obtain fulltext data for a node.
 
diff --git a/mercurial/filelog.py b/mercurial/filelog.py
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -71,10 +71,6 @@
 def iscensored(self, rev):
 return self._revlog.iscensored(rev)
 
-# Might be unused.
-def checkhash(self, text, node, p1=None, p2=None, rev=None):
-return self._revlog.checkhash(text, node, p1=p1, p2=p2, rev=rev)
-
 def revision(self, node, _df=None, raw=False):
 return self._revlog.revision(node, _df=_df, raw=raw)
 



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


D4792: filelog: remove revdiff() (API)

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG2f80eaf38ed4: filelog: remove revdiff() (API) (authored by 
indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4792?vs=11475=11606

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

AFFECTED FILES
  mercurial/filelog.py
  mercurial/repository.py
  mercurial/testing/storage.py
  tests/simplestorerepo.py

CHANGE DETAILS

diff --git a/tests/simplestorerepo.py b/tests/simplestorerepo.py
--- a/tests/simplestorerepo.py
+++ b/tests/simplestorerepo.py
@@ -487,16 +487,6 @@
 
 return nodes
 
-def revdiff(self, rev1, rev2):
-validaterev(rev1)
-validaterev(rev2)
-
-node1 = self.node(rev1)
-node2 = self.node(rev2)
-
-return mdiff.textdiff(self.revision(node1, raw=True),
-  self.revision(node2, raw=True))
-
 def heads(self, start=None, stop=None):
 # This is copied from revlog.py.
 if start is None and stop is None:
diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -396,17 +396,6 @@
 with self.assertRaises(error.LookupError):
 f.cmp(b'\x01' * 20, b'irrelevant')
 
-self.assertEqual(f.revdiff(nullrev, nullrev), b'')
-
-with self.assertRaises(IndexError):
-f.revdiff(0, nullrev)
-
-with self.assertRaises(IndexError):
-f.revdiff(nullrev, 0)
-
-with self.assertRaises(IndexError):
-f.revdiff(0, 0)
-
 # Emitting empty list is an empty generator.
 gen = f.emitrevisions([])
 with self.assertRaises(StopIteration):
@@ -459,14 +448,6 @@
 self.assertFalse(f.cmp(node, fulltext))
 self.assertTrue(f.cmp(node, fulltext + b'extra'))
 
-self.assertEqual(f.revdiff(0, 0), b'')
-self.assertEqual(f.revdiff(nullrev, 0),
- b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07%s' 
%
- fulltext)
-
-self.assertEqual(f.revdiff(0, nullrev),
- b'\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00')
-
 # Emitting a single revision works.
 gen = f.emitrevisions([node])
 rev = next(gen)
@@ -577,14 +558,6 @@
 with self.assertRaises(error.LookupError):
 f.cmp(b'\x01' * 20, b'irrelevant')
 
-self.assertEqual(f.revdiff(0, 1),
- b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
- fulltext1)
-
-self.assertEqual(f.revdiff(0, 2),
- b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x02' +
- fulltext2)
-
 # Nodes should be emitted in order.
 gen = f.emitrevisions([node0, node1, node2], revisiondata=True)
 
diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -586,15 +586,6 @@
 TODO better document the copy metadata and censoring logic.
 """
 
-def revdiff(rev1, rev2):
-"""Obtain a delta between two revision numbers.
-
-Operates on raw data in the store (``revision(node, raw=True)``).
-
-The returned data is the result of ``bdiff.bdiff`` on the raw
-revision data.
-"""
-
 def emitrevisions(nodes,
   nodesorder=None,
   revisiondata=False,
diff --git a/mercurial/filelog.py b/mercurial/filelog.py
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -78,9 +78,6 @@
 def revision(self, node, _df=None, raw=False):
 return self._revlog.revision(node, _df=_df, raw=raw)
 
-def revdiff(self, rev1, rev2):
-return self._revlog.revdiff(rev1, rev2)
-
 def emitrevisions(self, nodes, nodesorder=None,
   revisiondata=False, assumehaveparentrevisions=False,
   deltaprevious=False):



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


D4790: wireprotov2: derive "required" from presence of default value

2018-10-03 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG582676acaf6d: wireprotov2: derive required from 
presence of default value (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4790?vs=11473=11604

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

AFFECTED FILES
  mercurial/wireprotov2server.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py
--- a/mercurial/wireprotov2server.py
+++ b/mercurial/wireprotov2server.py
@@ -477,9 +477,6 @@
   A callable returning the default value for this argument. If not
   specified, ``None`` will be the default value.
 
-   ``required``
-  Bool indicating whether the argument is required.
-
``example``
   An example value for this argument.
 
@@ -535,13 +532,9 @@
 raise error.ProgrammingError('%s argument for command %s does not '
  'declare example field' % (arg, name))
 
-if 'default' in meta and meta.get('required'):
-raise error.ProgrammingError('%s argument for command %s is marked 
'
- 'as required but has a default value' 
%
- (arg, name))
+meta['required'] = 'default' not in meta
 
 meta.setdefault('default', lambda: None)
-meta.setdefault('required', False)
 meta.setdefault('validvalues', None)
 
 def register(func):
@@ -570,14 +563,17 @@
 args={
 'noderange': {
 'type': 'list',
+'default': lambda: None,
 'example': [[b'0123456...'], [b'abcdef...']],
 },
 'nodes': {
 'type': 'list',
+'default': lambda: None,
 'example': [b'0123456...'],
 },
 'nodesdepth': {
 'type': 'int',
+'default': lambda: None,
 'example': 10,
 },
 'fields': {
@@ -746,7 +742,6 @@
 },
 'nodes': {
 'type': 'list',
-'required': True,
 'example': [b'0123456...'],
 },
 'fields': {
@@ -757,7 +752,6 @@
 },
 'path': {
 'type': 'bytes',
-'required': True,
 'example': b'foo.txt',
 }
 },
@@ -848,7 +842,6 @@
 args={
 'namespace': {
 'type': 'bytes',
-'required': True,
 'example': b'ns',
 },
 },
@@ -865,7 +858,6 @@
 args={
 'key': {
 'type': 'bytes',
-'required': True,
 'example': b'foo',
 },
 },
@@ -883,7 +875,6 @@
 args={
 'nodes': {
 'type': 'list',
-'required': True,
 'example': [b'0123456...'],
 },
 'haveparents': {
@@ -899,7 +890,6 @@
 },
 'tree': {
 'type': 'bytes',
-'required': True,
 'example': b'',
 },
 },
@@ -956,22 +946,18 @@
 args={
 'namespace': {
 'type': 'bytes',
-'required': True,
 'example': b'ns',
 },
 'key': {
 'type': 'bytes',
-'required': True,
 'example': b'key',
 },
 'old': {
 'type': 'bytes',
-'required': True,
 'example': b'old',
 },
 'new': {
 'type': 'bytes',
-'required': True,
 'example': 'new',
 },
 },



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


D4803: storageutil: extract most of emitrevisions() to standalone function

2018-10-03 Thread durin42 (Augie Fackler)
durin42 added a comment.


  Oh, I just got to https://phab.mercurial-scm.org/D4805. I think the helper is 
still of somewhat limited utility and truly novel storage engines will end up 
totally reimplementing emitrevisions, but that's fine.

REPOSITORY
  rHG Mercurial

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

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


D4851: streamclone: pass narrowing related info in generatev2() and _walkstreamfiles()

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

REVISION SUMMARY
  This patch adds includes and excludes as argument to generatev2() and build a
  matcher using that and pass that into _walkstreamfiles(). This will help us in
  filtering files we stream depending on the includes and excludes passed in by
  the user.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/streamclone.py

CHANGE DETAILS

diff --git a/mercurial/streamclone.py b/mercurial/streamclone.py
--- a/mercurial/streamclone.py
+++ b/mercurial/streamclone.py
@@ -16,6 +16,7 @@
 branchmap,
 cacheutil,
 error,
+narrowspec,
 phases,
 pycompat,
 store,
@@ -190,8 +191,8 @@
 return True
 
 # This is it's own function so extensions can override it.
-def _walkstreamfiles(repo):
-return repo.store.walk()
+def _walkstreamfiles(repo, matcher=None):
+return repo.store.walk(matcher)
 
 def generatev1(repo):
 """Emit content for version 1 of a streaming clone.
@@ -527,7 +528,7 @@
 finally:
 fp.close()
 
-def generatev2(repo):
+def generatev2(repo, includes=None, excludes=None):
 """Emit content for version 2 of a streaming clone.
 
 the data stream consists the following entries:
@@ -545,8 +546,12 @@
 entries = []
 totalfilesize = 0
 
+matcher = None
+if includes or excludes:
+matcher = narrowspec.match(repo.root, includes, excludes)
+
 repo.ui.debug('scanning\n')
-for name, ename, size in _walkstreamfiles(repo):
+for name, ename, size in _walkstreamfiles(repo, matcher):
 if size:
 entries.append((_srcstore, name, _fileappend, size))
 totalfilesize += size



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


D4850: store: pass matcher to store.datafiles() and filter files according to it

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

REVISION SUMMARY
  To get narrow stream clones working, we need a way to filter the storage files
  using a matcher. This patch adds matcher as an argument to store.walk() and
  store.datafiles() so that we can filter the files returned according to the
  matcher.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/store.py

CHANGE DETAILS

diff --git a/mercurial/store.py b/mercurial/store.py
--- a/mercurial/store.py
+++ b/mercurial/store.py
@@ -374,17 +374,21 @@
 l.sort()
 return l
 
-def datafiles(self):
+def datafiles(self, matcher=None):
 return self._walk('data', True) + self._walk('meta', True)
 
 def topfiles(self):
 # yield manifest before changelog
 return reversed(self._walk('', False))
 
-def walk(self):
-'''yields (unencoded, encoded, size)'''
+def walk(self, matcher=None):
+'''yields (unencoded, encoded, size)
+
+if a matcher is passed, storage files of only those tracked paths
+are passed with matches the matcher
+'''
 # yield data files first
-for x in self.datafiles():
+for x in self.datafiles(matcher):
 yield x
 for x in self.topfiles():
 yield x
@@ -422,12 +426,14 @@
 self.vfs = vfsmod.filtervfs(vfs, encodefilename)
 self.opener = self.vfs
 
-def datafiles(self):
+def datafiles(self, matcher=None):
 for a, b, size in super(encodedstore, self).datafiles():
 try:
 a = decodefilename(a)
 except KeyError:
 a = None
+if matcher and not matcher(_gettrackedpath(a)):
+continue
 yield a, b, size
 
 def join(self, f):
@@ -551,8 +557,10 @@
 def getsize(self, path):
 return self.rawvfs.stat(path).st_size
 
-def datafiles(self):
+def datafiles(self, matcher=None):
 for f in sorted(self.fncache):
+if matcher and not matcher(_gettrackedpath(f)):
+continue
 ef = self.encode(f)
 try:
 yield f, ef, self.getsize(ef)



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


D4849: store: introduce a function to get tracked path from a fncache entry

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

REVISION SUMMARY
  This patch introduces a function to get the trakced path from a fncache entry.
  This will be used to filter out files to streamclone using a narrowmatcher.
  
  The function decodes the entries, and then returns the part after omitting the
  ending .d, .i and starting meta/ and data/.
  
  I am not sure if this is correct.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/store.py

CHANGE DETAILS

diff --git a/mercurial/store.py b/mercurial/store.py
--- a/mercurial/store.py
+++ b/mercurial/store.py
@@ -24,6 +24,21 @@
 
 parsers = policy.importmod(r'parsers')
 
+def _gettrackedpath(path):
+"""parses a fncahe entry and returns the path which that
+entry is tracking.
+
+If None is returned, it means it does not track any path.
+"""
+path = decodefilename(path)
+if path.startswith('data/'):
+return path[5:-2]
+elif path.startswith('dh/'):
+return path[3:-2]
+elif path.startswith('meta/'):
+return path[5:-2]
+return None
+
 # This avoids a collision between a file named foo and a dir named
 # foo.i or foo.d
 def _encodedir(path):



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


Re: [PATCH 07 of 13] rebase: use tuple as `replacement` keys

2018-10-03 Thread Boris FELD
On 30/09/2018 14:34, Yuya Nishihara wrote:
> On Thu, 27 Sep 2018 19:08:39 +0200, Boris Feld wrote:
>> # HG changeset patch
>> # User Boris Feld 
>> # Date 1537998671 -7200
>> #  Wed Sep 26 23:51:11 2018 +0200
>> # Node ID 79a0f8fcb5c1af9a8ad5dd292a8ef67d75b6779d
>> # Parent  77b0a61c3cc5be70c3686f9b7217e59fbf98f5c7
>> # EXP-Topic trackfold
>> # Available At https://bitbucket.org/octobus/mercurial-devel/
>> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
>> 79a0f8fcb5c1
>> rebase: use tuple as `replacement` keys
>>
>> Now that `cleanupnodes` support tuples as key, we update the rebase code to 
>> use
>> them. No changes in the replacement tracked are introduced yet.
>>
>> diff --git a/hgext/rebase.py b/hgext/rebase.py
>> --- a/hgext/rebase.py
>> +++ b/hgext/rebase.py
>> @@ -1777,15 +1777,16 @@ def clearrebased(ui, repo, destmap, stat
>>  else:
>>  succs = (newnode,)
>>  if succs is not None:
>> -replacements[oldnode] = succs
>> +replacements[(oldnode,)] = succs
> Somewhat related to this. Is there any reason to build replacements as a dict?
> I don't think we'll ever want to lookup succs by multi-oldnodes.
I don't think so, using a dict is probably an artifact of when this code
belonged to rebase or histedit. Here, a dict was probably used to ease
transitive update of finals successors.
> ___
> 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


D4803: storageutil: extract most of emitrevisions() to standalone function

2018-10-03 Thread durin42 (Augie Fackler)
durin42 requested changes to this revision.
durin42 added inline comments.
This revision now requires changes to proceed.

INLINE COMMENTS

> storageutil.py:266
> +
> +def emitrevisions(store, revs, resultcls, deltaparentfn, candeltafn,
> +  rawsizefn, revdifffn, flagsfn, sendfulltext=False,

This is a huge step backwards for remotefilelog and friends: it's all defined 
in terms of revs, whereas emitrevisions (as copypasta-inducing as it was) was 
in terms of nodes. We need to do better.

REPOSITORY
  rHG Mercurial

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

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


D4713: largefiles: automatically load largefiles extension when required (BC)

2018-10-03 Thread yuja (Yuya Nishihara)
yuja added a comment.


  >   The only data point I have is what I did, which was to only enable it on 
the command line when cloning.  The clone command modifying the local hgrc if 
necessary handled the rest.  I only started to do that because I got annoyed at 
how simply having it loaded could alter certain commands.  IDK if command line 
enabling was ever documented as the preferred alternative, but that's how I 
described it in 
https://phab.mercurial-scm.org/rHGe1dbe0b215ae137eec53ceb12440536d570a83d2.
  >   
  >   At this point, I can't recall specific issues with globally enabling, and 
they might be mostly fixed.  They definitely aren't all fixed.  That said, this 
implicit loading on demand seems roughly equivalent to the previous behavior, 
so I'm not sure that this would be any more surprising.  Repos on the command 
line would be isolated, but not with commandserver because of the global 
function wrapping.  But I'm guessing most people don't understand that about 
commandserver.
  
  IIUC, we would have to enable the largefiles extension once to clone the
  repo, but that's no longer needed. So you can enable the extension without
  hearing its name at all.
  
  Perhaps, a warning can be displayed when the non-core repository requirement
  is added?

REPOSITORY
  rHG Mercurial

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

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


Re: D4713: largefiles: automatically load largefiles extension when required (BC)

2018-10-03 Thread Yuya Nishihara
>   The only data point I have is what I did, which was to only enable it on 
> the command line when cloning.  The clone command modifying the local hgrc if 
> necessary handled the rest.  I only started to do that because I got annoyed 
> at how simply having it loaded could alter certain commands.  IDK if command 
> line enabling was ever documented as the preferred alternative, but that's 
> how I described it in 
> https://phab.mercurial-scm.org/rHGe1dbe0b215ae137eec53ceb12440536d570a83d2.
>   
>   At this point, I can't recall specific issues with globally enabling, and 
> they might be mostly fixed.  They definitely aren't all fixed.  That said, 
> this implicit loading on demand seems roughly equivalent to the previous 
> behavior, so I'm not sure that this would be any more surprising.  Repos on 
> the command line would be isolated, but not with commandserver because of the 
> global function wrapping.  But I'm guessing most people don't understand that 
> about commandserver.

IIUC, we would have to enable the largefiles extension once to clone the
repo, but that's no longer needed. So you can enable the extension without
hearing its name at all.

Perhaps, a warning can be displayed when the non-core repository requirement
is added?
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


mercurial@39966: new changeset

2018-10-03 Thread Mercurial Commits
New changeset in mercurial:

https://www.mercurial-scm.org/repo/hg/rev/707c3804e607
changeset:   39966:707c3804e607
bookmark:@
tag: tip
user:Martin von Zweigbergk 
date:Fri Sep 28 12:56:57 2018 -0700
summary: narrow: move copies overrides to core

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


[PATCH 6 of 6] help: document about "export" template keywords

2018-10-03 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1538574499 -32400
#  Wed Oct 03 22:48:19 2018 +0900
# Node ID 4b485ae732aea8285de993cecc59e60a22780c53
# Parent  5657857137840bbb4406c7d5ca2b17b99918eb94
help: document about "export" template keywords

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2033,6 +2033,14 @@ def export(ui, repo, *changesets, **opts
 
 .. container:: verbose
 
+  Template:
+
+  The following keywords are supported in addition to the common template
+  keywords and functions. See also :hg:`help templates`.
+
+  :diff:String. Diff content.
+  :parents: List of strings. Parent nodes of the changeset.
+
   Examples:
 
   - use export and import to transplant a bugfix to the current
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 5 of 6] help: document about "config" template keywords

2018-10-03 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1538574237 -32400
#  Wed Oct 03 22:43:57 2018 +0900
# Node ID 5657857137840bbb4406c7d5ca2b17b99918eb94
# Parent  221a266fb0313847e30acb095e080aee3d955a8d
help: document about "config" template keywords

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1729,6 +1729,16 @@ def config(ui, repo, *values, **opts):
 
 See :hg:`help config` for more information about config files.
 
+.. container:: verbose
+
+  Template:
+
+  The following keywords are supported. See also :hg:`help templates`.
+
+  :name:String. Config name.
+  :source:  String. Filename and line number where the item is defined.
+  :value:   String. Config value.
+
 Returns 0 on success, 1 if NAME does not exist.
 
 """
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 6] help: document about "cat" template keywords

2018-10-03 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1538573658 -32400
#  Wed Oct 03 22:34:18 2018 +0900
# Node ID 221a266fb0313847e30acb095e080aee3d955a8d
# Parent  1d6252375718965479b2602fa7558436a08cbeb1
help: document about "cat" template keywords

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1358,6 +1358,16 @@ def cat(ui, repo, file1, *pats, **opts):
 :``%b``: basename of the exporting repository
 :``\\``: literal "\\" character
 
+.. container:: verbose
+
+  Template:
+
+  The following keywords are supported in addition to the common template
+  keywords and functions. See also :hg:`help templates`.
+
+  :data:String. File content.
+  :path:String. Repository-absolute path of the file.
+
 Returns 0 on success.
 """
 opts = pycompat.byteskwargs(opts)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 6] help: document about "branches" template keywords

2018-10-03 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1538573929 -32400
#  Wed Oct 03 22:38:49 2018 +0900
# Node ID 1d6252375718965479b2602fa7558436a08cbeb1
# Parent  6d44024b584d8e8c35d693eddd87e368aa8ea3dd
help: document about "branches" template keywords

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1132,6 +1132,18 @@ def branches(ui, repo, active=False, clo
 
 Use the command :hg:`update` to switch to an existing branch.
 
+.. container:: verbose
+
+  Template:
+
+  The following keywords are supported in addition to the common template
+  keywords and functions such as ``{branch}``. See also
+  :hg:`help templates`.
+
+  :active:  Boolean. True if the branch is active.
+  :closed:  Boolean. True if the branch is closed.
+  :current: Boolean. True if it is the current branch.
+
 Returns 0.
 """
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 6] help: document about "bookmarks" template keywords

2018-10-03 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1538573538 -32400
#  Wed Oct 03 22:32:18 2018 +0900
# Node ID 6d44024b584d8e8c35d693eddd87e368aa8ea3dd
# Parent  79f940d8a9daa1ad391d5bc9cc1c19be37e6a484
help: document about "bookmarks" template keywords

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -954,6 +954,14 @@ def bookmark(ui, repo, *names, **opts):
 
 .. container:: verbose
 
+  Template:
+
+  The following keywords are supported in addition to the common template
+  keywords and functions such as ``{bookmark}``. See also
+  :hg:`help templates`.
+
+  :active:  Boolean. True if the bookmark is active.
+
   Examples:
 
   - create an active bookmark for a new line of development::
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 6] help: document about "annotate" template keywords

2018-10-03 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1538573265 -32400
#  Wed Oct 03 22:27:45 2018 +0900
# Node ID 79f940d8a9daa1ad391d5bc9cc1c19be37e6a484
# Parent  6962ebc8f817c2df412d1ab4070088909d32fa05
help: document about "annotate" template keywords

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -288,6 +288,25 @@ def annotate(ui, repo, *pats, **opts):
 anyway, although the results will probably be neither useful
 nor desirable.
 
+.. container:: verbose
+
+  Template:
+
+  The following keywords are supported in addition to the common template
+  keywords and functions. See also :hg:`help templates`.
+
+  :lines:   List of lines with annotation data.
+  :path:String. Repository-absolute path of the specified file.
+
+  And each entry of ``{lines}`` provides the following sub-keywords in
+  addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
+
+  :line:String. Line content.
+  :lineno:  Integer. Line number at that revision.
+  :path:String. Repository-absolute path of the file at that revision.
+
+  See :hg:`help templates.operators` for the list expansion syntax.
+
 Returns 0 on success.
 """
 opts = pycompat.byteskwargs(opts)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


  1   2   >