D7631: absorb: allowing committed changes to be absorbed into their ancestors

2020-02-06 Thread rdamazio (Rodrigo Damazio Bovendorp)
rdamazio updated this revision to Diff 19981.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7631?vs=19979=19981

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7631/new/

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

AFFECTED FILES
  hgext/absorb.py
  mercurial/scmutil.py
  relnotes/5.3
  relnotes/next
  tests/test-absorb-rev.t
  tests/test-absorb.t

CHANGE DETAILS

diff --git a/tests/test-absorb.t b/tests/test-absorb.t
--- a/tests/test-absorb.t
+++ b/tests/test-absorb.t
@@ -143,7 +143,7 @@
   nothing applied
   [1]
 
-Insertaions:
+Insertions:
 
   $ cat > a << EOF
   > insert before 2b
diff --git a/tests/test-absorb.t b/tests/test-absorb-rev.t
copy from tests/test-absorb.t
copy to tests/test-absorb-rev.t
--- a/tests/test-absorb.t
+++ b/tests/test-absorb-rev.t
@@ -1,26 +1,16 @@
   $ cat >> $HGRCPATH << EOF
   > [extensions]
   > absorb=
+  > rebase=
+  > [experimental]
+  > evolution=createmarkers
+  > [alias]
+  > glog=log -G -T '{node|short} {desc} {instabilities}'
   > EOF
 
-  $ sedi() { # workaround check-code
-  > pattern="$1"
-  > shift
-  > for i in "$@"; do
-  > sed "$pattern" "$i" > "$i".tmp
-  > mv "$i".tmp "$i"
-  > done
-  > }
-
   $ hg init repo1
   $ cd repo1
 
-Do not crash with empty repo:
-
-  $ hg absorb
-  abort: no mutable changeset to change
-  [255]
-
 Make some commits:
 
   $ for i in 1 2 3 4 5; do
@@ -45,9 +35,26 @@
   > 5e
   > EOF
 
+Commit that, too.
+
+  $ hg commit -qm "commit to absorb"
+  $ hg glog
+  @  1631091f9648 commit to absorb
+  |
+  o  4f55fa657dae commit 5
+  |
+  o  ad8b8b75557f commit 4
+  |
+  o  43f0a75bede7 commit 3
+  |
+  o  5c5f95224a50 commit 2
+  |
+  o  4ec16f85269a commit 1
+  
+
 Preview absorb changes:
 
-  $ hg absorb --print-changes --dry-run
+  $ hg absorb --print-changes --dry-run --from .
   showing changes for a
   @@ -0,2 +0,2 @@
   4ec16f8 -1
@@ -66,462 +73,185 @@
   5c5f952 commit 2
   4ec16f8 commit 1
 
+Try to absorb multiple revisions:
+
+  $ hg absorb --apply-changes --from '.^+.'
+  abort: revision set matched multiple revisions
+  [255]
+
+Add an uncommitted working directory change:
+
+  $ echo 6 >> a
+
 Run absorb:
 
-  $ hg absorb --apply-changes
-  saved backup bundle to * (glob)
+  $ hg absorb --apply-changes --from .
+  1 new orphan changesets
   2 of 2 chunk(s) applied
-  $ hg annotate a
-  0: 1a
-  1: 2b
-  2: 3
-  3: 4d
-  4: 5e
-
-Delete a few lines and related commits will be removed if they will be empty:
-
-  $ cat > a < 2b
-  > 4d
-  > EOF
-  $ echo y | hg absorb --config ui.interactive=1
-  showing changes for a
-  @@ -0,1 +0,0 @@
-  f548282 -1a
-  @@ -2,1 +1,0 @@
-  ff5d556 -3
-  @@ -4,1 +2,0 @@
-  84e5416 -5e
+Note: this only shows disconnected graphs because the root node was also
+absorbed into.
+  $ hg glog
+  o  2f7ba78d6abc commit 5
+  |
+  o  04c8ba6df782 commit 4
+  |
+  o  484c6ac0cea3 commit 3
+  |
+  o  9b19176bb127 commit 2
+  |
+  o  241ace8326d0 commit 1
   
-  3 changesets affected
-  84e5416 commit 5
-  ff5d556 commit 3
-  f548282 commit 1
-  apply changes (yn)?  y
-  saved backup bundle to * (glob)
-  3 of 3 chunk(s) applied
-  $ hg annotate a
-  1: 2b
-  2: 4d
-  $ hg log -T '{rev} {desc}\n' -Gp
-  @  2 commit 4
-  |  diff -r 1cae118c7ed8 -r 58a62bade1c6 a
-  |  --- a/a   Thu Jan 01 00:00:00 1970 +
-  |  +++ b/a   Thu Jan 01 00:00:00 1970 +
-  |  @@ -1,1 +1,2 @@
-  |   2b
-  |  +4d
+  @  1631091f9648 commit to absorb orphan
+  |
+  x  4f55fa657dae commit 5
+  |
+  x  ad8b8b75557f commit 4
   |
-  o  1 commit 2
-  |  diff -r 84add69aeac0 -r 1cae118c7ed8 a
-  |  --- a/a   Thu Jan 01 00:00:00 1970 +
-  |  +++ b/a   Thu Jan 01 00:00:00 1970 +
-  |  @@ -0,0 +1,1 @@
-  |  +2b
+  x  43f0a75bede7 commit 3
   |
-  o  0 commit 1
+  x  5c5f95224a50 commit 2
+  |
+  x  4ec16f85269a commit 1
   
 
-Non 1:1 map changes will be ignored:
-
-  $ echo 1 > a
-  $ hg absorb --apply-changes
-  nothing applied
-  [1]
-
-The prompt is not given if there are no changes to be applied, even if there
-are some changes that won't be applied:
-
-  $ hg absorb
-  showing changes for a
-  @@ -0,2 +0,1 @@
-  -2b
-  -4d
-  +1
-  
-  0 changesets affected
-  nothing applied
-  [1]
-
-Insertaions:
-
-  $ cat > a << EOF
-  > insert before 2b
-  > 2b
-  > 4d
-  > insert aftert 4d
-  > EOF
-  $ hg absorb -q --apply-changes
-  $ hg status
-  $ hg annotate a
-  1: insert before 2b
-  1: 2b
-  2: 4d
-  2: insert aftert 4d
-
-Bookmarks are moved:
-
-  $ hg bookmark -r 1 b1
-  $ hg bookmark -r 2 b2
-  $ hg bookmark ba
-  $ hg bookmarks
- b11:b35060a57a50
- b22:946e4bc87915
-   * ba2:946e4bc87915
-  $ sedi 's/insert/INSERT/' a
-  $ hg absorb -q --apply-changes
-  $ hg status
-  $ hg bookmarks
- b11:a4183e9b3d31
- b22:c9b20c925790
-   * ba

D7630: absorb: make the absorbed changeset be automatically "evolved"

2020-02-06 Thread rdamazio (Rodrigo Damazio Bovendorp)
rdamazio updated this revision to Diff 19982.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7630?vs=19980=19982

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7630/new/

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

AFFECTED FILES
  hgext/absorb.py
  tests/test-absorb-rev.t

CHANGE DETAILS

diff --git a/tests/test-absorb-rev.t b/tests/test-absorb-rev.t
--- a/tests/test-absorb-rev.t
+++ b/tests/test-absorb-rev.t
@@ -86,11 +86,10 @@
 Run absorb:
 
   $ hg absorb --apply-changes --from .
-  1 new orphan changesets
   2 of 2 chunk(s) applied
-Note: this only shows disconnected graphs because the root node was also
-absorbed into.
   $ hg glog
+  @  9a0ec5cae1a1 commit to absorb
+  |
   o  2f7ba78d6abc commit 5
   |
   o  04c8ba6df782 commit 4
@@ -101,18 +100,6 @@
   |
   o  241ace8326d0 commit 1
   
-  @  1631091f9648 commit to absorb orphan
-  |
-  x  4f55fa657dae commit 5
-  |
-  x  ad8b8b75557f commit 4
-  |
-  x  43f0a75bede7 commit 3
-  |
-  x  5c5f95224a50 commit 2
-  |
-  x  4ec16f85269a commit 1
-  
 
 Check that the pending wdir change was left alone:
 
@@ -127,34 +114,21 @@
4d
5e
   +6
-  $ hg update -Cq .
-
-Rebase the absorbed revision on top of the destination (as evolve would):
-TODO: the evolve-type operation should happen automatically for the changeset
-being absorbed, and even through that the pending wdir change should be left
-alone.
-
-  $ hg rebase -d tip -r .
-  rebasing 5:1631091f9648 "commit to absorb"
-  note: not rebasing 5:1631091f9648 "commit to absorb", its destination 
already has all its changes
 
-  $ hg glog
-  @  2f7ba78d6abc commit 5
-  |
-  o  04c8ba6df782 commit 4
-  |
-  o  484c6ac0cea3 commit 3
-  |
-  o  9b19176bb127 commit 2
-  |
-  o  241ace8326d0 commit 1
-  
-  $ hg annotate -c a
-  241ace8326d0: 1a
-  9b19176bb127: 2b
-  484c6ac0cea3: 3
-  04c8ba6df782: 4d
-  2f7ba78d6abc: 5e
+  $ hg annotate -c a -r 'wdir()'
+  241ace8326d0 : 1a
+  9b19176bb127 : 2b
+  484c6ac0cea3 : 3
+  04c8ba6df782 : 4d
+  2f7ba78d6abc : 5e
+  9a0ec5cae1a1+: 6
+
+TODO: The absorbed commit should have disappeared when it became empty.
+  $ hg diff -c .
+  $ hg debugobsolete $(hg log -T "{node}\n" -r .)
+  1 new obsolescence markers
+  obsoleted 1 changesets
+  $ hg update -Cq '.^'
 
 Do it again, but this time with an unrelated commit checked out (plus working
 directory changes on top):
@@ -200,22 +174,17 @@
   2 changesets affected
   2f7ba78 commit 5
   04c8ba6 commit 4
-  1 new orphan changesets
   1 of 1 chunk(s) applied
 
   $ hg glog
+  o  da8aed1fcb63 commit to absorb 2
+  |
   o  789b01face13 commit 5
   |
   o  9c83c60f49f2 commit 4
   |
   | @  dbce69d9fe03 unrelated commit
   | |
-  | | *  410fcc72c5c9 commit to absorb 2 orphan
-  | | |
-  | | x  2f7ba78d6abc commit 5
-  | | |
-  +---x  04c8ba6df782 commit 4
-  | |
   o |  484c6ac0cea3 commit 3
   | |
   o |  9b19176bb127 commit 2
@@ -228,18 +197,16 @@
   dbce69d9fe03 : committed unrelated
   dbce69d9fe03+: pending wdir change
 
-  $ hg update -Cq .
-
-  $ hg rebase -d tip -r ${TOABSORB}
-  rebasing \d+:[0-9a-f]+ "commit to absorb 2" (re)
-  note: not rebasing \d+:[0-9a-f]+ "commit to absorb 2", its destination 
already has all its changes (re)
+  $ hg update -Cq tip
 
   $ hg glog
+  o  da8aed1fcb63 commit to absorb 2
+  |
   o  789b01face13 commit 5
   |
   o  9c83c60f49f2 commit 4
   |
-  | @  dbce69d9fe03 unrelated commit
+  | o  dbce69d9fe03 unrelated commit
   | |
   o |  484c6ac0cea3 commit 3
   | |
@@ -248,7 +215,7 @@
   o  241ace8326d0 commit 1
   
 
-  $ hg annotate -c a -r tip
+  $ hg annotate -c a
   241ace8326d0: 1a
   9b19176bb127: 2b
   484c6ac0cea3: 3
diff --git a/hgext/absorb.py b/hgext/absorb.py
--- a/hgext/absorb.py
+++ b/hgext/absorb.py
@@ -34,6 +34,7 @@
 from __future__ import absolute_import
 
 import collections
+import itertools
 
 from mercurial.i18n import _
 from mercurial import (
@@ -662,16 +663,19 @@
 4. call commit, to commit changes to hg database
 """
 
-def __init__(self, stack, ui=None, opts=None):
+def __init__(self, stack, fixuptargets=[], ui=None, opts=None):
 """([ctx], ui or None) -> None
 
 stack: should be linear, and sorted by topo order - oldest first.
+fixuptargets: changeset contexts that need to be fixed up, but are not
+used for fixup computation.
 all commits in stack are considered mutable.
 """
 assert stack
 self.ui = ui or nullui()
 self.opts = opts or {}
 self.stack = stack
+self.fixuptargets = fixuptargets
 self.repo = stack[-1].repo().unfiltered()
 
 # following fields will be filled later
@@ -777,7 +781,7 @@
 # p1 which overrides the parent of the next commit, "None" means use
 # the original parent unchanged
 nextp1 = None
-for ctx in self.stack:
+for ctx in itertools.chain(self.stack, self.fixuptargets):
 

D7631: absorb: allowing committed changes to be absorbed into their ancestors

2020-02-06 Thread rdamazio (Rodrigo Damazio Bovendorp)
rdamazio updated this revision to Diff 19979.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7631?vs=19811=19979

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7631/new/

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

AFFECTED FILES
  hgext/absorb.py
  mercurial/scmutil.py
  relnotes/5.3
  relnotes/next
  tests/test-absorb-rev.t
  tests/test-absorb.t

CHANGE DETAILS

diff --git a/tests/test-absorb.t b/tests/test-absorb.t
--- a/tests/test-absorb.t
+++ b/tests/test-absorb.t
@@ -143,7 +143,7 @@
   nothing applied
   [1]
 
-Insertaions:
+Insertions:
 
   $ cat > a << EOF
   > insert before 2b
diff --git a/tests/test-absorb.t b/tests/test-absorb-rev.t
copy from tests/test-absorb.t
copy to tests/test-absorb-rev.t
--- a/tests/test-absorb.t
+++ b/tests/test-absorb-rev.t
@@ -1,26 +1,16 @@
   $ cat >> $HGRCPATH << EOF
   > [extensions]
   > absorb=
+  > rebase=
+  > [experimental]
+  > evolution=createmarkers
+  > [alias]
+  > glog=log -G -T '{node|short} {desc} {instabilities}'
   > EOF
 
-  $ sedi() { # workaround check-code
-  > pattern="$1"
-  > shift
-  > for i in "$@"; do
-  > sed "$pattern" "$i" > "$i".tmp
-  > mv "$i".tmp "$i"
-  > done
-  > }
-
   $ hg init repo1
   $ cd repo1
 
-Do not crash with empty repo:
-
-  $ hg absorb
-  abort: no mutable changeset to change
-  [255]
-
 Make some commits:
 
   $ for i in 1 2 3 4 5; do
@@ -45,9 +35,26 @@
   > 5e
   > EOF
 
+Commit that, too.
+
+  $ hg commit -qm "commit to absorb"
+  $ hg glog
+  @  1631091f9648 commit to absorb
+  |
+  o  4f55fa657dae commit 5
+  |
+  o  ad8b8b75557f commit 4
+  |
+  o  43f0a75bede7 commit 3
+  |
+  o  5c5f95224a50 commit 2
+  |
+  o  4ec16f85269a commit 1
+  
+
 Preview absorb changes:
 
-  $ hg absorb --print-changes --dry-run
+  $ hg absorb --print-changes --dry-run -s .
   showing changes for a
   @@ -0,2 +0,2 @@
   4ec16f8 -1
@@ -66,462 +73,185 @@
   5c5f952 commit 2
   4ec16f8 commit 1
 
+Try to absorb multiple revisions:
+
+  $ hg absorb --apply-changes -s '.^+.'
+  abort: revision set matched multiple revisions
+  [255]
+
+Add an uncommitted working directory change:
+
+  $ echo 6 >> a
+
 Run absorb:
 
-  $ hg absorb --apply-changes
-  saved backup bundle to * (glob)
+  $ hg absorb --apply-changes -s .
+  1 new orphan changesets
   2 of 2 chunk(s) applied
-  $ hg annotate a
-  0: 1a
-  1: 2b
-  2: 3
-  3: 4d
-  4: 5e
-
-Delete a few lines and related commits will be removed if they will be empty:
-
-  $ cat > a < 2b
-  > 4d
-  > EOF
-  $ echo y | hg absorb --config ui.interactive=1
-  showing changes for a
-  @@ -0,1 +0,0 @@
-  f548282 -1a
-  @@ -2,1 +1,0 @@
-  ff5d556 -3
-  @@ -4,1 +2,0 @@
-  84e5416 -5e
+Note: this only shows disconnected graphs because the root node was also
+absorbed into.
+  $ hg glog
+  o  2f7ba78d6abc commit 5
+  |
+  o  04c8ba6df782 commit 4
+  |
+  o  484c6ac0cea3 commit 3
+  |
+  o  9b19176bb127 commit 2
+  |
+  o  241ace8326d0 commit 1
   
-  3 changesets affected
-  84e5416 commit 5
-  ff5d556 commit 3
-  f548282 commit 1
-  apply changes (yn)?  y
-  saved backup bundle to * (glob)
-  3 of 3 chunk(s) applied
-  $ hg annotate a
-  1: 2b
-  2: 4d
-  $ hg log -T '{rev} {desc}\n' -Gp
-  @  2 commit 4
-  |  diff -r 1cae118c7ed8 -r 58a62bade1c6 a
-  |  --- a/a   Thu Jan 01 00:00:00 1970 +
-  |  +++ b/a   Thu Jan 01 00:00:00 1970 +
-  |  @@ -1,1 +1,2 @@
-  |   2b
-  |  +4d
+  @  1631091f9648 commit to absorb orphan
+  |
+  x  4f55fa657dae commit 5
+  |
+  x  ad8b8b75557f commit 4
   |
-  o  1 commit 2
-  |  diff -r 84add69aeac0 -r 1cae118c7ed8 a
-  |  --- a/a   Thu Jan 01 00:00:00 1970 +
-  |  +++ b/a   Thu Jan 01 00:00:00 1970 +
-  |  @@ -0,0 +1,1 @@
-  |  +2b
+  x  43f0a75bede7 commit 3
   |
-  o  0 commit 1
+  x  5c5f95224a50 commit 2
+  |
+  x  4ec16f85269a commit 1
   
 
-Non 1:1 map changes will be ignored:
-
-  $ echo 1 > a
-  $ hg absorb --apply-changes
-  nothing applied
-  [1]
-
-The prompt is not given if there are no changes to be applied, even if there
-are some changes that won't be applied:
-
-  $ hg absorb
-  showing changes for a
-  @@ -0,2 +0,1 @@
-  -2b
-  -4d
-  +1
-  
-  0 changesets affected
-  nothing applied
-  [1]
-
-Insertaions:
-
-  $ cat > a << EOF
-  > insert before 2b
-  > 2b
-  > 4d
-  > insert aftert 4d
-  > EOF
-  $ hg absorb -q --apply-changes
-  $ hg status
-  $ hg annotate a
-  1: insert before 2b
-  1: 2b
-  2: 4d
-  2: insert aftert 4d
-
-Bookmarks are moved:
-
-  $ hg bookmark -r 1 b1
-  $ hg bookmark -r 2 b2
-  $ hg bookmark ba
-  $ hg bookmarks
- b11:b35060a57a50
- b22:946e4bc87915
-   * ba2:946e4bc87915
-  $ sedi 's/insert/INSERT/' a
-  $ hg absorb -q --apply-changes
-  $ hg status
-  $ hg bookmarks
- b11:a4183e9b3d31
- b22:c9b20c925790
-   * ba

D7630: absorb: make the absorbed changeset be automatically "evolved"

2020-02-06 Thread rdamazio (Rodrigo Damazio Bovendorp)
rdamazio updated this revision to Diff 19980.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7630?vs=19812=19980

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7630/new/

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

AFFECTED FILES
  hgext/absorb.py
  tests/test-absorb-rev.t

CHANGE DETAILS

diff --git a/tests/test-absorb-rev.t b/tests/test-absorb-rev.t
--- a/tests/test-absorb-rev.t
+++ b/tests/test-absorb-rev.t
@@ -86,11 +86,10 @@
 Run absorb:
 
   $ hg absorb --apply-changes -s .
-  1 new orphan changesets
   2 of 2 chunk(s) applied
-Note: this only shows disconnected graphs because the root node was also
-absorbed into.
   $ hg glog
+  @  9a0ec5cae1a1 commit to absorb
+  |
   o  2f7ba78d6abc commit 5
   |
   o  04c8ba6df782 commit 4
@@ -101,18 +100,6 @@
   |
   o  241ace8326d0 commit 1
   
-  @  1631091f9648 commit to absorb orphan
-  |
-  x  4f55fa657dae commit 5
-  |
-  x  ad8b8b75557f commit 4
-  |
-  x  43f0a75bede7 commit 3
-  |
-  x  5c5f95224a50 commit 2
-  |
-  x  4ec16f85269a commit 1
-  
 
 Check that the pending wdir change was left alone:
 
@@ -127,34 +114,21 @@
4d
5e
   +6
-  $ hg update -Cq .
-
-Rebase the absorbed revision on top of the destination (as evolve would):
-TODO: the evolve-type operation should happen automatically for the changeset
-being absorbed, and even through that the pending wdir change should be left
-alone.
-
-  $ hg rebase -d tip -r .
-  rebasing 5:1631091f9648 "commit to absorb"
-  note: not rebasing 5:1631091f9648 "commit to absorb", its destination 
already has all its changes
 
-  $ hg glog
-  @  2f7ba78d6abc commit 5
-  |
-  o  04c8ba6df782 commit 4
-  |
-  o  484c6ac0cea3 commit 3
-  |
-  o  9b19176bb127 commit 2
-  |
-  o  241ace8326d0 commit 1
-  
-  $ hg annotate -c a
-  241ace8326d0: 1a
-  9b19176bb127: 2b
-  484c6ac0cea3: 3
-  04c8ba6df782: 4d
-  2f7ba78d6abc: 5e
+  $ hg annotate -c a -r 'wdir()'
+  241ace8326d0 : 1a
+  9b19176bb127 : 2b
+  484c6ac0cea3 : 3
+  04c8ba6df782 : 4d
+  2f7ba78d6abc : 5e
+  9a0ec5cae1a1+: 6
+
+TODO: The absorbed commit should have disappeared when it became empty.
+  $ hg diff -c .
+  $ hg debugobsolete $(hg log -T "{node}\n" -r .)
+  1 new obsolescence markers
+  obsoleted 1 changesets
+  $ hg update -Cq '.^'
 
 Do it again, but this time with an unrelated commit checked out (plus working
 directory changes on top):
@@ -200,22 +174,17 @@
   2 changesets affected
   2f7ba78 commit 5
   04c8ba6 commit 4
-  1 new orphan changesets
   1 of 1 chunk(s) applied
 
   $ hg glog
+  o  da8aed1fcb63 commit to absorb 2
+  |
   o  789b01face13 commit 5
   |
   o  9c83c60f49f2 commit 4
   |
   | @  dbce69d9fe03 unrelated commit
   | |
-  | | *  410fcc72c5c9 commit to absorb 2 orphan
-  | | |
-  | | x  2f7ba78d6abc commit 5
-  | | |
-  +---x  04c8ba6df782 commit 4
-  | |
   o |  484c6ac0cea3 commit 3
   | |
   o |  9b19176bb127 commit 2
@@ -228,18 +197,16 @@
   dbce69d9fe03 : committed unrelated
   dbce69d9fe03+: pending wdir change
 
-  $ hg update -Cq .
-
-  $ hg rebase -d tip -r ${TOABSORB}
-  rebasing \d+:[0-9a-f]+ "commit to absorb 2" (re)
-  note: not rebasing \d+:[0-9a-f]+ "commit to absorb 2", its destination 
already has all its changes (re)
+  $ hg update -Cq tip
 
   $ hg glog
+  o  da8aed1fcb63 commit to absorb 2
+  |
   o  789b01face13 commit 5
   |
   o  9c83c60f49f2 commit 4
   |
-  | @  dbce69d9fe03 unrelated commit
+  | o  dbce69d9fe03 unrelated commit
   | |
   o |  484c6ac0cea3 commit 3
   | |
@@ -248,7 +215,7 @@
   o  241ace8326d0 commit 1
   
 
-  $ hg annotate -c a -r tip
+  $ hg annotate -c a
   241ace8326d0: 1a
   9b19176bb127: 2b
   484c6ac0cea3: 3
diff --git a/hgext/absorb.py b/hgext/absorb.py
--- a/hgext/absorb.py
+++ b/hgext/absorb.py
@@ -34,6 +34,7 @@
 from __future__ import absolute_import
 
 import collections
+import itertools
 
 from mercurial.i18n import _
 from mercurial import (
@@ -662,16 +663,19 @@
 4. call commit, to commit changes to hg database
 """
 
-def __init__(self, stack, ui=None, opts=None):
+def __init__(self, stack, fixuptargets=[], ui=None, opts=None):
 """([ctx], ui or None) -> None
 
 stack: should be linear, and sorted by topo order - oldest first.
+fixuptargets: changeset contexts that need to be fixed up, but are not
+used for fixup computation.
 all commits in stack are considered mutable.
 """
 assert stack
 self.ui = ui or nullui()
 self.opts = opts or {}
 self.stack = stack
+self.fixuptargets = fixuptargets
 self.repo = stack[-1].repo().unfiltered()
 
 # following fields will be filled later
@@ -777,7 +781,7 @@
 # p1 which overrides the parent of the next commit, "None" means use
 # the original parent unchanged
 nextp1 = None
-for ctx in self.stack:
+for ctx in itertools.chain(self.stack, self.fixuptargets):
 

D8089: py3: __repr__ needs to return str, not bytes

2020-02-06 Thread spectral (Kyle Lippincott)
spectral added inline comments.

INLINE COMMENTS

> mharbison72 wrote in bundle2.py:1018
> Aren't `self.__class__.__module__` and `self.__class__.__name__` str?

Yep, so this instance fails for other reasons as well. Sigh.  I've sent a 
followup (D8091 ). This may cause output 
like .

I didn't actually test most of these, obviously :P  I just did a grep for 
__repr__ returning bytes...

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8089/new/

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

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


D8091: py3: fully fix bundlepart.__repr__ to return str not bytes

2020-02-06 Thread spectral (Kyle Lippincott)
spectral created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  My previous fix did not fully fix the issue: it would attempt to use
  %-formatting to combine two strs into a bytes, which won't work. Let's just
  switch the entire function to operating in strs. This can cause a small output
  difference that will likely not be noticed since no one noticed that the 
method
  wasn't working at all before: if `id` or `type` are not-None, they'll be shown
  as `b'val'` instead of `val`. Since this is a debugging aid and these strings
  shouldn't be shown to the user, slightly rough output is most likely fine and
  it's likely not worthwhile to add the necessary conditionals to marginally
  improve it.

REPOSITORY
  rHG Mercurial

BRANCH
  stable

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

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -1013,10 +1013,9 @@
 self._generated = None
 self.mandatory = mandatory
 
-@encoding.strmethod
 def __repr__(self):
-cls = b"%s.%s" % (self.__class__.__module__, self.__class__.__name__)
-return b'<%s object at %x; id: %s; type: %s; mandatory: %s>' % (
+cls = "%s.%s" % (self.__class__.__module__, self.__class__.__name__)
+return '<%s object at %x; id: %s; type: %s; mandatory: %s>' % (
 cls,
 id(self),
 self.id,



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


D7902: merge: introduce a clean_update() for that use-case

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
Closed by commit rHGf546d2170b0f: merge: introduce a clean_update() for that 
use-case (authored by martinvonz).
martinvonz marked an inline comment as done.
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7902?vs=19929=19970

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7902/new/

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

AFFECTED FILES
  hgext/histedit.py
  hgext/rebase.py
  mercurial/hg.py
  mercurial/merge.py
  mercurial/shelve.py

CHANGE DETAILS

diff --git a/mercurial/shelve.py b/mercurial/shelve.py
--- a/mercurial/shelve.py
+++ b/mercurial/shelve.py
@@ -745,7 +745,7 @@
 try:
 checkparents(repo, state)
 
-merge.update(repo, state.pendingctx, branchmerge=False, force=True)
+merge.clean_update(state.pendingctx)
 if state.activebookmark and state.activebookmark in 
repo._bookmarks:
 bookmarks.activate(repo, state.activebookmark)
 mergefiles(ui, repo, state.wctx, state.pendingctx)
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -2597,6 +2597,15 @@
 return stats
 
 
+def clean_update(ctx, wc=None):
+"""Do a clean update to the given commit.
+
+This involves updating to the commit and discarding any changes in the
+working copy.
+"""
+return update(ctx.repo(), ctx.rev(), branchmerge=False, force=True, wc=wc)
+
+
 def graft(
 repo,
 ctx,
diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -1173,7 +1173,7 @@
 node = repo[b'.'].hex()
 
 repo.ui.status(_(b"aborting the merge, updating back to %s\n") % node[:12])
-stats = mergemod.update(repo, node, branchmerge=False, force=True)
+stats = mergemod.clean_update(repo[node])
 assert stats.unresolvedcount == 0
 _showstats(repo, stats)
 
diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -800,9 +800,7 @@
 
 # Update away from the rebase if necessary
 if shouldupdate:
-mergemod.update(
-repo, self.originalwd, branchmerge=False, force=True
-)
+mergemod.clean_update(repo[self.originalwd])
 
 # Strip from the first rebased revision
 if rebased:
@@ -1477,7 +1475,7 @@
 else:
 if repo[b'.'].rev() != p1:
 repo.ui.debug(b" update to %d:%s\n" % (p1, p1ctx))
-mergemod.update(repo, p1, branchmerge=False, force=True)
+mergemod.clean_update(p1ctx)
 else:
 repo.ui.debug(b" already in destination\n")
 # This is, alas, necessary to invalidate workingctx's manifest cache,
diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -945,7 +945,7 @@
 class base(histeditaction):
 def run(self):
 if self.repo[b'.'].node() != self.node:
-mergemod.update(self.repo, self.node, branchmerge=False, 
force=True)
+mergemod.clean_update(self.repo[self.node])
 return self.continueclean()
 
 def continuedirty(self):



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


D8071: copies: avoid filtering by short-circuit dirstate-only copies earlier

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
Closed by commit rHG30862e226339: copies: avoid filtering by short-circuit 
dirstate-only copies earlier (authored by martinvonz).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8071?vs=19873=19976

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8071/new/

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

AFFECTED FILES
  mercurial/copies.py
  tests/test-repo-filters-tiptoe.t

CHANGE DETAILS

diff --git a/tests/test-repo-filters-tiptoe.t b/tests/test-repo-filters-tiptoe.t
--- a/tests/test-repo-filters-tiptoe.t
+++ b/tests/test-repo-filters-tiptoe.t
@@ -68,7 +68,6 @@
   ! b
 
   $ hg status --copies
-  debug.filters: computing revision filter for "visible"
   M c
   A d
   R a
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -403,13 +403,15 @@
 )
 if x == y or not x or not y:
 return {}
+if y.rev() is None and x == y.p1():
+if debug:
+repo.ui.debug(b'debug.copies: search mode: dirstate\n')
+# short-circuit to avoid issues with merge states
+return _dirstatecopies(repo, match)
 a = y.ancestor(x)
 if a == x:
 if debug:
 repo.ui.debug(b'debug.copies: search mode: forward\n')
-if y.rev() is None and x == y.p1():
-# short-circuit to avoid issues with merge states
-return _dirstatecopies(repo, match)
 copies = _forwardcopies(x, y, match=match)
 elif a == y:
 if debug:



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


D7992: clean: delete obsolete unlinking of .hg/graftstate

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
Closed by commit rHG3245cdea2c63: clean: delete obsolete unlinking of 
.hg/graftstate (authored by martinvonz).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7992?vs=19735=19977

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7992/new/

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

AFFECTED FILES
  mercurial/hg.py

CHANGE DETAILS

diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -1041,7 +1041,6 @@
 """forcibly switch the working directory to node, clobbering changes"""
 stats = updaterepo(repo, node, True)
 assert stats.unresolvedcount == 0
-repo.vfs.unlinkpath(b'graftstate', ignoremissing=True)
 if show_stats:
 _showstats(repo, stats, quietempty)
 



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


D8070: tests: add test showing that repo filter is calculated for `hg st --copies`

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
Closed by commit rHG66dab0d9a78e: tests: add test showing that repo filter is 
calculated for `hg st --copies` (authored by martinvonz).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8070?vs=19872=19975

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8070/new/

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

AFFECTED FILES
  tests/test-repo-filters-tiptoe.t

CHANGE DETAILS

diff --git a/tests/test-repo-filters-tiptoe.t b/tests/test-repo-filters-tiptoe.t
--- a/tests/test-repo-filters-tiptoe.t
+++ b/tests/test-repo-filters-tiptoe.t
@@ -67,6 +67,13 @@
   R a
   ! b
 
+  $ hg status --copies
+  debug.filters: computing revision filter for "visible"
+  M c
+  A d
+  R a
+  ! b
+
 Getting data about the working copy parent
 
   $ hg log -r '.' -T "{node}\n{date}\n"



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


D8089: py3: __repr__ needs to return str, not bytes

2020-02-06 Thread spectral (Kyle Lippincott)
Closed by commit rHGc443b9ba6f63: py3: __repr__ needs to return str, not bytes 
(authored by spectral).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8089?vs=19965=19969

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8089/new/

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

AFFECTED FILES
  mercurial/bundle2.py
  mercurial/linelog.py
  mercurial/manifest.py
  mercurial/patch.py

CHANGE DETAILS

diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -1090,6 +1090,7 @@
 def filename(self):
 return self.header.filename()
 
+@encoding.strmethod
 def __repr__(self):
 return b'' % (self.filename(), self.fromline)
 
diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -21,6 +21,7 @@
 )
 from .pycompat import getattr
 from . import (
+encoding,
 error,
 mdiff,
 pathutil,
@@ -867,9 +868,10 @@
 self._loadalllazy()
 return not self._dirs or all(m._isempty() for m in self._dirs.values())
 
+@encoding.strmethod
 def __repr__(self):
 return (
-b''
+b''
 % (
 self._dir,
 hex(self._node),
diff --git a/mercurial/linelog.py b/mercurial/linelog.py
--- a/mercurial/linelog.py
+++ b/mercurial/linelog.py
@@ -255,7 +255,7 @@
 )
 
 def __repr__(self):
-return b'' % (
+return '' % (
 hex(id(self)),
 self._maxrev,
 len(self._program),
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -1013,6 +1013,7 @@
 self._generated = None
 self.mandatory = mandatory
 
+@encoding.strmethod
 def __repr__(self):
 cls = b"%s.%s" % (self.__class__.__module__, self.__class__.__name__)
 return b'<%s object at %x; id: %s; type: %s; mandatory: %s>' % (



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


D7963: lfs: enable workers by default

2020-02-06 Thread mharbison72 (Matt Harbison)
Closed by commit rHG87167caa2989: lfs: enable workers by default (authored by 
mharbison72).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7963?vs=19497=19974

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7963/new/

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

AFFECTED FILES
  hgext/lfs/TODO.rst
  hgext/lfs/__init__.py
  tests/test-lfs-serve-access.t
  tests/test-lfs-serve.t
  tests/test-lfs-test-server.t

CHANGE DETAILS

diff --git a/tests/test-lfs-test-server.t b/tests/test-lfs-test-server.t
--- a/tests/test-lfs-test-server.t
+++ b/tests/test-lfs-test-server.t
@@ -40,6 +40,8 @@
 #endif
 
   $ cat >> $HGRCPATH < [experimental]
+  > lfs.worker-enable = False
   > [extensions]
   > lfs=
   > [lfs]
diff --git a/tests/test-lfs-serve.t b/tests/test-lfs-serve.t
--- a/tests/test-lfs-serve.t
+++ b/tests/test-lfs-serve.t
@@ -65,6 +65,7 @@
   > debugprocessors = $TESTTMP/debugprocessors.py
   > [experimental]
   > lfs.disableusercache = True
+  > lfs.worker-enable = False
   > [lfs]
   > threshold=10
   > [web]
diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t
--- a/tests/test-lfs-serve-access.t
+++ b/tests/test-lfs-serve-access.t
@@ -17,6 +17,7 @@
   $ hg init server
   $ hg --config "lfs.usercache=$TESTTMP/servercache" \
   >--config experimental.lfs.serve=False -R server serve -d \
+  >--config experimental.lfs.worker-enable=False \
   >-p $HGPORT --pid-file=hg.pid -A $TESTTMP/access.log -E 
$TESTTMP/errors.log
   $ cat hg.pid >> $DAEMON_PIDS
 
diff --git a/hgext/lfs/__init__.py b/hgext/lfs/__init__.py
--- a/hgext/lfs/__init__.py
+++ b/hgext/lfs/__init__.py
@@ -181,7 +181,7 @@
 b'experimental', b'lfs.disableusercache', default=False,
 )
 eh.configitem(
-b'experimental', b'lfs.worker-enable', default=False,
+b'experimental', b'lfs.worker-enable', default=True,
 )
 
 eh.configitem(
diff --git a/hgext/lfs/TODO.rst b/hgext/lfs/TODO.rst
--- a/hgext/lfs/TODO.rst
+++ b/hgext/lfs/TODO.rst
@@ -38,9 +38,6 @@
 
* `hg diff` is similar, and probably shouldn't see the pointer file
 
-#. `Fix https multiplexing, and re-enable workers
-   
`_.
-
 #. Show to-be-applied rules with `hg files -r 'wdir()' 'set:lfs()'`
 
* `debugignore` can show file + line number, so a dedicated command could be



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


D7901: merge: introduce a revert_to() for that use-case

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
Closed by commit rHGc791ed6a2154: merge: introduce a revert_to() for that 
use-case (authored by martinvonz).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7901?vs=19930=19971

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7901/new/

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

AFFECTED FILES
  hgext/fix.py
  mercurial/cmdutil.py
  mercurial/merge.py

CHANGE DETAILS

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -2225,6 +2225,7 @@
 labels=None,
 matcher=None,
 mergeforce=False,
+updatedirstate=True,
 updatecheck=None,
 wc=None,
 ):
@@ -2523,7 +2524,7 @@
 # If we're doing a partial update, we need to skip updating
 # the dirstate.
 always = matcher is None or matcher.always()
-updatedirstate = always and not wc.isinmemory()
+updatedirstate = updatedirstate and always and not wc.isinmemory()
 if updatedirstate:
 repo.hook(b'preupdate', throw=True, parent1=xp1, parent2=xp2)
 # note that we're in the middle of an update
@@ -2606,6 +2607,24 @@
 return update(ctx.repo(), ctx.rev(), branchmerge=False, force=True, wc=wc)
 
 
+def revert_to(ctx, matcher=None, wc=None):
+"""Revert the working copy to the given commit.
+
+The working copy will keep its current parent(s) but its content will
+be the same as in the given commit.
+"""
+
+return update(
+ctx.repo(),
+ctx.rev(),
+branchmerge=False,
+force=True,
+updatedirstate=False,
+matcher=matcher,
+wc=wc,
+)
+
+
 def graft(
 repo,
 ctx,
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -584,15 +584,8 @@
 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
 # 3a. apply filtered patch to clean repo  (clean)
 if backups:
-# Equivalent to hg.revert
 m = scmutil.matchfiles(repo, set(backups.keys()) | alsorestore)
-mergemod.update(
-repo,
-repo.dirstate.p1(),
-branchmerge=False,
-force=True,
-matcher=m,
-)
+mergemod.revert_to(repo[b'.'], matcher=m)
 
 # 3b. (apply)
 if dopatch:
diff --git a/hgext/fix.py b/hgext/fix.py
--- a/hgext/fix.py
+++ b/hgext/fix.py
@@ -735,15 +735,7 @@
 
 wctx = context.overlayworkingctx(repo)
 wctx.setbase(repo[newp1node])
-merge.update(
-repo,
-ctx.rev(),
-branchmerge=False,
-force=True,
-ancestor=p1rev,
-mergeancestor=False,
-wc=wctx,
-)
+merge.revert_to(ctx, wc=wctx)
 copies.graftcopies(wctx, ctx, ctx.p1())
 
 for path in filedata.keys():



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


D7871: rust-utils: add util for canonical path

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> files.rs:231
> +}
> +auditor.audit_path(path_to_hg_path_buf(name)?)?;
> +return Ok(name.to_owned());

Related to the comment above, this seems to (generally) return an absolute 
parent directory instead of a repo-relative path. Try adding a `println!()` 
just inside the `if same` to make sure you have test coverage.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7871/new/

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

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


D7962: lfs: fix the stall and corruption issue when concurrently uploading blobs

2020-02-06 Thread mharbison72 (Matt Harbison)
Closed by commit rHG43eea17ae7b3: lfs: fix the stall and corruption issue when 
concurrently uploading blobs (authored by mharbison72).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7962?vs=19496=19973

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7962/new/

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

AFFECTED FILES
  hgext/lfs/blobstore.py

CHANGE DETAILS

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -21,6 +21,7 @@
 from mercurial import (
 encoding,
 error,
+httpconnection as httpconnectionmod,
 node,
 pathutil,
 pycompat,
@@ -94,28 +95,16 @@
 pass
 
 
-class lfsuploadfile(object):
-"""a file-like object that supports __len__ and read.
+class lfsuploadfile(httpconnectionmod.httpsendfile):
+"""a file-like object that supports keepalive.
 """
 
-def __init__(self, fp):
-self._fp = fp
-fp.seek(0, os.SEEK_END)
-self._len = fp.tell()
-fp.seek(0)
-
-def __len__(self):
-return self._len
+def __init__(self, ui, filename):
+super(lfsuploadfile, self).__init__(ui, filename, b'rb')
+self.read = self._data.read
 
-def read(self, size):
-if self._fp is None:
-return b''
-return self._fp.read(size)
-
-def close(self):
-if self._fp is not None:
-self._fp.close()
-self._fp = None
+def _makeprogress(self):
+return None  # progress is handled by the worker client
 
 
 class local(object):
@@ -507,10 +496,10 @@
 
 try:
 if action == b'upload':
-request.data = lfsuploadfile(localstore.open(oid))
+request.data = lfsuploadfile(self.ui, localstore.path(oid))
 request.get_method = lambda: 'PUT'
 request.add_header('Content-Type', 'application/octet-stream')
-request.add_header('Content-Length', len(request.data))
+request.add_header('Content-Length', request.data.length)
 
 with contextlib.closing(self.urlopener.open(request)) as res:
 contentlength = res.info().get(b"content-length")



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


D7961: lfs: add a method to the local blobstore to convert OIDs to file paths

2020-02-06 Thread mharbison72 (Matt Harbison)
Closed by commit rHG06de4a673f48: lfs: add a method to the local blobstore to 
convert OIDs to file paths (authored by mharbison72).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7961?vs=19495=19972

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7961/new/

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

AFFECTED FILES
  hgext/lfs/blobstore.py

CHANGE DETAILS

diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py
--- a/hgext/lfs/blobstore.py
+++ b/hgext/lfs/blobstore.py
@@ -139,6 +139,17 @@
 def open(self, oid):
 """Open a read-only file descriptor to the named blob, in either the
 usercache or the local store."""
+return open(self.path(oid), b'rb')
+
+def path(self, oid):
+"""Build the path for the given blob ``oid``.
+
+If the blob exists locally, the path may point to either the usercache
+or the local store.  If it doesn't, it will point to the local store.
+This is meant for situations where existing code that isn't LFS aware
+needs to open a blob.  Generally, prefer the ``open`` method on this
+class.
+"""
 # The usercache is the most likely place to hold the file.  Commit will
 # write to both it and the local store, as will anything that downloads
 # the blobs.  However, things like clone without an update won't
@@ -146,9 +157,9 @@
 # the usercache is the only place it _could_ be.  If not present, the
 # missing file msg here will indicate the local repo, not the 
usercache.
 if self.cachevfs.exists(oid):
-return self.cachevfs(oid, b'rb')
+return self.cachevfs.join(oid)
 
-return self.vfs(oid, b'rb')
+return self.vfs.join(oid)
 
 def download(self, oid, src, content_length):
 """Read the blob from the remote source in chunks, verify the content,



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


D8081: manifest: fix _very_ subtle bug with exact matchers passed to walk()

2020-02-06 Thread durin42 (Augie Fackler)
Closed by commit rHG48a1a974a92c: manifest: fix _very_ subtle bug with exact 
matchers passed to walk() (authored by durin42).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8081?vs=19924=19968

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8081/new/

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

AFFECTED FILES
  mercurial/manifest.py

CHANGE DETAILS

diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -530,7 +530,8 @@
 # avoid the entire walk if we're only looking for specific files
 if self._filesfastpath(match):
 for fn in sorted(fset):
-yield fn
+if fn in self:
+yield fn
 return
 
 for fn in self:



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


D8090: archival: use walk() instead of matches() on manifest

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

REVISION SUMMARY
  All we care about is the filepaths, so this avoids a pointless copy of the
  manifest that we only used to extract matching filenames.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  mercurial/archival.py

CHANGE DETAILS

diff --git a/mercurial/archival.py b/mercurial/archival.py
--- a/mercurial/archival.py
+++ b/mercurial/archival.py
@@ -355,7 +355,7 @@
 if match(name):
 write(name, 0o644, False, lambda: buildmetadata(ctx))
 
-files = [f for f in ctx.manifest().matches(match)]
+files = list(ctx.manifest().walk(match))
 total = len(files)
 if total:
 files.sort()



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


D8083: archival: use walk() instead of matches() on manifest

2020-02-06 Thread durin42 (Augie Fackler)
durin42 updated this revision to Diff 19966.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8083?vs=19952=19966

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8083/new/

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

AFFECTED FILES
  mercurial/archival.py

CHANGE DETAILS

diff --git a/mercurial/archival.py b/mercurial/archival.py
--- a/mercurial/archival.py
+++ b/mercurial/archival.py
@@ -355,7 +355,7 @@
 if match(name):
 write(name, 0o644, False, lambda: buildmetadata(ctx))
 
-files = [f for f in ctx.manifest().matches(match)]
+files = list(ctx.manifest().walk(match))
 total = len(files)
 if total:
 files.sort()



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


D8078: copies: add a new test dedicated to testing chain of changeset with merge

2020-02-06 Thread marmoute (Pierre-Yves David)
marmoute added a comment.


  Yeah, not it is. I added extra comment and output to review and clarify 
things.
  
  FYI, coming next on this topic is fixing some inconsistency and then fixing 
then changeset centric behavior. (but do not hold your breath, nodemap has an 
higher priority)

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8078/new/

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

To: marmoute, #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


D7871: rust-utils: add util for canonical path

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> Alphare wrote in files.rs:220-222
> I could reword this sentence if you feel that it does not convey the same 
> meaning. It fits the Python implementation better, that's for sure.

To me, the current sentence very much makes it sound like it iterates until 
`name != name.parent()`, which doesn't seem correct. So, yes, please reword it. 
(Unless I'm just misunderstanding something.)

> Alphare wrote in files.rs:227-230
> For `b'/'` it would return `Some(std::Path::Components::RootDir)`. It only 
> returns `None` if there are no components.

Okay, but it seems that that doesn't address my concern. If I understand 
correctly (now that you've corrected me), we get here if `name == ""`. However, 
name is an absolute path (right?), so with `root = "/some/path/"` and `name = 
""`, why should we return `Ok()`? If `name` is indeed an absolute path, I would 
interpret "" as the root (file system root, not repo root), which is not inside 
"/some/path". What am I missing?

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7871/new/

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

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


D7871: rust-utils: add util for canonical path

2020-02-06 Thread Raphaël Gomès
Alphare added inline comments.

INLINE COMMENTS

> martinvonz wrote in files.rs:207-216
> Might be worth having a fast path for when `name` is not absolute (including 
> "") and neither `name` nor `cwd` contains "../"so we don't do `let name = 
> root.join().join()` immediately followed by `let name = 
> name.strip_prefix().unwrap()`. Especially since that seems like the 
> common case. Or can that ever produce different results? Anyway, that can be 
> done later.

That might be worth investigating indeed. I will defer to a later time, though. 
:)

> martinvonz wrote in files.rs:220-222
> Is this accurate? It looks like we break when `name.parent() == None`.

I could reword this sentence if you feel that it does not convey the same 
meaning. It fits the Python implementation better, that's for sure.

> martinvonz wrote in files.rs:227-230
> `name.components().next()` will be `None` only if `name` is something like 
> "/", right? But then we shouldn't return "" (a repo-relative path), we should 
> error out.

For `b'/'` it would return `Some(std::Path::Components::RootDir)`. It only 
returns `None` if there are no components.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7871/new/

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

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


D8078: copies: add a new test dedicated to testing chain of changeset with merge

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


  In D8078#119493 , @marmoute 
wrote:
  
  > oops, this one got out by mistake.
  
  But now it's ready for review (seems ready to me)? Thanks for adding these 
tests.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8078/new/

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

To: marmoute, #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


D8089: py3: __repr__ needs to return str, not bytes

2020-02-06 Thread mharbison72 (Matt Harbison)
mharbison72 added inline comments.

INLINE COMMENTS

> bundle2.py:1018
>  def __repr__(self):
>  cls = b"%s.%s" % (self.__class__.__module__, self.__class__.__name__)
>  return b'<%s object at %x; id: %s; type: %s; mandatory: %s>' % (

Aren't `self.__class__.__module__` and `self.__class__.__name__` str?

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8089/new/

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

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


D8089: py3: __repr__ needs to return str, not bytes

2020-02-06 Thread marmoute (Pierre-Yves David)
marmoute added a comment.
marmoute accepted this revision.


  looks good.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8089/new/

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

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


D7927: rust-status: add util for listing a directory

2020-02-06 Thread marmoute (Pierre-Yves David)
marmoute added inline comments.

INLINE COMMENTS

> Alphare wrote in status.rs:74
> I'm not entirely sure I understand your question.

If I understand you code correctly you currently do:

  filenames = listdir()
  result = [(f, entry(f)) for f in filenames]
  result.sort()

Would it make sense to do:

  filenames = listdir()
  filenames.sort()
  result = [(f, entry(f)) for f in filenames]

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7927/new/

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

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


D7929: rust-status: add bare `hg status` support in hg-core

2020-02-06 Thread marmoute (Pierre-Yves David)
marmoute added inline comments.

INLINE COMMENTS

> Alphare wrote in status.rs:29-38
> I was fixing conflicts and prefer this style. `rustfmt` does not nest already 
> separate imports. If that's an issue I suppose I can change it.

This is not an issue, but this add noise that distract from the core of the 
patch. Consider doing this kind og small change in independant changesets.

> Alphare wrote in status.rs:241
> Clarified in the updated inline comment. I mainly wanted to avoid even more 
> code that had very little chance of being useful. If you disagree, please let 
> me know.

It is still not very clear to me. Do we have BadType case where it would make 
sense to use somethign else than Unknown?

> Alphare wrote in status.rs:656
> Oops, it's "insensitive", not "sensitive".

So, right now, the status code do now work on case insensitive file system. I 
assume the proper gards are in place at a higher level ?

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7929/new/

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

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


D8089: py3: __repr__ needs to return str, not bytes

2020-02-06 Thread spectral (Kyle Lippincott)
spectral created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  mercurial/bundle2.py
  mercurial/linelog.py
  mercurial/manifest.py
  mercurial/patch.py

CHANGE DETAILS

diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -1090,6 +1090,7 @@
 def filename(self):
 return self.header.filename()
 
+@encoding.strmethod
 def __repr__(self):
 return b'' % (self.filename(), self.fromline)
 
diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -21,6 +21,7 @@
 )
 from .pycompat import getattr
 from . import (
+encoding,
 error,
 mdiff,
 pathutil,
@@ -867,9 +868,10 @@
 self._loadalllazy()
 return not self._dirs or all(m._isempty() for m in self._dirs.values())
 
+@encoding.strmethod
 def __repr__(self):
 return (
-b''
+b''
 % (
 self._dir,
 hex(self._node),
diff --git a/mercurial/linelog.py b/mercurial/linelog.py
--- a/mercurial/linelog.py
+++ b/mercurial/linelog.py
@@ -255,7 +255,7 @@
 )
 
 def __repr__(self):
-return b'' % (
+return '' % (
 hex(id(self)),
 self._maxrev,
 len(self._program),
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -1013,6 +1013,7 @@
 self._generated = None
 self.mandatory = mandatory
 
+@encoding.strmethod
 def __repr__(self):
 cls = b"%s.%s" % (self.__class__.__module__, self.__class__.__name__)
 return b'<%s object at %x; id: %s; type: %s; mandatory: %s>' % (



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


mercurial@44246: 4 new changesets (4 on stable)

2020-02-06 Thread Mercurial Commits
4 new changesets (4 on stable) in mercurial:

https://www.mercurial-scm.org/repo/hg/rev/238790674d69
changeset:   44243:238790674d69
branch:  stable
user:Pierre-Yves David 
date:Tue Feb 04 12:31:19 2020 +0100
summary: config: add a function in `rcutil` to abstract HGRCSKIPREPO

https://www.mercurial-scm.org/repo/hg/rev/ef11dfc56674
changeset:   44244:ef11dfc56674
branch:  stable
user:Pierre-Yves David 
date:Mon Feb 03 20:41:11 2020 +0100
summary: config: also respect HGRCSKIPREPO in `dispatch._getlocal`

https://www.mercurial-scm.org/repo/hg/rev/bf23d6ee7ec7
changeset:   44245:bf23d6ee7ec7
branch:  stable
user:Pierre-Yves David 
date:Tue Feb 04 12:07:42 2020 +0100
summary: config: also respect HGRCSKIPREPO in hgwebdir_mod

https://www.mercurial-scm.org/repo/hg/rev/eecc005229ff
changeset:   44246:eecc005229ff
branch:  stable
tag: tip
user:Pierre-Yves David 
date:Tue Feb 04 12:07:37 2020 +0100
summary: config: also respect HGRCSKIPREPO in the zeroconf extension

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


D7871: rust-utils: add util for canonical path

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
This revision now requires changes to proceed.
martinvonz added inline comments.
martinvonz requested changes to this revision.

INLINE COMMENTS

> files.rs:207-216
> +let name = if !name.is_absolute() {
> +root.join().join()
> +} else {
> +name.to_owned()
> +};
> +let mut auditor = PathAuditor::new();
> +if name != root && name.starts_with() {

Might be worth having a fast path for when `name` is not absolute (including 
"") and neither `name` nor `cwd` contains "../"so we don't do `let name = 
root.join().join()` immediately followed by `let name = 
name.strip_prefix().unwrap()`. Especially since that seems like the common 
case. Or can that ever produce different results? Anyway, that can be done 
later.

> files.rs:220-222
> +// Determine whether `name' is in the hierarchy at or beneath `root',
> +// by iterating name=name.parent() until that causes no change (can't
> +// check name == '/', because that doesn't work on windows).

Is this accurate? It looks like we break when `name.parent() == None`.

> files.rs:227-230
> +if name.components().next().is_none() {
> +// `name` was actually the same as root (maybe a symlink)
> +return Ok("".into());
> +}

`name.components().next()` will be `None` only if `name` is something like "/", 
right? But then we shouldn't return "" (a repo-relative path), we should error 
out.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7871/new/

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

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


D7870: rust-utils: add `Escaped` trait

2020-02-06 Thread Raphaël Gomès
Closed by commit rHGaa0fc32ece9e: rust-utils: add `Escaped` trait (authored by 
Alphare).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7870?vs=19958=19964

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7870/new/

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

AFFECTED FILES
  rust/hg-core/src/utils.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils.rs b/rust/hg-core/src/utils.rs
--- a/rust/hg-core/src/utils.rs
+++ b/rust/hg-core/src/utils.rs
@@ -7,6 +7,9 @@
 
 //! Contains useful functions, traits, structs, etc. for use in core.
 
+use crate::utils::hg_path::HgPath;
+use std::{io::Write, ops::Deref};
+
 pub mod files;
 pub mod hg_path;
 pub mod path_auditor;
@@ -112,3 +115,54 @@
 }
 }
 }
+
+pub trait Escaped {
+/// Return bytes escaped for display to the user
+fn escaped_bytes() -> Vec;
+}
+
+impl Escaped for u8 {
+fn escaped_bytes() -> Vec {
+let mut acc = vec![];
+match self {
+c @ b'\'' | c @ b'\\' => {
+acc.push(b'\\');
+acc.push(*c);
+}
+b'\t' => {
+acc.extend(br"\\t");
+}
+b'\n' => {
+acc.extend(br"\\n");
+}
+b'\r' => {
+acc.extend(br"\\r");
+}
+c if (*c < b' ' || *c >= 127) => {
+write!(acc, "\\x{:x}", self).unwrap();
+}
+c => {
+acc.push(*c);
+}
+}
+acc
+}
+}
+
+impl<'a, T: Escaped> Escaped for &'a [T] {
+fn escaped_bytes() -> Vec {
+self.iter().flat_map(|item| item.escaped_bytes()).collect()
+}
+}
+
+impl Escaped for Vec {
+fn escaped_bytes() -> Vec {
+self.deref().escaped_bytes()
+}
+}
+
+impl<'a> Escaped for &'a HgPath {
+fn escaped_bytes() -> Vec {
+self.as_bytes().escaped_bytes()
+}
+}



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


D8083: archival: use walk() instead of matches() on manifest

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


  Oops, I queued this one out of order because I wanted to think more about the 
previous two patches first, but that made `test-subrepo-deep-nested-change.t` 
fail. I should have known there was a reason for the order in this series. I'll 
de-queue this one for now, so please revive your local copy.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8083/new/

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

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


D7982: rust-utils: introduce `subslice_index` function

2020-02-06 Thread Raphaël Gomès
Alphare added a comment.
Alphare abandoned this revision.


  I was certain to have pruned this one. I'll do it.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7982/new/

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

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


D7982: rust-utils: introduce `subslice_index` function

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19959.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7982?vs=19547=19959

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7982/new/

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

AFFECTED FILES
  rust/hg-core/src/utils.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils.rs b/rust/hg-core/src/utils.rs
--- a/rust/hg-core/src/utils.rs
+++ b/rust/hg-core/src/utils.rs
@@ -61,6 +61,36 @@
 }
 }
 
+/// Find the offset of the subslice relative to the original collection
+///
+/// This function panics for zero-sized types.
+/// # Examples:
+///
+/// ```
+/// use crate::hg::utils::subslice_offset;
+/// let mut line = b"Subslice me!".to_vec();
+/// assert_eq!(subslice_offset(, [8..]), Some(8));
+///
+/// assert_eq!(subslice_offset(, b"hahaha"), None);
+///
+/// // Empty array
+/// let v: [u8; 0] = [];
+/// assert_eq!(subslice_offset(, ), Some(0));
+/// assert_eq!(subslice_offset(, b"hehe"), None);
+/// ```
+pub fn subslice_offset(outer: &[T], inner: &[T]) -> Option {
+let pointee_size = std::mem::size_of::();
+assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize);
+
+let outer_start = outer.as_ptr() as usize;
+let inner = inner.as_ptr() as usize;
+if inner < outer_start || inner > outer_start.wrapping_add(outer.len()) {
+None
+} else {
+Some(inner.wrapping_sub(outer_start))
+}
+}
+
 pub trait SliceExt {
 fn trim_end() -> 
 fn trim_start() -> 



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


D7869: rust-dirs-multiset: add `DirsChildrenMultiset`

2020-02-06 Thread Raphaël Gomès
Closed by commit rHG2dca0d76358c: rust-dirs-multiset: add 
`DirsChildrenMultiset` (authored by Alphare).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7869?vs=19936=19957

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7869/new/

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

AFFECTED FILES
  rust/hg-core/src/dirstate/dirs_multiset.rs
  rust/hg-core/src/utils/files.rs
  rust/hg-core/src/utils/hg_path.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils/hg_path.rs 
b/rust/hg-core/src/utils/hg_path.rs
--- a/rust/hg-core/src/utils/hg_path.rs
+++ b/rust/hg-core/src/utils/hg_path.rs
@@ -183,6 +183,29 @@
 [..]
 })
 }
+/// Returns a tuple of slices `(base, filename)` resulting from the split
+/// at the rightmost `/`, if any.
+///
+/// # Examples:
+///
+/// ```
+/// use hg::utils::hg_path::HgPath;
+///
+/// let path = HgPath::new(b"cool/hg/path").split_filename();
+/// assert_eq!(path, (HgPath::new(b"cool/hg"), HgPath::new(b"path")));
+///
+/// let path = HgPath::new(b"pathwithoutsep").split_filename();
+/// assert_eq!(path, (HgPath::new(b""), HgPath::new(b"pathwithoutsep")));
+/// ```
+pub fn split_filename() -> (, ) {
+match ().rposition(|c| *c == b'/') {
+None => (HgPath::new(""), ),
+Some(size) => (
+HgPath::new([..*size]),
+HgPath::new([*size + 1..]),
+),
+}
+}
 pub fn join>(, other: ) -> HgPathBuf {
 let mut inner = self.inner.to_owned();
 if inner.len() != 0 && inner.last() != Some('/') {
diff --git a/rust/hg-core/src/utils/files.rs b/rust/hg-core/src/utils/files.rs
--- a/rust/hg-core/src/utils/files.rs
+++ b/rust/hg-core/src/utils/files.rs
@@ -10,11 +10,11 @@
 //! Functions for fiddling with files.
 
 use crate::utils::hg_path::{HgPath, HgPathBuf};
-use std::iter::FusedIterator;
 
 use crate::utils::replace_slice;
 use lazy_static::lazy_static;
 use std::fs::Metadata;
+use std::iter::FusedIterator;
 use std::path::Path;
 
 pub fn get_path_from_bytes(bytes: &[u8]) ->  {
@@ -64,6 +64,28 @@
 
 impl<'a> FusedIterator for Ancestors<'a> {}
 
+/// An iterator over repository path yielding itself and its ancestors.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct AncestorsWithBase<'a> {
+next: Option<(&'a HgPath, &'a HgPath)>,
+}
+
+impl<'a> Iterator for AncestorsWithBase<'a> {
+type Item = (&'a HgPath, &'a HgPath);
+
+fn next( self) -> Option {
+let next = self.next;
+self.next = match self.next {
+Some((s, _)) if s.is_empty() => None,
+Some((s, _)) => Some(s.split_filename()),
+None => None,
+};
+next
+}
+}
+
+impl<'a> FusedIterator for AncestorsWithBase<'a> {}
+
 /// Returns an iterator yielding ancestor directories of the given repository
 /// path.
 ///
@@ -79,6 +101,25 @@
 dirs
 }
 
+/// Returns an iterator yielding ancestor directories of the given repository
+/// path.
+///
+/// The path is separated by '/', and must not start with '/'.
+///
+/// The path itself isn't included unless it is b"" (meaning the root
+/// directory.)
+pub(crate) fn find_dirs_with_base<'a>(
+path: &'a HgPath,
+) -> AncestorsWithBase<'a> {
+let mut dirs = AncestorsWithBase {
+next: Some((path, HgPath::new(b""))),
+};
+if !path.is_empty() {
+dirs.next(); // skip itself
+}
+dirs
+}
+
 /// TODO more than ASCII?
 pub fn normalize_case(path: ) -> HgPathBuf {
 #[cfg(windows)] // NTFS compares via upper()
@@ -170,4 +211,28 @@
 assert_eq!(dirs.next(), None);
 assert_eq!(dirs.next(), None);
 }
+
+#[test]
+fn test_find_dirs_with_base_some() {
+let mut dirs = super::find_dirs_with_base(HgPath::new(b"foo/bar/baz"));
+assert_eq!(
+dirs.next(),
+Some((HgPath::new(b"foo/bar"), HgPath::new(b"baz")))
+);
+assert_eq!(
+dirs.next(),
+Some((HgPath::new(b"foo"), HgPath::new(b"bar")))
+);
+assert_eq!(dirs.next(), Some((HgPath::new(b""), HgPath::new(b"foo";
+assert_eq!(dirs.next(), None);
+assert_eq!(dirs.next(), None);
+}
+
+#[test]
+fn test_find_dirs_with_base_empty() {
+let mut dirs = super::find_dirs_with_base(HgPath::new(b""));
+assert_eq!(dirs.next(), Some((HgPath::new(b""), HgPath::new(b"";
+assert_eq!(dirs.next(), None);
+assert_eq!(dirs.next(), None);
+}
 }
diff --git a/rust/hg-core/src/dirstate/dirs_multiset.rs 
b/rust/hg-core/src/dirstate/dirs_multiset.rs
--- a/rust/hg-core/src/dirstate/dirs_multiset.rs
+++ b/rust/hg-core/src/dirstate/dirs_multiset.rs
@@ -8,12 +8,15 @@
 //! A multiset of directory names.
 //!

D7870: rust-utils: add `Escaped` trait

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19958.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7870?vs=19348=19958

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7870/new/

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

AFFECTED FILES
  rust/hg-core/src/utils.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils.rs b/rust/hg-core/src/utils.rs
--- a/rust/hg-core/src/utils.rs
+++ b/rust/hg-core/src/utils.rs
@@ -7,6 +7,9 @@
 
 //! Contains useful functions, traits, structs, etc. for use in core.
 
+use crate::utils::hg_path::HgPath;
+use std::{io::Write, ops::Deref};
+
 pub mod files;
 pub mod hg_path;
 pub mod path_auditor;
@@ -112,3 +115,54 @@
 }
 }
 }
+
+pub trait Escaped {
+/// Return bytes escaped for display to the user
+fn escaped_bytes() -> Vec;
+}
+
+impl Escaped for u8 {
+fn escaped_bytes() -> Vec {
+let mut acc = vec![];
+match self {
+c @ b'\'' | c @ b'\\' => {
+acc.push(b'\\');
+acc.push(*c);
+}
+b'\t' => {
+acc.extend(br"\\t");
+}
+b'\n' => {
+acc.extend(br"\\n");
+}
+b'\r' => {
+acc.extend(br"\\r");
+}
+c if (*c < b' ' || *c >= 127) => {
+write!(acc, "\\x{:x}", self).unwrap();
+}
+c => {
+acc.push(*c);
+}
+}
+acc
+}
+}
+
+impl<'a, T: Escaped> Escaped for &'a [T] {
+fn escaped_bytes() -> Vec {
+self.iter().flat_map(|item| item.escaped_bytes()).collect()
+}
+}
+
+impl Escaped for Vec {
+fn escaped_bytes() -> Vec {
+self.deref().escaped_bytes()
+}
+}
+
+impl<'a> Escaped for &'a HgPath {
+fn escaped_bytes() -> Vec {
+self.as_bytes().escaped_bytes()
+}
+}



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


D7867: rust-hg-path: add useful methods to `HgPath`

2020-02-06 Thread Raphaël Gomès
Closed by commit rHGe1ba9c5d5e78: rust-hg-path: add useful methods to `HgPath` 
(authored by Alphare).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7867?vs=19935=19956

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7867/new/

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

AFFECTED FILES
  rust/Cargo.lock
  rust/hg-core/Cargo.toml
  rust/hg-core/src/utils/hg_path.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils/hg_path.rs 
b/rust/hg-core/src/utils/hg_path.rs
--- a/rust/hg-core/src/utils/hg_path.rs
+++ b/rust/hg-core/src/utils/hg_path.rs
@@ -173,10 +173,17 @@
 pub fn contains(, other: u8) -> bool {
 self.inner.contains()
 }
-pub fn starts_with(, needle: impl AsRef) -> bool {
+pub fn starts_with(, needle: impl AsRef) -> bool {
 self.inner.starts_with(needle.as_ref().as_bytes())
 }
-pub fn join>(, other: ) -> HgPathBuf {
+pub fn trim_trailing_slash() ->  {
+Self::new(if self.inner.last() == Some('/') {
+[..self.inner.len() - 1]
+} else {
+[..]
+})
+}
+pub fn join>(, other: ) -> HgPathBuf {
 let mut inner = self.inner.to_owned();
 if inner.len() != 0 && inner.last() != Some('/') {
 inner.push(b'/');
@@ -184,17 +191,24 @@
 inner.extend(other.as_ref().bytes());
 HgPathBuf::from_bytes()
 }
+pub fn parent() ->  {
+let inner = self.as_bytes();
+HgPath::new(match inner.iter().rposition(|b| *b == b'/') {
+Some(pos) => [..pos],
+None => &[],
+})
+}
 /// Given a base directory, returns the slice of `self` relative to the
 /// base directory. If `base` is not a directory (does not end with a
 /// `b'/'`), returns `None`.
-pub fn relative_to(, base: impl AsRef) -> Option<> {
+pub fn relative_to(, base: impl AsRef) -> Option<> {
 let base = base.as_ref();
 if base.is_empty() {
 return Some(self);
 }
 let is_dir = base.as_bytes().ends_with(b"/");
 if is_dir && self.starts_with(base) {
-Some(HgPath::new([base.len()..]))
+Some(Self::new([base.len()..]))
 } else {
 None
 }
@@ -484,6 +498,7 @@
 #[cfg(test)]
 mod tests {
 use super::*;
+use pretty_assertions::assert_eq;
 
 #[test]
 fn test_path_states() {
@@ -712,4 +727,19 @@
 )
 );
 }
+
+#[test]
+fn test_parent() {
+let path = HgPath::new(b"");
+assert_eq!(path.parent(), path);
+
+let path = HgPath::new(b"a");
+assert_eq!(path.parent(), HgPath::new(b""));
+
+let path = HgPath::new(b"a/b");
+assert_eq!(path.parent(), HgPath::new(b"a"));
+
+let path = HgPath::new(b"a/other/b");
+assert_eq!(path.parent(), HgPath::new(b"a/other"));
+}
 }
diff --git a/rust/hg-core/Cargo.toml b/rust/hg-core/Cargo.toml
--- a/rust/hg-core/Cargo.toml
+++ b/rust/hg-core/Cargo.toml
@@ -20,4 +20,5 @@
 twox-hash = "1.5.0"
 
 [dev-dependencies]
-tempfile = "3.1.0"
\ No newline at end of file
+tempfile = "3.1.0"
+pretty_assertions = "0.6.1"
\ No newline at end of file
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -2,13 +2,21 @@
 # It is not intended for manual editing.
 [[package]]
 name = "aho-corasick"
-version = "0.7.7"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index;
 dependencies = [
  "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index;
+dependencies = [
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "autocfg"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index;
@@ -51,13 +59,13 @@
 
 [[package]]
 name = "cpython"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index;
 dependencies = [
  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "python27-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "python3-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -102,6 +110,20 @@
 ]
 
 [[package]]
+name = "ctor"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index;
+dependencies = [
+ "quote 1.0.2 

D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread Raphaël Gomès
Alphare added inline comments.

INLINE COMMENTS

> martinvonz wrote in path_auditor.rs:191
> This test now fails. I'll fix it.

Right, sorry!

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

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


D7870: rust-utils: add `Escaped` trait

2020-02-06 Thread Raphaël Gomès
Alphare added inline comments.

INLINE COMMENTS

> martinvonz wrote in utils.rs:154-157
> i.e. `self.iter().flat_map(|item| item.escaped_bytes()).collect()`?

Sometimes I forget about `flat_map`. Thanks!

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7870/new/

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

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


D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> path_auditor.rs:191
> +auditor.audit_path(path),
> +Err(HgPathError::ContainsIllegalComponent(path.to_owned()))
> +);

This test now fails. I'll fix it.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

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


D7870: rust-utils: add `Escaped` trait

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
This revision now requires changes to proceed.
martinvonz added a comment.
martinvonz requested changes to this revision.


  I'm also not sure about the name, but I don't have a better proposal. We can 
revisit that later when it's clearer how it will be used.

INLINE COMMENTS

> utils.rs:154-157
> +self.iter().fold(vec![], |mut acc, item| {
> +acc.extend(item.escaped_bytes());
> +acc
> +})

i.e. `self.iter().flat_map(|item| item.escaped_bytes()).collect()`?

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7870/new/

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

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


D7867: rust-hg-path: add useful methods to `HgPath`

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> hg_path.rs:195
> +pub fn parent() ->  {
> +let inner = self.as_bytes();
> +HgPath::new(match inner.iter().rposition(|b| *b == b'/') {

Might be good to add an `assert!` here in case my assertion (that `HgPath` 
should never have a trailing `/`) is not correct.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7867/new/

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

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


D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread Raphaël Gomès
Closed by commit rHGa540e96b9029: rust-pathauditor: add Rust implementation of 
the `pathauditor` (authored by Alphare).
This revision was automatically updated to reflect the committed changes.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7866?vs=19934=19954

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

AFFECTED FILES
  rust/Cargo.lock
  rust/hg-core/Cargo.toml
  rust/hg-core/src/utils.rs
  rust/hg-core/src/utils/files.rs
  rust/hg-core/src/utils/hg_path.rs
  rust/hg-core/src/utils/path_auditor.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils/path_auditor.rs 
b/rust/hg-core/src/utils/path_auditor.rs
new file mode 100644
--- /dev/null
+++ b/rust/hg-core/src/utils/path_auditor.rs
@@ -0,0 +1,230 @@
+// path_auditor.rs
+//
+// Copyright 2020
+// Raphaël Gomès ,
+//
+// This software may be used and distributed according to the terms of the
+// GNU General Public License version 2 or any later version.
+
+use crate::utils::{
+files::lower_clean,
+find_slice_in_slice,
+hg_path::{hg_path_to_path_buf, HgPath, HgPathBuf, HgPathError},
+};
+use std::collections::HashSet;
+use std::path::{Path, PathBuf};
+
+/// Ensures that a path is valid for use in the repository i.e. does not use
+/// any banned components, does not traverse a symlink, etc.
+#[derive(Debug, Default)]
+pub struct PathAuditor {
+audited: HashSet,
+audited_dirs: HashSet,
+root: PathBuf,
+}
+
+impl PathAuditor {
+pub fn new(root: impl AsRef) -> Self {
+Self {
+root: root.as_ref().to_owned(),
+..Default::default()
+}
+}
+pub fn audit_path(
+ self,
+path: impl AsRef,
+) -> Result<(), HgPathError> {
+// TODO windows "localpath" normalization
+let path = path.as_ref();
+if path.is_empty() {
+return Ok(());
+}
+// TODO case normalization
+if self.audited.contains(path) {
+return Ok(());
+}
+// AIX ignores "/" at end of path, others raise EISDIR.
+let last_byte = path.as_bytes()[path.len() - 1];
+if last_byte == b'/' || last_byte == b'\\' {
+return Err(HgPathError::EndsWithSlash(path.to_owned()));
+}
+let parts: Vec<_> = path
+.as_bytes()
+.split(|b| std::path::is_separator(*b as char))
+.collect();
+
+let first_component = lower_clean(parts[0]);
+let first_component = first_component.as_slice();
+if !path.split_drive().0.is_empty()
+|| (first_component == b".hg"
+|| first_component == b".hg."
+|| first_component == b"")
+|| parts.iter().any(|c| c == b"..")
+{
+return Err(HgPathError::InsideDotHg(path.to_owned()));
+}
+
+// Windows shortname aliases
+for part in parts.iter() {
+if part.contains('~') {
+let mut split = part.splitn(1, |b| *b == b'~');
+let first =
+split.next().unwrap().to_owned().to_ascii_uppercase();
+let last = split.next().unwrap();
+if last.iter().all(u8::is_ascii_digit)
+&& (first == b"HG" || first == b"HG8B6C")
+{
+return Err(HgPathError::ContainsIllegalComponent(
+path.to_owned(),
+));
+}
+}
+}
+let lower_path = lower_clean(path.as_bytes());
+if find_slice_in_slice(_path, b".hg").is_some() {
+let lower_parts: Vec<_> = path
+.as_bytes()
+.split(|b| std::path::is_separator(*b as char))
+.collect();
+for pattern in [b".hg".to_vec(), b".hg.".to_vec()].iter() {
+if let Some(pos) = lower_parts[1..]
+.iter()
+.position(|part| part == _slice())
+{
+let base = lower_parts[..=pos]
+.iter()
+.fold(HgPathBuf::new(), |acc, p| {
+acc.join(HgPath::new(p))
+});
+return Err(HgPathError::IsInsideNestedRepo {
+path: path.to_owned(),
+nested_repo: base,
+});
+}
+}
+}
+
+let parts = [..parts.len().saturating_sub(1)];
+
+// We don't want to add "foo/bar/baz" to `audited_dirs` before checking
+// if there's a "foo/.hg" directory. This also means we won't
+// accidentally traverse a symlink into some other filesystem (which
+// is potentially expensive to access).
+for index in 0..parts.len() {
+let prefix = [..index + 1].join('/');
+let prefix = 

D7965: py3: catch AttributeError too with ImportError

2020-02-06 Thread pulkit (Pulkit Goyal)
Closed by commit rHG9a92b29cf930: py3: catch AttributeError too with 
ImportError (authored by pulkit).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7965?vs=19499=19953

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7965/new/

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

AFFECTED FILES
  mercurial/color.py
  mercurial/crecord.py
  tests/hghave.py

CHANGE DETAILS

diff --git a/tests/hghave.py b/tests/hghave.py
--- a/tests/hghave.py
+++ b/tests/hghave.py
@@ -685,7 +685,7 @@
 
 curses.COLOR_BLUE
 return matchoutput('test -x "`which tic`"', br'')
-except ImportError:
+except (ImportError, AttributeError):
 return False
 
 
diff --git a/mercurial/crecord.py b/mercurial/crecord.py
--- a/mercurial/crecord.py
+++ b/mercurial/crecord.py
@@ -63,13 +63,13 @@
 import curses.ascii
 
 curses.error
-except ImportError:
+except (ImportError, AttributeError):
 # I have no idea if wcurses works with crecord...
 try:
 import wcurses as curses
 
 curses.error
-except ImportError:
+except (ImportError, AttributeError):
 # wcurses is not shipped on Windows by default, or python is not
 # compiled with curses
 curses = False
diff --git a/mercurial/color.py b/mercurial/color.py
--- a/mercurial/color.py
+++ b/mercurial/color.py
@@ -44,7 +44,7 @@
 b'cyan': (False, curses.COLOR_CYAN, b''),
 b'white': (False, curses.COLOR_WHITE, b''),
 }
-except ImportError:
+except (ImportError, AttributeError):
 curses = None
 _baseterminfoparams = {}
 



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


D8080: context: use manifest.walk() instead of manifest.match() to get file list

2020-02-06 Thread durin42 (Augie Fackler)
Closed by commit rHGbeea86e4d332: context: use manifest.walk() instead of 
manifest.match() to get file list (authored by durin42).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8080?vs=19923=19951

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8080/new/

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

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
@@ -2357,8 +2357,7 @@
 # Test the other direction -- that this path from p2 isn't a directory
 # in p1 (test that p1 doesn't have any paths matching `path/*`).
 match = self.match([path], default=b'path')
-matches = self.p1().manifest().matches(match)
-mfiles = matches.keys()
+mfiles = list(self.p1().manifest().walk(match))
 if len(mfiles) > 0:
 if len(mfiles) == 1 and mfiles[0] == path:
 return



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


D8079: manifest: remove `.new()` from the interface

2020-02-06 Thread durin42 (Augie Fackler)
Closed by commit rHGc86256bd4eb8: manifest: remove `.new()` from the interface 
(authored by durin42).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8079?vs=19922=19950

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8079/new/

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

AFFECTED FILES
  mercurial/interfaces/repository.py
  mercurial/manifest.py
  tests/test-check-interfaces.py

CHANGE DETAILS

diff --git a/tests/test-check-interfaces.py b/tests/test-check-interfaces.py
--- a/tests/test-check-interfaces.py
+++ b/tests/test-check-interfaces.py
@@ -252,7 +252,6 @@
 checkzobject(mctx)
 
 # Conforms to imanifestrevisionwritable.
-checkzobject(mctx.new())
 checkzobject(mctx.copy())
 
 # Conforms to imanifestdict.
diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -1921,9 +1921,6 @@
 def _storage(self):
 return self._manifestlog.getstorage(b'')
 
-def new(self):
-return memmanifestctx(self._manifestlog)
-
 def copy(self):
 memmf = memmanifestctx(self._manifestlog)
 memmf._manifestdict = self.read().copy()
@@ -1970,9 +1967,6 @@
 def node(self):
 return self._node
 
-def new(self):
-return memmanifestctx(self._manifestlog)
-
 def copy(self):
 memmf = memmanifestctx(self._manifestlog)
 memmf._manifestdict = self.read().copy()
@@ -2037,9 +2031,6 @@
 def _storage(self):
 return self._manifestlog.getstorage(b'')
 
-def new(self, dir=b''):
-return memtreemanifestctx(self._manifestlog, dir=dir)
-
 def copy(self):
 memmf = memtreemanifestctx(self._manifestlog, dir=self._dir)
 memmf._treemanifest = self._treemanifest.copy()
@@ -2122,9 +2113,6 @@
 def node(self):
 return self._node
 
-def new(self, dir=b''):
-return memtreemanifestctx(self._manifestlog, dir=dir)
-
 def copy(self):
 memmf = memtreemanifestctx(self._manifestlog, dir=self._dir)
 memmf._treemanifest = self.read().copy()
diff --git a/mercurial/interfaces/repository.py 
b/mercurial/interfaces/repository.py
--- a/mercurial/interfaces/repository.py
+++ b/mercurial/interfaces/repository.py
@@ -1071,14 +1071,6 @@
 as part of a larger interface.
 """
 
-def new():
-"""Obtain a new manifest instance.
-
-Returns an object conforming to the ``imanifestrevisionwritable``
-interface. The instance will be associated with the same
-``imanifestlog`` collection as this instance.
-"""
-
 def copy():
 """Obtain a copy of this manifest instance.
 



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


D8083: archival: use walk() instead of matches() on manifest

2020-02-06 Thread durin42 (Augie Fackler)
Closed by commit rHG2d1b2ad3705b: archival: use walk() instead of matches() on 
manifest (authored by durin42).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8083?vs=19926=19952

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8083/new/

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

AFFECTED FILES
  mercurial/archival.py

CHANGE DETAILS

diff --git a/mercurial/archival.py b/mercurial/archival.py
--- a/mercurial/archival.py
+++ b/mercurial/archival.py
@@ -355,7 +355,7 @@
 if match(name):
 write(name, 0o644, False, lambda: buildmetadata(ctx))
 
-files = [f for f in ctx.manifest().matches(match)]
+files = list(ctx.manifest().walk(match))
 total = len(files)
 if total:
 files.sort()



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


D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
This revision is now accepted and ready to land.
martinvonz added inline comments.
martinvonz accepted this revision.

INLINE COMMENTS

> martinvonz wrote in path_auditor.rs:86
> Well, you already have different errors for `InsideDotHg` and 
> `IsInsideNestedRepo`, so I think you're good. I was just trying to explain 
> the reason for the `1` there in the code (which I assume you just copied from 
> Python). Sorry about the confusion.

Oh, I only now looked at the diff from the previous review and you just added 
`InsideDotHg`. So my comment was useful then and you were not confused -- I 
was. Thanks for fixing :)

REPOSITORY
  rHG Mercurial

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

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


D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> Alphare wrote in path_auditor.rs:86
> Good idea. I'm rewriting my patches, I will soon send an update for all of 
> them.

Well, you already have different errors for `InsideDotHg` and 
`IsInsideNestedRepo`, so I think you're good. I was just trying to explain the 
reason for the `1` there in the code (which I assume you just copied from 
Python). Sorry about the confusion.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

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


D7931: rust-status: use bare hg status fastpath from Python

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19949.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7931?vs=19423=19949

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7931/new/

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

AFFECTED FILES
  mercurial/dirstate.py
  mercurial/match.py
  tests/test-subrepo-deep-nested-change.t

CHANGE DETAILS

diff --git a/tests/test-subrepo-deep-nested-change.t 
b/tests/test-subrepo-deep-nested-change.t
--- a/tests/test-subrepo-deep-nested-change.t
+++ b/tests/test-subrepo-deep-nested-change.t
@@ -355,6 +355,11 @@
   R sub1/sub2/folder/test.txt
   ! sub1/.hgsub
   ? sub1/x.hgsub
+  $ hg status -R sub1
+  warning: subrepo spec file 'sub1/.hgsub' not found
+  R .hgsubstate
+  ! .hgsub
+  ? x.hgsub
   $ mv sub1/x.hgsub sub1/.hgsub
   $ hg update -Cq
   $ touch sub1/foo
diff --git a/mercurial/match.py b/mercurial/match.py
--- a/mercurial/match.py
+++ b/mercurial/match.py
@@ -45,6 +45,7 @@
 
 propertycache = util.propertycache
 
+rustmod = policy.importrust('dirstate')
 
 def _rematcher(regex):
 '''compile the regexp with the best available regexp engine and return a
@@ -666,7 +667,10 @@
 class includematcher(basematcher):
 def __init__(self, root, kindpats, badfn=None):
 super(includematcher, self).__init__(badfn)
-
+if rustmod is not None:
+# We need to pass the patterns to Rust because they can contain
+# patterns from the user interface
+self._kindpats = kindpats
 self._pats, self.matchfn = _buildmatch(kindpats, b'(?:/|$)', root)
 self._prefix = _prefix(kindpats)
 roots, dirs, parents = _rootsdirsandparents(kindpats)
diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -27,6 +27,7 @@
 policy,
 pycompat,
 scmutil,
+sparse,
 txnutil,
 util,
 )
@@ -1083,7 +1084,7 @@
 results[next(iv)] = st
 return results
 
-def _rust_status(self, matcher, list_clean):
+def _rust_status(self, matcher, list_clean, list_ignored, list_unknown):
 # Force Rayon (Rust parallelism library) to respect the number of
 # workers. This is a temporary workaround until Rust code knows
 # how to read the config file.
@@ -1101,16 +1102,45 @@
 added,
 removed,
 deleted,
+clean,
+ignored,
 unknown,
-clean,
+warnings,
+bad,
 ) = rustmod.status(
 self._map._rustmap,
 matcher,
 self._rootdir,
-bool(list_clean),
+self._ignorefiles(),
+self._checkexec,
 self._lastnormaltime,
-self._checkexec,
+bool(list_clean),
+bool(list_ignored),
+bool(list_unknown),
 )
+if self._ui.warn:
+for item in warnings:
+if isinstance(item, tuple):
+file_path, syntax = item
+msg = _(b"%s: ignoring invalid syntax '%s'\n") % (
+file_path,
+syntax,
+)
+self._ui.warn(msg)
+else:
+msg = _(b"skipping unreadable pattern file '%s': %s\n")
+self._ui.warn(
+msg
+% (
+pathutil.canonpath(
+self._rootdir, self._rootdir, item
+),
+b"No such file or directory",
+)
+)
+
+for (fn, message) in bad:
+matcher.bad(fn, encoding.strtolocal(message))
 
 status = scmutil.status(
 modified=modified,
@@ -1118,7 +1148,7 @@
 removed=removed,
 deleted=deleted,
 unknown=unknown,
-ignored=[],
+ignored=ignored,
 clean=clean,
 )
 return (lookup, status)
@@ -1148,26 +1178,32 @@
 
 use_rust = True
 
-allowed_matchers = (matchmod.alwaysmatcher, matchmod.exactmatcher)
+allowed_matchers = (
+matchmod.alwaysmatcher,
+matchmod.exactmatcher,
+matchmod.includematcher,
+)
 
 if rustmod is None:
 use_rust = False
 elif subrepos:
 use_rust = False
-elif bool(listunknown):
-# Pathauditor does not exist yet in Rust, unknown files
-# can't be trusted.
+elif sparse.enabled:
 use_rust = False
-elif self._ignorefiles() and listignored:
-# Rust has no ignore mechanism yet, so don't use Rust for
-# commands that need ignore.
+elif match.traversedir is not None:
 use_rust = False

D7930: rust-status: update rust-cpython bridge to account for the changes in core

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19948.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7930?vs=19422=19948

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7930/new/

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

AFFECTED FILES
  rust/hg-cpython/src/dirstate.rs
  rust/hg-cpython/src/dirstate/status.rs
  rust/hg-cpython/src/exceptions.rs

CHANGE DETAILS

diff --git a/rust/hg-cpython/src/exceptions.rs 
b/rust/hg-cpython/src/exceptions.rs
--- a/rust/hg-cpython/src/exceptions.rs
+++ b/rust/hg-cpython/src/exceptions.rs
@@ -40,3 +40,5 @@
 }
 
 py_exception!(rustext, HgPathPyError, RuntimeError);
+py_exception!(rustext, FallbackError, RuntimeError);
+py_exception!(shared_ref, AlreadyBorrowed, RuntimeError);
diff --git a/rust/hg-cpython/src/dirstate/status.rs 
b/rust/hg-cpython/src/dirstate/status.rs
--- a/rust/hg-cpython/src/dirstate/status.rs
+++ b/rust/hg-cpython/src/dirstate/status.rs
@@ -9,26 +9,28 @@
 //! `hg-core` crate. From Python, this will be seen as
 //! `rustext.dirstate.status`.
 
-use crate::dirstate::DirstateMap;
-use cpython::exc::ValueError;
+use crate::{dirstate::DirstateMap, exceptions::FallbackError};
 use cpython::{
-ObjectProtocol, PyBytes, PyErr, PyList, PyObject, PyResult, PyTuple,
-Python, PythonObject, ToPyObject,
+exc::ValueError, ObjectProtocol, PyBytes, PyErr, PyList, PyObject,
+PyResult, PyTuple, Python, PythonObject, ToPyObject,
 };
-use hg::utils::hg_path::HgPathBuf;
 use hg::{
-matchers::{AlwaysMatcher, FileMatcher},
-status,
-utils::{files::get_path_from_bytes, hg_path::HgPath},
-DirstateStatus,
+matchers::{AlwaysMatcher, FileMatcher, IncludeMatcher},
+parse_pattern_syntax, status,
+utils::{
+files::{get_bytes_from_path, get_path_from_bytes},
+hg_path::{HgPath, HgPathBuf},
+},
+BadMatch, BadType, DirstateStatus, IgnorePattern, PatternFileWarning,
+StatusError, StatusOptions,
 };
-use std::borrow::Borrow;
+use std::borrow::{Borrow, Cow};
 
 /// This will be useless once trait impls for collection are added to `PyBytes`
 /// upstream.
-fn collect_pybytes_list>(
+fn collect_pybytes_list(
 py: Python,
-collection: &[P],
+collection: &[impl AsRef],
 ) -> PyList {
 let list = PyList::new(py, &[]);
 
@@ -43,34 +45,105 @@
 list
 }
 
+fn collect_bad_matches(
+py: Python,
+collection: &[(impl AsRef, BadMatch)],
+) -> PyResult {
+let list = PyList::new(py, &[]);
+
+let os = py.import("os")?;
+let get_error_message = |code: i32| -> PyResult<_> {
+os.call(
+py,
+"strerror",
+PyTuple::new(py, &[code.to_py_object(py).into_object()]),
+None,
+)
+};
+
+for (i, (path, bad_match)) in collection.iter().enumerate() {
+let message = match bad_match {
+BadMatch::OsError(code) => get_error_message(*code)?,
+BadMatch::BadType(bad_type) => format!(
+"unsupported file type (type is {})",
+match bad_type {
+BadType::CharacterDevice => "character device",
+BadType::BlockDevice => "block device",
+BadType::FIFO => "fifo",
+BadType::Socket => "socket",
+BadType::Directory => "directory",
+BadType::Unknown => "unknown",
+}
+)
+.to_py_object(py)
+.into_object(),
+};
+list.insert_item(
+py,
+i,
+(PyBytes::new(py, path.as_ref().as_bytes()), message)
+.to_py_object(py)
+.into_object(),
+)
+}
+
+Ok(list)
+}
+
+fn handle_fallback(py: Python, err: StatusError) -> PyErr {
+match err {
+StatusError::Pattern(e) => {
+PyErr::new::(py, e.to_string())
+}
+e => PyErr::new::(py, e.to_string()),
+}
+}
+
 pub fn status_wrapper(
 py: Python,
 dmap: DirstateMap,
 matcher: PyObject,
 root_dir: PyObject,
-list_clean: bool,
+ignore_files: PyList,
+check_exec: bool,
 last_normal_time: i64,
-check_exec: bool,
-) -> PyResult<(PyList, PyList, PyList, PyList, PyList, PyList, PyList)> {
+list_clean: bool,
+list_ignored: bool,
+list_unknown: bool,
+) -> PyResult {
 let bytes = root_dir.extract::(py)?;
 let root_dir = get_path_from_bytes(bytes.data(py));
 
 let dmap: DirstateMap = dmap.to_py_object(py);
 let dmap = dmap.get_inner(py);
 
+let ignore_files: PyResult> = ignore_files
+.iter(py)
+.map(|b| {
+let file = b.extract::(py)?;
+Ok(get_path_from_bytes(file.data(py)).to_owned())
+})
+.collect();
+let ignore_files = ignore_files?;
+
 match matcher.get_type(py).name(py).borrow() {
 "alwaysmatcher" => {
 let matcher = AlwaysMatcher;
-let 

D7910: rust-re2: add wrapper for calling Re2 from Rust

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19938.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7910?vs=19546=19938

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7910/new/

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

AFFECTED FILES
  rust/Cargo.lock
  rust/hg-core/Cargo.toml
  rust/hg-core/build.rs
  rust/hg-core/src/lib.rs
  rust/hg-core/src/re2/mod.rs
  rust/hg-core/src/re2/re2.rs
  rust/hg-core/src/re2/rust_re2.cpp
  rust/hg-cpython/Cargo.toml
  setup.py

CHANGE DETAILS

diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -1351,10 +1351,19 @@
 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
 
 cargocmd = ['cargo', 'rustc', '-vv', '--release']
+
+feature_flags = []
+
 if sys.version_info[0] == 3 and self.py3_features is not None:
-cargocmd.extend(
-('--features', self.py3_features, '--no-default-features')
-)
+feature_flags.append(self.py3_features)
+cargocmd.append('--no-default-features')
+
+rust_features = env.get("HG_RUST_FEATURES")
+if rust_features:
+feature_flags.append(rust_features)
+
+cargocmd.extend(('--features', " ".join(feature_flags)))
+
 cargocmd.append('--')
 if sys.platform == 'darwin':
 cargocmd.extend(
diff --git a/rust/hg-cpython/Cargo.toml b/rust/hg-cpython/Cargo.toml
--- a/rust/hg-cpython/Cargo.toml
+++ b/rust/hg-cpython/Cargo.toml
@@ -10,6 +10,7 @@
 
 [features]
 default = ["python27"]
+with-re2 = ["hg-core/with-re2"]
 
 # Features to build an extension module:
 python27 = ["cpython/python27-sys", "cpython/extension-module-2-7"]
@@ -21,7 +22,7 @@
 python3-bin = ["cpython/python3-sys"]
 
 [dependencies]
-hg-core = { path = "../hg-core" }
+hg-core = { path = "../hg-core"}
 libc = '*'
 
 [dependencies.cpython]
diff --git a/rust/hg-core/src/re2/rust_re2.cpp 
b/rust/hg-core/src/re2/rust_re2.cpp
new file mode 100644
--- /dev/null
+++ b/rust/hg-core/src/re2/rust_re2.cpp
@@ -0,0 +1,49 @@
+/*
+rust_re2.cpp
+
+C ABI export of Re2's C++ interface for Rust FFI.
+
+Copyright 2020 Valentin Gatien-Baron
+
+This software may be used and distributed according to the terms of the
+GNU General Public License version 2 or any later version.
+*/
+
+#include 
+using namespace re2;
+
+extern "C" {
+   RE2* rust_re2_create(const char* data, size_t len) {
+   RE2::Options o;
+   o.set_encoding(RE2::Options::Encoding::EncodingLatin1);
+   o.set_log_errors(false);
+   o.set_max_mem(5000);
+
+   return new RE2(StringPiece(data, len), o);
+   }
+
+   void rust_re2_destroy(RE2* re) {
+   delete re;
+   }
+
+   bool rust_re2_ok(RE2* re) {
+   return re->ok();
+   }
+
+   void rust_re2_error(RE2* re, const char** outdata, size_t* outlen) {
+   const std::string& e = re->error();
+   *outdata = e.data();
+   *outlen = e.length();
+   }
+
+   bool rust_re2_match(RE2* re, char* data, size_t len, int ianchor) {
+   const StringPiece sp = StringPiece(data, len);
+
+   RE2::Anchor anchor =
+   ianchor == 0 ? RE2::Anchor::UNANCHORED :
+   (ianchor == 1 ? RE2::Anchor::ANCHOR_START :
+RE2::Anchor::ANCHOR_BOTH);
+
+   return re->Match(sp, 0, len, anchor, NULL, 0);
+   }
+}
diff --git a/rust/hg-core/src/re2/re2.rs b/rust/hg-core/src/re2/re2.rs
new file mode 100644
--- /dev/null
+++ b/rust/hg-core/src/re2/re2.rs
@@ -0,0 +1,66 @@
+/*
+re2.rs
+
+Rust FFI bindings to Re2.
+
+Copyright 2020 Valentin Gatien-Baron
+
+This software may be used and distributed according to the terms of the
+GNU General Public License version 2 or any later version.
+*/
+use libc::{c_int, c_void};
+
+type Re2Ptr = *const c_void;
+
+pub struct Re2(Re2Ptr);
+
+/// `re2.h` says:
+/// "An "RE2" object is safe for concurrent use by multiple threads."
+unsafe impl Sync for Re2 {}
+
+/// These bind to the C ABI in `rust_re2.cpp`.
+extern "C" {
+fn rust_re2_create(data: *const u8, len: usize) -> Re2Ptr;
+fn rust_re2_destroy(re2: Re2Ptr);
+fn rust_re2_ok(re2: Re2Ptr) -> bool;
+fn rust_re2_error(
+re2: Re2Ptr,
+outdata: *mut *const u8,
+outlen: *mut usize,
+) -> bool;
+fn rust_re2_match(
+re2: Re2Ptr,
+data: *const u8,
+len: usize,
+anchor: c_int,
+) -> bool;
+}
+
+impl Re2 {
+pub fn new(pattern: &[u8]) -> Result {
+unsafe {
+let re2 = rust_re2_create(pattern.as_ptr(), pattern.len());
+if rust_re2_ok(re2) {
+Ok(Re2(re2))
+} else {
+let mut data: *const u8 = std::ptr::null();
+let mut len: usize = 0;
+rust_re2_error(re2,  data,  len);
+

D7929: rust-status: add bare `hg status` support in hg-core

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19947.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7929?vs=19421=19947

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7929/new/

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

AFFECTED FILES
  rust/hg-core/src/dirstate/status.rs
  rust/hg-core/src/lib.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/lib.rs b/rust/hg-core/src/lib.rs
--- a/rust/hg-core/src/lib.rs
+++ b/rust/hg-core/src/lib.rs
@@ -13,7 +13,9 @@
 dirs_multiset::{DirsMultiset, DirsMultisetIter},
 dirstate_map::DirstateMap,
 parsers::{pack_dirstate, parse_dirstate, PARENT_SIZE},
-status::{status, DirstateStatus, StatusOptions},
+status::{
+status, BadMatch, BadType, DirstateStatus, StatusError, StatusOptions,
+},
 CopyMap, CopyMapIter, DirstateEntry, DirstateParents, EntryState,
 StateMap, StateMapIter,
 };
diff --git a/rust/hg-core/src/dirstate/status.rs 
b/rust/hg-core/src/dirstate/status.rs
--- a/rust/hg-core/src/dirstate/status.rs
+++ b/rust/hg-core/src/dirstate/status.rs
@@ -11,22 +11,31 @@
 
 use crate::{
 dirstate::SIZE_FROM_OTHER_PARENT,
-matchers::{Matcher, VisitChildrenSet},
+filepatterns::PatternFileWarning,
+matchers::{get_ignore_function, Matcher, VisitChildrenSet},
 utils::{
-files::HgMetadata,
+files::{find_dirs, HgMetadata},
 hg_path::{
 hg_path_to_path_buf, os_string_to_hg_path_buf, HgPath, HgPathBuf,
+HgPathError,
 },
+path_auditor::PathAuditor,
 },
 CopyMap, DirstateEntry, DirstateMap, EntryState, FastHashMap,
+PatternError,
 };
+use lazy_static::lazy_static;
 use rayon::prelude::*;
-use std::borrow::Cow;
-use std::collections::{HashSet, VecDeque};
-use std::fs::{read_dir, DirEntry};
-use std::io::ErrorKind;
-use std::ops::Deref;
-use std::path::Path;
+use std::collections::VecDeque;
+use std::{
+borrow::Cow,
+collections::HashSet,
+fs::{read_dir, DirEntry},
+io::ErrorKind,
+ops::Deref,
+path::Path,
+sync::mpsc,
+};
 
 /// Wrong type of file from a `BadMatch`
 /// Note: a lot of those don't exist on all platforms.
@@ -50,6 +59,7 @@
 /// Marker enum used to dispatch new status entries into the right collections.
 /// Is similar to `crate::EntryState`, but represents the transient state of
 /// entries during the lifetime of a command.
+#[derive(Debug)]
 enum Dispatch {
 Unsure,
 Modified,
@@ -150,7 +160,7 @@
 } else if options.list_clean {
 Dispatch::Clean
 } else {
-Dispatch::Unknown
+Dispatch::None
 }
 }
 EntryState::Merged => Dispatch::Modified,
@@ -174,57 +184,95 @@
 }
 }
 
+lazy_static! {
+static ref DEFAULT_WORK: HashSet<&'static HgPath> = {
+let mut h = HashSet::new();
+h.insert(HgPath::new(b""));
+h
+};
+}
+
 /// Get stat data about the files explicitly specified by match.
 /// TODO subrepos
 fn walk_explicit<'a>(
-files: &'a HashSet<>,
+files: Option<&'a HashSet<>>,
 dmap: &'a DirstateMap,
 root_dir: impl AsRef + Sync + Send,
+work: mpsc::Sender<&'a HgPath>,
 options: StatusOptions,
-) -> impl ParallelIterator> {
-files.par_iter().filter_map(move |filename| {
-// TODO normalization
-let normalized = filename.as_ref();
+) -> impl ParallelIterator, Dispatch)>> {
+files
+.unwrap_or(_WORK)
+.par_iter()
+.map_with(work, move |work, filename| {
+// TODO normalization
+let normalized = filename.as_ref();
 
-let buf = match hg_path_to_path_buf(normalized) {
-Ok(x) => x,
-Err(e) => return Some(Err(e.into())),
-};
-let target = root_dir.as_ref().join(buf);
-let st = target.symlink_metadata();
-match st {
-Ok(meta) => {
-let file_type = meta.file_type();
-if file_type.is_file() || file_type.is_symlink() {
-if let Some(entry) = dmap.get(normalized) {
+let buf = match hg_path_to_path_buf(normalized) {
+Ok(x) => x,
+Err(e) => return Some(Err(e.into())),
+};
+let target = root_dir.as_ref().join(buf);
+let st = target.symlink_metadata();
+let in_dmap = dmap.get(normalized);
+match st {
+Ok(meta) => {
+let file_type = meta.file_type();
+if file_type.is_file() || file_type.is_symlink() {
+if let Some(entry) = in_dmap {
+return Some(Ok((
+Cow::Borrowed(normalized),
+dispatch_found(
+,
+*entry,
+

D7928: rust-status: add function for sequential traversal of the working directory

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19946.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7928?vs=19417=19946

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7928/new/

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

AFFECTED FILES
  rust/hg-core/src/dirstate/status.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/dirstate/status.rs 
b/rust/hg-core/src/dirstate/status.rs
--- a/rust/hg-core/src/dirstate/status.rs
+++ b/rust/hg-core/src/dirstate/status.rs
@@ -11,18 +11,21 @@
 
 use crate::{
 dirstate::SIZE_FROM_OTHER_PARENT,
-matchers::Matcher,
+matchers::{Matcher, VisitChildrenSet},
 utils::{
 files::HgMetadata,
 hg_path::{
 hg_path_to_path_buf, os_string_to_hg_path_buf, HgPath, HgPathBuf,
 },
 },
-CopyMap, DirstateEntry, DirstateMap, EntryState,
+CopyMap, DirstateEntry, DirstateMap, EntryState, FastHashMap,
 };
 use rayon::prelude::*;
-use std::collections::HashSet;
+use std::borrow::Cow;
+use std::collections::{HashSet, VecDeque};
 use std::fs::{read_dir, DirEntry};
+use std::io::ErrorKind;
+use std::ops::Deref;
 use std::path::Path;
 
 /// Wrong type of file from a `BadMatch`
@@ -229,6 +232,168 @@
 pub last_normal_time: i64,
 pub check_exec: bool,
 pub list_clean: bool,
+pub list_unknown: bool,
+pub list_ignored: bool,
+}
+
+/// Dispatch a single file found during `traverse`.
+/// If `file` is a folder that needs to be traversed, it will be pushed into
+/// `work`.
+fn traverse_worker<'a>(
+work:  VecDeque,
+matcher:  Matcher,
+dmap: ,
+filename: impl AsRef,
+dir_entry: ,
+ignore_fn:  for<'r> Fn(&'r HgPath) -> bool,
+options: StatusOptions,
+) -> Option, Dispatch)>> {
+let file_type = match dir_entry.file_type() {
+Ok(x) => x,
+Err(e) => return Some(Err(e.into())),
+};
+let filename = filename.as_ref();
+let entry_option = dmap.get(filename);
+
+if file_type.is_dir() {
+// Do we need to traverse it?
+if !ignore_fn() {
+work.push_front(filename.to_owned());
+} else {
+if options.list_ignored {
+work.push_front(filename.to_owned());
+}
+}
+// Nested `if` until `rust-lang/rust#53668` is stable
+if let Some(entry) = entry_option {
+// Used to be a file, is now a folder
+if matcher.matches_everything() || matcher.matches() {
+return Some(Ok((
+Cow::Owned(filename.to_owned()),
+dispatch_missing(entry.state),
+)));
+}
+}
+} else if file_type.is_file() || file_type.is_symlink() {
+if let Some(entry) = entry_option {
+if matcher.matches_everything() || matcher.matches() {
+let metadata = match dir_entry.metadata() {
+Ok(x) => x,
+Err(e) => return Some(Err(e.into())),
+};
+return Some(Ok((
+Cow::Owned(filename.to_owned()),
+dispatch_found(
+,
+*entry,
+HgMetadata::from_metadata(metadata),
+_map,
+options,
+),
+)));
+}
+} else if (matcher.matches_everything() || matcher.matches())
+&& !ignore_fn()
+{
+return Some(Ok((
+Cow::Owned(filename.to_owned()),
+Dispatch::Unknown,
+)));
+} else if ignore_fn() {
+return Some(Ok((
+Cow::Owned(filename.to_owned()),
+Dispatch::Ignored,
+)));
+}
+} else if let Some(entry) = entry_option {
+// Used to be a file or a folder, now something else.
+if matcher.matches_everything() || matcher.matches() {
+return Some(Ok((
+Cow::Owned(filename.to_owned()),
+dispatch_missing(entry.state),
+)));
+}
+}
+None
+}
+
+/// Walk the working directory recursively to look for changes compared to the
+/// current `DirstateMap`.
+fn traverse<'a>(
+matcher: &(impl Matcher + Sync),
+root_dir: impl AsRef,
+dmap: ,
+path: impl AsRef,
+old_results: FastHashMap, Dispatch>,
+ignore_fn: &(impl for<'r> Fn(&'r HgPath) -> bool + Sync),
+options: StatusOptions,
+) -> IoResult, Dispatch>> {
+let root_dir = root_dir.as_ref();
+let mut new_results = FastHashMap::default();
+
+let mut work = VecDeque::new();
+work.push_front(path.as_ref().to_owned());
+
+while let Some(ref directory) = work.pop_front() {
+if directory.as_bytes() == b".hg" {
+continue;
+}
+let visit_entries = match matcher.visit_children_set(directory) {
+

D8087: rust-status: rename `StatusResult` to `DirstateStatus`

2020-02-06 Thread Raphaël Gomès
Alphare created this revision.
Herald added subscribers: mercurial-devel, kevincox.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  "Result" has a special meaning in the Rust world, this should be clearer.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  rust/hg-core/src/dirstate/status.rs
  rust/hg-core/src/lib.rs
  rust/hg-cpython/src/dirstate/status.rs

CHANGE DETAILS

diff --git a/rust/hg-cpython/src/dirstate/status.rs 
b/rust/hg-cpython/src/dirstate/status.rs
--- a/rust/hg-cpython/src/dirstate/status.rs
+++ b/rust/hg-cpython/src/dirstate/status.rs
@@ -20,7 +20,7 @@
 matchers::{AlwaysMatcher, FileMatcher},
 status,
 utils::{files::get_path_from_bytes, hg_path::HgPath},
-StatusResult,
+DirstateStatus,
 };
 use std::borrow::Borrow;
 
@@ -114,7 +114,7 @@
 
 fn build_response(
 lookup: Vec<>,
-status_res: StatusResult,
+status_res: DirstateStatus,
 py: Python,
 ) -> PyResult<(PyList, PyList, PyList, PyList, PyList, PyList, PyList)> {
 let modified = collect_pybytes_list(py, status_res.modified.as_ref());
diff --git a/rust/hg-core/src/lib.rs b/rust/hg-core/src/lib.rs
--- a/rust/hg-core/src/lib.rs
+++ b/rust/hg-core/src/lib.rs
@@ -13,7 +13,7 @@
 dirs_multiset::{DirsMultiset, DirsMultisetIter},
 dirstate_map::DirstateMap,
 parsers::{pack_dirstate, parse_dirstate, PARENT_SIZE},
-status::{status, StatusOptions, StatusResult},
+status::{status, DirstateStatus, StatusOptions},
 CopyMap, CopyMapIter, DirstateEntry, DirstateParents, EntryState,
 StateMap, StateMapIter,
 };
diff --git a/rust/hg-core/src/dirstate/status.rs 
b/rust/hg-core/src/dirstate/status.rs
--- a/rust/hg-core/src/dirstate/status.rs
+++ b/rust/hg-core/src/dirstate/status.rs
@@ -251,7 +251,7 @@
 })
 }
 
-pub struct StatusResult<'a> {
+pub struct DirstateStatus<'a> {
 pub modified: Vec<&'a HgPath>,
 pub added: Vec<&'a HgPath>,
 pub removed: Vec<&'a HgPath>,
@@ -263,7 +263,7 @@
 
 fn build_response<'a>(
 results: impl IntoIterator>,
-) -> IoResult<(Vec<&'a HgPath>, StatusResult<'a>)> {
+) -> IoResult<(Vec<&'a HgPath>, DirstateStatus<'a>)> {
 let mut lookup = vec![];
 let mut modified = vec![];
 let mut added = vec![];
@@ -286,7 +286,7 @@
 
 Ok((
 lookup,
-StatusResult {
+DirstateStatus {
 modified,
 added,
 removed,
@@ -301,7 +301,7 @@
 matcher: &'b impl Matcher,
 root_dir: impl AsRef + Sync + Send + Copy,
 options: StatusOptions,
-) -> IoResult<(Vec<&'c HgPath>, StatusResult<'c>)> {
+) -> IoResult<(Vec<&'c HgPath>, DirstateStatus<'c>)> {
 let files = matcher.file_set();
 let mut results = vec![];
 if let Some(files) = files {



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


D8086: rust-status: refactor options into a `StatusOptions` struct

2020-02-06 Thread Raphaël Gomès
Alphare created this revision.
Herald added subscribers: mercurial-devel, kevincox.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  rust/hg-core/src/dirstate/status.rs
  rust/hg-core/src/lib.rs
  rust/hg-core/src/matchers.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs
--- a/rust/hg-core/src/matchers.rs
+++ b/rust/hg-core/src/matchers.rs
@@ -704,7 +704,11 @@
 
 assert_eq!(
 roots_dirs_and_parents().unwrap(),
-RootsDirsAndParents {roots, dirs, parents}
+RootsDirsAndParents {
+roots,
+dirs,
+parents
+}
 );
 }
 
diff --git a/rust/hg-core/src/lib.rs b/rust/hg-core/src/lib.rs
--- a/rust/hg-core/src/lib.rs
+++ b/rust/hg-core/src/lib.rs
@@ -13,7 +13,7 @@
 dirs_multiset::{DirsMultiset, DirsMultisetIter},
 dirstate_map::DirstateMap,
 parsers::{pack_dirstate, parse_dirstate, PARENT_SIZE},
-status::{status, StatusResult},
+status::{status, StatusOptions, StatusResult},
 CopyMap, CopyMapIter, DirstateEntry, DirstateParents, EntryState,
 StateMap, StateMapIter,
 };
diff --git a/rust/hg-core/src/dirstate/status.rs 
b/rust/hg-core/src/dirstate/status.rs
--- a/rust/hg-core/src/dirstate/status.rs
+++ b/rust/hg-core/src/dirstate/status.rs
@@ -83,9 +83,7 @@
 entry: DirstateEntry,
 metadata: HgMetadata,
 copy_map: ,
-check_exec: bool,
-list_clean: bool,
-last_normal_time: i64,
+options: StatusOptions,
 ) -> Dispatch {
 let DirstateEntry {
 state,
@@ -105,7 +103,7 @@
 EntryState::Normal => {
 let size_changed = mod_compare(size, st_size as i32);
 let mode_changed =
-(mode ^ st_mode as i32) & 0o100 != 0o000 && check_exec;
+(mode ^ st_mode as i32) & 0o100 != 0o000 && options.check_exec;
 let metadata_changed = size >= 0 && (size_changed || mode_changed);
 let other_parent = size == SIZE_FROM_OTHER_PARENT;
 if metadata_changed
@@ -115,14 +113,14 @@
 Dispatch::Modified
 } else if mod_compare(mtime, st_mtime as i32) {
 Dispatch::Unsure
-} else if st_mtime == last_normal_time {
+} else if st_mtime == options.last_normal_time {
 // the file may have just been marked as normal and
 // it may have changed in the same second without
 // changing its size. This can happen if we quickly
 // do multiple commits. Force lookup, so we don't
 // miss such a racy file change.
 Dispatch::Unsure
-} else if list_clean {
+} else if options.list_clean {
 Dispatch::Clean
 } else {
 Dispatch::Unknown
@@ -155,9 +153,7 @@
 files: &'a HashSet<>,
 dmap: &'a DirstateMap,
 root_dir: impl AsRef + Sync + Send,
-check_exec: bool,
-list_clean: bool,
-last_normal_time: i64,
+options: StatusOptions,
 ) -> impl ParallelIterator> {
 files.par_iter().filter_map(move |filename| {
 // TODO normalization
@@ -181,9 +177,7 @@
 *entry,
 HgMetadata::from_metadata(meta),
 _map,
-check_exec,
-list_clean,
-last_normal_time,
+options,
 ),
 )));
 }
@@ -206,14 +200,19 @@
 })
 }
 
+#[derive(Debug, Copy, Clone)]
+pub struct StatusOptions {
+pub last_normal_time: i64,
+pub check_exec: bool,
+pub list_clean: bool,
+}
+
 /// Stat all entries in the `DirstateMap` and mark them for dispatch into
 /// the relevant collections.
 fn stat_dmap_entries(
 dmap: ,
 root_dir: impl AsRef + Sync + Send,
-check_exec: bool,
-list_clean: bool,
-last_normal_time: i64,
+options: StatusOptions,
 ) -> impl ParallelIterator> {
 dmap.par_iter().map(move |(filename, entry)| {
 let filename:  = filename;
@@ -234,9 +233,7 @@
 *entry,
 HgMetadata::from_metadata(m),
 _map,
-check_exec,
-list_clean,
-last_normal_time,
+options,
 ),
 )),
 Err(ref e)
@@ -303,31 +300,16 @@
 dmap: &'a DirstateMap,
 matcher: &'b impl Matcher,
 root_dir: impl AsRef + Sync + Send + Copy,
-list_clean: bool,
-last_normal_time: i64,
-check_exec: bool,
+options: StatusOptions,
 ) -> IoResult<(Vec<&'c HgPath>, StatusResult<'c>)> {
 let files = matcher.file_set();
 let mut results = 

D8088: rust-status: add missing variants to `Dispatch` enum

2020-02-06 Thread Raphaël Gomès
Alphare created this revision.
Herald added subscribers: mercurial-devel, kevincox.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  rust/hg-core/src/dirstate/status.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/dirstate/status.rs 
b/rust/hg-core/src/dirstate/status.rs
--- a/rust/hg-core/src/dirstate/status.rs
+++ b/rust/hg-core/src/dirstate/status.rs
@@ -25,6 +25,25 @@
 use std::fs::{read_dir, DirEntry};
 use std::path::Path;
 
+/// Wrong type of file from a `BadMatch`
+/// Note: a lot of those don't exist on all platforms.
+#[derive(Debug)]
+pub enum BadType {
+CharacterDevice,
+BlockDevice,
+FIFO,
+Socket,
+Directory,
+Unknown,
+}
+
+/// Was explicitly matched but cannot be found/accessed
+#[derive(Debug)]
+pub enum BadMatch {
+OsError(i32),
+BadType(BadType),
+}
+
 /// Marker enum used to dispatch new status entries into the right collections.
 /// Is similar to `crate::EntryState`, but represents the transient state of
 /// entries during the lifetime of a command.
@@ -36,6 +55,11 @@
 Deleted,
 Clean,
 Unknown,
+Ignored,
+/// Empty dispatch, the file is not worth listing
+None,
+/// Was explicitly matched but cannot be found/accessed
+Bad(BadMatch),
 }
 
 type IoResult = std::io::Result;
@@ -257,6 +281,9 @@
 pub removed: Vec<&'a HgPath>,
 pub deleted: Vec<&'a HgPath>,
 pub clean: Vec<&'a HgPath>,
+pub ignored: Vec<&'a HgPath>,
+pub unknown: Vec<&'a HgPath>,
+pub bad: Vec<(&'a HgPath, BadMatch)>,
 /* TODO ignored
  * TODO unknown */
 }
@@ -270,17 +297,23 @@
 let mut removed = vec![];
 let mut deleted = vec![];
 let mut clean = vec![];
+let mut ignored = vec![];
+let mut unknown = vec![];
+let mut bad = vec![];
 
 for res in results.into_iter() {
 let (filename, dispatch) = res?;
 match dispatch {
-Dispatch::Unknown => {}
+Dispatch::Unknown => unknown.push(filename),
 Dispatch::Unsure => lookup.push(filename),
 Dispatch::Modified => modified.push(filename),
 Dispatch::Added => added.push(filename),
 Dispatch::Removed => removed.push(filename),
 Dispatch::Deleted => deleted.push(filename),
 Dispatch::Clean => clean.push(filename),
+Dispatch::Ignored => ignored.push(filename),
+Dispatch::None => {}
+Dispatch::Bad(reason) => bad.push((filename, reason)),
 }
 }
 
@@ -292,6 +325,9 @@
 removed,
 deleted,
 clean,
+ignored,
+unknown,
+bad,
 },
 ))
 }



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


D7927: rust-status: add util for listing a directory

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19942.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7927?vs=19416=19942

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7927/new/

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

AFFECTED FILES
  rust/hg-core/src/dirstate/status.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/dirstate/status.rs 
b/rust/hg-core/src/dirstate/status.rs
--- a/rust/hg-core/src/dirstate/status.rs
+++ b/rust/hg-core/src/dirstate/status.rs
@@ -14,12 +14,15 @@
 matchers::Matcher,
 utils::{
 files::HgMetadata,
-hg_path::{hg_path_to_path_buf, HgPath},
+hg_path::{
+hg_path_to_path_buf, os_string_to_hg_path_buf, HgPath, HgPathBuf,
+},
 },
 CopyMap, DirstateEntry, DirstateMap, EntryState,
 };
 use rayon::prelude::*;
 use std::collections::HashSet;
+use std::fs::{read_dir, DirEntry};
 use std::path::Path;
 
 /// Marker enum used to dispatch new status entries into the right collections.
@@ -48,6 +51,32 @@
 a & i32::max_value() != b & i32::max_value()
 }
 
+/// Return a sorted list containing information about the entries
+/// in the directory.
+///
+/// * `skip_dot_hg` - Return an empty vec if `path` contains a `.hg` directory
+fn list_directory(
+path: impl AsRef,
+skip_dot_hg: bool,
+) -> std::io::Result> {
+let mut results = vec![];
+let entries = read_dir(path.as_ref())?;
+
+for entry in entries {
+let entry = entry?;
+let filename = os_string_to_hg_path_buf(entry.file_name())?;
+let file_type = entry.file_type()?;
+if skip_dot_hg && filename.as_bytes() == b".hg" && file_type.is_dir() {
+return Ok(vec![]);
+} else {
+results.push((HgPathBuf::from(filename), entry))
+}
+}
+
+results.sort_by(|a, b| a.0.cmp());
+Ok(results)
+}
+
 /// The file corresponding to the dirstate entry was found on the filesystem.
 fn dispatch_found(
 filename: impl AsRef,



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


D7925: rust-matchers: add `IgnoreMatcher`

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19941.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7925?vs=19420=19941

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7925/new/

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

AFFECTED FILES
  rust/hg-core/src/matchers.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs
--- a/rust/hg-core/src/matchers.rs
+++ b/rust/hg-core/src/matchers.rs
@@ -10,14 +10,25 @@
 #[cfg(feature = "with-re2")]
 use crate::re2::Re2;
 use crate::{
-filepatterns::{build_single_regex, PatternResult},
-utils::hg_path::{HgPath, HgPathBuf},
-DirsMultiset, DirstateMapError, IgnorePattern, PatternError,
+dirstate::dirs_multiset::DirsChildrenMultiset,
+filepatterns::{
+build_single_regex, filter_subincludes, get_patterns_from_file,
+PatternFileWarning, PatternResult, SubInclude,
+},
+utils::{
+files::find_dirs,
+hg_path::{HgPath, HgPathBuf},
+Escaped,
+},
+DirsMultiset, DirstateMapError, FastHashMap, IgnorePattern, PatternError,
 PatternSyntax,
 };
+
 use std::collections::HashSet;
+use std::fmt::{Display, Error, Formatter};
 use std::iter::FromIterator;
 use std::ops::Deref;
+use std::path::Path;
 
 #[derive(Debug, PartialEq)]
 pub enum VisitChildrenSet<'a> {
@@ -223,6 +234,88 @@
 }
 }
 
+/// Matches files that are included in the ignore rules.
+///
+#[cfg_attr(
+feature = "with-re2",
+doc = r##"
+```
+use hg::{
+matchers::{IncludeMatcher, Matcher},
+IgnorePattern,
+PatternSyntax,
+utils::hg_path::HgPath
+};
+use std::path::Path;
+///
+let ignore_patterns =
+vec![IgnorePattern::new(PatternSyntax::RootGlob, b"this*", Path::new(""))];
+let (matcher, _) = IncludeMatcher::new(ignore_patterns, "").unwrap();
+///
+assert_eq!(matcher.matches(HgPath::new(b"testing")), false);
+assert_eq!(matcher.matches(HgPath::new(b"this should work")), true);
+assert_eq!(matcher.matches(HgPath::new(b"this also")), true);
+assert_eq!(matcher.matches(HgPath::new(b"but not this")), false);
+```
+"##
+)]
+pub struct IncludeMatcher<'a> {
+patterns: Vec,
+match_fn: Box Fn(&'r HgPath) -> bool + 'a + Sync>,
+/// Whether all the patterns match a prefix (i.e. recursively)
+prefix: bool,
+roots: HashSet,
+dirs: HashSet,
+parents: HashSet,
+}
+
+impl<'a> Matcher for IncludeMatcher<'a> {
+fn file_set() -> Option<<>> {
+None
+}
+
+fn exact_match(, _filename: impl AsRef) -> bool {
+false
+}
+
+fn matches(, filename: impl AsRef) -> bool {
+(self.match_fn)(filename.as_ref())
+}
+
+fn visit_children_set(
+,
+directory: impl AsRef,
+) -> VisitChildrenSet {
+let dir = directory.as_ref();
+if self.prefix && self.roots.contains(dir) {
+return VisitChildrenSet::Recursive;
+}
+if self.roots.contains(HgPath::new(b""))
+|| self.roots.contains(dir)
+|| self.dirs.contains(dir)
+|| find_dirs(dir).any(|parent_dir| self.roots.contains(parent_dir))
+{
+return VisitChildrenSet::This;
+}
+
+if self.parents.contains(directory.as_ref()) {
+let multiset = self.get_all_parents_children();
+if let Some(children) = multiset.get(dir) {
+return VisitChildrenSet::Set(children.to_owned());
+}
+}
+VisitChildrenSet::Empty
+}
+
+fn matches_everything() -> bool {
+false
+}
+
+fn is_exact() -> bool {
+false
+}
+}
+
 const MAX_RE_SIZE: usize = 2;
 
 #[cfg(feature = "with-re2")]
@@ -396,6 +489,175 @@
 })
 }
 
+/// Returns a function that checks whether a given file (in the general sense)
+/// should be matched.
+fn build_match<'a, 'b>(
+ignore_patterns: &'a [IgnorePattern],
+root_dir: impl AsRef,
+) -> PatternResult<(
+Vec,
+Box bool + 'b + Sync>,
+Vec,
+)> {
+let mut match_funcs: Vec bool + Sync>> = vec![];
+// For debugging and printing
+let mut patterns = vec![];
+let mut all_warnings = vec![];
+
+let (subincludes, ignore_patterns) =
+filter_subincludes(ignore_patterns, root_dir)?;
+
+if !subincludes.is_empty() {
+// Build prefix-based matcher functions for subincludes
+let mut submatchers = FastHashMap::default();
+let mut prefixes = vec![];
+
+for SubInclude { prefix, root, path } in subincludes.into_iter() {
+let (match_fn, warnings) = get_ignore_function(&[path], root)?;
+all_warnings.extend(warnings);
+prefixes.push(prefix.to_owned());
+submatchers.insert(prefix.to_owned(), match_fn);
+}
+
+let match_subinclude = move |filename: | {
+for prefix in prefixes.iter() {
+if let Some(rel) = filename.relative_to(prefix) {
+if 

D7924: rust-matchers: add `build_regex_match` function

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19940.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7924?vs=19419=19940

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7924/new/

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

AFFECTED FILES
  rust/hg-core/src/matchers.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs
--- a/rust/hg-core/src/matchers.rs
+++ b/rust/hg-core/src/matchers.rs
@@ -10,7 +10,7 @@
 #[cfg(feature = "with-re2")]
 use crate::re2::Re2;
 use crate::{
-filepatterns::PatternResult,
+filepatterns::{build_single_regex, PatternResult},
 utils::hg_path::{HgPath, HgPathBuf},
 DirsMultiset, DirstateMapError, IgnorePattern, PatternError,
 PatternSyntax,
@@ -244,6 +244,57 @@
 Err(PatternError::Re2NotInstalled)
 }
 
+/// Returns a function that matches an `HgPath` against the regex formed by
+/// the given patterns.
+fn build_regex_match<'a>(
+ignore_patterns: &'a [&'a IgnorePattern],
+) -> PatternResult<(Vec, Box bool + Sync>)> {
+let mut all_groups = vec![];
+let regexps: Result, PatternError> = ignore_patterns
+.into_iter()
+.map(|k| build_single_regex(*k))
+.collect();
+let regexps = regexps?;
+let full_regex = regexps.join('|');
+
+let mut start_index = 0;
+let mut group_size = 0;
+
+for (index, re) in regexps.iter().enumerate() {
+let piece_size = re.len();
+if piece_size > MAX_RE_SIZE {
+return Err(PatternError::TooLong(piece_size));
+}
+if (group_size + piece_size) > MAX_RE_SIZE {
+let group = [start_index..index];
+all_groups.push(group.join('|'));
+start_index = index;
+group_size = 0
+}
+group_size += piece_size + 1;
+}
+
+let func = if start_index == 0 {
+let matcher = re_matcher(_regex)?;
+Box::new(move |filename: | matcher(filename))
+as Box bool + Sync>
+} else {
+let group = [start_index..];
+all_groups.push(group.join('|'));
+
+let all_matchers: PatternResult> =
+all_groups.iter().map(|group| re_matcher(group)).collect();
+let all_matchers = all_matchers?;
+
+let ret = Box::new(move |filename: | {
+all_matchers.iter().any(|f| f(filename))
+});
+ret as Box bool + Sync>
+};
+
+Ok((full_regex, func))
+}
+
 /// Returns roots and directories corresponding to each pattern.
 ///
 /// This calculates the roots and directories exactly matching the patterns and



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


D7923: rust-matchers: add functions to get roots, dirs and parents from patterns

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19939.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7923?vs=19418=19939

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7923/new/

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

AFFECTED FILES
  rust/hg-core/src/matchers.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs
--- a/rust/hg-core/src/matchers.rs
+++ b/rust/hg-core/src/matchers.rs
@@ -10,8 +10,10 @@
 #[cfg(feature = "with-re2")]
 use crate::re2::Re2;
 use crate::{
-filepatterns::PatternResult, utils::hg_path::HgPath, DirsMultiset,
-DirstateMapError, PatternError,
+filepatterns::PatternResult,
+utils::hg_path::{HgPath, HgPathBuf},
+DirsMultiset, DirstateMapError, IgnorePattern, PatternError,
+PatternSyntax,
 };
 use std::collections::HashSet;
 use std::iter::FromIterator;
@@ -242,10 +244,156 @@
 Err(PatternError::Re2NotInstalled)
 }
 
+/// Returns roots and directories corresponding to each pattern.
+///
+/// This calculates the roots and directories exactly matching the patterns and
+/// returns a tuple of (roots, dirs). It does not return other directories
+/// which may also need to be considered, like the parent directories.
+fn roots_and_dirs(
+ignore_patterns: &[IgnorePattern],
+) -> (Vec, Vec) {
+let mut roots = Vec::new();
+let mut dirs = Vec::new();
+
+for ignore_pattern in ignore_patterns {
+let IgnorePattern {
+syntax, pattern, ..
+} = ignore_pattern;
+match syntax {
+PatternSyntax::RootGlob | PatternSyntax::Glob => {
+let mut root = vec![];
+
+for p in pattern.split(|c| *c == b'/') {
+if p.iter().any(|c| match *c {
+b'[' | b'{' | b'*' | b'?' => true,
+_ => false,
+}) {
+break;
+}
+root.push(HgPathBuf::from_bytes(p));
+}
+let buf =
+root.iter().fold(HgPathBuf::new(), |acc, r| acc.join(r));
+roots.push(buf);
+}
+PatternSyntax::Path | PatternSyntax::RelPath => {
+let pat = HgPath::new(if pattern == b"." {
+&[] as &[u8]
+} else {
+pattern
+});
+roots.push(pat.to_owned());
+}
+PatternSyntax::RootFiles => {
+let pat = if pattern == b"." {
+&[] as &[u8]
+} else {
+pattern
+};
+dirs.push(HgPathBuf::from_bytes(pat));
+}
+_ => {
+roots.push(HgPathBuf::new());
+}
+}
+}
+(roots, dirs)
+}
+
+/// Paths extracted from patterns
+#[derive(Debug, PartialEq)]
+struct RootsDirsAndParents {
+/// Directories to match recursively
+pub roots: HashSet,
+/// Directories to match non-recursively
+pub dirs: HashSet,
+/// Implicitly required directories to go to items in either roots or dirs
+pub parents: HashSet,
+}
+
+/// Extract roots, dirs and parents from patterns.
+fn roots_dirs_and_parents(
+ignore_patterns: &[IgnorePattern],
+) -> PatternResult {
+let (roots, dirs) = roots_and_dirs(ignore_patterns);
+
+let mut parents = HashSet::new();
+
+parents.extend(
+DirsMultiset::from_manifest()
+.map_err(|e| match e {
+DirstateMapError::InvalidPath(e) => e,
+_ => unreachable!(),
+})?
+.iter()
+.map(|k| k.to_owned()),
+);
+parents.extend(
+DirsMultiset::from_manifest()
+.map_err(|e| match e {
+DirstateMapError::InvalidPath(e) => e,
+_ => unreachable!(),
+})?
+.iter()
+.map(|k| k.to_owned()),
+);
+
+Ok(RootsDirsAndParents {
+roots: HashSet::from_iter(roots),
+dirs: HashSet::from_iter(dirs),
+parents,
+})
+}
+
 #[cfg(test)]
 mod tests {
 use super::*;
 use pretty_assertions::assert_eq;
+use std::path::Path;
+
+#[test]
+fn test_roots_and_dirs() {
+let pats = vec![
+IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")),
+IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")),
+IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")),
+];
+let (roots, dirs) = roots_and_dirs();
+
+assert_eq!(
+roots,
+vec!(
+HgPathBuf::from_bytes(b"g/h"),
+HgPathBuf::from_bytes(b"g/h"),
+HgPathBuf::new()
+),
+);
+assert_eq!(dirs, vec!());
+}
+
+#[test]
+fn test_roots_dirs_and_parents() {
+

D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19934.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7866?vs=19544=19934

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

AFFECTED FILES
  rust/Cargo.lock
  rust/hg-core/Cargo.toml
  rust/hg-core/src/utils.rs
  rust/hg-core/src/utils/files.rs
  rust/hg-core/src/utils/hg_path.rs
  rust/hg-core/src/utils/path_auditor.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils/path_auditor.rs 
b/rust/hg-core/src/utils/path_auditor.rs
new file mode 100644
--- /dev/null
+++ b/rust/hg-core/src/utils/path_auditor.rs
@@ -0,0 +1,230 @@
+// path_auditor.rs
+//
+// Copyright 2020
+// Raphaël Gomès ,
+//
+// This software may be used and distributed according to the terms of the
+// GNU General Public License version 2 or any later version.
+
+use crate::utils::{
+files::lower_clean,
+find_slice_in_slice,
+hg_path::{hg_path_to_path_buf, HgPath, HgPathBuf, HgPathError},
+};
+use std::collections::HashSet;
+use std::path::{Path, PathBuf};
+
+/// Ensures that a path is valid for use in the repository i.e. does not use
+/// any banned components, does not traverse a symlink, etc.
+#[derive(Debug, Default)]
+pub struct PathAuditor {
+audited: HashSet,
+audited_dirs: HashSet,
+root: PathBuf,
+}
+
+impl PathAuditor {
+pub fn new(root: impl AsRef) -> Self {
+Self {
+root: root.as_ref().to_owned(),
+..Default::default()
+}
+}
+pub fn audit_path(
+ self,
+path: impl AsRef,
+) -> Result<(), HgPathError> {
+// TODO windows "localpath" normalization
+let path = path.as_ref();
+if path.is_empty() {
+return Ok(());
+}
+// TODO case normalization
+if self.audited.contains(path) {
+return Ok(());
+}
+// AIX ignores "/" at end of path, others raise EISDIR.
+let last_byte = path.as_bytes()[path.len() - 1];
+if last_byte == b'/' || last_byte == b'\\' {
+return Err(HgPathError::EndsWithSlash(path.to_owned()));
+}
+let parts: Vec<_> = path
+.as_bytes()
+.split(|b| std::path::is_separator(*b as char))
+.collect();
+
+let first_component = lower_clean(parts[0]);
+let first_component = first_component.as_slice();
+if !path.split_drive().0.is_empty()
+|| (first_component == b".hg"
+|| first_component == b".hg."
+|| first_component == b"")
+|| parts.iter().any(|c| c == b"..")
+{
+return Err(HgPathError::InsideDotHg(path.to_owned()));
+}
+
+// Windows shortname aliases
+for part in parts.iter() {
+if part.contains('~') {
+let mut split = part.splitn(1, |b| *b == b'~');
+let first =
+split.next().unwrap().to_owned().to_ascii_uppercase();
+let last = split.next().unwrap();
+if last.iter().all(u8::is_ascii_digit)
+&& (first == b"HG" || first == b"HG8B6C")
+{
+return Err(HgPathError::ContainsIllegalComponent(
+path.to_owned(),
+));
+}
+}
+}
+let lower_path = lower_clean(path.as_bytes());
+if find_slice_in_slice(_path, b".hg").is_some() {
+let lower_parts: Vec<_> = path
+.as_bytes()
+.split(|b| std::path::is_separator(*b as char))
+.collect();
+for pattern in [b".hg".to_vec(), b".hg.".to_vec()].iter() {
+if let Some(pos) = lower_parts[1..]
+.iter()
+.position(|part| part == _slice())
+{
+let base = lower_parts[..=pos]
+.iter()
+.fold(HgPathBuf::new(), |acc, p| {
+acc.join(HgPath::new(p))
+});
+return Err(HgPathError::IsInsideNestedRepo {
+path: path.to_owned(),
+nested_repo: base,
+});
+}
+}
+}
+
+let parts = [..parts.len().saturating_sub(1)];
+
+// We don't want to add "foo/bar/baz" to `audited_dirs` before checking
+// if there's a "foo/.hg" directory. This also means we won't
+// accidentally traverse a symlink into some other filesystem (which
+// is potentially expensive to access).
+for index in 0..parts.len() {
+let prefix = [..index + 1].join('/');
+let prefix = HgPath::new(prefix);
+if self.audited_dirs.contains(prefix) {
+continue;
+}
+

D7869: rust-dirs-multiset: add `DirsChildrenMultiset`

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19936.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7869?vs=19383=19936

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7869/new/

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

AFFECTED FILES
  rust/hg-core/src/dirstate/dirs_multiset.rs
  rust/hg-core/src/utils/files.rs
  rust/hg-core/src/utils/hg_path.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils/hg_path.rs 
b/rust/hg-core/src/utils/hg_path.rs
--- a/rust/hg-core/src/utils/hg_path.rs
+++ b/rust/hg-core/src/utils/hg_path.rs
@@ -183,6 +183,29 @@
 [..]
 })
 }
+/// Returns a tuple of slices `(base, filename)` resulting from the split
+/// at the rightmost `/`, if any.
+///
+/// # Examples:
+///
+/// ```
+/// use hg::utils::hg_path::HgPath;
+///
+/// let path = HgPath::new(b"cool/hg/path").split_filename();
+/// assert_eq!(path, (HgPath::new(b"cool/hg"), HgPath::new(b"path")));
+///
+/// let path = HgPath::new(b"pathwithoutsep").split_filename();
+/// assert_eq!(path, (HgPath::new(b""), HgPath::new(b"pathwithoutsep")));
+/// ```
+pub fn split_filename() -> (, ) {
+match ().rposition(|c| *c == b'/') {
+None => (HgPath::new(""), ),
+Some(size) => (
+HgPath::new([..*size]),
+HgPath::new([*size + 1..]),
+),
+}
+}
 pub fn join>(, other: ) -> HgPathBuf {
 let mut inner = self.inner.to_owned();
 if inner.len() != 0 && inner.last() != Some('/') {
diff --git a/rust/hg-core/src/utils/files.rs b/rust/hg-core/src/utils/files.rs
--- a/rust/hg-core/src/utils/files.rs
+++ b/rust/hg-core/src/utils/files.rs
@@ -10,11 +10,11 @@
 //! Functions for fiddling with files.
 
 use crate::utils::hg_path::{HgPath, HgPathBuf};
-use std::iter::FusedIterator;
 
 use crate::utils::replace_slice;
 use lazy_static::lazy_static;
 use std::fs::Metadata;
+use std::iter::FusedIterator;
 use std::path::Path;
 
 pub fn get_path_from_bytes(bytes: &[u8]) ->  {
@@ -64,6 +64,28 @@
 
 impl<'a> FusedIterator for Ancestors<'a> {}
 
+/// An iterator over repository path yielding itself and its ancestors.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct AncestorsWithBase<'a> {
+next: Option<(&'a HgPath, &'a HgPath)>,
+}
+
+impl<'a> Iterator for AncestorsWithBase<'a> {
+type Item = (&'a HgPath, &'a HgPath);
+
+fn next( self) -> Option {
+let next = self.next;
+self.next = match self.next {
+Some((s, _)) if s.is_empty() => None,
+Some((s, _)) => Some(s.split_filename()),
+None => None,
+};
+next
+}
+}
+
+impl<'a> FusedIterator for AncestorsWithBase<'a> {}
+
 /// Returns an iterator yielding ancestor directories of the given repository
 /// path.
 ///
@@ -79,6 +101,25 @@
 dirs
 }
 
+/// Returns an iterator yielding ancestor directories of the given repository
+/// path.
+///
+/// The path is separated by '/', and must not start with '/'.
+///
+/// The path itself isn't included unless it is b"" (meaning the root
+/// directory.)
+pub(crate) fn find_dirs_with_base<'a>(
+path: &'a HgPath,
+) -> AncestorsWithBase<'a> {
+let mut dirs = AncestorsWithBase {
+next: Some((path, HgPath::new(b""))),
+};
+if !path.is_empty() {
+dirs.next(); // skip itself
+}
+dirs
+}
+
 /// TODO more than ASCII?
 pub fn normalize_case(path: ) -> HgPathBuf {
 #[cfg(windows)] // NTFS compares via upper()
@@ -170,4 +211,28 @@
 assert_eq!(dirs.next(), None);
 assert_eq!(dirs.next(), None);
 }
+
+#[test]
+fn test_find_dirs_with_base_some() {
+let mut dirs = super::find_dirs_with_base(HgPath::new(b"foo/bar/baz"));
+assert_eq!(
+dirs.next(),
+Some((HgPath::new(b"foo/bar"), HgPath::new(b"baz")))
+);
+assert_eq!(
+dirs.next(),
+Some((HgPath::new(b"foo"), HgPath::new(b"bar")))
+);
+assert_eq!(dirs.next(), Some((HgPath::new(b""), HgPath::new(b"foo";
+assert_eq!(dirs.next(), None);
+assert_eq!(dirs.next(), None);
+}
+
+#[test]
+fn test_find_dirs_with_base_empty() {
+let mut dirs = super::find_dirs_with_base(HgPath::new(b""));
+assert_eq!(dirs.next(), Some((HgPath::new(b""), HgPath::new(b"";
+assert_eq!(dirs.next(), None);
+assert_eq!(dirs.next(), None);
+}
 }
diff --git a/rust/hg-core/src/dirstate/dirs_multiset.rs 
b/rust/hg-core/src/dirstate/dirs_multiset.rs
--- a/rust/hg-core/src/dirstate/dirs_multiset.rs
+++ b/rust/hg-core/src/dirstate/dirs_multiset.rs
@@ -8,12 +8,15 @@
 //! A multiset of directory names.
 //!
 //! Used to counts the references to directories in a manifest or dirstate.
-use crate::utils::hg_path::{HgPath, HgPathBuf};
 use crate::{
-dirstate::EntryState, utils::files, DirstateEntry, 

D7871: rust-utils: add util for canonical path

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19937.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7871?vs=19359=19937

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7871/new/

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

AFFECTED FILES
  rust/Cargo.lock
  rust/hg-core/Cargo.toml
  rust/hg-core/src/utils/files.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils/files.rs b/rust/hg-core/src/utils/files.rs
--- a/rust/hg-core/src/utils/files.rs
+++ b/rust/hg-core/src/utils/files.rs
@@ -9,13 +9,17 @@
 
 //! Functions for fiddling with files.
 
-use crate::utils::hg_path::{HgPath, HgPathBuf};
-
-use crate::utils::replace_slice;
+use crate::utils::{
+hg_path::{path_to_hg_path_buf, HgPath, HgPathBuf, HgPathError},
+path_auditor::PathAuditor,
+replace_slice,
+};
 use lazy_static::lazy_static;
+use same_file::is_same_file;
 use std::fs::Metadata;
 use std::iter::FusedIterator;
-use std::path::Path;
+use std::ops::Deref;
+use std::path::{Path, PathBuf};
 
 pub fn get_path_from_bytes(bytes: &[u8]) ->  {
 let os_str;
@@ -189,9 +193,62 @@
 }
 }
 
+/// Returns the canonical path of `name`, given `cwd` and `root`
+pub fn canonical_path(
+root: impl AsRef,
+cwd: impl AsRef,
+name: impl AsRef,
+) -> Result {
+// TODO add missing normalization for other platforms
+let root = root.as_ref();
+let cwd = cwd.as_ref();
+let name = name.as_ref();
+
+let name = if !name.is_absolute() {
+root.join().join()
+} else {
+name.to_owned()
+};
+let mut auditor = PathAuditor::new();
+if name != root && name.starts_with() {
+let name = name.strip_prefix().unwrap();
+auditor.audit_path(path_to_hg_path_buf(name)?)?;
+return Ok(name.to_owned());
+} else if name == root {
+return Ok("".into());
+} else {
+// Determine whether `name' is in the hierarchy at or beneath `root',
+// by iterating name=name.parent() until that causes no change (can't
+// check name == '/', because that doesn't work on windows).
+let mut name = name.deref();
+loop {
+let same = is_same_file(, ).unwrap_or(false);
+if same {
+if name.components().next().is_none() {
+// `name` was actually the same as root (maybe a symlink)
+return Ok("".into());
+}
+auditor.audit_path(path_to_hg_path_buf(name)?)?;
+return Ok(name.to_owned());
+}
+name = match name.parent() {
+None => break,
+Some(p) => p,
+};
+}
+// TODO hint to the user about using --cwd
+// Bubble up the responsibility to Python for now
+Err(HgPathError::NotUnderRoot {
+path: name.to_owned(),
+root: root.to_owned(),
+})
+}
+}
+
 #[cfg(test)]
 mod tests {
 use super::*;
+use pretty_assertions::assert_eq;
 
 #[test]
 fn find_dirs_some() {
@@ -235,4 +292,53 @@
 assert_eq!(dirs.next(), None);
 assert_eq!(dirs.next(), None);
 }
+
+#[test]
+fn test_canonical_path() {
+let root = Path::new("/repo");
+let cwd = Path::new("/dir");
+let name = Path::new("filename");
+assert_eq!(
+canonical_path(root, cwd, name),
+Err(HgPathError::NotUnderRoot {
+path: PathBuf::from("/"),
+root: root.to_path_buf()
+})
+);
+
+let root = Path::new("/repo");
+let cwd = Path::new("/");
+let name = Path::new("filename");
+assert_eq!(
+canonical_path(root, cwd, name),
+Err(HgPathError::NotUnderRoot {
+path: PathBuf::from("/"),
+root: root.to_path_buf()
+})
+);
+
+let root = Path::new("/repo");
+let cwd = Path::new("/");
+let name = Path::new("repo/filename");
+assert_eq!(
+canonical_path(root, cwd, name),
+Ok(PathBuf::from("filename"))
+);
+
+let root = Path::new("/repo");
+let cwd = Path::new("/repo");
+let name = Path::new("filename");
+assert_eq!(
+canonical_path(root, cwd, name),
+Ok(PathBuf::from("filename"))
+);
+
+let root = Path::new("/repo");
+let cwd = Path::new("/repo/subdir");
+let name = Path::new("filename");
+assert_eq!(
+canonical_path(root, cwd, name),
+Ok(PathBuf::from("subdir/filename"))
+);
+}
 }
diff --git a/rust/hg-core/Cargo.toml b/rust/hg-core/Cargo.toml
--- a/rust/hg-core/Cargo.toml
+++ b/rust/hg-core/Cargo.toml
@@ -18,7 +18,8 @@
 rayon = "1.3.0"
 regex = "1.1.0"
 twox-hash = "1.5.0"
+same-file = "1.0.6"
 
 [dev-dependencies]
 tempfile = "3.1.0"
 pretty_assertions = "0.6.1"
\ No 

D7867: rust-hg-path: add useful methods to `HgPath`

2020-02-06 Thread Raphaël Gomès
Alphare updated this revision to Diff 19935.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7867?vs=19382=19935

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7867/new/

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

AFFECTED FILES
  rust/Cargo.lock
  rust/hg-core/Cargo.toml
  rust/hg-core/src/utils/hg_path.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils/hg_path.rs 
b/rust/hg-core/src/utils/hg_path.rs
--- a/rust/hg-core/src/utils/hg_path.rs
+++ b/rust/hg-core/src/utils/hg_path.rs
@@ -173,10 +173,17 @@
 pub fn contains(, other: u8) -> bool {
 self.inner.contains()
 }
-pub fn starts_with(, needle: impl AsRef) -> bool {
+pub fn starts_with(, needle: impl AsRef) -> bool {
 self.inner.starts_with(needle.as_ref().as_bytes())
 }
-pub fn join>(, other: ) -> HgPathBuf {
+pub fn trim_trailing_slash() ->  {
+Self::new(if self.inner.last() == Some('/') {
+[..self.inner.len() - 1]
+} else {
+[..]
+})
+}
+pub fn join>(, other: ) -> HgPathBuf {
 let mut inner = self.inner.to_owned();
 if inner.len() != 0 && inner.last() != Some('/') {
 inner.push(b'/');
@@ -184,17 +191,24 @@
 inner.extend(other.as_ref().bytes());
 HgPathBuf::from_bytes()
 }
+pub fn parent() ->  {
+let inner = self.as_bytes();
+HgPath::new(match inner.iter().rposition(|b| *b == b'/') {
+Some(pos) => [..pos],
+None => &[],
+})
+}
 /// Given a base directory, returns the slice of `self` relative to the
 /// base directory. If `base` is not a directory (does not end with a
 /// `b'/'`), returns `None`.
-pub fn relative_to(, base: impl AsRef) -> Option<> {
+pub fn relative_to(, base: impl AsRef) -> Option<> {
 let base = base.as_ref();
 if base.is_empty() {
 return Some(self);
 }
 let is_dir = base.as_bytes().ends_with(b"/");
 if is_dir && self.starts_with(base) {
-Some(HgPath::new([base.len()..]))
+Some(Self::new([base.len()..]))
 } else {
 None
 }
@@ -484,6 +498,7 @@
 #[cfg(test)]
 mod tests {
 use super::*;
+use pretty_assertions::assert_eq;
 
 #[test]
 fn test_path_states() {
@@ -712,4 +727,19 @@
 )
 );
 }
+
+#[test]
+fn test_parent() {
+let path = HgPath::new(b"");
+assert_eq!(path.parent(), path);
+
+let path = HgPath::new(b"a");
+assert_eq!(path.parent(), HgPath::new(b""));
+
+let path = HgPath::new(b"a/b");
+assert_eq!(path.parent(), HgPath::new(b"a"));
+
+let path = HgPath::new(b"a/other/b");
+assert_eq!(path.parent(), HgPath::new(b"a/other"));
+}
 }
diff --git a/rust/hg-core/Cargo.toml b/rust/hg-core/Cargo.toml
--- a/rust/hg-core/Cargo.toml
+++ b/rust/hg-core/Cargo.toml
@@ -20,4 +20,5 @@
 twox-hash = "1.5.0"
 
 [dev-dependencies]
-tempfile = "3.1.0"
\ No newline at end of file
+tempfile = "3.1.0"
+pretty_assertions = "0.6.1"
\ No newline at end of file
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -2,13 +2,21 @@
 # It is not intended for manual editing.
 [[package]]
 name = "aho-corasick"
-version = "0.7.7"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index;
 dependencies = [
  "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index;
+dependencies = [
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "autocfg"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index;
@@ -51,13 +59,13 @@
 
 [[package]]
 name = "cpython"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index;
 dependencies = [
  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "python27-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "python3-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -102,6 +110,20 @@
 ]
 
 [[package]]
+name = "ctor"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index;
+dependencies = [
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = 

D7929: rust-status: add bare `hg status` support in hg-core

2020-02-06 Thread Raphaël Gomès
Alphare added inline comments.

INLINE COMMENTS

> marmoute wrote in status.rs:29-38
> I am curious about where this changes comes from? did rust-format changed 
> opinion or did we reached a threshold?

I was fixing conflicts and prefer this style. `rustfmt` does not nest already 
separate imports. If that's an issue I suppose I can change it.

> marmoute wrote in status.rs:241
> Does this TODO affect the "readiness" of this code to be used in production ? 
> If not, can you clarify what that TODO implies ?

Clarified in the updated inline comment. I mainly wanted to avoid even more 
code that had very little chance of being useful. If you disagree, please let 
me know.

> marmoute wrote in status.rs:656
> What's the implication of this comment ? (or rephrase, the consequence on not 
> having that "done" yet?)

Oops, it's "insensitive", not "sensitive".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7929/new/

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

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


D8076: worker: Manually buffer reads from pickle stream

2020-02-06 Thread yuja (Yuya Nishihara)
yuja added a comment.


  > +if pycompat.ispy3:
  > +
  > +class _blockingreader(object):
  > +def __init__(self, wrapped):
  > +self._wrapped = wrapped
  > +
  > +def __getattr__(self, attr):
  > +return getattr(self._wrapped, attr)
  > +
  > +# issue multiple reads until size is fulfilled
  > +def read(self, size=-1):
  > +if size < 0:
  > +return self._wrapped.readall()
  > +
  > +buf = bytearray(size)
  > +view = memoryview(buf)
  > +pos = 0
  > +
  > +while pos < size:
  > +ret = self._wrapped.readinto(view[pos:])
  > +if not ret:
  > +break
  > +pos += ret
  > +
  > +del view
  > +del buf[pos:]
  > +return buf
  
  Might be better to optimize the common case `wrapped.read(size) == size`.
  FWIW, if we don't mind issuing extra `read()` syscalls, maybe we can abuse
  BufferedReader of `buffer_size=1`.
  
  Another option is to rewrite the select loop to fully manage response buffer
  by ourselves.
  
for key, events in selector.select():
...
our_buffer.extend(key.fileobj.read())
temp_io = BytesIO(our_buffer)
while ...:
try:
pickle.load(temp_io)
except ...
...
del our_buffer[:temp_io.tell()]

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8076/new/

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

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


Re: D8076: worker: Manually buffer reads from pickle stream

2020-02-06 Thread Yuya Nishihara
> +if pycompat.ispy3:
> +
> +class _blockingreader(object):
> +def __init__(self, wrapped):
> +self._wrapped = wrapped
> +
> +def __getattr__(self, attr):
> +return getattr(self._wrapped, attr)
> +
> +# issue multiple reads until size is fulfilled
> +def read(self, size=-1):
> +if size < 0:
> +return self._wrapped.readall()
> +
> +buf = bytearray(size)
> +view = memoryview(buf)
> +pos = 0
> +
> +while pos < size:
> +ret = self._wrapped.readinto(view[pos:])
> +if not ret:
> +break
> +pos += ret
> +
> +del view
> +del buf[pos:]
> +return buf

Might be better to optimize the common case `wrapped.read(size) == size`.
FWIW, if we don't mind issuing extra `read()` syscalls, maybe we can abuse
BufferedReader of `buffer_size=1`.

Another option is to rewrite the select loop to fully manage response buffer
by ourselves.

```
for key, events in selector.select():
...
our_buffer.extend(key.fileobj.read())
temp_io = BytesIO(our_buffer)
while ...:
try:
pickle.load(temp_io)
except ...
...
del our_buffer[:temp_io.tell()]
```
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D7867: rust-hg-path: add useful methods to `HgPath`

2020-02-06 Thread Raphaël Gomès
Alphare added inline comments.

INLINE COMMENTS

> martinvonz wrote in hg_path.rs:173
> And what happens if you remove it?

It only breaks the single rust test I had to check for that particular case. 
I'll remove it.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7867/new/

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

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


D7927: rust-status: add util for listing a directory

2020-02-06 Thread Raphaël Gomès
Alphare added inline comments.
Alphare marked an inline comment as done.

INLINE COMMENTS

> marmoute wrote in status.rs:74
> Silly question: would it make sense to sort the filename before the loop ? It 
> might result is less bytes to move around since the entry will not be 
> attached yet.

I'm not entirely sure I understand your question.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7927/new/

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

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


D8039: chg: force-set LC_CTYPE on server start to actual value from the environment

2020-02-06 Thread spectral (Kyle Lippincott)
Closed by commit rHG04a3ae7aba14: chg: force-set LC_CTYPE on server start to 
actual value from the environment (authored by spectral).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8039?vs=19876=19933

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8039/new/

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

AFFECTED FILES
  contrib/chg/chg.c
  mercurial/chgserver.py
  tests/test-chg.t

CHANGE DETAILS

diff --git a/tests/test-chg.t b/tests/test-chg.t
--- a/tests/test-chg.t
+++ b/tests/test-chg.t
@@ -332,8 +332,8 @@
   /MM/DD HH:MM:SS (PID)> log -R cached
   /MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in  ...s)
 
-Test that chg works even when python "coerces" the locale (py3.7+, which is 
done
-by default if none of LC_ALL, LC_CTYPE, or LANG are set in the environment)
+Test that chg works (sets to the user's actual LC_CTYPE) even when python
+"coerces" the locale (py3.7+)
 
   $ cat > $TESTTMP/debugenv.py < from mercurial import encoding
@@ -347,9 +347,22 @@
   > if v is not None:
   > ui.write(b'%s=%s\n' % (k, encoding.environ[k]))
   > EOF
+(hg keeps python's modified LC_CTYPE, chg doesn't)
+  $ (unset LC_ALL; unset LANG; LC_CTYPE= "$CHGHG" \
+  >--config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
+  LC_CTYPE=C.UTF-8 (py37 !)
+  LC_CTYPE= (no-py37 !)
+  $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
+  >--config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
+  LC_CTYPE=
+  $ (unset LC_ALL; unset LANG; LC_CTYPE=unsupported_value chg \
+  >--config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
+  LC_CTYPE=unsupported_value
+  $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
+  >--config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
+  LC_CTYPE=
   $ LANG= LC_ALL= LC_CTYPE= chg \
   >--config extensions.debugenv=$TESTTMP/debugenv.py debugenv
   LC_ALL=
-  LC_CTYPE=C.UTF-8 (py37 !)
-  LC_CTYPE= (no-py37 !)
+  LC_CTYPE=
   LANG=
diff --git a/mercurial/chgserver.py b/mercurial/chgserver.py
--- a/mercurial/chgserver.py
+++ b/mercurial/chgserver.py
@@ -550,40 +550,6 @@
 raise ValueError(b'unexpected value in setenv request')
 self.ui.log(b'chgserver', b'setenv: %r\n', sorted(newenv.keys()))
 
-# Python3 has some logic to "coerce" the C locale to a UTF-8 capable
-# one, and it sets LC_CTYPE in the environment to C.UTF-8 if none of
-# 'LC_CTYPE', 'LC_ALL' or 'LANG' are set (to any value). This can be
-# disabled with PYTHONCOERCECLOCALE=0 in the environment.
-#
-# When fromui is called via _inithashstate, python has already set
-# this, so that's in the environment right when we start up the hg
-# process. Then chg will call us and tell us to set the environment to
-# the one it has; this might NOT have LC_CTYPE, so we'll need to
-# carry-forward the LC_CTYPE that was coerced in these situations.
-#
-# If this is not handled, we will fail config+env validation and fail
-# to start chg. If this is just ignored instead of carried forward, we
-# may have different behavior between chg and non-chg.
-if pycompat.ispy3:
-# Rename for wordwrapping purposes
-oldenv = encoding.environ
-if not any(
-e.get(b'PYTHONCOERCECLOCALE') == b'0' for e in [oldenv, newenv]
-):
-keys = [b'LC_CTYPE', b'LC_ALL', b'LANG']
-old_keys = [k for k, v in oldenv.items() if k in keys and v]
-new_keys = [k for k, v in newenv.items() if k in keys and v]
-# If the user's environment (from chg) doesn't have ANY of the
-# keys that python looks for, and the environment (from
-# initialization) has ONLY LC_CTYPE and it's set to C.UTF-8,
-# carry it forward.
-if (
-not new_keys
-and old_keys == [b'LC_CTYPE']
-and oldenv[b'LC_CTYPE'] == b'C.UTF-8'
-):
-newenv[b'LC_CTYPE'] = oldenv[b'LC_CTYPE']
-
 encoding.environ.clear()
 encoding.environ.update(newenv)
 
@@ -730,6 +696,16 @@
 # environ cleaner.
 if b'CHGINTERNALMARK' in encoding.environ:
 del encoding.environ[b'CHGINTERNALMARK']
+# Python3.7+ "coerces" the LC_CTYPE environment variable to a UTF-8 one if
+# it thinks the current value is "C". This breaks the hash computation and
+# causes chg to restart loop.
+if b'CHGORIG_LC_CTYPE' in encoding.environ:
+encoding.environ[b'LC_CTYPE'] = encoding.environ[b'CHGORIG_LC_CTYPE']
+del encoding.environ[b'CHGORIG_LC_CTYPE']
+elif b'CHG_CLEAR_LC_CTYPE' in encoding.environ:
+   

D8039: chg: force-set LC_CTYPE on server start to actual value from the environment

2020-02-06 Thread yuja (Yuya Nishihara)
yuja added a comment.


  I like the simplicity of this patch. Queued, thanks.
  
  > Computing the hash on the client avoids the restart loop, but doesn't avoid 
the behavior difference - chg will still call setenv and replace the modified 
version with the original one.
  
  Indeed.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8039/new/

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

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


Re: D8039: chg: force-set LC_CTYPE on server start to actual value from the environment

2020-02-06 Thread Yuya Nishihara
I like the simplicity of this patch. Queued, thanks.

> Computing the hash on the client avoids the restart loop, but doesn't avoid 
> the behavior difference - chg will still call setenv and replace the modified 
> version with the original one.

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


D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread Raphaël Gomès
Alphare added inline comments.

INLINE COMMENTS

> martinvonz wrote in path_auditor.rs:86
> Sorry, I just meant that we do it this way so that we can provide different 
> error messages for "inside .hg" and "inside subrepo" :)

Good idea. I'm rewriting my patches, I will soon send an update for all of them.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

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


D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> Alphare wrote in path_auditor.rs:86
> I see. What error message do you propose?

Sorry, I just meant that we do it this way so that we can provide different 
error messages for "inside .hg" and "inside subrepo" :)

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

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


D7733: hgext: initial version of fastexport extension

2020-02-06 Thread joerg.sonnenberger (Joerg Sonnenberger)
joerg.sonnenberger added a comment.


  Now blank and Python 3 clean.

INLINE COMMENTS

> pulkit wrote in fastexport.py:110
> These temporary variables can be prevented.

Will be dropped.

> pulkit wrote in fastexport.py:121
> This one is also same as `ctx.files()` I guess. I remember @martinvonz  did 
> some cleanup here.

For a merge, ctx.files() doesn't contain added or removed files relative to one 
parent. This is covered by tests.

> pulkit wrote in fastexport.py:123
> This one seems same as `ctx.files()`

It is nowadays.

> pulkit wrote in fastexport.py:151
> s/marks/marker seems clearer in the flag name.
> It's not clear what a marker means. There seems to be no tests for these 
> flags too.
> 
> Also, what do you think about having a single flag where you read markers 
> from that file and write back to it.

This follows the terminology used in other implementations of this 
functionality and being consistent on that front seems more important. That 
said, I'm changing it to `marks file` consistently. A single flag doesn't help 
with typical use cases. For incremental conversion, you only want to use the 
newly created marks file when the other part of the conversion (e.g. `git 
fast-import`) was successful too.

> pulkit wrote in fastexport.py:166
> this temporary variable can be prevented too

I don't like doing the lookup twice, so I would prefer to keep the variable in 
this case.

> pulkit wrote in test-fastexport.t:117
> any reason you redirect the output in a file and then cat it instead of just 
> printing them on stdout?

It was easier for testing. Dropping this part.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7733/new/

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

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


D7733: hgext: initial version of fastexport extension

2020-02-06 Thread joerg.sonnenberger (Joerg Sonnenberger)
joerg.sonnenberger marked 8 inline comments as done.
joerg.sonnenberger updated this revision to Diff 19932.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7733?vs=18949=19932

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7733/new/

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

AFFECTED FILES
  hgext/fastexport.py
  tests/test-fastexport.t
  tests/test-help.t

CHANGE DETAILS

diff --git a/tests/test-help.t b/tests/test-help.t
--- a/tests/test-help.t
+++ b/tests/test-help.t
@@ -364,6 +364,7 @@
eol   automatically manage newlines in repository files
extdiff   command to allow external programs to compare revisions
factotum  http authentication with factotum
+   fastexportexport repositories as git fast-import stream
githelp   try mapping git commands to Mercurial commands
gpg   commands to sign and verify changesets
hgk   browse the repository in a graphical way
diff --git a/tests/test-fastexport.t b/tests/test-fastexport.t
new file mode 100644
--- /dev/null
+++ b/tests/test-fastexport.t
@@ -0,0 +1,855 @@
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > fastexport=
+  > EOF
+
+  $ hg init
+
+  $ hg debugbuilddag -mon '+2:tbase @name1 +3:thead1  0 -
+  data 2
+  r0
+  M 644 :1 mf
+  M 644 :2 nf0
+  M 644 :2 of
+  
+  blob
+  mark :4
+  data 68
+  0 r0
+  1
+  2 r1
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :5
+  data 3
+  r1
+  
+  blob
+  mark :6
+  data 3
+  r1
+  
+  commit refs/heads/default
+  mark :7
+  committer "debugbuilddag"  1 -
+  data 2
+  r1
+  from :3
+  M 644 :4 mf
+  M 644 :5 nf1
+  M 644 :6 of
+  
+  blob
+  mark :8
+  data 71
+  0 r0
+  1
+  2 r1
+  3
+  4 r2
+  5
+  6
+  7
+  8
+  9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :9
+  data 3
+  r2
+  
+  blob
+  mark :10
+  data 3
+  r2
+  
+  commit refs/heads/name1
+  mark :11
+  committer "debugbuilddag"  2 -
+  data 2
+  r2
+  from :7
+  M 644 :8 mf
+  M 644 :9 nf2
+  M 644 :10 of
+  
+  blob
+  mark :12
+  data 74
+  0 r0
+  1
+  2 r1
+  3
+  4 r2
+  5
+  6 r3
+  7
+  8
+  9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :13
+  data 3
+  r3
+  
+  blob
+  mark :14
+  data 3
+  r3
+  
+  commit refs/heads/name1
+  mark :15
+  committer "debugbuilddag"  3 -
+  data 2
+  r3
+  from :11
+  M 644 :12 mf
+  M 644 :13 nf3
+  M 644 :14 of
+  
+  blob
+  mark :16
+  data 77
+  0 r0
+  1
+  2 r1
+  3
+  4 r2
+  5
+  6 r3
+  7
+  8 r4
+  9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :17
+  data 3
+  r4
+  
+  blob
+  mark :18
+  data 3
+  r4
+  
+  commit refs/heads/name1
+  mark :19
+  committer "debugbuilddag"  4 -
+  data 2
+  r4
+  from :15
+  M 644 :16 mf
+  M 644 :17 nf4
+  M 644 :18 of
+  
+  blob
+  mark :20
+  data 71
+  0 r0
+  1
+  2 r1
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+  10 r5
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :21
+  data 3
+  r5
+  
+  blob
+  mark :22
+  data 3
+  r5
+  
+  commit refs/heads/name2
+  mark :23
+  committer "debugbuilddag"  5 -
+  data 2
+  r5
+  from :7
+  M 644 :20 mf
+  M 644 :21 nf5
+  M 644 :22 of
+  
+  blob
+  mark :24
+  data 74
+  0 r0
+  1
+  2 r1
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+  10 r5
+  11
+  12 r6
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :25
+  data 3
+  r6
+  
+  blob
+  mark :26
+  data 3
+  r6
+  
+  commit refs/heads/name2
+  mark :27
+  committer "debugbuilddag"  6 -
+  data 2
+  r6
+  from :23
+  M 644 :24 mf
+  M 644 :25 nf6
+  M 644 :26 of
+  
+  blob
+  mark :28
+  data 77
+  0 r0
+  1
+  2 r1
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+  10 r5
+  11
+  12 r6
+  13
+  14 r7
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :29
+  data 3
+  r7
+  
+  blob
+  mark :30
+  data 3
+  r7
+  
+  commit refs/heads/name2
+  mark :31
+  committer "debugbuilddag"  7 -
+  data 2
+  r7
+  from :27
+  M 644 :28 mf
+  M 644 :29 nf7
+  M 644 :30 of
+  
+  blob
+  mark :32
+  data 80
+  0 r0
+  1
+  2 r1
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+  10 r5
+  11
+  12 r6
+  13
+  14 r7
+  15
+  16 r8
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :33
+  data 3
+  r8
+  
+  blob
+  mark :34
+  data 3
+  r8
+  
+  commit refs/heads/name2
+  mark :35
+  committer "debugbuilddag"  8 -
+  data 2
+  r8
+  from :31
+  M 644 :32 mf
+  M 644 :33 nf8
+  M 644 :34 of
+  
+  blob
+  mark :36
+  data 92
+  0 r0
+  1
+  2 r1
+  3
+  4 r2
+  5
+  6 r3
+  7
+  8 r4
+  9
+  10 r5
+  11
+  12 r6
+  13
+  14 r7
+  15
+  16 r8
+  17
+  18 r9
+  19
+  20
+  21
+  22
+  23
+  
+  blob
+  mark :37
+  data 3
+  r9
+  
+  

D8078: copies: add a new test dedicated to testing chain of changeset with merge

2020-02-06 Thread marmoute (Pierre-Yves David)
marmoute edited the summary of this revision.
marmoute retitled this revision from "tests/test-copies-chain-merge.t" to 
"copies: add a new test dedicated to testing chain of changeset with merge".
marmoute updated this revision to Diff 19931.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8078?vs=19908=19931

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8078/new/

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

AFFECTED FILES
  tests/test-copies-chain-merge.t

CHANGE DETAILS

diff --git a/tests/test-copies-chain-merge.t b/tests/test-copies-chain-merge.t
new file mode 100644
--- /dev/null
+++ b/tests/test-copies-chain-merge.t
@@ -0,0 +1,619 @@
+=
+Test Copy tracing for chain of copies involving merge
+=
+
+This test files covers copies/rename case for a chains of commit where merges
+are involved. It cheks we do not have unwanted update of behavior and that the
+different options to retrieve copies behave correctly.
+
+Setup
+=
+
+use git diff to see rename
+
+  $ cat << EOF >> $HGRCPATH
+  > [diff]
+  > git=yes
+  > [ui]
+  > logtemplate={rev} {desc}]\n
+  > EOF
+
+  $ hg init repo-chain
+  $ cd repo-chain
+
+Add some linear rename initialy
+
+  $ touch a b
+  $ hg ci -Am 'i-0 initial commit: a b'
+  adding a
+  adding b
+  $ hg mv a c
+  $ hg ci -Am 'i-1: a -move-> c'
+  $ hg mv c d
+  $ hg ci -Am 'i-2: c -move-> d'
+  $ hg log -G
+  @  2 i-2: c -move-> d]
+  |
+  o  1 i-1: a -move-> c]
+  |
+  o  0 i-0 initial commit: a b]
+  
+
+Have a branching with nothing on one side
+
+  $ hg mv d e
+  $ hg ci -Am 'a-1: d -move-> e'
+  $ hg mv e f
+  $ hg ci -Am 'a-2: e -move-> f'
+  $ hg log -G --rev '::.'
+  @  4 a-2: e -move-> f]
+  |
+  o  3 a-1: d -move-> e]
+  |
+  o  2 i-2: c -move-> d]
+  |
+  o  1 i-1: a -move-> c]
+  |
+  o  0 i-0 initial commit: a b]
+  
+
+And Having another branch with renames on the other side
+
+  $ hg up 'desc("i-2")'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo foo > b
+  $ hg ci -m 'b-1: b update'
+  created new head
+  $ hg log -G --rev '::.'
+  @  5 b-1: b update]
+  |
+  o  2 i-2: c -move-> d]
+  |
+  o  1 i-1: a -move-> c]
+  |
+  o  0 i-0 initial commit: a b]
+  
+
+
+Merge the two branches we just defined (in both directions)
+- one with change to an unrelated file
+- one with renames in them
+
+  $ hg up 'desc("b-1")'
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge 'desc("a-2")'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg ci -m 'mBAm-0 simple merge - one way'
+  $ hg up 'desc("a-2")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge 'desc("b-1")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg ci -m 'mABm-0 simple merge - the other way'
+  created new head
+  $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
+  @7 mABm-0 simple merge - the other way]
+  |\
+  +---o  6 mBAm-0 simple merge - one way]
+  | |/
+  | o  5 b-1: b update]
+  | |
+  o |  4 a-2: e -move-> f]
+  | |
+  o |  3 a-1: d -move-> e]
+  |/
+  o  2 i-2: c -move-> d]
+  |
+  o  1 i-1: a -move-> c]
+  |
+  o  0 i-0 initial commit: a b]
+  
+
+Create a branch that delete a file previous renamed
+
+  $ hg up 'desc("i-2")'
+  2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg rm d
+  $ hg ci -m 'c-1 delete d'
+  created new head
+  $ hg log -G --rev '::.'
+  @  8 c-1 delete d]
+  |
+  o  2 i-2: c -move-> d]
+  |
+  o  1 i-1: a -move-> c]
+  |
+  o  0 i-0 initial commit: a b]
+  
+
+Merge:
+- one with change to an unrelated file
+- one deleting the change
+and recreate an unrelated file after the merge
+
+  $ hg up 'desc("b-1")'
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge 'desc("c-1")'
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg ci -m 'mBCm-0 simple merge - one way'
+  $ echo bar > d
+  $ hg add d
+  $ hg ci -m 'mBCm-1 re-add d'
+  $ hg up 'desc("c-1")'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge 'desc("b-1")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg ci -m 'mCBm-0 simple merge - the other way'
+  created new head
+  $ echo bar > d
+  $ hg add d
+  $ hg ci -m 'mCBm-1 re-add d'
+  $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
+  @  12 mCBm-1 re-add d]
+  |
+  o11 mCBm-0 simple merge - the other way]
+  |\
+  | | o  10 mBCm-1 re-add d]
+  | | |
+  +---o  9 mBCm-0 simple merge - one way]
+  | |/
+  | o  8 c-1 delete d]
+  | |
+  o |  5 b-1: b update]
+  |/
+  o  2 i-2: c -move-> d]
+  |
+  o  1 i-1: a -move-> c]
+  

D7928: rust-status: add function for sequential traversal of the working directory

2020-02-06 Thread Raphaël Gomès
Alphare added a comment.
Alphare marked an inline comment as done.


  In D7928#119428 , @marmoute 
wrote:
  
  > There is a lot going on in this changeset. I am counting at least:
  >
  > - new `BadType/BadMatch` structs,
  > - `StatusResult` → `DirstateStatus` change,
  > - new `StatusOptions` struct
  > - new `traverse_worker` function.
  >
  > Can we get the smaller cleanup as reparated chagneset before hand? It would 
make the thing clearer in my opinion.
  
  I don't think the `BadType/BadMatch` struct warrant a new changeset. I'll 
split into 3 then.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7928/new/

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

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


D7866: rust-pathauditor: add Rust implementation of the `pathauditor`

2020-02-06 Thread Raphaël Gomès
Alphare added inline comments.

INLINE COMMENTS

> martinvonz wrote in path_auditor.rs:86
> Since `HgRepoPath` is a path that's stored in the repo, I don't think so. Oh, 
> we just want to provide a different error message so we handle that further 
> up (lines 60-61).

I see. What error message do you propose?

> martinvonz wrote in path_auditor.rs:57-58
> nit 1: inline the first `first_component` rather than redefining it on the 
> next line?
> nit 2: does `as_slice()` better convey what the second line does?

nit 1: that creates a temporary variable that is instantly freed, so no luck 
there

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7866/new/

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

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


D8078: tests/test-copies-chain-merge.t

2020-02-06 Thread marmoute (Pierre-Yves David)
marmoute added a comment.


  oops, this one got out by mistake.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8078/new/

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

To: marmoute, #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


D7969: exchange: check the `ui.clonebundleprefers` form while processing (issue6257)

2020-02-06 Thread marmoute (Pierre-Yves David)
marmoute added inline comments.

INLINE COMMENTS

> mharbison72 wrote in test-clonebundles.t:458-464
> Not sure I understand.  There are a handful of tests in test-clonebundles.t 
> that have multiple key/value pairs already, so the good case is covered.  (I 
> missed this before and thought that I commented there was no coverage, but I 
> was wrong and don't see that comment now.)
> 
> The setting needs to be in `ui.clonebundles=key=value[,key=value]` form.  So 
> if it catches a single malformed key/value pair, I'm not sure that it buys us 
> anything to have a `good,bad` test too, unless I'm missing something.

a test mixing good and bad would check that we report error on the appropriate 
blocks.

something like:

$ hg --config ui.clonebundleprefers=extra=b,bad,COMPRESSION=unknown clone -U 
http://localhost:$HGPORT bad-input

  abort: invalid ui.clonebundleprefers item: bad
  (each comma separated item should be key=value pairs)
  [255]

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7969/new/

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

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


D6846: packaging: script the building of a MacOS installer using a custom python

2020-02-06 Thread marmoute (Pierre-Yves David)
marmoute added a comment.


  Ha, ok.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D6846/new/

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

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