[entropy.client.interfaces.repository] major Repository class rework

:: move repository update logic inside EntropyRepositoryBase.update()
   static method
:: provide two new static methods EntropyRepositoryBase.revision()
   and EntropyRepositoryBase.remote_revision() that have to be
   implemented by subclasses if they are supporting fetching local
   or remote revision.
:: several minor code quality improvements
This commit is contained in:
Fabio Erculiani
2010-06-26 19:15:02 +02:00
parent 21cf951b98
commit 9c6782e21c
15 changed files with 2153 additions and 2022 deletions
+1 -1
View File
@@ -230,7 +230,7 @@ def _show_repository_info(entropy_client, reponame):
print_info( red("\t%s: %s") % (_("Repository name"), bold(reponame),) )
print_info( red("\t%s: %s") % (_("Repository database path"),
blue(repo_data['dbpath']),) )
revision = entropy_client.get_repository_revision(reponame)
revision = entropy_client.get_repository(reponame).revision(reponame)
print_info( red("\t%s: %s") % (_("Repository revision"),
darkgreen(str(revision)),) )
+1 -1
View File
@@ -840,7 +840,7 @@ def _getinfo(entropy_client):
info['Repository databases'][x]['Installation internal protected directories'] = dbconn.listConfigProtectEntries()
info['Repository databases'][x]['Installation internal protected directory masks'] = dbconn.listConfigProtectEntries(mask = True)
info['Repository databases'][x]['Total available packages'] = len(dbconn.listAllPackageIds())
info['Repository databases'][x]['Database revision'] = entropy_client.get_repository_revision(x)
info['Repository databases'][x]['Database revision'] = entropy_client.get_repository(x).revision(x)
keys = sorted(info)
for x in keys:
+12 -5
View File
@@ -1,20 +1,27 @@
0.99.50:
- move repository sync() code inside EntropyRepository? (makes sense)
EntropyRepositoryBase:
- 2. implement revision(), remote_revision() in Entropy server db classes.
- 3. move update() code to Entropy server db class (change semantic?)
- entropy.server: when repackaging pkgs due to slotmove/pkgmove, repackage
them in all the repos they are?
- entropy error reports: catch dmidecode data (to figure out if bug is related
to faulty virtual machines)
- entropy.server API docs
- entropy.client API docs
1.0_beta1:
1.0:
- add ENTROPY_KNOWN_BROKEN_DEPS support into ebuild/PortagePlugin?
- implement system snapshots (as snapshots, sets).
- Client.urlFetcher/MultipleUrlFetcher? ugly!
- entropy.db.search* unittest
- entropy package metadata .dtd specs
- complete API documentation
- entropy.db: remove @deprecated methods
2.0:
1.1:
- PackageKit replacement
- UGC based on XML requests (all the commands into one string)
File diff suppressed because it is too large Load Diff
+32 -19
View File
@@ -30,7 +30,8 @@ from entropy.exceptions import RepositoryError, InvalidPackageSet,\
SystemDatabaseError
from entropy.db import EntropyRepository
from entropy.cache import EntropyCacher
from entropy.client.interfaces.db import ClientEntropyRepositoryPlugin
from entropy.client.interfaces.db import ClientEntropyRepositoryPlugin, \
InstalledPackagesRepository, AvailablePackagesRepository, GenericRepository
from entropy.client.mirrors import StatusInterface
from entropy.output import purple, bold, red, blue, darkgreen, darkred, brown
@@ -161,6 +162,25 @@ class RepositoryMixin:
self._repodb_cache[key] = dbconn
return dbconn
@staticmethod
def get_repository(repoid):
"""
Given a repository identifier, returns the repository class associated
with it.
NOTE: stub. When more EntropyRepositoryBase classes will be available,
this method will start making more sense.
WARNING: do not use this to open a repository. Please use
Client.open_repository() instead.
@param repoid: repository identifier
@type repoid: string
@return: EntropyRepositoryBase based class
@rtype: class object
"""
if repoid == etpConst['clientdbid']:
return InstalledPackagesRepository
return AvailablePackagesRepository
def _load_repository_database(self, repoid, xcache = True, indexing = True):
if const_isstring(repoid):
@@ -196,7 +216,7 @@ class RepositoryMixin:
self._repo_error_messages_cache.add(repoid)
raise RepositoryError("RepositoryError: %s" % (t,))
conn = EntropyRepository(
conn = self.get_repository(repoid)(
readOnly = True,
dbFile = dbfile,
dbname = etpConst['dbnamerepoprefix']+repoid,
@@ -222,20 +242,11 @@ class RepositoryMixin:
return conn
def get_repository_revision(self, reponame):
db_data = self._settings['repositories']['available'][reponame]
fname = os.path.join(db_data['dbpath'],
etpConst['etpdatabaserevisionfile'])
revision = -1
if os.path.isfile(fname) and os.access(fname, os.R_OK):
with open(fname, "r") as f:
try:
revision = int(f.readline().strip())
except (OSError, IOError, ValueError,):
pass
return revision
""" @deprecated """
try:
return int(self.get_repository(reponame).revision(reponame))
except (ValueError, TypeError,):
return -1
def add_repository(self, repodata):
@@ -593,7 +604,9 @@ class RepositoryMixin:
entropy.tools.print_traceback(f = self.clientLog)
else:
try:
conn = EntropyRepository(readOnly = False, dbFile = db_path,
repo_class = self.get_repository(etpConst['clientdbid'])
conn = repo_class(readOnly = False,
dbFile = db_path,
dbname = etpConst['clientdbid'],
xcache = self.xcache, indexing = self.indexing
)
@@ -635,7 +648,7 @@ class RepositoryMixin:
indexing = self.indexing
if dbname is None:
dbname = etpConst['genericdbid']
conn = EntropyRepository(
conn = GenericRepository(
readOnly = read_only,
dbFile = dbfile,
dbname = dbname,
@@ -652,7 +665,7 @@ class RepositoryMixin:
if temp_file is None:
temp_file = entropy.tools.get_random_temp_file()
dbc = EntropyRepository(
dbc = GenericRepository(
readOnly = False,
dbFile = temp_file,
dbname = dbname,
File diff suppressed because it is too large Load Diff
+2
View File
@@ -455,6 +455,8 @@ def const_default_settings(rootdir):
# Entropy database API revision
'etpapi': etpSys['api'],
# Entropy database API currently supported
'supportedapis': (1, 2, 3),
# contains the current running architecture
'currentarch': etpSys['arch'],
# Entropy supported Archs
+7 -8
View File
@@ -474,7 +474,7 @@ class EntropyRepository(EntropyRepositoryBase):
pass
try:
conn = self.__connection_cache.pop((th_id, pid))
if not self.readOnly:
if not self.readonly:
try:
conn.commit()
except OperationalError:
@@ -542,7 +542,7 @@ class EntropyRepository(EntropyRepositoryBase):
first_part = "<EntropyRepository instance at %s, %s" % (
hex(id(self)), self.__db_path,)
second_part = ", ro: %s, caching: %s, indexing: %s" % (
self.readOnly, self.xcache, self.indexing,)
self.readonly, self.xcache, self.indexing,)
third_part = ", name: %s, skip_upd: %s, st_upd: %s" % (
self.reponame, self.__skip_checks, self.__structure_update,)
fourth_part = ", conn_cache: %s, cursor_cache: %s>" % (
@@ -612,7 +612,7 @@ class EntropyRepository(EntropyRepositoryBase):
super(EntropyRepository, self).commitChanges(force = force,
no_plugins = no_plugins)
if force or (not self.readOnly):
if force or (not self.readonly):
try:
self._connection().commit()
except Error:
@@ -4073,7 +4073,7 @@ class EntropyRepository(EntropyRepositoryBase):
cur = self._cursor().execute("""
SELECT idpackage FROM baseinfo where idcategory = (?)
""" + order_by_string, (idcategory,))
""" + order_by_string, (category_id,))
return self._cur2set(cur)
@@ -4231,8 +4231,8 @@ class EntropyRepository(EntropyRepositoryBase):
def _databaseStructureUpdates(self):
old_readonly = self.readOnly
self.readOnly = False
old_readonly = self.readonly
self.readonly = False
if not self._doesTableExist("packagedesktopmime"):
self._createPackageDesktopMimeTable()
@@ -4279,7 +4279,7 @@ class EntropyRepository(EntropyRepositoryBase):
self._foreignKeySupport()
self.readOnly = old_readonly
self.readonly = old_readonly
self._connection().commit()
def validateDatabase(self):
@@ -5603,4 +5603,3 @@ class EntropyRepository(EntropyRepositoryBase):
""" @deprecated """
warnings.warn("deprecated call!")
return self.maskFilter(*args, **kwargs)
+70 -5
View File
@@ -377,12 +377,12 @@ class EntropyRepositoryBase(TextInterface, EntropyRepositoryPluginStore, object)
VIRTUAL_META_PACKAGE_CATEGORY = "virtual"
def __init__(self, readOnly, xcache, temporary, reponame, indexing):
def __init__(self, readonly, xcache, temporary, reponame, indexing):
"""
EntropyRepositoryBase constructor.
@param readOnly: readonly bit
@type readOnly: bool
@param readonly: readonly bit
@type readonly: bool
@param xcache: xcache bit (enable on-disk cache?)
@type xcache: bool
@param temporary: is this repo a temporary (non persistent) one?
@@ -392,11 +392,12 @@ class EntropyRepositoryBase(TextInterface, EntropyRepositoryPluginStore, object)
@param indexing: enable metadata indexing (for faster retrieval)
@type indexing: bool
"""
self.readOnly = readOnly
self.readonly = readonly
self.xcache = xcache
self.temporary = temporary
self.indexing = indexing
# XXX: backward compatibility
self.readOnly = readonly
self.dbname = reponame
self.reponame = reponame
self._settings = SystemSettings()
@@ -414,7 +415,7 @@ class EntropyRepositoryBase(TextInterface, EntropyRepositoryPluginStore, object)
Attention: call this method from your subclass, otherwise
EntropyRepositoryPlugins won't be notified of a repo close.
"""
if not self.readOnly:
if not self.readonly:
self.commitChanges()
plugins = self.get_plugins()
@@ -3498,6 +3499,70 @@ class EntropyRepositoryBase(TextInterface, EntropyRepositoryPluginStore, object)
"""
raise NotImplementedError()
"""
Update status flags, self explanatory.
"""
REPOSITORY_ALREADY_UPTODATE = -1
REPOSITORY_NOT_AVAILABLE = -2
REPOSITORY_GENERIC_ERROR = -3
REPOSITORY_CHECKSUM_ERROR = -4
REPOSITORY_UPDATED_OK = 0
@staticmethod
def update(entropy_client, repository_id, force, gpg):
"""
Update the content of this repository. Every subclass can implement
its own update way.
This method must return a status code that can be either
EntropyRepositoryBase.REPOSITORY_ALREADY_UPTODATE or
EntropyRepositoryBase.REPOSITORY_NOT_AVAILABLE or
EntropyRepositoryBase.REPOSITORY_GENERIC_ERROR or
EntropyRepositoryBase.REPOSITORY_CHECKSUM_ERROR or
EntropyRepositoryBase.REPOSITORY_UPDATED_OK
If your repository is not supposed to be remotely updated, just
ignore this method.
@param entropy_client: Entropy Client based object
@type entropy_client: entropy.client.interfaces.Client
@param repository_id: repository identifier
@type repository_id: string
@param force: force update anyway
@type force: bool
@param gpg: GPG feature enable
@type gpg: bool
@return: status code
@rtype: int
"""
raise NotImplementedError()
@staticmethod
def revision(repository_id):
"""
Returns the repository local revision in int format or None, if
no revision is available.
@param repository_id: repository identifier
@type repository_id: string
@return: repository revision
@rtype: int or None
@raise KeyError: if repository is not available
"""
raise NotImplementedError()
@staticmethod
def remote_revision(repository_id):
"""
Returns the repository remote revision in int format or None, if
no revision is available.
@param repository_id: repository identifier
@type repository_id: string
@return: repository revision
@rtype: int or None
@raise KeyError: if repository is not available
"""
raise NotImplementedError()
def _maskFilter_live(self, package_id, reponame):
ref = self._settings['pkg_masking_reference']
@@ -112,6 +112,8 @@ class ServerEntropyRepositoryPlugin(EntropyRepositoryPlugin):
if not local_dbfile_exists:
# better than having a completely broken db
self._metadata['read_only'] = False
entropy_repository_instance.readonly = False
# XXX remove this in future
entropy_repository_instance.readOnly = False
entropy_repository_instance.initializeRepository()
entropy_repository_instance.commitChanges()
@@ -2316,6 +2316,8 @@ class PortagePlugin(SpmPlugin):
if do_rescan or (str(stored_digest) != str(portage_dirs_digest)):
# force parameters
entropy_repository.readonly = False
# XXX: remove this in future
entropy_repository.readOnly = False
# disable upload trigger
from entropy.server.interfaces.main import \
+1 -2
View File
@@ -37,8 +37,7 @@ sys.path.insert(0,'../client')
from entropy.cache import EntropyCacher
from entropy.misc import LogFile
from entropy.i18n import _
from entropy.exceptions import PermissionDenied, RepositoryError, \
MissingParameter
from entropy.exceptions import PermissionDenied, RepositoryError
import entropy.tools as entropyTools
from entropy.client.interfaces import Client
from entropy.fetchers import UrlFetcher
+20 -46
View File
@@ -41,8 +41,7 @@ EntropyCacher.WRITEBACK_TIMEOUT = 120
from entropy.misc import LogFile
from entropy.i18n import _
from entropy.exceptions import PermissionDenied, RepositoryError, \
MissingParameter
from entropy.exceptions import PermissionDenied, RepositoryError
import entropy.tools
from entropy.client.interfaces import Client
from entropy.fetchers import UrlFetcher
@@ -287,11 +286,6 @@ class UpdatesDaemon(dbus.service.Object):
entropy_updates_alert = True)
if DAEMON_DEBUG:
write_output("__run_sync: repository interface loaded")
except MissingParameter, err:
if DAEMON_DEBUG:
write_output(
"__run_sync: MissingParameter exception, error: %s" % (
err,))
except Exception, err:
if DAEMON_DEBUG:
write_output(
@@ -367,7 +361,7 @@ class UpdatesDaemon(dbus.service.Object):
if DAEMON_DEBUG:
write_output("__run_fetcher: called %s" % (time.time(),))
repos_to_up = self.get_repo_status(entropy)
repos_to_up = self.get_repo_status()
if repos_to_up:
@@ -440,49 +434,29 @@ class UpdatesDaemon(dbus.service.Object):
# compare repos status for updates
@dbus.service.method ( "org.entropy.Client", in_signature = '',
out_signature = 'a{si}')
def get_repo_status(self, entropy = None):
def get_repo_status(self):
destroy = False
if entropy is None:
destroy = True
entropy = Entropy()
repos = {}
# now get remote
sys_set = SysSet()
for repoid in sys_set['repositories']['available']:
try:
repo_rev = Entropy.get_repository(repoid).revision(repoid)
online_rev = Entropy.get_repository(repoid).remote_revision(repoid)
if (online_rev == -1) or (repo_rev != online_rev):
repos = {}
try:
repo_conn = entropy.Repositories(
entropy_updates_alert = True, fetch_security = False)
except MissingParameter:
return repos
except Exception, e:
return repos
if DAEMON_DEBUG:
write_output(
"get_repo_status: repo needs to be updated: %s" % (
repoid,))
# now get remote
for repoid in entropy.SystemSettings['repositories']['available']:
sys_set._clear_repository_cache(repoid = repoid)
repos[repoid] = {
'local': repo_rev,
'remote': online_rev,
}
repo_rev = entropy.get_repository_revision(repoid)
online_rev = repo_conn.get_online_repository_revision(repoid)
if (online_rev == -1) or (repo_rev != online_rev):
if DAEMON_DEBUG:
write_output(
"get_repo_status: repo needs to be updated: %s" % (
repoid,))
entropy.SystemSettings._clear_repository_cache(
repoid = repoid)
repos[repoid] = {
'local': repo_rev,
'remote': online_rev,
}
del repo_conn
return repos
finally:
if destroy:
entropy.shutdown()
return repos
@dbus.service.method ( "org.entropy.Client", in_signature = '',
out_signature = '')
+1 -1
View File
@@ -589,7 +589,7 @@ class SulfurApplication(Controller, SulfurApplicationEventsMixin):
valid_repos = self._entropy.repositories()
invalid_repos = [x for x in all_repos if x not in valid_repos]
invalid_repos = [x for x in invalid_repos if \
(self._entropy.get_repository_revision(x) == -1)]
(self._entropy.get_repository(x).revision(x) == -1)]
if invalid_repos:
mydialog = ConfirmationDialog(self.ui.main, invalid_repos,
top_text = _("The repositories listed below are configured but not available. They should be downloaded."),
+7
View File
@@ -2842,16 +2842,23 @@ class EntropyRepoView:
def populate(self):
self.store.clear()
cache = set()
for repo in self._entropy.Settings()['repositories']['order']:
if repo in cache:
continue
repodata = self._entropy.Settings()['repositories']['available'][repo]
self.store.append([1, 1, repodata['dbrevision'], repo,
repodata['description']])
cache.add(repo)
# excluded ones
repo_excluded = self._entropy.Settings()['repositories']['excluded']
for repo in repo_excluded:
if repo in cache:
continue
repodata = repo_excluded[repo]
self.store.append([0, 0, repodata['dbrevision'], repo,
repodata['description']])
cache.add(repo)
def new_pixbuf( self, column, cell, model, myiter ):
gpg = model.get_value( myiter, 3 )