summaryrefslogtreecommitdiffstats
path: root/pym/portage
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2008-05-08 07:48:59 +0000
committerZac Medico <zmedico@gentoo.org>2008-05-08 07:48:59 +0000
commit459afecb958f9d6a6d7fb44c08c533e991cbfa63 (patch)
tree9bba8b0126230441b92ce632ffe0bf40de1d2cbc /pym/portage
parent30612136631ec3a0ddf7d4ac24e80ea757a802b5 (diff)
downloadportage-459afecb958f9d6a6d7fb44c08c533e991cbfa63.tar.gz
portage-459afecb958f9d6a6d7fb44c08c533e991cbfa63.tar.bz2
portage-459afecb958f9d6a6d7fb44c08c533e991cbfa63.zip
Instead of doing automatic uninstalls in advance, install conflicting
packages first and then do the uninstall afterwards. This requires special handling for file collisions occur, but it's preferred because it ensures that package files remain installed in a usable state whenever possible. When file collisions occur between conflicting packages, the contents entries for those files are removed from the packages that are scheduled for uninstallation. This prevents uninstallation operations from removing overlapping files that have been claimed by conflicting packages. svn path=/main/trunk/; revision=10225
Diffstat (limited to 'pym/portage')
-rw-r--r--pym/portage/__init__.py9
-rw-r--r--pym/portage/dbapi/vartree.py54
2 files changed, 56 insertions, 7 deletions
diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py
index c51497eef..139fa57e0 100644
--- a/pym/portage/__init__.py
+++ b/pym/portage/__init__.py
@@ -5313,13 +5313,13 @@ def movefile(src,dest,newmtime=None,sstat=None,mysettings=None):
return newmtime
def merge(mycat, mypkg, pkgloc, infloc, myroot, mysettings, myebuild=None,
- mytree=None, mydbapi=None, vartree=None, prev_mtimes=None):
+ mytree=None, mydbapi=None, vartree=None, prev_mtimes=None, blockers=None):
if not os.access(myroot, os.W_OK):
writemsg("Permission denied: access('%s', W_OK)\n" % myroot,
noiselevel=-1)
return errno.EACCES
mylink = dblink(mycat, mypkg, myroot, mysettings, treetype=mytree,
- vartree=vartree)
+ vartree=vartree, blockers=blockers)
return mylink.merge(pkgloc, infloc, myroot, myebuild,
mydbapi=mydbapi, prev_mtimes=prev_mtimes)
@@ -6184,7 +6184,8 @@ class FetchlistDict(UserDict.DictMixin):
"""Returns keys for all packages within pkgdir"""
return self.portdb.cp_list(self.cp, mytree=self.mytree)
-def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes=None):
+def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None,
+ vartree=None, prev_mtimes=None, blockers=None):
"""will merge a .tbz2 file, returning a list of runtime dependencies
that must be satisfied, or None if there was a merge error. This
code assumes the package exists."""
@@ -6277,7 +6278,7 @@ def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes
#tbz2_lock = None
mylink = dblink(mycat, mypkg, myroot, mysettings, vartree=vartree,
- treetype="bintree")
+ treetype="bintree", blockers=blockers)
retval = mylink.merge(pkgloc, infloc, myroot, myebuild, cleanup=0,
mydbapi=mydbapi, prev_mtimes=prev_mtimes)
did_merge_phase = True
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index 145016edc..f433789cd 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -932,7 +932,7 @@ class dblink(object):
}
def __init__(self, cat, pkg, myroot, mysettings, treetype=None,
- vartree=None):
+ vartree=None, blockers=None):
"""
Creates a DBlink object for a given CPV.
The given CPV may not be present in the database already.
@@ -961,6 +961,7 @@ class dblink(object):
from portage import db
vartree = db[myroot]["vartree"]
self.vartree = vartree
+ self._blockers = blockers
self.dbroot = normalize_path(os.path.join(myroot, VDB_PATH))
self.dbcatdir = self.dbroot+"/"+cat
@@ -1037,6 +1038,11 @@ class dblink(object):
if os.path.exists(self.dbdir+"/CONTENTS"):
os.unlink(self.dbdir+"/CONTENTS")
+ def _clear_contents_cache(self):
+ self.contentscache = None
+ self._contents_inodes = None
+ self._contents_basenames = None
+
def getcontents(self):
"""
Get the installed files of a given package (aka what that package installed)
@@ -1923,6 +1929,7 @@ class dblink(object):
"""
srcroot = normalize_path(srcroot).rstrip(os.path.sep) + os.path.sep
+ destroot = normalize_path(destroot).rstrip(os.path.sep) + os.path.sep
if not os.path.isdir(srcroot):
writemsg("!!! Directory Not Found: D='%s'\n" % srcroot,
@@ -2063,8 +2070,11 @@ class dblink(object):
self._preserve_libs(srcroot, destroot, myfilelist+mylinklist, counter, inforoot)
# check for package collisions
- collisions = self._collision_protect(srcroot, destroot, others_in_slot,
- myfilelist+mylinklist)
+ blockers = self._blockers
+ if blockers is None:
+ blockers = []
+ collisions = self._collision_protect(srcroot, destroot,
+ others_in_slot + blockers, myfilelist + mylinklist)
# Make sure the ebuild environment is initialized and that ${T}/elog
# exists for logging of collision-protect eerror messages.
@@ -2284,6 +2294,44 @@ class dblink(object):
self.dbdir = self.dbpkgdir
self.delete()
_movefile(self.dbtmpdir, self.dbpkgdir, mysettings=self.settings)
+
+ # Check for file collisions with blocking packages
+ # and remove any colliding files from their CONTENTS
+ # since they now belong to this package.
+ self._clear_contents_cache()
+ contents = self.getcontents()
+ destroot_len = len(destroot) - 1
+ for blocker in blockers:
+ blocker_contents = blocker.getcontents()
+ collisions = []
+ for filename in blocker_contents:
+ relative_filename = filename[destroot_len:]
+ if self.isowner(relative_filename, destroot):
+ collisions.append(filename)
+ if not collisions:
+ continue
+ for filename in collisions:
+ del blocker_contents[filename]
+ f = atomic_ofstream(os.path.join(blocker.dbdir, "CONTENTS"))
+ try:
+ for filename in sorted(blocker_contents):
+ entry_data = blocker_contents[filename]
+ entry_type = entry_data[0]
+ relative_filename = filename[destroot_len:]
+ if entry_type == "obj":
+ entry_type, mtime, md5sum = entry_data
+ line = "%s %s %s %s\n" % \
+ (entry_type, relative_filename, md5sum, mtime)
+ elif entry_type == "sym":
+ entry_type, mtime, link = entry_data
+ line = "%s %s -> %s %s\n" % \
+ (entry_type, relative_filename, link, mtime)
+ else: # dir, dev, fif
+ line = "%s %s\n" % (entry_type, relative_filename)
+ f.write(line)
+ finally:
+ f.close()
+
# Due to mtime granularity, mtime checks do not always properly
# invalidate vardbapi caches.
self.vartree.dbapi.mtdircache.pop(self.cat, None)