From 59d6837ebb0ed7933ed211e1b3cf5a6d1e85c229 Mon Sep 17 00:00:00 2001 From: Marius Mauch Date: Sat, 17 Feb 2007 08:53:35 +0000 Subject: Ignore compiled files. Add new feature 'preserve-libs' that injects files into $D that - belong to a package instance that is about to be autocleaned - are not installed by the new package instance - are listed in at least one NEEDED file in vdb - are not just used by other files of the package instance As a side-effect a new file /var/db/pkg/.NEEDED is created that contains a reversed map of the NEEDED files found in a packages dbdir. svn path=/main/trunk/; revision=5975 --- pym/portage/dbapi/vartree.py | 92 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 99cd9e7be..2267ca92e 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -523,6 +523,39 @@ class vardbapi(dbapi): write_atomic(cpath, str(counter)) return counter + def get_library_map(self): + """ Read the global library->consumer map for this vdb instance """ + mapfilename = self.getpath(".NEEDED") + if not os.path.exists(mapfilename): + self.update_library_map() + rValue = {} + for l in open(mapfilename, "r").read().split("\n"): + mysplit = l.split() + if len(mysplit) > 1: + rValue[mysplit[0]] = mysplit[1].split(",") + return rValue + + def update_library_map(self): + """ Update the global library->consumer map for this vdb instance. """ + mapfilename = self.getpath(".NEEDED") + obj_dict = {} + for cpv in self.cpv_all(): + needed_list = self.aux_get(cpv, ["NEEDED"])[0] + for l in needed_list.split("\n"): + mysplit = l.split() + if len(mysplit) < 2: + continue + libs = mysplit[1].split(",") + for lib in libs: + if not obj_dict.has_key(lib): + obj_dict[lib] = [mysplit[0]] + else: + obj_dict[lib].append(mysplit[0]) + mapfile = open(mapfilename, "w") + for lib in obj_dict.keys(): + mapfile.write(lib+" "+",".join(obj_dict[lib])+"\n") + mapfile.close() + class vartree(object): "this tree will scan a var/db/pkg database located at root (passed to init)" def __init__(self, root="/", virtual=None, clone=None, categories=None, @@ -952,6 +985,9 @@ class dblink(object): doebuild(myebuildpath, "cleanrm", self.myroot, self.settings, tree="vartree", mydbapi=self.vartree.dbapi, vartree=self.vartree) + + # regenerate reverse NEEDED map + self.vartree.dbapi.update_library_map() finally: if builddir_lock: @@ -1162,6 +1198,7 @@ class dblink(object): This function does the following: + Preserve old libraries that are still used. Collision Protection. calls doebuild(mydo=pkg_preinst) Merges the package to the livefs @@ -1197,6 +1234,10 @@ class dblink(object): if not os.path.exists(self.dbcatdir): os.makedirs(self.dbcatdir) + myfilelist = listdir(srcroot, recursive=1, filesonly=1, followSymlinks=True) + mysymlinks = filter(os.path.islink, listdir(srcroot, recursive=1, filesonly=0, followSymlinks=False)) + myfilelist.extend(mysymlinks) + otherversions = [] for v in self.vartree.dbapi.cp_list(self.mysplit[0]): otherversions.append(v.split("/")[1]) @@ -1209,17 +1250,59 @@ class dblink(object): catsplit(slot_matches[0])[1], destroot, self.settings, vartree=self.vartree) + # Preserve old libs if they are still in use + if slot_matches and "preserve-libs" in self.settings.features: + # read global reverse NEEDED map + libmap = self.vartree.dbapi.get_library_map() + + # get list of libraries from old package instance + old_contents = self._installed_instance.getcontents().keys() + old_libs = set([os.path.basename(x) for x in old_contents]).intersection(libmap.keys()) + + # get list of libraries from new package instance + mylibs = set([os.path.basename(x) for x in myfilelist]).intersection(libmap.keys()) + + # check which libs are present in the old, but not the new package instance + preserve_libs = old_libs.difference(mylibs) + + # ignore any libs that are only internally used by the package + for lib in preserve_libs.copy(): + old_contents_without_libs = [x for x in old_contents if os.path.basename(x) not in preserve_libs] + if len(set(libmap[lib]).intersection(old_contents_without_libs)) == len(libmap[lib]): + preserve_libs.remove(lib) + + # get the real paths for the libs + preserve_paths = [x for x in old_contents if os.path.basename(x) in preserve_libs] + + # inject files that should be preserved into our image dir + import shutil + for x in preserve_paths: + print "injecting %s into %s" % (x, srcroot) + mydir = os.path.join(srcroot, os.path.dirname(x)) + if not os.path.exists(mydir): + os.makedirs(mydir) + + # resolve symlinks and extend preserve list + # NOTE: we're extending the list in the loop to emulate recursion to + # also get indirect symlinks + if os.path.islink(x): + linktarget = os.readlink(x) + os.symlink(linktarget, os.path.join(srcroot, x.lstrip(os.sep))) + if linktarget[0] != os.sep: + linktarget = os.path.join(os.path.dirname(x), linktarget) + preserve_paths.append(linktarget) + else: + shutil.copy2(x, os.path.join(srcroot, x.lstrip(os.sep))) + + # check for package collisions if "collision-protect" in self.settings.features: collision_ignore = set([normalize_path(myignore) for myignore in \ self.settings.get("COLLISION_IGNORE", "").split()]) - myfilelist = listdir(srcroot, recursive=1, filesonly=1, followSymlinks=False) # the linkcheck only works if we are in srcroot mycwd = os.getcwd() os.chdir(srcroot) - mysymlinks = filter(os.path.islink, listdir(srcroot, recursive=1, filesonly=0, followSymlinks=False)) - myfilelist.extend(mysymlinks) mysymlinked_directories = [s + os.path.sep for s in mysymlinks] del mysymlinks @@ -1442,6 +1525,9 @@ class dblink(object): writedict(cfgfiledict, conf_mem_file) del conf_mem_file + # regenerate reverse NEEDED map + self.vartree.dbapi.update_library_map() + #do postinst script a = doebuild(myebuild, "postinst", destroot, self.settings, use_cache=0, tree=self.treetype, mydbapi=mydbapi, vartree=self.vartree) -- cgit v1.2.3-1-g7c22