Introduce a new logic for INSTALL_MASK handling in merging code,
replacing the old code that removed matching files and directories
from imagedir in bash. The new code actually ignores matching files
on-the-fly while testing for file collisions and merging files.
The files are still written to CONTENTS, and output using "###" zing
to indicate being masked, yet are not actually merged to the filesystem.
---
 bin/misc-functions.sh                |  17 ------
 pym/portage/dbapi/vartree.py         | 102 ++++++++++++++++++++++-------------
 pym/portage/package/ebuild/config.py |   4 +-
 3 files changed, 66 insertions(+), 57 deletions(-)

diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh
index b42e1d6..4086981 100755
--- a/bin/misc-functions.sh
+++ b/bin/misc-functions.sh
@@ -300,23 +300,6 @@ install_mask() {
        set -${shopts}
 }
 
-preinst_mask() {
-       if [ -z "${D}" ]; then
-                eerror "${FUNCNAME}: D is unset"
-                return 1
-       fi
-
-       if ! ___eapi_has_prefix_variables; then
-               local ED=${D}
-       fi
-
-       # Make sure $PWD is not ${D} so that we don't leave gmon.out files
-       # in there in case any tools were built with -pg in CFLAGS.
-       cd "${T}"
-
-       install_mask "${ED}" "${INSTALL_MASK}"
-}
-
 preinst_sfperms() {
        if [ -z "${D}" ]; then
                 eerror "${FUNCNAME}: D is unset"
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index 6209a86..8e5ac43 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -2490,7 +2490,7 @@ class dblink(object):
                                                                
(statobj.st_dev, statobj.st_ino),
                                                                
[]).append(relative_path)
 
-                                       if is_owned:
+                                       if is_owned and not 
self._is_install_masked(relative_path[1:]):
                                                show_unmerge("---", 
unmerge_desc["replaced"], file_type, obj)
                                                continue
                                        elif relative_path in cfgfiledict:
@@ -3687,6 +3687,24 @@ class dblink(object):
        def _emerge_log(self, msg):
                emergelog(False, msg)
 
+       def _is_install_masked(self, relative_path):
+               ret = False
+               for pattern in self.settings.install_mask:
+                       # absolute path pattern
+                       if pattern.startswith('/'):
+                               # match either exact path or one of parent dirs
+                               # the latter is done via matching pattern/*
+                               if (fnmatch.fnmatch(relative_path, pattern[1:])
+                                               or 
fnmatch.fnmatch(relative_path, pattern[1:] + '/*')):
+                                       ret = True
+                                       break
+                       # filename
+                       else:
+                               if 
fnmatch.fnmatch(os.path.basename(relative_path), pattern):
+                                       ret = True
+                                       break
+               return ret
+
        def treewalk(self, srcroot, destroot, inforoot, myebuild, cleanup=0,
                mydbapi=None, prev_mtimes=None, counter=None):
                """
@@ -3846,16 +3864,6 @@ class dblink(object):
                                        max_dblnk = dblnk
                        self._installed_instance = max_dblnk
 
-               # Apply INSTALL_MASK before collision-protect, since it may
-               # be useful to avoid collisions in some scenarios.
-               # We cannot detect if this is needed or not here as 
INSTALL_MASK can be
-               # modified by bashrc files.
-               phase = MiscFunctionsProcess(background=False,
-                       commands=["preinst_mask"], phase="preinst",
-                       scheduler=self._scheduler, settings=self.settings)
-               phase.start()
-               phase.wait()
-
                # We check for unicode encoding issues after src_install. 
However,
                # the check must be repeated here for binary packages (it's
                # inexpensive since we call os.walk() here anyway).
@@ -3927,6 +3935,10 @@ class dblink(object):
 
                                        relative_path = fpath[srcroot_len:]
 
+                                       # filter on INSTALL_MASK
+                                       if 
self._is_install_masked(relative_path):
+                                               continue
+
                                        if line_ending_re.search(relative_path) 
is not None:
                                                
paths_with_newlines.append(relative_path)
 
@@ -4642,6 +4654,7 @@ class dblink(object):
                while mergelist:
 
                        relative_path = mergelist.pop()
+                       instmasked = self._is_install_masked(relative_path)
                        mysrc = join(srcroot, relative_path)
                        mydest = join(destroot, relative_path)
                        # myrealdest is mydest without the $ROOT prefix (makes 
a difference if ROOT!="/")
@@ -4730,7 +4743,7 @@ class dblink(object):
                                destmd5 = None
 
                        moveme = True
-                       if protected:
+                       if protected and not instmasked:
                                mydest, protected, moveme = 
self._protect(cfgfiledict,
                                        protect_if_modified, mymd5, myto, 
mydest,
                                        myrealdest, mydmode, destmd5, 
mydest_link)
@@ -4758,7 +4771,7 @@ class dblink(object):
                                # we can simply test for existence of this file 
to see if the target has been merged yet
                                myrealto = 
normalize_path(os.path.join(destroot, myabsto))
                                if mydmode is not None and 
stat.S_ISDIR(mydmode):
-                                       if not protected:
+                                       if not protected and not instmasked:
                                                # we can't merge a symlink over 
a directory
                                                newdest = 
self._new_backup_path(mydest)
                                                msg = []
@@ -4778,26 +4791,32 @@ class dblink(object):
                                        # it later.
                                        secondhand.append(mysrc[len(srcroot):])
                                        continue
-                               # unlinking no longer necessary; "movefile" 
will overwrite symlinks atomically and correctly
-                               if moveme:
-                                       zing = ">>>"
-                                       mymtime = movefile(mysrc, mydest, 
newmtime=thismtime,
-                                               sstat=mystat, 
mysettings=self.settings,
-                                               encoding=_encodings['merge'])
 
-                               try:
-                                       self._merged_path(mydest, 
os.lstat(mydest))
-                               except OSError:
-                                       pass
+                               if instmasked:
+                                       zing = "###"
+                                       # pass mymtime through from initial stat
+                               else:
+                                       # unlinking no longer necessary; 
"movefile" will overwrite symlinks atomically and correctly
+                                       if moveme:
+                                               zing = ">>>"
+                                               mymtime = movefile(mysrc, 
mydest, newmtime=thismtime,
+                                                       sstat=mystat, 
mysettings=self.settings,
+                                                       
encoding=_encodings['merge'])
+
+                                       try:
+                                               self._merged_path(mydest, 
os.lstat(mydest))
+                                       except OSError:
+                                               pass
 
                                if mymtime != None:
-                                       # Use lexists, since if the target 
happens to be a broken
-                                       # symlink then that should trigger an 
independent warning.
-                                       if not (os.path.lexists(myrealto) or
-                                               os.path.lexists(join(srcroot, 
myabsto))):
-                                               self._eqawarn('preinst',
-                                                       [_("QA Notice: Symbolic 
link /%s points to /%s which does not exist.")
-                                                       % (relative_path, 
myabsto)])
+                                       if not instmasked:
+                                               # Use lexists, since if the 
target happens to be a broken
+                                               # symlink then that should 
trigger an independent warning.
+                                               if not 
(os.path.lexists(myrealto) or
+                                                       
os.path.lexists(join(srcroot, myabsto))):
+                                                       self._eqawarn('preinst',
+                                                               [_("QA Notice: 
Symbolic link /%s points to /%s which does not exist.")
+                                                               % 
(relative_path, myabsto)])
 
                                        showMessage("%s %s -> %s\n" % (zing, 
mydest, myto))
                                        if sys.hexversion >= 0x3030000:
@@ -4812,7 +4831,9 @@ class dblink(object):
                                        return 1
                        elif stat.S_ISDIR(mymode):
                                # we are merging a directory
-                               if mydmode != None:
+                               if instmasked:
+                                       showMessage("### %s/\n" % mydest)
+                               elif mydmode != None:
                                        # destination exists
 
                                        if bsd_chflags:
@@ -4899,10 +4920,11 @@ class dblink(object):
                                        os.chown(mydest, mystat[4], mystat[5])
                                        showMessage(">>> %s/\n" % mydest)
 
-                               try:
-                                       self._merged_path(mydest, 
os.lstat(mydest))
-                               except OSError:
-                                       pass
+                               if not instmasked:
+                                       try:
+                                               self._merged_path(mydest, 
os.lstat(mydest))
+                                       except OSError:
+                                               pass
 
                                outfile.write("dir "+myrealdest+"\n")
                                # recurse and merge this directory
@@ -4911,7 +4933,7 @@ class dblink(object):
 
                        elif stat.S_ISREG(mymode):
                                # we are merging a regular file
-                               if not protected and \
+                               if not protected and not instmasked and \
                                        mydmode is not None and 
stat.S_ISDIR(mydmode):
                                                # install of destination is 
blocked by an existing directory with the same name
                                                newdest = 
self._new_backup_path(mydest)
@@ -4925,9 +4947,11 @@ class dblink(object):
                                                self._eerror("preinst", msg)
                                                mydest = newdest
 
+                               if instmasked:
+                                       zing = "###"
                                # whether config protection or not, we merge 
the new file the
                                # same way.  Unless moveme=0 (blocking 
directory)
-                               if moveme:
+                               elif moveme:
                                        # Create hardlinks only for source 
files that already exist
                                        # as hardlinks (having identical st_dev 
and st_ino).
                                        hardlink_key = (mystat.st_dev, 
mystat.st_ino)
@@ -4960,7 +4984,9 @@ class dblink(object):
                        else:
                                # we are merging a fifo or device node
                                zing = "!!!"
-                               if mydmode is None:
+                               if instmasked:
+                                       zing = "###"
+                               elif mydmode is None:
                                        # destination doesn't exist
                                        if movefile(mysrc, mydest, 
newmtime=thismtime,
                                                sstat=mystat, 
mysettings=self.settings,
diff --git a/pym/portage/package/ebuild/config.py 
b/pym/portage/package/ebuild/config.py
index fcc7ce5..9d13703 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -1774,14 +1774,14 @@ class config(object):
                _eapi_cache.clear()
 
                # Prepare the final value of INSTALL_MASK
-               install_mask = self["INSTALL_MASK"].split()
+               install_mask = self.get("INSTALL_MASK", "").split()
                if 'nodoc' in self.features:
                        install_mask.append("/usr/share/doc")
                if 'noinfo' in self.features:
                        install_mask.append("/usr/share/info")
                if 'noman' in self.features:
                        install_mask.append("/usr/share/man")
-               self["INSTALL_MASK"] = ' '.join(install_mask)
+               self.install_mask = install_mask
 
        def _grab_pkg_env(self, penv, container, protected_keys=None):
                if protected_keys is None:
-- 
2.8.3


Reply via email to