[PATCH] sshserver: add a couple of tests for argument parsing

2018-01-19 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1516400709 28800
#  Fri Jan 19 14:25:09 2018 -0800
# Node ID 897f09345e370f08c019e7025d51e3e7ff3832fb
# Parent  6d65cef5b038ff4c141c0bbc1a2e366e45c016a2
sshserver: add a couple of tests for argument parsing

I noticed that we didn't have any unit tests covering wire protocol argument
parsing.

diff --git a/tests/test-sshserver.py b/tests/test-sshserver.py
new file mode 100644
--- /dev/null
+++ b/tests/test-sshserver.py
@@ -0,0 +1,44 @@
+from __future__ import absolute_import, print_function
+
+import io
+import unittest
+
+import silenttestrunner
+
+from mercurial import (
+sshserver,
+wireproto,
+)
+
+class SSHServerGetArgsTests(unittest.TestCase):
+def testparseknown(self):
+tests = [
+('* 0\nnodes 0\n', ['', {}]),
+('* 0\nnodes 40\n\n',
+ ['', {}]),
+]
+for input, expected in tests:
+self.assertparse('known', input, expected)
+
+def assertparse(self, cmd, input, expected):
+server = mockserver(input)
+_func, spec = wireproto.commands[cmd]
+self.assertEqual(server.getargs(spec), expected)
+
+def mockserver(inbytes):
+ui = mockui(inbytes)
+repo = mockrepo(ui)
+return sshserver.sshserver(ui, repo)
+
+class mockrepo(object):
+def __init__(self, ui):
+self.ui = ui
+
+class mockui(object):
+def __init__(self, inbytes):
+self.fin = io.BytesIO(inbytes)
+self.fout = io.BytesIO()
+self.ferr = io.BytesIO()
+
+if __name__ == '__main__':
+silenttestrunner.main(__name__)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1222: merge: add a config option to disable path conflict checking

2017-10-30 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG37450a122128: merge: add a config option to disable path 
conflict checking (authored by sid0, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1222?vs=3081=3160

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

AFFECTED FILES
  mercurial/configitems.py
  mercurial/merge.py

CHANGE DETAILS

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -693,6 +693,7 @@
 abortconflicts = set()
 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
+pathconfig = repo.ui.configbool('experimental', 'merge.checkpathconflicts')
 if not force:
 def collectconflicts(conflicts, config):
 if config == 'abort':
@@ -704,7 +705,7 @@
 if m in ('c', 'dc'):
 if _checkunknownfile(repo, wctx, mctx, f):
 fileconflicts.add(f)
-elif f not in wctx:
+elif pathconfig and f not in wctx:
 path = _checkunknowndirs(repo, f)
 if path is not None:
 pathconflicts.add(path)
@@ -1139,8 +1140,9 @@
 actions[f] = ('dc', (None, f, f, False, pa.node()),
   "prompt deleted/changed")
 
-# If we are merging, look for path conflicts.
-checkpathconflicts(repo, wctx, p2, actions)
+if repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
+# If we are merging, look for path conflicts.
+checkpathconflicts(repo, wctx, p2, actions)
 
 return actions, diverge, renamedelete
 
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -578,6 +578,9 @@
 coreconfigitem('merge', 'checkignored',
 default='abort',
 )
+coreconfigitem('experimental', 'merge.checkpathconflicts',
+default=True,
+)
 coreconfigitem('merge', 'followcopies',
 default=True,
 )



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


D1223: merge: disable path conflict checking by default (issue5716)

2017-10-30 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG2a774cae3a03: merge: disable path conflict checking by 
default (issue5716) (authored by sid0, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1223?vs=3082=3161

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

AFFECTED FILES
  mercurial/configitems.py
  tests/test-audit-path.t
  tests/test-commandserver.t
  tests/test-merge1.t
  tests/test-pathconflicts-basic.t
  tests/test-pathconflicts-merge.t
  tests/test-pathconflicts-update.t
  tests/test-update-names.t

CHANGE DETAILS

diff --git a/tests/test-update-names.t b/tests/test-update-names.t
--- a/tests/test-update-names.t
+++ b/tests/test-update-names.t
@@ -50,9 +50,7 @@
   $ hg st
   ? name/file
   $ hg up 1
-  name: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd ..
 
 #if symlink
diff --git a/tests/test-pathconflicts-update.t 
b/tests/test-pathconflicts-update.t
--- a/tests/test-pathconflicts-update.t
+++ b/tests/test-pathconflicts-update.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -150,4 +158,3 @@
   $ hg up file2 --clean
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (activating bookmark file2)
-
diff --git a/tests/test-pathconflicts-merge.t b/tests/test-pathconflicts-merge.t
--- a/tests/test-pathconflicts-merge.t
+++ b/tests/test-pathconflicts-merge.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
diff --git a/tests/test-pathconflicts-basic.t b/tests/test-pathconflicts-basic.t
--- a/tests/test-pathconflicts-basic.t
+++ b/tests/test-pathconflicts-basic.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -96,4 +104,3 @@
   commit: (clean)
   update: 1 new changesets, 2 branch heads (merge)
   phases: 4 draft
-
diff --git a/tests/test-merge1.t b/tests/test-merge1.t
--- a/tests/test-merge1.t
+++ b/tests/test-merge1.t
@@ -30,22 +30,23 @@
 
   $ mkdir b && touch b/nonempty
   $ hg up
-  b: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg ci
   nothing changed
   [1]
   $ hg sum
-  parent: 0:538afb845929 
-   commit #0
+  parent: 1:b8bb4a988f25 tip
+   commit #1
   branch: default
-  commit: 1 unknown (clean)
-  update: 1 new changesets (update)
+  commit: (clean)
+  update: (current)
   phases: 2 draft
-  $ rm b/nonempty
+
+The following line is commented out because the file doesn't exist at the 
moment, and some OSes error out even with `rm -f`.
+$ rm b/nonempty
+
   $ hg up
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg sum
   parent: 1:b8bb4a988f25 tip
commit #1
diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t
--- a/tests/test-commandserver.t
+++ b/tests/test-commandserver.t
@@ -975,12 +975,8 @@
   *** runcommand up -qC 2
   *** runcommand up -qC 1
   *** runcommand merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to 
abandon
-   [1]
+  abort: path 'a/poisoned' traverses symbolic link 'a'
+   [255]
   $ ls ../merge-symlink-out
 
 cache of repo.auditor should be discarded, so matcher would never traverse
diff --git a/tests/test-audit-path.t b/tests/test-audit-path.t
--- a/tests/test-audit-path.t
+++ b/tests/test-audit-path.t
@@ -104,8 +104,7 @@
   back/test
 #if symlink
   $ hg update -Cr2
-  back: is both a file and a directory
-  abort: destination manifest contains path conflicts
+  abort: path 'back/test' traverses symbolic link 'back'
   [255]
 #else
 ('back' will be a file and cause some other system specific error)
@@ -167,24 +166,17 @@
 
   $ hg up -qC 1
   $ hg merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has 

D1223: merge: disable path conflict checking by default (issue5716)

2017-10-24 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 3082.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1223?vs=3076=3082

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

AFFECTED FILES
  mercurial/configitems.py
  tests/test-audit-path.t
  tests/test-commandserver.t
  tests/test-merge1.t
  tests/test-pathconflicts-basic.t
  tests/test-pathconflicts-merge.t
  tests/test-pathconflicts-update.t
  tests/test-update-names.t

CHANGE DETAILS

diff --git a/tests/test-update-names.t b/tests/test-update-names.t
--- a/tests/test-update-names.t
+++ b/tests/test-update-names.t
@@ -50,9 +50,7 @@
   $ hg st
   ? name/file
   $ hg up 1
-  name: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd ..
 
 #if symlink
diff --git a/tests/test-pathconflicts-update.t 
b/tests/test-pathconflicts-update.t
--- a/tests/test-pathconflicts-update.t
+++ b/tests/test-pathconflicts-update.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -150,4 +158,3 @@
   $ hg up file2 --clean
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (activating bookmark file2)
-
diff --git a/tests/test-pathconflicts-merge.t b/tests/test-pathconflicts-merge.t
--- a/tests/test-pathconflicts-merge.t
+++ b/tests/test-pathconflicts-merge.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
diff --git a/tests/test-pathconflicts-basic.t b/tests/test-pathconflicts-basic.t
--- a/tests/test-pathconflicts-basic.t
+++ b/tests/test-pathconflicts-basic.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -96,4 +104,3 @@
   commit: (clean)
   update: 1 new changesets, 2 branch heads (merge)
   phases: 4 draft
-
diff --git a/tests/test-merge1.t b/tests/test-merge1.t
--- a/tests/test-merge1.t
+++ b/tests/test-merge1.t
@@ -30,22 +30,23 @@
 
   $ mkdir b && touch b/nonempty
   $ hg up
-  b: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg ci
   nothing changed
   [1]
   $ hg sum
-  parent: 0:538afb845929 
-   commit #0
+  parent: 1:b8bb4a988f25 tip
+   commit #1
   branch: default
-  commit: 1 unknown (clean)
-  update: 1 new changesets (update)
+  commit: (clean)
+  update: (current)
   phases: 2 draft
-  $ rm b/nonempty
+
+The following line is commented out because the file doesn't exist at the 
moment, and some OSes error out even with `rm -f`.
+$ rm b/nonempty
+
   $ hg up
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg sum
   parent: 1:b8bb4a988f25 tip
commit #1
diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t
--- a/tests/test-commandserver.t
+++ b/tests/test-commandserver.t
@@ -975,12 +975,8 @@
   *** runcommand up -qC 2
   *** runcommand up -qC 1
   *** runcommand merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to 
abandon
-   [1]
+  abort: path 'a/poisoned' traverses symbolic link 'a'
+   [255]
   $ ls ../merge-symlink-out
 
 cache of repo.auditor should be discarded, so matcher would never traverse
diff --git a/tests/test-audit-path.t b/tests/test-audit-path.t
--- a/tests/test-audit-path.t
+++ b/tests/test-audit-path.t
@@ -104,8 +104,7 @@
   back/test
 #if symlink
   $ hg update -Cr2
-  back: is both a file and a directory
-  abort: destination manifest contains path conflicts
+  abort: path 'back/test' traverses symbolic link 'back'
   [255]
 #else
 ('back' will be a file and cause some other system specific error)
@@ -167,24 +166,17 @@
 
   $ hg up -qC 1
   $ hg merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 

D1222: merge: add a config option to disable path conflict checking

2017-10-24 Thread sid0 (Siddharth Agarwal)
sid0 added a comment.


  > The debug section doesn't seem to exists, could we use 'experimental' 
instead while we fix the performance regression?
  
  Good idea! Done, thanks!

REPOSITORY
  rHG Mercurial

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

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


D1222: merge: add a config option to disable path conflict checking

2017-10-24 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 3081.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1222?vs=3073=3081

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

AFFECTED FILES
  mercurial/configitems.py
  mercurial/merge.py

CHANGE DETAILS

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -693,6 +693,7 @@
 abortconflicts = set()
 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
+pathconfig = repo.ui.configbool('experimental', 'merge.checkpathconflicts')
 if not force:
 def collectconflicts(conflicts, config):
 if config == 'abort':
@@ -704,7 +705,7 @@
 if m in ('c', 'dc'):
 if _checkunknownfile(repo, wctx, mctx, f):
 fileconflicts.add(f)
-elif f not in wctx:
+elif pathconfig and f not in wctx:
 path = _checkunknowndirs(repo, f)
 if path is not None:
 pathconflicts.add(path)
@@ -1139,8 +1140,9 @@
 actions[f] = ('dc', (None, f, f, False, pa.node()),
   "prompt deleted/changed")
 
-# If we are merging, look for path conflicts.
-checkpathconflicts(repo, wctx, p2, actions)
+if repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
+# If we are merging, look for path conflicts.
+checkpathconflicts(repo, wctx, p2, actions)
 
 return actions, diverge, renamedelete
 
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -575,6 +575,9 @@
 coreconfigitem('merge', 'checkignored',
 default='abort',
 )
+coreconfigitem('experimental', 'merge.checkpathconflicts',
+default=True,
+)
 coreconfigitem('merge', 'followcopies',
 default=True,
 )



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


D1224: merge: cache unknown dir checks (issue5716)

2017-10-24 Thread sid0 (Siddharth Agarwal)
sid0 added a comment.


  Could you make this a class with unknowndircache and missingdircache being 
private members?
  
  How much do you think writing some of this code in native code (e.g. Rust) 
would help?

REPOSITORY
  rHG Mercurial

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

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


D1223: merge: disable path conflict checking by default (issue5716)

2017-10-23 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 3076.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1223?vs=3075=3076

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

AFFECTED FILES
  mercurial/configitems.py
  tests/test-audit-path.t
  tests/test-commandserver.t
  tests/test-merge1.t
  tests/test-pathconflicts-basic.t
  tests/test-pathconflicts-merge.t
  tests/test-pathconflicts-update.t
  tests/test-update-names.t

CHANGE DETAILS

diff --git a/tests/test-update-names.t b/tests/test-update-names.t
--- a/tests/test-update-names.t
+++ b/tests/test-update-names.t
@@ -50,9 +50,7 @@
   $ hg st
   ? name/file
   $ hg up 1
-  name: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd ..
 
 #if symlink
diff --git a/tests/test-pathconflicts-update.t 
b/tests/test-pathconflicts-update.t
--- a/tests/test-pathconflicts-update.t
+++ b/tests/test-pathconflicts-update.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -150,4 +158,3 @@
   $ hg up file2 --clean
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (activating bookmark file2)
-
diff --git a/tests/test-pathconflicts-merge.t b/tests/test-pathconflicts-merge.t
--- a/tests/test-pathconflicts-merge.t
+++ b/tests/test-pathconflicts-merge.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
diff --git a/tests/test-pathconflicts-basic.t b/tests/test-pathconflicts-basic.t
--- a/tests/test-pathconflicts-basic.t
+++ b/tests/test-pathconflicts-basic.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -96,4 +104,3 @@
   commit: (clean)
   update: 1 new changesets, 2 branch heads (merge)
   phases: 4 draft
-
diff --git a/tests/test-merge1.t b/tests/test-merge1.t
--- a/tests/test-merge1.t
+++ b/tests/test-merge1.t
@@ -30,22 +30,23 @@
 
   $ mkdir b && touch b/nonempty
   $ hg up
-  b: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg ci
   nothing changed
   [1]
   $ hg sum
-  parent: 0:538afb845929 
-   commit #0
+  parent: 1:b8bb4a988f25 tip
+   commit #1
   branch: default
-  commit: 1 unknown (clean)
-  update: 1 new changesets (update)
+  commit: (clean)
+  update: (current)
   phases: 2 draft
-  $ rm b/nonempty
+
+The following line is commented out because the file doesn't exist at the 
moment, and some OSes error out even with `rm -f`.
+$ rm b/nonempty
+
   $ hg up
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg sum
   parent: 1:b8bb4a988f25 tip
commit #1
diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t
--- a/tests/test-commandserver.t
+++ b/tests/test-commandserver.t
@@ -975,12 +975,8 @@
   *** runcommand up -qC 2
   *** runcommand up -qC 1
   *** runcommand merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to 
abandon
-   [1]
+  abort: path 'a/poisoned' traverses symbolic link 'a'
+   [255]
   $ ls ../merge-symlink-out
 
 cache of repo.auditor should be discarded, so matcher would never traverse
diff --git a/tests/test-audit-path.t b/tests/test-audit-path.t
--- a/tests/test-audit-path.t
+++ b/tests/test-audit-path.t
@@ -104,8 +104,7 @@
   back/test
 #if symlink
   $ hg update -Cr2
-  back: is both a file and a directory
-  abort: destination manifest contains path conflicts
+  abort: path 'back/test' traverses symbolic link 'back'
   [255]
 #else
 ('back' will be a file and cause some other system specific error)
@@ -167,24 +166,17 @@
 
   $ hg up -qC 1
   $ hg merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 'hg resolve' to retry 

D1223: merge: disable path conflict checking by default (issue5716)

2017-10-23 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 3075.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1223?vs=3074=3075

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

AFFECTED FILES
  mercurial/configitems.py
  tests/test-audit-path.t
  tests/test-commandserver.t
  tests/test-merge1.t
  tests/test-pathconflicts-basic.t
  tests/test-pathconflicts-merge.t
  tests/test-pathconflicts-update.t
  tests/test-update-names.t

CHANGE DETAILS

diff --git a/tests/test-update-names.t b/tests/test-update-names.t
--- a/tests/test-update-names.t
+++ b/tests/test-update-names.t
@@ -50,9 +50,7 @@
   $ hg st
   ? name/file
   $ hg up 1
-  name: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd ..
 
 #if symlink
diff --git a/tests/test-pathconflicts-update.t 
b/tests/test-pathconflicts-update.t
--- a/tests/test-pathconflicts-update.t
+++ b/tests/test-pathconflicts-update.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -150,4 +158,3 @@
   $ hg up file2 --clean
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (activating bookmark file2)
-
diff --git a/tests/test-pathconflicts-merge.t b/tests/test-pathconflicts-merge.t
--- a/tests/test-pathconflicts-merge.t
+++ b/tests/test-pathconflicts-merge.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
diff --git a/tests/test-pathconflicts-basic.t b/tests/test-pathconflicts-basic.t
--- a/tests/test-pathconflicts-basic.t
+++ b/tests/test-pathconflicts-basic.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -96,4 +104,3 @@
   commit: (clean)
   update: 1 new changesets, 2 branch heads (merge)
   phases: 4 draft
-
diff --git a/tests/test-merge1.t b/tests/test-merge1.t
--- a/tests/test-merge1.t
+++ b/tests/test-merge1.t
@@ -30,22 +30,20 @@
 
   $ mkdir b && touch b/nonempty
   $ hg up
-  b: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg ci
   nothing changed
   [1]
   $ hg sum
-  parent: 0:538afb845929 
-   commit #0
+  parent: 1:b8bb4a988f25 tip
+   commit #1
   branch: default
-  commit: 1 unknown (clean)
-  update: 1 new changesets (update)
+  commit: (clean)
+  update: (current)
   phases: 2 draft
-  $ rm b/nonempty
+  $ rm -f b/nonempty
   $ hg up
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg sum
   parent: 1:b8bb4a988f25 tip
commit #1
diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t
--- a/tests/test-commandserver.t
+++ b/tests/test-commandserver.t
@@ -975,12 +975,8 @@
   *** runcommand up -qC 2
   *** runcommand up -qC 1
   *** runcommand merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to 
abandon
-   [1]
+  abort: path 'a/poisoned' traverses symbolic link 'a'
+   [255]
   $ ls ../merge-symlink-out
 
 cache of repo.auditor should be discarded, so matcher would never traverse
diff --git a/tests/test-audit-path.t b/tests/test-audit-path.t
--- a/tests/test-audit-path.t
+++ b/tests/test-audit-path.t
@@ -104,8 +104,7 @@
   back/test
 #if symlink
   $ hg update -Cr2
-  back: is both a file and a directory
-  abort: destination manifest contains path conflicts
+  abort: path 'back/test' traverses symbolic link 'back'
   [255]
 #else
 ('back' will be a file and cause some other system specific error)
@@ -167,24 +166,17 @@
 
   $ hg up -qC 1
   $ hg merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to 
abandon
-  [1]
+  abort: path 'a/poisoned' traverses symbolic link 'a'
+  [255]
 

D1222: merge: add a config option to disable path conflict checking

2017-10-23 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  We've found a severe perf regression in `hg update` caused by the path 
conflict
  checking code. The next patch will disable this by default.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/configitems.py
  mercurial/merge.py

CHANGE DETAILS

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -693,6 +693,7 @@
 abortconflicts = set()
 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
+pathconfig = repo.ui.configbool('debug', 'merge.checkpathconflicts')
 if not force:
 def collectconflicts(conflicts, config):
 if config == 'abort':
@@ -704,7 +705,7 @@
 if m in ('c', 'dc'):
 if _checkunknownfile(repo, wctx, mctx, f):
 fileconflicts.add(f)
-elif f not in wctx:
+elif pathconfig and f not in wctx:
 path = _checkunknowndirs(repo, f)
 if path is not None:
 pathconflicts.add(path)
@@ -1139,8 +1140,9 @@
 actions[f] = ('dc', (None, f, f, False, pa.node()),
   "prompt deleted/changed")
 
-# If we are merging, look for path conflicts.
-checkpathconflicts(repo, wctx, p2, actions)
+if repo.ui.configbool('debug', 'merge.checkpathconflicts'):
+# If we are merging, look for path conflicts.
+checkpathconflicts(repo, wctx, p2, actions)
 
 return actions, diverge, renamedelete
 
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -575,6 +575,9 @@
 coreconfigitem('merge', 'checkignored',
 default='abort',
 )
+coreconfigitem('debug', 'merge.checkpathconflicts',
+default=True,
+)
 coreconfigitem('merge', 'followcopies',
 default=True,
 )



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


D1223: merge: disable path conflict checking by default (issue5716)

2017-10-23 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  We shouldn't ship a severe perf regression in hg update for 4.4.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/configitems.py
  tests/test-audit-path.t
  tests/test-commandserver.t
  tests/test-merge1.t
  tests/test-pathconflicts-basic.t
  tests/test-pathconflicts-merge.t
  tests/test-pathconflicts-update.t
  tests/test-update-names.t

CHANGE DETAILS

diff --git a/tests/test-update-names.t b/tests/test-update-names.t
--- a/tests/test-update-names.t
+++ b/tests/test-update-names.t
@@ -50,9 +50,7 @@
   $ hg st
   ? name/file
   $ hg up 1
-  name: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd ..
 
 #if symlink
diff --git a/tests/test-pathconflicts-update.t 
b/tests/test-pathconflicts-update.t
--- a/tests/test-pathconflicts-update.t
+++ b/tests/test-pathconflicts-update.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -150,4 +158,3 @@
   $ hg up file2 --clean
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (activating bookmark file2)
-
diff --git a/tests/test-pathconflicts-merge.t b/tests/test-pathconflicts-merge.t
--- a/tests/test-pathconflicts-merge.t
+++ b/tests/test-pathconflicts-merge.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
diff --git a/tests/test-pathconflicts-basic.t b/tests/test-pathconflicts-basic.t
--- a/tests/test-pathconflicts-basic.t
+++ b/tests/test-pathconflicts-basic.t
@@ -1,3 +1,11 @@
+Path conflict checking is currently disabled by default because of issue5716.
+Turn it on for this test.
+
+  $ cat >> $HGRCPATH << EOF
+  > [debug]
+  > merge.checkpathconflicts=True
+  > EOF
+
   $ hg init repo
   $ cd repo
   $ echo base > base
@@ -96,4 +104,3 @@
   commit: (clean)
   update: 1 new changesets, 2 branch heads (merge)
   phases: 4 draft
-
diff --git a/tests/test-merge1.t b/tests/test-merge1.t
--- a/tests/test-merge1.t
+++ b/tests/test-merge1.t
@@ -30,22 +30,22 @@
 
   $ mkdir b && touch b/nonempty
   $ hg up
-  b: untracked directory conflicts with file
-  abort: untracked files in working directory differ from files in requested 
revision
-  [255]
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg ci
   nothing changed
   [1]
   $ hg sum
-  parent: 0:538afb845929 
-   commit #0
+  parent: 1:b8bb4a988f25 tip
+   commit #1
   branch: default
-  commit: 1 unknown (clean)
-  update: 1 new changesets (update)
+  commit: (clean)
+  update: (current)
   phases: 2 draft
   $ rm b/nonempty
+  rm: cannot remove 'b/nonempty': Not a directory
+  [1]
   $ hg up
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg sum
   parent: 1:b8bb4a988f25 tip
commit #1
diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t
--- a/tests/test-commandserver.t
+++ b/tests/test-commandserver.t
@@ -975,12 +975,8 @@
   *** runcommand up -qC 2
   *** runcommand up -qC 1
   *** runcommand merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to 
abandon
-   [1]
+  abort: path 'a/poisoned' traverses symbolic link 'a'
+   [255]
   $ ls ../merge-symlink-out
 
 cache of repo.auditor should be discarded, so matcher would never traverse
diff --git a/tests/test-audit-path.t b/tests/test-audit-path.t
--- a/tests/test-audit-path.t
+++ b/tests/test-audit-path.t
@@ -104,8 +104,7 @@
   back/test
 #if symlink
   $ hg update -Cr2
-  back: is both a file and a directory
-  abort: destination manifest contains path conflicts
+  abort: path 'back/test' traverses symbolic link 'back'
   [255]
 #else
 ('back' will be a file and cause some other system specific error)
@@ -167,24 +166,17 @@
 
   $ hg up -qC 1
   $ hg merge 2
-  a: path conflict - a file or link has the same name as a directory
-  the local file has been renamed to a~aa04623eb0c3
-  resolve manually then use 'hg resolve --mark a'
-  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-  use 'hg resolve' to retry unresolved file 

D899: annotate: track whether a particular annotation was the result of a skip

2017-10-02 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG2f5a135b2b04: annotate: track whether a particular 
annotation was the result of a skip (authored by sid0, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D899?vs=2331=2341

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

AFFECTED FILES
  mercurial/context.py
  tests/test-annotate.py

CHANGE DETAILS

diff --git a/tests/test-annotate.py b/tests/test-annotate.py
--- a/tests/test-annotate.py
+++ b/tests/test-annotate.py
@@ -80,20 +80,22 @@
  diffopts)
 self.assertEqual(childann[0], [
 annotateline('old', 1),
-annotateline('old', 2),
+annotateline('old', 2, True),
+# note that this line was carried over from earlier so it is *not*
+# marked skipped
 annotateline('p2', 2),
-annotateline('p2', 2),
+annotateline('p2', 2, True),
 annotateline('p2', 3),
 ])
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p2ann, p1ann], childfctx, childann, True,
  diffopts)
 self.assertEqual(childann[0], [
 annotateline('old', 1),
-annotateline('old', 2),
+annotateline('old', 2, True),
 annotateline('p1', 3),
-annotateline('p1', 3),
+annotateline('p1', 3, True),
 annotateline('p2', 3),
 ])
 
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -,6 +,8 @@
 class annotateline(object):
 fctx = attr.ib()
 lineno = attr.ib(default=False)
+# Whether this annotation was the result of a skip-annotate.
+skip = attr.ib(default=False)
 
 def _annotatepair(parents, childfctx, child, skipchild, diffopts):
 r'''
@@ -1159,7 +1161,7 @@
 for bk in xrange(b1, b2):
 if child[0][bk].fctx == childfctx:
 ak = min(a1 + (bk - b1), a2 - 1)
-child[0][bk] = parent[0][ak]
+child[0][bk] = attr.evolve(parent[0][ak], 
skip=True)
 else:
 remaining[idx][1].append((a1, a2, b1, b2))
 
@@ -1170,7 +1172,7 @@
 for bk in xrange(b1, b2):
 if child[0][bk].fctx == childfctx:
 ak = min(a1 + (bk - b1), a2 - 1)
-child[0][bk] = parent[0][ak]
+child[0][bk] = attr.evolve(parent[0][ak], skip=True)
 return child
 
 class filectx(basefilectx):



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


D897: context: rename local 'attr' to 'attr_'

2017-10-02 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG52e9310626a8: context: rename local attr to 
attr_ (authored by sid0, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D897?vs=2318=2339

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

AFFECTED FILES
  mercurial/context.py

CHANGE DETAILS

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -2420,9 +2420,9 @@
 if reusable:
 # copy extra fields from originalfctx
 attrs = ['rawdata', 'rawflags', '_filenode', '_filerev']
-for attr in attrs:
-if util.safehasattr(originalfctx, attr):
-setattr(self, attr, getattr(originalfctx, attr))
+for attr_ in attrs:
+if util.safehasattr(originalfctx, attr_):
+setattr(self, attr_, getattr(originalfctx, attr_))
 
 def data(self):
 return self._datafunc()



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


D896: annotate: move annotatepair unit tests to a separate file

2017-10-02 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG80215865d154: annotate: move annotatepair unit tests to a 
separate file (authored by sid0, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D896?vs=2317=2338

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

AFFECTED FILES
  mercurial/context.py
  tests/test-annotate.py

CHANGE DETAILS

diff --git a/tests/test-annotate.py b/tests/test-annotate.py
new file mode 100644
--- /dev/null
+++ b/tests/test-annotate.py
@@ -0,0 +1,75 @@
+from __future__ import absolute_import
+from __future__ import print_function
+
+import unittest
+
+from mercurial import (
+mdiff,
+)
+from mercurial.context import (
+_annotatepair,
+)
+
+class AnnotateTests(unittest.TestCase):
+"""Unit tests for annotate code."""
+
+def testannotatepair(self):
+self.maxDiff = None # camelcase-required
+
+oldfctx = b'old'
+p1fctx, p2fctx, childfctx = b'p1', b'p2', b'c'
+olddata = b'a\nb\n'
+p1data = b'a\nb\nc\n'
+p2data = b'a\nc\nd\n'
+childdata = b'a\nb2\nc\nc2\nd\n'
+diffopts = mdiff.diffopts()
+
+def decorate(text, rev):
+return ([(rev, i) for i in xrange(1, text.count(b'\n') + 1)], text)
+
+# Basic usage
+
+oldann = decorate(olddata, oldfctx)
+p1ann = decorate(p1data, p1fctx)
+p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts)
+self.assertEqual(p1ann[0], [('old', 1), ('old', 2), ('p1', 3)])
+
+p2ann = decorate(p2data, p2fctx)
+p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts)
+self.assertEqual(p2ann[0], [('old', 1), ('p2', 2), ('p2', 3)])
+
+# Test with multiple parents (note the difference caused by ordering)
+
+childann = decorate(childdata, childfctx)
+childann = _annotatepair([p1ann, p2ann], childfctx, childann, False,
+ diffopts)
+self.assertEqual(childann[0],
+[('old', 1), ('c', 2), ('p2', 2), ('c', 4), ('p2', 3)]
+)
+
+childann = decorate(childdata, childfctx)
+childann = _annotatepair([p2ann, p1ann], childfctx, childann, False,
+ diffopts)
+self.assertEqual(childann[0],
+[('old', 1), ('c', 2), ('p1', 3), ('c', 4), ('p2', 3)]
+)
+
+# Test with skipchild (note the difference caused by ordering)
+
+childann = decorate(childdata, childfctx)
+childann = _annotatepair([p1ann, p2ann], childfctx, childann, True,
+ diffopts)
+self.assertEqual(childann[0],
+[('old', 1), ('old', 2), ('p2', 2), ('p2', 2), ('p2', 3)]
+)
+
+childann = decorate(childdata, childfctx)
+childann = _annotatepair([p2ann, p1ann], childfctx, childann, True,
+ diffopts)
+self.assertEqual(childann[0],
+[('old', 1), ('old', 2), ('p1', 3), ('p1', 3), ('p2', 3)]
+)
+
+if __name__ == '__main__':
+import silenttestrunner
+silenttestrunner.main(__name__)
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1112,56 +1112,7 @@
 Additionally, if `skipchild` is True, replace all other lines with parent
 annotate data as well such that child is never blamed for any lines.
 
->>> oldfctx = b'old'
->>> p1fctx, p2fctx, childfctx = b'p1', b'p2', b'c'
->>> olddata = b'a\nb\n'
->>> p1data = b'a\nb\nc\n'
->>> p2data = b'a\nc\nd\n'
->>> childdata = b'a\nb2\nc\nc2\nd\n'
->>> diffopts = mdiff.diffopts()
-
->>> def decorate(text, rev):
-... return ([(rev, i) for i in xrange(1, text.count(b'\n') + 1)], text)
-
-Basic usage:
-
->>> oldann = decorate(olddata, oldfctx)
->>> p1ann = decorate(p1data, p1fctx)
->>> p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts)
->>> p1ann[0]
-[('old', 1), ('old', 2), ('p1', 3)]
->>> p2ann = decorate(p2data, p2fctx)
->>> p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts)
->>> p2ann[0]
-[('old', 1), ('p2', 2), ('p2', 3)]
-
-Test with multiple parents (note the difference caused by ordering):
-
->>> childann = decorate(childdata, childfctx)
->>> childann = _annotatepair([p1ann, p2ann], childfctx, childann, False,
-...  diffopts)
->>> childann[0]
-[('old', 1), ('c', 2), ('p2', 2), ('c', 4), ('p2', 3)]
-
->>> childann = decorate(childdata, childfctx)
->>> childann = _annotatepair([p2ann, p1ann], childfctx, childann, False,
-...  diffopts)
->>> childann[0]
-[('old', 1), ('c', 2), ('p1', 3), ('c', 4), ('p2', 3)]
-
-Test with skipchild (note the difference caused by ordering):
-
->>> childann = decorate(childdata, childfctx)
->>> childann 

D895: check-code: allow an exception for camelcase where required

2017-10-02 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGb332c01247d8: check-code: allow an exception for camelcase 
where required (authored by sid0, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D895?vs=2316=2337

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

AFFECTED FILES
  contrib/check-code.py

CHANGE DETAILS

diff --git a/contrib/check-code.py b/contrib/check-code.py
--- a/contrib/check-code.py
+++ b/contrib/check-code.py
@@ -273,7 +273,7 @@
 #(r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
 # "don't use underbars in identifiers"),
 (r'^\s+(self\.)?[A-Za-z][a-z0-9]+[A-Z]\w* = ',
- "don't use camelcase in identifiers"),
+ "don't use camelcase in identifiers", r'#.*camelcase-required'),
 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
  "linebreak after :"),
 (r'class\s[^( \n]+:', "old-style class, use class foo(object)",



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


D899: annotate: track whether a particular annotation was the result of a skip

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 added a comment.


  Turns out it actually was buggy. Thanks for catching it!
  
  I switched to using `attrs.evolve` (and in the earlier diff setting 
`frozen=True` to make the attr immutable)

REPOSITORY
  rHG Mercurial

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

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


D899: annotate: track whether a particular annotation was the result of a skip

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 2331.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D899?vs=2329=2331

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

AFFECTED FILES
  mercurial/context.py
  tests/test-annotate.py

CHANGE DETAILS

diff --git a/tests/test-annotate.py b/tests/test-annotate.py
--- a/tests/test-annotate.py
+++ b/tests/test-annotate.py
@@ -80,20 +80,22 @@
  diffopts)
 self.assertEqual(childann[0], [
 annotateline('old', 1),
-annotateline('old', 2),
+annotateline('old', 2, True),
+# note that this line was carried over from earlier so it is *not*
+# marked skipped
 annotateline('p2', 2),
-annotateline('p2', 2),
+annotateline('p2', 2, True),
 annotateline('p2', 3),
 ])
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p2ann, p1ann], childfctx, childann, True,
  diffopts)
 self.assertEqual(childann[0], [
 annotateline('old', 1),
-annotateline('old', 2),
+annotateline('old', 2, True),
 annotateline('p1', 3),
-annotateline('p1', 3),
+annotateline('p1', 3, True),
 annotateline('p2', 3),
 ])
 
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -,6 +,8 @@
 class annotateline(object):
 fctx = attr.ib()
 lineno = attr.ib(default=False)
+# Whether this annotation was the result of a skip-annotate.
+skip = attr.ib(default=False)
 
 def _annotatepair(parents, childfctx, child, skipchild, diffopts):
 r'''
@@ -1159,7 +1161,7 @@
 for bk in xrange(b1, b2):
 if child[0][bk].fctx == childfctx:
 ak = min(a1 + (bk - b1), a2 - 1)
-child[0][bk] = parent[0][ak]
+child[0][bk] = attr.evolve(parent[0][ak], 
skip=True)
 else:
 remaining[idx][1].append((a1, a2, b1, b2))
 
@@ -1170,7 +1172,7 @@
 for bk in xrange(b1, b2):
 if child[0][bk].fctx == childfctx:
 ak = min(a1 + (bk - b1), a2 - 1)
-child[0][bk] = parent[0][ak]
+child[0][bk] = attr.evolve(parent[0][ak], skip=True)
 return child
 
 class filectx(basefilectx):



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


D898: annotate: introduce attr for storing per-line annotate data

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 2328.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D898?vs=2319=2328

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

AFFECTED FILES
  mercurial/commands.py
  mercurial/context.py
  mercurial/hgweb/webcommands.py
  tests/test-annotate.py

CHANGE DETAILS

diff --git a/tests/test-annotate.py b/tests/test-annotate.py
--- a/tests/test-annotate.py
+++ b/tests/test-annotate.py
@@ -7,6 +7,7 @@
 mdiff,
 )
 from mercurial.context import (
+annotateline,
 _annotatepair,
 )
 
@@ -25,50 +26,76 @@
 diffopts = mdiff.diffopts()
 
 def decorate(text, rev):
-return ([(rev, i) for i in xrange(1, text.count(b'\n') + 1)], text)
+return ([annotateline(fctx=rev, lineno=i)
+ for i in xrange(1, text.count(b'\n') + 1)],
+text)
 
 # Basic usage
 
 oldann = decorate(olddata, oldfctx)
 p1ann = decorate(p1data, p1fctx)
 p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts)
-self.assertEqual(p1ann[0], [('old', 1), ('old', 2), ('p1', 3)])
+self.assertEqual(p1ann[0], [
+annotateline('old', 1),
+annotateline('old', 2),
+annotateline('p1', 3),
+])
 
 p2ann = decorate(p2data, p2fctx)
 p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts)
-self.assertEqual(p2ann[0], [('old', 1), ('p2', 2), ('p2', 3)])
+self.assertEqual(p2ann[0], [
+annotateline('old', 1),
+annotateline('p2', 2),
+annotateline('p2', 3),
+])
 
 # Test with multiple parents (note the difference caused by ordering)
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p1ann, p2ann], childfctx, childann, False,
  diffopts)
-self.assertEqual(childann[0],
-[('old', 1), ('c', 2), ('p2', 2), ('c', 4), ('p2', 3)]
-)
+self.assertEqual(childann[0], [
+annotateline('old', 1),
+annotateline('c', 2),
+annotateline('p2', 2),
+annotateline('c', 4),
+annotateline('p2', 3),
+])
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p2ann, p1ann], childfctx, childann, False,
  diffopts)
-self.assertEqual(childann[0],
-[('old', 1), ('c', 2), ('p1', 3), ('c', 4), ('p2', 3)]
-)
+self.assertEqual(childann[0], [
+annotateline('old', 1),
+annotateline('c', 2),
+annotateline('p1', 3),
+annotateline('c', 4),
+annotateline('p2', 3),
+])
 
 # Test with skipchild (note the difference caused by ordering)
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p1ann, p2ann], childfctx, childann, True,
  diffopts)
-self.assertEqual(childann[0],
-[('old', 1), ('old', 2), ('p2', 2), ('p2', 2), ('p2', 3)]
-)
+self.assertEqual(childann[0], [
+annotateline('old', 1),
+annotateline('old', 2),
+annotateline('p2', 2),
+annotateline('p2', 2),
+annotateline('p2', 3),
+])
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p2ann, p1ann], childfctx, childann, True,
  diffopts)
-self.assertEqual(childann[0],
-[('old', 1), ('old', 2), ('p1', 3), ('p1', 3), ('p2', 3)]
-)
+self.assertEqual(childann[0], [
+annotateline('old', 1),
+annotateline('old', 2),
+annotateline('p1', 3),
+annotateline('p1', 3),
+annotateline('p2', 3),
+])
 
 if __name__ == '__main__':
 import silenttestrunner
diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -906,7 +906,8 @@
 
 previousrev = None
 blockparitygen = paritygen(1)
-for lineno, ((f, targetline), l) in enumerate(lines):
+for lineno, (aline, l) in enumerate(lines):
+f = aline.fctx
 rev = f.rev()
 if rev != previousrev:
 blockhead = True
@@ -924,7 +925,7 @@
"file": f.path(),
"blockhead": blockhead,
"blockparity": blockparity,
-   "targetline": targetline,
+   "targetline": aline.lineno,
"line": l,
"lineno": lineno + 1,
"lineid": "l%d" % (lineno + 1),
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -25,6 +25,9 @@
 wdirnodes,
 wdirrev,
 )
+from 

D900: annotate: mark lines affected by skip-annotate with *

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 2330.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D900?vs=2321=2330

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

AFFECTED FILES
  mercurial/commands.py
  tests/test-annotate.t

CHANGE DETAILS

diff --git a/tests/test-annotate.t b/tests/test-annotate.t
--- a/tests/test-annotate.t
+++ b/tests/test-annotate.t
@@ -261,8 +261,8 @@
 
   $ hg annotate -nlf b --skip 6
   0 a:1: a
-  1 a:2: z (no-pure !)
   0 a:1: z (pure !)
+  1 a:2* z
   1 a:3: a
   3 b:4: b4
   4 b:5: c
@@ -275,27 +275,27 @@
   0 a:1: a
   6 b:2: z
   1 a:3: a
-  1 a:3: b4
+  1 a:3* b4
   4 b:5: c
-  1 a:3: b5
+  1 a:3* b5
   7 b:7: d
 
   $ hg annotate -nlf b --skip 4
   0 a:1: a
   6 b:2: z
   1 a:3: a
   3 b:4: b4
-  1 a:3: c
+  1 a:3* c
   3 b:5: b5
   7 b:7: d
 
   $ hg annotate -nlf b --skip 3 --skip 4
   0 a:1: a
   6 b:2: z
   1 a:3: a
-  1 a:3: b4
-  1 a:3: c
-  1 a:3: b5
+  1 a:3* b4
+  1 a:3* c
+  1 a:3* b5
   7 b:7: d
 
   $ hg annotate -nlf b --skip 'merge()'
@@ -305,18 +305,18 @@
   3 b:4: b4
   4 b:5: c
   3 b:5: b5
-  3 b:5: d
+  3 b:5* d
 
 --skip everything -- use the revision the file was introduced in
 
   $ hg annotate -nlf b --skip 'all()'
   0 a:1: a
-  0 a:1: z
-  0 a:1: a
-  0 a:1: b4
-  0 a:1: c
-  0 a:1: b5
-  0 a:1: d
+  0 a:1* z
+  0 a:1* a
+  0 a:1* b4
+  0 a:1* c
+  0 a:1* b5
+  0 a:1* d
 
 Issue2807: alignment of line numbers with -l
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -400,7 +400,11 @@
 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
 fm.startitem()
 fm.write(fields, "".join(f), *p)
-fm.write('line', ": %s", l[1])
+if l[0].skip:
+fmt = "* %s"
+else:
+fmt = ": %s"
+fm.write('line', fmt, l[1])
 
 if not lines[-1][1].endswith('\n'):
 fm.plain('\n')



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


D899: annotate: track whether a particular annotation was the result of a skip

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 2329.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D899?vs=2320=2329

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

AFFECTED FILES
  mercurial/context.py
  tests/test-annotate.py

CHANGE DETAILS

diff --git a/tests/test-annotate.py b/tests/test-annotate.py
--- a/tests/test-annotate.py
+++ b/tests/test-annotate.py
@@ -80,20 +80,22 @@
  diffopts)
 self.assertEqual(childann[0], [
 annotateline('old', 1),
-annotateline('old', 2),
+annotateline('old', 2, True),
+# note that this line was carried over from earlier so it is *not*
+# marked skipped
 annotateline('p2', 2),
-annotateline('p2', 2),
+annotateline('p2', 2, True),
 annotateline('p2', 3),
 ])
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p2ann, p1ann], childfctx, childann, True,
  diffopts)
 self.assertEqual(childann[0], [
 annotateline('old', 1),
-annotateline('old', 2),
-annotateline('p1', 3),
-annotateline('p1', 3),
+annotateline('old', 2, True),
+annotateline('p1', 3, True),
+annotateline('p1', 3, True),
 annotateline('p2', 3),
 ])
 
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -,6 +,8 @@
 class annotateline(object):
 fctx = attr.ib()
 lineno = attr.ib(default=False)
+# Whether this annotation was the result of a skip-annotate.
+skip = attr.ib(default=False)
 
 def _annotatepair(parents, childfctx, child, skipchild, diffopts):
 r'''
@@ -1159,7 +1161,7 @@
 for bk in xrange(b1, b2):
 if child[0][bk].fctx == childfctx:
 ak = min(a1 + (bk - b1), a2 - 1)
-child[0][bk] = parent[0][ak]
+child[0][bk] = attr.evolve(parent[0][ak], 
skip=True)
 else:
 remaining[idx][1].append((a1, a2, b1, b2))
 
@@ -1170,7 +1172,7 @@
 for bk in xrange(b1, b2):
 if child[0][bk].fctx == childfctx:
 ak = min(a1 + (bk - b1), a2 - 1)
-child[0][bk] = parent[0][ak]
+child[0][bk] = attr.evolve(parent[0][ak], skip=True)
 return child
 
 class filectx(basefilectx):



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


D899: annotate: track whether a particular annotation was the result of a skip

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 added inline comments.

INLINE COMMENTS

> sid0 wrote in context.py:1164-1165
> Good question! Not in this case, because a particular annotation can never go 
> from skip=True to skip=False. If we decide to overwrite the annotation 
> afterwards, the whole object is replaced, not just fctx and lineno.

Actually -- hmm, you're right, this is a bit risky to code changes in the 
future -- especially if the same object gets shared between skipped and 
not-skipped lines. I'll create a new one to be safe.

REPOSITORY
  rHG Mercurial

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

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


D899: annotate: track whether a particular annotation was the result of a skip

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 added a comment.


  I'll add a comment explaining that.

REPOSITORY
  rHG Mercurial

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

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


D899: annotate: track whether a particular annotation was the result of a skip

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 added inline comments.

INLINE COMMENTS

> indygreg wrote in context.py:1164-1165
> I see that we're copying a ref to the object instead of making an object 
> copy. When we had tuples, that was fine because tuples are immutable. But 
> with attr, instances can be modified.
> 
> Will this pose any problems?

Good question! Not in this case, because a particular annotation can never go 
from skip=True to skip=False. If we decide to overwrite the annotation 
afterwards, the whole object is replaced, not just fctx and lineno.

REPOSITORY
  rHG Mercurial

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

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


D900: annotate: mark lines affected by skip-annotate with *

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 added a comment.


  Yeah, I plan to do all of those before marking the option un-experimental.

REPOSITORY
  rHG Mercurial

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

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


D898: annotate: introduce attr for storing per-line annotate data

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  We're going to extend this a bit -- at first by simply adding whether this was
  a skipped child. We're well on our way to outgrowing tuples, though -- adding
  more and more fields to tuples becomes annoying very quickly.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/commands.py
  mercurial/context.py
  mercurial/hgweb/webcommands.py
  tests/test-annotate.py

CHANGE DETAILS

diff --git a/tests/test-annotate.py b/tests/test-annotate.py
--- a/tests/test-annotate.py
+++ b/tests/test-annotate.py
@@ -7,6 +7,7 @@
 mdiff,
 )
 from mercurial.context import (
+annotateline,
 _annotatepair,
 )
 
@@ -25,50 +26,76 @@
 diffopts = mdiff.diffopts()
 
 def decorate(text, rev):
-return ([(rev, i) for i in xrange(1, text.count(b'\n') + 1)], text)
+return ([annotateline(fctx=rev, lineno=i)
+ for i in xrange(1, text.count(b'\n') + 1)],
+text)
 
 # Basic usage
 
 oldann = decorate(olddata, oldfctx)
 p1ann = decorate(p1data, p1fctx)
 p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts)
-self.assertEqual(p1ann[0], [('old', 1), ('old', 2), ('p1', 3)])
+self.assertEqual(p1ann[0], [
+annotateline('old', 1),
+annotateline('old', 2),
+annotateline('p1', 3),
+])
 
 p2ann = decorate(p2data, p2fctx)
 p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts)
-self.assertEqual(p2ann[0], [('old', 1), ('p2', 2), ('p2', 3)])
+self.assertEqual(p2ann[0], [
+annotateline('old', 1),
+annotateline('p2', 2),
+annotateline('p2', 3),
+])
 
 # Test with multiple parents (note the difference caused by ordering)
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p1ann, p2ann], childfctx, childann, False,
  diffopts)
-self.assertEqual(childann[0],
-[('old', 1), ('c', 2), ('p2', 2), ('c', 4), ('p2', 3)]
-)
+self.assertEqual(childann[0], [
+annotateline('old', 1),
+annotateline('c', 2),
+annotateline('p2', 2),
+annotateline('c', 4),
+annotateline('p2', 3),
+])
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p2ann, p1ann], childfctx, childann, False,
  diffopts)
-self.assertEqual(childann[0],
-[('old', 1), ('c', 2), ('p1', 3), ('c', 4), ('p2', 3)]
-)
+self.assertEqual(childann[0], [
+annotateline('old', 1),
+annotateline('c', 2),
+annotateline('p1', 3),
+annotateline('c', 4),
+annotateline('p2', 3),
+])
 
 # Test with skipchild (note the difference caused by ordering)
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p1ann, p2ann], childfctx, childann, True,
  diffopts)
-self.assertEqual(childann[0],
-[('old', 1), ('old', 2), ('p2', 2), ('p2', 2), ('p2', 3)]
-)
+self.assertEqual(childann[0], [
+annotateline('old', 1),
+annotateline('old', 2),
+annotateline('p2', 2),
+annotateline('p2', 2),
+annotateline('p2', 3),
+])
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p2ann, p1ann], childfctx, childann, True,
  diffopts)
-self.assertEqual(childann[0],
-[('old', 1), ('old', 2), ('p1', 3), ('p1', 3), ('p2', 3)]
-)
+self.assertEqual(childann[0], [
+annotateline('old', 1),
+annotateline('old', 2),
+annotateline('p1', 3),
+annotateline('p1', 3),
+annotateline('p2', 3),
+])
 
 if __name__ == '__main__':
 import silenttestrunner
diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -906,7 +906,8 @@
 
 previousrev = None
 blockparitygen = paritygen(1)
-for lineno, ((f, targetline), l) in enumerate(lines):
+for lineno, (aline, l) in enumerate(lines):
+f = aline.fctx
 rev = f.rev()
 if rev != previousrev:
 blockhead = True
@@ -924,7 +925,7 @@
"file": f.path(),
"blockhead": blockhead,
"blockparity": blockparity,
-   "targetline": targetline,
+   "targetline": aline.lineno,
"line": l,

D900: annotate: mark lines affected by skip-annotate with *

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This is to prevent weird surprises from happening with skips being attributed
  to the wrong changeset.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/commands.py
  tests/test-annotate.t

CHANGE DETAILS

diff --git a/tests/test-annotate.t b/tests/test-annotate.t
--- a/tests/test-annotate.t
+++ b/tests/test-annotate.t
@@ -261,8 +261,8 @@
 
   $ hg annotate -nlf b --skip 6
   0 a:1: a
-  1 a:2: z (no-pure !)
   0 a:1: z (pure !)
+  1 a:2* z
   1 a:3: a
   3 b:4: b4
   4 b:5: c
@@ -274,49 +274,49 @@
   $ hg annotate -nlf b --skip 3
   0 a:1: a
   6 b:2: z
-  1 a:3: a
-  1 a:3: b4
+  1 a:3* a
+  1 a:3* b4
   4 b:5: c
-  1 a:3: b5
+  1 a:3* b5
   7 b:7: d
 
   $ hg annotate -nlf b --skip 4
   0 a:1: a
   6 b:2: z
-  1 a:3: a
+  1 a:3* a
   3 b:4: b4
-  1 a:3: c
+  1 a:3* c
   3 b:5: b5
   7 b:7: d
 
   $ hg annotate -nlf b --skip 3 --skip 4
   0 a:1: a
   6 b:2: z
-  1 a:3: a
-  1 a:3: b4
-  1 a:3: c
-  1 a:3: b5
+  1 a:3* a
+  1 a:3* b4
+  1 a:3* c
+  1 a:3* b5
   7 b:7: d
 
   $ hg annotate -nlf b --skip 'merge()'
   0 a:1: a
   6 b:2: z
   1 a:3: a
   3 b:4: b4
   4 b:5: c
-  3 b:5: b5
-  3 b:5: d
+  3 b:5* b5
+  3 b:5* d
 
 --skip everything -- use the revision the file was introduced in
 
   $ hg annotate -nlf b --skip 'all()'
-  0 a:1: a
-  0 a:1: z
-  0 a:1: a
-  0 a:1: b4
-  0 a:1: c
-  0 a:1: b5
-  0 a:1: d
+  0 a:1* a
+  0 a:1* z
+  0 a:1* a
+  0 a:1* b4
+  0 a:1* c
+  0 a:1* b5
+  0 a:1* d
 
 Issue2807: alignment of line numbers with -l
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -400,7 +400,11 @@
 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
 fm.startitem()
 fm.write(fields, "".join(f), *p)
-fm.write('line', ": %s", l[1])
+if l[0].skip:
+fmt = "* %s"
+else:
+fmt = ": %s"
+fm.write('line', fmt, l[1])
 
 if not lines[-1][1].endswith('\n'):
 fm.plain('\n')



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


D896: annotate: move annotatepair unit tests to a separate file

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  In upcoming patches the output is going to be significantly longer than it is
  today, and doctests don't allow wrapping the output.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/context.py
  tests/test-annotate.py

CHANGE DETAILS

diff --git a/tests/test-annotate.py b/tests/test-annotate.py
new file mode 100644
--- /dev/null
+++ b/tests/test-annotate.py
@@ -0,0 +1,75 @@
+from __future__ import absolute_import
+from __future__ import print_function
+
+import unittest
+
+from mercurial import (
+mdiff,
+)
+from mercurial.context import (
+_annotatepair,
+)
+
+class AnnotateTests(unittest.TestCase):
+"""Unit tests for annotate code."""
+
+def testannotatepair(self):
+self.maxDiff = None # camelcase-required
+
+oldfctx = b'old'
+p1fctx, p2fctx, childfctx = b'p1', b'p2', b'c'
+olddata = b'a\nb\n'
+p1data = b'a\nb\nc\n'
+p2data = b'a\nc\nd\n'
+childdata = b'a\nb2\nc\nc2\nd\n'
+diffopts = mdiff.diffopts()
+
+def decorate(text, rev):
+return ([(rev, i) for i in xrange(1, text.count(b'\n') + 1)], text)
+
+# Basic usage
+
+oldann = decorate(olddata, oldfctx)
+p1ann = decorate(p1data, p1fctx)
+p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts)
+self.assertEqual(p1ann[0], [('old', 1), ('old', 2), ('p1', 3)])
+
+p2ann = decorate(p2data, p2fctx)
+p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts)
+self.assertEqual(p2ann[0], [('old', 1), ('p2', 2), ('p2', 3)])
+
+# Test with multiple parents (note the difference caused by ordering)
+
+childann = decorate(childdata, childfctx)
+childann = _annotatepair([p1ann, p2ann], childfctx, childann, False,
+ diffopts)
+self.assertEqual(childann[0],
+[('old', 1), ('c', 2), ('p2', 2), ('c', 4), ('p2', 3)]
+)
+
+childann = decorate(childdata, childfctx)
+childann = _annotatepair([p2ann, p1ann], childfctx, childann, False,
+ diffopts)
+self.assertEqual(childann[0],
+[('old', 1), ('c', 2), ('p1', 3), ('c', 4), ('p2', 3)]
+)
+
+# Test with skipchild (note the difference caused by ordering)
+
+childann = decorate(childdata, childfctx)
+childann = _annotatepair([p1ann, p2ann], childfctx, childann, True,
+ diffopts)
+self.assertEqual(childann[0],
+[('old', 1), ('old', 2), ('p2', 2), ('p2', 2), ('p2', 3)]
+)
+
+childann = decorate(childdata, childfctx)
+childann = _annotatepair([p2ann, p1ann], childfctx, childann, True,
+ diffopts)
+self.assertEqual(childann[0],
+[('old', 1), ('old', 2), ('p1', 3), ('p1', 3), ('p2', 3)]
+)
+
+if __name__ == '__main__':
+import silenttestrunner
+silenttestrunner.main(__name__)
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1112,56 +1112,7 @@
 Additionally, if `skipchild` is True, replace all other lines with parent
 annotate data as well such that child is never blamed for any lines.
 
->>> oldfctx = b'old'
->>> p1fctx, p2fctx, childfctx = b'p1', b'p2', b'c'
->>> olddata = b'a\nb\n'
->>> p1data = b'a\nb\nc\n'
->>> p2data = b'a\nc\nd\n'
->>> childdata = b'a\nb2\nc\nc2\nd\n'
->>> diffopts = mdiff.diffopts()
-
->>> def decorate(text, rev):
-... return ([(rev, i) for i in xrange(1, text.count(b'\n') + 1)], text)
-
-Basic usage:
-
->>> oldann = decorate(olddata, oldfctx)
->>> p1ann = decorate(p1data, p1fctx)
->>> p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts)
->>> p1ann[0]
-[('old', 1), ('old', 2), ('p1', 3)]
->>> p2ann = decorate(p2data, p2fctx)
->>> p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts)
->>> p2ann[0]
-[('old', 1), ('p2', 2), ('p2', 3)]
-
-Test with multiple parents (note the difference caused by ordering):
-
->>> childann = decorate(childdata, childfctx)
->>> childann = _annotatepair([p1ann, p2ann], childfctx, childann, False,
-...  diffopts)
->>> childann[0]
-[('old', 1), ('c', 2), ('p2', 2), ('c', 4), ('p2', 3)]
-
->>> childann = decorate(childdata, childfctx)
->>> childann = _annotatepair([p2ann, p1ann], childfctx, childann, False,
-...  diffopts)
->>> childann[0]
-[('old', 1), ('c', 2), ('p1', 3), ('c', 4), ('p2', 3)]
-
-Test with skipchild (note the difference caused by ordering):
-
->>> childann = decorate(childdata, childfctx)
->>> childann = 

D899: annotate: track whether a particular annotation was the result of a skip

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  We're going to expose this information in the UI in an upcoming patch.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/context.py
  tests/test-annotate.py

CHANGE DETAILS

diff --git a/tests/test-annotate.py b/tests/test-annotate.py
--- a/tests/test-annotate.py
+++ b/tests/test-annotate.py
@@ -80,20 +80,20 @@
  diffopts)
 self.assertEqual(childann[0], [
 annotateline('old', 1),
-annotateline('old', 2),
-annotateline('p2', 2),
-annotateline('p2', 2),
+annotateline('old', 2, True),
+annotateline('p2', 2, True),
+annotateline('p2', 2, True),
 annotateline('p2', 3),
 ])
 
 childann = decorate(childdata, childfctx)
 childann = _annotatepair([p2ann, p1ann], childfctx, childann, True,
  diffopts)
 self.assertEqual(childann[0], [
 annotateline('old', 1),
-annotateline('old', 2),
-annotateline('p1', 3),
-annotateline('p1', 3),
+annotateline('old', 2, True),
+annotateline('p1', 3, True),
+annotateline('p1', 3, True),
 annotateline('p2', 3),
 ])
 
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -,6 +,8 @@
 class annotateline(object):
 fctx = attr.ib()
 lineno = attr.ib(default=False)
+# Whether this annotation was the result of a skip-annotate.
+skip = attr.ib(default=False)
 
 def _annotatepair(parents, childfctx, child, skipchild, diffopts):
 r'''
@@ -1160,6 +1162,7 @@
 if child[0][bk].fctx == childfctx:
 ak = min(a1 + (bk - b1), a2 - 1)
 child[0][bk] = parent[0][ak]
+child[0][bk].skip = True
 else:
 remaining[idx][1].append((a1, a2, b1, b2))
 
@@ -1171,6 +1174,7 @@
 if child[0][bk].fctx == childfctx:
 ak = min(a1 + (bk - b1), a2 - 1)
 child[0][bk] = parent[0][ak]
+child[0][bk].skip = True
 return child
 
 class filectx(basefilectx):



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


D895: check-code: allow an exception for camelcase where required

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  unittest has a `maxDiff` parameter which has to be set to `None` in order for
  large enough failure diffs to be displayed. Add a comment to disable the
  camelcase check for `self.maxDiff = None` lines.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  contrib/check-code.py

CHANGE DETAILS

diff --git a/contrib/check-code.py b/contrib/check-code.py
--- a/contrib/check-code.py
+++ b/contrib/check-code.py
@@ -273,7 +273,7 @@
 #(r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
 # "don't use underbars in identifiers"),
 (r'^\s+(self\.)?[A-Za-z][a-z0-9]+[A-Z]\w* = ',
- "don't use camelcase in identifiers"),
+ "don't use camelcase in identifiers", r'#.*camelcase-required'),
 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
  "linebreak after :"),
 (r'class\s[^( \n]+:', "old-style class, use class foo(object)",



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


D897: context: rename local 'attr' to 'attr_'

2017-10-02 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  In the next diff we're going to import mercurial.thirdparty.attr, and pyflakes
  complains about this if this rename isn't done.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/context.py

CHANGE DETAILS

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -2420,9 +2420,9 @@
 if reusable:
 # copy extra fields from originalfctx
 attrs = ['rawdata', 'rawflags', '_filenode', '_filerev']
-for attr in attrs:
-if util.safehasattr(originalfctx, attr):
-setattr(self, attr, getattr(originalfctx, attr))
+for attr_ in attrs:
+if util.safehasattr(originalfctx, attr_):
+setattr(self, attr_, getattr(originalfctx, attr_))
 
 def data(self):
 return self._datafunc()



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


The 'attrs' library is now available within Mercurial -- a better namedtuple

2017-10-01 Thread Siddharth Agarwal

Hi everyone --

The attrs library is now available to use within Mercurial as 
'mercurial.thirdparty.attrs'. attrs is basically a better version of 
collections.namedtuple with none of the weird semantics (e.g. you can't 
compare a tuple and an attr) and no runtime performance cost (especially 
with slots turned on).


The documentation for attrs is available at [1]. See e51c8ffa1ffa [2] 
for an example of how to use attrs.


Please feel free to send cleanup patches to move existing tuples or 
namedtuples to use attrs.


[1] http://www.attrs.org/en/stable/
[2] https://www.mercurial-scm.org/repo/hg/rev/e51c8ffa1ffa

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


D867: thirdparty: vendor attrs

2017-10-01 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG765eb17a7eb8: thirdparty: vendor attrs (authored by sid0, 
committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D867?vs=2244=2253

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

AFFECTED FILES
  mercurial/thirdparty/__init__.py
  mercurial/thirdparty/attr/LICENSE.txt
  mercurial/thirdparty/attr/__init__.py
  mercurial/thirdparty/attr/_compat.py
  mercurial/thirdparty/attr/_config.py
  mercurial/thirdparty/attr/_funcs.py
  mercurial/thirdparty/attr/_make.py
  mercurial/thirdparty/attr/converters.py
  mercurial/thirdparty/attr/exceptions.py
  mercurial/thirdparty/attr/filters.py
  mercurial/thirdparty/attr/validators.py
  setup.py

CHANGE DETAILS

diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -709,6 +709,8 @@
 'mercurial.hgweb',
 'mercurial.httpclient',
 'mercurial.pure',
+'mercurial.thirdparty',
+'mercurial.thirdparty.attr',
 'hgext', 'hgext.convert', 'hgext.fsmonitor',
 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd',
diff --git a/mercurial/thirdparty/attr/validators.py 
b/mercurial/thirdparty/attr/validators.py
new file mode 100644
--- /dev/null
+++ b/mercurial/thirdparty/attr/validators.py
@@ -0,0 +1,166 @@
+"""
+Commonly useful validators.
+"""
+
+from __future__ import absolute_import, division, print_function
+
+from ._make import attr, attributes, and_, _AndValidator
+
+
+__all__ = [
+"and_",
+"in_",
+"instance_of",
+"optional",
+"provides",
+]
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _InstanceOfValidator(object):
+type = attr()
+
+def __call__(self, inst, attr, value):
+"""
+We use a callable class to be able to change the ``__repr__``.
+"""
+if not isinstance(value, self.type):
+raise TypeError(
+"'{name}' must be {type!r} (got {value!r} that is a "
+"{actual!r})."
+.format(name=attr.name, type=self.type,
+actual=value.__class__, value=value),
+attr, self.type, value,
+)
+
+def __repr__(self):
+return (
+""
+.format(type=self.type)
+)
+
+
+def instance_of(type):
+"""
+A validator that raises a :exc:`TypeError` if the initializer is called
+with a wrong type for this particular attribute (checks are perfomed using
+:func:`isinstance` therefore it's also valid to pass a tuple of types).
+
+:param type: The type to check for.
+:type type: type or tuple of types
+
+:raises TypeError: With a human readable error message, the attribute
+(of type :class:`attr.Attribute`), the expected type, and the value it
+got.
+"""
+return _InstanceOfValidator(type)
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _ProvidesValidator(object):
+interface = attr()
+
+def __call__(self, inst, attr, value):
+"""
+We use a callable class to be able to change the ``__repr__``.
+"""
+if not self.interface.providedBy(value):
+raise TypeError(
+"'{name}' must provide {interface!r} which {value!r} "
+"doesn't."
+.format(name=attr.name, interface=self.interface, value=value),
+attr, self.interface, value,
+)
+
+def __repr__(self):
+return (
+""
+.format(interface=self.interface)
+)
+
+
+def provides(interface):
+"""
+A validator that raises a :exc:`TypeError` if the initializer is called
+with an object that does not provide the requested *interface* (checks are
+performed using ``interface.providedBy(value)`` (see `zope.interface
+`_).
+
+:param zope.interface.Interface interface: The interface to check for.
+
+:raises TypeError: With a human readable error message, the attribute
+(of type :class:`attr.Attribute`), the expected interface, and the
+value it got.
+"""
+return _ProvidesValidator(interface)
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _OptionalValidator(object):
+validator = attr()
+
+def __call__(self, inst, attr, value):
+if value is None:
+return
+
+self.validator(inst, attr, value)
+
+def __repr__(self):
+return (
+""
+.format(what=repr(self.validator))
+)
+
+
+def optional(validator):
+"""
+A validator that makes an attribute optional.  An optional attribute is one
+which can be set to ``None`` in addition to satisfying the requirements of
+the sub-validator.
+
+:param validator: A validator (or a list of validators) that is 

D871: python3: don't byte mangle third-party packages

2017-10-01 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG9fb9f8440b71: python3: dont byte mangle third-party 
packages (authored by sid0, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D871?vs=2246=2251

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

AFFECTED FILES
  mercurial/__init__.py

CHANGE DETAILS

diff --git a/mercurial/__init__.py b/mercurial/__init__.py
--- a/mercurial/__init__.py
+++ b/mercurial/__init__.py
@@ -34,6 +34,9 @@
 # selectors2 is already dual-version clean, don't try and mangle it
 if fullname.startswith('mercurial.selectors2'):
 return None
+# third-party packages are expected to be dual-version clean
+if fullname.startswith('mercurial.thirdparty'):
+return None
 # zstd is already dual-version clean, don't try and mangle it
 if fullname.startswith('mercurial.zstd'):
 return None



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


D868: changelog: use attrs instead of namedtuple

2017-10-01 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGe51c8ffa1ffa: changelog: use attrs instead of namedtuple 
(authored by sid0, committed by ).

CHANGED PRIOR TO COMMIT
  https://phab.mercurial-scm.org/D868?vs=2232=2252#toc

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D868?vs=2232=2252

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

AFFECTED FILES
  mercurial/changelog.py

CHANGE DETAILS

diff --git a/mercurial/changelog.py b/mercurial/changelog.py
--- a/mercurial/changelog.py
+++ b/mercurial/changelog.py
@@ -7,14 +7,15 @@
 
 from __future__ import absolute_import
 
-import collections
-
 from .i18n import _
 from .node import (
 bin,
 hex,
 nullid,
 )
+from .thirdparty import (
+attr,
+)
 
 from . import (
 encoding,
@@ -142,10 +143,16 @@
 return appender(opener, name, mode, buf)
 return _delay
 
-_changelogrevision = collections.namedtuple(u'changelogrevision',
-(u'manifest', u'user', u'date',
- u'files', u'description',
- u'extra'))
+@attr.s
+class _changelogrevision(object):
+# Extensions might modify _defaultextra, so let the constructor below pass
+# it in
+extra = attr.ib()
+manifest = attr.ib(default=nullid)
+user = attr.ib(default='')
+date = attr.ib(default=(0, 0))
+files = attr.ib(default=[])
+description = attr.ib(default='')
 
 class changelogrevision(object):
 """Holds results of a parsed changelog revision.
@@ -162,14 +169,7 @@
 
 def __new__(cls, text):
 if not text:
-return _changelogrevision(
-manifest=nullid,
-user='',
-date=(0, 0),
-files=[],
-description='',
-extra=_defaultextra,
-)
+return _changelogrevision(extra=_defaultextra)
 
 self = super(changelogrevision, cls).__new__(cls)
 # We could return here and implement the following as an __init__.



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


D866: tests: disable lints on mercurial/thirdparty

2017-10-01 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG41401f502c83: tests: disable lints on mercurial/thirdparty 
(authored by sid0, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D866?vs=2230=2250

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

AFFECTED FILES
  contrib/import-checker.py
  tests/test-check-code.t
  tests/test-check-module-imports.t
  tests/test-check-pylint.t

CHANGE DETAILS

diff --git a/tests/test-check-pylint.t b/tests/test-check-pylint.t
--- a/tests/test-check-pylint.t
+++ b/tests/test-check-pylint.t
@@ -12,6 +12,7 @@
   $ touch $TESTTMP/fakerc
   $ pylint --rcfile=$TESTTMP/fakerc --disable=all \
   >   --enable=W0102 --reports=no \
+  >   --ignore=thirdparty \
   >   mercurial hgdemandimport hgext hgext3rd
(?)
    (?)
diff --git a/tests/test-check-module-imports.t 
b/tests/test-check-module-imports.t
--- a/tests/test-check-module-imports.t
+++ b/tests/test-check-module-imports.t
@@ -25,6 +25,7 @@
   > -X doc/gendoc.py \
   > -X doc/hgmanpage.py \
   > -X i18n/posplit \
+  > -X mercurial/thirdparty \
   > -X tests/hypothesishelpers.py \
   > -X tests/test-commit-interactive.t \
   > -X tests/test-contrib-check-code.t \
diff --git a/tests/test-check-code.t b/tests/test-check-code.t
--- a/tests/test-check-code.t
+++ b/tests/test-check-code.t
@@ -7,9 +7,11 @@
 New errors are not allowed. Warnings are strongly discouraged.
 (The writing "no-che?k-code" is for not skipping this file when checking.)
 
-  $ testrepohg locate -X contrib/python-zstandard \
-  > -X hgext/fsmonitor/pywatchman |
-  > sed 's-\\-/-g' | "$check_code" --warnings --per-file=0 - || false
+  $ testrepohg locate \
+  > -X contrib/python-zstandard \
+  > -X hgext/fsmonitor/pywatchman \
+  > -X mercurial/thirdparty \
+  > | sed 's-\\-/-g' | "$check_code" --warnings --per-file=0 - || false
   Skipping i18n/polib.py it has no-che?k-code (glob)
   Skipping mercurial/httpclient/__init__.py it has no-che?k-code (glob)
   Skipping mercurial/httpclient/_readers.py it has no-che?k-code (glob)
diff --git a/contrib/import-checker.py b/contrib/import-checker.py
--- a/contrib/import-checker.py
+++ b/contrib/import-checker.py
@@ -35,6 +35,8 @@
 'mercurial.pure.mpatch',
 'mercurial.pure.osutil',
 'mercurial.pure.parsers',
+# third-party imports should be directly imported
+'mercurial.thirdparty',
 )
 
 # Whitelist of symbols that can be directly imported.



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


D871: python3: don't byte mangle third-party packages

2017-10-01 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 2246.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D871?vs=2243=2246

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

AFFECTED FILES
  mercurial/__init__.py

CHANGE DETAILS

diff --git a/mercurial/__init__.py b/mercurial/__init__.py
--- a/mercurial/__init__.py
+++ b/mercurial/__init__.py
@@ -34,6 +34,9 @@
 # selectors2 is already dual-version clean, don't try and mangle it
 if fullname.startswith('mercurial.selectors2'):
 return None
+# third-party packages are expected to be dual-version clean
+if fullname.startswith('mercurial.thirdparty'):
+return None
 # zstd is already dual-version clean, don't try and mangle it
 if fullname.startswith('mercurial.zstd'):
 return None



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


D867: thirdparty: vendor attrs

2017-10-01 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 2244.
sid0 edited the summary of this revision.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D867?vs=2231=2244

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

AFFECTED FILES
  mercurial/thirdparty/__init__.py
  mercurial/thirdparty/attr/LICENSE.txt
  mercurial/thirdparty/attr/__init__.py
  mercurial/thirdparty/attr/_compat.py
  mercurial/thirdparty/attr/_config.py
  mercurial/thirdparty/attr/_funcs.py
  mercurial/thirdparty/attr/_make.py
  mercurial/thirdparty/attr/converters.py
  mercurial/thirdparty/attr/exceptions.py
  mercurial/thirdparty/attr/filters.py
  mercurial/thirdparty/attr/validators.py
  setup.py

CHANGE DETAILS

diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -709,6 +709,8 @@
 'mercurial.hgweb',
 'mercurial.httpclient',
 'mercurial.pure',
+'mercurial.thirdparty',
+'mercurial.thirdparty.attr',
 'hgext', 'hgext.convert', 'hgext.fsmonitor',
 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd',
diff --git a/mercurial/thirdparty/attr/validators.py 
b/mercurial/thirdparty/attr/validators.py
new file mode 100644
--- /dev/null
+++ b/mercurial/thirdparty/attr/validators.py
@@ -0,0 +1,166 @@
+"""
+Commonly useful validators.
+"""
+
+from __future__ import absolute_import, division, print_function
+
+from ._make import attr, attributes, and_, _AndValidator
+
+
+__all__ = [
+"and_",
+"in_",
+"instance_of",
+"optional",
+"provides",
+]
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _InstanceOfValidator(object):
+type = attr()
+
+def __call__(self, inst, attr, value):
+"""
+We use a callable class to be able to change the ``__repr__``.
+"""
+if not isinstance(value, self.type):
+raise TypeError(
+"'{name}' must be {type!r} (got {value!r} that is a "
+"{actual!r})."
+.format(name=attr.name, type=self.type,
+actual=value.__class__, value=value),
+attr, self.type, value,
+)
+
+def __repr__(self):
+return (
+""
+.format(type=self.type)
+)
+
+
+def instance_of(type):
+"""
+A validator that raises a :exc:`TypeError` if the initializer is called
+with a wrong type for this particular attribute (checks are perfomed using
+:func:`isinstance` therefore it's also valid to pass a tuple of types).
+
+:param type: The type to check for.
+:type type: type or tuple of types
+
+:raises TypeError: With a human readable error message, the attribute
+(of type :class:`attr.Attribute`), the expected type, and the value it
+got.
+"""
+return _InstanceOfValidator(type)
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _ProvidesValidator(object):
+interface = attr()
+
+def __call__(self, inst, attr, value):
+"""
+We use a callable class to be able to change the ``__repr__``.
+"""
+if not self.interface.providedBy(value):
+raise TypeError(
+"'{name}' must provide {interface!r} which {value!r} "
+"doesn't."
+.format(name=attr.name, interface=self.interface, value=value),
+attr, self.interface, value,
+)
+
+def __repr__(self):
+return (
+""
+.format(interface=self.interface)
+)
+
+
+def provides(interface):
+"""
+A validator that raises a :exc:`TypeError` if the initializer is called
+with an object that does not provide the requested *interface* (checks are
+performed using ``interface.providedBy(value)`` (see `zope.interface
+`_).
+
+:param zope.interface.Interface interface: The interface to check for.
+
+:raises TypeError: With a human readable error message, the attribute
+(of type :class:`attr.Attribute`), the expected interface, and the
+value it got.
+"""
+return _ProvidesValidator(interface)
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _OptionalValidator(object):
+validator = attr()
+
+def __call__(self, inst, attr, value):
+if value is None:
+return
+
+self.validator(inst, attr, value)
+
+def __repr__(self):
+return (
+""
+.format(what=repr(self.validator))
+)
+
+
+def optional(validator):
+"""
+A validator that makes an attribute optional.  An optional attribute is one
+which can be set to ``None`` in addition to satisfying the requirements of
+the sub-validator.
+
+:param validator: A validator (or a list of validators) that is used for
+non-``None`` values.
+:type validator: callable or :class:`list` 

D871: python3: don't byte mangle third-party packages

2017-10-01 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Third-party packages are already expected to be dual-version clean.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/__init__.py

CHANGE DETAILS

diff --git a/mercurial/__init__.py b/mercurial/__init__.py
--- a/mercurial/__init__.py
+++ b/mercurial/__init__.py
@@ -31,6 +31,9 @@
 # Only handle Mercurial-related modules.
 if not fullname.startswith(('mercurial.', 'hgext.', 'hgext3rd.')):
 return None
+# third-party packages are expected to be dual-version clean
+if fullname.startswith('mercurial.thirdparty'):
+return None
 # selectors2 is already dual-version clean, don't try and mangle it
 if fullname.startswith('mercurial.selectors2'):
 return None



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


D868: changelog: use attrs instead of namedtuple

2017-10-01 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  See http://www.attrs.org/en/stable/why.html#namedtuples for why attrs are
  better than namedtuples.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/changelog.py

CHANGE DETAILS

diff --git a/mercurial/changelog.py b/mercurial/changelog.py
--- a/mercurial/changelog.py
+++ b/mercurial/changelog.py
@@ -15,6 +15,9 @@
 hex,
 nullid,
 )
+from .thirdparty import (
+attr,
+)
 
 from . import (
 encoding,
@@ -142,10 +145,16 @@
 return appender(opener, name, mode, buf)
 return _delay
 
-_changelogrevision = collections.namedtuple(u'changelogrevision',
-(u'manifest', u'user', u'date',
- u'files', u'description',
- u'extra'))
+@attr.s
+class _changelogrevision(object):
+# Extensions might modify _defaultextra, so let the constructor below pass
+# it in
+extra = attr.ib()
+manifest = attr.ib(default=nullid)
+user = attr.ib(default='')
+date = attr.ib(default=(0, 0))
+files = attr.ib(default=[])
+description = attr.ib(default='')
 
 class changelogrevision(object):
 """Holds results of a parsed changelog revision.
@@ -162,14 +171,7 @@
 
 def __new__(cls, text):
 if not text:
-return _changelogrevision(
-manifest=nullid,
-user='',
-date=(0, 0),
-files=[],
-description='',
-extra=_defaultextra,
-)
+return _changelogrevision(extra=_defaultextra)
 
 self = super(changelogrevision, cls).__new__(cls)
 # We could return here and implement the following as an __init__.



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


D866: tests: disable lints on mercurial/thirdparty

2017-10-01 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  In the next patch, this directory will be used to vendor in some third-party
  code.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  contrib/import-checker.py
  tests/test-check-code.t
  tests/test-check-module-imports.t
  tests/test-check-pylint.t

CHANGE DETAILS

diff --git a/tests/test-check-pylint.t b/tests/test-check-pylint.t
--- a/tests/test-check-pylint.t
+++ b/tests/test-check-pylint.t
@@ -12,6 +12,7 @@
   $ touch $TESTTMP/fakerc
   $ pylint --rcfile=$TESTTMP/fakerc --disable=all \
   >   --enable=W0102 --reports=no \
+  >   --ignore=thirdparty \
   >   mercurial hgdemandimport hgext hgext3rd
(?)
    (?)
diff --git a/tests/test-check-module-imports.t 
b/tests/test-check-module-imports.t
--- a/tests/test-check-module-imports.t
+++ b/tests/test-check-module-imports.t
@@ -25,6 +25,7 @@
   > -X doc/gendoc.py \
   > -X doc/hgmanpage.py \
   > -X i18n/posplit \
+  > -X mercurial/thirdparty \
   > -X tests/hypothesishelpers.py \
   > -X tests/test-commit-interactive.t \
   > -X tests/test-contrib-check-code.t \
diff --git a/tests/test-check-code.t b/tests/test-check-code.t
--- a/tests/test-check-code.t
+++ b/tests/test-check-code.t
@@ -7,9 +7,11 @@
 New errors are not allowed. Warnings are strongly discouraged.
 (The writing "no-che?k-code" is for not skipping this file when checking.)
 
-  $ testrepohg locate -X contrib/python-zstandard \
-  > -X hgext/fsmonitor/pywatchman |
-  > sed 's-\\-/-g' | "$check_code" --warnings --per-file=0 - || false
+  $ testrepohg locate \
+  > -X contrib/python-zstandard \
+  > -X hgext/fsmonitor/pywatchman \
+  > -X mercurial/thirdparty \
+  > | sed 's-\\-/-g' | "$check_code" --warnings --per-file=0 - || false
   Skipping i18n/polib.py it has no-che?k-code (glob)
   Skipping mercurial/httpclient/__init__.py it has no-che?k-code (glob)
   Skipping mercurial/httpclient/_readers.py it has no-che?k-code (glob)
diff --git a/contrib/import-checker.py b/contrib/import-checker.py
--- a/contrib/import-checker.py
+++ b/contrib/import-checker.py
@@ -35,6 +35,8 @@
 'mercurial.pure.mpatch',
 'mercurial.pure.osutil',
 'mercurial.pure.parsers',
+# third-party imports should be directly imported
+'mercurial.thirdparty',
 )
 
 # Whitelist of symbols that can be directly imported.



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


D867: thirdparty: vendor attrs

2017-10-01 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The attrs package allows defining namedtuple-like classes with no weird
  behavior and no runtime performance cost.
  
  This patch vendors in attrs 17.2.0.
  
  1. no-check-commit

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/thirdparty/__init__.py
  mercurial/thirdparty/attr/LICENSE.txt
  mercurial/thirdparty/attr/__init__.py
  mercurial/thirdparty/attr/_compat.py
  mercurial/thirdparty/attr/_config.py
  mercurial/thirdparty/attr/_funcs.py
  mercurial/thirdparty/attr/_make.py
  mercurial/thirdparty/attr/converters.py
  mercurial/thirdparty/attr/exceptions.py
  mercurial/thirdparty/attr/filters.py
  mercurial/thirdparty/attr/validators.py

CHANGE DETAILS

diff --git a/mercurial/thirdparty/attr/validators.py 
b/mercurial/thirdparty/attr/validators.py
new file mode 100644
--- /dev/null
+++ b/mercurial/thirdparty/attr/validators.py
@@ -0,0 +1,166 @@
+"""
+Commonly useful validators.
+"""
+
+from __future__ import absolute_import, division, print_function
+
+from ._make import attr, attributes, and_, _AndValidator
+
+
+__all__ = [
+"and_",
+"in_",
+"instance_of",
+"optional",
+"provides",
+]
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _InstanceOfValidator(object):
+type = attr()
+
+def __call__(self, inst, attr, value):
+"""
+We use a callable class to be able to change the ``__repr__``.
+"""
+if not isinstance(value, self.type):
+raise TypeError(
+"'{name}' must be {type!r} (got {value!r} that is a "
+"{actual!r})."
+.format(name=attr.name, type=self.type,
+actual=value.__class__, value=value),
+attr, self.type, value,
+)
+
+def __repr__(self):
+return (
+""
+.format(type=self.type)
+)
+
+
+def instance_of(type):
+"""
+A validator that raises a :exc:`TypeError` if the initializer is called
+with a wrong type for this particular attribute (checks are perfomed using
+:func:`isinstance` therefore it's also valid to pass a tuple of types).
+
+:param type: The type to check for.
+:type type: type or tuple of types
+
+:raises TypeError: With a human readable error message, the attribute
+(of type :class:`attr.Attribute`), the expected type, and the value it
+got.
+"""
+return _InstanceOfValidator(type)
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _ProvidesValidator(object):
+interface = attr()
+
+def __call__(self, inst, attr, value):
+"""
+We use a callable class to be able to change the ``__repr__``.
+"""
+if not self.interface.providedBy(value):
+raise TypeError(
+"'{name}' must provide {interface!r} which {value!r} "
+"doesn't."
+.format(name=attr.name, interface=self.interface, value=value),
+attr, self.interface, value,
+)
+
+def __repr__(self):
+return (
+""
+.format(interface=self.interface)
+)
+
+
+def provides(interface):
+"""
+A validator that raises a :exc:`TypeError` if the initializer is called
+with an object that does not provide the requested *interface* (checks are
+performed using ``interface.providedBy(value)`` (see `zope.interface
+`_).
+
+:param zope.interface.Interface interface: The interface to check for.
+
+:raises TypeError: With a human readable error message, the attribute
+(of type :class:`attr.Attribute`), the expected interface, and the
+value it got.
+"""
+return _ProvidesValidator(interface)
+
+
+@attributes(repr=False, slots=True, hash=True)
+class _OptionalValidator(object):
+validator = attr()
+
+def __call__(self, inst, attr, value):
+if value is None:
+return
+
+self.validator(inst, attr, value)
+
+def __repr__(self):
+return (
+""
+.format(what=repr(self.validator))
+)
+
+
+def optional(validator):
+"""
+A validator that makes an attribute optional.  An optional attribute is one
+which can be set to ``None`` in addition to satisfying the requirements of
+the sub-validator.
+
+:param validator: A validator (or a list of validators) that is used for
+non-``None`` values.
+:type validator: callable or :class:`list` of callables.
+
+.. versionadded:: 15.1.0
+.. versionchanged:: 17.1.0 *validator* can be a list of validators.
+"""
+if isinstance(validator, list):
+return _OptionalValidator(_AndValidator(validator))
+return _OptionalValidator(validator)
+
+
+@attributes(repr=False, 

D351: demandimport: disable by default if chg is being used

2017-08-15 Thread sid0 (Siddharth Agarwal)
sid0 added a comment.


  > I tried that approach. If we only set HGDEMANDIMPORT for the forked process 
to execute hg server, it will be an infinite loop - environment config hash 
will mismatch. Setting HGDEMANDIMPORT for both the forked and non-forked chg 
client processes seems less cleaner.
  
  This should be a comment in this patch :)

REPOSITORY
  rHG Mercurial

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

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


Mercurial 4.4 sprint: September 29-October 1 at Facebook Dublin

2017-08-08 Thread Siddharth Agarwal

Hi everyone,

I'm happy to announce that the Mercurial 4.4 sprint will be held from 
September 29-October 1, 2017, at Facebook Dublin in Ireland.


For more details and to mark your attendance and suggest topics, please 
see https://www.mercurial-scm.org/wiki/4.4sprint.


Thanks,
Siddharth

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


Re: PLEASE SIGN UP: Mercurial 4.4 sprint

2017-07-25 Thread Siddharth Agarwal

On 7/21/17 10:43 AM, Siddharth Agarwal wrote:

Hi everyone,

The Mercurial 4.4 sprint is going to be held in Europe some time in 
September or early October. Please sign up here with your availability:


Thank you to everyone who's signed up already.

Reminder -- please sign up by tomorrow, July 26 at 23:59 UTC.

https://www.mercurial-scm.org/wiki/4.4sprint




https://www.mercurial-scm.org/wiki/4.4sprint <<<


Please get your signups in by **Wednesday, July 26 at 23:59 UTC**.

Thanks,
Siddharth on behalf of the Steering Committee



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


PLEASE SIGN UP: Mercurial 4.4 sprint

2017-07-21 Thread Siddharth Agarwal

Hi everyone,

The Mercurial 4.4 sprint is going to be held in Europe some time in 
September or early October. Please sign up here with your availability:



https://www.mercurial-scm.org/wiki/4.4sprint <<<


Please get your signups in by **Wednesday, July 26 at 23:59 UTC**.

Thanks,
Siddharth on behalf of the Steering Committee

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


Re: D153: test-dirstate-race: hide irrelevant hg status output

2017-07-20 Thread sid0 (Siddharth Agarwal)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG34a8ef358c93: test-dirstate-race: hide irrelevant hg status 
output (authored by sid0).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D153?vs=351=354

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

AFFECTED FILES
  tests/test-dirstate-race.t

CHANGE DETAILS

diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -204,12 +204,16 @@
   $ hg commit -m c4
   created new head
 
-Configure a merge tool that runs status in the middle of the rebase.
+Configure a merge tool that runs status in the middle of the rebase. The goal 
of
+the status call is to trigger a potential bug if fsmonitor's state is written
+even though the wlock is held by another process. The output of 'hg status' in
+the merge tool goes to /dev/null because we're more interested in the results 
of
+'hg status' run after the rebase.
 
   $ cat >> $TESTTMP/mergetool-race.sh << EOF
   > echo "custom merge tool"
   > printf "c2\nc3\nc4\n" > \$1
-  > hg --cwd "$TESTTMP/repo" status
+  > hg --cwd "$TESTTMP/repo" status > /dev/null
   > echo "custom merge tool end"
   > EOF
   $ cat >> $HGRCPATH << EOF
@@ -220,14 +224,10 @@
   > test.args=$TESTTMP/mergetool-race.sh \$output
   > EOF
 
-BROKEN: the "M b" line should not be there
   $ hg rebase -s . -d 3 --tool test
   rebasing 4:b08445fd6b2a "c4" (tip)
   merging a
   custom merge tool
-  M a
-  M b
-  ? a.orig
   custom merge tool end
   saved backup bundle to $TESTTMP/repo/.hg/strip-backup/* (glob)
 



EMAIL PREFERENCES
  https://phab.mercurial-scm.org/settings/panel/emailpreferences/

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


Re: D153: test-dirstate-race: replace BROKEN line with explanation of changed output

2017-07-20 Thread sid0 (Siddharth Agarwal)
sid0 updated this revision to Diff 351.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D153?vs=337=351

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

AFFECTED FILES
  tests/test-dirstate-race.t

CHANGE DETAILS

diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -204,12 +204,16 @@
   $ hg commit -m c4
   created new head
 
-Configure a merge tool that runs status in the middle of the rebase.
+Configure a merge tool that runs status in the middle of the rebase. The goal 
of
+the status call is to trigger a potential bug if fsmonitor's state is written
+even though the wlock is held by another process. The output of 'hg status' in
+the merge tool goes to /dev/null because we're more interested in the results 
of
+'hg status' run after the rebase.
 
   $ cat >> $TESTTMP/mergetool-race.sh << EOF
   > echo "custom merge tool"
   > printf "c2\nc3\nc4\n" > \$1
-  > hg --cwd "$TESTTMP/repo" status
+  > hg --cwd "$TESTTMP/repo" status > /dev/null
   > echo "custom merge tool end"
   > EOF
   $ cat >> $HGRCPATH << EOF
@@ -220,14 +224,10 @@
   > test.args=$TESTTMP/mergetool-race.sh \$output
   > EOF
 
-BROKEN: the "M b" line should not be there
   $ hg rebase -s . -d 3 --tool test
   rebasing 4:b08445fd6b2a "c4" (tip)
   merging a
   custom merge tool
-  M a
-  M b
-  ? a.orig
   custom merge tool end
   saved backup bundle to $TESTTMP/repo/.hg/strip-backup/* (glob)
 



EMAIL PREFERENCES
  https://phab.mercurial-scm.org/settings/panel/emailpreferences/

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


Re: D153: test-dirstate-race: replace BROKEN line with explanation of changed output

2017-07-20 Thread sid0 (Siddharth Agarwal)
sid0 added inline comments.

INLINE COMMENTS

> martinvonz wrote in test-dirstate-race.t:223-231
> Oh, the "hg status" is just to cause it to write the dirstate? Would "hg 
> debugrebuilddirstate" work? That doesn't produce any output and it's clearer 
> that that will result in the dirstate getting written ("hg status" doesn't 
> always write it, as I'm sure you know). If that would work, we can delete the 
> whole comment, I think.

I'm afraid not -- debugrebuilddirstate will try to acquire the wlock, which is 
already held by the rebase.

REPOSITORY
  rHG Mercurial

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

EMAIL PREFERENCES
  https://phab.mercurial-scm.org/settings/panel/emailpreferences/

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


Re: D153: test-dirstate-race: replace BROKEN line with explanation of changed output

2017-07-19 Thread sid0 (Siddharth Agarwal)
sid0 added inline comments.

INLINE COMMENTS

> test-dirstate-race.t:244
>  
>$ hg status

^^ this one should be empty.

REPOSITORY
  rHG Mercurial

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

EMAIL PREFERENCES
  https://phab.mercurial-scm.org/settings/panel/emailpreferences/

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


Re: D153: test-dirstate-race: replace BROKEN line with explanation of changed output

2017-07-19 Thread sid0 (Siddharth Agarwal)
sid0 added inline comments.

INLINE COMMENTS

> martinvonz wrote in test-dirstate-race.t:223-231
> The commit that introduced this test case 
> (https://phab.mercurial-scm.org/rHG15e85dded93323d286dc0a758edde1b9dbea5cdd) 
> referred to bug https://bz.mercurial-scm.org/show_bug.cgi?id=5581. The 
> description of that issue (filed by you) finishes with "That last 'hg status' 
> should be empty, but it returns 'M b'.". You changed your mind about what the 
> expected behavior should be?

The *last* hg status should be empty. This is an intermediate hg status.

REPOSITORY
  rHG Mercurial

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

EMAIL PREFERENCES
  https://phab.mercurial-scm.org/settings/panel/emailpreferences/

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


Re: D153: test-dirstate-race: replace BROKEN line with explanation of changed output

2017-07-19 Thread sid0 (Siddharth Agarwal)
sid0 added a comment.


  (I think this should go into stable as a "test fix")

REPOSITORY
  rHG Mercurial

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

EMAIL PREFERENCES
  https://phab.mercurial-scm.org/settings/panel/emailpreferences/

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


Re: D153: test-dirstate-race: replace BROKEN line with explanation of changed output

2017-07-19 Thread sid0 (Siddharth Agarwal)
sid0 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  See the explanation for more.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  tests/test-dirstate-race.t

CHANGE DETAILS

diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -220,7 +220,15 @@
   > test.args=$TESTTMP/mergetool-race.sh \$output
   > EOF
 
-BROKEN: the "M b" line should not be there
+The "M b" line in the hg status output used to not exist, but the changes in
+b63351f6a246 caused the ordering of operations to change such that the dirstate
+gets written out at a different time. This causes the 'hg status' in the middle
+to think that "b" is modified. Note that strictly speaking isn't wrong since c4
+does actually modify "b".
+
+Regardless, we're more interested in testing what happens to 'hg status'
+afterwards, both with and without fsmonitor.
+
   $ hg rebase -s . -d 3 --tool test
   rebasing 4:b08445fd6b2a "c4" (tip)
   merging a



EMAIL PREFERENCES
  https://phab.mercurial-scm.org/settings/panel/emailpreferences/

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


Re: Next plans on radixlink and hash-preserving obsstore

2017-07-10 Thread Siddharth Agarwal

On 7/9/17 10:16 PM, Sean Farley wrote:

Jun Wu  writes:


hash-preserving obsstore,

I've commented on this before but I will try to be as explicit as
possible here.

I do not want to think about hash-preserving obsstore right now.


I'm speaking from the point of view of someone who uses obsolete markers 
but isn't involved in the day to day design work.


I do want us to think about it, actually.



I do not want to think about it for the next year even.

I want obs-exchange to solved before hash-preserving.

I want all the UI/UX of evolve to be solve and in core before we even
*contemplate* (the over-engineered) hash-preserving.



Hash preservation (or not) is necessarily one of the core tenets of any 
UX based around obsolete markers. This isn't about whether it's 
overengineered -- this is about whether it makes sense to users, and 
whether an "hg undo" command brings you back to the same hash or not is 
one of the more fundamental design decisions to make.


It's usually a good practice to first determine what users expect and 
work backwards from there.


- Siddharth



I don't know how to be more clear with you while still being polite.


___
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: Next plans on radixlink and hash-preserving obsstore

2017-07-10 Thread Siddharth Agarwal

On 7/9/17 10:16 PM, Sean Farley wrote:

Jun Wu  writes:


hash-preserving obsstore,

I've commented on this before but I will try to be as explicit as
possible here.

I do not want to think about hash-preserving obsstore right now.


I'm speaking from the point of view of someone who uses obsolete markers 
but isn't involved in the day to day design work.


I do want us to think about it, actually.



I do not want to think about it for the next year even.

I want obs-exchange to solved before hash-preserving.

I want all the UI/UX of evolve to be solve and in core before we even
*contemplate* (the over-engineered) hash-preserving.



Hash preservation (or not) is necessarily one of the core tenets of any 
UX based around obsolete markers. This isn't about whether it's 
overengineered -- this is about whether it makes sense to users, and 
whether an "hg undo" command brings you back to the same hash or not is 
one of the more fundamental design decisions to make.


It's usually a good practice to first determine what users expect and 
work backwards from there.


- Siddharth



I don't know how to be more clear with you while still being polite.


___
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 01 of 13 sparse] sparse: vendor Facebook-developed extension

2017-07-05 Thread Siddharth Agarwal

On 7/5/17 3:35 PM, Augie Fackler wrote:

Yep. I think we'll need to bikeshed a bit around UX, but
experimental-in-core looks like it should offer some nice
consolidation and ease the path of getting narrow in core.

I'm +1 on this too - Greg, do you want to address the bits of feedback
you got (about the choice of the merge module etc) and roll a v2?


While debugging something else I also found a bug in sparse -- matchers 
need to implement __repr__. If you can sneak a fix in that would be 
great, otherwise I can send a fix after this lands.

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


Re: [PATCH 1 of 3] phabricator: add a contrib script

2017-07-02 Thread Siddharth Agarwal

On 7/2/17 8:10 PM, Jun Wu wrote:

# HG changeset patch
# User Jun Wu 
# Date 1499051289 25200
#  Sun Jul 02 20:08:09 2017 -0700
# Node ID dde88a5ead698208226301a62a5f2aa2629d7839
# Parent  c077eac329e26a4ca7da8b80071ba9161994bcfe
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r dde88a5ead69
phabricator: add a contrib script


Does this series mean we can provide a basically equivalent experience 
to email? (Maybe even better than that because applying changes looks 
pretty easy?)





The default Phabricator client arcanist is not friendly to send a stack of
changesets. It works better when a feature branch is reviewed as a single
review unit. However, we want multiple revisions per feature branch.

To be able to have an `hg email`-like UX to send and receive a stack of
commits easily, it seems we have to re-invent things. This patch adds
`phabricator.py` speaking Conduit API [1] in `contrib` as the first step.
This may also be an option for people who don't want to run PHP.

Config could be done in `hgrc` (instead of `arcrc` or `arcconfig`):

 [phabricator]
 # API token. Get it from https://phab.mercurial-scm.org/conduit/login/
 token = cli-
 url = https://phab.mercurial-scm.org/
 # callsign is used by the next patch
 callsign = HG

This patch only adds a single command: `debugcallconduit` to keep the patch
size small. To test it, having the above config, and run:

 $ hg debugcallconduit diffusion.repository.search < {"constraints": {"callsigns": ["HG"]}}
 > EOF

The result will be printed in prettified JSON format.

[1]: Conduit APIs are listed at https://phab.mercurial-scm.org/conduit/

diff --git a/contrib/phabricator.py b/contrib/phabricator.py
new file mode 100644
--- /dev/null
+++ b/contrib/phabricator.py
@@ -0,0 +1,98 @@
+# phabricator.py - simple Phabricator integration
+#
+# Copyright 2017 Facebook, Inc.
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+"""simple Phabricator integration
+
+Config::
+
+[phabricator]
+# Phabricator URL
+url = https://phab.example.com/
+
+# API token. Get it from https://$HOST/conduit/login/
+token = cli-
+"""
+
+from __future__ import absolute_import
+
+import json
+
+from mercurial.i18n import _
+from mercurial import (
+error,
+registrar,
+url as urlmod,
+util,
+)
+
+cmdtable = {}
+command = registrar.command(cmdtable)
+
+def urlencodenested(params):
+"""like urlencode, but works with nested parameters.
+
+For example, if params is {'a': ['b', 'c'], 'd': {'e': 'f'}}, it will be
+flattened to {'a[0]': 'b', 'a[1]': 'c', 'd[e]': 'f'} and then passed to
+urlencode. Note: the encoding is consistent with PHP's http_build_query.
+"""
+flatparams = util.sortdict()
+def process(prefix, obj):
+items = {list: enumerate, dict: lambda x: x.items()}.get(type(obj))
+if items is None:
+flatparams[prefix] = obj
+else:
+for k, v in items(obj):
+if prefix:
+process('%s[%s]' % (prefix, k), v)
+else:
+process(k, v)
+process('', params)
+return util.urlreq.urlencode(flatparams)
+
+def readurltoken(repo):
+"""return conduit url, token and make sure they exist
+
+Currently read from [phabricator] config section. In the future, it might
+make sense to read from .arcconfig and .arcrc as well.
+"""
+values = []
+section = 'phabricator'
+for name in ['url', 'token']:
+value = repo.ui.config(section, name)
+if not value:
+raise error.Abort(_('config %s.%s is required') % (section, name))
+values.append(value)
+return values
+
+def callconduit(repo, name, params):
+"""call Conduit API, params is a dict. return json.loads result, or None"""
+host, token = readurltoken(repo)
+url, authinfo = util.url('/'.join([host, 'api', name])).authinfo()
+urlopener = urlmod.opener(repo.ui, authinfo)
+repo.ui.debug('Conduit Call: %s %s\n' % (url, params))
+params = params.copy()
+params['api.token'] = token
+request = util.urlreq.request(url, data=urlencodenested(params))
+body = urlopener.open(request).read()
+repo.ui.debug('Conduit Response: %s\n' % body)
+parsed = json.loads(body)
+if parsed.get(r'error_code'):
+msg = (_('Conduit Error (%s): %s')
+   % (parsed[r'error_code'], parsed[r'error_info']))
+raise error.Abort(msg)
+return parsed[r'result']
+
+@command('debugcallconduit', [], _('METHOD'))
+def debugcallconduit(ui, repo, name):
+"""call Conduit API
+
+Call parameters are read from stdin as a JSON blob. Result will be written
+to stdout as a JSON blob.
+"""
+params = 

[PATCH 1 of 2] bundle2: add some debugging information to the not-a-bundle error

2017-06-27 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1498599055 25200
#  Tue Jun 27 14:30:55 2017 -0700
# Node ID 8b59a6d6f77927cc7b40b282056278829ca398b3
# Parent  eb4c49f55f1f0d7719f514c16bec54515eb54f62
bundle2: add some debugging information to the not-a-bundle error

I found this useful while trying to debug wireproto-related issues.

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -678,6 +678,9 @@ def getunbundler(ui, fp, magicstring=Non
 magicstring = changegroup.readexactly(fp, 4)
 magic, version = magicstring[0:2], magicstring[2:4]
 if magic != 'HG':
+ui.debug(
+"error: invalid magic: %r (version %r), should be 'HG'\n"
+% (magic, version))
 raise error.Abort(_('not a Mercurial bundle'))
 unbundlerclass = formatmap.get(version)
 if unbundlerclass is None:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 2] bundle2: add debug info about the number of stream params

2017-06-27 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1498599480 25200
#  Tue Jun 27 14:38:00 2017 -0700
# Node ID d3c71b4e989d6db9e65469c930755a38b4994ae7
# Parent  8b59a6d6f77927cc7b40b282056278829ca398b3
bundle2: add debug info about the number of stream params

Seems like the %i was never substituted.

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -349,7 +349,7 @@ def processbundle(repo, unbundler, trans
 if repo.ui.debugflag:
 msg = ['bundle2-input-bundle:']
 if unbundler.params:
-msg.append(' %i params')
+msg.append(' %i params' % len(unbundler.params))
 if op.gettransaction is None or op.gettransaction is _notransaction:
 msg.append(' no-transaction')
 else:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH RFC] ui: add support for a tweakdefaults knob

2017-06-14 Thread Siddharth Agarwal

On 6/14/17 6:37 PM, Augie Fackler wrote:

# HG changeset patch
# User Augie Fackler 
# Date 1497488194 14400
#  Wed Jun 14 20:56:34 2017 -0400
# Node ID 0e5ea7a86a8021d02218c35b07366ac6081ab3fb
# Parent  3abba5bc34546951b11b1bd3f5e5c77b90d950d1
ui: add support for a tweakdefaults knob


+1 -- this gives us a great path forward.



We've been talking for years about a one-stop config knob to opt in to
better behavior. There have been a lot of ideas thrown around, but
they all seem to be too complicated to get anyone to actually do the
work.. As such, this patch is the stupidest thing that can possibly
work in the name of getting a good feature to users.

Right now it's just three config settings that I think are generally
uncontroversial, but I expect to add more soon. That will likely
include adding new config knobs for the express purpose of adding them
to tweakdefaults.

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -2071,6 +2071,15 @@ User interface controls.
  on all exceptions, even those recognized by Mercurial (such as
  IOError or MemoryError). (default: False)
  
+``tweakdefaults``

+
+By default Mercurial's behavior changes very little from release
+to release, but over time the recommended config settings
+shift. Enable this config to opt in to get automatic tweaks to
+Mercurial's behavior over time. This config setting will have no
+effet if ``HGPLAIN` is set or ``HGPLAINEXCEPT`` is set and does
+not include ``tweakdefaults``. (default: False)
+
  ``username``
  The committer of a changeset created when running "commit".
  Typically a person's name and email address, e.g. ``Fred Widget
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -43,6 +43,20 @@ urlreq = util.urlreq
  _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
   if not c.isalnum())
  
+# The config knobs that will be altered (if unset) by ui.tweakdefaults.

+tweakrc = """
+[ui]
+# The rollback command is dangerous. As a rule, don't use it.
+rollback = False
+
+[commands]
+# Make `hg status` emit cwd-relative paths by default.
+status.relative = yes
+
+[diff]
+git = 1
+"""
+
  samplehgrcs = {
  'user':
  """# example user config (see 'hg help config' for more info)
@@ -182,6 +196,7 @@ class ui(object):
  self.fin = src.fin
  self.pageractive = src.pageractive
  self._disablepager = src._disablepager
+self._tweaked = src._tweaked
  
  self._tcfg = src._tcfg.copy()

  self._ucfg = src._ucfg.copy()
@@ -205,6 +220,7 @@ class ui(object):
  self.fin = util.stdin
  self.pageractive = False
  self._disablepager = False
+self._tweaked = False
  
  # shared read-only environment

  self.environ = encoding.environ
@@ -241,8 +257,29 @@ class ui(object):
  u.fixconfig(section=section)
  else:
  raise error.ProgrammingError('unknown rctype: %s' % t)
+u._maybetweakdefaults()
  return u
  
+def _maybetweakdefaults(self):

+if not self.configbool('ui', 'tweakdefaults'):
+return
+if self._tweaked or self.plain('tweakdefaults'):
+return
+
+# Note: it is SUPER IMPORTANT that you set self._tweaked to
+# True *before* any calls to setconfig(), otherwise you'll get
+# infinite recursion between setconfig and this method.
+#
+# TODO: We should extract an inner method in setconfig() to
+# avoid this weirdness.
+self._tweaked = True
+tmpcfg = config.config()
+tmpcfg.parse('', tweakrc)
+for section in tmpcfg:
+for name, value in tmpcfg.items(section):
+if not self.hasconfig(section, name):
+self.setconfig(section, name, value, "")
+
  def copy(self):
  return self.__class__(self)
  
@@ -387,6 +424,7 @@ class ui(object):

  for cfg in (self._ocfg, self._tcfg, self._ucfg):
  cfg.set(section, name, value, source)
  self.fixconfig(section=section)
+self._maybetweakdefaults()
  
  def _data(self, untrusted):

  return untrusted and self._ucfg or self._tcfg
diff --git a/tests/test-status.t b/tests/test-status.t
--- a/tests/test-status.t
+++ b/tests/test-status.t
@@ -107,6 +107,29 @@ combining patterns with root and pattern
? a/in_a
? b/in_b
  
+tweaking defaults works

+  $ hg status --cwd a --config ui.tweakdefaults=yes
+  ? 1/in_a_1
+  ? in_a
+  ? ../b/1/in_b_1
+  ? ../b/2/in_b_2
+  ? ../b/in_b
+  ? ../in_root
+  $ HGPLAIN=1 hg status --cwd a --config ui.tweakdefaults=yes
+  ? a/1/in_a_1 (glob)
+  ? a/in_a (glob)
+  ? b/1/in_b_1 (glob)
+  ? b/2/in_b_2 (glob)
+  ? b/in_b (glob)
+  ? in_root
+  

Is the bugzilla bug closer bot broken?

2017-06-14 Thread Siddharth Agarwal
https://bz.mercurial-scm.org/show_bug.cgi?id=5581 should have been 
closed by https://www.mercurial-scm.org/repo/hg/rev/1b25c648d5b7, but 
looks like it wasn't. I think this used to work a while ago -- did it 
break at some point?


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


Re: [PATCH 5 of 5] fsmonitor: don't write out state if identity has changed (issue5581)

2017-06-12 Thread Siddharth Agarwal

On 6/12/17 3:36 PM, Siddharth Agarwal wrote:

+# Read the identity from the file on disk rather than from the open 
file
+# pointer below, because the latter is actually a brand new file.
+identity = util.filestat.frompath(self._vfs.join('fsmonitor.state'))
+if identity != self._identity:
+self._ui.debug('skip updating fsmonitor.state: identity 
mismatch\n')
+return
+else:
+self._ui.debug('identity new: %s %s old: %s %s' % (identity, 
identity.stat, self._identity, self._identity.stat))



Whoops, left these last two lines in by accident. Happy to send a V2, or 
if someone can fix it inflight that would be great.


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


Re: [PATCH 3 of 5] workingctx: add a way for extensions to run code at status fixup time

2017-06-12 Thread Siddharth Agarwal

On 6/12/17 3:59 PM, Sean Farley wrote:

The ownership could be in localrepo, for sure. But the methods could
still live in workingctx (and just call self._repo._dirstate). I'm also
ok with doing the refactor myself and can queue this as-is.



Hmm, that might be inconvenient for extensions that need to use it, 
since (as in patch 4) they may plug in at the dirstate.status or 
localrepo.status level.


Seems to me that creating a wctx through repo[None] just to mutate some 
state that lives on the localrepo anyway is unnecessarily indirect.


This might make a bit more sense once dirstate is in workingctx, I 
guess. (I don't know what your plans are around dirstate uniqueness -- 
if the dirstate object isn't destroyed on invalidation like it is today, 
then this state can live there.)


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


Re: [PATCH 3 of 5] workingctx: add a way for extensions to run code at status fixup time

2017-06-12 Thread Siddharth Agarwal

On 6/12/17 3:56 PM, Sean Farley wrote:

The series' direction (adding a callback within a lock) looks good to
me. My only feedback is that I'm currently ripping out dirstate from
localrepo and putting it into the workingctx itself. Can these callbacks
live in dirstate.py? Or maybe even workingctx?



I'm afraid not, because just like the workingctx, the dirstate isn't 
unique per-repo. The localrepo is the only place this state can live.


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


[PATCH 1 of 5] workingctx: factor out post-status dirstate fixup

2017-06-12 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1497300899 25200
#  Mon Jun 12 13:54:59 2017 -0700
# Node ID f9a3b5bd5c5a9e1fdf68f5b0af1675ecfbc7ae7a
# Parent  0b9bca3118048ef1d52b27af156c98df8a0fa685
workingctx: factor out post-status dirstate fixup

We want to allow extensions to be able to add code to run inside the wlock.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1738,7 +1738,10 @@ class workingctx(committablectx):
 # it's in the dirstate.
 deleted.append(f)
 
-# update dirstate for files that are actually clean
+return modified, deleted, fixup
+
+def _poststatusfixup(self, fixup):
+"""update dirstate for files that are actually clean"""
 if fixup:
 try:
 oldid = self._repo.dirstate.identity()
@@ -1767,7 +1770,6 @@ class workingctx(committablectx):
 'identity mismatch\n')
 except error.LockError:
 pass
-return modified, deleted, fixup
 
 def _dirstatestatus(self, match=None, ignored=False, clean=False,
 unknown=False):
@@ -1781,15 +1783,17 @@ class workingctx(committablectx):
 listclean, listunknown)
 
 # check for any possibly clean files
+fixup = []
 if cmp:
 modified2, deleted2, fixup = self._checklookup(cmp)
 s.modified.extend(modified2)
 s.deleted.extend(deleted2)
 
-# update dirstate for files that are actually clean
 if fixup and listclean:
 s.clean.extend(fixup)
 
+self._poststatusfixup(fixup)
+
 if match.always():
 # cache for performance
 if s.unknown or s.ignored or s.clean:
diff --git a/tests/fakedirstatewritetime.py b/tests/fakedirstatewritetime.py
--- a/tests/fakedirstatewritetime.py
+++ b/tests/fakedirstatewritetime.py
@@ -2,7 +2,7 @@
 # specified by '[fakedirstatewritetime] fakenow', only when
 # 'dirstate.write()' is invoked via functions below:
 #
-#   - 'workingctx._checklookup()' (= 'repo.status()')
+#   - 'workingctx._poststatusfixup()' (= 'repo.status()')
 #   - 'committablectx.markcommitted()'
 
 from __future__ import absolute_import
@@ -55,16 +55,16 @@ def fakewrite(ui, func):
 parsers.pack_dirstate = orig_pack_dirstate
 dirstate._getfsnow = orig_dirstate_getfsnow
 
-def _checklookup(orig, workingctx, files):
+def _poststatusfixup(orig, workingctx, fixup):
 ui = workingctx.repo().ui
-return fakewrite(ui, lambda : orig(workingctx, files))
+return fakewrite(ui, lambda : orig(workingctx, fixup))
 
 def markcommitted(orig, committablectx, node):
 ui = committablectx.repo().ui
 return fakewrite(ui, lambda : orig(committablectx, node))
 
 def extsetup(ui):
-extensions.wrapfunction(context.workingctx, '_checklookup',
-_checklookup)
+extensions.wrapfunction(context.workingctx, '_poststatusfixup',
+_poststatusfixup)
 extensions.wrapfunction(context.committablectx, 'markcommitted',
 markcommitted)
diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -101,7 +101,7 @@ anyway.
 
 Test that dirstate changes aren't written out at the end of "hg
 status", if .hg/dirstate is already changed simultaneously before
-acquisition of wlock in workingctx._checklookup().
+acquisition of wlock in workingctx._poststatusfixup().
 
 This avoidance is important to keep consistency of dirstate in race
 condition (see issue5584 for detail).
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 5] fsmonitor: write state with wlock held and dirstate unchanged (issue5581)

2017-06-12 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1497306871 25200
#  Mon Jun 12 15:34:31 2017 -0700
# Node ID 1b02cda9518bbda5ad4a08bbad5b3c346dbe
# Parent  f4563ba01434aec8b238693721c246fc86a40732
fsmonitor: write state with wlock held and dirstate unchanged (issue5581)

This means that the state will not be written if:

(1) either the wlock can't be obtained
(2) something else came along and changed the dirstate while we were in the
middle of a status run.

diff --git a/hgext/fsmonitor/__init__.py b/hgext/fsmonitor/__init__.py
--- a/hgext/fsmonitor/__init__.py
+++ b/hgext/fsmonitor/__init__.py
@@ -485,17 +485,14 @@ def overridestatus(
 else:
 stateunknown = listunknown
 
+if updatestate:
+ps = poststatus(startclock)
+self.addpostdsstatus(ps)
+
 r = orig(node1, node2, match, listignored, listclean, stateunknown,
  listsubrepos)
 modified, added, removed, deleted, unknown, ignored, clean = r
 
-if updatestate:
-notefiles = modified + added + removed + deleted + unknown
-self._fsmonitorstate.set(
-self._fsmonitorstate.getlastclock() or startclock,
-_hashignore(self.dirstate._ignore),
-notefiles)
-
 if not listunknown:
 unknown = []
 
@@ -528,6 +525,17 @@ def overridestatus(
 return scmutil.status(
 modified, added, removed, deleted, unknown, ignored, clean)
 
+class poststatus(object):
+def __init__(self, startclock):
+self._startclock = startclock
+
+def __call__(self, wctx, status):
+clock = wctx.repo()._fsmonitorstate.getlastclock() or self._startclock
+hashignore = _hashignore(wctx.repo().dirstate._ignore)
+notefiles = (status.modified + status.added + status.removed +
+ status.deleted + status.unknown)
+wctx.repo()._fsmonitorstate.set(clock, hashignore, notefiles)
+
 def makedirstate(cls):
 class fsmonitordirstate(cls):
 def _fsmonitorinit(self, fsmonitorstate, watchmanclient):
diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -157,3 +157,50 @@ treated differently in _checklookup() ac
   a
   $ hg debugdirstate
   n * * * a (glob)
+
+  $ rm b
+
+Set up a rebase situation for issue5581.
+
+  $ echo c2 > a
+  $ echo c2 > b
+  $ hg add b
+  $ hg commit -m c2
+  created new head
+  $ echo c3 >> a
+  $ hg commit -m c3
+  $ hg update 2
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo c4 >> a
+  $ echo c4 >> b
+  $ hg commit -m c4
+  created new head
+
+Configure a merge tool that runs status in the middle of the rebase.
+
+  $ cat >> $TESTTMP/mergetool-race.sh << EOF
+  > echo "custom merge tool"
+  > printf "c2\nc3\nc4\n" > \$1
+  > hg --cwd $TESTTMP/repo status
+  > echo "custom merge tool end"
+  > EOF
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > rebase =
+  > [merge-tools]
+  > test.executable=sh
+  > test.args=$TESTTMP/mergetool-race.sh \$output
+  > EOF
+
+  $ hg rebase -s . -d 3 --tool test
+  rebasing 4:b08445fd6b2a "c4" (tip)
+  merging a
+  custom merge tool
+  M a
+  ? a.orig
+  custom merge tool end
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/* (glob)
+
+This hg status should be empty, whether or not fsmonitor is enabled 
(issue5581).
+
+  $ hg status
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 5] workingctx: also pass status tuple into poststatusfixup

2017-06-12 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1497301003 25200
#  Mon Jun 12 13:56:43 2017 -0700
# Node ID 3097d182d5b89ba643e834215dc41e7e34716857
# Parent  f9a3b5bd5c5a9e1fdf68f5b0af1675ecfbc7ae7a
workingctx: also pass status tuple into poststatusfixup

fsmonitor is going to need this to compute its set of notable files to persist.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1740,7 +1740,7 @@ class workingctx(committablectx):
 
 return modified, deleted, fixup
 
-def _poststatusfixup(self, fixup):
+def _poststatusfixup(self, status, fixup):
 """update dirstate for files that are actually clean"""
 if fixup:
 try:
@@ -1792,7 +1792,7 @@ class workingctx(committablectx):
 if fixup and listclean:
 s.clean.extend(fixup)
 
-self._poststatusfixup(fixup)
+self._poststatusfixup(s, fixup)
 
 if match.always():
 # cache for performance
diff --git a/tests/fakedirstatewritetime.py b/tests/fakedirstatewritetime.py
--- a/tests/fakedirstatewritetime.py
+++ b/tests/fakedirstatewritetime.py
@@ -55,9 +55,9 @@ def fakewrite(ui, func):
 parsers.pack_dirstate = orig_pack_dirstate
 dirstate._getfsnow = orig_dirstate_getfsnow
 
-def _poststatusfixup(orig, workingctx, fixup):
+def _poststatusfixup(orig, workingctx, status, fixup):
 ui = workingctx.repo().ui
-return fakewrite(ui, lambda : orig(workingctx, fixup))
+return fakewrite(ui, lambda : orig(workingctx, status, fixup))
 
 def markcommitted(orig, committablectx, node):
 ui = committablectx.repo().ui
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH] test-dirstate-race: back out changeset c82fa7efcbc8

2017-06-12 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1497298209 25200
#  Mon Jun 12 13:10:09 2017 -0700
# Node ID 0b9bca3118048ef1d52b27af156c98df8a0fa685
# Parent  6f775d10e83b928c99d5d6a7caa559c79fd925e1
test-dirstate-race: back out changeset c82fa7efcbc8

This is non-deterministic. In any case, I switched to using
debugrebuilddirstate in my WIP patches, which makes this moot.

diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -156,4 +156,4 @@ treated differently in _checklookup() ac
   $ hg files
   a
   $ hg debugdirstate
-  n 644  2 unset   a
+  n * * * a (glob)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 3 of 4] test-dirstate-race: ensure that a isn't in the lookup set at the end

2017-06-11 Thread Siddharth Agarwal

On 6/11/17 10:21 PM, Martin von Zweigbergk via Mercurial-devel wrote:

Doesn't look like it's guaranteed to be unset. Running "run-tests.py
-j50 --runs-per-test=50 test-dirstate-race.t" seems to confirm that (2
of 5 failed for me). How do you rely on it in an upcoming patch?



Interesting, I'm not seeing that on my Linux box. Could you drop this 
for now? I think I can work around this problem.


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


Re: [PATCH 1 of 4] tests: add a wrapper to run fsmonitor tests

2017-06-11 Thread Siddharth Agarwal

On 6/10/17 7:49 PM, Yuya Nishihara wrote:

Perhaps it's better to wait the process termination by proc.communicate()
or proc.wait().



Unfortunately, in this case we can't really communicate() to it since 
it'll keep running unless it is told to shutdown or terminated.


One interesting option would be to send a shutdown-server command over 
the domain socket.


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


[PATCH 1 of 4] tests: add a wrapper to run fsmonitor tests

2017-06-10 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1497128850 25200
#  Sat Jun 10 14:07:30 2017 -0700
# Node ID af12ded5040ae8b5becf5c354aafe19949d93444
# Parent  776d077eb4ef815e08631fb1e7b33375adca3ef1
tests: add a wrapper to run fsmonitor tests

This script does a bunch of non-trivial configuration work: in particular, it
sets up an isolated instance of Watchman which isn't affected by global state
and can be torn down on completion.

This script also sets the HGFSMONITOR_TESTS environment variable, which hghave
will use in the next patch to allow gating on whether fsmonitor is enabled.

With fsmonitor enabled, there appear to be a number of failures in the test
suite. It's not yet clear to me why they're happening, but if someone would
like to jump in and fix some of them I hope this will be helpful for that.

diff --git a/tests/blacklists/fsmonitor b/tests/blacklists/fsmonitor
--- a/tests/blacklists/fsmonitor
+++ b/tests/blacklists/fsmonitor
@@ -1,7 +1,5 @@
 # Blacklist for a full testsuite run with fsmonitor enabled.
-# Use with
-# run-tests --blacklist=blacklists/fsmonitor \
-# --extra-config="extensions.fsmonitor="
+# Used by fsmonitor-run-tests.
 # The following tests all fail because they either use extensions that conflict
 # with fsmonitor, use subrepositories, or don't anticipate the extra file in
 # the .hg directory that fsmonitor adds.
diff --git a/tests/fsmonitor-run-tests.py b/tests/fsmonitor-run-tests.py
new file mode 100755
--- /dev/null
+++ b/tests/fsmonitor-run-tests.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+
+# fsmonitor-run-tests.py - Run Mercurial tests with fsmonitor enabled
+#
+# Copyright 2017 Facebook, Inc.
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+#
+# This is a wrapper around run-tests.py that spins up an isolated instance of
+# Watchman and runs the Mercurial tests against it. This ensures that the 
global
+# version of Watchman isn't affected by anything this test does.
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+import argparse
+import contextlib
+import json
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import uuid
+
+osenvironb = getattr(os, 'environb', os.environ)
+
+if sys.version_info > (3, 5, 0):
+PYTHON3 = True
+xrange = range # we use xrange in one place, and we'd rather not use range
+def _bytespath(p):
+return p.encode('utf-8')
+
+elif sys.version_info >= (3, 0, 0):
+print('%s is only supported on Python 3.5+ and 2.7, not %s' %
+  (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3])))
+sys.exit(70) # EX_SOFTWARE from `man 3 sysexit`
+else:
+PYTHON3 = False
+
+# In python 2.x, path operations are generally done using
+# bytestrings by default, so we don't have to do any extra
+# fiddling there. We define the wrapper functions anyway just to
+# help keep code consistent between platforms.
+def _bytespath(p):
+return p
+
+def getparser():
+"""Obtain the argument parser used by the CLI."""
+parser = argparse.ArgumentParser(
+description='Run tests with fsmonitor enabled.',
+epilog='Unrecognized options are passed to run-tests.py.')
+# - keep these sorted
+# - none of these options should conflict with any in run-tests.py
+parser.add_argument('--keep-fsmonitor-tmpdir', action='store_true',
+help='keep temporary directory with fsmonitor state')
+parser.add_argument('--watchman',
+help='location of watchman binary (default: watchman in PATH)',
+default='watchman')
+
+return parser
+
+@contextlib.contextmanager
+def watchman(args):
+basedir = tempfile.mkdtemp(prefix='hg-fsmonitor')
+try:
+# Much of this configuration is borrowed from Watchman's test harness.
+cfgfile = os.path.join(basedir, 'config.json')
+# TODO: allow setting a config
+with open(cfgfile, 'w') as f:
+f.write(json.dumps({}))
+
+logfile = os.path.join(basedir, 'log')
+clilogfile = os.path.join(basedir, 'cli-log')
+if os.name == 'nt':
+sockfile = '.\\pipe\\watchman-test-%s' % uuid.uuid4().hex
+else:
+sockfile = os.path.join(basedir, 'sock')
+pidfile = os.path.join(basedir, 'pid')
+statefile = os.path.join(basedir, 'state')
+
+argv = [
+args.watchman,
+'--sockname', sockfile,
+'--logfile', logfile,
+'--pidfile', pidfile,
+'--statefile', statefile,
+'--foreground',
+'--log-level=2', # debug logging for watchman
+]
+
+envb = osenvironb.copy()
+envb[b'WATCHMAN_CONFIG_FILE'] = _bytespath(cfgfile)
+with open(clilogfile, 'wb') as f:
+proc = subprocess.Popen(
+

[PATCH 4 of 4] filestat: move __init__ to frompath constructor

2017-06-10 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1497128994 25200
#  Sat Jun 10 14:09:54 2017 -0700
# Node ID 8f558c7b7e5bd4e2a4aee5ba933da74e81b301bb
# Parent  212b4b3a41a4edf86cdea2057bfa1c4d3f8a923f
filestat: move __init__ to frompath constructor

We're going to add a `fromfp` constructor soon, and this also allows a filestat
object for a non-existent file to be created.

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -432,7 +432,8 @@ class dirstate(object):
 self._map = {}
 self._copymap = {}
 # ignore HG_PENDING because identity is used only for writing
-self._identity = util.filestat(self._opener.join(self._filename))
+self._identity = util.filestat.frompath(
+self._opener.join(self._filename))
 try:
 fp = self._opendirstatefile()
 try:
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -1098,7 +1098,7 @@ def copyfile(src, dest, hardlink=False, 
 oldstat = None
 if os.path.lexists(dest):
 if checkambig:
-oldstat = checkambig and filestat(dest)
+oldstat = checkambig and filestat.frompath(dest)
 unlink(dest)
 if hardlink:
 # Hardlinks are problematic on CIFS (issue4546), do not allow hardlinks
@@ -1128,7 +1128,7 @@ def copyfile(src, dest, hardlink=False, 
 else:
 shutil.copymode(src, dest)
 if oldstat and oldstat.stat:
-newstat = filestat(dest)
+newstat = filestat.frompath(dest)
 if newstat.isambig(oldstat):
 # stat of copied file is ambiguous to original one
 advanced = (oldstat.stat.st_mtime + 1) & 0x7fff
@@ -1506,13 +1506,18 @@ class filestat(object):
 exists. Otherwise, it is None. This can avoid preparative
 'exists()' examination on client side of this class.
 """
-def __init__(self, path):
+def __init__(self, stat):
+self.stat = stat
+
+@classmethod
+def frompath(cls, path):
 try:
-self.stat = os.stat(path)
+stat = os.stat(path)
 except OSError as err:
 if err.errno != errno.ENOENT:
 raise
-self.stat = None
+stat = None
+return cls(stat)
 
 __hash__ = object.__hash__
 
@@ -1622,10 +1627,10 @@ class atomictempfile(object):
 if not self._fp.closed:
 self._fp.close()
 filename = localpath(self.__name)
-oldstat = self._checkambig and filestat(filename)
+oldstat = self._checkambig and filestat.frompath(filename)
 if oldstat and oldstat.stat:
 rename(self._tempname, filename)
-newstat = filestat(filename)
+newstat = filestat.frompath(filename)
 if newstat.isambig(oldstat):
 # stat of changed file is ambiguous to original one
 advanced = (oldstat.stat.st_mtime + 1) & 0x7fff
diff --git a/mercurial/vfs.py b/mercurial/vfs.py
--- a/mercurial/vfs.py
+++ b/mercurial/vfs.py
@@ -176,11 +176,11 @@ class abstractvfs(object):
 """
 srcpath = self.join(src)
 dstpath = self.join(dst)
-oldstat = checkambig and util.filestat(dstpath)
+oldstat = checkambig and util.filestat.frompath(dstpath)
 if oldstat and oldstat.stat:
 def dorename(spath, dpath):
 ret = util.rename(spath, dpath)
-newstat = util.filestat(dpath)
+newstat = util.filestat.frompath(dpath)
 if newstat.isambig(oldstat):
 # stat of renamed file is ambiguous to original one
 return ret, newstat.avoidambig(dpath, oldstat)
@@ -625,12 +625,12 @@ class checkambigatclosing(closewrapbase)
 """
 def __init__(self, fh):
 super(checkambigatclosing, self).__init__(fh)
-object.__setattr__(self, r'_oldstat', util.filestat(fh.name))
+object.__setattr__(self, r'_oldstat', util.filestat.frompath(fh.name))
 
 def _checkambig(self):
 oldstat = self._oldstat
 if oldstat.stat:
-newstat = util.filestat(self._origfh.name)
+newstat = util.filestat.frompath(self._origfh.name)
 if newstat.isambig(oldstat):
 # stat of changed file is ambiguous to original one
 newstat.avoidambig(self._origfh.name, oldstat)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 4] hghave: add test for whether fsmonitor is enabled

2017-06-10 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1497128851 25200
#  Sat Jun 10 14:07:31 2017 -0700
# Node ID a69ae05fa66239c2aecb3673115de82105c8e9c6
# Parent  af12ded5040ae8b5becf5c354aafe19949d93444
hghave: add test for whether fsmonitor is enabled

This uses the HGFSMONITOR_TESTS environment variable that
fsmonitor-run-tests.py adds.

diff --git a/tests/hghave.py b/tests/hghave.py
--- a/tests/hghave.py
+++ b/tests/hghave.py
@@ -643,3 +643,7 @@ def has_virtualenv():
 return True
 except ImportError:
 return False
+
+@check("fsmonitor", "running tests with fsmonitor")
+def has_fsmonitor():
+return 'HGFSMONITOR_TESTS' in os.environ
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 4] test-dirstate-race: ensure that a isn't in the lookup set at the end

2017-06-10 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1497128851 25200
#  Sat Jun 10 14:07:31 2017 -0700
# Node ID 212b4b3a41a4edf86cdea2057bfa1c4d3f8a923f
# Parent  a69ae05fa66239c2aecb3673115de82105c8e9c6
test-dirstate-race: ensure that a isn't in the lookup set at the end

We're going to rely on this in upcoming patches.

diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -156,4 +156,4 @@ treated differently in _checklookup() ac
   $ hg files
   a
   $ hg debugdirstate
-  n * * * a (glob)
+  n 644  2 unset   a
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 5] run-tests: write JSON reports to output dir

2017-06-07 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496893603 25200
#  Wed Jun 07 20:46:43 2017 -0700
# Node ID 511ebc1769a9de229c5cca69ef3893bea1f2a63a
# Parent  47a479f6ee522ad1f1d4e72a8d32096000360dc2
run-tests: write JSON reports to output dir

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -1925,7 +1925,7 @@ class TextTestRunner(unittest.TextTestRu
 self._writexunit(result, xuf)
 
 if self._runner.options.json:
-jsonpath = os.path.join(self._runner._testdir, b'report.json')
+jsonpath = os.path.join(self._runner._outputdir, b'report.json')
 with open(jsonpath, 'w') as fp:
 self._writejson(result, fp)
 
@@ -1960,7 +1960,7 @@ class TextTestRunner(unittest.TextTestRu
 self._writexunit(result, xuf)
 
 if self._runner.options.json:
-jsonpath = os.path.join(self._runner._testdir, b'report.json')
+jsonpath = os.path.join(self._runner._outputdir, 
b'report.json')
 with open(jsonpath, 'w') as fp:
 self._writejson(result, fp)
 
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
--- a/tests/test-run-tests.t
+++ b/tests/test-run-tests.t
@@ -300,10 +300,10 @@ test --xunit support
 
   
 
-  $ rt --list-tests test-failure* --json --xunit=xunit.xml
+  $ rt --list-tests test-failure* --json --xunit=xunit.xml --outputdir output
   test-failure-unicode.t
   test-failure.t
-  $ cat report.json
+  $ cat output/report.json
   testreport ={
   "test-failure-unicode.t": {
   "result": "success"
@@ -836,6 +836,68 @@ test for --json
   "time": "\s*[\d\.]{4,5}" (re)
   }
   } (no-eol)
+--json with --outputdir
+
+  $ rm report.json
+  $ rm -r output
+  $ mkdir output
+  $ rt --json --outputdir output
+  
+  --- $TESTTMP/test-failure.t
+  +++ $TESTTMP/output/test-failure.t.err
+  @@ -1,5 +1,5 @@
+ $ echo babar
+  -  rataxes
+  +  babar
+   This is a noop statement so that
+   this test is still more bytes than success.
+   pad pad pad pad
+  
+  ERROR: test-failure.t output changed
+  !.s
+  Skipped test-skip.t: missing feature: nail clipper
+  Failed test-failure.t: output changed
+  # Ran 2 tests, 1 skipped, 0 warned, 1 failed.
+  python hash seed: 1138307315
+  [1]
+  $ f report.json
+  report.json: file not found
+  $ cat output/report.json
+  testreport ={
+  "test-failure.t": [\{] (re)
+  "csys": "\s*[\d\.]{4,5}", ? (re)
+  "cuser": "\s*[\d\.]{4,5}", ? (re)
+  "diff": "---.+\+\+\+.+", ? (re)
+  "end": "\s*[\d\.]{4,5}", ? (re)
+  "result": "failure", ? (re)
+  "start": "\s*[\d\.]{4,5}", ? (re)
+  "time": "\s*[\d\.]{4,5}" (re)
+  }, ? (re)
+  "test-skip.t": {
+  "csys": "\s*[\d\.]{4,5}", ? (re)
+  "cuser": "\s*[\d\.]{4,5}", ? (re)
+  "diff": "", ? (re)
+  "end": "\s*[\d\.]{4,5}", ? (re)
+  "result": "skip", ? (re)
+  "start": "\s*[\d\.]{4,5}", ? (re)
+  "time": "\s*[\d\.]{4,5}" (re)
+  }, ? (re)
+  "test-success.t": [\{] (re)
+  "csys": "\s*[\d\.]{4,5}", ? (re)
+  "cuser": "\s*[\d\.]{4,5}", ? (re)
+  "diff": "", ? (re)
+  "end": "\s*[\d\.]{4,5}", ? (re)
+  "result": "success", ? (re)
+  "start": "\s*[\d\.]{4,5}", ? (re)
+  "time": "\s*[\d\.]{4,5}" (re)
+  }
+  } (no-eol)
+  $ ls -a output
+  .
+  ..
+  .testtimes
+  report.json
+  test-failure.t.err
 
 Test that failed test accepted through interactive are properly reported:
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 5] run-tests: output coverage to output dir

2017-06-07 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496895426 25200
#  Wed Jun 07 21:17:06 2017 -0700
# Node ID 1403ca58e0bbd50a9a9287915073516db610b3c2
# Parent  511ebc1769a9de229c5cca69ef3893bea1f2a63a
run-tests: output coverage to output dir

There do not appear to be any tests for this, and I've never used either of
these options before, but this works.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -2756,10 +2756,10 @@ class TestRunner(object):
 cov.report(ignore_errors=True, omit=omit)
 
 if self.options.htmlcov:
-htmldir = os.path.join(self._testdir, 'htmlcov')
+htmldir = os.path.join(self._outputdir, 'htmlcov')
 cov.html_report(directory=htmldir, omit=omit)
 if self.options.annotate:
-adir = os.path.join(self._testdir, 'annotated')
+adir = os.path.join(self._outputdir, 'annotated')
 if not os.path.isdir(adir):
 os.mkdir(adir)
 cov.annotate(directory=adir, omit=omit)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 5] run-tests: write test times to output dir

2017-06-07 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496892731 25200
#  Wed Jun 07 20:32:11 2017 -0700
# Node ID 47a479f6ee522ad1f1d4e72a8d32096000360dc2
# Parent  90d5a9bc558130c69a8eaf58712f26d2530c49af
run-tests: write test times to output dir

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -1866,10 +1866,10 @@ class TestSuite(unittest.TestSuite):
 # alphabetically, while times for each test are listed from oldest to
 # newest.
 
-def loadtimes(testdir):
+def loadtimes(outputdir):
 times = []
 try:
-with open(os.path.join(testdir, b'.testtimes-')) as fp:
+with open(os.path.join(outputdir, b'.testtimes-')) as fp:
 for line in fp:
 ts = line.split()
 times.append((ts[0], [float(t) for t in ts[1:]]))
@@ -1878,8 +1878,8 @@ def loadtimes(testdir):
 raise
 return times
 
-def savetimes(testdir, result):
-saved = dict(loadtimes(testdir))
+def savetimes(outputdir, result):
+saved = dict(loadtimes(outputdir))
 maxruns = 5
 skipped = set([str(t[0]) for t in result.skipped])
 for tdata in result.times:
@@ -1890,11 +1890,11 @@ def savetimes(testdir, result):
 ts[:] = ts[-maxruns:]
 
 fd, tmpname = tempfile.mkstemp(prefix=b'.testtimes',
-   dir=testdir, text=True)
+   dir=outputdir, text=True)
 with os.fdopen(fd, 'w') as fp:
 for name, ts in sorted(saved.items()):
 fp.write('%s %s\n' % (name, ' '.join(['%.3f' % (t,) for t in ts])))
-timepath = os.path.join(testdir, b'.testtimes')
+timepath = os.path.join(outputdir, b'.testtimes')
 try:
 os.unlink(timepath)
 except OSError:
@@ -1966,7 +1966,7 @@ class TextTestRunner(unittest.TextTestRu
 
 self._runner._checkhglib('Tested')
 
-savetimes(self._runner._testdir, result)
+savetimes(self._runner._outputdir, result)
 
 if failed and self._runner.options.known_good_rev:
 def nooutput(args):
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
--- a/tests/test-run-tests.t
+++ b/tests/test-run-tests.t
@@ -199,6 +199,7 @@ test --outputdir
   $ ls -a output
   .
   ..
+  .testtimes
   test-failure-unicode.t.err
   test-failure.t.err
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 5] run-tests: allow specifying an output dir to write .errs to

2017-06-07 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496892608 25200
#  Wed Jun 07 20:30:08 2017 -0700
# Node ID 90d5a9bc558130c69a8eaf58712f26d2530c49af
# Parent  8fbb4ec8b06c1513fee3299696be8bdc3e505de1
run-tests: allow specifying an output dir to write .errs to

I'm trying to use run-tests.py on a read-only file system. This series allows
that to happen.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -274,6 +274,8 @@ def getparser():
 help="run each test N times (default=1)", default=1)
 parser.add_option("-n", "--nodiff", action="store_true",
 help="skip showing test changes")
+parser.add_option("--outputdir", type="string",
+help="directory to write error logs to (default=test directory)")
 parser.add_option("-p", "--port", type="int",
 help="port on which servers should listen"
  " (default: $%s or %d)" % defaults['port'])
@@ -564,7 +566,7 @@ class Test(unittest.TestCase):
 # Status code reserved for skipped tests (used by hghave).
 SKIPPED_STATUS = 80
 
-def __init__(self, path, tmpdir, keeptmpdir=False,
+def __init__(self, path, outputdir, tmpdir, keeptmpdir=False,
  debug=False,
  timeout=defaults['timeout'],
  startport=defaults['port'], extraconfigopts=None,
@@ -605,8 +607,9 @@ class Test(unittest.TestCase):
 self.bname = os.path.basename(path)
 self.name = _strpath(self.bname)
 self._testdir = os.path.dirname(path)
+self._outputdir = outputdir
 self._tmpname = os.path.basename(path)
-self.errpath = os.path.join(self._testdir, b'%s.err' % self.bname)
+self.errpath = os.path.join(self._outputdir, b'%s.err' % self.bname)
 
 self._threadtmp = tmpdir
 self._keeptmpdir = keeptmpdir
@@ -2135,6 +2138,7 @@ class TestRunner(object):
 self.options = None
 self._hgroot = None
 self._testdir = None
+self._outputdir = None
 self._hgtmp = None
 self._installdir = None
 self._bindir = None
@@ -2214,6 +2218,10 @@ class TestRunner(object):
 
 self._testdir = osenvironb[b'TESTDIR'] = getattr(
 os, 'getcwdb', os.getcwd)()
+if self.options.outputdir:
+self._outputdir = canonpath(_bytespath(self.options.outputdir))
+else:
+self._outputdir = self._testdir
 
 if 'PYTHONHASHSEED' not in os.environ:
 # use a random python hash seed all the time
@@ -2338,6 +2346,7 @@ class TestRunner(object):
 vlog("# Using HGTMP", self._hgtmp)
 vlog("# Using PATH", os.environ["PATH"])
 vlog("# Using", IMPL_PATH, osenvironb[IMPL_PATH])
+vlog("# Writing to directory", self._outputdir)
 
 try:
 return self._runtests(testdescs) or 0
@@ -2493,7 +2502,7 @@ class TestRunner(object):
 # extra keyword parameters. 'case' is used by .t tests
 kwds = dict((k, testdesc[k]) for k in ['case'] if k in testdesc)
 
-t = testcls(refpath, tmpdir,
+t = testcls(refpath, self._outputdir, tmpdir,
 keeptmpdir=self.options.keep_tmpdir,
 debug=self.options.debug,
 timeout=self.options.timeout,
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
--- a/tests/test-run-tests.t
+++ b/tests/test-run-tests.t
@@ -166,6 +166,42 @@ basic failing test
   python hash seed: * (glob)
   [1]
 
+test --outputdir
+  $ mkdir output
+  $ rt --outputdir output
+  
+  --- $TESTTMP/test-failure.t
+  +++ $TESTTMP/output/test-failure.t.err
+  @@ -1,5 +1,5 @@
+ $ echo babar
+  -  rataxes
+  +  babar
+   This is a noop statement so that
+   this test is still more bytes than success.
+   pad pad pad pad
+  
+  ERROR: test-failure.t output changed
+  !.
+  --- $TESTTMP/test-failure-unicode.t
+  +++ $TESTTMP/output/test-failure-unicode.t.err
+  @@ -1,2 +1,2 @@
+ $ echo babar\xce\xb1 (esc)
+  -  l\xce\xb5\xce\xb5t (esc)
+  +  babar\xce\xb1 (esc)
+  
+  ERROR: test-failure-unicode.t output changed
+  !
+  Failed test-failure.t: output changed
+  Failed test-failure-unicode.t: output changed
+  # Ran 3 tests, 0 skipped, 0 warned, 2 failed.
+  python hash seed: * (glob)
+  [1]
+  $ ls -a output
+  .
+  ..
+  test-failure-unicode.t.err
+  test-failure.t.err
+
 test --xunit support
   $ rt --xunit=xunit.xml
   
@@ -306,6 +342,29 @@ test for --retest
   python hash seed: * (glob)
   [1]
 
+--retest works with --outputdir
+  $ rm -r output
+  $ mkdir output
+  $ mv test-failure.t.err output
+  $ rt --retest --outputdir output
+  
+  --- $TESTTMP/test-failure.t
+  +++ $TESTTMP/output/t

[PATCH 5 of 5] run-tests: make --restart work with output dir

2017-06-07 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496895444 25200
#  Wed Jun 07 21:17:24 2017 -0700
# Node ID 7157ecbb2426689cd8f1133bf7dde2822d68b6a8
# Parent  1403ca58e0bbd50a9a9287915073516db610b3c2
run-tests: make --restart work with output dir

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -2399,10 +2399,12 @@ class TestRunner(object):
 orig = list(testdescs)
 while testdescs:
 desc = testdescs[0]
+# desc['path'] is a relative path
 if 'case' in desc:
 errpath = b'%s.%s.err' % (desc['path'], desc['case'])
 else:
 errpath = b'%s.err' % desc['path']
+errpath = os.path.join(self._outputdir, errpath)
 if os.path.exists(errpath):
 break
 testdescs.pop(0)
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
--- a/tests/test-run-tests.t
+++ b/tests/test-run-tests.t
@@ -858,7 +858,7 @@ test for --json
   Skipped test-skip.t: missing feature: nail clipper
   Failed test-failure.t: output changed
   # Ran 2 tests, 1 skipped, 0 warned, 1 failed.
-  python hash seed: 1138307315
+  python hash seed: * (glob)
   [1]
   $ f report.json
   report.json: file not found
@@ -1183,3 +1183,28 @@ Test cases in .t files
   # Ran 2 tests, 0 skipped, 0 warned, 1 failed.
   python hash seed: * (glob)
   [1]
+
+--restart works with outputdir
+
+  $ mkdir output
+  $ mv test-cases-abc.t.B.err output
+  $ rt --restart --outputdir output
+  
+  --- $TESTTMP/anothertests/cases/test-cases-abc.t
+  +++ $TESTTMP/anothertests/cases/output/test-cases-abc.t.B.err
+  @@ -7,7 +7,7 @@
+ $ V=C
+   #endif
+ $ echo $V | sed 's/A/C/'
+  -  C
+  +  B
+   #if C
+ $ [ $V = C ]
+   #endif
+  
+  ERROR: test-cases-abc.t (case B) output changed
+  !.
+  Failed test-cases-abc.t (case B): output changed
+  # Ran 2 tests, 0 skipped, 0 warned, 1 failed.
+  python hash seed: * (glob)
+  [1]
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 2] run-tests: add information about skipped tests to XUnit output

2017-06-07 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496875626 25200
#  Wed Jun 07 15:47:06 2017 -0700
# Node ID 8e05986478080f8eefd5f645166020d7802175e8
# Parent  0bdfd2f0e15b0d4a20ea4d288e0b4e04f37f25b4
run-tests: add information about skipped tests to XUnit output

The XUnit spec supports skipped tests.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -2061,6 +2061,17 @@ class TextTestRunner(unittest.TextTestRu
 failelem.appendChild(cd)
 t.appendChild(failelem)
 s.appendChild(t)
+for tc, message in result.skipped:
+# According to the schema, 'skipped' has no attributes. So store
+# the skip message as a text node instead.
+t = doc.createElement('testcase')
+t.setAttribute('name', tc.name)
+message = cdatasafe(message).decode('utf-8', 'replace')
+cd = doc.createCDATASection(message)
+skipelem = doc.createElement('skipped')
+skipelem.appendChild(cd)
+t.appendChild(skipelem)
+s.appendChild(t)
 outf.write(doc.toprettyxml(indent='  ', encoding='utf-8'))
 
 @staticmethod
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
--- a/tests/test-run-tests.t
+++ b/tests/test-run-tests.t
@@ -676,6 +676,10 @@ Skips with xml
   
   
  (glob)
+
+  
+  
+
   
 
 Missing skips or blacklisted skips don't count as executed:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 2] run-tests: wrap failures in an XUnit 'failure' element

2017-06-07 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496875626 25200
#  Wed Jun 07 15:47:06 2017 -0700
# Node ID 0bdfd2f0e15b0d4a20ea4d288e0b4e04f37f25b4
# Parent  3210ffcae3d0b2c2a34b0485f7e20c4057ba6953
run-tests: wrap failures in an XUnit 'failure' element

This is closer to what most XUnit consumers can understand.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -2024,6 +2024,7 @@ class TextTestRunner(unittest.TextTestRu
 
 @staticmethod
 def _writexunit(result, outf):
+# See http://llg.cubic.org/docs/junit/ for a reference.
 timesd = dict((t[0], t[3]) for t in result.times)
 doc = minidom.Document()
 s = doc.createElement('testsuite')
@@ -2052,7 +2053,13 @@ class TextTestRunner(unittest.TextTestRu
 # fail if string isn't ASCII.
 err = cdatasafe(err).decode('utf-8', 'replace')
 cd = doc.createCDATASection(err)
-t.appendChild(cd)
+# Use 'failure' here instead of 'error' to match errors = 0,
+# failures = len(result.failures) in the testsuite element.
+failelem = doc.createElement('failure')
+failelem.setAttribute('message', 'output changed')
+failelem.setAttribute('type', 'output-mismatch')
+failelem.appendChild(cd)
+t.appendChild(failelem)
 s.appendChild(t)
 outf.write(doc.toprettyxml(indent='  ', encoding='utf-8'))
 
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
--- a/tests/test-run-tests.t
+++ b/tests/test-run-tests.t
@@ -200,14 +200,17 @@ test --xunit support
   
  (glob)
  (glob)
+  
 
+  ]]>
+
  (glob)
+  
 
+  ]]>
+
   
 
   $ cat .testtimes
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 5] run-tests: make time field optional for xunit report

2017-06-06 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496782345 25200
#  Tue Jun 06 13:52:25 2017 -0700
# Node ID cd0fe3fedddab358d47d6f34d5c1e596298199bb
# Parent  737bb0771ca0bff0673f861c068018c8f606cf7d
run-tests: make time field optional for xunit report

We're going to use XUnit to list tests, and we don't have a time field in that
case.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -2016,12 +2016,16 @@ class TextTestRunner(unittest.TextTestRu
 for tc in result.successes:
 t = doc.createElement('testcase')
 t.setAttribute('name', tc.name)
-t.setAttribute('time', '%.3f' % timesd[tc.name])
+tctime = timesd.get(tc.name)
+if tctime is not None:
+t.setAttribute('time', '%.3f' % tctime)
 s.appendChild(t)
 for tc, err in sorted(result.faildata.items()):
 t = doc.createElement('testcase')
 t.setAttribute('name', tc)
-t.setAttribute('time', '%.3f' % timesd[tc])
+tctime = timesd.get(tc)
+if tctime is not None:
+t.setAttribute('time', '%.3f' % tctime)
 # createCDATASection expects a unicode or it will
 # convert using default conversion rules, which will
 # fail if string isn't ASCII.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 5 of 5] run-tests: add a way to list tests, with JSON and XUnit support

2017-06-06 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496785139 25200
#  Tue Jun 06 14:38:59 2017 -0700
# Node ID 5e521dfd40ae206de2f050bd5915f0f52429f971
# Parent  29aaeed22502929559e1e85d8fb0c1ed6433ecba
run-tests: add a way to list tests, with JSON and XUnit support

Some test runners are interested in listing tests, so they can do their own
filtering on top (usually based on attributes like historically observed
runtime). Add support for that.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -263,6 +263,8 @@ def getparser():
 help="keep temporary directory after running tests")
 parser.add_option("-k", "--keywords",
 help="run tests matching keywords")
+parser.add_option("--list-tests", action="store_true",
+help="list tests instead of running them")
 parser.add_option("-l", "--local", action="store_true",
 help="shortcut for --with-hg=/../hg, "
  "and --with-chg=/../contrib/chg/chg if --chg is set")
@@ -1907,6 +1909,25 @@ class TextTestRunner(unittest.TextTestRu
 
 self._runner = runner
 
+def listtests(self, test):
+result = TestResult(self._runner.options, self.stream,
+self.descriptions, 0)
+test = sorted(test, key=lambda t: t.name)
+for t in test:
+print(t.name)
+result.addSuccess(t)
+
+if self._runner.options.xunit:
+with open(self._runner.options.xunit, "wb") as xuf:
+self._writexunit(result, xuf)
+
+if self._runner.options.json:
+jsonpath = os.path.join(self._runner._testdir, b'report.json')
+with open(jsonpath, 'w') as fp:
+self._writejson(result, fp)
+
+return result
+
 def run(self, test):
 result = TestResult(self._runner.options, self.stream,
 self.descriptions, self.verbosity)
@@ -2385,16 +2406,19 @@ class TestRunner(object):
 verbosity = 2
 runner = TextTestRunner(self, verbosity=verbosity)
 
-if self._installdir:
-self._installhg()
-self._checkhglib("Testing")
+if self.options.list_tests:
+result = runner.listtests(suite)
 else:
-self._usecorrectpython()
-if self.options.chg:
-assert self._installdir
-self._installchg()
+if self._installdir:
+self._installhg()
+self._checkhglib("Testing")
+else:
+self._usecorrectpython()
+if self.options.chg:
+assert self._installdir
+self._installchg()
 
-result = runner.run(suite)
+result = runner.run(suite)
 
 if result.failures:
 failed = True
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
--- a/tests/test-run-tests.t
+++ b/tests/test-run-tests.t
@@ -224,6 +224,60 @@ test --xunit support
   test-failure-unicode.t * (glob)
   test-failure.t * (glob)
   test-success.t * (glob)
+
+  $ rt --list-tests
+  test-failure-unicode.t
+  test-failure.t
+  test-success.t
+
+  $ rt --list-tests --json
+  test-failure-unicode.t
+  test-failure.t
+  test-success.t
+  $ cat report.json
+  testreport ={
+  "test-failure-unicode.t": {
+  "result": "success"
+  },
+  "test-failure.t": {
+  "result": "success"
+  },
+  "test-success.t": {
+  "result": "success"
+  }
+  } (no-eol)
+
+  $ rt --list-tests --xunit=xunit.xml
+  test-failure-unicode.t
+  test-failure.t
+  test-success.t
+  $ cat xunit.xml
+  
+  
+
+
+
+  
+
+  $ rt --list-tests test-failure* --json --xunit=xunit.xml
+  test-failure-unicode.t
+  test-failure.t
+  $ cat report.json
+  testreport ={
+  "test-failure-unicode.t": {
+  "result": "success"
+  },
+  "test-failure.t": {
+  "result": "success"
+  }
+  } (no-eol)
+  $ cat xunit.xml
+  
+  
+
+
+  
+
   $ rm test-failure-unicode.t
 
 test for --retest
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 5] run-tests: install hg after computing tests to run

2017-06-06 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496782613 25200
#  Tue Jun 06 13:56:53 2017 -0700
# Node ID 29aaeed22502929559e1e85d8fb0c1ed6433ecba
# Parent  cd0fe3fedddab358d47d6f34d5c1e596298199bb
run-tests: install hg after computing tests to run

We're going to add a way to list tests, and we don't need to install hg for
that.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -2347,15 +2347,6 @@ class TestRunner(object):
 return self._gettest(desc, i)
 
 try:
-if self._installdir:
-self._installhg()
-self._checkhglib("Testing")
-else:
-self._usecorrectpython()
-if self.options.chg:
-assert self._installdir
-self._installchg()
-
 if self.options.restart:
 orig = list(testdescs)
 while testdescs:
@@ -2393,6 +2384,16 @@ class TestRunner(object):
 if self.options.verbose:
 verbosity = 2
 runner = TextTestRunner(self, verbosity=verbosity)
+
+if self._installdir:
+self._installhg()
+self._checkhglib("Testing")
+else:
+self._usecorrectpython()
+if self.options.chg:
+assert self._installdir
+self._installchg()
+
 result = runner.run(suite)
 
 if result.failures:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 5] run-tests: factor out json write code into another method

2017-06-06 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496779855 25200
#  Tue Jun 06 13:10:55 2017 -0700
# Node ID 737bb0771ca0bff0673f861c068018c8f606cf7d
# Parent  2d78617dd0b04d927beff7bc8bb2a1329b92ed8e
run-tests: factor out json write code into another method

We're going to use this code to output a JSON-formatted listing of tests.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -1938,36 +1938,7 @@ class TextTestRunner(unittest.TextTestRu
 if self._runner.options.json:
 jsonpath = os.path.join(self._runner._testdir, b'report.json')
 with open(jsonpath, 'w') as fp:
-timesd = {}
-for tdata in result.times:
-test = tdata[0]
-timesd[test] = tdata[1:]
-
-outcome = {}
-groups = [('success', ((tc, None)
-   for tc in result.successes)),
-  ('failure', result.failures),
-  ('skip', result.skipped)]
-for res, testcases in groups:
-for tc, __ in testcases:
-if tc.name in timesd:
-diff = result.faildata.get(tc.name, b'')
-tres = {'result': res,
-'time': ('%0.3f' % timesd[tc.name][2]),
-'cuser': ('%0.3f' % 
timesd[tc.name][0]),
-'csys': ('%0.3f' % timesd[tc.name][1]),
-'start': ('%0.3f' % 
timesd[tc.name][3]),
-'end': ('%0.3f' % timesd[tc.name][4]),
-'diff': diff.decode('unicode_escape'),
-}
-else:
-# blacklisted test
-tres = {'result': res}
-
-outcome[tc.name] = tres
-jsonout = json.dumps(outcome, sort_keys=True, indent=4,
- separators=(',', ': '))
-fp.writelines(("testreport =", jsonout))
+self._writejson(result, fp)
 
 self._runner._checkhglib('Tested')
 
@@ -2060,6 +2031,40 @@ class TextTestRunner(unittest.TextTestRu
 s.appendChild(t)
 outf.write(doc.toprettyxml(indent='  ', encoding='utf-8'))
 
+@staticmethod
+def _writejson(result, outf):
+timesd = {}
+for tdata in result.times:
+test = tdata[0]
+timesd[test] = tdata[1:]
+
+outcome = {}
+groups = [('success', ((tc, None)
+   for tc in result.successes)),
+  ('failure', result.failures),
+  ('skip', result.skipped)]
+for res, testcases in groups:
+for tc, __ in testcases:
+if tc.name in timesd:
+diff = result.faildata.get(tc.name, b'')
+tres = {'result': res,
+'time': ('%0.3f' % timesd[tc.name][2]),
+'cuser': ('%0.3f' % timesd[tc.name][0]),
+'csys': ('%0.3f' % timesd[tc.name][1]),
+'start': ('%0.3f' % timesd[tc.name][3]),
+'end': ('%0.3f' % timesd[tc.name][4]),
+'diff': diff.decode('unicode_escape'),
+}
+else:
+# blacklisted test
+tres = {'result': res}
+
+outcome[tc.name] = tres
+jsonout = json.dumps(outcome, sort_keys=True, indent=4,
+ separators=(',', ': '))
+outf.writelines(("testreport =", jsonout))
+
+
 class TestRunner(object):
 """Holds context for executing tests.
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 5] run-tests: factor out xunit write code into another method

2017-06-06 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496779855 25200
#  Tue Jun 06 13:10:55 2017 -0700
# Node ID 2d78617dd0b04d927beff7bc8bb2a1329b92ed8e
# Parent  e696f597d02f971eeed1217096b8f200ddb903d2
run-tests: factor out xunit write code into another method

We're going to use this code to output an XUnit-formatted listing of tests.

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -1932,33 +1932,8 @@ class TextTestRunner(unittest.TextTestRu
 self.stream.writeln('Errored %s: %s' % (test.name, msg))
 
 if self._runner.options.xunit:
-with open(self._runner.options.xunit, 'wb') as xuf:
-timesd = dict((t[0], t[3]) for t in result.times)
-doc = minidom.Document()
-s = doc.createElement('testsuite')
-s.setAttribute('name', 'run-tests')
-s.setAttribute('tests', str(result.testsRun))
-s.setAttribute('errors', "0") # TODO
-s.setAttribute('failures', str(failed))
-s.setAttribute('skipped', str(skipped + ignored))
-doc.appendChild(s)
-for tc in result.successes:
-t = doc.createElement('testcase')
-t.setAttribute('name', tc.name)
-t.setAttribute('time', '%.3f' % timesd[tc.name])
-s.appendChild(t)
-for tc, err in sorted(result.faildata.items()):
-t = doc.createElement('testcase')
-t.setAttribute('name', tc)
-t.setAttribute('time', '%.3f' % timesd[tc])
-# createCDATASection expects a unicode or it will
-# convert using default conversion rules, which will
-# fail if string isn't ASCII.
-err = cdatasafe(err).decode('utf-8', 'replace')
-cd = doc.createCDATASection(err)
-t.appendChild(cd)
-s.appendChild(t)
-xuf.write(doc.toprettyxml(indent='  ', encoding='utf-8'))
+with open(self._runner.options.xunit, "wb") as xuf:
+self._writexunit(result, xuf)
 
 if self._runner.options.json:
 jsonpath = os.path.join(self._runner._testdir, b'report.json')
@@ -2055,6 +2030,36 @@ class TextTestRunner(unittest.TextTestRu
 cuser, csys, real, start, end = tdata[1:6]
 self.stream.writeln(cols % (start, end, cuser, csys, real, test))
 
+@staticmethod
+def _writexunit(result, outf):
+timesd = dict((t[0], t[3]) for t in result.times)
+doc = minidom.Document()
+s = doc.createElement('testsuite')
+s.setAttribute('name', 'run-tests')
+s.setAttribute('tests', str(result.testsRun))
+s.setAttribute('errors', "0") # TODO
+s.setAttribute('failures', str(len(result.failures)))
+s.setAttribute('skipped', str(len(result.skipped) +
+  len(result.ignored)))
+doc.appendChild(s)
+for tc in result.successes:
+t = doc.createElement('testcase')
+t.setAttribute('name', tc.name)
+t.setAttribute('time', '%.3f' % timesd[tc.name])
+s.appendChild(t)
+for tc, err in sorted(result.faildata.items()):
+t = doc.createElement('testcase')
+t.setAttribute('name', tc)
+t.setAttribute('time', '%.3f' % timesd[tc])
+# createCDATASection expects a unicode or it will
+# convert using default conversion rules, which will
+# fail if string isn't ASCII.
+err = cdatasafe(err).decode('utf-8', 'replace')
+cd = doc.createCDATASection(err)
+t.appendChild(cd)
+s.appendChild(t)
+outf.write(doc.toprettyxml(indent='  ', encoding='utf-8'))
+
 class TestRunner(object):
 """Holds context for executing tests.
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: users repositories?

2017-06-04 Thread Siddharth Agarwal

On 6/4/17 4:19 PM, Pierre-Yves David wrote:



On 06/05/2017 12:10 AM, Siddharth Agarwal wrote:

On 6/4/17 4:07 PM, Pierre-Yves David wrote:

About access: This is the users repository that was on David Soria
Para machine hosting the clowncopter. Using the same credential should
work, I think we ported the configuration as is.


What path do I need to specify to push to it?

I tried:

ssh://h...@mercurial-scm.org/repo/users/sid0/hg

but that just hangs.


the path seems correct. did you tried sshing to the machine?


Thanks. With some spelunking I found that the following works:

ssh://s...@mercurial-scm.org//home/hg/repo/users/sid0/hg

- Siddharth



What kind of hanging do you get? what does --debug says?

Cheers,



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


Re: users repositories?

2017-06-04 Thread Siddharth Agarwal

On 6/4/17 4:07 PM, Pierre-Yves David wrote:
About access: This is the users repository that was on David Soria 
Para machine hosting the clowncopter. Using the same credential should 
work, I think we ported the configuration as is.


What path do I need to specify to push to it?

I tried:

ssh://h...@mercurial-scm.org/repo/users/sid0/hg

but that just hangs.




On 06/05/2017 12:05 AM, Siddharth Agarwal wrote:

Apparently there's some space on mercurial-scm.org for user
repositories, e.g. https://www.mercurial-scm.org/repo/users/sid0/hg.

1. Could this be documented somewhere? I searched on the wiki for user
repositories and didn't see anything.
2. What credentials do I need to get access to it?

Thanks,
Siddharth

___
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] dirstate: add docstring for invalidate

2017-06-04 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496617730 25200
#  Sun Jun 04 16:08:50 2017 -0700
# Node ID 45841cedb603b93803eec37bd7d01456a6b8e812
# Parent  5277d6faabb4f9593a5d33cdab6c4a6191ad856d
dirstate: add docstring for invalidate

This always confuses me, and we already have a docstring on
localrepo.invalidatedirstate.

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -470,6 +470,12 @@ class dirstate(object):
 self._pl = p
 
 def invalidate(self):
+'''Causes the next access to reread the dirstate.
+
+This is different from localrepo.invalidatedirstate() because it always
+rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
+check whether the dirstate has changed before rereading it.'''
+
 for a in ("_map", "_copymap", "_filefoldmap", "_dirfoldmap", "_branch",
   "_pl", "_dirs", "_ignore", "_nonnormalset",
   "_otherparentset"):
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


users repositories?

2017-06-04 Thread Siddharth Agarwal
Apparently there's some space on mercurial-scm.org for user 
repositories, e.g. https://www.mercurial-scm.org/repo/users/sid0/hg.


1. Could this be documented somewhere? I searched on the wiki for user 
repositories and didn't see anything.

2. What credentials do I need to get access to it?

Thanks,
Siddharth

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


Re: [PATCH STABLE] status: don't crash if a lookup file disappears

2017-06-03 Thread Siddharth Agarwal

On 6/3/17 7:26 AM, Yuya Nishihara wrote:

On Fri, 2 Jun 2017 22:28:07 -0700, Siddharth Agarwal wrote:

# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496467672 25200
#  Fri Jun 02 22:27:52 2017 -0700
# Branch stable
# Node ID d39f934da0c80a568486cd8645eb6bbe513f1f03
# Parent  62e42e2897502bcbaa3a57d3301c789309596391
status: don't crash if a lookup file disappears

Looks good to me. A few nits.


diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1613,18 +1613,30 @@ class workingctx(committablectx):
  def _checklookup(self, files):
  # check for any possibly clean files
  if not files:
-return [], []
+return [], [], []
  
  modified = []

+deleted = []
  fixup = []
  pctx = self._parents[0]
  # do a full compare of any files that might have changed
  for f in sorted(files):
-if (f not in pctx or self.flags(f) != pctx.flags(f)
-or pctx[f].cmp(self[f])):
-modified.append(f)
-else:
-fixup.append(f)
+try:
+# This will return True for a file that got replaced by a
+# directory in the interim, but fixing that is pretty hard.
+if (f not in pctx or self.flags(f) != pctx.flags(f)
+or pctx[f].cmp(self[f])):

If cmp() falls back to fctx.data() path, maybe IOError could be raised.


That sounds like a good idea. (Sorry, I've been writing some Python 3 
where OSError and IOError are the same.)





+modified.append(f)
+else:
+fixup.append(f)
+except OSError:

Can we check errno strictly? Perhaps ENOENT and EISDIR should be caught.


The dirstate doesn't check errno strictly, and I think both the dirstate 
and this should do the same thing.



___
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 STABLE] status: don't crash if a lookup file disappears

2017-06-02 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496467672 25200
#  Fri Jun 02 22:27:52 2017 -0700
# Branch stable
# Node ID d39f934da0c80a568486cd8645eb6bbe513f1f03
# Parent  62e42e2897502bcbaa3a57d3301c789309596391
status: don't crash if a lookup file disappears

This can happen if another process (even another hg process!) comes along and
removes the file at that time.

This partly resolves issue5584, but not completely -- a bogus dirstate update
can still happen. However, the full fix is too involved for stable.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1613,18 +1613,30 @@ class workingctx(committablectx):
 def _checklookup(self, files):
 # check for any possibly clean files
 if not files:
-return [], []
+return [], [], []
 
 modified = []
+deleted = []
 fixup = []
 pctx = self._parents[0]
 # do a full compare of any files that might have changed
 for f in sorted(files):
-if (f not in pctx or self.flags(f) != pctx.flags(f)
-or pctx[f].cmp(self[f])):
-modified.append(f)
-else:
-fixup.append(f)
+try:
+# This will return True for a file that got replaced by a
+# directory in the interim, but fixing that is pretty hard.
+if (f not in pctx or self.flags(f) != pctx.flags(f)
+or pctx[f].cmp(self[f])):
+modified.append(f)
+else:
+fixup.append(f)
+except OSError:
+# A file become inaccessible in between? Mark it as deleted,
+# matching dirstate behavior (issue5584).
+# The dirstate has more complex behavior around whether a
+# missing file matches a directory, etc, but we don't need to
+# bother with that: if f has made it to this point, we're sure
+# it's in the dirstate.
+deleted.append(f)
 
 # update dirstate for files that are actually clean
 if fixup:
@@ -1644,7 +1656,7 @@ class workingctx(committablectx):
 self._repo.dirstate.write(self._repo.currenttransaction())
 except error.LockError:
 pass
-return modified, fixup
+return modified, deleted, fixup
 
 def _dirstatestatus(self, match=None, ignored=False, clean=False,
 unknown=False):
@@ -1659,8 +1671,9 @@ class workingctx(committablectx):
 
 # check for any possibly clean files
 if cmp:
-modified2, fixup = self._checklookup(cmp)
+modified2, deleted2, fixup = self._checklookup(cmp)
 s.modified.extend(modified2)
+s.deleted.extend(deleted2)
 
 # update dirstate for files that are actually clean
 if fixup and listclean:
diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -1,4 +1,5 @@
-  $ hg init
+  $ hg init repo
+  $ cd repo
   $ echo a > a
   $ hg add a
   $ hg commit -m test
@@ -31,3 +32,62 @@ Do we ever miss a sub-second change?:
   M a
   M a
 
+  $ echo test > b
+  $ mkdir dir1
+  $ echo test > dir1/c
+  $ echo test > d
+
+  $ echo test > e
+#if execbit
+A directory will typically have the execute bit -- make sure it doesn't get
+confused with a file with the exec bit set
+  $ chmod +x e
+#endif
+
+  $ hg add b dir1 d e
+  adding dir1/c
+  $ hg commit -m test2
+
+  $ cat >> $TESTTMP/dirstaterace.py << EOF
+  > from mercurial import (
+  > context,
+  > extensions,
+  > )
+  > def extsetup():
+  > extensions.wrapfunction(context.workingctx, '_checklookup', 
overridechecklookup)
+  > def overridechecklookup(orig, self, files):
+  > # make an update that changes the dirstate from underneath
+  > self._repo.ui.system(self._repo.ui.config('dirstaterace', 'command'), 
cwd=self._repo.root)
+  > return orig(self, files)
+  > EOF
+
+  $ hg debugrebuilddirstate
+  $ hg debugdirstate
+  n   0 -1 unset   a
+  n   0 -1 unset   b
+  n   0 -1 unset   d
+  n   0 -1 unset   dir1/c
+  n   0 -1 unset   e
+
+XXX Note that this returns M for files that got replaced by directories. This 
is
+definitely a bug, but the fix for that is hard and the next status run is fine
+anyway.
+
+  $ hg status --config extensions.dirstaterace=$TESTTMP/dirstaterace.py \
+  >   --config dirstaterace.command='rm b && rm -r dir1 && rm d && mkdir d && 
rm e && mkdir e'
+  M d
+  M e
+  ! b
+  ! dir1/c
+  $ hg debugdirstate
+  n 644  2 * a (glob)
+  n   0 -1 u

[PATCH] match: introduce nevermatcher for when no ignore files are present

2017-06-01 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496302852 25200
#  Thu Jun 01 00:40:52 2017 -0700
# Node ID 14f332c8fe10c498e7c35bef09e53b8b6c7e5f43
# Parent  dbf330cadc5a3c0707c4611f2f4150be13cac02a
match: introduce nevermatcher for when no ignore files are present

952017471f93 introduced a deterministic `__repr__` for ignores. However, it
didn't account for when ignore was `util.never`. This broke fsmonitor's ignore
change detection -- with an empty hgignore, it would kick in all the time.

Introduce `nevermatcher` and switch to it. This neatly parallels
`alwaysmatcher`.

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -232,7 +232,7 @@ class dirstate(object):
 def _ignore(self):
 files = self._ignorefiles()
 if not files:
-return util.never
+return matchmod.never(self._root, '')
 
 pats = ['include:%s' % f for f in files]
 return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
diff --git a/mercurial/match.py b/mercurial/match.py
--- a/mercurial/match.py
+++ b/mercurial/match.py
@@ -175,6 +175,9 @@ def exact(root, cwd, files, badfn=None):
 def always(root, cwd):
 return alwaysmatcher(root, cwd)
 
+def never(root, cwd):
+return nevermatcher(root, cwd)
+
 def badmatch(match, badfn):
 """Make a copy of the given matcher, replacing its bad method with the 
given
 one.
@@ -339,6 +342,25 @@ class alwaysmatcher(basematcher):
 def __repr__(self):
 return ''
 
+class nevermatcher(basematcher):
+'''Matches nothing.'''
+
+def __init__(self, root, cwd, badfn=None, relativeuipath=False):
+super(nevermatcher, self).__init__(root, cwd, badfn,
+   relativeuipath=relativeuipath)
+
+def always(self):
+return False
+
+def matchfn(self, f):
+return False
+
+def visitdir(self, dir):
+return False
+
+def __repr__(self):
+return ''
+
 class patternmatcher(basematcher):
 
 def __init__(self, root, cwd, kindpats, ctx=None, listsubrepos=False,
diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
--- a/tests/test-hgignore.t
+++ b/tests/test-hgignore.t
@@ -1,6 +1,10 @@
   $ hg init ignorerepo
   $ cd ignorerepo
 
+debugignore with no hgignore should be deterministic:
+  $ hg debugignore
+  
+
 Issue562: .hgignore requires newline at end:
 
   $ touch foo
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH] rebase: drop unnecessary parentchange call

2017-05-31 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496285164 25200
#  Wed May 31 19:46:04 2017 -0700
# Node ID bd3d33c6014f4553c799c0d3236e17b28ffc85e3
# Parent  dc0da9829c2972e1c97e07428d6885c1cd4b8f1f
rebase: drop unnecessary parentchange call

We're calling localrepo.setparents here, not dirstate.setparents.
localrepo.setparents calls dirstate.parentchange already.

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -427,8 +427,7 @@ class rebaseruntime(object):
 mergemod.mergestate.clean(repo)
 else:
 # Skip commit if we are collapsing
-with repo.dirstate.parentchange():
-repo.setparents(repo[p1].node())
+repo.setparents(repo[p1].node())
 newnode = None
 # Update the state
 if newnode is not None:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH] import-checker: add hgdemandimport to local modules

2017-05-31 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1496286428 25200
#  Wed May 31 20:07:08 2017 -0700
# Node ID 884f32a63e57d5d7ff3fce3d5b6b99c84df8309d
# Parent  bd3d33c6014f4553c799c0d3236e17b28ffc85e3
import-checker: add hgdemandimport to local modules

This fixes test-check-module-imports.t.

diff --git a/contrib/import-checker.py b/contrib/import-checker.py
--- a/contrib/import-checker.py
+++ b/contrib/import-checker.py
@@ -244,7 +244,8 @@ def list_stdlib_modules():
 for top, dirs, files in os.walk(libpath):
 for i, d in reversed(list(enumerate(dirs))):
 if (not os.path.exists(os.path.join(top, d, '__init__.py'))
-or top == libpath and d in ('hgext', 'mercurial')):
+or top == libpath and d in ('hgdemandimport', 'hgext',
+'mercurial')):
 del dirs[i]
 for name in files:
 if not name.endswith(('.py', '.so', '.pyc', '.pyo', '.pyd')):
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 4 of 4 hyperblame] annotate: add a new experimental --skip option to skip revs

2017-05-30 Thread Siddharth Agarwal

On 5/29/17 6:37 AM, Yuya Nishihara wrote:

On Sun, 28 May 2017 22:40:47 -0700, Martin von Zweigbergk via Mercurial-devel 
wrote:

On Wed, May 24, 2017 at 7:39 PM, Siddharth Agarwal <s...@fb.com> wrote:

# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1495679973 25200
#  Wed May 24 19:39:33 2017 -0700
# Node ID 0c6f6c4b027191c30d867fb4eb0005682ea90a76
# Parent  134dcc1222e4b992b4a60c44c9b9ed8d10422632
annotate: add a new experimental --skip option to skip revs
+--skip a modified line
+
+  $ hg annotate -nlf b --skip 6
+  0 a:1: a
+  1 a:2: z
+  1 a:3: a
+  3 b:4: b4
+  4 b:5: c
+  3 b:5: b5
+  7 b:7: d

This fails with --pure as follows. I haven't even tried to figure it out.

@@ -232,7 +232,7 @@

$ hg annotate -nlf b --skip 6
0 a:1: a
-  1 a:2: z
+  0 a:1: z
1 a:3: a
3 b:4: b4
4 b:5: c

Perhaps this shows pure/cext bdiff incompatibility. Pure version uses Python
difflib.


That's what I suspect it is. I'll look at it today, thanks.

- Siddharth


___
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 4 of 4 hyperblame] annotate: add a new experimental --skip option to skip revs

2017-05-26 Thread Siddharth Agarwal

On 5/25/17 10:14 PM, Gregory Szorc wrote:
On Thu, May 25, 2017 at 8:24 PM, Siddharth Agarwal 
<s...@less-broken.com <mailto:s...@less-broken.com>> wrote:


On 5/25/17 8:19 PM, Gregory Szorc wrote:

I could also imagine the inverse of a skip feature: an
"include" feature. You could use this to say "only annotate
revisions that correspond to tagged revisions" so you could
easily see how a file evolved from release to release.



Huh, interesting. I hadn't thought of that.


Following that line of thought, why are we defining this in terms of a 
"skip" list? Everything else in Mercurial that speaks in revisions 
does so in an inclusive manner. e.g. `hg log` can be thought of as `hg 
log -r 'all()'`. The feature we're talking about essentially turns `hg 
annotate` from "start at  and consider all() revisions that 
are ancestors" to "start at  and consider  revisions 
that are ancestors," as a skip list is essentially "all() - ." 
So we /could/ invert the design so we teach `hg annotate` which 
revisions to "consider" or are "relevant." `hg annotate -r 123 --from 
'all() - desc(backout) - desc(REFACTOR)'` or something to that effect. 
The only thing this really changes is that files defining revsets 
would have to invert inclusion. e.g. instead of "X\nY" the file is 
"all()\n-X\n-Y". That's mildly more annoying, but arguably more useful 
and flexible than figuring out semantics when there is an implicit 
all() involved.


Hmm, so thinking about this a bit more, there are actually two 
completely different use cases here.


1. Large-scale codemods, for which the most useful thing to present here 
is the nearest changeset that's an *ancestor* of a skipped cset.
2. "What changed in ", for which the most useful thing to 
present is the nearest changeset that's a *descendant* of a skipped cset.


The two cases are quite different, and probably deserve different UI 
surfaces. I'm only solving case 1 for now.


Case 2 definitely doesn't involve any heuristics for linear commits, and 
probably doesn't for branchy history, though I haven't fully worked out 
the latter.

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


Re: [PATCH 4 of 4 hyperblame] annotate: add a new experimental --skip option to skip revs

2017-05-25 Thread Siddharth Agarwal

On 5/25/17 8:19 PM, Gregory Szorc wrote:
I could also imagine the inverse of a skip feature: an "include" 
feature. You could use this to say "only annotate revisions that 
correspond to tagged revisions" so you could easily see how a file 
evolved from release to release.



Huh, interesting. I hadn't thought of that.

I think I've been convinced that specifying --skip on the CLI should 
disable reading the defaults file.


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


Re: [PATCH 1 of 4 hyperblame] annotate: move pair function to top level

2017-05-25 Thread Siddharth Agarwal

On 5/24/17 7:39 PM, Siddharth Agarwal wrote:

# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1495672708 25200
#  Wed May 24 17:38:28 2017 -0700
# Node ID de6d23b18ea0e4e6eb46b509639c63b2318ac979
# Parent  e8c043375b53b30c4b468687f08323cbeeb452ef
annotate: move pair function to top level


Sorry about the threading being broken here -- it's related to some 
Facebook MTA changes that I'm following up on :/




We'll want to make this more complicated and have unit tests for it in upcoming
patches.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -969,15 +969,6 @@ class basefilectx(object):
  def decorate(text, rev):
  return ([(rev, False)] * lines(text), text)
  
-def pair(parent, child):

-blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts)
-for (a1, a2, b1, b2), t in blocks:
-# Changed blocks ('!') or blocks made only of blank lines ('~')
-# belong to the child.
-if t == '=':
-child[0][b1:b2] = parent[0][a1:a2]
-return child
-
  getlog = util.lrucachefunc(lambda x: self._repo.file(x))
  
  def parents(f):

@@ -1054,7 +1045,7 @@ class basefilectx(object):
  visit.pop()
  curr = decorate(f.data(), f)
  for p in pl:
-curr = pair(hist[p], curr)
+curr = _annotatepair(hist[p], curr, diffopts)
  if needed[p] == 1:
  del hist[p]
  del needed[p]
@@ -1082,6 +1073,15 @@ class basefilectx(object):
  c = visit.pop(max(visit))
  yield c
  
+def _annotatepair(parent, child, diffopts):

+blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts)
+for (a1, a2, b1, b2), t in blocks:
+# Changed blocks ('!') or blocks made only of blank lines ('~')
+# belong to the child.
+if t == '=':
+child[0][b1:b2] = parent[0][a1:a2]
+return child
+
  class filectx(basefilectx):
  """A filecontext object makes access to data related to a particular
 filerevision convenient."""
___
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 4 of 4 hyperblame] annotate: add a new experimental --skip option to skip revs

2017-05-25 Thread Siddharth Agarwal

On 5/24/17 7:39 PM, Siddharth Agarwal wrote:

# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1495679973 25200
#  Wed May 24 19:39:33 2017 -0700
# Node ID 0c6f6c4b027191c30d867fb4eb0005682ea90a76
# Parent  134dcc1222e4b992b4a60c44c9b9ed8d10422632
annotate: add a new experimental --skip option to skip revs

This option is most useful for mechanical code modifications, especially ones
that retain the same number of lines.


BTW, some questions that would be worth addressing at some point:

1. Should we call it --skip, --ignore or something else? I'm worried 
that "ignore" is too close to hgignore, which is completely unrelated.
2. For this to be effective, we'd probably want to have a checked in 
file that can apply a default list of revsets to ignore. What should 
that file be called, and what should be the UI around that look like? 
Will we want to enable this by default with hg blame, and then have a 
way to disable it? If additional revsets are specified with 
--skip/--ignore, how do those interact?
3. git hyper-blame adds a * at the end of each commit that god skipped. 
Do we want to do anything similar? I'm worried that if we turn something 
like that on by default, we'll break tools that parse annotate output.


- Siddharth



diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -262,7 +262,8 @@ def addremove(ui, repo, *pats, **opts):
  ('d', 'date', None, _('list the date (short with -q)')),
  ('n', 'number', None, _('list the revision number (default)')),
  ('c', 'changeset', None, _('list the changeset')),
-('l', 'line-number', None, _('show line number at the first appearance'))
+('l', 'line-number', None, _('show line number at the first appearance')),
+('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
  ] + diffwsopts + walkopts + formatteropts,
  _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
  inferrepo=True)
@@ -368,6 +369,10 @@ def annotate(ui, repo, *pats, **opts):
  follow = not opts.get('no_follow')
  diffopts = patch.difffeatureopts(ui, opts, section='annotate',
   whitespace=True)
+skiprevs = opts.get('skip')
+if skiprevs:
+skiprevs = scmutil.revrange(repo, skiprevs)
+
  for abs in ctx.walk(m):
  fctx = ctx[abs]
  if not opts.get('text') and fctx.isbinary():
@@ -375,7 +380,7 @@ def annotate(ui, repo, *pats, **opts):
  continue
  
  lines = fctx.annotate(follow=follow, linenumber=linenumber,

-  diffopts=diffopts)
+  skiprevs=skiprevs, diffopts=diffopts)
  if not lines:
  continue
  formats = []
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -949,7 +949,8 @@ class basefilectx(object):
  return p[1]
  return filectx(self._repo, self._path, fileid=-1, 
filelog=self._filelog)
  
-def annotate(self, follow=False, linenumber=False, diffopts=None):

+def annotate(self, follow=False, linenumber=False, skiprevs=None,
+ diffopts=None):
  '''returns a list of tuples of ((ctx, number), line) for each line
  in the file, where ctx is the filectx of the node where
  that line was last changed; if linenumber parameter is true, number is
@@ -1044,7 +1045,10 @@ class basefilectx(object):
  if ready:
  visit.pop()
  curr = decorate(f.data(), f)
-curr = _annotatepair([hist[p] for p in pl], f, curr, False,
+skipchild = False
+if skiprevs is not None:
+skipchild = f._changeid in skiprevs
+curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild,
   diffopts)
  for p in pl:
  if needed[p] == 1:
diff --git a/tests/test-annotate.t b/tests/test-annotate.t
--- a/tests/test-annotate.t
+++ b/tests/test-annotate.t
@@ -217,6 +217,77 @@ annotate after rename merge with -l
3 b:5: b5
7 b:7: d
  
+--skip nothing (should be the same as no --skip at all)

+
+  $ hg annotate -nlf b --skip '1::0'
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  3 b:4: b4
+  4 b:5: c
+  3 b:5: b5
+  7 b:7: d
+
+--skip a modified line
+
+  $ hg annotate -nlf b --skip 6
+  0 a:1: a
+  1 a:2: z
+  1 a:3: a
+  3 b:4: b4
+  4 b:5: c
+  3 b:5: b5
+  7 b:7: d
+
+--skip added lines (and test multiple skip)
+
+  $ hg annotate -nlf b --skip 3
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  1 a:3: b4
+  4 b:5: c
+  1 a:3: b5
+  7 b:7: d
+
+  $ hg annotate -nlf b --skip 4
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  3 b:4: b4
+  1 a:3: c
+  3 b:5: b5
+  7 b:7: d
+
+  $ hg annotate -nlf b --skip 3 --skip 4
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  1 a:3: b4
+  1 a:3: c
+  1 a:3

[PATCH 4 of 4 hyperblame] annotate: add a new experimental --skip option to skip revs

2017-05-24 Thread Siddharth Agarwal
# HG changeset patch
# User Siddharth Agarwal <s...@fb.com>
# Date 1495679973 25200
#  Wed May 24 19:39:33 2017 -0700
# Node ID 0c6f6c4b027191c30d867fb4eb0005682ea90a76
# Parent  134dcc1222e4b992b4a60c44c9b9ed8d10422632
annotate: add a new experimental --skip option to skip revs

This option is most useful for mechanical code modifications, especially ones
that retain the same number of lines.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -262,7 +262,8 @@ def addremove(ui, repo, *pats, **opts):
 ('d', 'date', None, _('list the date (short with -q)')),
 ('n', 'number', None, _('list the revision number (default)')),
 ('c', 'changeset', None, _('list the changeset')),
-('l', 'line-number', None, _('show line number at the first appearance'))
+('l', 'line-number', None, _('show line number at the first appearance')),
+('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
 ] + diffwsopts + walkopts + formatteropts,
 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
 inferrepo=True)
@@ -368,6 +369,10 @@ def annotate(ui, repo, *pats, **opts):
 follow = not opts.get('no_follow')
 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
  whitespace=True)
+skiprevs = opts.get('skip')
+if skiprevs:
+skiprevs = scmutil.revrange(repo, skiprevs)
+
 for abs in ctx.walk(m):
 fctx = ctx[abs]
 if not opts.get('text') and fctx.isbinary():
@@ -375,7 +380,7 @@ def annotate(ui, repo, *pats, **opts):
 continue
 
 lines = fctx.annotate(follow=follow, linenumber=linenumber,
-  diffopts=diffopts)
+  skiprevs=skiprevs, diffopts=diffopts)
 if not lines:
 continue
 formats = []
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -949,7 +949,8 @@ class basefilectx(object):
 return p[1]
 return filectx(self._repo, self._path, fileid=-1, 
filelog=self._filelog)
 
-def annotate(self, follow=False, linenumber=False, diffopts=None):
+def annotate(self, follow=False, linenumber=False, skiprevs=None,
+ diffopts=None):
 '''returns a list of tuples of ((ctx, number), line) for each line
 in the file, where ctx is the filectx of the node where
 that line was last changed; if linenumber parameter is true, number is
@@ -1044,7 +1045,10 @@ class basefilectx(object):
 if ready:
 visit.pop()
 curr = decorate(f.data(), f)
-curr = _annotatepair([hist[p] for p in pl], f, curr, False,
+skipchild = False
+if skiprevs is not None:
+skipchild = f._changeid in skiprevs
+curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild,
  diffopts)
 for p in pl:
 if needed[p] == 1:
diff --git a/tests/test-annotate.t b/tests/test-annotate.t
--- a/tests/test-annotate.t
+++ b/tests/test-annotate.t
@@ -217,6 +217,77 @@ annotate after rename merge with -l
   3 b:5: b5
   7 b:7: d
 
+--skip nothing (should be the same as no --skip at all)
+
+  $ hg annotate -nlf b --skip '1::0'
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  3 b:4: b4
+  4 b:5: c
+  3 b:5: b5
+  7 b:7: d
+
+--skip a modified line
+
+  $ hg annotate -nlf b --skip 6
+  0 a:1: a
+  1 a:2: z
+  1 a:3: a
+  3 b:4: b4
+  4 b:5: c
+  3 b:5: b5
+  7 b:7: d
+
+--skip added lines (and test multiple skip)
+
+  $ hg annotate -nlf b --skip 3
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  1 a:3: b4
+  4 b:5: c
+  1 a:3: b5
+  7 b:7: d
+
+  $ hg annotate -nlf b --skip 4
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  3 b:4: b4
+  1 a:3: c
+  3 b:5: b5
+  7 b:7: d
+
+  $ hg annotate -nlf b --skip 3 --skip 4
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  1 a:3: b4
+  1 a:3: c
+  1 a:3: b5
+  7 b:7: d
+
+  $ hg annotate -nlf b --skip 'merge()'
+  0 a:1: a
+  6 b:2: z
+  1 a:3: a
+  3 b:4: b4
+  4 b:5: c
+  3 b:5: b5
+  3 b:5: d
+
+--skip everything -- use the revision the file was introduced in
+
+  $ hg annotate -nlf b --skip 'all()'
+  0 a:1: a
+  0 a:1: z
+  0 a:1: a
+  0 a:1: b4
+  0 a:1: c
+  0 a:1: b5
+  0 a:1: d
+
 Issue2807: alignment of line numbers with -l
 
   $ echo more >> b
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -217,7 +217,7 @@ Show an error if we use --options with a
 Show all commands + options
   $ hg debugcommands
   add: include, exclude, subrepos, dry-run
-  annotate: rev, follow, no-follow, text, user, file, date, number, changeset, 
line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, 
include, exclude, template
+  annotate: rev, follow, no-follow, text, user

  1   2   >