Re: [PATCH 2 of 2 V2] extdiff: add --mode option

2019-01-13 Thread Ludovic Chabant
> I was just speaking about the current implementation (without your patch.)
> Maybe I should say .gui flag isn't checked because the current extdiff never
> spawns more than one processes at a time.

Yeah, and I meant that I don't understand what's the difference between one vs. 
multiple processes?


> AFAIK, it duplicates alias functionality because there wasn't no [alias]
> when the extdiff extension was introduced. And I think that's the major
> reason why the extdiff is still an extension. It can't be trivially ported
> to a core command.
> 
> If the extdiff had the option to look for a diff tool from stock templates
> (i.e. [diff-tools], [merge-tools], and maybe [extdiff]), alias could be
> expressed as follows:
> 
>   [alias]
>   bcomp = extdiff --tool bcomp --per-file
> 
> This should be good enough.

Yeah makes sense, I figured extdiff predated alias. And I would indeed like if 
we could clean up the way extdiff integrates with the rest of mercurial... it's 
not far off since, right now, "hg extdiff -p blah" will just run "blah" instead 
of first checking if there's a "merge-tools.blah" config... but I guess 
implementing that would qualify as a breaking change and wouldn't be acceptable?


> You can turn off the --per-file by --no-per-file. A separate --dir option
> isn't needed as long as --no-per-file == --dir. See hg help flags.

Ah right I forgot about the "no" flags... it still feels a bit awkward to use 
IMHO (since you have to remember the implementation of the alias or extdiff in 
order to remember to cancel a specific flag) but I can live with that.

-- 
 l u d o .
 . 8 0 17 80
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D5570: hg-docker: fix Python 3.4 compatibility (for CentOS 7)

2019-01-13 Thread Mathias De Maré
Mathiasdm added a comment.


  In https://phab.mercurial-scm.org/D5570#82332, @yuja wrote:
  
  > > +if p.returncode:
  > >  +raise Exception('failed to build docker image: %s %s' % 
(p.stdout, p.stderr))
  >
  > Can you change the exception type? test-check-code.t complains about it.
  
  
  I'll submit a new version. Apologies, I didn't realize code in contrib/ would 
have impact on the tests.

REPOSITORY
  rHG Mercurial

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

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


Re: [PATCH 2 of 2 V2] extdiff: add --mode option

2019-01-13 Thread Yuya Nishihara
On Sun, 13 Jan 2019 15:31:07 -0800, Ludovic Chabant wrote:
> > A separate patch seems fine. To make clear, there's no need to check if the
> > tool is console-based or not unless multiple diff processes are spawned
> > simultaneously. Currently the .gui flag is tested only by filemerge.py.
> 
> So you mean I don't need to modify the previous code path (dir-diff), nor do 
> I need to check the gui flag if the "confirm" flag is given (i.e. one 
> external process at a time)?
> How come? Wouldn't even one gui process be a problem if you're in a 
> shell-only instance of hg?

I was just speaking about the current implementation (without your patch.)
Maybe I should say .gui flag isn't checked because the current extdiff never
spawns more than one processes at a time.

> > The latter looks worse for me. Instead, you can use [alias] to pass in
> > arguments to hg commands.
> 
> That's true, but then the entire extdiff configuration section would be 
> deprecated if that was the case, no?
> Like, AFAIK there's not much difference between:
> 
> [extdiff]
> cmd.bcomp = /path/to/bcomp
> opts.bcomp = --whatever
> 
> and:
> 
> [alias]
> bcomp = extdiff -p /path/to/bcomp -o "--whatever"
> 
> I assume the point of extdiff is to be a slighly better version of an alias 
> for the purpose of a diffing stuff, but maybe someone with a better knowledge 
> of the history of both features can correct me.

AFAIK, it duplicates alias functionality because there wasn't no [alias]
when the extdiff extension was introduced. And I think that's the major
reason why the extdiff is still an extension. It can't be trivially ported
to a core command.

If the extdiff had the option to look for a diff tool from stock templates
(i.e. [diff-tools], [merge-tools], and maybe [extdiff]), alias could be
expressed as follows:

  [alias]
  bcomp = extdiff --tool bcomp --per-file

This should be good enough.

> More importantly, I actually just realized (maybe) why a --mode option might 
> be better. Remember how I intended to have, say, BeyondCompare setup to do 
> per-file-diffs by default, and I would pass a dir-diff option for the 5% 
> cases where I want to only diff a few files in a revision?
> Well, if we have multiple flags, the extdiff/alias/whatever section of my 
> .hgrc would specify --per-file (so I get per-file diffs by default), but if I 
> then pass --dir (to revert back to a dir-diff), it wouldn't override the 
> default... the extdiff command would instead get both --per-file and --dir, 
> and would most likely throw an error because it doesn't make sense to pass 
> those options togethers.

You can turn off the --per-file by --no-per-file. A separate --dir option
isn't needed as long as --no-per-file == --dir. See hg help flags.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D5490: commit: remove ignore whitespace option on --interactive (issue6042)

2019-01-13 Thread yuja (Yuya Nishihara)
yuja added a comment.


  >   > `_performrevert()` would be in the same boat, but it was explicitly 
flagged on
  >   >  at 
https://phab.mercurial-scm.org/rHGf37a69ec3f4717fdb4f00699ca06c225f106696c. 
This implies that the `diff.ignorews` option would be used
  >   >  in practice to exclude whitespace changes while interactive 
commit/revert.
  >   >  So disabling any whitespace options would break someone's workflow.
  >   
  >   I'm confused after this comment. How do you want me to move forward?
  
  Yeah, I'm also confused about the current state. Honestly, I'm out of ideas.
  We could add diff options to commit and revert, but I'm not sure if they
  are widely used enough to being options of these commands.

REPOSITORY
  rHG Mercurial

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

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


Re: D5490: commit: remove ignore whitespace option on --interactive (issue6042)

2019-01-13 Thread Yuya Nishihara
>   > `_performrevert()` would be in the same boat, but it was explicitly 
> flagged on
>   >  at 
> https://phab.mercurial-scm.org/rHGf37a69ec3f4717fdb4f00699ca06c225f106696c. 
> This implies that the `diff.ignorews` option would be used
>   >  in practice to exclude whitespace changes while interactive 
> commit/revert.
>   >  So disabling any whitespace options would break someone's workflow.
>   
>   I'm confused after this comment. How do you want me to move forward?

Yeah, I'm also confused about the current state. Honestly, I'm out of ideas.
We could add diff options to commit and revert, but I'm not sure if they
are widely used enough to being options of these commands.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D5495: revset: add "branch" positional arguments to the merge revset

2019-01-13 Thread yuja (Yuya Nishihara)
yuja added a comment.


  Generally looks good.
  
  Can you fix a couple of nits? And if possible, fold the tests from 
https://phab.mercurial-scm.org/D5577
  into this and the next patch. We prefer including relevant test in each
  commit.
  
  > -@predicate('merge()', safe=True)
  >  +@predicate('merge(withbranch)', safe=True)
  
  `merge([withbranch])` as it is an optional parameter.
  
  >   def merge(repo, subset, x):
  > 
  > - """Changeset is a merge changeset. +"""Changeset is a merge changeset 
+ +All merge revisions are returned by default. If a "withbranch" +
pattern is provided only merges with (i.e. whose second parent +belongs to) 
those branches that match the pattern will be returned. +The simplest 
pattern is the name of a single branch. It is also +possible to specify a 
regular expression by starting the pattern +with "re:". This can be used to 
match more than one branch +(e.g. "re:branch1|branch2"). """
  >   1. i18n: "merge" is a keyword
  > - getargs(x, 0, 0, _("merge takes no arguments")) +args = 
getargsdict(x, 'merge', 'withbranch') +withbranch = '' +if 'withbranch' 
in args: +withbranch = getstring(args['withbranch'], +  
 _('withbranch argument must be a string')) +kind, 
branchname, branchmatcher = stringutil.stringmatcher(withbranch)
  
  Can you merge this with the next `if withbranch:` block to reduce the number
  of conditionally defined variables referenced later?
  
  >   cl = repo.changelog
  > 
  > - return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
  > - condrepr='') +# create the function that will be used to 
filter the subset +if withbranch:
  
  
  
  > +# matchfn is a function that returns true when a revision
  >  +# is a merge and the second parent belongs to a branch that
  >  +# matches the withbranch pattern (which can be a literal or a 
regex)
  
  Nit: these comments seem a bit verbose. It's documented in stringmatcher().
  
  > +if kind == 'literal':
  >  +matchfn = lambda r: (cl.parentrevs(r)[1] != -1
  >  + and repo[r].p2().branch() == withbranch)
  >  +else:
  >  +matchfn = lambda r: (cl.parentrevs(r)[1] != -1
  >  + and branchmatcher(repo[r].p2().branch()))
  
  If we don't have anything special about the `literal` kind, we can always use
  the `branchmatcher()`. `if kind == 'literal'` isn't needed.

REPOSITORY
  rHG Mercurial

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

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


D5496: revset: add "samebranch" keyword argument to the merge revset

2019-01-13 Thread yuja (Yuya Nishihara)
yuja added a comment.


  > -@predicate('merge(withbranch)', safe=True)
  >  +@predicate('merge(withbranch, samebranch=True)', safe=True)
  
  `[, samebranch]` or [, samebranch=False]`.
  
  >   withbranch = ''
  >   if 'withbranch' in args:
  >   withbranch = getstring(args['withbranch'],
  >  _('withbranch argument must be a string'))
  >   kind, branchname, branchmatcher = stringutil.stringmatcher(withbranch)
  > 
  > +samebranch = None
  >  +if 'samebranch' in args:
  >  +# i18n: "samebranch" is a keyword
  >  +samebranch = getboolean(args['samebranch'],
  >  +_('samebranch argument must be a True or False'))
  > 
  >   cl = repo.changelog
  >   # create the function that will be used to filter the subset
  >   if withbranch:
  >   # matchfn is a function that returns true when a revision
  >   # is a merge and the second parent belongs to a branch that
  >   # matches the withbranch pattern (which can be a literal or a regex)
  >   if kind == 'literal':
  > 
  > - matchfn = lambda r: (cl.parentrevs(r)[1] != -1
  > - and repo[r].p2().branch() == withbranch) +basematchfn = 
lambda r: (cl.parentrevs(r)[1] != -1 + and 
repo[r].p2().branch() == withbranch) else:
  > - matchfn = lambda r: (cl.parentrevs(r)[1] != -1
  > - and branchmatcher(repo[r].p2().branch()))
  > - else:
  > - # matchfn is a function that returns true when a revision is a merge
  > - matchfn = lambda r: cl.parentrevs(r)[1] != -1 +basematchfn = 
lambda r: (cl.parentrevs(r)[1] != -1 + and 
branchmatcher(repo[r].p2().branch())) +else: +basematchfn = lambda 
r: cl.parentrevs(r)[1] != -1 +if samebranch is None: +matchfn = 
basematchfn +else: +# if samebranch was specified, build a new 
match function +# that on top of basematch checks if the parents belong 
(or not) +# to the same branch (depending on the value of samebranch) + 
   def matchfn(r): +c = repo[r] +if not 
basematchfn(r): +return False +issamebranchmerge = 
c.p1().branch() == c.p2().branch() +return issamebranchmerge if 
samebranch else not issamebranchmerge
  
  These conditions can be formed as followed:
  
matchfns = [lambda r: cl.parentrevs(r)[1] != -1]
if withbranch:
matchfns.append(lambda r: branchmatcher(repo[r].p2().branch()))
if samebranch:
matchfns.append(samebranchmatchfn)

if len(matchfns) == 1:
# fast path for common case
return subset.filter(matchfn[0], ...)
else:
return subset.filter(lambda r: all(p(r) for p in matchfn), ...)

REPOSITORY
  rHG Mercurial

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

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


Re: D5495: revset: add "branch" positional arguments to the merge revset

2019-01-13 Thread Yuya Nishihara
Generally looks good.

Can you fix a couple of nits? And if possible, fold the tests from D5577
into this and the next patch. We prefer including relevant test in each
commit.

> -@predicate('merge()', safe=True)
> +@predicate('merge(withbranch)', safe=True)

`merge([withbranch])` as it is an optional parameter.

>  def merge(repo, subset, x):
> -"""Changeset is a merge changeset.
> +"""Changeset is a merge changeset
> +
> +All merge revisions are returned by default. If a "withbranch"
> +pattern is provided only merges with (i.e. whose second parent
> +belongs to) those branches that match the pattern will be returned.
> +The simplest pattern is the name of a single branch. It is also
> +possible to specify a regular expression by starting the pattern
> +with "re:". This can be used to match more than one branch
> +(e.g. "re:branch1|branch2").
>  """
>  # i18n: "merge" is a keyword
> -getargs(x, 0, 0, _("merge takes no arguments"))
> +args = getargsdict(x, 'merge', 'withbranch')
> +withbranch = ''
> +if 'withbranch' in args:
> +withbranch = getstring(args['withbranch'],
> +   _('withbranch argument must be a string'))
> +kind, branchname, branchmatcher = 
> stringutil.stringmatcher(withbranch)

Can you merge this with the next `if withbranch:` block to reduce the number
of conditionally defined variables referenced later?

>  cl = repo.changelog
> -return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
> - condrepr='')
> +# create the function that will be used to filter the subset
> +if withbranch:

> +# matchfn is a function that returns true when a revision
> +# is a merge and the second parent belongs to a branch that
> +# matches the withbranch pattern (which can be a literal or a regex)

Nit: these comments seem a bit verbose. It's documented in stringmatcher().

> +if kind == 'literal':
> +matchfn = lambda r: (cl.parentrevs(r)[1] != -1
> + and repo[r].p2().branch() == withbranch)
> +else:
> +matchfn = lambda r: (cl.parentrevs(r)[1] != -1
> + and branchmatcher(repo[r].p2().branch()))

If we don't have anything special about the `literal` kind, we can always use
the `branchmatcher()`. `if kind == 'literal'` isn't needed.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: D5496: revset: add "samebranch" keyword argument to the merge revset

2019-01-13 Thread Yuya Nishihara
> -@predicate('merge(withbranch)', safe=True)
> +@predicate('merge(withbranch, samebranch=True)', safe=True)

`[, samebranch]` or [, samebranch=False]`.

>  withbranch = ''
>  if 'withbranch' in args:
>  withbranch = getstring(args['withbranch'],
> _('withbranch argument must be a string'))
>  kind, branchname, branchmatcher = 
> stringutil.stringmatcher(withbranch)
> +samebranch = None
> +if 'samebranch' in args:
> +# i18n: "samebranch" is a keyword
> +samebranch = getboolean(args['samebranch'],
> +_('samebranch argument must be a True or False'))
>  cl = repo.changelog
>  # create the function that will be used to filter the subset
>  if withbranch:
>  # matchfn is a function that returns true when a revision
>  # is a merge and the second parent belongs to a branch that
>  # matches the withbranch pattern (which can be a literal or a regex)
>  if kind == 'literal':
> -matchfn = lambda r: (cl.parentrevs(r)[1] != -1
> - and repo[r].p2().branch() == withbranch)
> +basematchfn = lambda r: (cl.parentrevs(r)[1] != -1
> + and repo[r].p2().branch() == withbranch)
>  else:
> -matchfn = lambda r: (cl.parentrevs(r)[1] != -1
> - and branchmatcher(repo[r].p2().branch()))
> -else:
> -# matchfn is a function that returns true when a revision is a merge
> -matchfn = lambda r: cl.parentrevs(r)[1] != -1
> +basematchfn = lambda r: (cl.parentrevs(r)[1] != -1
> + and 
> branchmatcher(repo[r].p2().branch()))
> +else:
> +basematchfn = lambda r: cl.parentrevs(r)[1] != -1
> +if samebranch is None:
> +matchfn = basematchfn
> +else:
> +# if samebranch was specified, build a new match function
> +# that on top of basematch checks if the parents belong (or not)
> +# to the same branch (depending on the value of samebranch)
> +def matchfn(r):
> +c = repo[r]
> +if not basematchfn(r):
> +return False
> +issamebranchmerge = c.p1().branch() == c.p2().branch()
> +return issamebranchmerge if samebranch else not issamebranchmerge

These conditions can be formed as followed:

```
matchfns = [lambda r: cl.parentrevs(r)[1] != -1]
if withbranch:
matchfns.append(lambda r: branchmatcher(repo[r].p2().branch()))
if samebranch:
matchfns.append(samebranchmatchfn)

if len(matchfns) == 1:
# fast path for common case
return subset.filter(matchfn[0], ...)
else:
return subset.filter(lambda r: all(p(r) for p in matchfn), ...)
```
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D5577: tests: replaced mockmakedate function in test-amend.t

2019-01-13 Thread taapas1128 (Taapas Agrawal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG8633c716f908: tests: replace mockmakedate function in 
test-amend.t (authored by taapas1128, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D5577?vs=13203=13207

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

AFFECTED FILES
  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
@@ -368,30 +368,11 @@
 ==
 Test update-timestamp config option|
 ==
-  $ cat >> testmocks.py << EOF
-  > # mock out util.makedate() to supply testable values
-  > import os
-  > from mercurial import pycompat, util
-  > from mercurial.utils import dateutil
-  > 
-  > def mockmakedate():
-  > filename = os.path.join(os.environ['TESTTMP'], 'testtime')
-  > try:
-  > with open(filename, 'rb') as timef:
-  > time = float(timef.read()) + 1
-  > except IOError:
-  > time = 0.0
-  > with open(filename, 'wb') as timef:
-  > timef.write(pycompat.bytestr(time))
-  > return (time, 0)
-  > 
-  > dateutil.makedate = mockmakedate
-  > EOF
 
   $ cat >> $HGRCPATH << EOF
   > [extensions]
   > amend=
-  > testmocks=`pwd`/testmocks.py
+  > mockmakedate = $TESTDIR/mockmakedate.py
   > EOF
 
   $ hg init $TESTTMP/repo5



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


Re: [PATCH] update: fix edge-case with update.atomic-file and read-only files

2019-01-13 Thread Yuya Nishihara
On Sun, 13 Jan 2019 10:28:33 +0100, Boris FELD wrote:
> On 12/01/2019 04:32, Yuya Nishihara wrote:
> >>  self._tempname = mktempcopy(name, emptyok=('w' in mode),
> >>  createmode=createmode)
> >> +
> >> +# If we are gonna write on the tempfile, we need to make sure we 
> >> have
> >> +# the permission to do so
> >> +if 'w' in mode and os.path.isfile(name):
> >> +oldstat = filestat.frompath(name)
> >> +newstat = oldstat.stat.st_mode | stat.S_IWUSR
> >> +os.chmod(self._tempname, newstat)
> > Isn't it better to add an option for mktempcopy() to forcibly flag S_IWUSR
> > bit on?
> 
> I was hesitant between the two designs. I give a try to the mktempcopy
> modification design thanks to your comment and it seems better.
> 
> I'm not familiar with how Windows handle file permissions but I see that
> copymode for windows does nothing. Should we also avoid enforcing the
> writable bit on Windows platform?

Maybe no. If we didn't copy the file mode, the temporary file should be
writable.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH V2] update: fix edge-case with update.atomic-file and read-only files

2019-01-13 Thread Yuya Nishihara
On Sun, 13 Jan 2019 10:38:37 +0100, Boris Feld wrote:
> # HG changeset patch
> # User Boris Feld 
> # Date 1547128621 -3600
> #  Thu Jan 10 14:57:01 2019 +0100
> # Node ID d46392ed9a76773561c74c8df2063aaad4c3c952
> # Parent  963462786f6e028563bcedc9008622e0f3b59c86
> # EXP-Topic atomic-update-read-only
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
> d46392ed9a76
> update: fix edge-case with update.atomic-file and read-only files
> 
> We used to create the tempfile with the original file mode. That means
> creating a read-only tempfile when the original file is read-only, which crash
> if we need to write on the tempfile.
> 
> The file in the working directory ends up being writable with and without the
> atomic update config, so the behavior is the same.
> 
> diff --git a/mercurial/util.py b/mercurial/util.py
> --- a/mercurial/util.py
> +++ b/mercurial/util.py
> @@ -2045,7 +2045,7 @@ def splitpath(path):
>  function if need.'''
>  return path.split(pycompat.ossep)
>  
> -def mktempcopy(name, emptyok=False, createmode=None):
> +def mktempcopy(name, emptyok=False, createmode=None, enforcewritable=False):
>  """Create a temporary file with the same contents from name
>  
>  The permission bits are copied from the original file.
> @@ -2062,6 +2062,15 @@ def mktempcopy(name, emptyok=False, crea
>  # what we want.  If the original file already exists, just copy
>  # its mode.  Otherwise, manually obey umask.
>  copymode(name, temp, createmode)
> +
> +# If the resulting temporary file needs to be writable enforce it now.
> +# createmode argument of copy mode is not used when the original file
> +# already exists so we need to do it outside of it
> +if enforcewritable:
> +oldstat = filestat.frompath(temp)
> +newstat = oldstat.stat.st_mode | stat.S_IWUSR
> +os.chmod(temp, newstat)

I meant it would be better handled in copymode() where the chmod() business
is handled.

  os.chmod(dst, st_mode | addmode)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 8 of 8] revset: introduce an API that avoids `formatspec` input serialization

2019-01-13 Thread Yuya Nishihara
On Sun, 13 Jan 2019 18:53:13 +0900, Yuya Nishihara wrote:
> So here we have string to parse, b''.join(ret), and replacements, inputs.
> If b''.join(ret) contained '$0' instead of 'internal(0)', and if inputs
> were dict of {'$0': alias('$0', ..., ('smartset', inputs[0]))}, we can just
> feed them to _aliasrules.
> 
>   aliases = build_dict_of_inputs(inputs)
>   tree = _parsewith(b''.join(ret), syminitletters=_aliassyminitletters)
>   tree = _aliasrules.expand(aliases, tree)

Actually there's a simpler tool, parser.buildtree(). We still need an invalid
placeholder symbol that can be parsed, e.g. '$', but we don't have to care
about the internals of the alias expansion.

  tree = _parsewith(b''.join(ret), syminitletters=_aliassyminitletters)
  tree = parser.buildtree(tree, ('symbol', '$'), ('smartset', inputs[0]), ...)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 2 V2] extdiff: add --mode option

2019-01-13 Thread Ludovic Chabant

> A separate patch seems fine. To make clear, there's no need to check if the
> tool is console-based or not unless multiple diff processes are spawned
> simultaneously. Currently the .gui flag is tested only by filemerge.py.

So you mean I don't need to modify the previous code path (dir-diff), nor do I 
need to check the gui flag if the "confirm" flag is given (i.e. one external 
process at a time)?
How come? Wouldn't even one gui process be a problem if you're in a shell-only 
instance of hg?


> The latter looks worse for me. Instead, you can use [alias] to pass in
> arguments to hg commands.

That's true, but then the entire extdiff configuration section would be 
deprecated if that was the case, no?
Like, AFAIK there's not much difference between:

[extdiff]
cmd.bcomp = /path/to/bcomp
opts.bcomp = --whatever

and:

[alias]
bcomp = extdiff -p /path/to/bcomp -o "--whatever"

I assume the point of extdiff is to be a slighly better version of an alias for 
the purpose of a diffing stuff, but maybe someone with a better knowledge of 
the history of both features can correct me.

More importantly, I actually just realized (maybe) why a --mode option might be 
better. Remember how I intended to have, say, BeyondCompare setup to do 
per-file-diffs by default, and I would pass a dir-diff option for the 5% cases 
where I want to only diff a few files in a revision?
Well, if we have multiple flags, the extdiff/alias/whatever section of my .hgrc 
would specify --per-file (so I get per-file diffs by default), but if I then 
pass --dir (to revert back to a dir-diff), it wouldn't override the default... 
the extdiff command would instead get both --per-file and --dir, and would most 
likely throw an error because it doesn't make sense to pass those options 
togethers.
However, with a --mode option, the one I pass on the command line would 
correctly override the one specified in the .hgrc, and everything works as you 
would expect... does that make sense?
-- 
 l u d o .
 . 8 0 17 80
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D5497: revset: add tests for the new merge() arguments (withbranch and samebranch)

2019-01-13 Thread angel.ezquerra (Angel Ezquerra)
angel.ezquerra updated this revision to Diff 13206.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D5497?vs=13019=13206

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

AFFECTED FILES
  tests/test-help.t
  tests/test-revset.t

CHANGE DETAILS

diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -2954,3 +2954,107 @@
   * set:
   
   0
+
+test the merge() revset parameters
+
+create a few merge revisions to test merge() parameters
+  $ hg up 9
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo a > a
+  $ hg branch --force ".a.b.c."
+  marked working directory as branch .a.b.c.
+  $ hg add a
+  $ hg commit -m "added a"
+  created new head
+  $ hg merge 7
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg commit -m "same branch merge 1"
+  $ hg up 10
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo a2 > a
+  $ hg commit -m "changed a to a2"
+  created new head
+  $ hg up 11
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge 12
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg commit -m "same branch merge 2"
+  $ echo a3 > a
+  $ hg commit -m "changed a to a3"
+  $ hg up 12
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg branch --force "_a_b_c_"
+  marked working directory as branch _a_b_c_
+  $ hg merge 14
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg commit -m "same branch merge 3 (both parents on same branch while merge 
is on another branch)"
+  created new head
+  $ hg up 14
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo a4 > a
+  $ hg commit -m "changed a to a4"
+  $ hg up 15
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge 16
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg commit -m "different branch merge 1"
+  $ hg up 16
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo a5 > a
+  $ hg branch --force "_a_b_c_"
+  marked working directory as branch _a_b_c_
+  $ hg commit -m "changed a to a5"
+  created new head
+  $ hg up 17
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge 18
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg commit -m "different branch merge 2"
+
+test that the merge revisions can be split between those where
+samebranch is True and those where it is False
+  $ log 'merge()'
+  6
+  11
+  13
+  15
+  17
+  19
+
+show merges with the same branch
+  $ log 'merge(samebranch=True)'
+  11
+  13
+  15
+  19
+
+show merges with other branches (but not the same branch)
+  $ log 'merge(samebranch=False)'
+  6
+  17
+
+show merges with a particular branch
+  $ log 'merge(.a.b.c.)'
+  11
+  13
+  15
+  17
+  $ log 'merge(-a-b-c-)'
+  6
+
+  $ log 'merge(".a.b.c.", samebranch=False)'
+  17
+
+show merges with multiple branches
+  $ log 'merge("re:.a.b.c.")'
+  6
+  11
+  13
+  15
+  17
+  19
\ No newline at end of file
diff --git a/tests/test-help.t b/tests/test-help.t
--- a/tests/test-help.t
+++ b/tests/test-help.t
@@ -1743,8 +1743,20 @@
 Test section lookup
 
   $ hg help revset.merge
-  "merge()"
-Changeset is a merge changeset.
+  "merge(withbranch, samebranch=True)"
+Changeset is a merge changeset
+  
+All merge revisions are returned by default. If a "withbranch" pattern
+is provided only merges with (i.e. whose second parent belongs to) 
those
+branches that match the pattern will be returned. The simplest pattern
+is the name of a single branch. It is also possible to specify a 
regular
+expression by starting the pattern with "re:". This can be used to 
match
+more than one branch (e.g. "re:branch1|branch2").
+  
+It is also possible to only return merges where both parents belong to
+the same branch by specifying samebranch=True. If samebranch=False is
+set then only merges where both parents do not belong to the same 
branch
+will be returned.
   
   $ hg help glossary.dag
   DAG



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


D5496: revset: add "samebranch" keyword argument to the merge revset

2019-01-13 Thread angel.ezquerra (Angel Ezquerra)
angel.ezquerra updated this revision to Diff 13205.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D5496?vs=13018=13205

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

AFFECTED FILES
  mercurial/revset.py

CHANGE DETAILS

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1249,7 +1249,7 @@
 pass
 return baseset(datarepr=('', subset, os))
 
-@predicate('merge(withbranch)', safe=True)
+@predicate('merge(withbranch, samebranch=True)', safe=True)
 def merge(repo, subset, x):
 """Changeset is a merge changeset
 
@@ -1260,29 +1260,50 @@
 possible to specify a regular expression by starting the pattern
 with "re:". This can be used to match more than one branch
 (e.g. "re:branch1|branch2").
+
+It is also possible to only return merges where both parents belong to
+the same branch by specifying samebranch=True. If samebranch=False is
+set then only merges where both parents do not belong to the same branch
+will be returned.
 """
 # i18n: "merge" is a keyword
-args = getargsdict(x, 'merge', 'withbranch')
+args = getargsdict(x, 'merge', 'withbranch samebranch')
 withbranch = ''
 if 'withbranch' in args:
 withbranch = getstring(args['withbranch'],
_('withbranch argument must be a string'))
 kind, branchname, branchmatcher = stringutil.stringmatcher(withbranch)
+samebranch = None
+if 'samebranch' in args:
+# i18n: "samebranch" is a keyword
+samebranch = getboolean(args['samebranch'],
+_('samebranch argument must be a True or False'))
 cl = repo.changelog
 # create the function that will be used to filter the subset
 if withbranch:
 # matchfn is a function that returns true when a revision
 # is a merge and the second parent belongs to a branch that
 # matches the withbranch pattern (which can be a literal or a regex)
 if kind == 'literal':
-matchfn = lambda r: (cl.parentrevs(r)[1] != -1
- and repo[r].p2().branch() == withbranch)
+basematchfn = lambda r: (cl.parentrevs(r)[1] != -1
+ and repo[r].p2().branch() == withbranch)
 else:
-matchfn = lambda r: (cl.parentrevs(r)[1] != -1
- and branchmatcher(repo[r].p2().branch()))
-else:
-# matchfn is a function that returns true when a revision is a merge
-matchfn = lambda r: cl.parentrevs(r)[1] != -1
+basematchfn = lambda r: (cl.parentrevs(r)[1] != -1
+ and branchmatcher(repo[r].p2().branch()))
+else:
+basematchfn = lambda r: cl.parentrevs(r)[1] != -1
+if samebranch is None:
+matchfn = basematchfn
+else:
+# if samebranch was specified, build a new match function
+# that on top of basematch checks if the parents belong (or not)
+# to the same branch (depending on the value of samebranch)
+def matchfn(r):
+c = repo[r]
+if not basematchfn(r):
+return False
+issamebranchmerge = c.p1().branch() == c.p2().branch()
+return issamebranchmerge if samebranch else not issamebranchmerge
 return subset.filter(matchfn, condrepr='')
 
 @predicate('branchpoint()', safe=True)



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


D5495: revset: add "branch" positional arguments to the merge revset

2019-01-13 Thread angel.ezquerra (Angel Ezquerra)
angel.ezquerra updated this revision to Diff 13204.
angel.ezquerra edited the summary of this revision.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D5495?vs=13017=13204

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

AFFECTED FILES
  mercurial/revset.py

CHANGE DETAILS

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1249,15 +1249,41 @@
 pass
 return baseset(datarepr=('', subset, os))
 
-@predicate('merge()', safe=True)
+@predicate('merge(withbranch)', safe=True)
 def merge(repo, subset, x):
-"""Changeset is a merge changeset.
+"""Changeset is a merge changeset
+
+All merge revisions are returned by default. If a "withbranch"
+pattern is provided only merges with (i.e. whose second parent
+belongs to) those branches that match the pattern will be returned.
+The simplest pattern is the name of a single branch. It is also
+possible to specify a regular expression by starting the pattern
+with "re:". This can be used to match more than one branch
+(e.g. "re:branch1|branch2").
 """
 # i18n: "merge" is a keyword
-getargs(x, 0, 0, _("merge takes no arguments"))
+args = getargsdict(x, 'merge', 'withbranch')
+withbranch = ''
+if 'withbranch' in args:
+withbranch = getstring(args['withbranch'],
+   _('withbranch argument must be a string'))
+kind, branchname, branchmatcher = stringutil.stringmatcher(withbranch)
 cl = repo.changelog
-return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
- condrepr='')
+# create the function that will be used to filter the subset
+if withbranch:
+# matchfn is a function that returns true when a revision
+# is a merge and the second parent belongs to a branch that
+# matches the withbranch pattern (which can be a literal or a regex)
+if kind == 'literal':
+matchfn = lambda r: (cl.parentrevs(r)[1] != -1
+ and repo[r].p2().branch() == withbranch)
+else:
+matchfn = lambda r: (cl.parentrevs(r)[1] != -1
+ and branchmatcher(repo[r].p2().branch()))
+else:
+# matchfn is a function that returns true when a revision is a merge
+matchfn = lambda r: cl.parentrevs(r)[1] != -1
+return subset.filter(matchfn, condrepr='')
 
 @predicate('branchpoint()', safe=True)
 def branchpoint(repo, subset, x):



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


Re: [PATCH] update: fix edge-case with update.atomic-file and read-only files

2019-01-13 Thread Martin von Zweigbergk via Mercurial-devel
On Sun, Jan 13, 2019, 01:26 Boris FELD  Thank you for the thorough review
> On 11/01/2019 18:24, Martin von Zweigbergk via Mercurial-devel wrote:
>
>
>
> On Fri, Jan 11, 2019 at 7:26 AM Boris Feld 
> wrote:
>
> +
>> +  $ find * -printf "%f:%p:%m\n"
>> +  a1:a1:644
>> +  a2:a2:755
>> +  b1:b1:644
>> +  b2:b2:755
>> +  d:d:644
>> +  ro:ro:644
>> +
>> +Manually reset the mode of the read-only file
>>
>
> Can we also have a test case where a read-only file is committed (so
> updating to it should create it in read-only mode)?
>
> I tried modifying the test case to commit `ro` in read-only for changeset
> #2 but it didn't changed a things. I think that Mercurial is only tracking
> the exec bit on files. I'm not surprised that the files ends up writable
> after an update (with or without atomic temp option).
>
> Do you think it's a bug?
>
No, just not supported. I should have known that. Sorry to make you waste
time trying that.

Perhaps we should add a test for updating a read-only file when *not* using
atomic-temp. I assume we don't since nothing failed when you ran with
--extra-config-opt. I don't even know how it behaves.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D5577: tests: replaced mockmakedate function in test-amend.t

2019-01-13 Thread taapas1128 (Taapas Agrawal)
taapas1128 added a subscriber: yuja.
taapas1128 added a comment.


  @yuja please review this.

REPOSITORY
  rHG Mercurial

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

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


D5490: commit: remove ignore whitespace option on --interactive (issue6042)

2019-01-13 Thread navaneeth.suresh (Navaneeth Suresh)
navaneeth.suresh added a comment.


  > `_performrevert()` would be in the same boat, but it was explicitly flagged 
on
  >  at 
https://phab.mercurial-scm.org/rHGf37a69ec3f4717fdb4f00699ca06c225f106696c. 
This implies that the `diff.ignorews` option would be used
  >  in practice to exclude whitespace changes while interactive commit/revert.
  >  So disabling any whitespace options would break someone's workflow.
  
  I'm confused after this comment. How do you want me to move forward?

REPOSITORY
  rHG Mercurial

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

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


D5554: histedit: added rewrite.update-timestamp to fold and mess

2019-01-13 Thread taapas1128 (Taapas Agrawal)
taapas1128 added a comment.


  @yuja thanks for the edits and queuing .

REPOSITORY
  rHG Mercurial

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

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


D5577: tests: replaced mockmakedate function in test-amend.t

2019-01-13 Thread taapas1128 (Taapas Agrawal)
taapas1128 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/D5577

AFFECTED FILES
  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
@@ -368,30 +368,11 @@
 ==
 Test update-timestamp config option|
 ==
-  $ cat >> testmocks.py << EOF
-  > # mock out util.makedate() to supply testable values
-  > import os
-  > from mercurial import pycompat, util
-  > from mercurial.utils import dateutil
-  > 
-  > def mockmakedate():
-  > filename = os.path.join(os.environ['TESTTMP'], 'testtime')
-  > try:
-  > with open(filename, 'rb') as timef:
-  > time = float(timef.read()) + 1
-  > except IOError:
-  > time = 0.0
-  > with open(filename, 'wb') as timef:
-  > timef.write(pycompat.bytestr(time))
-  > return (time, 0)
-  > 
-  > dateutil.makedate = mockmakedate
-  > EOF
 
   $ cat >> $HGRCPATH << EOF
   > [extensions]
   > amend=
-  > testmocks=`pwd`/testmocks.py
+  > mockmakedate = $TESTDIR/mockmakedate.py
   > EOF
 
   $ hg init $TESTTMP/repo5



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


D5554: histedit: added rewrite.update-timestamp to fold and mess

2019-01-13 Thread taapas1128 (Taapas Agrawal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG6459797090ea: histedit: add rewrite.update-timestamp 
support to fold and mess (authored by taapas1128, committed by ).

CHANGED PRIOR TO COMMIT
  https://phab.mercurial-scm.org/D5554?vs=13201=13202#toc

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D5554?vs=13201=13202

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

AFFECTED FILES
  hgext/histedit.py
  tests/mockmakedate.py
  tests/test-histedit-edit.t
  tests/test-histedit-fold.t

CHANGE DETAILS

diff --git a/tests/test-histedit-fold.t b/tests/test-histedit-fold.t
--- a/tests/test-histedit-fold.t
+++ b/tests/test-histedit-fold.t
@@ -15,6 +15,7 @@
   > logt = log --template '{rev}:{node|short} {desc|firstline}\n'
   > [extensions]
   > histedit=
+  > mockmakedate = $TESTDIR/mockmakedate.py
   > EOF
 
 
@@ -597,3 +598,110 @@
   o  8f0162e483d0 aa
   
 
+  $ cd ..
+
+
+Test update-timestamp config option|
+
+
+  $ addwithdate ()
+  > {
+  > echo $1 > $1
+  > hg add $1
+  > hg ci -m $1 -d "$2 0"
+  > }
+
+  $ initrepo ()
+  > {
+  > hg init r
+  > cd r
+  > addwithdate a 1
+  > addwithdate b 2
+  > addwithdate c 3
+  > addwithdate d 4
+  > addwithdate e 5
+  > addwithdate f 6
+  > }
+
+  $ initrepo
+
+log before edit
+
+  $ hg log
+  changeset:   5:178e35e0ce73
+  tag: tip
+  user:test
+  date:Thu Jan 01 00:00:06 1970 +
+  summary: f
+  
+  changeset:   4:1ddb6c90f2ee
+  user:test
+  date:Thu Jan 01 00:00:05 1970 +
+  summary: e
+  
+  changeset:   3:532247a8969b
+  user:test
+  date:Thu Jan 01 00:00:04 1970 +
+  summary: d
+  
+  changeset:   2:ff2c9fa2018b
+  user:test
+  date:Thu Jan 01 00:00:03 1970 +
+  summary: c
+  
+  changeset:   1:97d72e5f12c7
+  user:test
+  date:Thu Jan 01 00:00:02 1970 +
+  summary: b
+  
+  changeset:   0:8580ff50825a
+  user:test
+  date:Thu Jan 01 00:00:01 1970 +
+  summary: a
+  
+
+  $ hg histedit 1ddb6c90f2ee --commands - 2>&1 --config 
rewrite.update-timestamp=True < pick 178e35e0ce73 f
+  > fold 1ddb6c90f2ee e
+  > EOF
+
+log after edit
+observe time from f is updated
+
+  $ hg log
+  changeset:   4:f7909b1863a2
+  tag: tip
+  user:test
+  date:Thu Jan 01 00:00:01 1970 +
+  summary: f
+  
+  changeset:   3:532247a8969b
+  user:test
+  date:Thu Jan 01 00:00:04 1970 +
+  summary: d
+  
+  changeset:   2:ff2c9fa2018b
+  user:test
+  date:Thu Jan 01 00:00:03 1970 +
+  summary: c
+  
+  changeset:   1:97d72e5f12c7
+  user:test
+  date:Thu Jan 01 00:00:02 1970 +
+  summary: b
+  
+  changeset:   0:8580ff50825a
+  user:test
+  date:Thu Jan 01 00:00:01 1970 +
+  summary: a
+  
+post-fold manifest
+  $ hg manifest
+  a
+  b
+  c
+  d
+  e
+  f
+
+  $ cd ..
diff --git a/tests/test-histedit-edit.t b/tests/test-histedit-edit.t
--- a/tests/test-histedit-edit.t
+++ b/tests/test-histedit-edit.t
@@ -4,6 +4,7 @@
   > [extensions]
   > histedit=
   > strip=
+  > mockmakedate = $TESTDIR/mockmakedate.py
   > EOF
 
   $ initrepo ()
@@ -484,6 +485,56 @@
 
   $ cd ..
 
+
+Test update-timestamp config option in mess|
+
+
+  $ addwithdate ()
+  > {
+  > echo $1 > $1
+  > hg add $1
+  > hg ci -m $1 -d "$2 0"
+  > }
+
+  $ initrepo ()
+  > {
+  > hg init r2
+  > cd r2
+  > addwithdate a 1
+  > addwithdate b 2
+  > addwithdate c 3
+  > addwithdate d 4
+  > addwithdate e 5
+  > addwithdate f 6
+  > }
+
+  $ initrepo
+
+log before edit
+
+  $ hg log --limit 1
+  changeset:   5:178e35e0ce73
+  tag: tip
+  user:test
+  date:Thu Jan 01 00:00:06 1970 +
+  summary: f
+  
+  $ hg histedit tip --commands - 2>&1 --config rewrite.update-timestamp=True 
<< EOF | fixbundle
+  > mess 178e35e0ce73 f
+  > EOF
+
+log after edit
+
+  $ hg log --limit 1
+  changeset:   5:98bf456d476b
+  tag: tip
+  user:test
+  date:Thu Jan 01 00:00:00 1970 +
+  summary: f
+  
+
+  $ cd ..
+
 warn the user on editing tagged commits
 
   $ hg init issue4017
diff --git a/tests/mockmakedate.py b/tests/mockmakedate.py
new file mode 100644
--- /dev/null
+++ b/tests/mockmakedate.py
@@ -0,0 +1,21 @@
+# mock out util.makedate() to supply testable values
+
+from __future__ import absolute_import
+
+import os
+
+from mercurial import pycompat
+from mercurial.utils import dateutil
+
+def mockmakedate():
+filename = os.path.join(os.environ['TESTTMP'], 'testtime')
+try:
+with open(filename, 'rb') as timef:
+time = float(timef.read()) + 1
+

D5554: histedit: added rewrite.update-timestamp to fold and mess

2019-01-13 Thread yuja (Yuya Nishihara)
yuja added a comment.


  Queued with minor modifications, thanks.
  
  > - a/tests/test-histedit-fold.t +++ b/tests/test-histedit-fold.t @@ -15,6 
+15,7 @@ > logt = log --template '{rev}:{node|short} {desc|firstline}\n' > 
[extensions] > histedit= +  > mockmakedate = $TESTDIR/mockmakedate.py > EOF
  
  Inserted `cd ..`
  
  > +-==
  >  +Test update-timestamp config option|
  >  +==
  >  +  $ addwithdate ()
  >  +  > {
  >  +  > echo $1 > $1
  >  +  > hg add $1
  >  +  > hg ci -m $1 -d "$2 0"
  >  +  > }
  >  +
  >  +  $ initrepo ()
  >  +  > {
  >  +  > hg init r
  >  +  > cd r
  
  and renamed `r` to `r2` to get around name conflicts.
  
  > +++ b/tests/mockmakedate.py
  >  @@ -0,0 +1,19 @@
  >  +from __future__ import absolute_import
  >  +
  >  +# mock out util.makedate() to supply testable values
  >  +import os
  >  +from mercurial import pycompat, util
  >  +from mercurial.utils import dateutil
  
  Removed unused import of `util`.

REPOSITORY
  rHG Mercurial

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

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


Re: D5554: histedit: added rewrite.update-timestamp to fold and mess

2019-01-13 Thread Yuya Nishihara
Queued with minor modifications, thanks.

> --- a/tests/test-histedit-fold.t
> +++ b/tests/test-histedit-fold.t
> @@ -15,6 +15,7 @@
>> logt = log --template '{rev}:{node|short} {desc|firstline}\n'
>> [extensions]
>> histedit=
> +  > mockmakedate = $TESTDIR/mockmakedate.py
>> EOF
>  

Inserted `cd ..`

> +-==
> +Test update-timestamp config option|
> +==
> +  $ addwithdate ()
> +  > {
> +  > echo $1 > $1
> +  > hg add $1
> +  > hg ci -m $1 -d "$2 0"
> +  > }
> +
> +  $ initrepo ()
> +  > {
> +  > hg init r
> +  > cd r

and renamed `r` to `r2` to get around name conflicts.

> +++ b/tests/mockmakedate.py
> @@ -0,0 +1,19 @@
> +from __future__ import absolute_import
> +
> +# mock out util.makedate() to supply testable values
> +import os
> +from mercurial import pycompat, util
> +from mercurial.utils import dateutil

Removed unused import of `util`.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 8 of 8] revset: introduce an API that avoids `formatspec` input serialization

2019-01-13 Thread Yuya Nishihara
On Sun, 13 Jan 2019 08:40:41 +0100, Boris FELD wrote:
> On 12/01/2019 06:00, Yuya Nishihara wrote:
> > On Fri, 11 Jan 2019 12:29:10 +0100, Boris Feld wrote:
> >> # HG changeset patch
> >> # User Boris Feld 
> >> # Date 1546605681 -3600
> >> #  Fri Jan 04 13:41:21 2019 +0100
> >> # Node ID 73926c4ab24d6c01723ed050601b134bdc89562f
> >> # Parent  4a56fbdacff33c3985bbb84f2e19ddfbd48ed4fa
> >> # EXP-Topic revs-efficiency
> >> # Available At https://bitbucket.org/octobus/mercurial-devel/
> >> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
> >> 73926c4ab24d
> >> revset: introduce an API that avoids `formatspec` input serialization
> > The idea looks good.
> >
> >> +class _inputrules(parser.basealiasrules):
> >> +"""replace internal input reference by their actual value"""
> >> +
> >> +@classmethod
> >> +def _getalias(cls, inputs, tree):
> >> +if not isinstance(tree, tuple):
> >> +return None
> >> +if tree[0] != 'func':
> >> +return None
> >> +if getsymbol(tree[1]) != _internal_input:
> >> +return None
> >> +idx = int(getsymbol(tree[2]))
> >> +newtree = ('func',
> >> +   ('symbol', internal_input_func),
> >> +   ('smartset', inputs[idx])
> >> +)
> >> +return parser.alias(idx, None, None, newtree), None
> > Perhaps, this can be just ('smartset', ...) node like 'symbol'/'string'.
> > There's not point to convert it to a 'func' unless it can be expressed
> > as a revset string.
> >
> > And if we can probably ditch the specialized _inputrules. See below.
> 
> We need to combine the smartset with the existing subset. Doing it
> within a function seems simpler and less impactful.

Well, there's no practical difference between ('func', ..., ('smartset',))
and ('smartset',).

For ('func', ..., ('smartset',)), we'll need two functions:
symbols[internal_input_func] and methods['smartset'].
symbols[internal_input_func] needs to check the argument type, and
methods['smartset'] would raise ParseError.

For ('smartset',), methods['smartset'] knows 'x' is a smartset, so we can
just return 'x & subset' / 'subset & x'. See stringset() for example.

> >> +def formatspecargs(expr, *args):
> >> +"""same as formatspec, but preserve some expensive arguments"""
> >> +parsed = _parseargs(expr, args)
> >> +ret = []
> >> +inputs = []
> >> +for t, arg in parsed:
> >> +if t is None:
> >> +ret.append(arg)
> >> +if t == 'baseset':
> >> +key = '%s(%d)' % (_internal_input, len(inputs))
> >> +inputs.append(smartset.baseset(arg))
> >> +ret.append(key)
> > Maybe we can assign integer (e.g. '$0') for each parameter here, and we can
> > just use the _aliasrules.expand() to replace it. '$x' is invalid in user
> > expression, so it can be used as a reserved symbol.
> 
> Don't we use '$0' for user alias?

Yes, but that doesn't matter since 'expr' here isn't an alias expression.

> Also, I'm not sure what's the value of using alias replacement here. Can
> you detail your reasoning?

To get rid of the custom _inputrule class.

> The alias logic seems pretty tied to having string (that it parses) as
> replacement, that is why I used a dedicated object.

So here we have string to parse, b''.join(ret), and replacements, inputs.
If b''.join(ret) contained '$0' instead of 'internal(0)', and if inputs
were dict of {'$0': alias('$0', ..., ('smartset', inputs[0]))}, we can just
feed them to _aliasrules.

  aliases = build_dict_of_inputs(inputs)
  tree = _parsewith(b''.join(ret), syminitletters=_aliassyminitletters)
  tree = _aliasrules.expand(aliases, tree)

That's the idea.

> > If this function returned a parsed tree, we can hide all the implementation
> > details in it, and we can probably remove the inputs argument from
> > revset.matchany().
> 
> But revset/matchany does not take a parsed tree, does it?

A parsed tree can be directly passed in to revset.makematcher(). Since
repo.revs() is an internal API, there aren't much we have to copy from
matchany():

  tree = foldconcat(tree)
  tree = analyze(tree)
  tree = optimize(tree)
  return tree
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 7 of 8] revset: detect integer list on parsing

2019-01-13 Thread Yuya Nishihara
On Sun, 13 Jan 2019 08:38:47 +0100, Boris FELD wrote:
> On 12/01/2019 05:38, Yuya Nishihara wrote:
> > On Fri, 11 Jan 2019 12:29:09 +0100, Boris Feld wrote:
> >> # HG changeset patch
> >> # User Boris Feld 
> >> # Date 1546575973 -3600
> >> #  Fri Jan 04 05:26:13 2019 +0100
> >> # Node ID 4a56fbdacff33c3985bbb84f2e19ddfbd48ed4fa
> >> # Parent  438ea9b8a44c181d62741338c1d16b2031fdda41
> >> # EXP-Topic revs-efficiency
> >> # Available At https://bitbucket.org/octobus/mercurial-devel/
> >> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
> >> 4a56fbdacff3
> >> revset: detect integer list on parsing
> >> +if islist and d == 'd' and arg:
> >> +# special case, we might be able to speedup the list of 
> >> int case
> >> +safeinputtype = (list, tuple, set, 
> >> smartset.abstractsmartset)
> >> +if isinstance(arg, safeinputtype):
> > Just curious. What's the unsafe type for example? I think 'arg' may be an
> > iterator/generator of ints, but which can be safely converted to 
> > list/baseset.
> 
> Honestly, I'm not sure.
> 
> The code around revset is quite complex and I want to focus on having a
> first thing working. The overall speedup from this change is so massive
> that I rather have a very narrow version of it quickly and expand it later.

Can you add inline comment then?

Testing these types would give false notion that there are other types this
function has to support.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 4 of 8] revset: enforce "%d" to be interpreted as literal revision number (API)

2019-01-13 Thread Yuya Nishihara
On Sun, 13 Jan 2019 08:37:47 +0100, Boris FELD wrote:
> 
> On 12/01/2019 05:04, Yuya Nishihara wrote:
> > On Fri, 11 Jan 2019 12:29:06 +0100, Boris Feld wrote:
> >> # HG changeset patch
> >> # User Boris Feld 
> >> # Date 1547130238 -3600
> >> #  Thu Jan 10 15:23:58 2019 +0100
> >> # Node ID 38733dd8559578267617514a42f253efabb6
> >> # Parent  427247e84e29c144321d21a825d371458b5d3e1a
> >> # EXP-Topic revs-efficiency
> >> # Available At https://bitbucket.org/octobus/mercurial-devel/
> >> #  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
> >> 38733dd85595
> >> revset: enforce "%d" to be interpreted as literal revision number (API)
> > New behavior looks saner. Please also flag this as (BC). It's exposed as
> > revset() template function.
> >
> >>  %r = revset expression, parenthesized
> >> -%d = int(arg), no quoting
> >> +%d = rev(int(arg)), no quoting
> > 'rev(n)' returns an empty set if n is out of range, whereas 'n' aborts.
> > Suppose it's pretty much a coding error to pass in an invalid revision to
> > repo.revs(), we'll probably want aborts.
> >
> > Maybe we'll need an internal '_rev()' function?
> %ld silently pass on these too, so I would rather have %ld and %d
> consistent here (and align on the silence %ld behavior).

Indeed. I never thought %ld would behave in such way. Consistent behavior
should be better.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH V2] update: fix edge-case with update.atomic-file and read-only files

2019-01-13 Thread Boris Feld
# HG changeset patch
# User Boris Feld 
# Date 1547128621 -3600
#  Thu Jan 10 14:57:01 2019 +0100
# Node ID d46392ed9a76773561c74c8df2063aaad4c3c952
# Parent  963462786f6e028563bcedc9008622e0f3b59c86
# EXP-Topic atomic-update-read-only
# Available At https://bitbucket.org/octobus/mercurial-devel/
#  hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
d46392ed9a76
update: fix edge-case with update.atomic-file and read-only files

We used to create the tempfile with the original file mode. That means
creating a read-only tempfile when the original file is read-only, which crash
if we need to write on the tempfile.

The file in the working directory ends up being writable with and without the
atomic update config, so the behavior is the same.

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -2045,7 +2045,7 @@ def splitpath(path):
 function if need.'''
 return path.split(pycompat.ossep)
 
-def mktempcopy(name, emptyok=False, createmode=None):
+def mktempcopy(name, emptyok=False, createmode=None, enforcewritable=False):
 """Create a temporary file with the same contents from name
 
 The permission bits are copied from the original file.
@@ -2062,6 +2062,15 @@ def mktempcopy(name, emptyok=False, crea
 # what we want.  If the original file already exists, just copy
 # its mode.  Otherwise, manually obey umask.
 copymode(name, temp, createmode)
+
+# If the resulting temporary file needs to be writable enforce it now.
+# createmode argument of copy mode is not used when the original file
+# already exists so we need to do it outside of it
+if enforcewritable:
+oldstat = filestat.frompath(temp)
+newstat = oldstat.stat.st_mode | stat.S_IWUSR
+os.chmod(temp, newstat)
+
 if emptyok:
 return temp
 try:
@@ -2204,7 +2213,9 @@ class atomictempfile(object):
 def __init__(self, name, mode='w+b', createmode=None, checkambig=False):
 self.__name = name  # permanent name
 self._tempname = mktempcopy(name, emptyok=('w' in mode),
-createmode=createmode)
+createmode=createmode,
+enforcewritable=('w' in mode))
+
 self._fp = posixfile(self._tempname, mode)
 self._checkambig = checkambig
 
diff --git a/tests/test-update-atomic.t b/tests/test-update-atomic.t
new file mode 100644
--- /dev/null
+++ b/tests/test-update-atomic.t
@@ -0,0 +1,142 @@
+#require execbit
+
+Checking that experimental.atomic-file works.
+
+  $ cat > $TESTTMP/show_mode.py < from __future__ import print_function
+  > import sys
+  > import os
+  > from stat import ST_MODE
+  > 
+  > for file_path in sys.argv[1:]:
+  > file_stat = os.stat(file_path)
+  > octal_mode = oct(file_stat[ST_MODE] & 0o777)
+  > print("%s:%s" % (file_path, octal_mode))
+  > 
+  > EOF
+
+  $ hg init repo
+  $ cd repo
+
+  $ cat > .hg/showwrites.py < def uisetup(ui):
+  >   from mercurial import vfs
+  >   class newvfs(vfs.vfs):
+  > def __call__(self, *args, **kwargs):
+  >   print('vfs open', args, sorted(list(kwargs.items(
+  >   return super(newvfs, self).__call__(*args, **kwargs)
+  >   vfs.vfs = newvfs
+  > EOF
+
+  $ for v in a1 a2 b1 b2 c ro; do echo $v > $v; done
+  $ chmod +x b*
+  $ hg commit -Aqm _
+
+# We check that
+# - the changes are actually atomic
+# - that permissions are correct (all 4 cases of (executable before) * 
(executable after))
+# - that renames work, though they should be atomic anyway
+# - that it works when source files are read-only (but directories are 
read-write still)
+
+  $ for v in a1 a2 b1 b2 ro; do echo changed-$v > $v; done
+  $ chmod -x *1; chmod +x *2
+  $ hg rename c d
+  $ hg commit -qm _
+
+Check behavior without update.atomic-file
+
+  $ hg update -r 0 -q
+  $ hg update -r 1 --config extensions.showwrites=.hg/showwrites.py 2>&1 | 
grep "a1'.*wb"
+  ('vfs open', ('a1', 'wb'), [('atomictemp', False), ('backgroundclose', 
True)])
+
+  $ python $TESTTMP/show_mode.py *
+  a1:0644
+  a2:0755
+  b1:0644
+  b2:0755
+  d:0644
+  ro:0644
+
+Add a second revision for the ro file so we can test update when the file is
+present or not
+
+  $ echo "ro" > ro
+
+  $ hg commit -qm _
+
+Check behavior without update.atomic-file first
+
+  $ hg update -C -r 0 -q
+
+  $ hg update -r 1
+  6 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+  $ python $TESTTMP/show_mode.py *
+  a1:0644
+  a2:0755
+  b1:0644
+  b2:0755
+  d:0644
+  ro:0644
+
+Manually reset the mode of the read-only file
+
+  $ chmod a-w ro
+
+  $ python $TESTTMP/show_mode.py ro
+  ro:0444
+
+Now the file is present, try to update and check the permissions of the file
+
+  $ hg up -r 2
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ python $TESTTMP/show_mode.py ro
+  ro:0644
+
+# The file which was read-only is now 

Re: [PATCH] update: fix edge-case with update.atomic-file and read-only files

2019-01-13 Thread Boris FELD
On 12/01/2019 04:32, Yuya Nishihara wrote:
>>  self._tempname = mktempcopy(name, emptyok=('w' in mode),
>>  createmode=createmode)
>> +
>> +# If we are gonna write on the tempfile, we need to make sure we 
>> have
>> +# the permission to do so
>> +if 'w' in mode and os.path.isfile(name):
>> +oldstat = filestat.frompath(name)
>> +newstat = oldstat.stat.st_mode | stat.S_IWUSR
>> +os.chmod(self._tempname, newstat)
> Isn't it better to add an option for mktempcopy() to forcibly flag S_IWUSR
> bit on?

I was hesitant between the two designs. I give a try to the mktempcopy
modification design thanks to your comment and it seems better.

I'm not familiar with how Windows handle file permissions but I see that
copymode for windows does nothing. Should we also avoid enforcing the
writable bit on Windows platform?

> ___
> 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] update: fix edge-case with update.atomic-file and read-only files

2019-01-13 Thread Boris FELD
Thank you for the thorough review

On 11/01/2019 18:24, Martin von Zweigbergk via Mercurial-devel wrote:
>
>
> On Fri, Jan 11, 2019 at 7:26 AM Boris Feld  > wrote:
>
> # HG changeset patch
> # User Boris Feld  >
> # Date 1547128621 -3600
> #      Thu Jan 10 14:57:01 2019 +0100
> # Node ID 9d5ed4b088da0ece901b80c0fa40177cc6eaf676
> # Parent  963462786f6e028563bcedc9008622e0f3b59c86
> # EXP-Topic atomic-update-read-only
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> #              hg pull
> https://bitbucket.org/octobus/mercurial-devel/ -r 9d5ed4b088da
> update: fix edge-case with update.atomic-file and read-only files
>
> We used to create the tempfile with the original file mode. That means
> creating a read-only tempfile when the original file is read-only,
> which crash
> if we need to write on the tempfile.
>
> The file in the working directory ends up being writable with and
> without the
> atomic update config, so the behavior is the same.
>
> diff --git a/mercurial/util.py b/mercurial/util.py
> --- a/mercurial/util.py
> +++ b/mercurial/util.py
> @@ -48,6 +48,7 @@ from . import (
>      policy,
>      pycompat,
>      urllibcompat,
> +    util
>
>
> Delete.
>  
>
>  )
>  from .utils import (
>      procutil,
> @@ -2205,6 +2206,14 @@ class atomictempfile(object):
>          self.__name = name      # permanent name
>          self._tempname = mktempcopy(name, emptyok=('w' in mode),
>                                      createmode=createmode)
> +
> +        # If we are gonna write on the tempfile, we need to make
> sure we have
> +        # the permission to do so
> +        if 'w' in mode and os.path.isfile(name):
> +            oldstat = filestat.frompath(name)
> +            newstat = oldstat.stat.st_mode | stat.S_IWUSR
> +            os.chmod(self._tempname, newstat)
> +
>          self._fp = posixfile(self._tempname, mode)
>          self._checkambig = checkambig
>
> diff --git a/tests/test-update-atomic.t b/tests/test-update-atomic.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-update-atomic.t
> @@ -0,0 +1,124 @@
> +Checking that experimental.atomic-file works.
> +
> +  $ hg init .
> +  $ cat > .hg/showwrites.py < +  > def uisetup(ui):
> +  >   from mercurial import vfs
> +  >   class newvfs(vfs.vfs):
> +  >     def __call__(self, *args, **kwargs):
> +  >       print('vfs open', args, sorted(list(kwargs.items(
> +  >       return super(newvfs, self).__call__(*args, **kwargs)
> +  >   vfs.vfs = newvfs
> +  > EOF
> +  $ for v in a1 a2 b1 b2 c ro; do echo $v > $v; done
> +  $ chmod +x b*
>
>
> I think you need "#require execbit" for this.
Indeed, nice catch
>  
>
> +  $ hg commit -Aqm _
> +
> +# We check that
> +# - the changes are actually atomic
> +# - that permissions are correct (all 4 cases of (executable
> before) * (executable after))
> +# - that renames work, though they should be atomic anyway
> +# - that it works when source files are read-only (but
> directories are read-write still)
> +
> +  $ for v in a1 a2 b1 b2 ro; do echo changed-$v > $v; done
> +  $ chmod -x *1; chmod +x *2
> +  $ hg rename c d
> +  $ hg commit -qm _
> +
> +Check behavior without update.atomic-file
> +
> +  $ hg update -r 0 -q
> +  $ hg update -r 1 --config
> extensions.showwrites=.hg/showwrites.py |& grep "a1'.*wb"
>
>
> test-check-code.t fails:
>
> @@ -15,6 +15,34 @@
>    Skipping i18n/polib.py it has no-che?k-code (glob)
>    Skipping mercurial/statprof.py it has no-che?k-code (glob)
>    Skipping tests/badserverext.py it has no-che?k-code (glob)
> +  tests/test-update-atomic.t:31:
> +   >   $ hg update -r 1 --config
> extensions.showwrites=.hg/showwrites.py |& grep "a1'.*wb"
> +   don't use |&, use 2>&1
> +  tests/test-update-atomic.t:34:
> +   >   $ find * -printf "%f:%p:%m\n"
> +   don't use 'find -printf', it doesn't exist on BSD find(1)
> +  tests/test-update-atomic.t:56:
> +   >   $ find * -printf "%f:%p:%m\n"
> +   don't use 'find -printf', it doesn't exist on BSD find(1)
> +  tests/test-update-atomic.t:68:
> +   >   $ find ro -printf "%f:%p:%m\n"
> +   don't use 'find -printf', it doesn't exist on BSD find(1)
> +  tests/test-update-atomic.t:76:
> +   >   $ find ro -printf "%f:%p:%m\n"
> +   don't use 'find -printf', it doesn't exist on BSD find(1)
> +  tests/test-update-atomic.t:90:
> +   >   $ hg update -r 1 --config
> extensions.showwrites=.hg/showwrites.py |& grep "a1'.*wb"
> +   don't use |&, use 2>&1
> +  tests/test-update-atomic.t:101:
> +   >   $ find * -printf "%f:%p:%m\n"
> +   don't use 'find -printf', it doesn't exist on BSD find(1)
> +  tests/test-update-atomic.t:113: