summaryrefslogtreecommitdiffstats
path: root/pym
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2007-06-08 19:54:15 +0000
committerZac Medico <zmedico@gentoo.org>2007-06-08 19:54:15 +0000
commit9afcc2a0547ed77733c714050336d98fbda0821b (patch)
tree3278580efd60a447c52e3f6aa8d154fa89dfe7f5 /pym
parent87510cdd5f5e9b741b6b1efe29767bb858dd32e9 (diff)
downloadportage-9afcc2a0547ed77733c714050336d98fbda0821b.tar.gz
portage-9afcc2a0547ed77733c714050336d98fbda0821b.tar.bz2
portage-9afcc2a0547ed77733c714050336d98fbda0821b.zip
For bug #181021, preserve timestamps from during merge. For replacement operations, the unmerge phase checks the contents of the newer instance in order to prevent identical files in the newer instance from being unmerged. (trunk r6739, r6740, and r6745)
svn path=/main/branches/2.1.2/; revision=6760
Diffstat (limited to 'pym')
-rw-r--r--pym/portage.py145
1 files changed, 51 insertions, 94 deletions
diff --git a/pym/portage.py b/pym/portage.py
index d52a6da57..0719aa23d 100644
--- a/pym/portage.py
+++ b/pym/portage.py
@@ -3891,6 +3891,8 @@ def movefile(src,dest,newmtime=None,sstat=None,mysettings=None):
else:
os.symlink(target,dest)
lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ # utime() only works on the target of a symlink, so it's not
+ # possible to perserve mtime on symlinks.
return os.lstat(dest)[stat.ST_MTIME]
except SystemExit, e:
raise
@@ -6827,9 +6829,9 @@ class dblink:
mysettings.get("CONFIG_PROTECT","").split(),
mysettings.get("CONFIG_PROTECT_MASK","").split())
self.updateprotect = protect_obj.updateprotect
- self._config_protect = protect_obj
+ self.isprotected = protect_obj.isprotected
self._installed_instance = None
- self.contentscache=[]
+ self.contentscache = None
self._contents_inodes = None
def lockdb(self):
@@ -6894,7 +6896,7 @@ class dblink:
"""
if not os.path.exists(self.dbdir+"/CONTENTS"):
return None
- if self.contentscache != []:
+ if self.contentscache is not None:
return self.contentscache
pkgfiles={}
myc=open(self.dbdir+"/CONTENTS","r")
@@ -6953,7 +6955,7 @@ class dblink:
return pkgfiles
def unmerge(self, pkgfiles=None, trimworld=1, cleanup=1,
- ldpath_mtimes=None):
+ ldpath_mtimes=None, new_contents=None):
"""
Calls prerm
Unmerges a given package (CPV)
@@ -6969,6 +6971,8 @@ class dblink:
@type cleanup: Boolean
@param ldpath_mtimes: mtimes to pass to env_update (see env_update)
@type ldpath_mtimes: Dictionary
+ @param new_contents: contents from a new instance that will replace this one
+ @type new_contents: Dictionary
@rtype: Integer
@returns:
1. os.EX_OK if everything went well.
@@ -7032,7 +7036,7 @@ class dblink:
writemsg("!!! FAILED prerm: %s\n" % retval, noiselevel=-1)
return retval
- self._unmerge_pkgfiles(pkgfiles)
+ self._unmerge_pkgfiles(pkgfiles, new_contents=new_contents)
if myebuildpath:
retval = doebuild(myebuildpath, "postrm", self.myroot,
@@ -7071,7 +7075,7 @@ class dblink:
contents=contents)
return os.EX_OK
- def _unmerge_pkgfiles(self, pkgfiles):
+ def _unmerge_pkgfiles(self, pkgfiles, new_contents=None):
"""
Unmerges the contents of a package from the liveFS
@@ -7079,6 +7083,8 @@ class dblink:
@param pkgfiles: typically self.getcontents()
@type pkgfiles: Dictionary { filename: [ 'type', '?', 'md5sum' ] }
+ @param new_contents: contents from a new instance that will replace this one
+ @type new_contents: Dictionary
@rtype: None
"""
global dircache
@@ -7088,6 +7094,28 @@ class dblink:
writemsg_stdout("No package files given... Grabbing a set.\n")
pkgfiles=self.getcontents()
+ if not new_contents:
+ counter = self.vartree.dbapi.cpv_counter(self.mycpv)
+ slot = self.vartree.dbapi.aux_get(self.mycpv, ["SLOT"])[0]
+ slot_matches = self.vartree.dbapi.match(
+ "%s:%s" % (dep_getkey(self.mycpv), slot))
+ new_cpv = None
+ if slot_matches:
+ max_counter = -1
+ for cur_cpv in slot_matches:
+ cur_counter = self.vartree.dbapi.cpv_counter(cur_cpv)
+ if cur_counter == counter and \
+ cur_cpv == self.mycpv:
+ continue
+ if cur_counter > max_counter:
+ max_counter = cur_counter
+ new_cpv = cur_cpv
+ if new_cpv:
+ # The current instance has been replaced by a newer instance.
+ new_cat, new_pkg = catsplit(new_cpv)
+ new_contents = dblink(new_cat, new_pkg, self.vartree.root,
+ self.settings, vartree=self.vartree).getcontents()
+
if pkgfiles:
mykeys=pkgfiles.keys()
mykeys.sort()
@@ -7098,8 +7126,12 @@ class dblink:
modprotect="/lib/modules/"
for objkey in mykeys:
obj = normalize_path(objkey)
- if obj[:2]=="//":
- obj=obj[1:]
+ if new_contents and obj in new_contents:
+ # A new instance of this package claims the file, so don't
+ # unmerge it.
+ writemsg_stdout("--- !owned %s %s\n" % \
+ (pkgfiles[objkey][0], obj))
+ continue
statobj = None
try:
statobj = os.stat(obj)
@@ -7233,31 +7265,6 @@ class dblink:
return False
- def isprotected(self, filename):
- """In cases where an installed package in the same slot owns a
- protected file that will be merged, bump the mtime on the installed
- file in order to ensure that it isn't unmerged."""
- if not self._config_protect.isprotected(filename):
- return False
- if self._installed_instance is None:
- return True
- mydata = self._installed_instance.getcontents().get(filename, None)
- if mydata is None:
- return True
-
- # Bump the mtime in order to ensure that the old config file doesn't
- # get unmerged. The user will have an opportunity to merge the new
- # config with the old one.
- try:
- os.utime(filename, None)
- except OSError, e:
- if e.errno != errno.ENOENT:
- raise
- del e
- # The file has disappeared, so it's not protected.
- return False
- return True
-
def treewalk(self, srcroot, destroot, inforoot, myebuild, cleanup=0,
mydbapi=None, prev_mtimes=None):
"""
@@ -7442,9 +7449,6 @@ class dblink:
raise
del e
- # get old contents info for later unmerging
- oldcontents = self.getcontents()
-
self.dbdir = self.dbtmpdir
self.delete()
if not os.path.exists(self.dbtmpdir):
@@ -7490,12 +7494,11 @@ class dblink:
else:
cfgfiledict["IGNORE"]=0
- # Timestamp for files being merged. Use time() - 1 in order to prevent
- # a collision with timestamps that are bumped by the utime() call
- # inside isprotected(). This ensures that the new and old config have
- # different timestamps (for the benefit of programs like rsync that
- # that need distiguishable timestamps to detect file changes).
- mymtime = long(time.time() - 1)
+ # Don't bump mtimes on merge since some application require
+ # preservation of timestamps. This means that the unmerge phase must
+ # check to see if file belongs to an installed instance in the same
+ # slot.
+ mymtime = None
# set umask to 0 for merging; back up umask, save old one in prevmask (since this is a global change)
prevmask = os.umask(0)
@@ -7534,12 +7537,14 @@ class dblink:
#if we opened it, close it
outfile.flush()
outfile.close()
+ self.contentscache = None
+ new_contents = self.getcontents()
if os.path.exists(self.dbpkgdir):
writemsg_stdout(">>> Safely unmerging already-installed instance...\n")
- self.dbdir = self.dbpkgdir
- self.unmerge(oldcontents, trimworld=0, ldpath_mtimes=prev_mtimes)
- self.dbdir = self.dbtmpdir
+ dblink(self.cat, self.pkg, destroot, self.settings,
+ vartree=self.vartree).unmerge(trimworld=0,
+ ldpath_mtimes=prev_mtimes, new_contents=new_contents)
writemsg_stdout(">>> Original instance of package unmerged safely.\n")
# We hold both directory locks.
@@ -7805,9 +7810,7 @@ class dblink:
destmd5=portage_checksum.perform_md5(mydest,calc_prelink=1)
if mymd5==destmd5:
#file already in place; simply update mtimes of destination
- os.utime(mydest,(thismtime,thismtime))
- zing="---"
- moveme=0
+ moveme = 1
else:
if mymd5 == cfgfiledict.get(myrealdest, [None])[0]:
""" An identical update has previously been
@@ -7836,52 +7839,6 @@ class dblink:
if mymtime is None:
sys.exit(1)
zing=">>>"
- else:
- mymtime = long(time.time())
- # We need to touch the destination so that on --update the
- # old package won't yank the file with it. (non-cfgprot related)
- os.utime(mydest, (mymtime, mymtime))
- zing="---"
- if self.settings["USERLAND"] == "Darwin" and myrealdest[-2:] == ".a":
-
- # XXX kludge, can be killed when portage stops relying on
- # md5+mtime, and uses refcounts
- # alright, we've fooled w/ mtime on the file; this pisses off static archives
- # basically internal mtime != file's mtime, so the linker (falsely) thinks
- # the archive is stale, and needs to have it's toc rebuilt.
-
- myf = open(mydest, "r+")
-
- # ar mtime field is digits padded with spaces, 12 bytes.
- lms=str(thismtime+5).ljust(12)
- myf.seek(0)
- magic=myf.read(8)
- if magic != "!<arch>\n":
- # not an archive (dolib.a from portage.py makes it here fex)
- myf.close()
- else:
- st = os.stat(mydest)
- while myf.tell() < st.st_size - 12:
- # skip object name
- myf.seek(16,1)
-
- # update mtime
- myf.write(lms)
-
- # skip uid/gid/mperm
- myf.seek(20,1)
-
- # read the archive member's size
- x=long(myf.read(10))
-
- # skip the trailing newlines, and add the potential
- # extra padding byte if it's not an even size
- myf.seek(x + 2 + (x % 2),1)
-
- # and now we're at the end. yay.
- myf.close()
- mymd5 = portage_checksum.perform_md5(mydest, calc_prelink=1)
- os.utime(mydest,(thismtime,thismtime))
if mymtime!=None:
zing=">>>"