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 | 2 +- 3 files changed, 65 insertions(+), 56 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..8bc5883 100644 --- a/pym/portage/package/ebuild/config.py +++ b/pym/portage/package/ebuild/config.py @@ -1781,7 +1781,7 @@ class config(object): 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