Rework the INSTALL_MASK handler to filter installed files while merging
instead of removing them from the installation image.
The INSTALL_MASK handling is now moved to Python side of code, with bash
being only used to evaluate the value of INSTALL_MASK (with respect to
bashrc).
The evaluated value of INSTALL_MASK is used to test for collisions,
and afterwards to skip masked files from being installed. It is also
used in uninstall code to properly remove newly-masked files that were
installed previously.
---
bin/misc-functions.sh | 13 ++--
bin/phase-functions.sh | 3 +-
pym/portage/dbapi/vartree.py | 138 +++++++++++++++++++++++++++++++------------
3 files changed, 108 insertions(+), 46 deletions(-)
diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh
index 7643af7b5..5e11eadb4 100755
--- a/bin/misc-functions.sh
+++ b/bin/misc-functions.sh
@@ -383,12 +383,13 @@ preinst_mask() {
fi
done
- install_mask "${ED}" "${INSTALL_MASK}"
-
- # remove share dir if unnessesary
- if has nodoc $FEATURES || has noman $FEATURES || has noinfo $FEATURES;
then
- rmdir "${ED%/}/usr/share" &> /dev/null
- fi
+ # Store the final value of INSTALL_MASK in build-info
+ local x
+ set -f
+ local IFS=$' \t\n\r'
+ x=$(echo ${INSTALL_MASK})
+ [[ -n $x ]] && echo "$x" > "${PORTAGE_BUILDDIR}"/build-info/INSTALL_MASK
+ set +f
}
preinst_sfperms() {
diff --git a/bin/phase-functions.sh b/bin/phase-functions.sh
index 3aae3ef56..7f7f6fa11 100644
--- a/bin/phase-functions.sh
+++ b/bin/phase-functions.sh
@@ -666,7 +666,8 @@ __dyn_install() {
ASFLAGS CBUILD CC CFLAGS CHOST CTARGET CXX \
CXXFLAGS EXTRA_ECONF EXTRA_EINSTALL EXTRA_MAKE \
LDFLAGS LIBCFLAGS LIBCXXFLAGS QA_CONFIGURE_OPTIONS \
- QA_DESKTOP_FILE QA_PREBUILT PROVIDES_EXCLUDE REQUIRES_EXCLUDE ;
do
+ QA_DESKTOP_FILE QA_PREBUILT PROVIDES_EXCLUDE REQUIRES_EXCLUDE \
+ PKG_INSTALL_MASK ; do
x=$(echo -n ${!f})
[[ -n $x ]] && echo "$x" > $f
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index bed76d80f..12137a0a4 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -1876,6 +1876,7 @@ class dblink(object):
for pos, e in errors:
writemsg(_("!!! line %d: %s\n") % (pos, e),
noiselevel=-1)
self.contentscache = pkgfiles
+
return pkgfiles
def _prune_plib_registry(self, unmerge=False,
@@ -1953,7 +1954,7 @@ class dblink(object):
@_slot_locked
def unmerge(self, pkgfiles=None, trimworld=None, cleanup=True,
ldpath_mtimes=None, others_in_slot=None, needed=None,
- preserve_paths=None):
+ preserve_paths=None, install_mask=[]):
"""
Calls prerm
Unmerges a given package (CPV)
@@ -1978,6 +1979,10 @@ class dblink(object):
LinkageMap, since they are not registered in the
PreservedLibsRegistry yet.
@type preserve_paths: set
+ @param install_mask: List of INSTALL_MASK values for the install
+ enforcing cleanup. This is needed to let unmerge()
clean old
+ files that now are filtered via INSTALL_MASK.
+ @type install_mask: list
@rtype: Integer
@return:
1. os.EX_OK if everything went well.
@@ -2121,7 +2126,7 @@ class dblink(object):
self.vartree.dbapi._fs_lock()
try:
- self._unmerge_pkgfiles(pkgfiles, others_in_slot)
+ self._unmerge_pkgfiles(pkgfiles,
others_in_slot, install_mask)
finally:
self.vartree.dbapi._fs_unlock()
self._clear_contents_cache()
@@ -2267,7 +2272,7 @@ class dblink(object):
self._display_merge("%s %s %s %s\n" % \
(zing, desc.ljust(8), file_type, file_name))
- def _unmerge_pkgfiles(self, pkgfiles, others_in_slot):
+ def _unmerge_pkgfiles(self, pkgfiles, others_in_slot, install_mask):
"""
Unmerges the contents of a package from the liveFS
@@ -2277,6 +2282,8 @@ class dblink(object):
@type pkgfiles: Dictionary { filename: [ 'type', '?', 'md5sum'
] }
@param others_in_slot: all dblink instances in this slot,
excluding self
@type others_in_slot: list
+ @param install_mask: List of values in INSTALL_MASK.
+ @type install_maks: list
@rtype: None
"""
@@ -2491,7 +2498,10 @@ class dblink(object):
(statobj.st_dev, statobj.st_ino),
[]).append(relative_path)
- if is_owned:
+ # if the file was replaced by new
version, keep it
+ # unless it is also INSTALL_MASK-ed in
the new version
+ # (then it was not really installed and
we want to clean it)
+ if is_owned and not
self._is_install_masked(relative_path[1:], install_mask):
show_unmerge("---",
unmerge_desc["replaced"], file_type, obj)
continue
elif relative_path in cfgfiledict:
@@ -3689,6 +3699,24 @@ class dblink(object):
def _emerge_log(self, msg):
emergelog(False, msg)
+ def _is_install_masked(self, relative_path, install_mask):
+ ret = False
+ for pattern in 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):
"""
@@ -3841,7 +3869,7 @@ class dblink(object):
max_dblnk = dblnk
self._installed_instance = max_dblnk
- # Apply INSTALL_MASK before collision-protect, since it may
+ # Update 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.
@@ -3851,6 +3879,17 @@ class dblink(object):
phase.start()
phase.wait()
+ try:
+ print('!!!\nRead INSTALL_MASK from %s\n!!!' %
os.path.join(inforoot, "INSTALL_MASK"))
+ with io.open(_unicode_encode(
+ os.path.join(inforoot,
"INSTALL_MASK"),
+ encoding=_encodings['fs'],
errors='strict'),
+ mode='r',
encoding=_encodings['repo.content'],
+ errors='replace') as f:
+ install_mask = f.read().split()
+ except EnvironmentError as e:
+ install_mask = self.settings.get('INSTALL_MASK',
'').split()
+
# 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).
@@ -3922,6 +3961,10 @@ class dblink(object):
relative_path = fpath[srcroot_len:]
+ # filter on INSTALL_MASK
+ if
self._is_install_masked(relative_path, install_mask):
+ continue
+
if line_ending_re.search(relative_path)
is not None:
paths_with_newlines.append(relative_path)
@@ -4270,7 +4313,8 @@ class dblink(object):
else:
cfgfiledict["IGNORE"]=0
- rval = self._merge_contents(srcroot, destroot,
cfgfiledict)
+ rval = self._merge_contents(srcroot, destroot,
cfgfiledict,
+ install_mask)
if rval != os.EX_OK:
return rval
finally:
@@ -4351,7 +4395,7 @@ class dblink(object):
dblnk.settings.backup_changes("REPLACED_BY_VERSION")
unmerge_rval = dblnk.unmerge(ldpath_mtimes=prev_mtimes,
others_in_slot=others_in_slot, needed=needed,
- preserve_paths=preserve_paths)
+ preserve_paths=preserve_paths,
install_mask=install_mask)
dblnk.settings.pop("REPLACED_BY_VERSION", None)
if unmerge_rval == os.EX_OK:
@@ -4523,7 +4567,7 @@ class dblink(object):
return backup_p
- def _merge_contents(self, srcroot, destroot, cfgfiledict):
+ def _merge_contents(self, srcroot, destroot, cfgfiledict, install_mask):
cfgfiledict_orig = cfgfiledict.copy()
@@ -4550,7 +4594,8 @@ class dblink(object):
# we do a first merge; this will recurse through all files in
our srcroot but also build up a
# "second hand" of symlinks to merge later
if self.mergeme(srcroot, destroot, outfile, secondhand,
- self.settings["EPREFIX"].lstrip(os.sep), cfgfiledict,
mymtime):
+ self.settings["EPREFIX"].lstrip(os.sep),
cfgfiledict,
+ mymtime, install_mask):
return 1
# now, it's time for dealing our second hand; we'll loop until
we can't merge anymore. The rest are
@@ -4562,7 +4607,7 @@ class dblink(object):
thirdhand = []
if self.mergeme(srcroot, destroot, outfile, thirdhand,
- secondhand, cfgfiledict, mymtime):
+ secondhand, cfgfiledict, mymtime,
install_mask):
return 1
#swap hands
@@ -4576,7 +4621,7 @@ class dblink(object):
if len(secondhand):
# force merge of remaining symlinks (broken or
circular; oh well)
if self.mergeme(srcroot, destroot, outfile, None,
- secondhand, cfgfiledict, mymtime):
+ secondhand, cfgfiledict, mymtime,
install_mask):
return 1
#restore umask
@@ -4597,7 +4642,8 @@ class dblink(object):
return os.EX_OK
- def mergeme(self, srcroot, destroot, outfile, secondhand, stufftomerge,
cfgfiledict, thismtime):
+ def mergeme(self, srcroot, destroot, outfile, secondhand, stufftomerge,
+ cfgfiledict, thismtime, install_mask):
"""
This function handles actual merging of the package contents to
the livefs.
@@ -4651,6 +4697,7 @@ class dblink(object):
while mergelist:
relative_path = mergelist.pop()
+ instmasked = self._is_install_masked(relative_path,
install_mask)
mysrc = join(srcroot, relative_path)
mydest = join(destroot, relative_path)
# myrealdest is mydest without the $ROOT prefix (makes
a difference if ROOT!="/")
@@ -4737,7 +4784,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)
@@ -4765,7 +4812,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 = []
@@ -4785,26 +4832,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:
@@ -4819,7 +4872,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:
@@ -4906,10 +4961,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
@@ -4918,7 +4974,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)
@@ -4932,9 +4988,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)
@@ -4967,7 +5025,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,
--
2.16.2