commit:     deb87a465306d05146d7eb55d27d7d89943725c0
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Jun 24 21:42:52 2018 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Jun 27 03:15:08 2018 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=deb87a46

{,PKG_}INSTALL_MASK: support trailing slash (bug 658322)

Fix the python INSTALL_MASK implementation so that a trailing slash
matches a directory, for compatibility with the previous bash
implementation.

Fixes: 3416876c0ee7 ("{,PKG_}INSTALL_MASK: python implementation")
Bug: https://bugs.gentoo.org/658322

 pym/portage/tests/util/test_install_mask.py | 129 ++++++++++++++++++++++++++++
 pym/portage/util/install_mask.py            |   7 +-
 2 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/util/test_install_mask.py 
b/pym/portage/tests/util/test_install_mask.py
new file mode 100644
index 000000000..f651eb4b7
--- /dev/null
+++ b/pym/portage/tests/util/test_install_mask.py
@@ -0,0 +1,129 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util.install_mask import InstallMask
+
+
+class InstallMaskTestCase(TestCase):
+
+       def testTrailingSlash(self):
+               """
+               Test that elements with a trailing slash match a directory
+               but not a regular file.
+               """
+               cases = (
+                       (
+                               '/foo/bar/ -/foo/bar/*.foo -*.baz',
+                               (
+                                       (
+                                               'foo/bar/baz',
+                                               True,
+                                       ),
+                                       (
+                                               'foo/bar/',
+                                               True,
+                                       ),
+                                       # /foo/bar/ does not match
+                                       (
+                                               'foo/bar',
+                                               False,
+                                       ),
+                                       # this is excluded
+                                       (
+                                               'foo/bar/baz.foo',
+                                               False,
+                                       ),
+                                       # this is excluded
+                                       (
+                                               'foo/bar/baz.baz',
+                                               False,
+                                       ),
+                                       (
+                                               'foo/bar/baz.bar',
+                                               True,
+                                       ),
+                               )
+                       ),
+                       (
+                               '/foo/bar -/foo/bar/*.foo -*.baz',
+                               (
+                                       (
+                                               'foo/bar/baz',
+                                               True,
+                                       ),
+                                       # /foo/bar matches both foo/bar/ and 
foo/bar
+                                       (
+                                               'foo/bar/',
+                                               True,
+                                       ),
+                                       (
+                                               'foo/bar',
+                                               True,
+                                       ),
+                                       # this is excluded
+                                       (
+                                               'foo/bar/baz.foo',
+                                               False,
+                                       ),
+                                       # this is excluded
+                                       (
+                                               'foo/bar/baz.baz',
+                                               False,
+                                       ),
+                                       (
+                                               'foo/bar/baz.bar',
+                                               True,
+                                       ),
+                               )
+                       ),
+                       (
+                               '/foo*',
+                               (
+                                       (
+                                               'foo',
+                                               True,
+                                       ),
+                                       (
+                                               'foo/',
+                                               True,
+                                       ),
+                                       (
+                                               'foobar',
+                                               True,
+                                       ),
+                                       (
+                                               'foobar/',
+                                               True,
+                                       ),
+                               )
+                       ),
+                       (
+                               '/foo*/',
+                               (
+                                       (
+                                               'foo',
+                                               False,
+                                       ),
+                                       (
+                                               'foo/',
+                                               True,
+                                       ),
+                                       (
+                                               'foobar',
+                                               False,
+                                       ),
+                                       (
+                                               'foobar/',
+                                               True,
+                                       ),
+                               )
+                       ),
+               )
+
+               for install_mask_str, paths in cases:
+                       install_mask = InstallMask(install_mask_str)
+                       for path, expected in paths:
+                               self.assertEqual(install_mask.match(path), 
expected,
+                                       'unexpected match result for "{}" with 
path {}'.\
+                                       format(install_mask_str, path))

diff --git a/pym/portage/util/install_mask.py b/pym/portage/util/install_mask.py
index 1667d883a..32627eb05 100644
--- a/pym/portage/util/install_mask.py
+++ b/pym/portage/util/install_mask.py
@@ -41,10 +41,13 @@ class InstallMask(object):
                                pattern = pattern[1:]
                        # absolute path pattern
                        if pattern.startswith('/'):
+                               # handle trailing slash for explicit directory 
match
+                               if path.endswith('/'):
+                                       pattern = pattern.rstrip('/') + '/'
                                # match either exact path or one of parent dirs
                                # the latter is done via matching pattern/*
                                if (fnmatch.fnmatch(path, pattern[1:])
-                                               or fnmatch.fnmatch(path, 
pattern[1:] + '/*')):
+                                               or fnmatch.fnmatch(path, 
pattern[1:].rstrip('/') + '/*')):
                                        ret = is_inclusive
                        # filename
                        else:
@@ -118,7 +121,7 @@ def install_mask_dir(base_dir, install_mask, onerror=None):
                except IndexError:
                        break
 
-               if install_mask.match(dir_path[base_dir_len:]):
+               if install_mask.match(dir_path[base_dir_len:] + '/'):
                        try:
                                os.rmdir(dir_path)
                        except OSError:

Reply via email to