4179 lines
152 KiB
Python
4179 lines
152 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
|
|
@author: Fabio Erculiani <lxnay@sabayonlinux.org>
|
|
@contact: lxnay@sabayonlinux.org
|
|
@copyright: Fabio Erculiani
|
|
@license: GPL-2
|
|
|
|
B{Entropy Package Manager Server Main Interfaces}.
|
|
|
|
"""
|
|
import sys
|
|
import os
|
|
import shutil
|
|
from entropy.core import Singleton
|
|
from entropy.exceptions import OnlineMirrorError, PermissionDenied, \
|
|
SystemDatabaseError
|
|
from entropy.const import etpConst, etpSys, const_setup_perms, \
|
|
const_create_working_dirs, const_extract_srv_repo_params, etpUi, \
|
|
const_setup_file, const_get_stringtype, const_debug_write
|
|
from entropy.output import TextInterface, purple, red, darkgreen, \
|
|
bold, brown, blue, darkred
|
|
from entropy.server.interfaces.mirrors import Server as MirrorsServer
|
|
from entropy.i18n import _
|
|
from entropy.core.settings.base import SystemSettings
|
|
from entropy.core.settings.plugins.skel import SystemSettingsPlugin
|
|
from entropy.transceivers import EntropyTransceiver
|
|
from entropy.db import EntropyRepository
|
|
from entropy.db.skel import EntropyRepositoryPlugin
|
|
from entropy.server.interfaces.db import ServerRepositoryStatus
|
|
from entropy.spm.plugins.factory import get_default_instance as get_spm, \
|
|
get_default_class as get_spm_class
|
|
from entropy.qa import QAInterfacePlugin
|
|
|
|
SERVER_QA_PLUGIN = "ServerQAInterfacePlugin"
|
|
|
|
class ServerEntropyRepositoryPlugin(EntropyRepositoryPlugin):
|
|
|
|
import entropy.dump as dump
|
|
PLUGIN_ID = "__server__"
|
|
|
|
def __init__(self, server_interface, metadata = None):
|
|
"""
|
|
Entropy server-side repository EntropyRepository Plugin class.
|
|
This class will be instantiated and automatically added to
|
|
EntropyRepository instances generated by Entropy Server.
|
|
|
|
@param server_interface: Entropy Server interface instance
|
|
@type server_interface: entropy.server.interfaces.Server class
|
|
@param metadata: any dict form metadata map (key => value)
|
|
@type metadata: dict
|
|
"""
|
|
EntropyRepositoryPlugin.__init__(self)
|
|
self.SystemSettings = SystemSettings()
|
|
self.srv_sys_settings_plugin = \
|
|
etpConst['system_settings_plugins_ids']['server_plugin']
|
|
self._server = server_interface
|
|
if metadata is None:
|
|
self._metadata = {}
|
|
else:
|
|
self._metadata = metadata
|
|
|
|
# make sure we set client_repo metadata to False, this indicates
|
|
# EntropyRepository that we are a server-side repository
|
|
# Of course, it shouldn't make any diff to not set this, but we
|
|
# really want to make sure it's always enforced.
|
|
self._metadata['client_repo'] = False
|
|
|
|
def get_id(self):
|
|
return ServerEntropyRepositoryPlugin.PLUGIN_ID
|
|
|
|
def get_metadata(self):
|
|
"""
|
|
This method should always return a direct reference to the object and
|
|
NOT a copy.
|
|
"""
|
|
return self._metadata
|
|
|
|
def add_plugin_hook(self, entropy_repository_instance):
|
|
const_debug_write(__name__,
|
|
"ServerEntropyRepositoryPlugin: calling add_plugin_hook => %s" % (
|
|
self,)
|
|
)
|
|
|
|
use_branch = self._metadata.get('use_branch')
|
|
if use_branch is not None:
|
|
entropy_repository_instance.db_branch = use_branch
|
|
|
|
out_intf = self._metadata.get('output_interface')
|
|
if out_intf is not None:
|
|
entropy_repository_instance.updateProgress = out_intf.updateProgress
|
|
entropy_repository_instance.askQuestion = out_intf.askQuestion
|
|
|
|
return 0
|
|
|
|
def close_repo_hook(self, entropy_repository_instance):
|
|
const_debug_write(__name__,
|
|
"ServerEntropyRepositoryPlugin: calling close_repo_hook => %s" % (
|
|
self,)
|
|
)
|
|
|
|
# this happens because close_server_repositories() might be called
|
|
# before setup_services() and in general, at any time, so, in this
|
|
# case, there is no need to print bullshit to dev.
|
|
if self._server.MirrorsService is None:
|
|
return 0
|
|
|
|
repo = entropy_repository_instance.dbname
|
|
dbfile = entropy_repository_instance.dbFile
|
|
sts = ServerRepositoryStatus()
|
|
if sts.is_tainted(dbfile) and not sts.is_unlock_msg(dbfile):
|
|
u_msg = _("Mirrors have not been unlocked. Remember to sync them.")
|
|
self._server.updateProgress(
|
|
darkgreen(u_msg),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" * ")
|
|
)
|
|
# avoid spamming
|
|
sts.set_unlock_msg(dbfile)
|
|
|
|
return 0
|
|
|
|
def commit_hook(self, entropy_repository_instance):
|
|
|
|
const_debug_write(__name__,
|
|
"ServerEntropyRepositoryPlugin: calling commit_hook => %s" % (
|
|
self,)
|
|
)
|
|
|
|
dbs = ServerRepositoryStatus()
|
|
dbfile = entropy_repository_instance.dbFile
|
|
repo = entropy_repository_instance.dbname
|
|
read_only = entropy_repository_instance.readOnly
|
|
if read_only:
|
|
# do not taint database
|
|
return 0
|
|
|
|
# taint the database status
|
|
taint_file = self._server.get_local_database_taint_file(repo = repo)
|
|
f = open(taint_file, "w")
|
|
f.write(etpConst['currentarch']+" database tainted\n")
|
|
f.flush()
|
|
f.close()
|
|
const_setup_file(taint_file, etpConst['entropygid'], 0o664)
|
|
dbs.set_tainted(dbfile)
|
|
|
|
if not dbs.is_bumped(dbfile):
|
|
# bump revision, setting DatabaseBump causes
|
|
# the session to just bump once
|
|
dbs.set_bumped(dbfile)
|
|
"""
|
|
Entropy repository revision bumping function. Every time it's called,
|
|
revision is incremented by 1.
|
|
"""
|
|
revision_file = self._server.get_local_database_revision_file(
|
|
repo = repo)
|
|
if not os.path.isfile(revision_file):
|
|
revision = 1
|
|
else:
|
|
with open(revision_file, "r") as rev_f:
|
|
revision = int(rev_f.readline().strip())
|
|
revision += 1
|
|
|
|
tmp_revision_file = revision_file + ".tmp"
|
|
with open(tmp_revision_file, "w") as rev_fw:
|
|
rev_fw.write(str(revision)+"\n")
|
|
rev_fw.flush()
|
|
# atomic !
|
|
os.rename(tmp_revision_file, revision_file)
|
|
|
|
return 0
|
|
|
|
def _get_category_description_from_disk(self, category):
|
|
"""
|
|
Get category name description from Source Package Manager.
|
|
|
|
@param category: category name
|
|
@type category: string
|
|
@return: category description
|
|
@rtype: string
|
|
"""
|
|
spm = self._server.Spm()
|
|
return spm.get_package_category_description_metadata(category)
|
|
|
|
def _write_rss_for_removed_package(self, repo_db, idpackage):
|
|
|
|
# setup variables we're going to use
|
|
srv_repo = repo_db.dbname
|
|
rss_revision = repo_db.retrieveRevision(idpackage)
|
|
rss_atom = "%s~%s" % (repo_db.retrieveAtom(idpackage), rss_revision,)
|
|
status = ServerRepositoryStatus()
|
|
srv_updates = status.get_updates_log(srv_repo)
|
|
rss_name = srv_repo + etpConst['rss-dump-name']
|
|
|
|
# load metadata from on disk cache, if available
|
|
rss_obj = self.dump.loadobj(rss_name)
|
|
if rss_obj:
|
|
srv_updates.update(rss_obj)
|
|
|
|
# setup metadata keys, if not available
|
|
if 'added' not in srv_updates:
|
|
srv_updates['added'] = {}
|
|
if 'removed' not in srv_updates:
|
|
srv_updates['removed'] = {}
|
|
if 'light' not in srv_updates:
|
|
srv_updates['light'] = {}
|
|
|
|
# if pkgatom (rss_atom) is in the "added" metadata, drop it
|
|
if rss_atom in srv_updates['added']:
|
|
del srv_updates['added'][rss_atom]
|
|
# same thing for light key
|
|
if rss_atom in srv_updates['light']:
|
|
del srv_updates['light'][rss_atom]
|
|
|
|
# add metadata
|
|
mydict = {}
|
|
try:
|
|
mydict['description'] = repo_db.retrieveDescription(idpackage)
|
|
except TypeError:
|
|
mydict['description'] = "N/A"
|
|
try:
|
|
mydict['homepage'] = repo_db.retrieveHomepage(idpackage)
|
|
except TypeError:
|
|
mydict['homepage'] = ""
|
|
srv_updates['removed'][rss_atom] = mydict
|
|
|
|
# save to disk
|
|
self.dump.dumpobj(rss_name, srv_updates)
|
|
|
|
def _write_rss_for_added_package(self, repo_db, package_data):
|
|
|
|
# setup variables we're going to use
|
|
srv_repo = repo_db.dbname
|
|
rss_atom = "%s~%s" % (package_data['atom'], package_data['revision'],)
|
|
status = ServerRepositoryStatus()
|
|
srv_updates = status.get_updates_log(srv_repo)
|
|
rss_name = srv_repo + etpConst['rss-dump-name']
|
|
|
|
# load metadata from on disk cache, if available
|
|
rss_obj = self.dump.loadobj(rss_name)
|
|
if rss_obj:
|
|
srv_updates.update(rss_obj)
|
|
|
|
# setup metadata keys, if not available
|
|
if 'added' not in srv_updates:
|
|
srv_updates['added'] = {}
|
|
if 'removed' not in srv_updates:
|
|
srv_updates['removed'] = {}
|
|
if 'light' not in srv_updates:
|
|
srv_updates['light'] = {}
|
|
|
|
# if package_data['atom'] (rss_atom) is in the
|
|
# "removed" metadata, drop it
|
|
if rss_atom in srv_updates['removed']:
|
|
del srv_updates['removed'][rss_atom]
|
|
|
|
# add metadata
|
|
srv_updates['added'][rss_atom] = {}
|
|
srv_updates['added'][rss_atom]['description'] = \
|
|
package_data['description']
|
|
srv_updates['added'][rss_atom]['homepage'] = \
|
|
package_data['homepage']
|
|
srv_updates['light'][rss_atom] = {}
|
|
srv_updates['light'][rss_atom]['description'] = \
|
|
package_data['description']
|
|
|
|
# save to disk
|
|
self.dump.dumpobj(rss_name, srv_updates)
|
|
|
|
def add_package_hook(self, entropy_repository_instance, package_data):
|
|
|
|
const_debug_write(__name__,
|
|
"ServerEntropyRepositoryPlugin: calling add_package_hook => %s" % (
|
|
self,)
|
|
)
|
|
|
|
# handle server-side repo RSS support
|
|
sys_set_plug = self.srv_sys_settings_plugin
|
|
if self.SystemSettings[sys_set_plug]['server']['rss']['enabled']:
|
|
self._write_rss_for_added_package(entropy_repository_instance,
|
|
package_data)
|
|
|
|
try:
|
|
descdata = self._get_category_description_from_disk(
|
|
package_data['category'])
|
|
entropy_repository_instance.setCategoryDescription(
|
|
package_data['category'], descdata)
|
|
except (IOError, OSError, EOFError,):
|
|
pass
|
|
|
|
return 0
|
|
|
|
def remove_package_hook(self, entropy_repository_instance, idpackage,
|
|
from_add_package):
|
|
|
|
const_debug_write(__name__,
|
|
"ServerEntropyRepositoryPlugin: calling remove_package_hook => %s" % (
|
|
self,)
|
|
)
|
|
|
|
# handle server-side repo RSS support
|
|
sys_set_plug = self.srv_sys_settings_plugin
|
|
if self.SystemSettings[sys_set_plug]['server']['rss']['enabled'] \
|
|
and (not from_add_package):
|
|
|
|
# store addPackage action
|
|
self._write_rss_for_removed_package(entropy_repository_instance,
|
|
idpackage)
|
|
|
|
return 0
|
|
|
|
def treeupdates_move_action_hook(self, entropy_repository_instance,
|
|
idpackage):
|
|
# check for injection and warn the developer
|
|
injected = entropy_repository_instance.isInjected(idpackage)
|
|
new_atom = entropy_repository_instance.retrieveAtom(idpackage)
|
|
if injected:
|
|
mytxt = "%s: %s %s. %s !!! %s." % (
|
|
bold(_("INJECT")),
|
|
blue(str(new_atom)),
|
|
red(_("has been injected")),
|
|
red(_("quickpkg manually to update embedded db")),
|
|
red(_("Repository database updated anyway")),
|
|
)
|
|
self._server.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" * ")
|
|
)
|
|
return 0
|
|
|
|
def treeupdates_slot_move_action_hook(self, entropy_repository_instance,
|
|
idpackage):
|
|
return self.treeupdates_move_action_hook(entropy_repository_instance,
|
|
idpackage)
|
|
|
|
def reverse_dependencies_tree_generation_hook(self,
|
|
entropy_repository_instance):
|
|
# force commit even if readonly, this will allow
|
|
# to automagically fix dependstable server side
|
|
# we don't care much about syncing the
|
|
# database since it's a quite trivial change
|
|
entropy_repository_instance.commitChanges(force = True,
|
|
no_plugins = True)
|
|
|
|
return 0
|
|
|
|
|
|
class ServerSystemSettingsPlugin(SystemSettingsPlugin):
|
|
|
|
def server_parser(self, sys_set):
|
|
|
|
"""
|
|
Parses Entropy server system configuration file.
|
|
|
|
@return dict data
|
|
"""
|
|
|
|
data = {
|
|
'repositories': etpConst['server_repositories'].copy(),
|
|
'qa_langs': ["en_US", "C"],
|
|
'default_repository_id': etpConst['defaultserverrepositoryid'],
|
|
'base_repository_id': None,
|
|
'packages_expiration_days': etpConst['packagesexpirationdays'],
|
|
'database_file_format': etpConst['etpdatabasefileformat'],
|
|
'disabled_eapis': set(),
|
|
'exp_based_scope': etpConst['expiration_based_scope'],
|
|
'sync_speed_limit': None,
|
|
'rss': {
|
|
'enabled': etpConst['rss-feed'],
|
|
'name': etpConst['rss-name'],
|
|
'base_url': etpConst['rss-base-url'],
|
|
'website_url': etpConst['rss-website-url'],
|
|
'editor': etpConst['rss-managing-editor'],
|
|
'max_entries': etpConst['rss-max-entries'],
|
|
'light_max_entries': etpConst['rss-light-max-entries'],
|
|
},
|
|
}
|
|
|
|
fake_instance = self._helper.fake_default_repo
|
|
|
|
if not os.access(etpConst['serverconf'], os.R_OK):
|
|
return data
|
|
|
|
with open(etpConst['serverconf'], "r") as server_f:
|
|
serverconf = [x.strip() for x in server_f.readlines() if x.strip()]
|
|
|
|
default_repo_changed = False
|
|
|
|
for line in serverconf:
|
|
|
|
split_line = line.split("|")
|
|
split_line_len = len(split_line)
|
|
|
|
# TODO: remove this in future, supported for backward compat.
|
|
if (line.find("officialserverrepositoryid|") != -1) and \
|
|
(not line.startswith("#")) and (split_line_len == 2):
|
|
|
|
# TODO: added for backward and mixed compat.
|
|
if default_repo_changed:
|
|
continue
|
|
|
|
if not fake_instance:
|
|
data['default_repository_id'] = split_line[1].strip()
|
|
|
|
elif (line.find("default-repository|") != -1) and \
|
|
(not line.startswith("#")) and (split_line_len == 2):
|
|
|
|
if not fake_instance:
|
|
data['default_repository_id'] = split_line[1].strip()
|
|
default_repo_changed = True
|
|
|
|
elif line.startswith("expiration-days|") and (split_line_len == 2):
|
|
|
|
mydays = split_line[1].strip()
|
|
try:
|
|
mydays = int(mydays)
|
|
data['packages_expiration_days'] = mydays
|
|
except ValueError:
|
|
continue
|
|
|
|
elif line.startswith("expiration-based-scope|") and \
|
|
(split_line_len == 2):
|
|
|
|
exp_opt = split_line[1].strip().lower()
|
|
if exp_opt in ("enable", "enabled", "true", "1", "yes"):
|
|
data['exp_based_scope'] = True
|
|
else:
|
|
data['exp_based_scope'] = False
|
|
|
|
elif line.startswith("disabled-eapis|") and (split_line_len == 2):
|
|
|
|
mydis = split_line[1].strip().split(",")
|
|
try:
|
|
mydis = [int(x) for x in mydis]
|
|
mydis = set([x for x in mydis if x in (1, 2, 3,)])
|
|
except ValueError:
|
|
continue
|
|
if (len(mydis) < 3) and mydis:
|
|
data['disabled_eapis'] = mydis
|
|
|
|
elif line.startswith("server-basic-languages|") and \
|
|
(split_line_len == 2):
|
|
data['qa_langs'] = split_line[1].strip().split()
|
|
|
|
elif line.startswith("repository|") and (split_line_len in (5, 6)) \
|
|
and (not fake_instance):
|
|
|
|
repoid, repodata = const_extract_srv_repo_params(line,
|
|
product = sys_set['repositories']['product'])
|
|
if repoid in data['repositories']:
|
|
# just update mirrors
|
|
data['repositories'][repoid]['mirrors'].extend(
|
|
repodata['mirrors'])
|
|
else:
|
|
data['repositories'][repoid] = repodata.copy()
|
|
|
|
# base_repository_id support
|
|
if data['base_repository_id'] is None:
|
|
data['base_repository_id'] = repoid
|
|
|
|
elif line.startswith("database-format|") and (split_line_len == 2):
|
|
|
|
fmt = split_line[1]
|
|
if fmt in etpConst['etpdatabasesupportedcformats']:
|
|
data['database_file_format'] = fmt
|
|
|
|
elif line.startswith("syncspeedlimit|") and (split_line_len == 2):
|
|
|
|
try:
|
|
speed_limit = int(split_line[1])
|
|
except ValueError:
|
|
speed_limit = None
|
|
data['sync_speed_limit'] = speed_limit
|
|
|
|
elif line.startswith("rss-feed|") and (split_line_len == 2):
|
|
|
|
feed = split_line[1]
|
|
if feed in ("enable", "enabled", "true", "1"):
|
|
data['rss']['enabled'] = True
|
|
elif feed in ("disable", "disabled", "false", "0", "no",):
|
|
data['rss']['enabled'] = False
|
|
|
|
elif line.startswith("rss-name|") and (split_line_len == 2):
|
|
|
|
feedname = line.split("rss-name|")[1].strip()
|
|
data['rss']['name'] = feedname
|
|
|
|
elif line.startswith("rss-base-url|") and (split_line_len == 2):
|
|
|
|
data['rss']['base_url'] = line.split("rss-base-url|")[1].strip()
|
|
if not data['rss']['base_url'][-1] == "/":
|
|
data['rss']['base_url'] += "/"
|
|
|
|
elif line.startswith("rss-website-url|") and (split_line_len == 2):
|
|
|
|
data['rss']['website_url'] = split_line[1].strip()
|
|
|
|
elif line.startswith("managing-editor|") and (split_line_len == 2):
|
|
|
|
data['rss']['editor'] = split_line[1].strip()
|
|
|
|
elif line.startswith("max-rss-entries|") and (split_line_len == 2):
|
|
|
|
try:
|
|
entries = int(split_line[1].strip())
|
|
data['rss']['max_entries'] = entries
|
|
except (ValueError, IndexError,):
|
|
continue
|
|
|
|
elif line.startswith("max-rss-light-entries|") and \
|
|
(split_line_len == 2):
|
|
|
|
try:
|
|
entries = int(split_line[1].strip())
|
|
data['rss']['light_max_entries'] = entries
|
|
except (ValueError, IndexError,):
|
|
continue
|
|
|
|
# add system database if community repository mode is enabled
|
|
if self._helper.community_repo:
|
|
data['repositories'][etpConst['clientserverrepoid']] = {}
|
|
mydata = {}
|
|
mydata['description'] = "Community Repositories System Database"
|
|
mydata['mirrors'] = []
|
|
mydata['community'] = False
|
|
data['repositories'][etpConst['clientserverrepoid']].update(mydata)
|
|
# installed packages repository is now the base repository
|
|
data['base_repository_id'] = etpConst['clientserverrepoid']
|
|
|
|
# expand paths
|
|
for repoid in data['repositories']:
|
|
data['repositories'][repoid]['packages_dir'] = \
|
|
os.path.join( etpConst['entropyworkdir'],
|
|
"server",
|
|
repoid,
|
|
"packages",
|
|
etpSys['arch']
|
|
)
|
|
data['repositories'][repoid]['store_dir'] = \
|
|
os.path.join( etpConst['entropyworkdir'],
|
|
"server",
|
|
repoid,
|
|
"store",
|
|
etpSys['arch']
|
|
)
|
|
data['repositories'][repoid]['upload_dir'] = \
|
|
os.path.join( etpConst['entropyworkdir'],
|
|
"server",
|
|
repoid,
|
|
"upload",
|
|
etpSys['arch']
|
|
)
|
|
data['repositories'][repoid]['database_dir'] = \
|
|
os.path.join( etpConst['entropyworkdir'],
|
|
"server",
|
|
repoid,
|
|
"database",
|
|
etpSys['arch']
|
|
)
|
|
data['repositories'][repoid]['packages_relative_path'] = \
|
|
os.path.join( sys_set['repositories']['product'],
|
|
repoid,
|
|
"packages",
|
|
etpSys['arch']
|
|
)+"/"
|
|
data['repositories'][repoid]['database_relative_path'] = \
|
|
os.path.join( sys_set['repositories']['product'],
|
|
repoid,
|
|
"database",
|
|
etpSys['arch']
|
|
)+"/"
|
|
|
|
# Support for shell variables
|
|
shell_repoid = os.getenv('ETP_REPO')
|
|
if shell_repoid:
|
|
data['default_repository_id'] = shell_repoid
|
|
|
|
expiration_days = os.getenv('ETP_EXPIRATION_DAYS')
|
|
if expiration_days:
|
|
try:
|
|
expiration_days = int(expiration_days)
|
|
data['packages_expiration_days'] = expiration_days
|
|
except ValueError:
|
|
pass
|
|
|
|
return data
|
|
|
|
class ServerFatscopeSystemSettingsPlugin(SystemSettingsPlugin):
|
|
|
|
import entropy.tools as entropyTools
|
|
|
|
def repos_parser(self, sys_set):
|
|
|
|
data = {}
|
|
srv_plug_id = etpConst['system_settings_plugins_ids']['server_plugin']
|
|
# if support is not enabled, don't waste time scanning files
|
|
srv_parser_data = sys_set[srv_plug_id]['server']
|
|
if not srv_parser_data['exp_based_scope']:
|
|
return data
|
|
|
|
# get expiration-based packages removal data from config files
|
|
for repoid in srv_parser_data['repositories']:
|
|
|
|
# filter out system repository if community repository
|
|
# mode is enabled
|
|
if repoid == etpConst['clientserverrepoid']:
|
|
continue
|
|
|
|
idpackages = set()
|
|
exp_fp = self._helper.get_local_exp_based_pkgs_rm_whitelist_file(
|
|
repo = repoid)
|
|
dbconn = self._helper.open_server_repository(
|
|
just_reading = True, repo = repoid)
|
|
|
|
if os.access(exp_fp, os.R_OK) and os.path.isfile(exp_fp):
|
|
pkgs = self.entropyTools.generic_file_content_parser(exp_fp)
|
|
if '*' in pkgs: # wildcard support
|
|
idpackages.add(-1)
|
|
else:
|
|
for pkg in pkgs:
|
|
idpackage, rc_match = dbconn.atomMatch(pkg)
|
|
if rc_match:
|
|
continue
|
|
idpackages.add(idpackage)
|
|
|
|
data[repoid] = idpackages
|
|
|
|
return data
|
|
|
|
class ServerQAInterfacePlugin(QAInterfacePlugin):
|
|
|
|
def __check_package_using_spm(self, package_path):
|
|
|
|
spm_class = get_spm_class()
|
|
spm_rc, spm_msg = spm_class.execute_qa_tests(package_path)
|
|
|
|
if spm_rc == 0:
|
|
return True
|
|
sys.stderr.write("QA Error: " + spm_msg + "\n")
|
|
sys.stderr.flush()
|
|
return False
|
|
|
|
def get_tests(self):
|
|
return [self.__check_package_using_spm]
|
|
|
|
def get_id(self):
|
|
return SERVER_QA_PLUGIN
|
|
|
|
|
|
class Server(Singleton, TextInterface):
|
|
|
|
_memory_db_instances = {}
|
|
_treeupdates_repos = set()
|
|
|
|
def init_singleton(self, default_repository = None, save_repository = False,
|
|
community_repo = False, fake_default_repo = False,
|
|
fake_default_repo_id = '::fake::',
|
|
fake_default_repo_desc = 'this is a fake repository'):
|
|
|
|
self.__instance_destroyed = False
|
|
if etpConst['uid'] != 0:
|
|
mytxt = _("Entropy Server interface must be run as root")
|
|
import warnings
|
|
warnings.warn(mytxt)
|
|
|
|
# settings
|
|
self.__server_dbcache = {}
|
|
self.dbcache_load_metadata = {}
|
|
self.SystemSettings = SystemSettings()
|
|
self.community_repo = community_repo
|
|
from entropy.db import dbapi2
|
|
self.dbapi2 = dbapi2 # export for third parties
|
|
etpSys['serverside'] = True
|
|
self.fake_default_repo = fake_default_repo
|
|
self.indexing = False
|
|
self.xcache = False
|
|
self.MirrorsService = None
|
|
self.__settings_to_backup = []
|
|
self.__do_save_repository = save_repository
|
|
self.__sync_lock_cache = set()
|
|
self.rssMessages = {
|
|
'added': {},
|
|
'removed': {},
|
|
'commitmessage': "",
|
|
'light': {},
|
|
}
|
|
|
|
self.sys_settings_fatscope_plugin_id = \
|
|
etpConst['system_settings_plugins_ids']['server_plugin_fatscope']
|
|
self.sys_settings_plugin_id = \
|
|
etpConst['system_settings_plugins_ids']['server_plugin']
|
|
|
|
# create our SystemSettings plugin
|
|
self.sys_settings_plugin = ServerSystemSettingsPlugin(
|
|
self.sys_settings_plugin_id, self)
|
|
self.SystemSettings.add_plugin(self.sys_settings_plugin)
|
|
|
|
# Fatscope support SystemSettings plugin
|
|
self.sys_settings_fatscope_plugin = ServerFatscopeSystemSettingsPlugin(
|
|
self.sys_settings_fatscope_plugin_id, self)
|
|
self.SystemSettings.add_plugin(self.sys_settings_fatscope_plugin)
|
|
|
|
# setup fake repository
|
|
if fake_default_repo:
|
|
default_repository = fake_default_repo_id
|
|
self.init_generic_memory_server_repository(fake_default_repo_id,
|
|
fake_default_repo_desc, set_as_default = True)
|
|
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
self.default_repository = default_repository
|
|
if self.default_repository is None:
|
|
self.default_repository = srv_set['default_repository_id']
|
|
|
|
if self.default_repository in srv_set['repositories']:
|
|
self.ensure_paths(self.default_repository)
|
|
|
|
if self.default_repository not in srv_set['repositories']:
|
|
raise PermissionDenied("PermissionDenied: %s %s" % (
|
|
self.default_repository,
|
|
_("repository not configured"),
|
|
)
|
|
)
|
|
if etpConst['clientserverrepoid'] == self.default_repository:
|
|
raise PermissionDenied("PermissionDenied: %s %s" % (
|
|
etpConst['clientserverrepoid'],
|
|
_("protected repository id, can't use this, sorry dude..."),
|
|
)
|
|
)
|
|
|
|
self.switch_default_repository(self.default_repository)
|
|
|
|
def destroy(self):
|
|
self.__instance_destroyed = True
|
|
if hasattr(self, 'ClientService'):
|
|
self.ClientService.destroy()
|
|
if hasattr(self, 'sys_settings_server_plugin'):
|
|
try:
|
|
self.SystemSettings.remove_plugin(self.sys_settings_plugin_id)
|
|
except KeyError:
|
|
pass
|
|
if hasattr(self, 'sys_settings_fatscope_plugin'):
|
|
try:
|
|
self.SystemSettings.remove_plugin(
|
|
self.sys_settings_fatscope_plugin)
|
|
except KeyError:
|
|
pass
|
|
self.close_server_databases()
|
|
|
|
def is_destroyed(self):
|
|
return self.__instance_destroyed
|
|
|
|
def __del__(self):
|
|
self.destroy()
|
|
|
|
def ensure_paths(self, repo):
|
|
upload_dir = os.path.join(self.get_local_upload_directory(repo),
|
|
self.SystemSettings['repositories']['branch'])
|
|
db_dir = self.get_local_database_dir(repo)
|
|
for mydir in [upload_dir, db_dir]:
|
|
if (not os.path.isdir(mydir)) and (not os.path.lexists(mydir)):
|
|
os.makedirs(mydir)
|
|
const_setup_perms(mydir, etpConst['entropygid'])
|
|
|
|
def setup_services(self):
|
|
self.setup_entropy_settings()
|
|
cs_name = 'ClientService'
|
|
if hasattr(self, cs_name):
|
|
obj = getattr(self, cs_name)
|
|
# no need to close, remove, whatever QA plugins, it's automagically
|
|
# arranged
|
|
obj.destroy()
|
|
from entropy.client.interfaces import Client
|
|
self.ClientService = Client(
|
|
indexing = self.indexing,
|
|
xcache = self.xcache,
|
|
repo_validation = False,
|
|
noclientdb = 1
|
|
)
|
|
from entropy.cache import EntropyCacher
|
|
self.Cacher = EntropyCacher()
|
|
self.ClientService.updateProgress = self.updateProgress
|
|
self.validRepositories = self.ClientService.validRepositories
|
|
self.entropyTools = self.ClientService.entropyTools
|
|
self.dumpTools = self.ClientService.dumpTools
|
|
self.backup_entropy_settings()
|
|
|
|
self.MirrorsService = MirrorsServer(self)
|
|
|
|
def QA(self):
|
|
"""
|
|
Get Entropy QA Interface instance.
|
|
|
|
@return: Entropy QA Interface instance
|
|
@rtype: entropy.qa.QAInterface instance
|
|
"""
|
|
qa_plugin = ServerQAInterfacePlugin()
|
|
qa = self.ClientService.QA()
|
|
qa.add_plugin(qa_plugin)
|
|
return qa
|
|
|
|
def Spm(self):
|
|
"""
|
|
Get Source Package Manager interface instance.
|
|
|
|
@return: Source Package Manager interface instance
|
|
@rtype: entropy.spm.plugins.skel.SpmPlugin based instance
|
|
"""
|
|
return get_spm(self)
|
|
|
|
def Transceiver(self, uri):
|
|
"""
|
|
Get EntropyTransceiver interface instance.
|
|
|
|
@param uri: EntropyTransceiver URI
|
|
@type uri: string
|
|
@return: EntropyTransceiver instance
|
|
@rtype: entropy.transceivers.EntropyTransceiver
|
|
"""
|
|
txc = EntropyTransceiver(uri)
|
|
txc.set_output_interface(self)
|
|
return txc
|
|
|
|
def setup_entropy_settings(self, repo = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
backup_list = [
|
|
'etpdatabaseclientfilepath',
|
|
'clientdbid',
|
|
{'server': srv_set.copy()},
|
|
]
|
|
for setting in backup_list:
|
|
if setting not in self.__settings_to_backup:
|
|
self.__settings_to_backup.append(setting)
|
|
# setup client database
|
|
if not self.community_repo:
|
|
etpConst['etpdatabaseclientfilepath'] = \
|
|
self.get_local_database_file(repo)
|
|
etpConst['clientdbid'] = etpConst['serverdbid']
|
|
const_create_working_dirs()
|
|
|
|
def close_server_databases(self):
|
|
for item in self.__server_dbcache:
|
|
try:
|
|
self.__server_dbcache[item].closeDB()
|
|
except self.dbapi2.ProgrammingError: # already closed?
|
|
pass
|
|
self.__server_dbcache.clear()
|
|
|
|
def close_server_database(self, dbinstance):
|
|
found = None
|
|
for item in self.__server_dbcache:
|
|
if dbinstance == self.__server_dbcache[item]:
|
|
found = item
|
|
break
|
|
if found:
|
|
instance = self.__server_dbcache.pop(found)
|
|
instance.closeDB()
|
|
|
|
def get_available_repositories(self):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
return srv_set['repositories'].copy()
|
|
|
|
def switch_default_repository(self, repoid, save = None,
|
|
handle_uninitialized = True):
|
|
|
|
# avoid setting __default__ as default server repo
|
|
if repoid == etpConst['clientserverrepoid']:
|
|
return
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
|
|
if save is None:
|
|
save = self.__do_save_repository
|
|
if repoid not in srv_set['repositories']:
|
|
raise PermissionDenied("PermissionDenied: %s %s" % (
|
|
repoid,
|
|
_("repository not configured"),
|
|
)
|
|
)
|
|
self.close_server_databases()
|
|
srv_set['default_repository_id'] = repoid
|
|
self.default_repository = repoid
|
|
self.setup_services()
|
|
if save:
|
|
self.save_default_repository(repoid)
|
|
|
|
self.setup_community_repositories_settings()
|
|
self.show_interface_status()
|
|
if handle_uninitialized and etpUi['warn']:
|
|
self.handle_uninitialized_repository(repoid)
|
|
|
|
def setup_community_repositories_settings(self):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if self.community_repo:
|
|
for repoid in srv_set['repositories']:
|
|
srv_set['repositories'][repoid]['community'] = True
|
|
|
|
|
|
def handle_uninitialized_repository(self, repoid):
|
|
|
|
if not self.is_repository_initialized(repoid):
|
|
mytxt = blue("%s.") % (
|
|
_("Your default repository is not initialized"),)
|
|
self.updateProgress(
|
|
"[%s:%s] %s" % (
|
|
brown("repo"),
|
|
purple(repoid),
|
|
mytxt,
|
|
),
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" !!! ")
|
|
)
|
|
answer = self.askQuestion(
|
|
_("Do you want to initialize your default repository ?"))
|
|
if answer == _("No"):
|
|
mytxt = red("%s.") % (
|
|
_("Continuing with an uninitialized repository"),)
|
|
self.updateProgress(
|
|
"[%s:%s] %s" % (
|
|
brown("repo"),
|
|
purple(repoid),
|
|
mytxt,
|
|
),
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" !!! ")
|
|
)
|
|
else:
|
|
# move empty database for security sake
|
|
dbfile = self.get_local_database_file(repoid)
|
|
if os.path.isfile(dbfile):
|
|
shutil.move(dbfile, dbfile+".backup")
|
|
self.initialize_server_database(empty = True,
|
|
repo = repoid, warnings = False)
|
|
|
|
|
|
def show_interface_status(self):
|
|
type_txt = _("server-side repository")
|
|
if self.community_repo:
|
|
type_txt = _("community repository")
|
|
# ..on repository: <repository_name>
|
|
mytxt = _("Entropy Server Interface Instance on repository")
|
|
self.updateProgress(
|
|
blue("%s: %s, %s: %s (%s: %s)" % (
|
|
mytxt,
|
|
red(self.default_repository),
|
|
_("current branch"),
|
|
darkgreen(self.SystemSettings['repositories']['branch']),
|
|
purple(_("type")),
|
|
bold(type_txt),
|
|
)
|
|
),
|
|
importance = 2,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
repos = list(srv_set['repositories'].keys())
|
|
mytxt = blue("%s:") % (_("Currently configured repositories"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
for repo in repos:
|
|
self.updateProgress(
|
|
darkgreen(repo),
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
|
|
|
|
def save_default_repository(self, repoid):
|
|
|
|
# avoid setting __default__ as default server repo
|
|
if repoid == etpConst['clientserverrepoid']:
|
|
return
|
|
|
|
if os.path.isfile(etpConst['serverconf']):
|
|
f_srv = open(etpConst['serverconf'], "r")
|
|
content = f_srv.readlines()
|
|
f_srv.close()
|
|
content = [x.strip() for x in content]
|
|
found = False
|
|
new_content = []
|
|
for line in content:
|
|
if line.strip().startswith("default-repository|"):
|
|
line = "default-repository|%s" % (repoid,)
|
|
found = True
|
|
new_content.append(line)
|
|
if not found:
|
|
new_content.append("default-repository|%s" % (repoid,))
|
|
f_srv_t = open(etpConst['serverconf']+".save_default_repo_tmp", "w")
|
|
for line in new_content:
|
|
f_srv_t.write(line+"\n")
|
|
f_srv_t.flush()
|
|
f_srv_t.close()
|
|
os.rename(etpConst['serverconf']+".save_default_repo_tmp",
|
|
etpConst['serverconf'])
|
|
else:
|
|
f_srv = open(etpConst['serverconf'], "w")
|
|
f_srv.write("default-repository|%s\n" % (repoid,))
|
|
f_srv.flush()
|
|
f_srv.close()
|
|
|
|
def toggle_repository(self, repoid, enable = True):
|
|
|
|
# avoid setting __default__ as default server repo
|
|
if repoid == etpConst['clientserverrepoid']:
|
|
return False
|
|
|
|
if not os.path.isfile(etpConst['serverconf']):
|
|
return None
|
|
f_srv = open(etpConst['serverconf'])
|
|
tmpfile = etpConst['serverconf']+".switch"
|
|
mycontent = [x.strip() for x in f_srv.readlines()]
|
|
f_srv.close()
|
|
f_tmp = open(tmpfile, "w")
|
|
st = "repository|%s" % (repoid,)
|
|
status = False
|
|
for line in mycontent:
|
|
if enable:
|
|
if (line.find(st) != -1) and line.startswith("#") and \
|
|
(len(line.split("|")) == 5):
|
|
line = line[1:]
|
|
status = True
|
|
else:
|
|
if (line.find(st) != -1) and not line.startswith("#") and \
|
|
(len(line.split("|")) == 5):
|
|
line = "#"+line
|
|
status = True
|
|
f_tmp.write(line+"\n")
|
|
f_tmp.flush()
|
|
f_tmp.close()
|
|
shutil.move(tmpfile, etpConst['serverconf'])
|
|
if status:
|
|
self.close_server_databases()
|
|
self.SystemSettings.clear()
|
|
self.setup_services()
|
|
self.show_interface_status()
|
|
return status
|
|
|
|
def backup_entropy_settings(self):
|
|
for setting in self.__settings_to_backup:
|
|
if isinstance(setting, const_get_stringtype()):
|
|
self.ClientService.backup_constant(setting)
|
|
elif isinstance(setting, dict):
|
|
self.SystemSettings.set_persistent_setting(setting)
|
|
|
|
def is_repository_initialized(self, repo):
|
|
|
|
def do_validate(dbc):
|
|
try:
|
|
dbc.validateDatabase()
|
|
return True
|
|
except SystemDatabaseError:
|
|
return False
|
|
|
|
dbc = self.open_server_repository(just_reading = True, repo = repo)
|
|
valid = do_validate(dbc)
|
|
self.close_server_database(dbc)
|
|
if not valid: # check online?
|
|
dbc = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo, is_new = True)
|
|
valid = do_validate(dbc)
|
|
self.close_server_database(dbc)
|
|
|
|
return valid
|
|
|
|
def do_server_repository_sync_lock(self, repo, no_upload):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
# check if the database is locked locally
|
|
lock_file = self.MirrorsService.get_database_lockfile(repo)
|
|
if os.path.isfile(lock_file):
|
|
self.updateProgress(
|
|
red(_("Entropy database is already locked by you :-)")),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" * ")
|
|
)
|
|
else:
|
|
# check if the database is locked REMOTELY
|
|
mytxt = "%s ..." % (_("Locking and Syncing Entropy database"),)
|
|
self.updateProgress(
|
|
red(mytxt),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" * "),
|
|
back = True
|
|
)
|
|
for uri in self.get_remote_mirrors(repo):
|
|
|
|
crippled_uri = EntropyTransceiver.get_uri_name(uri)
|
|
|
|
given_up = self.MirrorsService.mirror_lock_check(uri,
|
|
repo = repo)
|
|
if given_up:
|
|
mytxt = "%s:" % (_("Mirrors status table"),)
|
|
self.updateProgress(
|
|
darkgreen(mytxt),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" * ")
|
|
)
|
|
dbstatus = self.MirrorsService.get_mirrors_lock(repo = repo)
|
|
for db_uri, db_st1, db_st2 in dbstatus:
|
|
db_st1_info = darkgreen(_("Unlocked"))
|
|
if db_st1:
|
|
db_st1_info = red(_("Locked"))
|
|
db_st2_info = darkgreen(_("Unlocked"))
|
|
if db_st2:
|
|
db_st2_info = red(_("Locked"))
|
|
|
|
crippled_uri = EntropyTransceiver.get_uri_name(db_uri)
|
|
self.updateProgress(
|
|
"%s: [%s: %s] [%s: %s]" % (
|
|
bold(crippled_uri),
|
|
brown(_("database")),
|
|
db_st1_info,
|
|
brown(_("download")),
|
|
db_st2_info,
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = "\t"
|
|
)
|
|
|
|
raise OnlineMirrorError("OnlineMirrorError: %s %s" % (
|
|
_("cannot lock mirror"),
|
|
crippled_uri,
|
|
)
|
|
)
|
|
|
|
# if we arrive here, it is because all the mirrors are unlocked
|
|
self.MirrorsService.lock_mirrors(True, repo = repo)
|
|
self.MirrorsService.sync_databases(no_upload, repo = repo)
|
|
|
|
|
|
def init_generic_memory_server_repository(self, repoid, description,
|
|
mirrors = None, community_repo = False, service_url = None,
|
|
set_as_default = False):
|
|
|
|
if mirrors is None:
|
|
mirrors = []
|
|
dbc = self._open_memory_database(repoid)
|
|
Server._memory_db_instances[repoid] = dbc
|
|
|
|
eapi3_port = int(etpConst['socket_service']['port'])
|
|
eapi3_ssl_port = int(etpConst['socket_service']['ssl_port'])
|
|
# add to settings
|
|
repodata = {
|
|
'repoid': repoid,
|
|
'description': description,
|
|
'mirrors': mirrors,
|
|
'community': community_repo,
|
|
'service_port': eapi3_port,
|
|
'ssl_service_port': eapi3_ssl_port,
|
|
'service_url': service_url,
|
|
'handler': '', # not supported
|
|
'in_memory': True,
|
|
}
|
|
|
|
etpConst['server_repositories'][repoid] = repodata
|
|
if set_as_default:
|
|
etpConst['defaultserverrepositoryid'] = repoid
|
|
sys_set = SystemSettings()
|
|
sys_set.clear()
|
|
|
|
etp_repo_meta = {
|
|
'lock_remote': False,
|
|
'no_upload': True,
|
|
'use_branch': None,
|
|
'output_interface': self,
|
|
}
|
|
srv_plug = ServerEntropyRepositoryPlugin(self, metadata = etp_repo_meta)
|
|
dbc.add_plugin(srv_plug)
|
|
return dbc
|
|
|
|
def _open_memory_database(self, repo):
|
|
"""
|
|
Open in-memory EntropyRepository interface.
|
|
|
|
@keyword dbname: database name
|
|
@type dbname: string
|
|
@keyword output_interface: entropy.output.TextInterface based instance
|
|
@type output_interface: entropy.output.TextInterface based instance
|
|
"""
|
|
conn = EntropyRepository(
|
|
readOnly = False,
|
|
dbFile = ':memory:',
|
|
dbname = repo,
|
|
xcache = False,
|
|
indexing = False,
|
|
skipChecks = True
|
|
)
|
|
conn.initializeDatabase()
|
|
return conn
|
|
|
|
|
|
def open_server_repository(
|
|
self,
|
|
read_only = True,
|
|
no_upload = True,
|
|
just_reading = False,
|
|
repo = None,
|
|
indexing = True,
|
|
warnings = True,
|
|
do_cache = True,
|
|
use_branch = None,
|
|
lock_remote = True,
|
|
is_new = False,
|
|
do_treeupdates = True
|
|
):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
if repo == etpConst['clientserverrepoid'] and self.community_repo:
|
|
return self.ClientService.clientDbconn
|
|
|
|
# in-memory server repos
|
|
if repo in Server._memory_db_instances:
|
|
return Server._memory_db_instances.get(repo)
|
|
|
|
if just_reading:
|
|
read_only = True
|
|
no_upload = True
|
|
|
|
local_dbfile = self.get_local_database_file(repo, use_branch)
|
|
if do_cache:
|
|
cached = self.__server_dbcache.get(
|
|
(repo, etpConst['systemroot'], local_dbfile, read_only,
|
|
no_upload, just_reading, use_branch, lock_remote,)
|
|
)
|
|
if cached != None:
|
|
return cached
|
|
|
|
local_dbfile_dir = os.path.dirname(local_dbfile)
|
|
if not os.path.isdir(local_dbfile_dir):
|
|
os.makedirs(local_dbfile_dir)
|
|
|
|
if (not read_only) and (lock_remote) and \
|
|
(repo not in self.__sync_lock_cache):
|
|
self.do_server_repository_sync_lock(repo, no_upload)
|
|
self.__sync_lock_cache.add(repo)
|
|
|
|
local_dbfile_exists = os.path.lexists(local_dbfile)
|
|
conn = EntropyRepository(
|
|
readOnly = read_only,
|
|
dbFile = local_dbfile,
|
|
dbname = repo,
|
|
xcache = False # always set to False, if you want to enable
|
|
# you need to make sure that client-side and server-side caches
|
|
# don't collide due to sharing EntropyRepository.dbname
|
|
)
|
|
etp_repo_meta = {
|
|
'lock_remote': lock_remote,
|
|
'no_upload': no_upload,
|
|
'use_branch': use_branch,
|
|
'output_interface': self,
|
|
}
|
|
srv_plug = ServerEntropyRepositoryPlugin(self, metadata = etp_repo_meta)
|
|
conn.add_plugin(srv_plug)
|
|
"""
|
|
FIXME: remove this once we have a pluggable EntropyRepository class
|
|
Setup server repository status information for newly created repos.
|
|
NOTE: This is a temp. workaround waiting for real pluggable
|
|
EntropyRepository interface calls.
|
|
"""
|
|
taint_file = self.get_local_database_taint_file(repo)
|
|
if os.path.isfile(taint_file):
|
|
dbs = ServerRepositoryStatus()
|
|
dbs.set_tainted(local_dbfile)
|
|
dbs.set_bumped(local_dbfile)
|
|
|
|
if not local_dbfile_exists:
|
|
# better than having a completely broken db
|
|
conn.readOnly = False
|
|
conn.initializeDatabase()
|
|
conn.commitChanges()
|
|
|
|
valid = True
|
|
try:
|
|
conn.validateDatabase()
|
|
except SystemDatabaseError:
|
|
valid = False
|
|
|
|
# verify if we need to update the database to sync
|
|
# with portage updates, we just ignore being readonly in the case
|
|
if (repo not in Server._treeupdates_repos) and \
|
|
(not just_reading):
|
|
# sometimes, when filling a new server db
|
|
# we need to avoid tree updates
|
|
if valid:
|
|
if do_treeupdates:
|
|
self.repository_packages_spm_sync(conn,
|
|
branch = use_branch, repo = repo)
|
|
elif warnings and not is_new:
|
|
mytxt = _("Entropy database is corrupted!")
|
|
self.updateProgress(
|
|
darkred(mytxt),
|
|
importance = 1,
|
|
type = "warning",
|
|
header = bold(" !!! ")
|
|
)
|
|
|
|
if not read_only and valid and indexing:
|
|
|
|
self.updateProgress(
|
|
"[repo:%s|%s] %s" % (
|
|
blue(repo),
|
|
red(_("database")),
|
|
blue(_("indexing database")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" @@ ")
|
|
)
|
|
conn.createAllIndexes()
|
|
|
|
if do_cache:
|
|
# !!! also cache just_reading otherwise there will be
|
|
# real issues if the connection is opened several times
|
|
self.__server_dbcache[
|
|
(repo, etpConst['systemroot'], local_dbfile, read_only,
|
|
no_upload, just_reading, use_branch, lock_remote,)] = conn
|
|
|
|
# auto-update package sets
|
|
if (not read_only) and (not is_new):
|
|
cur_sets = conn.retrievePackageSets()
|
|
sys_sets = self.get_configured_package_sets(repo)
|
|
if cur_sets != sys_sets:
|
|
self.update_database_package_sets(repo, dbconn = conn)
|
|
conn.commitChanges()
|
|
|
|
return conn
|
|
|
|
def repository_packages_spm_sync(self, repo_db, branch = None, repo = None):
|
|
"""
|
|
Service method used to sync package names with Source Package Manager.
|
|
Source Package Manager can change package names, categories or slot
|
|
and Entropy repositories must be kept in sync.
|
|
"""
|
|
if branch is None:
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
Server._treeupdates_repos.add(repo)
|
|
self.Spm().package_names_update(repo_db, repo, self, branch)
|
|
|
|
def deps_tester(self, default_repo = None):
|
|
|
|
sys_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
server_repos = list(sys_set['repositories'].keys())
|
|
installed_packages = set()
|
|
# if a default repository is passed, we will just test against it
|
|
if default_repo:
|
|
server_repos = [default_repo]
|
|
|
|
for repo in server_repos:
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo, do_treeupdates = False)
|
|
installed_packages |= set([(x, repo) for x in \
|
|
dbconn.listAllIdpackages()])
|
|
|
|
|
|
deps_not_satisfied = set()
|
|
length = str((len(installed_packages)))
|
|
count = 0
|
|
mytxt = _("Checking")
|
|
|
|
for idpackage, repo in installed_packages:
|
|
count += 1
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo, do_treeupdates = False)
|
|
|
|
if (count%150 == 0) or (count == length) or (count == 1):
|
|
atom = dbconn.retrieveAtom(idpackage)
|
|
self.updateProgress(
|
|
darkgreen(mytxt)+" "+bold(atom),
|
|
importance = 0,
|
|
type = "info",
|
|
back = True,
|
|
count = (count, length),
|
|
header = darkred(" @@ ")
|
|
)
|
|
|
|
xdeps = dbconn.retrieveDependencies(idpackage)
|
|
for xdep in xdeps:
|
|
xid, xuseless = self.atom_match(xdep)
|
|
if xid == -1:
|
|
deps_not_satisfied.add(xdep)
|
|
|
|
return deps_not_satisfied
|
|
|
|
def dependencies_test(self, repo = None):
|
|
|
|
mytxt = "%s %s" % (blue(_("Running dependencies test")), red("..."))
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 2,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
server_repos = list(srv_set['repositories'].keys())
|
|
deps_not_matched = self.deps_tester(repo)
|
|
|
|
if deps_not_matched:
|
|
|
|
crying_atoms = {}
|
|
for atom in deps_not_matched:
|
|
for repo in server_repos:
|
|
dbconn = self.open_server_repository(just_reading = True,
|
|
repo = repo, do_treeupdates = False)
|
|
riddep = dbconn.searchDependency(atom)
|
|
if riddep == -1:
|
|
continue
|
|
ridpackages = dbconn.searchIdpackageFromIddependency(riddep)
|
|
for i in ridpackages:
|
|
iatom = dbconn.retrieveAtom(i)
|
|
if atom not in crying_atoms:
|
|
crying_atoms[atom] = set()
|
|
crying_atoms[atom].add((iatom, repo))
|
|
|
|
mytxt = blue("%s:") % (_("These are the dependencies not found"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
mytxt = "%s:" % (_("Needed by"),)
|
|
for atom in deps_not_matched:
|
|
self.updateProgress(
|
|
red(atom),
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" # ")
|
|
)
|
|
if atom in crying_atoms:
|
|
self.updateProgress(
|
|
red(mytxt),
|
|
importance = 0,
|
|
type = "info",
|
|
header = blue(" # ")
|
|
)
|
|
for my_dep, myrepo in crying_atoms[atom]:
|
|
self.updateProgress(
|
|
"[%s:%s] %s" % (
|
|
blue(_("by repo")),
|
|
darkred(myrepo),
|
|
darkgreen(my_dep),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = blue(" # ")
|
|
)
|
|
else:
|
|
|
|
mytxt = blue(_("Every dependency is satisfied. It's all fine."))
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 2,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
return deps_not_matched
|
|
|
|
def test_shared_objects(self, get_files = False, repo = None,
|
|
dump_results_to_file = False):
|
|
|
|
pkg_list_path = None
|
|
if dump_results_to_file:
|
|
tmp_dir = os.path.dirname(self.entropyTools.get_random_temp_file())
|
|
pkg_list_path = os.path.join(tmp_dir, "libtest_broken.txt")
|
|
dmp_data = [
|
|
(_("Broken and matched packages list"), pkg_list_path,),
|
|
]
|
|
mytxt = "%s:" % (purple(_("Dumping results into these files")),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" @@ ")
|
|
)
|
|
for txt, path in dmp_data:
|
|
mytxt = "%s: %s" % (blue(txt), path,)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 0,
|
|
type = "info",
|
|
header = darkgreen(" ## ")
|
|
)
|
|
|
|
|
|
# load db
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo)
|
|
QA = self.QA()
|
|
packages_matched, brokenexecs, status = QA.test_shared_objects(dbconn,
|
|
broken_symbols = True, dump_results_to_file = dump_results_to_file)
|
|
if status != 0:
|
|
return 1, None
|
|
|
|
if get_files:
|
|
return 0, brokenexecs
|
|
|
|
if (not brokenexecs) and (not packages_matched):
|
|
mytxt = "%s." % (_("System is healthy"),)
|
|
self.updateProgress(
|
|
blue(mytxt),
|
|
importance = 2,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
return 0, None
|
|
|
|
mytxt = "%s..." % (_("Matching libraries with Spm, please wait"),)
|
|
self.updateProgress(
|
|
blue(mytxt),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
packages = self.Spm().search_paths_owners(brokenexecs)
|
|
|
|
if packages:
|
|
mytxt = "%s:" % (_("These are the matched packages"),)
|
|
self.updateProgress(
|
|
red(mytxt),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
for my_atom, my_elf_id in packages:
|
|
package_slot = my_atom, my_elf_id
|
|
self.updateProgress(
|
|
"%s [elf:%s]" % (
|
|
purple(my_atom),
|
|
darkgreen(str(my_elf_id)),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = red(" # ")
|
|
)
|
|
for filename in sorted(packages[package_slot]):
|
|
self.updateProgress(
|
|
darkgreen(filename),
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" => ")
|
|
)
|
|
|
|
pkgstring_list = sorted(["%s:%s" % (
|
|
self.entropyTools.dep_getkey(x[0]), x[1],) for x \
|
|
in sorted(packages)])
|
|
if pkg_list_path is not None:
|
|
with open(pkg_list_path, "w") as pkg_f:
|
|
for pkgstr in pkgstring_list:
|
|
pkg_f.write(pkgstr + "\n")
|
|
pkg_f.flush()
|
|
pkgstring = ' '.join(pkgstring_list)
|
|
mytxt = "%s: %s" % (darkgreen(_("Packages string")), pkgstring,)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
else:
|
|
self.updateProgress(
|
|
red(_("No matched packages")),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
return 0, packages
|
|
|
|
def orphaned_spm_packages_test(self):
|
|
|
|
mytxt = "%s %s" % (
|
|
blue(_("Running orphaned SPM packages test")), red("..."),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 2,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
installed_packages = self.Spm().get_installed_packages()
|
|
length = len(installed_packages)
|
|
not_found = {}
|
|
count = 0
|
|
for installed_package in installed_packages:
|
|
count += 1
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
darkgreen(_("Scanning package")),
|
|
brown(installed_package),),
|
|
importance = 0,
|
|
type = "info",
|
|
back = True,
|
|
count = (count, length),
|
|
header = darkred(" @@ ")
|
|
)
|
|
key, slot = (self.entropyTools.dep_getkey(installed_package),
|
|
self.Spm().get_installed_package_metadata(installed_package,
|
|
"SLOT"),)
|
|
pkg_atom = "%s:%s" % (key, slot,)
|
|
tree_atom = self.Spm().match_package(pkg_atom)
|
|
if not tree_atom:
|
|
not_found[installed_package] = pkg_atom
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
blue(pkg_atom),
|
|
darkred(_("not found anymore")),
|
|
),
|
|
importance = 0,
|
|
type = "warning",
|
|
count = (count, length),
|
|
header = darkred(" @@ ")
|
|
)
|
|
|
|
if not_found:
|
|
not_found_list = ' '.join([not_found[x] for x in sorted(not_found)])
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
blue(_("Packages string")),
|
|
not_found_list,
|
|
),
|
|
importance = 0,
|
|
type = "warning",
|
|
count = (count, length),
|
|
header = darkred(" @@ ")
|
|
)
|
|
|
|
return not_found
|
|
|
|
def depends_table_initialize(self, repo = None):
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
dbconn.generateReverseDependenciesMetadata()
|
|
self.taint_database(repo = repo)
|
|
dbconn.commitChanges()
|
|
|
|
def create_empty_database(self, dbpath = None, repo = None):
|
|
if dbpath is None:
|
|
dbpath = self.get_local_database_file(repo)
|
|
|
|
dbdir = os.path.dirname(dbpath)
|
|
if not os.path.isdir(dbdir):
|
|
os.makedirs(dbdir)
|
|
|
|
mytxt = red("%s ...") % (_("Initializing an empty database"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" * "),
|
|
back = True
|
|
)
|
|
dbconn = self.ClientService.open_generic_database(dbpath)
|
|
dbconn.initializeDatabase()
|
|
dbconn.commitChanges()
|
|
dbconn.closeDB()
|
|
mytxt = "%s %s %s." % (
|
|
red(_("Entropy database file")),
|
|
bold(dbpath),
|
|
red(_("successfully initialized")),
|
|
)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" * ")
|
|
)
|
|
|
|
def tag_packages(self, package_tag, idpackages, repo = None, ask = True):
|
|
|
|
# check package_tag "no spaces"
|
|
|
|
try:
|
|
package_tag = str(package_tag)
|
|
if " " in package_tag:
|
|
raise ValueError
|
|
except (UnicodeDecodeError, UnicodeEncodeError, ValueError,):
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
blue(_("Invalid tag specified")),
|
|
package_tag,
|
|
),
|
|
importance = 1, type = "error", header = darkred(" !! ")
|
|
)
|
|
return 1, package_tag
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
# sanity check
|
|
invalid_atoms = []
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo)
|
|
for idpackage in idpackages:
|
|
ver_tag = dbconn.retrieveVersionTag(idpackage)
|
|
if ver_tag:
|
|
invalid_atoms.append(dbconn.retrieveAtom(idpackage))
|
|
|
|
if invalid_atoms:
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
blue(_("Packages already tagged, action aborted")),
|
|
', '.join([darkred(str(x)) for x in invalid_atoms]),
|
|
),
|
|
importance = 1, type = "error", header = darkred(" !! ")
|
|
)
|
|
return 2, invalid_atoms
|
|
|
|
matches = [(x, repo) for x in idpackages]
|
|
status = 0
|
|
data = self.move_packages(
|
|
matches, to_repo = repo, from_repo = repo, ask = ask,
|
|
do_copy = True, new_tag = package_tag
|
|
)
|
|
return status, data
|
|
|
|
def flushback_packages(self, from_branches, repo = None, ask = True):
|
|
"""
|
|
When creating a new branch, for space reasons, packages are not
|
|
moved to a new location. This works fine until old branch is removed.
|
|
To avoid inconsistences, before deciding to do that, all the packages
|
|
in the old branch should be flushed back to the the currently configured
|
|
branch.
|
|
|
|
@param from_branches -- list of branches to move packages from
|
|
@type from_branches -- list
|
|
@param repo -- repository to work on
|
|
@type repo -- str
|
|
@param ask -- user interactivity
|
|
@type ask -- bool
|
|
|
|
@return status
|
|
"""
|
|
|
|
status = True
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
|
|
if branch in from_branches:
|
|
from_branches = [x for x in from_branches if x != branch]
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s" % (
|
|
darkgreen(', '.join(from_branches)),
|
|
darkred(branch),
|
|
brown(repo),
|
|
blue(_("flushing back selected packages from branches")),
|
|
),
|
|
importance = 2,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo)
|
|
|
|
idpackage_map = dict(((x, [],) for x in from_branches))
|
|
idpackages = dbconn.listAllIdpackages(order_by = 'atom')
|
|
for idpackage in idpackages:
|
|
download_url = dbconn.retrieveDownloadURL(idpackage)
|
|
url_br = self.ClientService.get_branch_from_download_relative_uri(
|
|
download_url)
|
|
if url_br in from_branches:
|
|
idpackage_map[url_br].append(idpackage)
|
|
|
|
mapped_branches = [x for x in idpackage_map if idpackage_map[x]]
|
|
if not mapped_branches:
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s !" % (
|
|
darkgreen(', '.join(from_branches)),
|
|
darkred(branch),
|
|
brown(repo),
|
|
blue(_("nothing to do")),
|
|
),
|
|
importance = 0,
|
|
type = "warning",
|
|
header = blue(" @@ ")
|
|
)
|
|
return status
|
|
|
|
|
|
all_fine = True
|
|
tmp_down_dir = self.entropyTools.get_random_temp_file()
|
|
os.makedirs(tmp_down_dir)
|
|
|
|
download_queue = {}
|
|
local_up_dir = self.get_local_upload_directory(repo)
|
|
local_basedir = os.path.join(local_up_dir, branch)
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
|
|
def generate_queue(branch, repo, from_branch, down_q, idpackage_map):
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
brown(_("these are the packages that will be flushed")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" @@ ")
|
|
)
|
|
|
|
|
|
for idpackage in idpackage_map[from_branch]:
|
|
atom = dbconn.retrieveAtom(idpackage)
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
purple(atom),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = blue(" # ")
|
|
)
|
|
pkg_fp = os.path.basename(dbconn.retrieveDownloadURL(idpackage))
|
|
pkg_fp = os.path.join(tmp_down_dir, pkg_fp)
|
|
down_q.append((pkg_fp, idpackage,))
|
|
|
|
|
|
for from_branch in sorted(mapped_branches):
|
|
|
|
download_queue[from_branch] = []
|
|
all_fine = False
|
|
generate_queue(branch, repo, from_branch,
|
|
download_queue[from_branch], idpackage_map)
|
|
|
|
if ask:
|
|
rc_question = self.askQuestion(
|
|
_("Would you like to continue ?"))
|
|
if rc_question == _("No"):
|
|
continue
|
|
|
|
remote_relative_path = self.get_remote_packages_relative_path(repo)
|
|
|
|
for uri in self.get_remote_mirrors(repo):
|
|
|
|
crippled_uri = EntropyTransceiver.get_uri_name(uri)
|
|
basedir = os.path.join(remote_relative_path, from_branch)
|
|
|
|
downloader_queue = [x[0] for x in download_queue[from_branch]]
|
|
downloader = self.MirrorsService.TransceiverServerHandler(
|
|
self,
|
|
[uri],
|
|
downloader_queue,
|
|
critical_files = downloader_queue,
|
|
txc_basedir = basedir,
|
|
local_basedir = tmp_down_dir,
|
|
download = True,
|
|
repo = repo
|
|
)
|
|
|
|
errors, m_fine_uris, m_broken_uris = downloader.go()
|
|
|
|
if not errors:
|
|
for downloaded_path, idpackage in \
|
|
download_queue[from_branch]:
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s|%s] %s: %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
dbconn.retrieveAtom(idpackage),
|
|
blue(_("checking package hash")),
|
|
darkgreen(os.path.basename(downloaded_path)),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" "),
|
|
back = True
|
|
)
|
|
|
|
md5hash = self.entropyTools.md5sum(downloaded_path)
|
|
db_md5hash = dbconn.retrieveDigest(idpackage)
|
|
if md5hash != db_md5hash:
|
|
errors = True
|
|
self.updateProgress(
|
|
"[%s=>%s|%s|%s] %s: %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
dbconn.retrieveAtom(idpackage),
|
|
blue(_("hash does not match for")),
|
|
darkgreen(os.path.basename(downloaded_path)),
|
|
),
|
|
importance = 0,
|
|
type = "error",
|
|
header = brown(" ")
|
|
)
|
|
continue
|
|
|
|
|
|
|
|
if errors:
|
|
reason = _("wrong md5")
|
|
if m_broken_uris:
|
|
my_broken_uris = [
|
|
(EntropyTransceiver.get_uri_name(x), y,) \
|
|
for x, y in m_broken_uris]
|
|
reason = my_broken_uris[0][1]
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s, %s: %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
blue(_("download errors")),
|
|
blue(_("reason")),
|
|
reason,
|
|
),
|
|
importance = 1,
|
|
type = "error",
|
|
header = darkred(" !!! ")
|
|
)
|
|
# continuing if possible
|
|
continue
|
|
|
|
all_fine = True
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
blue(_("download completed successfully")),
|
|
darkgreen(crippled_uri),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" * ")
|
|
)
|
|
|
|
if not all_fine:
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s" % (
|
|
darkgreen(', '.join(from_branches)),
|
|
darkred(branch),
|
|
brown(repo),
|
|
blue(_("error downloading packages from mirrors")),
|
|
),
|
|
importance = 2,
|
|
type = "error",
|
|
header = darkred(" !!! ")
|
|
)
|
|
return False
|
|
|
|
for from_branch in sorted(mapped_branches):
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
blue(_("working on branch")),
|
|
darkgreen(from_branch),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" @@ ")
|
|
)
|
|
|
|
down_queue = download_queue[from_branch]
|
|
for package_path, idpackage in down_queue:
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
blue(_("updating package")),
|
|
darkgreen(os.path.basename(package_path)),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" "),
|
|
back = True
|
|
)
|
|
|
|
# move files to upload
|
|
package_name = os.path.basename(package_path)
|
|
new_package_path = os.path.join(local_basedir, package_name)
|
|
try:
|
|
os.rename(package_path, new_package_path)
|
|
except OSError:
|
|
shutil.move(package_path, new_package_path)
|
|
|
|
# create md5 checksum
|
|
self.entropyTools.create_md5_file(new_package_path)
|
|
|
|
# update database
|
|
download_url = dbconn.retrieveDownloadURL(idpackage)
|
|
download_url = \
|
|
self.ClientService.swap_branch_in_download_relative_uri(
|
|
branch, download_url)
|
|
dbconn.setDownloadURL(idpackage, download_url)
|
|
dbconn.switchBranch(idpackage, branch)
|
|
dbconn.commitChanges()
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(from_branch),
|
|
darkred(branch),
|
|
brown(repo),
|
|
blue(_("package flushed")),
|
|
darkgreen(os.path.basename(package_path)),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" ")
|
|
)
|
|
|
|
try:
|
|
os.rmdir(tmp_down_dir)
|
|
except OSError:
|
|
pass
|
|
|
|
return True
|
|
|
|
def move_packages(self, matches, to_repo, from_repo = None, ask = True,
|
|
do_copy = False, new_tag = None, pull_deps = False):
|
|
|
|
if from_repo is None:
|
|
from_repo = self.default_repository
|
|
switched = set()
|
|
|
|
my_matches = list(matches)
|
|
|
|
# avoid setting __default__ as default server repo
|
|
if etpConst['clientserverrepoid'] in (to_repo, from_repo):
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
blue(_("Cannot touch system database")),
|
|
red(etpConst['clientserverrepoid']),
|
|
),
|
|
importance = 2, type = "warning", header = darkred(" @@ ")
|
|
)
|
|
return switched
|
|
|
|
if not my_matches and from_repo:
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = from_repo)
|
|
my_matches = set( \
|
|
[(x, from_repo) for x in \
|
|
dbconn.listAllIdpackages()]
|
|
)
|
|
|
|
mytxt = _("Preparing to move selected packages to")
|
|
if do_copy:
|
|
mytxt = _("Preparing to copy selected packages to")
|
|
self.updateProgress(
|
|
"%s %s:" % (
|
|
blue(mytxt),
|
|
red(to_repo),
|
|
),
|
|
importance = 2,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
bold(_("Note")),
|
|
red(_("all old packages with conflicting scope will be " \
|
|
"removed from destination repo unless injected")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
new_tag_string = ''
|
|
if new_tag != None:
|
|
new_tag_string = "[%s: %s]" % (darkgreen(_("new tag")),
|
|
brown(new_tag),)
|
|
|
|
my_qa = self.QA()
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
pull_deps_matches = []
|
|
for idpackage, repo in my_matches:
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo)
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s " % (
|
|
darkgreen(repo),
|
|
darkred(to_repo),
|
|
brown(branch),
|
|
blue(dbconn.retrieveAtom(idpackage)),
|
|
) + new_tag_string,
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
# do we want to pull in also package dependencies?
|
|
if pull_deps:
|
|
dep_idpackages = my_qa.get_deep_dependency_list(dbconn,
|
|
idpackage)
|
|
for dep_idpackage in dep_idpackages:
|
|
|
|
my_dep_match = (dep_idpackage, repo,)
|
|
if my_dep_match in pull_deps_matches:
|
|
continue
|
|
if my_dep_match in my_matches:
|
|
continue
|
|
|
|
pull_deps_matches.append(my_dep_match)
|
|
self.updateProgress(
|
|
"[%s|%s] %s" % (
|
|
brown(branch),
|
|
blue(_("dependency")),
|
|
purple(dbconn.retrieveAtom(dep_idpackage)),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = purple(" >> ")
|
|
)
|
|
|
|
if pull_deps:
|
|
# put deps first!
|
|
my_matches = pull_deps_matches + [x for x in my_matches if x not \
|
|
in pull_deps_matches]
|
|
|
|
if ask:
|
|
rc_question = self.askQuestion(_("Would you like to continue ?"))
|
|
if rc_question == _("No"):
|
|
return switched
|
|
|
|
for idpackage, repo in my_matches:
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
match_branch = dbconn.retrieveBranch(idpackage)
|
|
match_atom = dbconn.retrieveAtom(idpackage)
|
|
package_filename = os.path.basename(
|
|
dbconn.retrieveDownloadURL(idpackage))
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
darkred(to_repo),
|
|
brown(branch),
|
|
blue(_("switching")),
|
|
darkgreen(match_atom),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = red(" @@ "),
|
|
back = True
|
|
)
|
|
# move binary file
|
|
from_file = os.path.join(self.get_local_packages_directory(repo),
|
|
match_branch, package_filename)
|
|
if not os.path.isfile(from_file):
|
|
from_file = os.path.join(self.get_local_upload_directory(repo),
|
|
match_branch, package_filename)
|
|
if not os.path.isfile(from_file):
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s -> %s" % (
|
|
darkgreen(repo),
|
|
darkred(to_repo),
|
|
brown(branch),
|
|
bold(_("cannot switch, package not found, skipping")),
|
|
darkgreen(match_atom),
|
|
red(from_file),
|
|
),
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" !!! ")
|
|
)
|
|
continue
|
|
|
|
if new_tag != None:
|
|
match_category = dbconn.retrieveCategory(idpackage)
|
|
match_name = dbconn.retrieveName(idpackage)
|
|
match_version = dbconn.retrieveVersion(idpackage)
|
|
tagged_package_filename = \
|
|
self.entropyTools.create_package_filename(
|
|
match_category, match_name, match_version, new_tag)
|
|
to_file = os.path.join(self.get_local_upload_directory(to_repo),
|
|
match_branch, tagged_package_filename)
|
|
else:
|
|
to_file = os.path.join(self.get_local_upload_directory(to_repo),
|
|
match_branch, package_filename)
|
|
if not os.path.isdir(os.path.dirname(to_file)):
|
|
os.makedirs(os.path.dirname(to_file))
|
|
|
|
copy_data = [
|
|
(from_file, to_file,),
|
|
(from_file + etpConst['packagesmd5fileext'],
|
|
to_file + etpConst['packagesmd5fileext'],),
|
|
(from_file + etpConst['packagesexpirationfileext'],
|
|
to_file + etpConst['packagesexpirationfileext'],)
|
|
]
|
|
|
|
for from_item, to_item in copy_data:
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
darkred(to_repo),
|
|
brown(branch),
|
|
blue(_("moving file")),
|
|
darkgreen(os.path.basename(from_item)),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = red(" @@ "),
|
|
back = True
|
|
)
|
|
if os.path.isfile(from_item):
|
|
shutil.copy2(from_item, to_item)
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
darkred(to_repo),
|
|
brown(branch),
|
|
blue(_("loading data from source database")),
|
|
darkgreen(repo),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = red(" @@ "),
|
|
back = True
|
|
)
|
|
# install package into destination db
|
|
data = dbconn.getPackageData(idpackage)
|
|
if new_tag != None:
|
|
data['versiontag'] = new_tag
|
|
|
|
todbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = to_repo)
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
darkred(to_repo),
|
|
brown(branch),
|
|
blue(_("injecting data to destination database")),
|
|
darkgreen(to_repo),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = red(" @@ "),
|
|
back = True
|
|
)
|
|
new_idpackage, new_revision, new_data = todbconn.handlePackage(data)
|
|
del data
|
|
todbconn.commitChanges()
|
|
|
|
if not do_copy:
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
darkred(to_repo),
|
|
brown(branch),
|
|
blue(_("removing entry from source database")),
|
|
darkgreen(repo),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = red(" @@ "),
|
|
back = True
|
|
)
|
|
|
|
# remove package from old db
|
|
dbconn.removePackage(idpackage)
|
|
dbconn.commitChanges()
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
darkred(to_repo),
|
|
brown(branch),
|
|
blue(_("successfully handled atom")),
|
|
darkgreen(match_atom),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = blue(" @@ ")
|
|
)
|
|
switched.add((idpackage, repo,))
|
|
|
|
# just run this to make dev aware
|
|
self.dependencies_test(to_repo)
|
|
|
|
return switched
|
|
|
|
|
|
def package_injector(self, package_file, inject = False, repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
upload_dir = os.path.join(self.get_local_upload_directory(repo),
|
|
self.SystemSettings['repositories']['branch'])
|
|
if not os.path.isdir(upload_dir):
|
|
os.makedirs(upload_dir)
|
|
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
self.updateProgress(
|
|
red("[repo: %s] %s: %s" % (
|
|
darkgreen(repo),
|
|
_("adding package"),
|
|
bold(os.path.basename(package_file)),
|
|
)
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" * "),
|
|
back = True
|
|
)
|
|
mydata = self.Spm().extract_package_metadata(package_file)
|
|
mydata['injected'] = inject
|
|
idpackage, revision, mydata = dbconn.handlePackage(mydata)
|
|
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
myserver_repos = list(srv_set['repositories'].keys())
|
|
|
|
### since we are handling more repositories, we need to make sure
|
|
### that there are no packages in other repositories with same atom
|
|
### and greater revision
|
|
rev_test_atom = mydata['atom']
|
|
max_rev = -1
|
|
for myrepo in myserver_repos:
|
|
|
|
# not myself
|
|
if myrepo == repo:
|
|
continue
|
|
|
|
mydbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = myrepo)
|
|
|
|
myrepo_idpackages = mydbconn.getIDPackages(rev_test_atom)
|
|
for myrepo_idpackage in myrepo_idpackages:
|
|
myrev = mydbconn.retrieveRevision(myrepo_idpackage)
|
|
if myrev > max_rev:
|
|
max_rev = myrev
|
|
|
|
if max_rev >= revision:
|
|
max_rev += 1
|
|
revision = max_rev
|
|
mydata['revision'] = revision
|
|
# update revision for pkg now
|
|
dbconn.setRevision(idpackage, revision)
|
|
|
|
|
|
# set trashed counters
|
|
trashing_counters = set()
|
|
|
|
for myrepo in myserver_repos:
|
|
mydbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = myrepo)
|
|
mylist = mydbconn.retrieve_packages_to_remove(
|
|
mydata['name'],
|
|
mydata['category'],
|
|
mydata['slot'],
|
|
mydata['injected']
|
|
)
|
|
for myitem in mylist:
|
|
trashing_counters.add(mydbconn.retrieveSpmUid(myitem))
|
|
|
|
for mycounter in trashing_counters:
|
|
dbconn.setTrashedUid(mycounter)
|
|
|
|
# add package info to our current server repository
|
|
dbconn.dropInstalledPackageFromStore(idpackage)
|
|
dbconn.storeInstalledPackage(idpackage, repo)
|
|
atom = dbconn.retrieveAtom(idpackage)
|
|
|
|
self.updateProgress(
|
|
"[repo:%s] %s: %s %s: %s" % (
|
|
darkgreen(repo),
|
|
blue(_("added package")),
|
|
darkgreen(atom),
|
|
blue(_("rev")), # as in revision
|
|
bold(str(revision)),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
manual_deps = sorted(dbconn.retrieveManualDependencies(idpackage))
|
|
if manual_deps:
|
|
self.updateProgress(
|
|
"[repo:%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
blue(_("manual dependencies for")),
|
|
darkgreen(atom),
|
|
),
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkgreen(" ## ")
|
|
)
|
|
for m_dep in manual_deps:
|
|
self.updateProgress(
|
|
brown(m_dep),
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" # ")
|
|
)
|
|
|
|
download_url = self._setup_repository_package_filename(idpackage,
|
|
repo = repo)
|
|
downloadfile = os.path.basename(download_url)
|
|
destination_path = os.path.join(upload_dir, downloadfile)
|
|
try:
|
|
os.rename(package_file, destination_path)
|
|
except OSError:
|
|
shutil.move(package_file, destination_path)
|
|
|
|
dbconn.commitChanges()
|
|
return idpackage, destination_path
|
|
|
|
# this function changes the final repository package filename
|
|
def _setup_repository_package_filename(self, idpackage, repo = None):
|
|
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
|
|
downloadurl = dbconn.retrieveDownloadURL(idpackage)
|
|
packagerev = dbconn.retrieveRevision(idpackage)
|
|
downloaddir = os.path.dirname(downloadurl)
|
|
downloadfile = os.path.basename(downloadurl)
|
|
# add revision
|
|
downloadfile = downloadfile[:-5]+"~%s%s" % (packagerev,
|
|
etpConst['packagesext'],)
|
|
downloadurl = os.path.join(downloaddir, downloadfile)
|
|
|
|
# update url
|
|
dbconn.setDownloadURL(idpackage, downloadurl)
|
|
|
|
return downloadurl
|
|
|
|
def add_packages_to_repository(self, packages_data, ask = True,
|
|
repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
mycount = 0
|
|
maxcount = len(packages_data)
|
|
idpackages_added = set()
|
|
to_be_injected = set()
|
|
my_qa = self.QA()
|
|
missing_deps_taint = False
|
|
for package_filepath, inject in packages_data:
|
|
|
|
mycount += 1
|
|
self.updateProgress(
|
|
"[repo:%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
blue(_("adding package")),
|
|
darkgreen(os.path.basename(package_filepath)),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" @@ "),
|
|
count = (mycount, maxcount,)
|
|
)
|
|
|
|
try:
|
|
# add to database
|
|
idpackage, destination_path = self.package_injector(
|
|
package_filepath,
|
|
inject = inject,
|
|
repo = repo
|
|
)
|
|
idpackages_added.add(idpackage)
|
|
to_be_injected.add((idpackage, destination_path))
|
|
except Exception as err:
|
|
self.entropyTools.print_traceback()
|
|
self.updateProgress(
|
|
"[repo:%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
darkred(_("Exception caught, closing tasks")),
|
|
darkgreen(str(err)),
|
|
),
|
|
importance = 1,
|
|
type = "error",
|
|
header = bold(" !!! "),
|
|
count = (mycount, maxcount,)
|
|
)
|
|
# reinit depends table
|
|
self.depends_table_initialize(repo)
|
|
# reinit librarypathsidpackage table
|
|
if idpackages_added:
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
missing_deps_taint = my_qa.test_missing_dependencies(
|
|
idpackages_added,
|
|
dbconn,
|
|
ask = ask,
|
|
repo = repo,
|
|
self_check = True,
|
|
black_list = \
|
|
self.get_missing_dependencies_blacklist(
|
|
repo = repo),
|
|
black_list_adder = \
|
|
self.add_missing_dependencies_blacklist_items
|
|
)
|
|
my_qa.test_depends_linking(idpackages_added, dbconn,
|
|
repo = repo)
|
|
if to_be_injected:
|
|
self.inject_database_into_packages(to_be_injected,
|
|
repo = repo)
|
|
# reinit depends table
|
|
if missing_deps_taint:
|
|
self.depends_table_initialize(repo)
|
|
self.close_server_databases()
|
|
raise
|
|
|
|
# reinit depends table
|
|
self.depends_table_initialize(repo)
|
|
|
|
if idpackages_added:
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
missing_deps_taint = my_qa.test_missing_dependencies(
|
|
idpackages_added,
|
|
dbconn,
|
|
ask = ask,
|
|
repo = repo,
|
|
self_check = True,
|
|
black_list = \
|
|
self.get_missing_dependencies_blacklist(repo = repo),
|
|
black_list_adder = \
|
|
self.add_missing_dependencies_blacklist_items
|
|
)
|
|
my_qa.test_depends_linking(idpackages_added, dbconn, repo = repo)
|
|
|
|
# reinit depends table
|
|
if missing_deps_taint:
|
|
self.depends_table_initialize(repo)
|
|
|
|
# inject database into packages
|
|
self.inject_database_into_packages(to_be_injected, repo = repo)
|
|
|
|
return idpackages_added
|
|
|
|
|
|
def inject_database_into_packages(self, injection_data, repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
# now inject metadata into tbz2 packages
|
|
self.updateProgress(
|
|
"[repo:%s] %s:" % (
|
|
darkgreen(repo),
|
|
blue(_("Injecting entropy metadata into built packages")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
for idpackage, package_path in injection_data:
|
|
self.updateProgress(
|
|
"[repo:%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
brown(str(idpackage)),
|
|
blue(_("injecting entropy metadata")),
|
|
darkgreen(os.path.basename(package_path)),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" @@ "),
|
|
back = True
|
|
)
|
|
data = dbconn.getPackageData(idpackage)
|
|
treeupdates_actions = dbconn.listAllTreeUpdatesActions()
|
|
dbpath = self.ClientService.inject_entropy_database_into_package(
|
|
package_path, data, treeupdates_actions)
|
|
digest = self.entropyTools.md5sum(package_path)
|
|
# update digest
|
|
dbconn.setDigest(idpackage, digest)
|
|
# update signatures
|
|
signatures = data['signatures'].copy()
|
|
for hash_key in sorted(signatures):
|
|
hash_func = getattr(self.entropyTools, hash_key)
|
|
signatures[hash_key] = hash_func(package_path)
|
|
dbconn.setSignatures(idpackage, signatures['sha1'],
|
|
signatures['sha256'], signatures['sha512'])
|
|
self.entropyTools.create_md5_file(package_path)
|
|
const_setup_file(package_path, etpConst['entropygid'], 0o664)
|
|
# remove garbage
|
|
os.remove(dbpath)
|
|
self.updateProgress(
|
|
"[repo:%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
brown(str(idpackage)),
|
|
blue(_("injection complete")),
|
|
darkgreen(os.path.basename(package_path)),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
dbconn.commitChanges()
|
|
|
|
def check_config_file_updates(self):
|
|
self.updateProgress(
|
|
"[%s] %s" % (
|
|
red(_("config files")), # something short please
|
|
blue(_("checking system")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" @@ "),
|
|
back = True
|
|
)
|
|
# scanning for config files not updated
|
|
scandata = self.ClientService.FileUpdates.scanfs(dcache = False)
|
|
if scandata:
|
|
self.updateProgress(
|
|
"[%s] %s" % (
|
|
red(_("config files")), # something short please
|
|
blue(_("there are configuration files not updated yet")),
|
|
),
|
|
importance = 1,
|
|
type = "error",
|
|
header = darkred(" @@ ")
|
|
)
|
|
for key in scandata:
|
|
self.updateProgress(
|
|
"%s" % (brown(etpConst['systemroot'] + \
|
|
scandata[key]['destination'])),
|
|
importance = 1,
|
|
type = "info",
|
|
header = "\t"
|
|
)
|
|
return True
|
|
return False
|
|
|
|
def remove_packages(self, idpackages, repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
for idpackage in idpackages:
|
|
atom = dbconn.retrieveAtom(idpackage)
|
|
self.updateProgress(
|
|
"[repo:%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
blue(_("removing package")),
|
|
darkgreen(atom),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" @@ ")
|
|
)
|
|
dbconn.removePackage(idpackage)
|
|
self.close_server_database(dbconn)
|
|
self.updateProgress(
|
|
"[repo:%s] %s" % (
|
|
darkgreen(repo),
|
|
blue(_("removal complete")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" @@ ")
|
|
)
|
|
|
|
def taint_database(self, repo = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
# taint the database status
|
|
db_file = self.get_local_database_file(repo = repo)
|
|
taint_file = self.get_local_database_taint_file(repo = repo)
|
|
f = open(taint_file, "w")
|
|
f.write("database tainted\n")
|
|
f.flush()
|
|
f.close()
|
|
const_setup_file(taint_file, etpConst['entropygid'], 0o664)
|
|
ServerRepositoryStatus().set_tainted(db_file)
|
|
|
|
def bump_database(self, repo = None):
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
self.taint_database(repo = repo)
|
|
self.close_server_database(dbconn)
|
|
|
|
def get_remote_mirrors(self, repo = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return srv_set['repositories'][repo]['mirrors'][:]
|
|
|
|
def get_remote_packages_relative_path(self, repo = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return srv_set['repositories'][repo]['packages_relative_path']
|
|
|
|
def get_remote_database_relative_path(self, repo = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return srv_set['repositories'][repo]['database_relative_path']
|
|
|
|
def get_local_database_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasefile'])
|
|
|
|
def get_local_store_directory(self, repo = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return srv_set['repositories'][repo]['store_dir']
|
|
|
|
def get_local_upload_directory(self, repo = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return srv_set['repositories'][repo]['upload_dir']
|
|
|
|
def get_local_packages_directory(self, repo = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return srv_set['repositories'][repo]['packages_dir']
|
|
|
|
def get_local_database_taint_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasetaintfile'])
|
|
|
|
def get_local_database_revision_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabaserevisionfile'])
|
|
|
|
def get_local_database_timestamp_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasetimestampfile'])
|
|
|
|
def get_local_database_ca_cert_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasecacertfile'])
|
|
|
|
def get_local_database_server_cert_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabaseservercertfile'])
|
|
|
|
def get_local_database_mask_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasemaskfile'])
|
|
|
|
def get_local_database_system_mask_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasesytemmaskfile'])
|
|
|
|
def get_local_database_confl_tagged_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabaseconflictingtaggedfile'])
|
|
|
|
def get_local_database_licensewhitelist_file(self, repo = None,
|
|
branch = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabaselicwhitelistfile'])
|
|
|
|
def get_local_database_rss_file(self, repo = None, branch = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
srv_set['rss']['name'])
|
|
|
|
def get_local_database_rsslight_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['rss-light-name'])
|
|
|
|
def get_local_database_notice_board_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['rss-notice-board'])
|
|
|
|
def get_local_database_treeupdates_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabaseupdatefile'])
|
|
|
|
def get_local_database_compressed_metafiles_file(self, repo = None,
|
|
branch = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasemetafilesfile'])
|
|
|
|
def get_local_database_metafiles_not_found_file(self, repo = None,
|
|
branch = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasemetafilesnotfound'])
|
|
|
|
def get_local_exp_based_pkgs_rm_whitelist_file(self, repo = None,
|
|
branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabaseexpbasedpkgsrm'])
|
|
|
|
def get_local_pkglist_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasepkglist'])
|
|
|
|
def get_local_database_sets_dir(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['confsetsdirname'])
|
|
|
|
def get_local_post_branch_mig_script(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etp_post_branch_hop_script'])
|
|
|
|
def get_local_post_branch_upg_script(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etp_post_branch_upgrade_script'])
|
|
|
|
def get_local_post_repo_update_script(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etp_post_repo_update_script'])
|
|
|
|
def get_local_critical_updates_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasecriticalfile'])
|
|
|
|
def get_local_database_keywords_file(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
return os.path.join(self.get_local_database_dir(repo, branch),
|
|
etpConst['etpdatabasekeywordsfile'])
|
|
|
|
def get_local_database_dir(self, repo = None, branch = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
if branch is None:
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
return os.path.join(srv_set['repositories'][repo]['database_dir'],
|
|
branch)
|
|
|
|
def get_missing_dependencies_blacklist_file(self, repo = None,
|
|
branch = None):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
if branch is None:
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
return os.path.join(srv_set['repositories'][repo]['database_dir'],
|
|
branch, etpConst['etpdatabasemissingdepsblfile'])
|
|
|
|
def get_missing_dependencies_blacklist(self, repo = None, branch = None):
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
if branch is None:
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
wl_file = self.get_missing_dependencies_blacklist_file(repo, branch)
|
|
wl_data = []
|
|
if os.path.isfile(wl_file) and os.access(wl_file, os.R_OK):
|
|
f_wl = open(wl_file, "r")
|
|
wl_data = [x.strip() for x in f_wl.readlines() if x.strip() and \
|
|
not x.strip().startswith("#")]
|
|
f_wl.close()
|
|
return set(wl_data)
|
|
|
|
def add_missing_dependencies_blacklist_items(self, items, repo = None,
|
|
branch = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
if branch is None:
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
wl_file = self.get_missing_dependencies_blacklist_file(repo, branch)
|
|
wl_dir = os.path.dirname(wl_file)
|
|
if not (os.path.isdir(wl_dir) and os.access(wl_dir, os.W_OK)):
|
|
return
|
|
if os.path.isfile(wl_file) and not os.access(wl_file, os.W_OK):
|
|
return
|
|
f_wl = open(wl_file, "a+")
|
|
f_wl.write('\n'.join(items)+'\n')
|
|
f_wl.flush()
|
|
f_wl.close()
|
|
|
|
def get_local_database_revision(self, repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
dbrev_file = self.get_local_database_revision_file(repo)
|
|
if os.path.isfile(dbrev_file):
|
|
f_rev = open(dbrev_file)
|
|
rev = f_rev.readline().strip()
|
|
f_rev.close()
|
|
try:
|
|
rev = int(rev)
|
|
except ValueError:
|
|
self.updateProgress(
|
|
"[repo:%s] %s: %s - %s" % (
|
|
darkgreen(repo),
|
|
blue(_("invalid database revision")),
|
|
bold(rev),
|
|
blue(_("defaulting to 0")),
|
|
),
|
|
importance = 2,
|
|
type = "error",
|
|
header = darkred(" !!! ")
|
|
)
|
|
rev = 0
|
|
return rev
|
|
else:
|
|
return 0
|
|
|
|
def get_remote_database_revision(self, repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
remote_status = self.MirrorsService.get_remote_databases_status(repo)
|
|
if not [x for x in remote_status if x[1]]:
|
|
remote_revision = 0
|
|
else:
|
|
remote_revision = max([x[1] for x in remote_status])
|
|
|
|
return remote_revision
|
|
|
|
def get_branch_from_download_relative_uri(self, mypath):
|
|
return self.ClientService.get_branch_from_download_relative_uri(mypath)
|
|
|
|
def get_current_timestamp(self):
|
|
from datetime import datetime
|
|
import time
|
|
return "%s" % (datetime.fromtimestamp(time.time()),)
|
|
|
|
def create_repository_pkglist(self, repo = None, branch = None):
|
|
pkglist_file = self.get_local_pkglist_file(repo = repo, branch = branch)
|
|
|
|
tmp_pkglist_file = pkglist_file + ".tmp"
|
|
dbconn = self.open_server_repository(repo = repo, just_reading = True,
|
|
do_treeupdates = False)
|
|
pkglist = dbconn.listAllDownloads(do_sort = True, full_path = True)
|
|
|
|
with open(tmp_pkglist_file, "w") as pkg_f:
|
|
for pkg in pkglist:
|
|
pkg_f.write(pkg + "\n")
|
|
pkg_f.flush()
|
|
|
|
os.rename(tmp_pkglist_file, pkglist_file)
|
|
|
|
def package_set_list(self, *args, **kwargs):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
repos = list(srv_set['repositories'].keys())
|
|
kwargs['server_repos'] = repos
|
|
kwargs['serverInstance'] = self
|
|
return self.ClientService.package_set_list(*args, **kwargs)
|
|
|
|
def package_set_search(self, *args, **kwargs):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
repos = list(srv_set['repositories'].keys())
|
|
kwargs['server_repos'] = repos
|
|
kwargs['serverInstance'] = self
|
|
return self.ClientService.package_set_search(*args, **kwargs)
|
|
|
|
def package_set_match(self, *args, **kwargs):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
repos = list(srv_set['repositories'].keys())
|
|
kwargs['server_repos'] = repos
|
|
kwargs['serverInstance'] = self
|
|
return self.ClientService.package_set_match(*args, **kwargs)
|
|
|
|
def atom_match(self, *args, **kwargs):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
repos = list(srv_set['repositories'].keys())
|
|
kwargs['server_repos'] = repos
|
|
kwargs['serverInstance'] = self
|
|
return self.ClientService.atom_match(*args, **kwargs)
|
|
|
|
def scan_package_changes(self):
|
|
|
|
spm = self.Spm()
|
|
|
|
spm_packages = spm.get_installed_packages()
|
|
installed_packages = []
|
|
for spm_package in spm_packages:
|
|
pkg_counter = spm.get_installed_package_metadata(spm_package,
|
|
"COUNTER")
|
|
try:
|
|
pkg_counter = int(pkg_counter)
|
|
except ValueError:
|
|
continue
|
|
installed_packages.append((spm_package, pkg_counter,))
|
|
|
|
installed_counters = set()
|
|
to_be_added = set()
|
|
to_be_removed = set()
|
|
to_be_injected = set()
|
|
my_settings = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
exp_based_scope = my_settings['exp_based_scope']
|
|
|
|
server_repos = list(my_settings['repositories'].keys())
|
|
|
|
# packages to be added
|
|
for spm_atom, spm_counter in installed_packages:
|
|
found = False
|
|
for server_repo in server_repos:
|
|
installed_counters.add(spm_counter)
|
|
server_dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = server_repo)
|
|
counter = server_dbconn.isSpmUidAvailable(spm_counter)
|
|
if counter:
|
|
found = True
|
|
break
|
|
if not found:
|
|
to_be_added.add((spm_atom, spm_counter,))
|
|
|
|
# packages to be removed from the database
|
|
database_counters = {}
|
|
for server_repo in server_repos:
|
|
server_dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = server_repo)
|
|
database_counters[server_repo] = server_dbconn.listAllSpmUids()
|
|
|
|
ordered_counters = set()
|
|
for server_repo in database_counters:
|
|
for data in database_counters[server_repo]:
|
|
ordered_counters.add((data, server_repo))
|
|
database_counters = ordered_counters
|
|
|
|
for (counter, idpackage,), xrepo in database_counters:
|
|
|
|
if counter < 0:
|
|
continue # skip packages without valid counter
|
|
|
|
if counter in installed_counters:
|
|
continue
|
|
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = xrepo)
|
|
|
|
dorm = True
|
|
# check if the package is in to_be_added
|
|
if to_be_added:
|
|
|
|
dorm = False
|
|
atom = dbconn.retrieveAtom(idpackage)
|
|
atomkey = self.entropyTools.dep_getkey(atom)
|
|
atomtag = self.entropyTools.dep_gettag(atom)
|
|
atomslot = dbconn.retrieveSlot(idpackage)
|
|
|
|
add = True
|
|
for spm_atom, spm_counter in to_be_added:
|
|
addslot = self.Spm().get_installed_package_metadata(
|
|
spm_atom, "SLOT")
|
|
addkey = self.entropyTools.dep_getkey(spm_atom)
|
|
# workaround for ebuilds not having slot
|
|
if addslot is None:
|
|
addslot = '0'
|
|
# atomtag != None is for handling tagged pkgs correctly
|
|
if (atomkey == addkey) and \
|
|
((str(atomslot) == str(addslot)) or (atomtag != None)):
|
|
# do not add to to_be_removed
|
|
add = False
|
|
break
|
|
|
|
if not add:
|
|
continue
|
|
dorm = True
|
|
|
|
# checking if we are allowed to remove stuff on this repo
|
|
# it xrepo is not the default one, we MUST skip this to
|
|
# avoid touching what developer doesn't expect
|
|
if dorm and (xrepo == self.default_repository):
|
|
trashed = self.is_counter_trashed(counter)
|
|
if trashed:
|
|
# search into portage then
|
|
try:
|
|
key, slot = dbconn.retrieveKeySlot(idpackage)
|
|
trashed = self.Spm().match_installed_package(
|
|
key+":"+slot)
|
|
except TypeError: # referred to retrieveKeySlot
|
|
trashed = True
|
|
if not trashed:
|
|
|
|
dbtag = dbconn.retrieveVersionTag(idpackage)
|
|
if dbtag:
|
|
is_injected = dbconn.isInjected(idpackage)
|
|
if not is_injected:
|
|
to_be_injected.add((idpackage, xrepo))
|
|
|
|
elif exp_based_scope:
|
|
|
|
# check if support for this is set
|
|
plg_id = self.sys_settings_fatscope_plugin_id
|
|
exp_data = self.SystemSettings[plg_id]['repos'].get(
|
|
xrepo, set())
|
|
|
|
# only some packages are set, check if our is
|
|
# in the list
|
|
if (idpackage not in exp_data) and (-1 not in exp_data):
|
|
to_be_removed.add((idpackage, xrepo))
|
|
continue
|
|
|
|
idpackage_expired = self.is_match_expired((idpackage,
|
|
xrepo,))
|
|
|
|
if idpackage_expired:
|
|
# expired !!!
|
|
# add this and its depends (reverse deps)
|
|
to_be_removed.add((idpackage, xrepo))
|
|
for my_id in dbconn.retrieveReverseDependencies(
|
|
idpackage):
|
|
to_be_removed.add((my_id, xrepo))
|
|
|
|
else:
|
|
to_be_removed.add((idpackage, xrepo))
|
|
|
|
return to_be_added, to_be_removed, to_be_injected
|
|
|
|
def is_match_expired(self, match):
|
|
|
|
idpackage, repoid = match
|
|
dbconn = self.open_server_repository(repo = repoid, just_reading = True)
|
|
# 3600 * 24 = 86400
|
|
my_settings = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
pkg_exp_secs = my_settings['packages_expiration_days'] * 86400
|
|
cur_unix_time = self.entropyTools.get_current_unix_time()
|
|
# if packages removal is triggered by expiration
|
|
# we will have to check if our package is really
|
|
# expired and remove its reverse deps too
|
|
mydate = dbconn.retrieveCreationDate(idpackage)
|
|
# cross fingers hoping that time is set correctly
|
|
mydelta = cur_unix_time - float(mydate)
|
|
if mydelta > pkg_exp_secs:
|
|
return True
|
|
return False
|
|
|
|
def is_counter_trashed(self, counter):
|
|
srv_set = self.SystemSettings[self.sys_settings_plugin_id]['server']
|
|
server_repos = list(srv_set['repositories'].keys())
|
|
for repo in server_repos:
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo)
|
|
if dbconn.isSpmUidTrashed(counter):
|
|
return True
|
|
return False
|
|
|
|
def transform_package_into_injected(self, idpackage, repo = None):
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
counter = dbconn.getNewNegativeSpmUid()
|
|
dbconn.setSpmUid(idpackage, counter)
|
|
dbconn.setInjected(idpackage)
|
|
|
|
def initialize_server_database(self, empty = True, repo = None,
|
|
warnings = True):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
self.close_server_databases()
|
|
revisions_match = {}
|
|
treeupdates_actions = []
|
|
injected_packages = set()
|
|
idpackages = set()
|
|
idpackages_added = set()
|
|
|
|
mytxt = red("%s ...") % (_("Initializing Entropy database"),)
|
|
self.updateProgress(
|
|
mytxt, importance = 1,
|
|
type = "info", header = darkgreen(" * "),
|
|
back = True
|
|
)
|
|
|
|
if os.path.isfile(self.get_local_database_file(repo)):
|
|
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo, warnings = warnings)
|
|
|
|
try:
|
|
dbconn.validateDatabase()
|
|
idpackages = dbconn.listAllIdpackages()
|
|
except SystemDatabaseError:
|
|
pass
|
|
|
|
try:
|
|
treeupdates_actions = dbconn.listAllTreeUpdatesActions()
|
|
except dbconn.dbapi2.Error:
|
|
pass
|
|
|
|
# save list of injected packages
|
|
try:
|
|
injected_packages = dbconn.listAllInjectedPackages(
|
|
just_files = True)
|
|
injected_packages = set([os.path.basename(x) for x \
|
|
in injected_packages])
|
|
except dbconn.dbapi2.Error:
|
|
pass
|
|
|
|
for idpackage in idpackages:
|
|
url = dbconn.retrieveDownloadURL(idpackage)
|
|
package = os.path.basename(url)
|
|
branch = dbconn.retrieveBranch(idpackage)
|
|
revision = dbconn.retrieveRevision(idpackage)
|
|
revisions_match[package] = (branch, revision,)
|
|
|
|
self.close_server_database(dbconn)
|
|
|
|
mytxt = "%s: %s: %s" % (
|
|
bold(_("WARNING")),
|
|
red(_("database already exists")),
|
|
self.get_local_database_file(repo),
|
|
)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" !!! ")
|
|
)
|
|
|
|
rc_question = self.askQuestion(_("Do you want to continue ?"))
|
|
if rc_question == _("No"):
|
|
return
|
|
try:
|
|
os.remove(self.get_local_database_file(repo))
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
# initialize
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo, is_new = True)
|
|
dbconn.initializeDatabase()
|
|
|
|
if not empty:
|
|
|
|
revisions_file = "/entropy-revisions-dump.txt"
|
|
# dump revisions - as a backup
|
|
if revisions_match:
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
red(_("Dumping current revisions to file")),
|
|
darkgreen(revisions_file),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" * ")
|
|
)
|
|
f_rev = open(revisions_file, "w")
|
|
f_rev.write(str(revisions_match))
|
|
f_rev.flush()
|
|
f_rev.close()
|
|
|
|
# dump treeupdates - as a backup
|
|
treeupdates_file = "/entropy-treeupdates-dump.txt"
|
|
if treeupdates_actions:
|
|
self.updateProgress(
|
|
"%s: %s" % (
|
|
# do not translate treeupdates
|
|
red(_("Dumping current 'treeupdates' actions to file")),
|
|
bold(treeupdates_file),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" * ")
|
|
)
|
|
f_tree = open(treeupdates_file, "w")
|
|
f_tree.write(str(treeupdates_actions))
|
|
f_tree.flush()
|
|
f_tree.close()
|
|
|
|
rc_question = self.askQuestion(
|
|
_("Would you like to sync packages first (important!) ?"))
|
|
if rc_question == _("Yes"):
|
|
self.MirrorsService.sync_packages(repo = repo)
|
|
|
|
# fill tree updates actions
|
|
if treeupdates_actions:
|
|
dbconn.bumpTreeUpdatesActions(treeupdates_actions)
|
|
|
|
# now fill the database
|
|
pkg_branch_dir = os.path.join(
|
|
self.get_local_packages_directory(repo),
|
|
self.SystemSettings['repositories']['branch'])
|
|
pkglist = os.listdir(pkg_branch_dir)
|
|
# filter .md5 and .expired packages
|
|
pkg_ext_len = len(etpConst['packagesext'])
|
|
pkglist = [x for x in pkglist if (x[(pkg_ext_len*-1):] == \
|
|
etpConst['packagesext']) and not \
|
|
os.path.isfile(os.path.join(pkg_branch_dir,
|
|
x + etpConst['packagesexpirationfileext']))]
|
|
|
|
if pkglist:
|
|
self.updateProgress(
|
|
"%s '%s' %s %s" % (
|
|
red(_("Reinitializing Entropy database for branch")),
|
|
bold(self.SystemSettings['repositories']['branch']),
|
|
red(_("using Packages in the repository")),
|
|
red("..."),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" * ")
|
|
)
|
|
|
|
counter = 0
|
|
maxcount = len(pkglist)
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
for pkg in pkglist:
|
|
counter += 1
|
|
|
|
self.updateProgress(
|
|
"[repo:%s|%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
brown(branch),
|
|
blue(_("analyzing")),
|
|
bold(pkg),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = " ",
|
|
back = True,
|
|
count = (counter, maxcount,)
|
|
)
|
|
|
|
doinject = False
|
|
if pkg in injected_packages:
|
|
doinject = True
|
|
|
|
pkg_path = os.path.join(self.get_local_packages_directory(repo),
|
|
branch, pkg)
|
|
mydata = self.Spm().extract_package_metadata(pkg_path)
|
|
mydata['injected'] = doinject
|
|
|
|
# get previous revision
|
|
revision_avail = revisions_match.get(pkg)
|
|
add_revision = 0
|
|
if (revision_avail != None):
|
|
if branch == revision_avail[0]:
|
|
add_revision = revision_avail[1]
|
|
|
|
idpackage, revision, mydata_upd = dbconn.addPackage(mydata,
|
|
revision = add_revision)
|
|
idpackages_added.add(idpackage)
|
|
|
|
self.updateProgress(
|
|
"[repo:%s] [%s:%s/%s] %s: %s, %s: %s" % (
|
|
repo,
|
|
brown(branch),
|
|
darkgreen(str(counter)),
|
|
blue(str(maxcount)),
|
|
red(_("added package")),
|
|
darkgreen(pkg),
|
|
red(_("revision")),
|
|
brown(str(revision)),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = " ",
|
|
back = True
|
|
)
|
|
|
|
self.depends_table_initialize(repo)
|
|
|
|
my_qa = self.QA()
|
|
|
|
if idpackages_added:
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo)
|
|
my_qa.test_missing_dependencies(
|
|
idpackages_added, dbconn, ask = True,
|
|
repo = repo, self_check = True,
|
|
black_list = \
|
|
self.get_missing_dependencies_blacklist(repo = repo),
|
|
black_list_adder = \
|
|
self.add_missing_dependencies_blacklist_items
|
|
)
|
|
|
|
dbconn.commitChanges()
|
|
self.close_server_databases()
|
|
|
|
return 0
|
|
|
|
def match_packages(self, packages, repo = None):
|
|
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo)
|
|
if ("world" in packages) or not packages:
|
|
return dbconn.listAllIdpackages(), True
|
|
else:
|
|
idpackages = set()
|
|
for package in packages:
|
|
matches = dbconn.atomMatch(package, multiMatch = True)
|
|
if matches[1] == 0:
|
|
idpackages |= matches[0]
|
|
else:
|
|
mytxt = "%s: %s: %s" % (
|
|
red(_("Attention")),
|
|
blue(_("cannot match")),
|
|
bold(package),
|
|
)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" !!! ")
|
|
)
|
|
return idpackages, False
|
|
|
|
def verify_remote_packages(self, packages, ask = True, repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
self.updateProgress(
|
|
"[%s] %s:" % (
|
|
red("remote"),
|
|
blue(_("Integrity verification of the selected packages")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" @@ ")
|
|
)
|
|
|
|
idpackages, world = self.match_packages(packages)
|
|
dbconn = self.open_server_repository(read_only = True, no_upload = True,
|
|
repo = repo)
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
|
|
if world:
|
|
self.updateProgress(
|
|
blue(
|
|
_("All the packages in repository will be checked.")),
|
|
importance = 1,
|
|
type = "info",
|
|
header = " "
|
|
)
|
|
else:
|
|
mytxt = red("%s:") % (
|
|
_("This is the list of the packages that would be checked"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = " "
|
|
)
|
|
for idpackage in idpackages:
|
|
pkgatom = dbconn.retrieveAtom(idpackage)
|
|
down_url = dbconn.retrieveDownloadURL(idpackage)
|
|
pkgfile = os.path.basename(down_url)
|
|
self.updateProgress(
|
|
red(pkgatom) + " -> " + bold(os.path.join(branch, pkgfile)),
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" - ")
|
|
)
|
|
|
|
if ask:
|
|
rc_question = self.askQuestion(
|
|
_("Would you like to continue ?"))
|
|
if rc_question == _("No"):
|
|
return set(), set(), {}
|
|
|
|
match = set()
|
|
not_match = set()
|
|
broken_packages = {}
|
|
|
|
for uri in self.get_remote_mirrors(repo):
|
|
|
|
crippled_uri = EntropyTransceiver.get_uri_name(uri)
|
|
self.updateProgress(
|
|
"[repo:%s] %s: %s" % (
|
|
darkgreen(repo),
|
|
blue(_("Working on mirror")),
|
|
brown(crippled_uri),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
|
|
|
|
totalcounter = len(idpackages)
|
|
currentcounter = 0
|
|
|
|
txc = self.Transceiver(uri)
|
|
txc.set_verbosity(False)
|
|
with txc as handler:
|
|
|
|
for idpackage in idpackages:
|
|
|
|
currentcounter += 1
|
|
pkgfile = dbconn.retrieveDownloadURL(idpackage)
|
|
pkghash = dbconn.retrieveDigest(idpackage)
|
|
|
|
self.updateProgress(
|
|
"[%s] %s: %s" % (
|
|
brown(crippled_uri),
|
|
blue(_("checking hash")),
|
|
darkgreen(pkgfile),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" @@ "),
|
|
back = True,
|
|
count = (currentcounter, totalcounter,)
|
|
)
|
|
|
|
pkg_rel_path = '/'.join(pkgfile.split("/")[2:])
|
|
|
|
pkgfile = os.path.join(
|
|
self.get_remote_packages_relative_path(repo),
|
|
pkg_rel_path)
|
|
|
|
ck_remote = handler.get_md5(pkgfile)
|
|
if ck_remote is None:
|
|
self.updateProgress(
|
|
"[%s] %s: %s %s" % (
|
|
brown(crippled_uri),
|
|
blue(_("digest verification of")),
|
|
bold(pkgfile),
|
|
blue(_("not supported")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" @@ "),
|
|
count = (currentcounter, totalcounter,)
|
|
)
|
|
continue
|
|
|
|
if ck_remote == pkghash:
|
|
match.add(idpackage)
|
|
else:
|
|
not_match.add(idpackage)
|
|
self.updateProgress(
|
|
"[%s] %s: %s %s" % (
|
|
brown(crippled_uri),
|
|
blue(_("package")),
|
|
bold(pkgfile),
|
|
red(_("NOT healthy")),
|
|
),
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" !!! "),
|
|
count = (currentcounter, totalcounter,)
|
|
)
|
|
if crippled_uri not in broken_packages:
|
|
broken_packages[crippled_uri] = []
|
|
broken_packages[crippled_uri].append(pkgfile)
|
|
|
|
if broken_packages:
|
|
mytxt = blue("%s:") % (
|
|
_("This is the list of broken packages"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" * ")
|
|
)
|
|
for mirror in list(broken_packages.keys()):
|
|
mytxt = "%s: %s" % (
|
|
brown(_("Mirror")),
|
|
bold(mirror),
|
|
)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" <> ")
|
|
)
|
|
for broken_package in broken_packages[mirror]:
|
|
self.updateProgress(
|
|
blue(broken_package),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" - ")
|
|
)
|
|
|
|
self.updateProgress(
|
|
"%s:" % (
|
|
blue(_("Statistics")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = red(" @@ ")
|
|
)
|
|
self.updateProgress(
|
|
"[%s] %s:\t%s" % (
|
|
red(crippled_uri),
|
|
brown(_("Number of checked packages")),
|
|
brown(str(len(match) + len(not_match))),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
self.updateProgress(
|
|
"[%s] %s:\t%s" % (
|
|
red(crippled_uri),
|
|
darkgreen(_("Number of healthy packages")),
|
|
darkgreen(str(len(match))),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
self.updateProgress(
|
|
"[%s] %s:\t%s" % (
|
|
red(crippled_uri),
|
|
darkred(_("Number of broken packages")),
|
|
darkred(str(len(not_match))),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
|
|
return match, not_match, broken_packages
|
|
|
|
|
|
def verify_local_packages(self, packages, ask = True, repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
self.updateProgress(
|
|
"[%s] %s:" % (
|
|
red(_("local")),
|
|
blue(_("Integrity verification of the selected packages")),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" * ")
|
|
)
|
|
|
|
idpackages, world = self.match_packages(packages)
|
|
dbconn = self.open_server_repository(read_only = True,
|
|
no_upload = True, repo = repo)
|
|
|
|
if world:
|
|
self.updateProgress(
|
|
blue(_("All the packages in repository will be checked.")),
|
|
importance = 1,
|
|
type = "info",
|
|
header = " "
|
|
)
|
|
|
|
to_download = set()
|
|
available = set()
|
|
for idpackage in idpackages:
|
|
|
|
pkgatom = dbconn.retrieveAtom(idpackage)
|
|
pkg_path = dbconn.retrieveDownloadURL(idpackage)
|
|
pkg_rel_path = '/'.join(pkg_path.split("/")[2:])
|
|
|
|
bindir_path = os.path.join(self.get_local_packages_directory(repo),
|
|
pkg_rel_path)
|
|
uploaddir_path = os.path.join(self.get_local_upload_directory(repo),
|
|
pkg_rel_path)
|
|
|
|
if os.path.isfile(bindir_path):
|
|
if not world:
|
|
self.updateProgress(
|
|
"[%s] %s :: %s" % (
|
|
darkgreen(_("available")),
|
|
blue(pkgatom),
|
|
darkgreen(pkg_rel_path),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = darkgreen(" # ")
|
|
)
|
|
available.add(idpackage)
|
|
elif os.path.isfile(uploaddir_path):
|
|
if not world:
|
|
self.updateProgress(
|
|
"[%s] %s :: %s" % (
|
|
darkred(_("upload/ignored")),
|
|
blue(pkgatom),
|
|
darkgreen(pkg_rel_path),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = darkgreen(" # ")
|
|
)
|
|
else:
|
|
self.updateProgress(
|
|
"[%s] %s :: %s" % (
|
|
brown(_("download")),
|
|
blue(pkgatom),
|
|
darkgreen(pkg_rel_path),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = darkgreen(" # ")
|
|
)
|
|
to_download.add((idpackage, pkg_path,))
|
|
|
|
if ask:
|
|
rc_question = self.askQuestion(_("Would you like to continue ?"))
|
|
if rc_question == _("No"):
|
|
return set(), set(), set(), set()
|
|
|
|
|
|
fine = set()
|
|
failed = set()
|
|
downloaded_fine = set()
|
|
downloaded_errors = set()
|
|
|
|
if to_download:
|
|
|
|
not_downloaded = set()
|
|
mytxt = blue("%s ...") % (_("Starting to download missing files"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = " "
|
|
)
|
|
for uri in self.get_remote_mirrors(repo):
|
|
|
|
if not_downloaded:
|
|
mytxt = blue("%s ...") % (
|
|
_("Searching missing/broken files on another mirror"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = " "
|
|
)
|
|
to_download = not_downloaded.copy()
|
|
not_downloaded = set()
|
|
|
|
for idpackage, pkg_path in to_download:
|
|
rc_down = self.MirrorsService.download_package(uri,
|
|
pkg_path, repo = repo)
|
|
if rc_down:
|
|
downloaded_fine.add(idpackage)
|
|
available.add(idpackage)
|
|
else:
|
|
not_downloaded.add(pkg_path)
|
|
|
|
if not not_downloaded:
|
|
self.updateProgress(
|
|
red(_("Binary packages downloaded successfully.")),
|
|
importance = 1,
|
|
type = "info",
|
|
header = " "
|
|
)
|
|
break
|
|
|
|
if not_downloaded:
|
|
mytxt = blue("%s:") % (
|
|
_("These are the packages that cannot be found online"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = " "
|
|
)
|
|
for pkg_path in not_downloaded:
|
|
downloaded_errors.add(pkg_path)
|
|
self.updateProgress(
|
|
brown(pkg_path),
|
|
importance = 1,
|
|
type = "warning",
|
|
header = red(" * ")
|
|
)
|
|
downloaded_errors |= not_downloaded
|
|
mytxt = "%s." % (_("They won't be checked"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "warning",
|
|
header = " "
|
|
)
|
|
|
|
my_qa = self.QA()
|
|
|
|
totalcounter = str(len(available))
|
|
currentcounter = 0
|
|
for idpackage in available:
|
|
currentcounter += 1
|
|
pkg_path = dbconn.retrieveDownloadURL(idpackage)
|
|
orig_branch = self.get_branch_from_download_relative_uri(pkg_path)
|
|
pkgfile = os.path.basename(pkg_path)
|
|
|
|
self.updateProgress(
|
|
"[branch:%s] %s %s" % (
|
|
brown(orig_branch),
|
|
blue(_("checking status of")),
|
|
darkgreen(pkgfile),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = " ",
|
|
back = True,
|
|
count = (currentcounter, totalcounter,)
|
|
)
|
|
|
|
storedmd5 = dbconn.retrieveDigest(idpackage)
|
|
pkgpath = os.path.join(self.get_local_packages_directory(repo),
|
|
orig_branch, pkgfile)
|
|
result = self.entropyTools.compare_md5(pkgpath, storedmd5)
|
|
qa_fine = my_qa.entropy_package_checks(pkgpath)
|
|
if result and qa_fine:
|
|
fine.add(idpackage)
|
|
else:
|
|
failed.add(idpackage)
|
|
self.updateProgress(
|
|
"[branch:%s] %s %s %s: %s" % (
|
|
brown(orig_branch),
|
|
blue(_("package")),
|
|
darkgreen(pkg_path),
|
|
blue(_("is corrupted, stored checksum")),
|
|
brown(storedmd5),
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = " ",
|
|
count = (currentcounter, totalcounter,)
|
|
)
|
|
|
|
if failed:
|
|
mytxt = blue("%s:") % (_("This is the list of broken packages"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "warning",
|
|
header = darkred(" # ")
|
|
)
|
|
for idpackage in failed:
|
|
atom = dbconn.retrieveAtom(idpackage)
|
|
down_p = dbconn.retrieveDownloadURL(idpackage)
|
|
self.updateProgress(
|
|
blue("[atom:%s] %s" % (atom, down_p,)),
|
|
importance = 0,
|
|
type = "warning",
|
|
header = brown(" # ")
|
|
)
|
|
|
|
# print stats
|
|
self.updateProgress(
|
|
red("Statistics:"),
|
|
importance = 1,
|
|
type = "info",
|
|
header = blue(" * ")
|
|
)
|
|
self.updateProgress(
|
|
brown("%s => %s" % (
|
|
len(fine) + len(failed),
|
|
_("checked packages"),
|
|
)
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
self.updateProgress(
|
|
darkgreen("%s => %s" % (
|
|
len(fine),
|
|
_("healthy packages"),
|
|
)
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
self.updateProgress(
|
|
darkred("%s => %s" % (
|
|
len(failed),
|
|
_("broken packages"),
|
|
)
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
self.updateProgress(
|
|
blue("%s => %s" % (
|
|
len(downloaded_fine),
|
|
_("downloaded packages"),
|
|
)
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
self.updateProgress(
|
|
bold("%s => %s" % (
|
|
len(downloaded_errors),
|
|
_("failed downloads"),
|
|
)
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = brown(" # ")
|
|
)
|
|
|
|
self.close_server_database(dbconn)
|
|
return fine, failed, downloaded_fine, downloaded_errors
|
|
|
|
|
|
def switch_packages_branch(self, from_branch, to_branch, repo = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
if to_branch != self.SystemSettings['repositories']['branch']:
|
|
mytxt = "%s: %s %s" % (
|
|
blue(_("Please setup your branch to")),
|
|
bold(to_branch),
|
|
blue(_("and retry")),
|
|
)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "error",
|
|
header = darkred(" !! ")
|
|
)
|
|
return None
|
|
|
|
mytxt = red("%s ...") % (_("Copying database (if not exists)"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" @@ ")
|
|
)
|
|
branch_dbdir = self.get_local_database_dir(repo)
|
|
old_branch_dbdir = self.get_local_database_dir(repo, from_branch)
|
|
|
|
# close all our databases
|
|
self.close_server_databases()
|
|
|
|
# if database file did not exist got created as an empty file
|
|
# we can just rm -rf it
|
|
branch_dbfile = self.get_local_database_file(repo)
|
|
if os.path.isfile(branch_dbfile):
|
|
if self.entropyTools.get_file_size(branch_dbfile) == 0:
|
|
shutil.rmtree(branch_dbdir, True)
|
|
|
|
if os.path.isdir(branch_dbdir):
|
|
|
|
while True:
|
|
rnd_num = self.entropyTools.get_random_number()
|
|
backup_dbdir = branch_dbdir + str(rnd_num)
|
|
if not os.path.isdir(backup_dbdir):
|
|
break
|
|
os.rename(branch_dbdir, backup_dbdir)
|
|
|
|
if os.path.isdir(old_branch_dbdir):
|
|
shutil.copytree(old_branch_dbdir, branch_dbdir)
|
|
|
|
mytxt = red("%s ...") % (_("Switching packages"),)
|
|
self.updateProgress(
|
|
mytxt,
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" @@ ")
|
|
)
|
|
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo, lock_remote = False)
|
|
try:
|
|
dbconn.validateDatabase()
|
|
except SystemDatabaseError:
|
|
self.handle_uninitialized_repository(repo)
|
|
dbconn = self.open_server_repository(read_only = False,
|
|
no_upload = True, repo = repo, lock_remote = False)
|
|
|
|
idpackages = dbconn.listAllIdpackages()
|
|
already_switched = set()
|
|
not_found = set()
|
|
switched = set()
|
|
ignored = set()
|
|
no_checksum = set()
|
|
|
|
maxcount = len(idpackages)
|
|
count = 0
|
|
for idpackage in idpackages:
|
|
count += 1
|
|
|
|
cur_branch = dbconn.retrieveBranch(idpackage)
|
|
atom = dbconn.retrieveAtom(idpackage)
|
|
if cur_branch == to_branch:
|
|
already_switched.add(idpackage)
|
|
self.updateProgress(
|
|
red("%s %s, %s %s" % (
|
|
_("Ignoring"),
|
|
bold(atom),
|
|
_("already in branch"),
|
|
cur_branch,
|
|
)
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = darkgreen(" @@ "),
|
|
count = (count, maxcount,)
|
|
)
|
|
ignored.add(idpackage)
|
|
continue
|
|
|
|
self.updateProgress(
|
|
"[%s=>%s] %s" % (
|
|
brown(cur_branch),
|
|
bold(to_branch),
|
|
darkgreen(atom),
|
|
),
|
|
importance = 0,
|
|
type = "info",
|
|
header = darkgreen(" @@ "),
|
|
back = True,
|
|
count = (count, maxcount,)
|
|
)
|
|
dbconn.switchBranch(idpackage, to_branch)
|
|
dbconn.commitChanges()
|
|
switched.add(idpackage)
|
|
|
|
dbconn.commitChanges()
|
|
|
|
# now migrate counters
|
|
dbconn.moveSpmUidsToBranch(to_branch, from_branch = from_branch)
|
|
|
|
self.close_server_database(dbconn)
|
|
mytxt = blue("%s.") % (_("migration loop completed"),)
|
|
self.updateProgress(
|
|
"[%s=>%s] %s" % (
|
|
brown(from_branch),
|
|
bold(to_branch),
|
|
mytxt,
|
|
),
|
|
importance = 1,
|
|
type = "info",
|
|
header = darkgreen(" * ")
|
|
)
|
|
|
|
return switched, already_switched, ignored, not_found, no_checksum
|
|
|
|
def get_entropy_sets(self, repo = None, branch = None):
|
|
|
|
if branch is None:
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
sets_dir = self.get_local_database_sets_dir(repo, branch)
|
|
if not (os.path.isdir(sets_dir) and os.access(sets_dir, os.R_OK)):
|
|
return {}
|
|
|
|
mydata = {}
|
|
items = os.listdir(sets_dir)
|
|
for item in items:
|
|
|
|
try:
|
|
item_clean = str(item)
|
|
except (UnicodeEncodeError, UnicodeDecodeError,):
|
|
continue
|
|
item_path = os.path.join(sets_dir, item)
|
|
if not (os.path.isfile(item_path) and \
|
|
os.access(item_path, os.R_OK)):
|
|
continue
|
|
item_elements = self.entropyTools.extract_packages_from_set_file(
|
|
item_path)
|
|
if item_elements:
|
|
mydata[item_clean] = item_elements.copy()
|
|
|
|
return mydata
|
|
|
|
def get_configured_package_sets(self, repo = None, branch = None,
|
|
validate = True):
|
|
|
|
if branch is None:
|
|
branch = self.SystemSettings['repositories']['branch']
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
|
|
# portage sets
|
|
sets_data = self.Spm().get_package_sets(False)
|
|
sets_data.update(self.get_entropy_sets(repo, branch))
|
|
|
|
if validate:
|
|
invalid_sets = set()
|
|
# validate
|
|
for setname in sets_data:
|
|
good = True
|
|
for atom in sets_data[setname]:
|
|
dbconn = self.open_server_repository(just_reading = True,
|
|
repo = repo)
|
|
match = dbconn.atomMatch(atom)
|
|
if match[0] == -1:
|
|
good = False
|
|
break
|
|
if not good:
|
|
invalid_sets.add(setname)
|
|
for invalid_set in invalid_sets:
|
|
del sets_data[invalid_set]
|
|
|
|
return sets_data
|
|
|
|
def update_database_package_sets(self, repo = None, dbconn = None):
|
|
|
|
if repo is None:
|
|
repo = self.default_repository
|
|
package_sets = self.get_configured_package_sets(repo)
|
|
if dbconn is None:
|
|
dbconn = self.open_server_repository(
|
|
read_only = False, no_upload = True, repo = repo,
|
|
do_treeupdates = False)
|
|
dbconn.clearPackageSets()
|
|
if package_sets:
|
|
dbconn.insertPackageSets(package_sets)
|
|
dbconn.commitChanges()
|