Patchwork match: introduce nevermatcher for when no ignore files are present

login
register
mail settings
Submitter Siddharth Agarwal
Date June 1, 2017, 7:41 a.m.
Message ID <14f332c8fe10c498e7c3.1496302876@devvm31800.prn1.facebook.com>
Download mbox | patch
Permalink /patch/21115/
State Accepted
Headers show

Comments

Siddharth Agarwal - June 1, 2017, 7:41 a.m.
# HG changeset patch
# User Siddharth Agarwal <sid0@fb.com>
# Date 1496302852 25200
#      Thu Jun 01 00:40:52 2017 -0700
# Node ID 14f332c8fe10c498e7c35bef09e53b8b6c7e5f43
# Parent  dbf330cadc5a3c0707c4611f2f4150be13cac02a
match: introduce nevermatcher for when no ignore files are present

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

Introduce `nevermatcher` and switch to it. This neatly parallels
`alwaysmatcher`.
Augie Fackler - June 1, 2017, 2:19 p.m.
On Thu, Jun 01, 2017 at 12:41:16AM -0700, Siddharth Agarwal wrote:
> # HG changeset patch
> # User Siddharth Agarwal <sid0@fb.com>
> # Date 1496302852 25200
> #      Thu Jun 01 00:40:52 2017 -0700
> # Node ID 14f332c8fe10c498e7c35bef09e53b8b6c7e5f43
> # Parent  dbf330cadc5a3c0707c4611f2f4150be13cac02a
> match: introduce nevermatcher for when no ignore files are present

Queued, thanks.

> 952017471f93 introduced a deterministic `__repr__` for ignores. However, it
> didn't account for when ignore was `util.never`. This broke fsmonitor's ignore
> change detection -- with an empty hgignore, it would kick in all the time.
>
> Introduce `nevermatcher` and switch to it. This neatly parallels
> `alwaysmatcher`.
>
> diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
> --- a/mercurial/dirstate.py
> +++ b/mercurial/dirstate.py
> @@ -232,7 +232,7 @@ class dirstate(object):
>      def _ignore(self):
>          files = self._ignorefiles()
>          if not files:
> -            return util.never
> +            return matchmod.never(self._root, '')
>
>          pats = ['include:%s' % f for f in files]
>          return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
> diff --git a/mercurial/match.py b/mercurial/match.py
> --- a/mercurial/match.py
> +++ b/mercurial/match.py
> @@ -175,6 +175,9 @@ def exact(root, cwd, files, badfn=None):
>  def always(root, cwd):
>      return alwaysmatcher(root, cwd)
>
> +def never(root, cwd):
> +    return nevermatcher(root, cwd)
> +
>  def badmatch(match, badfn):
>      """Make a copy of the given matcher, replacing its bad method with the given
>      one.
> @@ -339,6 +342,25 @@ class alwaysmatcher(basematcher):
>      def __repr__(self):
>          return '<alwaysmatcher>'
>
> +class nevermatcher(basematcher):
> +    '''Matches nothing.'''
> +
> +    def __init__(self, root, cwd, badfn=None, relativeuipath=False):
> +        super(nevermatcher, self).__init__(root, cwd, badfn,
> +                                           relativeuipath=relativeuipath)
> +
> +    def always(self):
> +        return False
> +
> +    def matchfn(self, f):
> +        return False
> +
> +    def visitdir(self, dir):
> +        return False
> +
> +    def __repr__(self):
> +        return '<nevermatcher>'
> +
>  class patternmatcher(basematcher):
>
>      def __init__(self, root, cwd, kindpats, ctx=None, listsubrepos=False,
> diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
> --- a/tests/test-hgignore.t
> +++ b/tests/test-hgignore.t
> @@ -1,6 +1,10 @@
>    $ hg init ignorerepo
>    $ cd ignorerepo
>
> +debugignore with no hgignore should be deterministic:
> +  $ hg debugignore
> +  <nevermatcher>
> +
>  Issue562: .hgignore requires newline at end:
>
>    $ touch foo
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
via Mercurial-devel - June 1, 2017, 3:24 p.m.
On Thu, Jun 1, 2017 at 7:19 AM, Augie Fackler <raf@durin42.com> wrote:
> On Thu, Jun 01, 2017 at 12:41:16AM -0700, Siddharth Agarwal wrote:
>> # HG changeset patch
>> # User Siddharth Agarwal <sid0@fb.com>
>> # Date 1496302852 25200
>> #      Thu Jun 01 00:40:52 2017 -0700
>> # Node ID 14f332c8fe10c498e7c35bef09e53b8b6c7e5f43
>> # Parent  dbf330cadc5a3c0707c4611f2f4150be13cac02a
>> match: introduce nevermatcher for when no ignore files are present

Great, I had meant to add this anyway, but I didn't know I had a reason to :-)

>
> Queued, thanks.
>
>> 952017471f93 introduced a deterministic `__repr__` for ignores. However, it
>> didn't account for when ignore was `util.never`.

Oh, sorry about that, I had no idea it could be anything other than a matcher.

>> This broke fsmonitor's ignore
>> change detection -- with an empty hgignore, it would kick in all the time.
>>
>> Introduce `nevermatcher` and switch to it. This neatly parallels
>> `alwaysmatcher`.
>>
>> diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
>> --- a/mercurial/dirstate.py
>> +++ b/mercurial/dirstate.py
>> @@ -232,7 +232,7 @@ class dirstate(object):
>>      def _ignore(self):
>>          files = self._ignorefiles()
>>          if not files:
>> -            return util.never
>> +            return matchmod.never(self._root, '')
>>
>>          pats = ['include:%s' % f for f in files]
>>          return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
>> diff --git a/mercurial/match.py b/mercurial/match.py
>> --- a/mercurial/match.py
>> +++ b/mercurial/match.py
>> @@ -175,6 +175,9 @@ def exact(root, cwd, files, badfn=None):
>>  def always(root, cwd):
>>      return alwaysmatcher(root, cwd)
>>
>> +def never(root, cwd):
>> +    return nevermatcher(root, cwd)
>> +
>>  def badmatch(match, badfn):
>>      """Make a copy of the given matcher, replacing its bad method with the given
>>      one.
>> @@ -339,6 +342,25 @@ class alwaysmatcher(basematcher):
>>      def __repr__(self):
>>          return '<alwaysmatcher>'
>>
>> +class nevermatcher(basematcher):
>> +    '''Matches nothing.'''
>> +
>> +    def __init__(self, root, cwd, badfn=None, relativeuipath=False):
>> +        super(nevermatcher, self).__init__(root, cwd, badfn,
>> +                                           relativeuipath=relativeuipath)
>> +
>> +    def always(self):
>> +        return False
>> +
>> +    def matchfn(self, f):
>> +        return False
>> +
>> +    def visitdir(self, dir):
>> +        return False

These three are all copying the behavior from basematcher. I'll
rewrite the queued commit. I'll also update the existing comment that
says 'probably adding a "nevermatcher"' to say 'using nevermatcher'
now that it exists :-)

>> +
>> +    def __repr__(self):
>> +        return '<nevermatcher>'
>> +
>>  class patternmatcher(basematcher):
>>
>>      def __init__(self, root, cwd, kindpats, ctx=None, listsubrepos=False,
>> diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
>> --- a/tests/test-hgignore.t
>> +++ b/tests/test-hgignore.t
>> @@ -1,6 +1,10 @@
>>    $ hg init ignorerepo
>>    $ cd ignorerepo
>>
>> +debugignore with no hgignore should be deterministic:
>> +  $ hg debugignore
>> +  <nevermatcher>
>> +
>>  Issue562: .hgignore requires newline at end:
>>
>>    $ touch foo
>> _______________________________________________
>> Mercurial-devel mailing list
>> Mercurial-devel@mercurial-scm.org
>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
via Mercurial-devel - June 1, 2017, 3:25 p.m.
On Thu, Jun 1, 2017 at 8:24 AM, Martin von Zweigbergk
<martinvonz@google.com> wrote:
> On Thu, Jun 1, 2017 at 7:19 AM, Augie Fackler <raf@durin42.com> wrote:
>> On Thu, Jun 01, 2017 at 12:41:16AM -0700, Siddharth Agarwal wrote:
>>> # HG changeset patch
>>> # User Siddharth Agarwal <sid0@fb.com>
>>> # Date 1496302852 25200
>>> #      Thu Jun 01 00:40:52 2017 -0700
>>> # Node ID 14f332c8fe10c498e7c35bef09e53b8b6c7e5f43
>>> # Parent  dbf330cadc5a3c0707c4611f2f4150be13cac02a
>>> match: introduce nevermatcher for when no ignore files are present
>
> Great, I had meant to add this anyway, but I didn't know I had a reason to :-)
>
>>
>> Queued, thanks.
>>
>>> 952017471f93 introduced a deterministic `__repr__` for ignores. However, it
>>> didn't account for when ignore was `util.never`.
>
> Oh, sorry about that, I had no idea it could be anything other than a matcher.
>
>>> This broke fsmonitor's ignore
>>> change detection -- with an empty hgignore, it would kick in all the time.
>>>
>>> Introduce `nevermatcher` and switch to it. This neatly parallels
>>> `alwaysmatcher`.
>>>
>>> diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
>>> --- a/mercurial/dirstate.py
>>> +++ b/mercurial/dirstate.py
>>> @@ -232,7 +232,7 @@ class dirstate(object):
>>>      def _ignore(self):
>>>          files = self._ignorefiles()
>>>          if not files:
>>> -            return util.never
>>> +            return matchmod.never(self._root, '')
>>>
>>>          pats = ['include:%s' % f for f in files]
>>>          return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
>>> diff --git a/mercurial/match.py b/mercurial/match.py
>>> --- a/mercurial/match.py
>>> +++ b/mercurial/match.py
>>> @@ -175,6 +175,9 @@ def exact(root, cwd, files, badfn=None):
>>>  def always(root, cwd):
>>>      return alwaysmatcher(root, cwd)
>>>
>>> +def never(root, cwd):
>>> +    return nevermatcher(root, cwd)
>>> +
>>>  def badmatch(match, badfn):
>>>      """Make a copy of the given matcher, replacing its bad method with the given
>>>      one.
>>> @@ -339,6 +342,25 @@ class alwaysmatcher(basematcher):
>>>      def __repr__(self):
>>>          return '<alwaysmatcher>'
>>>
>>> +class nevermatcher(basematcher):
>>> +    '''Matches nothing.'''
>>> +
>>> +    def __init__(self, root, cwd, badfn=None, relativeuipath=False):
>>> +        super(nevermatcher, self).__init__(root, cwd, badfn,
>>> +                                           relativeuipath=relativeuipath)

Oh, and do we really need the relativeuipath argument? I'll drop that
too unless you see a reason to keep it.

>>> +
>>> +    def always(self):
>>> +        return False
>>> +
>>> +    def matchfn(self, f):
>>> +        return False
>>> +
>>> +    def visitdir(self, dir):
>>> +        return False
>
> These three are all copying the behavior from basematcher. I'll
> rewrite the queued commit. I'll also update the existing comment that
> says 'probably adding a "nevermatcher"' to say 'using nevermatcher'
> now that it exists :-)
>
>>> +
>>> +    def __repr__(self):
>>> +        return '<nevermatcher>'
>>> +
>>>  class patternmatcher(basematcher):
>>>
>>>      def __init__(self, root, cwd, kindpats, ctx=None, listsubrepos=False,
>>> diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
>>> --- a/tests/test-hgignore.t
>>> +++ b/tests/test-hgignore.t
>>> @@ -1,6 +1,10 @@
>>>    $ hg init ignorerepo
>>>    $ cd ignorerepo
>>>
>>> +debugignore with no hgignore should be deterministic:
>>> +  $ hg debugignore
>>> +  <nevermatcher>
>>> +
>>>  Issue562: .hgignore requires newline at end:
>>>
>>>    $ touch foo
>>> _______________________________________________
>>> Mercurial-devel mailing list
>>> Mercurial-devel@mercurial-scm.org
>>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>> _______________________________________________
>> Mercurial-devel mailing list
>> Mercurial-devel@mercurial-scm.org
>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
via Mercurial-devel - June 1, 2017, 3:39 p.m.
On Thu, Jun 1, 2017 at 8:25 AM, Martin von Zweigbergk
<martinvonz@google.com> wrote:
> On Thu, Jun 1, 2017 at 8:24 AM, Martin von Zweigbergk
> <martinvonz@google.com> wrote:
>> On Thu, Jun 1, 2017 at 7:19 AM, Augie Fackler <raf@durin42.com> wrote:
>>> On Thu, Jun 01, 2017 at 12:41:16AM -0700, Siddharth Agarwal wrote:
>>>> # HG changeset patch
>>>> # User Siddharth Agarwal <sid0@fb.com>
>>>> # Date 1496302852 25200
>>>> #      Thu Jun 01 00:40:52 2017 -0700
>>>> # Node ID 14f332c8fe10c498e7c35bef09e53b8b6c7e5f43
>>>> # Parent  dbf330cadc5a3c0707c4611f2f4150be13cac02a
>>>> match: introduce nevermatcher for when no ignore files are present
>>
>> Great, I had meant to add this anyway, but I didn't know I had a reason to :-)
>>
>>>
>>> Queued, thanks.
>>>
>>>> 952017471f93 introduced a deterministic `__repr__` for ignores. However, it
>>>> didn't account for when ignore was `util.never`.
>>
>> Oh, sorry about that, I had no idea it could be anything other than a matcher.
>>
>>>> This broke fsmonitor's ignore
>>>> change detection -- with an empty hgignore, it would kick in all the time.
>>>>
>>>> Introduce `nevermatcher` and switch to it. This neatly parallels
>>>> `alwaysmatcher`.
>>>>
>>>> diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
>>>> --- a/mercurial/dirstate.py
>>>> +++ b/mercurial/dirstate.py
>>>> @@ -232,7 +232,7 @@ class dirstate(object):
>>>>      def _ignore(self):
>>>>          files = self._ignorefiles()
>>>>          if not files:
>>>> -            return util.never
>>>> +            return matchmod.never(self._root, '')
>>>>
>>>>          pats = ['include:%s' % f for f in files]
>>>>          return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
>>>> diff --git a/mercurial/match.py b/mercurial/match.py
>>>> --- a/mercurial/match.py
>>>> +++ b/mercurial/match.py
>>>> @@ -175,6 +175,9 @@ def exact(root, cwd, files, badfn=None):
>>>>  def always(root, cwd):
>>>>      return alwaysmatcher(root, cwd)
>>>>
>>>> +def never(root, cwd):
>>>> +    return nevermatcher(root, cwd)
>>>> +
>>>>  def badmatch(match, badfn):
>>>>      """Make a copy of the given matcher, replacing its bad method with the given
>>>>      one.
>>>> @@ -339,6 +342,25 @@ class alwaysmatcher(basematcher):
>>>>      def __repr__(self):
>>>>          return '<alwaysmatcher>'
>>>>
>>>> +class nevermatcher(basematcher):
>>>> +    '''Matches nothing.'''
>>>> +
>>>> +    def __init__(self, root, cwd, badfn=None, relativeuipath=False):
>>>> +        super(nevermatcher, self).__init__(root, cwd, badfn,
>>>> +                                           relativeuipath=relativeuipath)
>
> Oh, and do we really need the relativeuipath argument? I'll drop that
> too unless you see a reason to keep it.
>
>>>> +
>>>> +    def always(self):
>>>> +        return False
>>>> +
>>>> +    def matchfn(self, f):
>>>> +        return False
>>>> +
>>>> +    def visitdir(self, dir):
>>>> +        return False
>>
>> These three are all copying the behavior from basematcher. I'll
>> rewrite the queued commit.

Your patch was already deeper in the stack than I was willing to
review right now (updating it and pushing implies approving everything
after it), so I sent a followup instead.

>> I'll also update the existing comment that
>> says 'probably adding a "nevermatcher"' to say 'using nevermatcher'
>> now that it exists :-)
>>
>>>> +
>>>> +    def __repr__(self):
>>>> +        return '<nevermatcher>'
>>>> +
>>>>  class patternmatcher(basematcher):
>>>>
>>>>      def __init__(self, root, cwd, kindpats, ctx=None, listsubrepos=False,
>>>> diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
>>>> --- a/tests/test-hgignore.t
>>>> +++ b/tests/test-hgignore.t
>>>> @@ -1,6 +1,10 @@
>>>>    $ hg init ignorerepo
>>>>    $ cd ignorerepo
>>>>
>>>> +debugignore with no hgignore should be deterministic:
>>>> +  $ hg debugignore
>>>> +  <nevermatcher>
>>>> +
>>>>  Issue562: .hgignore requires newline at end:
>>>>
>>>>    $ touch foo
>>>> _______________________________________________
>>>> Mercurial-devel mailing list
>>>> Mercurial-devel@mercurial-scm.org
>>>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>> _______________________________________________
>>> Mercurial-devel mailing list
>>> Mercurial-devel@mercurial-scm.org
>>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Patch

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