[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:
@@ -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)),) )
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = '')
|
||||
|
||||
@@ -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."),
|
||||
|
||||
@@ -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 )
|
||||
|
||||
Reference in New Issue
Block a user