blob: 0d0b57d21cdedb8caf867c368e38161b18f3dbc2 [file] [log] [blame]
# Copyright 1998-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
import errno
import logging
try:
import cPickle as pickle
except ImportError:
import pickle
from portage import os
from portage import _encodings
from portage import _os_merge
from portage import _unicode_encode
from portage.exception import PermissionDenied
from portage.localization import _
from portage.util import atomic_ofstream
from portage.util import writemsg_level
from portage.versions import cpv_getkey
class PreservedLibsRegistry(object):
""" This class handles the tracking of preserved library objects """
def __init__(self, root, filename, autocommit=True):
"""
@param root: root used to check existence of paths in pruneNonExisting
@type root: String
@param filename: absolute path for saving the preserved libs records
@type filename: String
@param autocommit: determines if the file is written after every update
@type autocommit: Boolean
"""
self._root = root
self._filename = filename
self._autocommit = autocommit
self.load()
self.pruneNonExisting()
def load(self):
""" Reload the registry data from file """
self._data = None
try:
self._data = pickle.load(
open(_unicode_encode(self._filename,
encoding=_encodings['fs'], errors='strict'), 'rb'))
except (ValueError, pickle.UnpicklingError) as e:
writemsg_level(_("!!! Error loading '%s': %s\n") % \
(self._filename, e), level=logging.ERROR, noiselevel=-1)
except (EOFError, IOError) as e:
if isinstance(e, EOFError) or e.errno == errno.ENOENT:
pass
elif e.errno == PermissionDenied.errno:
raise PermissionDenied(self._filename)
else:
raise
if self._data is None:
self._data = {}
self._data_orig = self._data.copy()
def store(self):
""" Store the registry data to file. No need to call this if autocommit
was enabled.
"""
if os.environ.get("SANDBOX_ON") == "1" or \
self._data == self._data_orig:
return
try:
f = atomic_ofstream(self._filename, 'wb')
pickle.dump(self._data, f, protocol=2)
f.close()
except EnvironmentError as e:
if e.errno != PermissionDenied.errno:
writemsg_level("!!! %s %s\n" % (e, self._filename),
level=logging.ERROR, noiselevel=-1)
else:
self._data_orig = self._data.copy()
def register(self, cpv, slot, counter, paths):
""" Register new objects in the registry. If there is a record with the
same packagename (internally derived from cpv) and slot it is
overwritten with the new data.
@param cpv: package instance that owns the objects
@type cpv: CPV (as String)
@param slot: the value of SLOT of the given package instance
@type slot: String
@param counter: vdb counter value for the package instace
@type counter: Integer
@param paths: absolute paths of objects that got preserved during an update
@type paths: List
"""
cp = cpv_getkey(cpv)
cps = cp+":"+slot
if len(paths) == 0 and cps in self._data \
and self._data[cps][0] == cpv and int(self._data[cps][1]) == int(counter):
del self._data[cps]
elif len(paths) > 0:
self._data[cps] = (cpv, counter, paths)
if self._autocommit:
self.store()
def unregister(self, cpv, slot, counter):
""" Remove a previous registration of preserved objects for the given package.
@param cpv: package instance whose records should be removed
@type cpv: CPV (as String)
@param slot: the value of SLOT of the given package instance
@type slot: String
"""
self.register(cpv, slot, counter, [])
def pruneNonExisting(self):
""" Remove all records for objects that no longer exist on the filesystem. """
os = _os_merge
for cps in list(self._data):
cpv, counter, paths = self._data[cps]
paths = [f for f in paths \
if os.path.exists(os.path.join(self._root, f.lstrip(os.sep)))]
if len(paths) > 0:
self._data[cps] = (cpv, counter, paths)
else:
del self._data[cps]
if self._autocommit:
self.store()
def hasEntries(self):
""" Check if this registry contains any records. """
return len(self._data) > 0
def getPreservedLibs(self):
""" Return a mapping of packages->preserved objects.
@returns mapping of package instances to preserved objects
@rtype Dict cpv->list-of-paths
"""
rValue = {}
for cps in self._data:
rValue[self._data[cps][0]] = self._data[cps][2]
return rValue