Files
entropy/lib/entropy/client/interfaces/cache.py
2011-10-17 14:27:58 +02:00

237 lines
8.4 KiB
Python

# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Package Manager Client Cache Interface}.
"""
import os
import shutil
import hashlib
from entropy.i18n import _
from entropy.output import purple
from entropy.const import etpConst, const_setup_perms, \
const_convert_to_unicode, const_convert_to_rawstring
from entropy.exceptions import RepositoryError
from entropy.cache import EntropyCacher
from entropy.db.exceptions import OperationalError, DatabaseError
REPO_LIST_CACHE_ID = 'repos/repolist'
class CacheMixin:
def _validate_repositories_cache(self):
# is the list of repos changed?
cached = self._cacher.pop(REPO_LIST_CACHE_ID)
if cached != self._settings['repositories']['order']:
# invalidate matching cache
try:
self._settings._clear_repository_cache(repoid = None)
except IOError:
pass
self._store_repository_list_cache()
def _store_repository_list_cache(self):
self._cacher.push(REPO_LIST_CACHE_ID,
self._settings['repositories']['order'],
async = False)
def clear_cache(self):
"""
Clear all the Entropy default cache directory. This function is
fault tolerant and will never return any exception.
"""
with self._cacher:
# no data is written while holding self._cacher by the balls
# drop all the buffers then remove on-disk data
self._cacher.discard()
# clear repositories live cache
if self._installed_repository is not None:
self._installed_repository.clearCache()
for repo in self._repodb_cache.values():
repo.clearCache()
cache_dir = self._cacher.current_directory()
try:
shutil.rmtree(cache_dir, True)
except (shutil.Error, IOError, OSError):
return
try:
os.makedirs(cache_dir, 0o775)
except (IOError, OSError):
return
try:
const_setup_perms(cache_dir, etpConst['entropygid'])
except (IOError, OSError):
return
def _get_available_packages_hash(self):
"""
Get available packages cache hash.
"""
# client digest not needed, cache is kept updated
c_hash = "%s|%s|%s" % (
self._repositories_hash(),
self._filter_available_repositories(),
# needed when users do bogus things like editing config files
# manually (branch setting)
self._settings['repositories']['branch'])
sha = hashlib.sha1()
sha.update(const_convert_to_rawstring(repr(c_hash)))
return sha.hexdigest()
def _repositories_hash(self):
"""
Return the checksum of available repositories, excluding package ones.
"""
enabled_repos = self._filter_available_repositories()
return self.__repositories_hash(enabled_repos)
def __repositories_hash(self, repositories):
sha = hashlib.sha1()
sha.update(const_convert_to_rawstring("0"))
for repo in repositories:
try:
dbconn = self.open_repository(repo)
except (RepositoryError):
continue # repo not available
try:
sha.update(const_convert_to_rawstring(repr(dbconn.mtime())))
except (OperationalError, DatabaseError, OSError, IOError):
txt = _("Repository") + " " + const_convert_to_unicode(repo) \
+ " " + _("is corrupted") + ". " + \
_("Cannot calculate the checksum")
self.output(
purple(txt),
importance = 1,
level = "warning"
)
return sha.hexdigest()
def _all_repositories_hash(self):
"""
Return the checksum of all the available repositories, including
package repos.
"""
return self.__repositories_hash(self._enabled_repos)
def _get_masked_packages_cache(self, chash):
"""
Return the on-disk cached object for all the masked packages.
@param chash: cache hash
@type chash: string
@return: list of masked packages (if cache hit) otherwise None
@rtype: list or None
"""
return self._cacher.pop("%s%s" % (
EntropyCacher.CACHE_IDS['world_masked'], chash))
def _get_available_packages_cache(self, chash):
"""
Return the on-disk cached object for all the available packages.
@param chash: cache hash
@type chash: string
@return: list of available packages (if cache hit) otherwise None
@rtype: list or None
"""
return self._cacher.pop("%s%s" % (
EntropyCacher.CACHE_IDS['world_available'], chash))
def _get_updates_cache(self, empty_deps, repo_hash = None):
"""
Get available updates on-disk cache, if available, otherwise return None
"""
cl_id = self.sys_settings_client_plugin_id
misc_settings = self._settings[cl_id]['misc']
ignore_spm_downgrades = misc_settings['ignore_spm_downgrades']
if self.xcache:
if repo_hash is None:
repo_hash = self._repositories_hash()
c_hash = self._get_updates_cache_hash(repo_hash, empty_deps,
ignore_spm_downgrades)
disk_cache = self._cacher.pop(c_hash)
if isinstance(disk_cache, tuple):
return disk_cache
def _filter_available_repositories(self, _enabled_repos = None):
"""
Filter out package repositories from the list of available,
enabled ones
@keyword _enabled_repos: an alternative list of enabled repository
identifiers
@type _enabled_repos: list
"""
if _enabled_repos is None:
_enabled_repos = self._enabled_repos
enabled_repos = [x for x in _enabled_repos if not \
x.endswith(etpConst['packagesext_webinstall'])]
enabled_repos = [x for x in enabled_repos if not \
x.endswith(etpConst['packagesext'])]
return enabled_repos
def _get_updates_cache_hash(self, repo_hash, empty_deps,
ignore_spm_downgrades):
"""
Get package updates cache hash that can be used to retrieve the on-disk
cached object.
"""
enabled_repos = self._filter_available_repositories()
repo_order = [x for x in self._settings['repositories']['order'] if
x in enabled_repos]
c_hash = "%s|%s|%s|%s|%s|%s" % (
repo_hash, empty_deps, enabled_repos,
repo_order,
ignore_spm_downgrades,
# needed when users do bogus things like editing config files
# manually (branch setting)
self._settings['repositories']['branch'],
)
sha = hashlib.sha1()
sha.update(const_convert_to_rawstring(repr(c_hash)))
return "%s_%s" % (EntropyCacher.CACHE_IDS['world_update'],
sha.hexdigest(),)
def _get_critical_updates_cache(self, repo_hash = None):
"""
Get critical package updates cache object, if available, otherwise
return None.
"""
if self.xcache:
if repo_hash is None:
repo_hash = self._repositories_hash()
c_hash = "%s%s" % (EntropyCacher.CACHE_IDS['critical_update'],
self._get_critical_update_cache_hash(repo_hash),)
return self._cacher.pop(c_hash)
def _get_critical_update_cache_hash(self, repo_hash):
"""
Get critical package updates cache hash that can be used to retrieve
the on-disk cached object.
"""
enabled_repos = self._filter_available_repositories()
repo_order = [x for x in self._settings['repositories']['order'] if
x in enabled_repos]
c_hash = "%s|%s|%s|%s" % (
repo_hash, enabled_repos,
repo_order,
# needed when users do bogus things like editing config files
# manually (branch setting)
self._settings['repositories']['branch'],
)
sha = hashlib.sha1()
sha.update(const_convert_to_rawstring(repr(c_hash)))
return sha.hexdigest()