[PATCH 2 of 2] test-split: stabilize for Windows

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1513928288 18000
#  Fri Dec 22 02:38:08 2017 -0500
# Node ID feaadb8201a95e7a3f36ab3d62c1f942c4faa297
# Parent  e3de939009d730b1e26ba37b59a0d2178adef6ef
test-split: stabilize for Windows

 - $PYTHON needs to be quoted when used as an executable in $HGEDITOR.  This
   avoids the error "'c' is not recognized as an internal or external command".

 - seq.py is printing out CRLF, and then the subsequent `sed` script seems to
   convert to LF on MSYS.  IDK if python print statements can be made to print
   LF on Windows, and I'm pretty sure CRLF is baked into some other tests.

 - A stray glob was causing the 'obsstore-off' case to report 'no result code
   from test'.

 - When I ran with --debug, the `hg diff` commands in the test both printed
   color sequences, and paused the output as it was run through the pager.

diff --git a/tests/test-split.t b/tests/test-split.t
--- a/tests/test-split.t
+++ b/tests/test-split.t
@@ -20,6 +20,8 @@
   > split=
   > [ui]
   > interactive=1
+  > color=no
+  > paginate=never
   > [diff]
   > git=1
   > unified=0
@@ -57,9 +59,10 @@
   abort: cannot split working directory
   [255]
 
-Generate some content
+Generate some content.  The sed filter drop CR on Windows, which is dropped in
+the a > b line.
 
-  $ $TESTDIR/seq.py 1 5 >> a
+  $ $TESTDIR/seq.py 1 5 | sed 's/\r$//' >> a
   $ hg ci -m a1 -A a -q
   $ hg bookmark -i r1
   $ sed 's/1/11/;s/3/33/;s/5/55/' a > b
@@ -132,7 +135,7 @@
   [255]
   $ hg status
 
-  $ HGEDITOR="$PYTHON $TESTTMP/editor.py"
+  $ HGEDITOR="\"$PYTHON\" $TESTTMP/editor.py"
   $ runsplit
   diff --git a/a b/a
   1 hunks, 1 lines changed
@@ -197,7 +200,7 @@
   EDITOR: HG: user: test
   EDITOR: HG: branch 'default'
   EDITOR: HG: changed a
-  saved backup bundle to 
$TESTTMP/a/.hg/strip-backup/1df0d5c5a3ab-8341b760-split.hg (glob) (obsstore-off 
!)
+  saved backup bundle to 
$TESTTMP/a/.hg/strip-backup/1df0d5c5a3ab-8341b760-split.hg (obsstore-off !)
 
 #if obsstore-off
   $ hg bookmark
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 2] lfs: use ui.note() and ui.debug() instead of ui.write() and their flags

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1513917106 18000
#  Thu Dec 21 23:31:46 2017 -0500
# Node ID e3de939009d730b1e26ba37b59a0d2178adef6ef
# Parent  bb6a80fc969a2c5da80cbb7f29de7ca576c4e251
lfs: use ui.note() and ui.debug() instead of ui.write() and their flags

Even though the upload/download message is still in a ui.verbose check, I
switched that to ui.note() too so that the 'ui.note' label is applied.  The
debug message is no longer marked for translation because check-code complained.

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -290,9 +290,9 @@
 sizes[obj.get('oid')] = obj.get('size', 0)
 topic = {'upload': _('lfs uploading'),
  'download': _('lfs downloading')}[action]
-if self.ui.verbose and len(objects) > 1:
-self.ui.write(_('lfs: need to transfer %d objects (%s)\n')
-  % (len(objects), util.bytecount(total)))
+if len(objects) > 1:
+self.ui.note(_('lfs: need to transfer %d objects (%s)\n')
+ % (len(objects), util.bytecount(total)))
 self.ui.progress(topic, 0, total=total)
 def transfer(chunk):
 for obj in chunk:
@@ -302,8 +302,8 @@
 msg = _('lfs: downloading %s (%s)\n')
 elif action == 'upload':
 msg = _('lfs: uploading %s (%s)\n')
-self.ui.write(msg % (obj.get('oid'),
-  util.bytecount(objsize)))
+self.ui.note(msg % (obj.get('oid'),
+ util.bytecount(objsize)))
 retry = self.retry
 while True:
 try:
@@ -312,10 +312,9 @@
 break
 except socket.error as ex:
 if retry > 0:
-if self.ui.verbose:
-self.ui.write(
-_('lfs: failed: %r (remaining retry %d)\n')
-% (ex, retry))
+self.ui.note(
+_('lfs: failed: %r (remaining retry %d)\n')
+% (ex, retry))
 retry -= 1
 continue
 raise
@@ -326,8 +325,7 @@
 for _one, oid in oids:
 processed += sizes[oid]
 self.ui.progress(topic, processed, total=total)
-if self.ui.verbose:
-self.ui.write(_('lfs: processed: %s\n') % oid)
+self.ui.note(_('lfs: processed: %s\n') % oid)
 self.ui.progress(topic, pos=None, total=total)
 
 def __del__(self):
diff --git a/hgext/lfs/wrapper.py b/hgext/lfs/wrapper.py
--- a/hgext/lfs/wrapper.py
+++ b/hgext/lfs/wrapper.py
@@ -273,9 +273,7 @@
 
 def extractpointers(repo, revs):
 """return a list of lfs pointers added by given revs"""
-ui = repo.ui
-if ui.debugflag:
-ui.write(_('lfs: computing set of blobs to upload\n'))
+repo.ui.debug('lfs: computing set of blobs to upload\n')
 pointers = {}
 for r in revs:
 ctx = repo[r]
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 7 of 7] lfs: only hardlink between the usercache and local store if the blob verifies

2017-12-21 Thread Kevin Bullock
> On Dec 21, 2017, at 14:39, Matt Harbison  wrote:
> 
> # HG changeset patch
> # User Matt Harbison 
> # Date 1513883619 18000
> #  Thu Dec 21 14:13:39 2017 -0500
> # Node ID 909f1310d199e4b5f542e1e72b07f2bf992dd7a7
> # Parent  d86777c0c198848df6e9083272685a202bebe534
> lfs: only hardlink between the usercache and local store if the blob verifies

Queued the series, thanks.

pacem in terris / мир / शान्ति / ‎‫سَلاَم‬ / 平和
Kevin R. Bullock

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


Re: [PATCH 3 of 7] lfs: add note messages indicating what store holds the lfs blob

2017-12-21 Thread Kevin Bullock
> On Dec 21, 2017, at 14:39, Matt Harbison  wrote:
> 
> # HG changeset patch
> # User Matt Harbison 
> # Date 1513724024 18000
> #  Tue Dec 19 17:53:44 2017 -0500
> # Node ID 1a68987ba0c3fa2494a8fae8321cddd0876efd7f
> # Parent  00f733da93f18119d262e988985661c55c1707c3
> lfs: add note messages indicating what store holds the lfs blob
> 
> The following corruption related patches were written prior to adding the user
> level cache, and it took awhile to track down why the tests changed.  (It
> generally made things more resilient.)  But I think this will be useful to the
> end user as well.  I didn't make it --debug level, because there can be a ton 
> of
> info coming out of clone/push/pull --debug.  The pointers are sorted for test
> stability.
> 
> I opted for ui.note() instead of checking ui.verbose and then using ui.write()
> for convenience, but I see most of this extension does the latter.  I have no
> idea what the preferred form is.

I think ui.note() is better for these circumstances. Checking ui.verbose is 
useful in more complicated situations, e.g. where (1) you're checking another 
condition along with verbosity, or (2) you're using formatter.condwrite().

pacem in terris / мир / शान्ति / ‎‫سَلاَم‬ / 平和
Kevin R. Bullock

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


Re: [PATCH 4 of 4] templater: look up symbols/resources as if they were separated (issue5699)

2017-12-21 Thread Kevin Bullock
> On Dec 21, 2017, at 09:08, Yuya Nishihara  wrote:
> 
> # HG changeset patch
> # User Yuya Nishihara 
> # Date 1513862259 -32400
> #  Thu Dec 21 22:17:39 2017 +0900
> # Node ID 9d50cfedc380d05dfbe0ed8b9360603b61b3c601
> # Parent  c06827f22f361f8e1ff3431c18ed0734708149ed
> templater: look up symbols/resources as if they were separated (issue5699)

Queued the series, thanks.

pacem in terris / мир / शान्ति / ‎‫سَلاَم‬ / 平和
Kevin R. Bullock

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


mercurial@35464: 7 new changesets

2017-12-21 Thread Mercurial Commits
7 new changesets in mercurial:

https://www.mercurial-scm.org/repo/hg/rev/5bec509dc1ff
changeset:   35458:5bec509dc1ff
user:Yuya Nishihara 
date:Tue Dec 19 21:41:39 2017 +0900
summary: log: make "slowpath" condition slightly more readable

https://www.mercurial-scm.org/repo/hg/rev/b520c8f98e1e
changeset:   35459:b520c8f98e1e
user:Yuya Nishihara 
date:Mon Dec 18 21:15:53 2017 +0900
summary: sshpeer: move docstring to top

https://www.mercurial-scm.org/repo/hg/rev/8652ab4046e4
changeset:   35460:8652ab4046e4
user:Jun Wu 
date:Wed Dec 20 02:13:35 2017 -0800
summary: osutil: add a function to unblock signals

https://www.mercurial-scm.org/repo/hg/rev/3a119a423953
changeset:   35461:3a119a423953
user:Jun Wu 
date:Wed Dec 20 11:35:38 2017 -0800
summary: commandserver: unblock SIGCHLD

https://www.mercurial-scm.org/repo/hg/rev/6f754b0fe54e
changeset:   35462:6f754b0fe54e
user:Jun Wu 
date:Wed Dec 20 16:44:35 2017 -0800
summary: journal: use pager

https://www.mercurial-scm.org/repo/hg/rev/ef7e667a4f7b
changeset:   35463:ef7e667a4f7b
user:Phil Cohen 
date:Wed Dec 20 17:22:16 2017 -0600
summary: filemerge: only raise InMemoryMergeConflictsError when running 
_xmerge

https://www.mercurial-scm.org/repo/hg/rev/6915f6a40283
changeset:   35464:6915f6a40283
bookmark:@
tag: tip
user:Anton Shestakov 
date:Thu Dec 21 21:35:20 2017 +0800
summary: paper: minor adjustments to table styles

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


D1720: debug: add newlines at the end of three locations that appear to need it

2017-12-21 Thread spectral (Kyle Lippincott)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG7906354cbc68: debug: add newlines at the end of three 
locations that appear to need it (authored by spectral, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1720?vs=4536&id=4574

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

AFFECTED FILES
  hgext/patchbomb.py
  mercurial/bundle2.py
  mercurial/dispatch.py

CHANGE DETAILS

diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -451,7 +451,7 @@
 return m.group()
 else:
 ui.debug("No argument found for substitution "
- "of %i variable in alias '%s' definition."
+ "of %i variable in alias '%s' definition.\n"
  % (int(m.groups()[0]), self.name))
 return ''
 cmd = re.sub(br'\$(\d+|\$)', _checkvar, self.definition[1:])
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -2056,7 +2056,7 @@
 # The mergemarkers call will crash if marker creation is not enabled.
 # we want to avoid this if the part is advisory.
 if not inpart.mandatory and op.repo.obsstore.readonly:
-op.repo.ui.debug('ignoring obsolescence markers, feature not enabled')
+op.repo.ui.debug('ignoring obsolescence markers, feature not 
enabled\n')
 return
 new = op.repo.obsstore.mergemarkers(tr, markerdata)
 op.repo.invalidatevolatilesets()
diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -632,15 +632,15 @@
 # check if revision exist on the public destination
 publicurl = repo.ui.config('patchbomb', 'publicurl')
 if publicurl:
-repo.ui.debug('checking that revision exist in the public repo')
+repo.ui.debug('checking that revision exist in the public repo\n')
 try:
 publicpeer = hg.peer(repo, {}, publicurl)
 except error.RepoError:
 repo.ui.write_err(_('unable to access public repo: %s\n')
   % publicurl)
 raise
 if not publicpeer.capable('known'):
-repo.ui.debug('skipping existence checks: public repo too old')
+repo.ui.debug('skipping existence checks: public repo too old\n')
 else:
 out = [repo[r] for r in revs]
 known = publicpeer.known(h.node() for h in out)



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


D1719: debug: remove an 'if ui.debug()' that is not doing anything

2017-12-21 Thread spectral (Kyle Lippincott)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG3bb1a647ab42: debug: remove an 'if ui.debug()' 
that is not doing anything (authored by spectral, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1719?vs=4535&id=4573

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

AFFECTED FILES
  mercurial/debugcommands.py

CHANGE DETAILS

diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -2307,10 +2307,6 @@
 cache = {}
 ctx2str = str
 node2str = short
-if ui.debug():
-def ctx2str(ctx):
-return ctx.hex()
-node2str = hex
 for rev in scmutil.revrange(repo, revs):
 ctx = repo[rev]
 ui.write('%s\n'% ctx2str(ctx))



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


D1720: debug: add newlines at the end of three locations that appear to need it

2017-12-21 Thread krbullock (Kevin Bullock)
krbullock accepted this revision.
krbullock added a comment.
This revision is now accepted and ready to land.


  Sure, queued.

REPOSITORY
  rHG Mercurial

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

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


D1719: debug: remove an 'if ui.debug()' that is not doing anything

2017-12-21 Thread krbullock (Kevin Bullock)
krbullock accepted this revision.
krbullock added a comment.
This revision is now accepted and ready to land.


  Seems reasonable.

REPOSITORY
  rHG Mercurial

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

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


D1591: visibility: improve the message when accessing filtered obsolete rev

2017-12-21 Thread krbullock (Kevin Bullock)
krbullock requested changes to this revision.
krbullock added a comment.
This revision now requires changes to proceed.


  One nit, otherwise looks nice!

INLINE COMMENTS

> obsutil.py:780
> +else:
> +return 'superseed_split'
> +

These should be 'superseded' and 'superseded_split' (in the docstring above as 
well as here)

REPOSITORY
  rHG Mercurial

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

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


Re: [PATCH 3 of 3] test-ssh: convert dumpenv to python for Windows

2017-12-21 Thread Matt Harbison

> On Dec 17, 2017, at 2:42 PM, Matt Harbison  wrote:
> 
> 
>> On Dec 17, 2017, at 2:07 PM, Gregory Szorc  wrote:
>> 
>>> On Sun, Dec 17, 2017 at 10:44 AM, Matt Harbison  
>>> wrote:
>>> 
>>> > On Dec 16, 2017, at 7:27 PM, Matt Harbison  wrote:
>>> >
>>> > # HG changeset patch
>>> > # User Matt Harbison 
>>> > # Date 1513468682 18000
>>> > #  Sat Dec 16 18:58:02 2017 -0500
>>> > # Node ID ca9cde0697c1e923f4c9a3396343afc238ba92f2
>>> > # Parent  d1fbb07b0b7259ae4ca88434e0eda2a21359f7ec
>>> > test-ssh: convert dumpenv to python for Windows
>>> >
>>> > Previously, this complained:
>>> >
>>> >remote: '.' is not recognized as an internal or external command,
>>> >remote: operable program or batch file.
>>> >
>>> > 1 out of 4 Linux runs failed to print 17 after converting, and instead 
>>> > printed
>>> > an empty remote line.  Not sure why, but maybe the flush will help.
>>> >
>>> > diff --git a/tests/test-ssh.t b/tests/test-ssh.t
>>> > --- a/tests/test-ssh.t
>>> > +++ b/tests/test-ssh.t
>>> > @@ -598,17 +598,19 @@
>>> >   [255]
>>> >
>>> > test that custom environment is passed down to ssh executable
>>> > -  $ cat >>dumpenv <>> > -  > #! /bin/sh
>>> > -  > echo \$VAR >&2
>>> > +  $ cat >>dumpenv.py <>> > +  > from __future__ import print_function
>>> > +  > import sys
>>> > +  > from mercurial import encoding
>>> > +  > print('%s' % encoding.environ.get('VAR', ''), file=sys.stderr)
>>> > +  > sys.stderr.flush()
>>> >> EOF
>>> > -  $ chmod +x dumpenv
>>> > -  $ hg pull ssh://something --config ui.ssh="./dumpenv"
>>> > +  $ hg pull ssh://something --config ui.ssh="$PYTHON dumpenv.py"
>>> >   pulling from ssh://something/
>>> >   remote:
>>> >   abort: no suitable response from remote hg!
>>> >   [255]
>>> > -  $ hg pull ssh://something --config ui.ssh="./dumpenv" --config 
>>> > sshenv.VAR=17
>>> > +  $ hg pull ssh://something --config ui.ssh="$PYTHON dumpenv.py" 
>>> > --config sshenv.VAR=17
>>> >   pulling from ssh://something/
>>> >   remote: 17
>>> 
>>> No idea why, but if I run this in my Linux VM with -j9, it wants to append 
>>> an extra “remote: “ at this point.  If run without workers, it appears 
>>> stable.
>> 
>> The flush() shouldn't be necessary because stdio descriptors will get 
>> flushed when process exits. The new Python appears the same as the old shell 
>> script.
> 
> That was my understanding of things too, but before I added the flush, the 
> instability seemed to be to omit the “remote: 17” line (but add the empty 
> remote line).
> 
>> I suspect we are encountering a preexisting race condition. I suspect the 
>> Python version is more susceptible to it because of Python process startup 
>> overhead. Before, the shell script likely ran in ~1ms. Now, it takes >10ms. 
>> That may be enough to perturb the race condition.

An additional data point: I ran without workers, with —loop, and it failed the 
same way in 3 out of 444 runs on the same Linux VM.

>>> >   abort: no suitable response from remote hg!
>>> ___
>>> 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 6 of 7] lfs: verify lfs object content when transferring to and from the remote store

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1510895205 18000
#  Fri Nov 17 00:06:45 2017 -0500
# Node ID d86777c0c198848df6e9083272685a202bebe534
# Parent  3ffb73f5ab3b12511008dc8496c913bd639f3f38
lfs: verify lfs object content when transferring to and from the remote store

This avoids inserting corrupt files into the usercache, and local and remote
stores.  One down side is that the bad file won't be available locally for
forensic purposes after a remote download.  I'm thinking about adding an
'incoming' directory to the local lfs store to handle the download, and then
move it to the 'objects' directory after it passes verification.  That would
have the additional benefit of not concatenating each transfer chunk in memory
until the full file is transferred.

Verification isn't needed when the data is passed back through the revlog
interface or when the oid was just calculated, but otherwise it is on by
default.  The additional overhead should be well worth avoiding problems with
file based remote stores, or buggy lfs servers.

Having two different verify functions is a little sad, but the full data of the
blob is mostly passed around in memory, because that's what the revlog interface
wants.  The upload function, however, chunks up the data.  It would be ideal if
that was how the content is always handled, but that's probably a huge project.

I don't really like printing the long hash, but `hg debugdata` isn't a public
interface, and is the only way to get it.  The filelog and revision info is
nowhere near this area, so recommending `hg verify` is the easiest thing to do.

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -7,6 +7,7 @@
 
 from __future__ import absolute_import
 
+import hashlib
 import json
 import os
 import re
@@ -99,8 +100,11 @@
 self.cachevfs = lfsvfs(usercache)
 self.ui = repo.ui
 
-def write(self, oid, data):
+def write(self, oid, data, verify=True):
 """Write blob to local blobstore."""
+if verify:
+_verify(oid, data)
+
 with self.vfs(oid, 'wb', atomictemp=True) as fp:
 fp.write(data)
 
@@ -110,14 +114,23 @@
 self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
 lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))
 
-def read(self, oid):
+def read(self, oid, verify=True):
 """Read blob from local blobstore."""
 if not self.vfs.exists(oid):
+blob = self._read(self.cachevfs, oid, verify)
+self.ui.note(_('lfs: found %s in the usercache\n') % oid)
 lfutil.link(self.cachevfs.join(oid), self.vfs.join(oid))
-self.ui.note(_('lfs: found %s in the usercache\n') % oid)
 else:
 self.ui.note(_('lfs: found %s in the local lfs store\n') % oid)
-return self.vfs.read(oid)
+blob = self._read(self.vfs, oid, verify)
+return blob
+
+def _read(self, vfs, oid, verify):
+"""Read blob (after verifying) from the given store"""
+blob = vfs.read(oid)
+if verify:
+_verify(oid, blob)
+return blob
 
 def has(self, oid):
 """Returns True if the local blobstore contains the requested blob,
@@ -233,6 +246,8 @@
 request = util.urlreq.request(href)
 if action == 'upload':
 # If uploading blobs, read data from local blobstore.
+with localstore.vfs(oid) as fp:
+_verifyfile(oid, fp)
 request.data = filewithprogress(localstore.vfs(oid), None)
 request.get_method = lambda: 'PUT'
 
@@ -253,7 +268,7 @@
 
 if action == 'download':
 # If downloading blobs, store downloaded data to local blobstore
-localstore.write(oid, response)
+localstore.write(oid, response, verify=True)
 
 def _batch(self, pointers, localstore, action):
 if action not in ['upload', 'download']:
@@ -324,14 +339,14 @@
 
 def writebatch(self, pointers, fromstore):
 for p in pointers:
-content = fromstore.read(p.oid())
+content = fromstore.read(p.oid(), verify=True)
 with self.vfs(p.oid(), 'wb', atomictemp=True) as fp:
 fp.write(content)
 
 def readbatch(self, pointers, tostore):
 for p in pointers:
 content = self.vfs.read(p.oid())
-tostore.write(p.oid(), content)
+tostore.write(p.oid(), content, verify=True)
 
 class _nullremote(object):
 """Null store storing blobs to /dev/null."""
@@ -368,6 +383,24 @@
 None: _promptremote,
 }
 
+def _verify(oid, content):
+realoid = hashlib.sha256(content).hexdigest()
+if realoid != oid:
+raise error.Abort(_('detected corrupt lfs object: %s') % oid,
+  hint=_('run hg verify'))
+
+def _verifyfile(oid, fp):
+sha256 = hashlib.sha256()
+while True:
+data = fp

[PATCH 4 of 7] test-lfs: add tests around corrupted lfs objects

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1510890773 18000
#  Thu Nov 16 22:52:53 2017 -0500
# Node ID 51a98a20b44618eade6d9227cc8c5473b44450f5
# Parent  1a68987ba0c3fa2494a8fae8321cddd0876efd7f
test-lfs: add tests around corrupted lfs objects

These are mostly tests against file:// based remote stores, because that's what
we have the most control over.

The test uploading a corrupt blob to lfs-test-server demonstrates an overly
broad exception handler in the retry loop.  A corrupt blob is actually
transferred in a download, but eventually caught when it is accessed (only after
it leaves the corrupt file in a couple places locally).  I don't think we want
to trust random 3rd party implementations, and this would be a problem if there
were a `debuglfsdownload` command that simply cached the files.  And given the
cryptic errors, we should probably validate the file hash locally before
uploading, and also after downloading.

diff --git a/tests/test-lfs-test-server.t b/tests/test-lfs-test-server.t
--- a/tests/test-lfs-test-server.t
+++ b/tests/test-lfs-test-server.t
@@ -105,6 +105,55 @@
   lfs: found 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 
in the local lfs store
   3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
+Test a corrupt file download, but clear the cache first to force a download
+
+XXX: ideally, the validation would occur before polluting the usercache and
+local store, with a clearer error message.
+
+  $ rm -rf `hg config lfs.usercache`
+  $ cp 
$TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
 blob
+  $ echo 'damage' > 
$TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
+  $ rm 
../repo1/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
+  $ rm ../repo1/*
+  $ hg --repo ../repo1 update -C tip -v
+  resolving manifests
+  getting a
+  lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b 
in the local lfs store
+  getting b
+  lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b 
in the local lfs store
+  getting c
+  lfs: downloading 
d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
+  lfs: adding d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 
to the usercache
+  lfs: processed: 
d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
+  lfs: found d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 
in the local lfs store
+  abort: integrity check failed on data/c.i:0!
+  [255]
+
+BUG: the corrupted blob was added to the usercache and local store
+
+  $ cat 
../repo1/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
 | $TESTDIR/f --sha256
+  sha256=fa82ca222fc9813afad3559637960bf311170cdd80ed35287f4623eb2320a660
+  $ cat `hg config 
lfs.usercache`/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
 | $TESTDIR/f --sha256
+  sha256=fa82ca222fc9813afad3559637960bf311170cdd80ed35287f4623eb2320a660
+  $ cp blob 
$TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
+
+Test a corrupted file upload
+
+  $ echo 'another lfs blob' > b
+  $ hg ci -m 'another blob'
+  $ echo 'damage' > 
.hg/store/lfs/objects/e6/59058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0
+  $ hg push -v ../repo1
+  pushing to ../repo1
+  searching for changes
+  lfs: uploading 
e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0 (17 bytes)
+  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 500: Internal Server 
Error (oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 5)
+  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 4)
+  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 3)
+  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 2)
+  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 1)
+  abort: HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)!
+  [255]
+
 Check error message when the remote missed a blob:
 
   $ echo F > b
diff --git a/tests/test-lfs.t b/tests/test-lfs.t
--- a/tests/test-lfs.t
+++ b/tests/test-lfs.t
@@ -605,6 +605,193 @@
   added 3 changesets with 2 changes to 1 files
   $ hg -R repo14 -q verify
 
+Test damaged file scenarios.  (This also damages the usercache because of the
+hardlinks.)
+
+ 

[PATCH 7 of 7] lfs: only hardlink between the usercache and local store if the blob verifies

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1513883619 18000
#  Thu Dec 21 14:13:39 2017 -0500
# Node ID 909f1310d199e4b5f542e1e72b07f2bf992dd7a7
# Parent  d86777c0c198848df6e9083272685a202bebe534
lfs: only hardlink between the usercache and local store if the blob verifies

This fixes the issue where verify (and other read commands) would propagate
corrupt blobs.  I originalled coded this to only hardlink if 'verify=True' for
store.read(), but then good blobs weren't being linked, and this broke a bunch
of tests.  (The blob in repo5 that is being corrupted seems to be linked into
repo5 in the loop running dumpflog.py prior to it being corrupted, but only if
verify=False is handled too.)  It's probably better to do a one time extra
verification in order to create these files, so that the repo can be copied to a
removable drive.

Adding the same check to store.write() was only for completeness, but also needs
to do a one time extra verification to avoid breaking tests.

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -111,15 +111,23 @@
 # XXX: should we verify the content of the cache, and hardlink back to
 # the local store on success, but truncate, write and link on failure?
 if not self.cachevfs.exists(oid):
-self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
-lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))
+if verify or hashlib.sha256(data).hexdigest() == oid:
+self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
+lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))
 
 def read(self, oid, verify=True):
 """Read blob from local blobstore."""
 if not self.vfs.exists(oid):
 blob = self._read(self.cachevfs, oid, verify)
-self.ui.note(_('lfs: found %s in the usercache\n') % oid)
-lfutil.link(self.cachevfs.join(oid), self.vfs.join(oid))
+
+# Even if revlog will verify the content, it needs to be verified
+# now before making the hardlink to avoid propagating corrupt 
blobs.
+# Don't abort if corruption is detected, because `hg verify` will
+# give more useful info about the corruption- simply don't add the
+# hardlink.
+if verify or hashlib.sha256(blob).hexdigest() == oid:
+self.ui.note(_('lfs: found %s in the usercache\n') % oid)
+lfutil.link(self.cachevfs.join(oid), self.vfs.join(oid))
 else:
 self.ui.note(_('lfs: found %s in the local lfs store\n') % oid)
 blob = self._read(self.vfs, oid, verify)
diff --git a/tests/test-lfs.t b/tests/test-lfs.t
--- a/tests/test-lfs.t
+++ b/tests/test-lfs.t
@@ -658,8 +658,8 @@
   lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c 
in the local lfs store
   4 files, 5 changesets, 10 total revisions
 
-BUG: Verify will copy/link a corrupted file from the usercache into the local
-store, and poison it.  (The verify with a good remote now fails.)
+Verify will not copy/link a corrupted file from the usercache into the local
+store, and poison it.  (The verify with a good remote now works.)
 
   $ rm -r 
fromcorrupt/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
   $ hg -R fromcorrupt verify -v
@@ -668,10 +668,8 @@
   checking manifests
   crosschecking files in changesets and manifests
   checking files
-  lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e 
in the usercache
l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
   lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b 
in the local lfs store
-  lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e 
in the local lfs store
large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
   lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 
in the local lfs store
   lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c 
in the local lfs store
@@ -685,17 +683,12 @@
   checking manifests
   crosschecking files in changesets and manifests
   checking files
-  lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e 
in the local lfs store
-   l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
+  lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e 
in the usercache
   lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b 
in the local lfs store
   lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e 
in the local lfs store
-   large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
   lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 
in the local lfs store
   lfs: found b1a6ea88da

[PATCH 5 of 7] lfs: narrow the exceptions that trigger a transfer retry

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1512441664 18000
#  Mon Dec 04 21:41:04 2017 -0500
# Node ID 3ffb73f5ab3b12511008dc8496c913bd639f3f38
# Parent  51a98a20b44618eade6d9227cc8c5473b44450f5
lfs: narrow the exceptions that trigger a transfer retry

The retries were added to workaround TCP RESETs in fb-experimental fc8c131314a9.
I have no idea if that's been debugged yet, but this wide net caught local I/O
errors, bad hostnames and other things that shouldn't be retried.  The next
patch will validate objects as they are uploaded, and there's no need to retry
those errors.

The spec[1] does mention that certain http errors can be retried, including 500.
But let's work through the corruption detection issues first.

[1] https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -10,6 +10,7 @@
 import json
 import os
 import re
+import socket
 
 from mercurial.i18n import _
 
@@ -286,7 +287,7 @@
 self._basictransfer(obj, action, localstore)
 yield 1, obj.get('oid')
 break
-except Exception as ex:
+except socket.error as ex:
 if retry > 0:
 if self.ui.verbose:
 self.ui.write(
diff --git a/tests/test-lfs-test-server.t b/tests/test-lfs-test-server.t
--- a/tests/test-lfs-test-server.t
+++ b/tests/test-lfs-test-server.t
@@ -146,12 +146,7 @@
   pushing to ../repo1
   searching for changes
   lfs: uploading 
e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0 (17 bytes)
-  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 500: Internal Server 
Error (oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 5)
-  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 4)
-  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 3)
-  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 2)
-  lfs: failed: LfsRemoteError('HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)',) (remaining retry 1)
-  abort: HTTP error: HTTP Error 404: Not Found 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)!
+  abort: HTTP error: HTTP Error 500: Internal Server Error 
(oid=e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0, 
action=upload)!
   [255]
 
 Check error message when the remote missed a blob:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 7] tests: teach `f` to handle sha256 checksums

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1513820793 18000
#  Wed Dec 20 20:46:33 2017 -0500
# Node ID 00f733da93f18119d262e988985661c55c1707c3
# Parent  8675cce538f01075e9ef13c521d5c9db3e59e6f3
tests: teach `f` to handle sha256 checksums

diff --git a/tests/f b/tests/f
--- a/tests/f
+++ b/tests/f
@@ -59,7 +59,7 @@
 if isfile:
 if opts.type:
 facts.append('file')
-if opts.hexdump or opts.dump or opts.md5 or opts.sha1:
+if any((opts.hexdump, opts.dump, opts.md5, opts.sha1, 
opts.sha256)):
 content = open(f, 'rb').read()
 elif islink:
 if opts.type:
@@ -95,6 +95,9 @@
 if opts.sha1 and content is not None:
 h = hashlib.sha1(content)
 facts.append('sha1=%s' % h.hexdigest()[:opts.bytes])
+if opts.sha256 and content is not None:
+h = hashlib.sha256(content)
+facts.append('sha256=%s' % h.hexdigest()[:opts.bytes])
 if isstdin:
 outfile.write(b', '.join(facts) + b'\n')
 elif facts:
@@ -150,6 +153,8 @@
   help="recurse into directories")
 parser.add_option("-S", "--sha1", action="store_true",
   help="show sha1 hash of the content")
+parser.add_option("", "--sha256", action="store_true",
+  help="show sha256 hash of the content")
 parser.add_option("-M", "--md5", action="store_true",
   help="show md5 hash of the content")
 parser.add_option("-D", "--dump", action="store_true",
diff --git a/tests/test-tools.t b/tests/test-tools.t
--- a/tests/test-tools.t
+++ b/tests/test-tools.t
@@ -13,6 +13,7 @@
   check if file is newer (or same)
 -r, --recurse recurse into directories
 -S, --sha1show sha1 hash of the content
+--sha256  show sha256 hash of the content
 -M, --md5 show md5 hash of the content
 -D, --dumpdump file content
 -H, --hexdump hexdump file content
@@ -41,6 +42,9 @@
   $ f --sha1 foo
   foo: sha1=f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
 
+  $ f --sha256 foo
+  foo: sha256=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
+
 #if symlink
   $ f foo --mode
   foo: mode=644
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 7] lfs: add note messages indicating what store holds the lfs blob

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1513724024 18000
#  Tue Dec 19 17:53:44 2017 -0500
# Node ID 1a68987ba0c3fa2494a8fae8321cddd0876efd7f
# Parent  00f733da93f18119d262e988985661c55c1707c3
lfs: add note messages indicating what store holds the lfs blob

The following corruption related patches were written prior to adding the user
level cache, and it took awhile to track down why the tests changed.  (It
generally made things more resilient.)  But I think this will be useful to the
end user as well.  I didn't make it --debug level, because there can be a ton of
info coming out of clone/push/pull --debug.  The pointers are sorted for test
stability.

I opted for ui.note() instead of checking ui.verbose and then using ui.write()
for convenience, but I see most of this extension does the latter.  I have no
idea what the preferred form is.

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -96,6 +96,7 @@
 self.vfs = lfsvfs(fullpath)
 usercache = lfutil._usercachedir(repo.ui, 'lfs')
 self.cachevfs = lfsvfs(usercache)
+self.ui = repo.ui
 
 def write(self, oid, data):
 """Write blob to local blobstore."""
@@ -105,12 +106,16 @@
 # XXX: should we verify the content of the cache, and hardlink back to
 # the local store on success, but truncate, write and link on failure?
 if not self.cachevfs.exists(oid):
+self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
 lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))
 
 def read(self, oid):
 """Read blob from local blobstore."""
 if not self.vfs.exists(oid):
 lfutil.link(self.cachevfs.join(oid), self.vfs.join(oid))
+self.ui.note(_('lfs: found %s in the usercache\n') % oid)
+else:
+self.ui.note(_('lfs: found %s in the local lfs store\n') % oid)
 return self.vfs.read(oid)
 
 def has(self, oid):
diff --git a/hgext/lfs/wrapper.py b/hgext/lfs/wrapper.py
--- a/hgext/lfs/wrapper.py
+++ b/hgext/lfs/wrapper.py
@@ -279,7 +279,7 @@
 ctx = repo[r]
 for p in pointersfromctx(ctx).values():
 pointers[p.oid()] = p
-return pointers.values()
+return sorted(pointers.values())
 
 def pointersfromctx(ctx):
 """return a dict {path: pointer} for given single changectx"""
diff --git a/tests/test-lfs-test-server.t b/tests/test-lfs-test-server.t
--- a/tests/test-lfs-test-server.t
+++ b/tests/test-lfs-test-server.t
@@ -61,7 +61,9 @@
   resolving manifests
   getting a
   lfs: downloading 
31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
+  lfs: adding 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b 
to the usercache
   lfs: processed: 
31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
+  lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b 
in the local lfs store
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 When the server has some blobs already
@@ -90,12 +92,17 @@
   $ hg --repo ../repo1 update tip -v
   resolving manifests
   getting b
+  lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b 
in the local lfs store
   getting c
   lfs: downloading 
d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
+  lfs: adding d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 
to the usercache
   lfs: processed: 
d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
+  lfs: found d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 
in the local lfs store
   getting d
   lfs: downloading 
37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
+  lfs: adding 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 
to the usercache
   lfs: processed: 
37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
+  lfs: found 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 
in the local lfs store
   3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 Check error message when the remote missed a blob:
diff --git a/tests/test-lfs.t b/tests/test-lfs.t
--- a/tests/test-lfs.t
+++ b/tests/test-lfs.t
@@ -59,6 +59,7 @@
   $ hg push -v | egrep -v '^(uncompressed| )'
   pushing to $TESTTMP/server
   searching for changes
+  lfs: found f11e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b 
in the local lfs store
   2 changesets found
   adding changesets
   adding manifests
@@ -192,6 +193,7 @@
   $ echo SMALL > small
   $ hg commit -Aqm 'create a lfs file' large small
   $ hg debuglfsupload -r 'all()' -v
+  lfs: found 8e92251415339ae9b148c8da89ed5ec665905166a1ab11b09dca8fad83344738 
in the local lfs store
 
   $ cd ..
 
@@ -316,6 +318,10 @@
   $ hg commit -m branching -q
 
   $ hg bundle --base 1 bundle.hg -v
+  lfs: found 5ab7a3739a5feec94a562d070a

[PATCH 1 of 7] tests: fix a bug in `f` that prevented calculating sha1sum on a file

2017-12-21 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1513820472 18000
#  Wed Dec 20 20:41:12 2017 -0500
# Node ID 8675cce538f01075e9ef13c521d5c9db3e59e6f3
# Parent  44fd4cfc6c0ad3107cacad10c76ed38bd74948f4
tests: fix a bug in `f` that prevented calculating sha1sum on a file

diff --git a/tests/f b/tests/f
--- a/tests/f
+++ b/tests/f
@@ -59,7 +59,7 @@
 if isfile:
 if opts.type:
 facts.append('file')
-if opts.hexdump or opts.dump or opts.md5:
+if opts.hexdump or opts.dump or opts.md5 or opts.sha1:
 content = open(f, 'rb').read()
 elif islink:
 if opts.type:
diff --git a/tests/test-tools.t b/tests/test-tools.t
--- a/tests/test-tools.t
+++ b/tests/test-tools.t
@@ -38,6 +38,9 @@
   $ f foo
   foo:
 
+  $ f --sha1 foo
+  foo: sha1=f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
+
 #if symlink
   $ f foo --mode
   foo: mode=644
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1739: filemerge: only raise InMemoryMergeConflictsError when running _xmerge

2017-12-21 Thread phillco (Phil Cohen)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGef7e667a4f7b: filemerge: only raise 
InMemoryMergeConflictsError when running _xmerge (authored by phillco, 
committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1739?vs=4567&id=4572

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

AFFECTED FILES
  mercurial/filemerge.py

CHANGE DETAILS

diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py
--- a/mercurial/filemerge.py
+++ b/mercurial/filemerge.py
@@ -490,6 +490,18 @@
 return _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files,
 labels=labels)
 
+def _xmergeimm(repo, mynode, orig, fcd, fco, fca, toolconf, files, 
labels=None):
+# In-memory merge simply raises an exception on all external merge tools,
+# for now.
+#
+# It would be possible to run most tools with temporary files, but this
+# raises the question of what to do if the user only partially resolves the
+# file -- we can't leave a merge state. (Copy to somewhere in the .hg/
+# directory and tell the user how to get it is my best idea, but it's
+# clunky.)
+raise error.InMemoryMergeConflictsError('in-memory merge does not support '
+'external merge tools')
+
 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
 tool, toolpath, binary, symlink = toolconf
 if fcd.isabsent() or fco.isabsent():
@@ -688,16 +700,14 @@
 onfailure = func.onfailure
 precheck = func.precheck
 else:
-func = _xmerge
+if wctx.isinmemory():
+func = _xmergeimm
+else:
+func = _xmerge
 mergetype = fullmerge
 onfailure = _("merging %s failed!\n")
 precheck = None
 
-if wctx.isinmemory():
-raise error.InMemoryMergeConflictsError('in-memory merge does not '
-'support external merge '
-'tools')
-
 toolconf = tool, toolpath, binary, symlink
 
 if mergetype == nomerge:



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


D1740: journal: use pager

2017-12-21 Thread quark (Jun Wu)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG6f754b0fe54e: journal: use pager (authored by quark, 
committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1740?vs=4568&id=4571

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

AFFECTED FILES
  hgext/journal.py

CHANGE DETAILS

diff --git a/hgext/journal.py b/hgext/journal.py
--- a/hgext/journal.py
+++ b/hgext/journal.py
@@ -480,6 +480,7 @@
 
 limit = cmdutil.loglimit(opts)
 entry = None
+ui.pager('journal')
 for count, entry in enumerate(repo.journal.filtered(name=name)):
 if count == limit:
 break



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


Re: [PATCH] paper: minor adjustments to table styles

2017-12-21 Thread Augie Fackler

> On Dec 21, 2017, at 9:45 AM, Anton Shestakov  wrote:
> 
> # HG changeset patch
> # User Anton Shestakov 
> # Date 1513863320 -28800
> #  Thu Dec 21 21:35:20 2017 +0800
> # Node ID cdf339ec88f4264c40d3613912f49988001ebc32
> # Parent  4273260ac0d6e9bcb293607c7bdc16d0d246e6e9
> # EXP-Topic hgweb-more-info
> paper: minor adjustments to table styles

queued, thanks

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


[PATCH 3 of 4] templater: move repo, ui and cache to per-engine resources

2017-12-21 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1513861530 -32400
#  Thu Dec 21 22:05:30 2017 +0900
# Node ID c06827f22f361f8e1ff3431c18ed0734708149ed
# Parent  420618063c2cf0ab50e06e075b2feb49eef77767
templater: move repo, ui and cache to per-engine resources

diff --git a/hgext/show.py b/hgext/show.py
--- a/hgext/show.py
+++ b/hgext/show.py
@@ -252,7 +252,9 @@ def showstack(ui, repo, displayer):
 # our simplicity and the customizations required.
 # TODO use proper graph symbols from graphmod
 
-shortesttmpl = formatter.maketemplater(ui, '{shortest(node, %d)}' % 
nodelen)
+tres = formatter.templateresources(ui, repo)
+shortesttmpl = formatter.maketemplater(ui, '{shortest(node, %d)}' % 
nodelen,
+   resources=tres)
 def shortest(ctx):
 return shortesttmpl.render({'ctx': ctx, 'node': ctx.hex()})
 
@@ -438,7 +440,10 @@ def longestshortest(repo, revs, minlen=4
 If we fail to do this, a value of e.g. ``10023`` could mean either
 revision 10023 or node ``10023abc...``.
 """
-tmpl = formatter.maketemplater(repo.ui, '{shortest(node, %d)}' % minlen)
+tres = formatter.templateresources(repo.ui, repo)
+tmpl = formatter.maketemplater(repo.ui, '{shortest(node, %d)}' % minlen,
+   resources=tres)
+
 lens = [minlen]
 for rev in revs:
 ctx = repo[rev]
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1843,10 +1843,11 @@ class changeset_templater(changeset_prin
 diffopts = diffopts or {}
 
 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
-self.t = formatter.loadtemplater(ui, tmplspec,
+tres = formatter.templateresources(ui, repo)
+self.t = formatter.loadtemplater(ui, tmplspec, resources=tres,
  cache=templatekw.defaulttempl)
 self._counter = itertools.count()
-self.cache = {}
+self.cache = tres['cache']  # shared with _graphnodeformatter()
 
 self._tref = tmplspec.ref
 self._parts = {'header': '', 'footer': '',
@@ -1887,11 +1888,8 @@ class changeset_templater(changeset_prin
 props = props.copy()
 props.update(templatekw.keywords)
 props['ctx'] = ctx
-props['repo'] = self.repo
-props['ui'] = self.repo.ui
 props['index'] = index = next(self._counter)
 props['revcache'] = {'copies': copies}
-props['cache'] = self.cache
 props = pycompat.strkwargs(props)
 
 # write separator, which wouldn't work well with the header part below
@@ -2657,16 +2655,14 @@ def _graphnodeformatter(ui, displayer):
 return templatekw.showgraphnode  # fast path for "{graphnode}"
 
 spec = templater.unquotestring(spec)
-templ = formatter.maketemplater(ui, spec)
-cache = {}
+tres = formatter.templateresources(ui)
 if isinstance(displayer, changeset_templater):
-cache = displayer.cache  # reuse cache of slow templates
+tres['cache'] = displayer.cache  # reuse cache of slow templates
+templ = formatter.maketemplater(ui, spec, resources=tres)
 props = templatekw.keywords.copy()
-props['cache'] = cache
 def formatnode(repo, ctx):
 props['ctx'] = ctx
 props['repo'] = repo
-props['ui'] = repo.ui
 props['revcache'] = {}
 return templ.render(props)
 return formatnode
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -2365,8 +2365,8 @@ def debugtemplate(ui, repo, tmpl, **opts
 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
 
 if revs is None:
-t = formatter.maketemplater(ui, tmpl)
-props['ui'] = ui
+tres = formatter.templateresources(ui, repo)
+t = formatter.maketemplater(ui, tmpl, resources=tres)
 ui.write(t.render(props))
 else:
 displayer = cmdutil.makelogtemplater(ui, repo, tmpl)
diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py
--- a/mercurial/filemerge.py
+++ b/mercurial/filemerge.py
@@ -569,7 +569,8 @@ def _formatlabels(repo, fcd, fco, fca, l
 ui = repo.ui
 template = ui.config('ui', 'mergemarkertemplate')
 template = templater.unquotestring(template)
-tmpl = formatter.maketemplater(ui, template)
+tres = formatter.templateresources(ui, repo)
+tmpl = formatter.maketemplater(ui, template, resources=tres)
 
 pad = max(len(l) for l in labels)
 
diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -363,11 +363,11 @@ class templateformatter(baseformatter):
 self._out = out
 spec = lookuptemplate(ui, topic, opts.get('template', ''))
 self._tref = spec.ref
-self._t = loadtemplater(ui, spec, cache=templatekw.defaulttempl)

[PATCH 1 of 4] templater: look up mapping table through template engine

2017-12-21 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1513857805 -32400
#  Thu Dec 21 21:03:25 2017 +0900
# Node ID 692f9bbcae0853b547ab0c2f2d9d0b93ede85ab0
# Parent  b520c8f98e1e47dd221df9cfeeaaa2d19c6dc4e9
templater: look up mapping table through template engine

These functions are stub for symbol/resource separation. This series is
intended to address the following problems:

 a) internal data may be exposed to user (issue5699)
 b) defaults['repo'] (a repository name) will conflict with mapping['repo']
(a repo object) in hgweb

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -382,9 +382,7 @@ def _runrecursivesymbol(context, mapping
 raise error.Abort(_("recursive reference '%s' in template") % key)
 
 def runsymbol(context, mapping, key, default=''):
-v = mapping.get(key)
-if v is None:
-v = context._defaults.get(key)
+v = context.symbol(mapping, key)
 if v is None:
 # put poison to cut recursion. we can't move this to parsing phase
 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
@@ -626,7 +624,7 @@ def diff(context, mapping, args):
 return [s]
 return []
 
-ctx = mapping['ctx']
+ctx = context.resource(mapping, 'ctx')
 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
 
 return ''.join(chunks)
@@ -639,8 +637,8 @@ def extdata(context, mapping, args):
 raise error.ParseError(_('extdata expects one argument'))
 
 source = evalstring(context, mapping, args['source'])
-cache = mapping['cache'].setdefault('extdata', {})
-ctx = mapping['ctx']
+cache = context.resource(mapping, 'cache').setdefault('extdata', {})
+ctx = context.resource(mapping, 'ctx')
 if source in cache:
 data = cache[source]
 else:
@@ -656,7 +654,7 @@ def files(context, mapping, args):
 raise error.ParseError(_("files expects one argument"))
 
 raw = evalstring(context, mapping, args[0])
-ctx = mapping['ctx']
+ctx = context.resource(mapping, 'ctx')
 m = ctx.match([raw])
 files = list(ctx.matches(m))
 return templatekw.showlist("file", files, mapping)
@@ -692,7 +690,7 @@ def formatnode(context, mapping, args):
 # i18n: "formatnode" is a keyword
 raise error.ParseError(_("formatnode expects one argument"))
 
-ui = mapping['ui']
+ui = context.resource(mapping, 'ui')
 node = evalstring(context, mapping, args[0])
 if ui.debugflag:
 return node
@@ -858,7 +856,7 @@ def label(context, mapping, args):
 # i18n: "label" is a keyword
 raise error.ParseError(_("label expects two arguments"))
 
-ui = mapping['ui']
+ui = context.resource(mapping, 'ui')
 thing = evalstring(context, mapping, args[1])
 # preserve unknown symbol as literal so effects like 'red', 'bold',
 # etc. don't need to be quoted
@@ -1030,7 +1028,7 @@ def relpath(context, mapping, args):
 # i18n: "relpath" is a keyword
 raise error.ParseError(_("relpath expects one argument"))
 
-repo = mapping['ctx'].repo()
+repo = context.resource(mapping, 'ctx').repo()
 path = evalstring(context, mapping, args[0])
 return repo.pathto(path)
 
@@ -1043,7 +1041,7 @@ def revset(context, mapping, args):
 raise error.ParseError(_("revset expects one or more arguments"))
 
 raw = evalstring(context, mapping, args[0])
-ctx = mapping['ctx']
+ctx = context.resource(mapping, 'ctx')
 repo = ctx.repo()
 
 def query(expr):
@@ -1055,7 +1053,8 @@ def revset(context, mapping, args):
 revs = query(revsetlang.formatspec(raw, *formatargs))
 revs = list(revs)
 else:
-revsetcache = mapping['cache'].setdefault("revsetcache", {})
+cache = context.resource(mapping, 'cache')
+revsetcache = cache.setdefault("revsetcache", {})
 if raw in revsetcache:
 revs = revsetcache[raw]
 else:
@@ -1116,7 +1115,7 @@ def shortest(context, mapping, args):
 # _partialmatch() of filtered changelog could take O(len(repo)) time,
 # which would be unacceptably slow. so we look for hash collision in
 # unfiltered space, which means some hashes may be slightly longer.
-cl = mapping['ctx']._repo.unfiltered().changelog
+cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog
 return cl.shortest(node, minlength)
 
 @templatefunc('strip(text[, chars])')
@@ -1302,6 +1301,18 @@ class engine(object):
 self._aliasmap = _aliasrules.buildmap(aliases)
 self._cache = {}  # key: (func, data)
 
+def symbol(self, mapping, key):
+"""Resolve symbol to value or function; None if nothing found"""
+v = mapping.get(key)
+if v is None:
+v = self._defaults.get(key)
+return v
+
+def resource(self, mapping, key):
+"""Return internal data (e.g. cache) used for keyword/function
+evalua

[PATCH 4 of 4] templater: look up symbols/resources as if they were separated (issue5699)

2017-12-21 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1513862259 -32400
#  Thu Dec 21 22:17:39 2017 +0900
# Node ID 9d50cfedc380d05dfbe0ed8b9360603b61b3c601
# Parent  c06827f22f361f8e1ff3431c18ed0734708149ed
templater: look up symbols/resources as if they were separated (issue5699)

It wouldn't be easy to split the mapping dict into (symbols, resources). This
patch instead rejects invalid lookup taking resources.keys() as source of
truth.

The doctest is updated since mapping['repo'] is now reserved for a repo
object.

diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -94,14 +94,14 @@ Nested example:
 
 >>> def subrepos(ui, fm):
 ... fm.startitem()
-... fm.write(b'repo', b'[%s]\\n', b'baz')
+... fm.write(b'reponame', b'[%s]\\n', b'baz')
 ... files(ui, fm.nested(b'files'))
 ... fm.end()
 >>> show(subrepos)
 [baz]
 foo
 bar
->>> show(subrepos, template=b'{repo}: {join(files % "{path}", ", ")}\\n')
+>>> show(subrepos, template=b'{reponame}: {join(files % "{path}", ", ")}\\n')
 baz: foo, bar
 """
 
@@ -491,7 +491,9 @@ def templateresources(ui, repo=None):
 and function"""
 return {
 'cache': {},  # for templatekw/funcs to store reusable data
+'ctx': None,
 'repo': repo,
+'revcache': None,  # per-ctx cache; set later
 'ui': ui,
 }
 
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -1320,7 +1320,9 @@ class engine(object):
 
 def symbol(self, mapping, key):
 """Resolve symbol to value or function; None if nothing found"""
-v = mapping.get(key)
+v = None
+if key not in self._resources:
+v = mapping.get(key)
 if v is None:
 v = self._defaults.get(key)
 return v
@@ -1328,11 +1330,13 @@ class engine(object):
 def resource(self, mapping, key):
 """Return internal data (e.g. cache) used for keyword/function
 evaluation"""
-v = mapping.get(key)
+v = None
+if key in self._resources:
+v = mapping.get(key)
 if v is None:
 v = self._resources.get(key)
 if v is None:
-raise KeyError
+raise error.Abort(_('template resource not available: %s') % key)
 return v
 
 def _load(self, t):
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -206,7 +206,13 @@ never cause crash:
 
 Internal resources shouldn't be exposed (issue5699):
 
-  $ hg log -r. -T '{cache}{repo}{templ}{ui}'
+  $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
+
+Never crash on internal resource not available:
+
+  $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
+  abort: template resource not available: ctx
+  [255]
 
 Quoting for ui.logtemplate
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 4] templater: keep default resources per template engine (API)

2017-12-21 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1513859346 -32400
#  Thu Dec 21 21:29:06 2017 +0900
# Node ID 420618063c2cf0ab50e06e075b2feb49eef77767
# Parent  692f9bbcae0853b547ab0c2f2d9d0b93ede85ab0
templater: keep default resources per template engine (API)

This allows us to register a repo object as a resource in hgweb template,
without loosing '{repo}' symbol:

  symbol('repo') -> mapping['repo'] (n/a) -> defaults['repo']
  resource('repo') -> mapping['repo'] (n/a) -> resources['repo']

I'm thinking of redesigning the templatekw API to take (context, mapping)
in place of **(context._resources + mapping), but that will be a big change
and not implemented yet.

props['templ'] is ported to the resources dict as an example.

.. api::

   mapping does not contain all template resources. use context.resource()
   in template functions.

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1886,7 +1886,6 @@ class changeset_templater(changeset_prin
 '''show a single changeset or file revision'''
 props = props.copy()
 props.update(templatekw.keywords)
-props['templ'] = self.t
 props['ctx'] = ctx
 props['repo'] = self.repo
 props['ui'] = self.repo.ui
@@ -2663,7 +2662,6 @@ def _graphnodeformatter(ui, displayer):
 if isinstance(displayer, changeset_templater):
 cache = displayer.cache  # reuse cache of slow templates
 props = templatekw.keywords.copy()
-props['templ'] = templ
 props['cache'] = cache
 def formatnode(repo, ctx):
 props['ctx'] = ctx
diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -392,7 +392,6 @@ class templateformatter(baseformatter):
 props.update(item)
 if 'ctx' in item:
 # but template resources must be always available
-props['templ'] = self._t
 props['repo'] = props['ctx'].repo()
 props['revcache'] = {}
 props = pycompat.strkwargs(props)
@@ -468,18 +467,19 @@ def templatepartsmap(spec, t, partnames)
 partsmap[part] = ref
 return partsmap
 
-def loadtemplater(ui, spec, cache=None):
+def loadtemplater(ui, spec, resources=None, cache=None):
 """Create a templater from either a literal template or loading from
 a map file"""
 assert not (spec.tmpl and spec.mapfile)
 if spec.mapfile:
-return templater.templater.frommapfile(spec.mapfile, cache=cache)
-return maketemplater(ui, spec.tmpl, cache=cache)
+frommapfile = templater.templater.frommapfile
+return frommapfile(spec.mapfile, resources=resources, cache=cache)
+return maketemplater(ui, spec.tmpl, resources=resources, cache=cache)
 
-def maketemplater(ui, tmpl, cache=None):
+def maketemplater(ui, tmpl, resources=None, cache=None):
 """Create a templater from a string template 'tmpl'"""
 aliases = ui.configitems('templatealias')
-t = templater.templater(cache=cache, aliases=aliases)
+t = templater.templater(resources=resources, cache=cache, aliases=aliases)
 t.cache.update((k, templater.unquotestring(v))
for k, v in ui.configitems('templates'))
 if tmpl:
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -393,7 +393,11 @@ def runsymbol(context, mapping, key, def
 except TemplateNotFound:
 v = default
 if callable(v):
-return v(**pycompat.strkwargs(mapping))
+# TODO: templatekw functions will be updated to take (context, mapping)
+# pair instead of **props
+props = context._resources.copy()
+props.update(mapping)
+return v(**props)
 return v
 
 def buildtemplate(exp, context):
@@ -657,7 +661,10 @@ def files(context, mapping, args):
 ctx = context.resource(mapping, 'ctx')
 m = ctx.match([raw])
 files = list(ctx.matches(m))
-return templatekw.showlist("file", files, mapping)
+# TODO: pass (context, mapping) pair to keyword function
+props = context._resources.copy()
+props.update(mapping)
+return templatekw.showlist("file", files, props)
 
 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
 def fill(context, mapping, args):
@@ -878,7 +885,10 @@ def latesttag(context, mapping, args):
 if len(args) == 1:
 pattern = evalstring(context, mapping, args[0])
 
-return templatekw.showlatesttags(pattern, **pycompat.strkwargs(mapping))
+# TODO: pass (context, mapping) pair to keyword function
+props = context._resources.copy()
+props.update(mapping)
+return templatekw.showlatesttags(pattern, **pycompat.strkwargs(props))
 
 @templatefunc('localdate(date[, tz])')
 def localdate(context, mapping, args):
@@ -1062,8 +1072,11 @@ def revset(context, mapping, args):
 revs = list(revs)
 revsetcache[raw] = revs

D1736: osutil: add a function to unblock signals

2017-12-21 Thread quark (Jun Wu)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG8652ab4046e4: osutil: add a function to unblock signals 
(authored by quark, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1736?vs=4561&id=4569

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

AFFECTED FILES
  mercurial/cext/osutil.c
  mercurial/policy.py
  mercurial/util.py

CHANGE DETAILS

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -163,6 +163,10 @@
 setprocname = osutil.setprocname
 except AttributeError:
 pass
+try:
+unblocksignal = osutil.unblocksignal
+except AttributeError:
+pass
 
 # Python compatibility
 
diff --git a/mercurial/policy.py b/mercurial/policy.py
--- a/mercurial/policy.py
+++ b/mercurial/policy.py
@@ -74,7 +74,7 @@
 (r'cext', r'bdiff'): 1,
 (r'cext', r'diffhelpers'): 1,
 (r'cext', r'mpatch'): 1,
-(r'cext', r'osutil'): 1,
+(r'cext', r'osutil'): 2,
 (r'cext', r'parsers'): 4,
 }
 
diff --git a/mercurial/cext/osutil.c b/mercurial/cext/osutil.c
--- a/mercurial/cext/osutil.c
+++ b/mercurial/cext/osutil.c
@@ -20,6 +20,7 @@
 #include 
 #else
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -,6 +1112,25 @@
 }
 #endif /* defined(HAVE_LINUX_STATFS) || defined(HAVE_BSD_STATFS) */
 
+static PyObject *unblocksignal(PyObject *self, PyObject *args)
+{
+   int sig = 0;
+   int r;
+   if (!PyArg_ParseTuple(args, "i", &sig))
+   return NULL;
+   sigset_t set;
+   r = sigemptyset(&set);
+   if (r != 0)
+   return PyErr_SetFromErrno(PyExc_OSError);
+   r = sigaddset(&set, sig);
+   if (r != 0)
+   return PyErr_SetFromErrno(PyExc_OSError);
+   r = sigprocmask(SIG_UNBLOCK, &set, NULL);
+   if (r != 0)
+   return PyErr_SetFromErrno(PyExc_OSError);
+   Py_RETURN_NONE;
+}
+
 #endif /* ndef _WIN32 */
 
 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
@@ -1291,6 +1311,8 @@
{"getfstype", (PyCFunction)getfstype, METH_VARARGS,
 "get filesystem type (best-effort)\n"},
 #endif
+   {"unblocksignal", (PyCFunction)unblocksignal, METH_VARARGS,
+"change signal mask to unblock a given signal\n"},
 #endif /* ndef _WIN32 */
 #ifdef __APPLE__
{
@@ -1301,7 +1323,7 @@
{NULL, NULL}
 };
 
-static const int version = 1;
+static const int version = 2;
 
 #ifdef IS_PY3K
 static struct PyModuleDef osutil_module = {



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


D1737: commandserver: unblock SIGCHLD

2017-12-21 Thread quark (Jun Wu)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG3a119a423953: commandserver: unblock SIGCHLD (authored by 
quark, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1737?vs=4562&id=4570

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

AFFECTED FILES
  mercurial/commandserver.py

CHANGE DETAILS

diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py
--- a/mercurial/commandserver.py
+++ b/mercurial/commandserver.py
@@ -449,6 +449,8 @@
 def init(self):
 self._sock = socket.socket(socket.AF_UNIX)
 self._servicehandler.bindsocket(self._sock, self.address)
+if util.safehasattr(util, 'unblocksignal'):
+util.unblocksignal(signal.SIGCHLD)
 o = signal.signal(signal.SIGCHLD, self._sigchldhandler)
 self._oldsigchldhandler = o
 self._socketunlinked = False



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


[PATCH] paper: minor adjustments to table styles

2017-12-21 Thread Anton Shestakov
# HG changeset patch
# User Anton Shestakov 
# Date 1513863320 -28800
#  Thu Dec 21 21:35:20 2017 +0800
# Node ID cdf339ec88f4264c40d3613912f49988001ebc32
# Parent  4273260ac0d6e9bcb293607c7bdc16d0d246e6e9
# EXP-Topic hgweb-more-info
paper: minor adjustments to table styles

Adding a bit of padding to table columns on e.g. /log means content and headers
are better aligned: headers already have this padding.

Right margin is removed from #changesetEntry th because elements with display:
table-cell (such as ) ignore margins anyway.

diff --git a/mercurial/templates/static/style-paper.css 
b/mercurial/templates/static/style-paper.css
--- a/mercurial/templates/static/style-paper.css
+++ b/mercurial/templates/static/style-paper.css
@@ -213,6 +213,7 @@ h3 {
 }
 
 .bigtable td {
+  padding: 1px 4px;
   vertical-align: top;
 }
 
@@ -431,7 +432,6 @@ span.followlines-select .btn-followlines
   text-align: right;
   font-weight: normal;
   color: #999;
-  margin-right: .5em;
   vertical-align: top;
 }
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel