Files
entropy/libraries/entropy/db.py
T

5275 lines
204 KiB
Python

# -*- coding: utf-8 -*-
"""
# DESCRIPTION:
# Entropy Object Oriented Interface
Copyright (C) 2007-2009 Fabio Erculiani
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from __future__ import with_statement
import os
import shutil
import subprocess
from entropy.const import etpConst, etpCache
from entropy.exceptions import IncorrectParameter, InvalidAtom, \
SystemDatabaseError, OperationNotPermitted
from entropy.i18n import _
from entropy.output import brown, bold, red, blue, darkred, darkgreen, \
TextInterface
from entropy.cache import EntropyCacher
from entropy.core import Singleton, SystemSettings
try: # try with sqlite3 from python 2.5 - default one
from sqlite3 import dbapi2
except ImportError: # fallback to pysqlite
try:
from pysqlite2 import dbapi2
except ImportError, e:
raise SystemError(
"%s. %s: %s" % (
_("Entropy needs Python compiled with sqlite3 support"),
_("Error"),
e,
)
)
class Status(Singleton):
def init_singleton(self):
self.__data = {}
def __create_if_necessary(self, db):
if db not in self.__data:
self.__data[db] = {}
self.__data[db]['tainted'] = False
self.__data[db]['bumped'] = False
self.__data[db]['unlock_msg'] = False
def set_unlock_msg(self, db):
self.__create_if_necessary(db)
self.__data[db]['unlock_msg'] = True
def unset_unlock_msg(self, db):
self.__create_if_necessary(db)
self.__data[db]['unlock_msg'] = False
def set_tainted(self, db):
self.__create_if_necessary(db)
self.__data[db]['tainted'] = True
def unset_tainted(self, db):
self.__create_if_necessary(db)
self.__data[db]['tainted'] = False
def set_bumped(self, db):
self.__create_if_necessary(db)
self.__data[db]['bumped'] = True
def unset_bumped(self, db):
self.__create_if_necessary(db)
self.__data[db]['bumped'] = False
def is_tainted(self, db):
self.__create_if_necessary(db)
return self.__data[db]['tainted']
def is_bumped(self, db):
self.__create_if_necessary(db)
return self.__data[db]['bumped']
def is_unlock_msg(self, db):
self.__create_if_necessary(db)
return self.__data[db]['unlock_msg']
class Schema:
def get_init(self):
return """
CREATE TABLE baseinfo (
idpackage INTEGER PRIMARY KEY AUTOINCREMENT,
atom VARCHAR,
idcategory INTEGER,
name VARCHAR,
version VARCHAR,
versiontag VARCHAR,
revision INTEGER,
branch VARCHAR,
slot VARCHAR,
idlicense INTEGER,
etpapi INTEGER,
trigger INTEGER
);
CREATE TABLE extrainfo (
idpackage INTEGER PRIMARY KEY,
description VARCHAR,
homepage VARCHAR,
download VARCHAR,
size VARCHAR,
idflags INTEGER,
digest VARCHAR,
datecreation VARCHAR
);
CREATE TABLE content (
idpackage INTEGER,
file VARCHAR,
type VARCHAR
);
CREATE TABLE provide (
idpackage INTEGER,
atom VARCHAR
);
CREATE TABLE dependencies (
idpackage INTEGER,
iddependency INTEGER,
type INTEGER
);
CREATE TABLE dependenciesreference (
iddependency INTEGER PRIMARY KEY AUTOINCREMENT,
dependency VARCHAR
);
CREATE TABLE dependstable (
iddependency INTEGER PRIMARY KEY,
idpackage INTEGER
);
CREATE TABLE conflicts (
idpackage INTEGER,
conflict VARCHAR
);
CREATE TABLE mirrorlinks (
mirrorname VARCHAR,
mirrorlink VARCHAR
);
CREATE TABLE sources (
idpackage INTEGER,
idsource INTEGER
);
CREATE TABLE sourcesreference (
idsource INTEGER PRIMARY KEY AUTOINCREMENT,
source VARCHAR
);
CREATE TABLE useflags (
idpackage INTEGER,
idflag INTEGER
);
CREATE TABLE useflagsreference (
idflag INTEGER PRIMARY KEY AUTOINCREMENT,
flagname VARCHAR
);
CREATE TABLE keywords (
idpackage INTEGER,
idkeyword INTEGER
);
CREATE TABLE keywordsreference (
idkeyword INTEGER PRIMARY KEY AUTOINCREMENT,
keywordname VARCHAR
);
CREATE TABLE categories (
idcategory INTEGER PRIMARY KEY AUTOINCREMENT,
category VARCHAR
);
CREATE TABLE licenses (
idlicense INTEGER PRIMARY KEY AUTOINCREMENT,
license VARCHAR
);
CREATE TABLE flags (
idflags INTEGER PRIMARY KEY AUTOINCREMENT,
chost VARCHAR,
cflags VARCHAR,
cxxflags VARCHAR
);
CREATE TABLE configprotect (
idpackage INTEGER PRIMARY KEY,
idprotect INTEGER
);
CREATE TABLE configprotectmask (
idpackage INTEGER PRIMARY KEY,
idprotect INTEGER
);
CREATE TABLE configprotectreference (
idprotect INTEGER PRIMARY KEY AUTOINCREMENT,
protect VARCHAR
);
CREATE TABLE systempackages (
idpackage INTEGER PRIMARY KEY
);
CREATE TABLE injected (
idpackage INTEGER PRIMARY KEY
);
CREATE TABLE installedtable (
idpackage INTEGER PRIMARY KEY,
repositoryname VARCHAR,
source INTEGER
);
CREATE TABLE sizes (
idpackage INTEGER PRIMARY KEY,
size INTEGER
);
CREATE TABLE messages (
idpackage INTEGER,
message VARCHAR
);
CREATE TABLE counters (
counter INTEGER,
idpackage INTEGER,
branch VARCHAR,
PRIMARY KEY(idpackage,branch)
);
CREATE TABLE trashedcounters (
counter INTEGER
);
CREATE TABLE eclasses (
idpackage INTEGER,
idclass INTEGER
);
CREATE TABLE eclassesreference (
idclass INTEGER PRIMARY KEY AUTOINCREMENT,
classname VARCHAR
);
CREATE TABLE needed (
idpackage INTEGER,
idneeded INTEGER,
elfclass INTEGER
);
CREATE TABLE neededreference (
idneeded INTEGER PRIMARY KEY AUTOINCREMENT,
library VARCHAR
);
CREATE TABLE treeupdates (
repository VARCHAR PRIMARY KEY,
digest VARCHAR
);
CREATE TABLE treeupdatesactions (
idupdate INTEGER PRIMARY KEY AUTOINCREMENT,
repository VARCHAR,
command VARCHAR,
branch VARCHAR,
date VARCHAR
);
CREATE TABLE licensedata (
licensename VARCHAR UNIQUE,
text BLOB,
compressed INTEGER
);
CREATE TABLE licenses_accepted (
licensename VARCHAR UNIQUE
);
CREATE TABLE triggers (
idpackage INTEGER PRIMARY KEY,
data BLOB
);
CREATE TABLE entropy_misc_counters (
idtype INTEGER PRIMARY KEY,
counter INTEGER
);
CREATE TABLE categoriesdescription (
category VARCHAR,
locale VARCHAR,
description VARCHAR
);
CREATE TABLE packagesets (
setname VARCHAR,
dependency VARCHAR
);
CREATE TABLE packagechangelogs (
category VARCHAR,
name VARCHAR,
changelog BLOB,
PRIMARY KEY (category, name)
);
CREATE TABLE automergefiles (
idpackage INTEGER,
configfile VARCHAR,
md5 VARCHAR
);
CREATE TABLE packagesignatures (
idpackage INTEGER PRIMARY KEY,
sha1 VARCHAR,
sha256 VARCHAR,
sha512 VARCHAR
);
CREATE TABLE packagespmphases (
idpackage INTEGER PRIMARY KEY,
phases VARCHAR
);
"""
class LocalRepository:
import entropy.tools as entropyTools
import entropy.dump as dumpTools
import threading
def __init__(self, readOnly = False, noUpload = False, dbFile = None,
clientDatabase = False, xcache = False, dbname = etpConst['serverdbid'],
indexing = True, OutputInterface = None, ServiceInterface = None,
skipChecks = False, useBranch = None, lockRemote = True):
self.SystemSettings = SystemSettings()
self.srv_sys_settings_plugin = \
etpConst['system_settings_plugins_ids']['server_plugin']
self.dbMatchCacheKey = etpCache['dbMatch']
self.dbSearchCacheKey = etpCache['dbSearch']
self.dbname = dbname
self.lockRemote = lockRemote
self.client_settings_plugin_id = etpConst['system_settings_plugins_ids']['client_plugin']
self.db_branch = self.SystemSettings['repositories']['branch']
if self.dbname == etpConst['clientdbid']:
self.db_branch = None
if useBranch != None: self.db_branch = useBranch
if OutputInterface == None:
OutputInterface = TextInterface()
if dbFile == None:
raise IncorrectParameter("IncorrectParameter: %s" % (
_("valid database path needed"),) )
self.Cacher = EntropyCacher()
self.__write_mutex = self.threading.Lock()
self.dbapi2 = dbapi2
# setup output interface
self.OutputInterface = OutputInterface
self.updateProgress = self.OutputInterface.updateProgress
self.askQuestion = self.OutputInterface.askQuestion
# setup service interface
self.ServiceInterface = ServiceInterface
self.readOnly = readOnly
self.noUpload = noUpload
self.clientDatabase = clientDatabase
self.xcache = xcache
self.indexing = indexing
self.skipChecks = skipChecks
if not self.skipChecks:
if not self.entropyTools.is_user_in_entropy_group():
# forcing since we won't have write access to db
self.indexing = False
# live systems don't like wasting RAM
if self.entropyTools.islive():
self.indexing = False
self.dbFile = dbFile
self.dbclosed = True
self.server_repo = None
if not self.clientDatabase:
self.server_repo = self.dbname[len(etpConst['serverdbid']):]
self.create_dbstatus_data()
if not self.skipChecks:
# no caching for non root and server connections
if (self.dbname.startswith(etpConst['serverdbid'])) or \
(not self.entropyTools.is_user_in_entropy_group()):
self.xcache = False
self.live_cache = {}
# create connection
self.connection = self.dbapi2.connect(dbFile, timeout=300.0,
check_same_thread = False)
self.cursor = self.connection.cursor()
if not self.skipChecks:
if os.access(self.dbFile, os.W_OK) and \
self.doesTableExist('baseinfo') and \
self.doesTableExist('extrainfo'):
if self.entropyTools.islive() and etpConst['systemroot']:
self.databaseStructureUpdates()
else:
self.databaseStructureUpdates()
# now we can set this to False
self.dbclosed = False
def setCacheSize(self, size):
self.cursor.execute('PRAGMA cache_size = '+str(size))
def setDefaultCacheSize(self, size):
self.cursor.execute('PRAGMA default_cache_size = '+str(size))
def __del__(self):
if not self.dbclosed:
self.closeDB()
def create_dbstatus_data(self):
taint_file = self.ServiceInterface.get_local_database_taint_file(
self.server_repo)
if os.path.isfile(taint_file):
dbs = Status()
dbs.set_tainted(self.dbFile)
dbs.set_bumped(self.dbFile)
def closeDB(self):
self.dbclosed = True
# if the class is opened readOnly, close and forget
if self.readOnly:
self.cursor.close()
self.connection.close()
return
if self.clientDatabase:
if self.dbname == etpConst['clientdbid']:
try:
self.doCleanups()
except self.dbapi2.Error:
pass
self.commitChanges()
self.cursor.close()
self.connection.close()
return
sts = Status()
if not sts.is_tainted(self.dbFile):
# we can unlock it, no changes were made
self.ServiceInterface.MirrorsService.lock_mirrors(False,
repo = self.server_repo)
elif not sts.is_unlock_msg(self.dbFile):
u_msg = _("Mirrors have not been unlocked. Remember to sync them.")
self.updateProgress(
darkgreen(u_msg),
importance = 1,
type = "info",
header = brown(" * ")
)
sts.set_unlock_msg(self.dbFile) # avoid spamming
self.commitChanges()
self.cursor.close()
self.connection.close()
def vacuum(self):
self.cursor.execute("vacuum")
def commitChanges(self):
if self.readOnly:
return
try:
self.connection.commit()
except self.dbapi2.Error:
pass
if not self.clientDatabase:
self.taintDatabase()
dbs = Status()
if (dbs.is_tainted(self.dbFile)) and \
(not dbs.is_bumped(self.dbFile)):
# bump revision, setting DatabaseBump causes
# the session to just bump once
dbs.set_bumped(self.dbFile)
self.revisionBump()
def taintDatabase(self):
# if it's equo to open it, this should be avoided
if self.clientDatabase:
return
# taint the database status
taint_file = self.ServiceInterface.get_local_database_taint_file(
repo = self.server_repo)
f = open(taint_file, "w")
f.write(etpConst['currentarch']+" database tainted\n")
f.flush()
f.close()
Status().set_tainted(self.dbFile)
def untaintDatabase(self):
# if it's equo to open it, this should be avoided
if self.clientDatabase:
return
Status().unset_tainted(self.dbFile)
# untaint the database status
taint_file = self.ServiceInterface.get_local_database_taint_file(
repo = self.server_repo)
if os.path.isfile(taint_file):
os.remove(taint_file)
def revisionBump(self):
revision_file = self.ServiceInterface.get_local_database_revision_file(
repo = self.server_repo)
if not os.path.isfile(revision_file):
revision = 1
else:
f = open(revision_file, "r")
revision = int(f.readline().strip())
revision += 1
f.close()
f = open(revision_file, "w")
f.write(str(revision)+"\n")
f.flush()
f.close()
def isDatabaseTainted(self):
taint_file = self.ServiceInterface.get_local_database_taint_file(
repo = self.server_repo)
if os.path.isfile(taint_file):
return True
return False
# never use this unless you know what you're doing
def initializeDatabase(self):
self.checkReadOnly()
my = Schema()
for table in self.listAllTables():
try:
self.cursor.execute("DROP TABLE %s" % (table,))
except self.dbapi2.OperationalError:
# skip tables that can't be dropped
continue
self.cursor.executescript(my.get_init())
self.databaseStructureUpdates()
# set cache size
self.setCacheSize(8192)
self.setDefaultCacheSize(8192)
self.commitChanges()
def checkReadOnly(self):
if self.readOnly:
raise OperationNotPermitted("OperationNotPermitted: %s." % (
_("can't do that on a readonly database"),
)
)
# check for /usr/portage/profiles/updates changes
def serverUpdatePackagesData(self):
etpConst['server_treeupdatescalled'].add(self.server_repo)
repo_updates_file = self.ServiceInterface.get_local_database_treeupdates_file(self.server_repo)
doRescan = False
stored_digest = self.retrieveRepositoryUpdatesDigest(self.server_repo)
if stored_digest == -1:
doRescan = True
# check portage files for changes if doRescan is still false
portage_dirs_digest = "0"
if not doRescan:
treeupdates_dict = self.ServiceInterface.repository_treeupdate_digests
if treeupdates_dict.has_key(self.server_repo):
portage_dirs_digest = treeupdates_dict.get(self.server_repo)
else:
spm = self.ServiceInterface.SpmService
# grab portdir
updates_dir = etpConst['systemroot'] + \
spm.get_spm_setting("PORTDIR") + "/profiles/updates"
if os.path.isdir(updates_dir):
# get checksum
mdigest = self.entropyTools.md5sum_directory(updates_dir,
get_obj = True)
# also checksum etpConst['etpdatabaseupdatefile']
if os.path.isfile(repo_updates_file):
f = open(repo_updates_file)
block = f.read(1024)
while block:
mdigest.update(block)
block = f.read(1024)
f.close()
portage_dirs_digest = mdigest.hexdigest()
treeupdates_dict[self.server_repo] = portage_dirs_digest
del updates_dir
if doRescan or (str(stored_digest) != str(portage_dirs_digest)):
# force parameters
self.readOnly = False
self.noUpload = True
# reset database tables
self.clearTreeupdatesEntries(self.server_repo)
spm = self.ServiceInterface.SpmService
updates_dir = etpConst['systemroot'] + \
spm.get_spm_setting("PORTDIR") + "/profiles/updates"
update_files = self.entropyTools.sort_update_files(
os.listdir(updates_dir))
update_files = [os.path.join(updates_dir, x) for x in update_files]
# now load actions from files
update_actions = []
for update_file in update_files:
f = open(update_file, "r")
mycontent = f.readlines()
f.close()
lines = [x.strip() for x in mycontent if x.strip()]
update_actions.extend(lines)
# add entropy packages.db.repo_updates content
if os.path.isfile(repo_updates_file):
f = open(repo_updates_file, "r")
mycontent = f.readlines()
f.close()
lines = [x.strip() for x in mycontent if x.strip() and \
not x.strip().startswith("#")]
update_actions.extend(lines)
# now filter the required actions
update_actions = self.filterTreeUpdatesActions(update_actions)
if update_actions:
mytxt = "%s: %s. %s %s" % (
bold(_("ATTENTION")),
red(_("forcing package updates")),
red(_("Syncing with")),
blue(updates_dir),
)
self.updateProgress(
mytxt,
importance = 1,
type = "info",
header = brown(" * ")
)
# lock database
if self.lockRemote:
self.ServiceInterface.do_server_repository_sync_lock(
self.server_repo, self.noUpload)
# now run queue
try:
self.runTreeUpdatesActions(update_actions)
except:
# destroy digest
self.setRepositoryUpdatesDigest(self.server_repo, "-1")
raise
# store new actions
self.addRepositoryUpdatesActions(
self.server_repo, update_actions, self.db_branch)
# store new digest into database
self.setRepositoryUpdatesDigest(
self.server_repo, portage_dirs_digest)
self.commitChanges()
def clientUpdatePackagesData(self, clientDbconn, force = False):
if clientDbconn == None:
return
repository = self.dbname[len(etpConst['dbnamerepoprefix']):]
etpConst['client_treeupdatescalled'].add(repository)
doRescan = False
shell_rescan = os.getenv("ETP_TREEUPDATES_RESCAN")
if shell_rescan: doRescan = True
# check database digest
stored_digest = self.retrieveRepositoryUpdatesDigest(repository)
if stored_digest == -1:
doRescan = True
# check stored value in client database
client_digest = "0"
if not doRescan:
client_digest = clientDbconn.retrieveRepositoryUpdatesDigest(
repository)
if doRescan or (str(stored_digest) != str(client_digest)) or force:
# reset database tables
clientDbconn.clearTreeupdatesEntries(repository)
# load updates
update_actions = self.retrieveTreeUpdatesActions(repository)
# now filter the required actions
update_actions = clientDbconn.filterTreeUpdatesActions(
update_actions)
if update_actions:
mytxt = "%s: %s. %s %s" % (
bold(_("ATTENTION")),
red(_("forcing packages metadata update")),
red(_("Updating system database using repository id")),
blue(repository),
)
self.updateProgress(
mytxt,
importance = 1,
type = "info",
header = darkred(" * ")
)
# run stuff
clientDbconn.runTreeUpdatesActions(update_actions)
# store new digest into database
clientDbconn.setRepositoryUpdatesDigest(repository, stored_digest)
# store new actions
clientDbconn.addRepositoryUpdatesActions(etpConst['clientdbid'],
update_actions, self.SystemSettings['repositories']['branch'])
clientDbconn.commitChanges()
# clear client cache
clientDbconn.clearCache()
return True
# this functions will filter either data from /usr/portage/profiles/updates/*
# or repository database returning only the needed actions
def filterTreeUpdatesActions(self, actions):
new_actions = []
for action in actions:
if action in new_actions: # skip dupies
continue
doaction = action.split()
if doaction[0] == "slotmove":
# slot move
atom = doaction[1]
from_slot = doaction[2]
to_slot = doaction[3]
atom_key = self.entropyTools.dep_getkey(atom)
category = atom_key.split("/")[0]
matches = self.atomMatch(atom, matchSlot = from_slot,
multiMatch = True)
found = False
# found atoms, check category
for idpackage in matches[0]:
myslot = self.retrieveSlot(idpackage)
mycategory = self.retrieveCategory(idpackage)
if mycategory == category:
if (myslot != to_slot) and \
(action not in new_actions):
new_actions.append(action)
found = True
break
if found:
continue
# if we get here it means found == False
# search into dependencies
dep_atoms = self.searchDependency(atom_key, like = True,
multi = True, strings = True)
dep_atoms = [x for x in dep_atoms if x.endswith(":"+from_slot) \
and self.entropyTools.dep_getkey(x) == atom_key]
if dep_atoms:
new_actions.append(action)
elif doaction[0] == "move":
atom = doaction[1] # usually a key
atom_key = self.entropyTools.dep_getkey(atom)
category = atom_key.split("/")[0]
matches = self.atomMatch(atom, multiMatch = True)
found = False
for idpackage in matches[0]:
mycategory = self.retrieveCategory(idpackage)
if (mycategory == category) and (action \
not in new_actions):
new_actions.append(action)
found = True
break
if found:
continue
# if we get here it means found == False
# search into dependencies
dep_atoms = self.searchDependency(atom_key, like = True,
multi = True, strings = True)
dep_atoms = [x for x in dep_atoms if \
self.entropyTools.dep_getkey(x) == atom_key]
if dep_atoms:
new_actions.append(action)
return new_actions
# this is the place to add extra actions support
def runTreeUpdatesActions(self, actions):
mytxt = "%s: %s, %s." % (
bold(_("SPM")),
blue(_("Running fixpackages")),
red(_("it could take a while")),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning",
header = darkred(" * ")
)
if self.clientDatabase:
try:
spm = self.ServiceInterface.Spm()
spm.run_fixpackages()
except:
pass
else:
self.ServiceInterface.SpmService.run_fixpackages()
spm_moves = set()
quickpkg_atoms = set()
for action in actions:
command = action.split()
mytxt = "%s: %s: %s." % (
bold(_("ENTROPY")),
red(_("action")),
blue(action),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning",
header = darkred(" * ")
)
if command[0] == "move":
spm_moves.add(action)
quickpkg_atoms |= self.runTreeUpdatesMoveAction(command[1:],
quickpkg_atoms)
elif command[0] == "slotmove":
quickpkg_atoms |= self.runTreeUpdatesSlotmoveAction(command[1:],
quickpkg_atoms)
if quickpkg_atoms and not self.clientDatabase:
# quickpkg package and packages owning it as a dependency
try:
self.runTreeUpdatesQuickpkgAction(quickpkg_atoms)
except:
self.entropyTools.print_traceback()
mytxt = "%s: %s: %s, %s." % (
bold(_("WARNING")),
red(_("Cannot complete quickpkg for atoms")),
blue(str(list(quickpkg_atoms))),
_("do it manually"),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning",
header = darkred(" * ")
)
self.commitChanges()
if spm_moves:
try:
self.doTreeupdatesSpmCleanup(spm_moves)
except Exception, e:
mytxt = "%s: %s: %s, %s." % (
bold(_("WARNING")),
red(_("Cannot run SPM cleanup, error")),
Exception,
e,
)
self.entropyTools.print_traceback()
# discard cache
self.clearCache()
# -- move action:
# 1) move package key to the new name: category + name + atom
# 2) update all the dependencies in dependenciesreference to the new key
# 3) run fixpackages which will update /var/db/pkg files
# 4) automatically run quickpkg() to build the new binary and
# tainted binaries owning tainted iddependency and taint database
def runTreeUpdatesMoveAction(self, move_command, quickpkg_queue):
key_from = move_command[0]
key_to = move_command[1]
cat_to = key_to.split("/")[0]
name_to = key_to.split("/")[1]
matches = self.atomMatch(key_from, multiMatch = True)
iddependencies = set()
for idpackage in matches[0]:
slot = self.retrieveSlot(idpackage)
old_atom = self.retrieveAtom(idpackage)
new_atom = old_atom.replace(key_from, key_to)
### UPDATE DATABASE
# update category
self.setCategory(idpackage, cat_to)
# update name
self.setName(idpackage, name_to)
# update atom
self.setAtom(idpackage, new_atom)
# look for packages we need to quickpkg again
# note: quickpkg_queue is simply ignored if self.clientDatabase
quickpkg_queue.add(key_to+":"+str(slot))
if not self.clientDatabase:
# check for injection and warn the developer
injected = self.isInjected(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.updateProgress(
mytxt,
importance = 1,
type = "warning",
header = darkred(" * ")
)
iddeps = self.searchDependency(key_from, like = True, multi = True)
for iddep in iddeps:
# update string
mydep = self.retrieveDependencyFromIddependency(iddep)
mydep_key = self.entropyTools.dep_getkey(mydep)
# avoid changing wrong atoms -> dev-python/qscintilla-python would
# become x11-libs/qscintilla if we don't do this check
if mydep_key != key_from:
continue
mydep = mydep.replace(key_from, key_to)
# now update
# dependstable on server is always re-generated
self.setDependency(iddep, mydep)
# we have to repackage also package owning this iddep
iddependencies |= self.searchIdpackageFromIddependency(iddep)
self.commitChanges()
quickpkg_queue = list(quickpkg_queue)
for x in range(len(quickpkg_queue)):
myatom = quickpkg_queue[x]
myatom = myatom.replace(key_from, key_to)
quickpkg_queue[x] = myatom
quickpkg_queue = set(quickpkg_queue)
for idpackage_owner in iddependencies:
myatom = self.retrieveAtom(idpackage_owner)
myatom = myatom.replace(key_from, key_to)
quickpkg_queue.add(myatom)
return quickpkg_queue
# -- slotmove action:
# 1) move package slot
# 2) update all the dependencies in dependenciesreference owning
# same matched atom + slot
# 3) run fixpackages which will update /var/db/pkg files
# 4) automatically run quickpkg() to build the new
# binary and tainted binaries owning tainted iddependency
# and taint database
def runTreeUpdatesSlotmoveAction(self, slotmove_command, quickpkg_queue):
atom = slotmove_command[0]
atomkey = self.entropyTools.dep_getkey(atom)
slot_from = slotmove_command[1]
slot_to = slotmove_command[2]
matches = self.atomMatch(atom, multiMatch = True)
iddependencies = set()
matched_idpackages = matches[0]
for idpackage in matched_idpackages:
### UPDATE DATABASE
# update slot
self.setSlot(idpackage, slot_to)
# look for packages we need to quickpkg again
# note: quickpkg_queue is simply ignored if self.clientDatabase
quickpkg_queue.add(atom+":"+str(slot_to))
if not self.clientDatabase:
# check for injection and warn the developer
injected = self.isInjected(idpackage)
if injected:
mytxt = "%s: %s %s. %s !!! %s." % (
bold(_("INJECT")),
blue(str(atom)),
red(_("has been injected")),
red(_("quickpkg manually to update embedded db")),
red(_("Repository database updated anyway")),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning",
header = darkred(" * ")
)
# only if we've found VALID matches !
iddeps = self.searchDependency(atomkey, like = True, multi = True)
for iddep in iddeps:
# update string
mydep = self.retrieveDependencyFromIddependency(iddep)
mydep_key = self.entropyTools.dep_getkey(mydep)
if mydep_key != atomkey:
continue
if not mydep.endswith(":"+slot_from): # probably slotted dep
continue
mydep_match = self.atomMatch(mydep)
if mydep_match not in matched_idpackages:
continue
mydep = mydep.replace(":"+slot_from, ":"+slot_to)
# now update
# dependstable on server is always re-generated
self.setDependency(iddep, mydep)
# we have to repackage also package owning this iddep
iddependencies |= self.searchIdpackageFromIddependency(iddep)
self.commitChanges()
for idpackage_owner in iddependencies:
myatom = self.retrieveAtom(idpackage_owner)
quickpkg_queue.add(myatom)
return quickpkg_queue
def runTreeUpdatesQuickpkgAction(self, atoms):
self.commitChanges()
package_paths = set()
runatoms = set()
for myatom in atoms:
mymatch = self.atomMatch(myatom)
if mymatch[0] == -1:
continue
myatom = self.retrieveAtom(mymatch[0])
runatoms.add(myatom)
for myatom in runatoms:
self.updateProgress(
red("%s: " % (_("repackaging"),) )+blue(myatom),
importance = 1,
type = "warning",
header = blue(" # ")
)
mydest = self.ServiceInterface.get_local_store_directory(
repo = self.server_repo)
try:
mypath = self.ServiceInterface.quickpkg(myatom, mydest)
except:
# remove broken bin before raising
mypath = os.path.join(mydest,
os.path.basename(myatom)+etpConst['packagesext'])
if os.path.isfile(mypath):
os.remove(mypath)
self.entropyTools.print_traceback()
mytxt = "%s: %s: %s, %s." % (
bold(_("WARNING")),
red(_("Cannot complete quickpkg for atom")),
blue(myatom),
_("do it manually"),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning",
header = darkred(" * ")
)
continue
package_paths.add(mypath)
packages_data = [(x, False,) for x in package_paths]
idpackages = self.ServiceInterface.add_packages_to_repository(
packages_data, repo = self.server_repo)
if not idpackages:
mytxt = "%s: %s. %s." % (
bold(_("ATTENTION")),
red(_("runTreeUpdatesQuickpkgAction did not run properly")),
red(_("Please update packages manually")),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning",
header = darkred(" * ")
)
def doTreeupdatesSpmCleanup(self, spm_moves):
# now erase Spm entries if necessary
for action in spm_moves:
command = action.split()
if len(command) < 2:
continue
key = command[1]
name = key.split("/")[1]
if self.clientDatabase:
try:
spm = self.ServiceInterface.Spm()
except:
continue
else:
spm = self.ServiceInterface.SpmService
vdb_path = spm.get_vdb_path()
pkg_path = os.path.join(vdb_path, key.split("/")[0])
try:
mydirs = [os.path.join(pkg_path, x) for x in \
os.listdir(pkg_path) if x.startswith(name)]
except OSError: # no dir, no party!
continue
mydirs = [x for x in mydirs if os.path.isdir(x)]
# now move these dirs
for mydir in mydirs:
to_path = os.path.join(etpConst['packagestmpdir'],
os.path.basename(mydir))
mytxt = "%s: %s '%s' %s '%s'" % (
bold(_("SPM")),
red(_("Moving old entry")),
blue(mydir),
red(_("to")),
blue(to_path),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning",
header = darkred(" * ")
)
if os.path.isdir(to_path):
shutil.rmtree(to_path, True)
try:
os.rmdir(to_path)
except OSError:
pass
shutil.move(mydir, to_path)
def handlePackage(self, etpData, forcedRevision = -1,
formattedContent = False):
self.checkReadOnly()
if self.clientDatabase:
return self.addPackage(etpData, revision = forcedRevision,
formatted_content = formattedContent)
# build atom string, server side
pkgatom = self.entropyTools.create_package_atom_string(
etpData['category'], etpData['name'], etpData['version'],
etpData['versiontag'])
foundid = self.isPackageAvailable(pkgatom)
if foundid < 0: # same atom doesn't exist in any branch
return self.addPackage(etpData, revision = forcedRevision,
formatted_content = formattedContent)
idpackage = self.getIDPackage(pkgatom)
curRevision = forcedRevision
if forcedRevision == -1:
curRevision = 0
if idpackage != -1:
curRevision = self.retrieveRevision(idpackage)
# remove old package atom, we do it here because othersie
if idpackage != -1:
# injected packages wouldn't be removed by addPackages
self.removePackage(idpackage)
if forcedRevision == -1: curRevision += 1
# add the new one
return self.addPackage(etpData, revision = curRevision,
formatted_content = formattedContent)
def retrieve_packages_to_remove(self, name, category, slot, injected):
removelist = set()
# support for expiration-based packages handling, also internally
# called Fat Scope.
filter_similar = False
srv_ss_plg = etpConst['system_settings_plugins_ids']['server_plugin']
srv_ss_fs_plg = \
etpConst['system_settings_plugins_ids']['server_plugin_fatscope']
if not self.clientDatabase: # server-side db
srv_plug_settings = self.SystemSettings.get(srv_ss_plg)
if srv_plug_settings != None:
if srv_plug_settings['server']['exp_based_scope']:
# in case support is enabled, return an empty set
filter_similar = True
searchsimilar = self.searchPackagesByNameAndCategory(
name = name,
category = category,
sensitive = True
)
if filter_similar:
# filter out packages in the same scope that are allowed to stay
idpkgs = self.SystemSettings[srv_ss_fs_plg]['repos'].get(
self.server_repo)
if idpkgs:
if -1 in idpkgs:
del searchsimilar[:]
else:
searchsimilar = [x for x in searchsimilar if x[1] \
not in idpkgs]
if not injected:
# read: if package has been injected, we'll skip
# the removal of packages in the same slot,
# usually used server side btw
for atom, idpackage in searchsimilar:
# get the package slot
myslot = self.retrieveSlot(idpackage)
# we merely ignore packages with
# negative counters, since they're the injected ones
if self.isInjected(idpackage): continue
if slot == myslot:
# remove!
removelist.add(idpackage)
return removelist
def addPackage(self, etpData, revision = -1, idpackage = None,
do_remove = True, do_commit = True, formatted_content = False):
self.checkReadOnly()
if revision == -1:
try:
revision = int(etpData['revision'])
except (KeyError, ValueError):
etpData['revision'] = 0 # revision not specified
revision = 0
elif not etpData.has_key('revision'):
etpData['revision'] = revision
manual_deps = set()
if do_remove:
removelist = self.retrieve_packages_to_remove(
etpData['name'],
etpData['category'],
etpData['slot'],
etpData['injected']
)
for r_idpackage in removelist:
manual_deps |= self.retrieveManualDependencies(r_idpackage)
self.removePackage(r_idpackage, do_cleanup = False,
do_commit = False)
# create new category if it doesn't exist
catid = self.isCategoryAvailable(etpData['category'])
if catid == -1: catid = self.addCategory(etpData['category'])
# create new license if it doesn't exist
licid = self.isLicenseAvailable(etpData['license'])
if licid == -1: licid = self.addLicense(etpData['license'])
idprotect = self.isProtectAvailable(etpData['config_protect'])
if idprotect == -1: idprotect = self.addProtect(
etpData['config_protect'])
idprotect_mask = self.isProtectAvailable(
etpData['config_protect_mask'])
if idprotect_mask == -1: idprotect_mask = self.addProtect(
etpData['config_protect_mask'])
idflags = self.areCompileFlagsAvailable(
etpData['chost'],etpData['cflags'],etpData['cxxflags'])
if idflags == -1: idflags = self.addCompileFlags(
etpData['chost'],etpData['cflags'],etpData['cxxflags'])
trigger = 0
if etpData['trigger']:
trigger = 1
# baseinfo
pkgatom = self.entropyTools.create_package_atom_string(
etpData['category'], etpData['name'], etpData['version'],
etpData['versiontag'])
# add atom metadatum
etpData['atom'] = pkgatom
mybaseinfo_data = (pkgatom, catid, etpData['name'], etpData['version'],
etpData['versiontag'], revision, etpData['branch'], etpData['slot'],
licid, etpData['etpapi'], trigger,)
myidpackage_string = 'NULL'
if isinstance(idpackage, int):
manual_deps |= self.retrieveManualDependencies(idpackage)
# does it exist?
self.removePackage(idpackage, do_cleanup = False,
do_commit = False, do_rss = False)
myidpackage_string = '?'
mybaseinfo_data = (idpackage,)+mybaseinfo_data
else:
idpackage = None
# merge old manual dependencies
for manual_dep in manual_deps:
if manual_dep in etpData['dependencies']: continue
etpData['dependencies'][manual_dep] = etpConst['spm']['mdepend_id']
with self.__write_mutex:
self.cursor.execute("""
INSERT into baseinfo VALUES (%s,?,?,?,?,?,?,?,?,?,?,?)""" % (
myidpackage_string,), mybaseinfo_data)
if idpackage == None:
idpackage = self.cursor.lastrowid
# extrainfo
self.cursor.execute(
'INSERT into extrainfo VALUES (?,?,?,?,?,?,?,?)',
( idpackage,
etpData['description'],
etpData['homepage'],
etpData['download'],
etpData['size'],
idflags,
etpData['digest'],
etpData['datecreation'],
)
)
### other information iserted below are not as critical as these above
# tables using a select
self.insertEclasses(idpackage, etpData['eclasses'])
self.insertNeeded(idpackage, etpData['needed'])
self.insertDependencies(idpackage, etpData['dependencies'])
self.insertSources(idpackage, etpData['sources'])
self.insertUseflags(idpackage, etpData['useflags'])
self.insertKeywords(idpackage, etpData['keywords'])
self.insertLicenses(etpData['licensedata'])
self.insertMirrors(etpData['mirrorlinks'])
# package ChangeLog
if etpData.get('changelog'):
self.insertChangelog(etpData['category'], etpData['name'],
etpData['changelog'])
# package signatures
if etpData.get('signatures'):
self.insertSignatures(idpackage, etpData['signatures'])
# spm phases
if etpData.get('spm_phases') != None:
self.insertSpmPhases(idpackage, etpData['spm_phases'])
# not depending on other tables == no select done
self.insertContent(idpackage, etpData['content'],
already_formatted = formatted_content)
etpData['counter'] = int(etpData['counter']) # cast to integer
etpData['counter'] = self.insertPortageCounter(
idpackage,
etpData['counter'],
etpData['branch'],
etpData['injected']
)
self.insertOnDiskSize(idpackage, etpData['disksize'])
if etpData['trigger']:
self.insertTrigger(idpackage, etpData['trigger'])
self.insertConflicts(idpackage, etpData['conflicts'])
self.insertProvide(idpackage, etpData['provide'])
self.insertMessages(idpackage, etpData['messages'])
self.insertConfigProtect(idpackage, idprotect)
self.insertConfigProtect(idpackage, idprotect_mask, mask = True)
# injected?
if etpData.get('injected'):
self.setInjected(idpackage, do_commit = False)
# is it a system package?
if etpData.get('systempackage'):
self.setSystemPackage(idpackage, do_commit = False)
self.clearCache() # we do live_cache.clear() here too
if do_commit:
self.commitChanges()
### RSS Atom support
### dictionary will be elaborated by activator
if self.SystemSettings.has_key(self.srv_sys_settings_plugin):
if self.SystemSettings[self.srv_sys_settings_plugin]['server']['rss']['enabled'] and \
not self.clientDatabase:
self._write_rss_for_added_package(pkgatom, revision,
etpData['description'], etpData['homepage'])
# Update category description
if not self.clientDatabase:
mycategory = etpData['category']
descdata = {}
try:
descdata = self.get_category_description_from_disk(mycategory)
except (IOError, OSError, EOFError,):
pass
if descdata:
self.setCategoryDescription(mycategory, descdata)
return idpackage, revision, etpData
def _write_rss_for_added_package(self, pkgatom, revision, description,
homepage):
rssAtom = pkgatom+"~"+str(revision)
rssObj = self.dumpTools.loadobj(etpConst['rss-dump-name'])
if rssObj: self.ServiceInterface.rssMessages = rssObj.copy()
if not isinstance(self.ServiceInterface.rssMessages, dict):
self.ServiceInterface.rssMessages = {}
if not self.ServiceInterface.rssMessages.has_key('added'):
self.ServiceInterface.rssMessages['added'] = {}
if not self.ServiceInterface.rssMessages.has_key('removed'):
self.ServiceInterface.rssMessages['removed'] = {}
if rssAtom in self.ServiceInterface.rssMessages['removed']:
del self.ServiceInterface.rssMessages['removed'][rssAtom]
self.ServiceInterface.rssMessages['added'][rssAtom] = {}
self.ServiceInterface.rssMessages['added'][rssAtom]['description'] = \
description
self.ServiceInterface.rssMessages['added'][rssAtom]['homepage'] = \
homepage
self.ServiceInterface.rssMessages['light'][rssAtom] = {}
self.ServiceInterface.rssMessages['light'][rssAtom]['description'] = \
description
self.dumpTools.dumpobj(etpConst['rss-dump-name'],
self.ServiceInterface.rssMessages)
def _write_rss_for_removed_package(self, idpackage):
rssObj = self.dumpTools.loadobj(etpConst['rss-dump-name'])
if rssObj: self.ServiceInterface.rssMessages = rssObj.copy()
rssAtom = self.retrieveAtom(idpackage)
rssRevision = self.retrieveRevision(idpackage)
rssAtom += "~"+str(rssRevision)
if not isinstance(self.ServiceInterface.rssMessages, dict):
self.ServiceInterface.rssMessages = {}
if not self.ServiceInterface.rssMessages.has_key('added'):
self.ServiceInterface.rssMessages['added'] = {}
if not self.ServiceInterface.rssMessages.has_key('removed'):
self.ServiceInterface.rssMessages['removed'] = {}
if rssAtom in self.ServiceInterface.rssMessages['added']:
del self.ServiceInterface.rssMessages['added'][rssAtom]
mydict = {}
try:
mydict['description'] = self.retrieveDescription(idpackage)
except TypeError:
mydict['description'] = "N/A"
try:
mydict['homepage'] = self.retrieveHomepage(idpackage)
except TypeError:
mydict['homepage'] = ""
self.dumpTools.dumpobj(etpConst['rss-dump-name'],
self.ServiceInterface.rssMessages)
self.ServiceInterface.rssMessages['removed'][rssAtom] = mydict
def removePackage(self, idpackage, do_cleanup = True, do_commit = True,
do_rss = True):
self.checkReadOnly()
# clear caches
self.clearCache()
### RSS Atom support
### dictionary will be elaborated by activator
if self.SystemSettings.has_key(self.srv_sys_settings_plugin):
if self.SystemSettings[self.srv_sys_settings_plugin]['server']['rss']['enabled'] and \
(not self.clientDatabase) and do_rss:
# store addPackage action
self._write_rss_for_removed_package(idpackage)
with self.__write_mutex:
r_tup = (idpackage,)*20
self.cursor.executescript("""
DELETE FROM baseinfo WHERE idpackage = %d;
DELETE FROM extrainfo WHERE idpackage = %d;
DELETE FROM dependencies WHERE idpackage = %d;
DELETE FROM provide WHERE idpackage = %d;
DELETE FROM conflicts WHERE idpackage = %d;
DELETE FROM configprotect WHERE idpackage = %d;
DELETE FROM configprotectmask WHERE idpackage = %d;
DELETE FROM sources WHERE idpackage = %d;
DELETE FROM useflags WHERE idpackage = %d;
DELETE FROM keywords WHERE idpackage = %d;
DELETE FROM content WHERE idpackage = %d;
DELETE FROM messages WHERE idpackage = %d;
DELETE FROM counters WHERE idpackage = %d;
DELETE FROM sizes WHERE idpackage = %d;
DELETE FROM eclasses WHERE idpackage = %d;
DELETE FROM needed WHERE idpackage = %d;
DELETE FROM triggers WHERE idpackage = %d;
DELETE FROM systempackages WHERE idpackage = %d;
DELETE FROM injected WHERE idpackage = %d;
DELETE FROM installedtable WHERE idpackage = %d;
""" % r_tup)
# not yet possible to add these calls above
try:
self.removeAutomergefiles(idpackage)
except self.dbapi2.OperationalError:
pass
try:
self.removeSignatures(idpackage)
except self.dbapi2.OperationalError:
pass
try:
self.removeSpmPhases(idpackage)
except self.dbapi2.OperationalError:
pass
# Remove from dependstable if exists
self.removePackageFromDependsTable(idpackage)
if do_cleanup:
# Cleanups if at least one package has been removed
self.doCleanups()
if do_commit:
self.commitChanges()
def removeMirrorEntries(self, mirrorname):
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM mirrorlinks WHERE mirrorname = (?)
""",(mirrorname,))
def addMirrors(self, mirrorname, mirrorlist):
with self.__write_mutex:
data = [(mirrorname, x,) for x in mirrorlist]
self.cursor.executemany("""
INSERT into mirrorlinks VALUES (?,?)
""", data)
def addCategory(self, category):
with self.__write_mutex:
self.cursor.execute("""
INSERT into categories VALUES (NULL,?)
""", (category,))
return self.cursor.lastrowid
def addProtect(self, protect):
with self.__write_mutex:
self.cursor.execute("""
INSERT into configprotectreference VALUES (NULL,?)
""", (protect,))
return self.cursor.lastrowid
def addSource(self, source):
with self.__write_mutex:
self.cursor.execute("""
INSERT into sourcesreference VALUES (NULL,?)
""", (source,))
return self.cursor.lastrowid
def addDependency(self, dependency):
with self.__write_mutex:
self.cursor.execute('INSERT into dependenciesreference VALUES (NULL,?)', (dependency,))
return self.cursor.lastrowid
def addKeyword(self, keyword):
with self.__write_mutex:
self.cursor.execute('INSERT into keywordsreference VALUES (NULL,?)', (keyword,))
return self.cursor.lastrowid
def addUseflag(self, useflag):
with self.__write_mutex:
self.cursor.execute('INSERT into useflagsreference VALUES (NULL,?)', (useflag,))
return self.cursor.lastrowid
def addEclass(self, eclass):
with self.__write_mutex:
self.cursor.execute('INSERT into eclassesreference VALUES (NULL,?)', (eclass,))
return self.cursor.lastrowid
def addNeeded(self, needed):
with self.__write_mutex:
self.cursor.execute('INSERT into neededreference VALUES (NULL,?)', (needed,))
return self.cursor.lastrowid
def addLicense(self, pkglicense):
if not self.entropyTools.is_valid_string(pkglicense):
pkglicense = ' ' # workaround for broken license entries
with self.__write_mutex:
self.cursor.execute('INSERT into licenses VALUES (NULL,?)', (pkglicense,))
return self.cursor.lastrowid
def addCompileFlags(self, chost, cflags, cxxflags):
with self.__write_mutex:
self.cursor.execute('INSERT into flags VALUES (NULL,?,?,?)', (chost,cflags,cxxflags,))
return self.cursor.lastrowid
def setSystemPackage(self, idpackage, do_commit = True):
with self.__write_mutex:
self.cursor.execute('INSERT into systempackages VALUES (?)', (idpackage,))
if do_commit:
self.commitChanges()
def setInjected(self, idpackage, do_commit = True):
with self.__write_mutex:
if not self.isInjected(idpackage):
self.cursor.execute('INSERT into injected VALUES (?)', (idpackage,))
if do_commit:
self.commitChanges()
# date expressed the unix way
def setDateCreation(self, idpackage, date):
with self.__write_mutex:
self.cursor.execute('UPDATE extrainfo SET datecreation = (?) WHERE idpackage = (?)', (str(date), idpackage,))
self.commitChanges()
def setDigest(self, idpackage, digest):
with self.__write_mutex:
self.cursor.execute('UPDATE extrainfo SET digest = (?) WHERE idpackage = (?)', (digest, idpackage,))
self.commitChanges()
def setSignatures(self, idpackage, signatures):
with self.__write_mutex:
sha1, sha256, sha512 = signatures['sha1'], signatures['sha256'], \
signatures['sha512']
self.cursor.execute("""
UPDATE packagesignatures SET sha1 = (?), sha256 = (?), sha512 = (?)
WHERE idpackage = (?)
""", (sha1, sha256, sha512, idpackage))
def setDownloadURL(self, idpackage, url):
with self.__write_mutex:
self.cursor.execute('UPDATE extrainfo SET download = (?) WHERE idpackage = (?)', (url, idpackage,))
self.commitChanges()
def setCategory(self, idpackage, category):
# create new category if it doesn't exist
catid = self.isCategoryAvailable(category)
if (catid == -1):
# create category
catid = self.addCategory(category)
with self.__write_mutex:
self.cursor.execute('UPDATE baseinfo SET idcategory = (?) WHERE idpackage = (?)', (catid, idpackage,))
self.commitChanges()
def setCategoryDescription(self, category, description_data):
with self.__write_mutex:
self.cursor.execute('DELETE FROM categoriesdescription WHERE category = (?)', (category,))
for locale in description_data:
mydesc = description_data[locale]
#if type(mydesc) is unicode:
# mydesc = mydesc.encode('raw_unicode_escape')
self.cursor.execute('INSERT INTO categoriesdescription VALUES (?,?,?)', (category, locale, mydesc,))
self.commitChanges()
def setName(self, idpackage, name):
with self.__write_mutex:
self.cursor.execute('UPDATE baseinfo SET name = (?) WHERE idpackage = (?)', (name, idpackage,))
self.commitChanges()
def setDependency(self, iddependency, dependency):
with self.__write_mutex:
self.cursor.execute('UPDATE dependenciesreference SET dependency = (?) WHERE iddependency = (?)', (dependency, iddependency,))
self.commitChanges()
def setAtom(self, idpackage, atom):
with self.__write_mutex:
self.cursor.execute('UPDATE baseinfo SET atom = (?) WHERE idpackage = (?)', (atom, idpackage,))
self.commitChanges()
def setSlot(self, idpackage, slot):
with self.__write_mutex:
self.cursor.execute('UPDATE baseinfo SET slot = (?) WHERE idpackage = (?)', (slot, idpackage,))
self.commitChanges()
def removeLicensedata(self, license_name):
if not self.doesTableExist("licensedata"):
return
with self.__write_mutex:
self.cursor.execute('DELETE FROM licensedata WHERE licensename = (?)', (license_name,))
def removeDependencies(self, idpackage):
with self.__write_mutex:
self.cursor.execute("DELETE FROM dependencies WHERE idpackage = (?)", (idpackage,))
self.commitChanges()
def insertDependencies(self, idpackage, depdata):
dcache = set()
add_dep = self.addDependency
is_dep_avail = self.isDependencyAvailable
def mymf(dep):
if dep in dcache: return 0
iddep = is_dep_avail(dep)
if iddep == -1: iddep = add_dep(dep)
deptype = 0
if isinstance(depdata, dict):
deptype = depdata[dep]
dcache.add(dep)
return (idpackage, iddep, deptype,)
# do not place inside the with statement, otherwise there'll be an obvious lockup
deps = [x for x in map(mymf, depdata) if type(x) != int]
with self.__write_mutex:
self.cursor.executemany('INSERT into dependencies VALUES (?,?,?)', deps)
def insertManualDependencies(self, idpackage, manual_deps):
mydict = {}
for manual_dep in manual_deps:
mydict[manual_dep] = etpConst['spm']['mdepend_id']
return self.insertDependencies(idpackage, mydict)
def removeContent(self, idpackage):
with self.__write_mutex:
self.cursor.execute("DELETE FROM content WHERE idpackage = (?)", (idpackage,))
self.commitChanges()
def insertContent(self, idpackage, content, already_formatted = False):
with self.__write_mutex:
if already_formatted:
self.cursor.executemany('INSERT INTO content VALUES (?,?,?)',((idpackage, x, y,) for a, x, y in content))
return
def my_cmap(xfile):
return (idpackage, xfile, content[xfile],)
self.cursor.executemany('INSERT INTO content VALUES (?,?,?)',map(my_cmap, content))
def insertAutomergefiles(self, idpackage, automerge_data):
with self.__write_mutex:
self.cursor.executemany('INSERT INTO automergefiles VALUES (?,?,?)',
((idpackage, x, y,) for x, y in automerge_data))
def removeAutomergefiles(self, idpackage):
with self.__write_mutex:
self.cursor.execute('DELETE FROM automergefiles WHERE idpackage = (?)', (idpackage,))
def removeSignatures(self, idpackage):
with self.__write_mutex:
self.cursor.execute('DELETE FROM packagesignatures WHERE idpackage = (?)', (idpackage,))
def removeSpmPhases(self, idpackage):
with self.__write_mutex:
self.cursor.execute('DELETE FROM packagespmphases WHERE idpackage = (?)', (idpackage,))
def insertChangelog(self, category, name, changelog_txt):
with self.__write_mutex:
mytxt = changelog_txt.encode('raw_unicode_escape')
self.cursor.execute('DELETE FROM packagechangelogs WHERE category = (?) AND name = (?)', (category, name,))
self.cursor.execute('INSERT INTO packagechangelogs VALUES (?,?,?)', (category, name, buffer(mytxt),))
def removeChangelog(self, category, name):
with self.__write_mutex:
self.cursor.execute('DELETE FROM packagechangelogs WHERE category = (?) AND name = (?)', (category, name,))
def insertLicenses(self, licenses_data):
mylicenses = licenses_data.keys()
is_lic_avail = self.isLicensedataKeyAvailable
def my_mf(mylicense):
return not is_lic_avail(mylicense)
def my_mm(mylicense):
lic_data = licenses_data.get(mylicense,'')
# support both utf8 and str input
if isinstance(lic_data, unicode): # encode to str
try:
lic_data = lic_data.encode('raw_unicode_escape')
except (UnicodeDecodeError,):
lic_data = lic_data.encode('utf-8')
return (mylicense, buffer(lic_data), 0,)
with self.__write_mutex:
self.cursor.executemany('INSERT into licensedata VALUES (?,?,?)',map(my_mm, list(set(filter(my_mf, mylicenses)))))
def insertConfigProtect(self, idpackage, idprotect, mask = False):
mytable = 'configprotect'
if mask: mytable += 'mask'
with self.__write_mutex:
self.cursor.execute('INSERT into %s VALUES (?,?)' % (mytable,), (idpackage, idprotect,))
def insertMirrors(self, mirrors):
for mirrorname, mirrorlist in mirrors:
# remove old
self.removeMirrorEntries(mirrorname)
# add new
self.addMirrors(mirrorname, mirrorlist)
def insertKeywords(self, idpackage, keywords):
mydata = set()
for key in keywords:
idkeyword = self.isKeywordAvailable(key)
if (idkeyword == -1):
# create category
idkeyword = self.addKeyword(key)
mydata.add((idpackage, idkeyword,))
with self.__write_mutex:
self.cursor.executemany('INSERT into keywords VALUES (?,?)', mydata)
def insertUseflags(self, idpackage, useflags):
mydata = set()
for flag in useflags:
iduseflag = self.isUseflagAvailable(flag)
if (iduseflag == -1):
# create category
iduseflag = self.addUseflag(flag)
mydata.add((idpackage, iduseflag,))
with self.__write_mutex:
self.cursor.executemany('INSERT into useflags VALUES (?,?)', mydata)
def insertSignatures(self, idpackage, signatures):
with self.__write_mutex:
sha1, sha256, sha512 = signatures['sha1'], signatures['sha256'], \
signatures['sha512']
self.cursor.execute("""
INSERT INTO packagesignatures VALUES (?,?,?,?)
""", (idpackage, sha1, sha256, sha512))
def insertSpmPhases(self, idpackage, phases):
with self.__write_mutex:
self.cursor.execute("""
INSERT INTO packagespmphases VALUES (?,?)
""", (idpackage,phases,))
def insertSources(self, idpackage, sources):
mydata = set()
for source in sources:
if (not source) or (source == "") or (not self.entropyTools.is_valid_string(source)):
continue
idsource = self.isSourceAvailable(source)
if (idsource == -1):
# create category
idsource = self.addSource(source)
mydata.add((idpackage, idsource,))
with self.__write_mutex:
self.cursor.executemany('INSERT into sources VALUES (?,?)', mydata)
def insertConflicts(self, idpackage, conflicts):
def myiter():
for conflict in conflicts:
yield (idpackage, conflict,)
with self.__write_mutex:
self.cursor.executemany('INSERT into conflicts VALUES (?,?)', myiter())
def insertMessages(self, idpackage, messages):
def myiter():
for message in messages:
yield (idpackage, message,)
with self.__write_mutex:
self.cursor.executemany('INSERT into messages VALUES (?,?)', myiter())
def insertProvide(self, idpackage, provides):
def myiter():
for atom in provides:
yield (idpackage, atom,)
with self.__write_mutex:
self.cursor.executemany('INSERT into provide VALUES (?,?)', myiter())
def insertNeeded(self, idpackage, neededs):
mydata = set()
for needed, elfclass in neededs:
idneeded = self.isNeededAvailable(needed)
if idneeded == -1:
# create eclass
idneeded = self.addNeeded(needed)
mydata.add((idpackage, idneeded, elfclass))
with self.__write_mutex:
self.cursor.executemany('INSERT into needed VALUES (?,?,?)', mydata)
def insertEclasses(self, idpackage, eclasses):
mydata = set()
for eclass in eclasses:
idclass = self.isEclassAvailable(eclass)
if (idclass == -1):
# create eclass
idclass = self.addEclass(eclass)
mydata.add((idpackage, idclass,))
with self.__write_mutex:
self.cursor.executemany('INSERT into eclasses VALUES (?,?)', mydata)
def insertOnDiskSize(self, idpackage, mysize):
with self.__write_mutex:
self.cursor.execute('INSERT into sizes VALUES (?,?)', (idpackage, mysize,))
def insertTrigger(self, idpackage, trigger):
with self.__write_mutex:
self.cursor.execute('INSERT into triggers VALUES (?,?)', (idpackage, buffer(trigger),))
def insertPortageCounter(self, idpackage, counter, branch, injected):
if (counter != -1) and not injected:
if counter <= -2:
# special cases
counter = self.getNewNegativeCounter()
with self.__write_mutex:
try:
self.cursor.execute(
'INSERT into counters VALUES '
'(?,?,?)'
, ( counter,
idpackage,
branch,
)
)
except self.dbapi2.IntegrityError: # we have a PRIMARY KEY we need to remove
self._migrateCountersTable()
self.cursor.execute(
'INSERT into counters VALUES '
'(?,?,?)'
, ( counter,
idpackage,
branch,
)
)
except:
if self.dbname == etpConst['clientdbid']: # force only for client database
if self.doesTableExist("counters"):
raise
self.cursor.execute(
'INSERT into counters VALUES '
'(?,?,?)'
, ( counter,
idpackage,
branch,
)
)
elif self.dbname.startswith(etpConst['serverdbid']):
raise
return counter
def insertCounter(self, idpackage, counter, branch = None):
if not branch: branch = self.db_branch
if not branch: branch = self.SystemSettings['repositories']['branch']
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM counters
WHERE (counter = (?) OR
idpackage = (?)) AND
branch = (?)""", (counter, idpackage, branch,))
self.cursor.execute('INSERT INTO counters VALUES (?,?,?)', (counter, idpackage, branch,))
self.commitChanges()
def setTrashedCounter(self, counter):
with self.__write_mutex:
self.cursor.execute('DELETE FROM trashedcounters WHERE counter = (?)', (counter,))
self.cursor.execute('INSERT INTO trashedcounters VALUES (?)', (counter,))
self.commitChanges()
def setCounter(self, idpackage, counter, branch = None):
branchstring = ''
insertdata = [counter, idpackage]
if branch:
branchstring = ', branch = (?)'
insertdata.insert(1, branch)
with self.__write_mutex:
try:
self.cursor.execute('UPDATE counters SET counter = (?) '+branchstring+' WHERE idpackage = (?)', insertdata)
self.commitChanges()
except:
if self.dbname == etpConst['clientdbid']:
raise
def contentDiff(self, idpackage, dbconn, dbconn_idpackage):
self.connection.text_factory = lambda x: unicode(x, "raw_unicode_escape")
# create a random table and fill
randomtable = "cdiff%s" % (self.entropyTools.get_random_number(),)
while self.doesTableExist(randomtable):
randomtable = "cdiff%s" % (self.entropyTools.get_random_number(),)
self.cursor.execute('CREATE TEMPORARY TABLE %s ( file VARCHAR )' % (randomtable,))
try:
dbconn.connection.text_factory = lambda x: unicode(x, "raw_unicode_escape")
dbconn.cursor.execute('select file from content where idpackage = (?)', (dbconn_idpackage,))
xfile = dbconn.cursor.fetchone()
while xfile:
self.cursor.execute('INSERT INTO %s VALUES (?)' % (randomtable,), (xfile[0],))
xfile = dbconn.cursor.fetchone()
# now compare
self.cursor.execute("""
SELECT file FROM content
WHERE content.idpackage = (?) AND
content.file NOT IN (SELECT file from %s)""" % (randomtable,), (idpackage,))
diff = self.fetchall2set(self.cursor.fetchall())
return diff
finally:
self.cursor.execute('DROP TABLE IF EXISTS %s' % (randomtable,))
def doCleanups(self):
self.cleanupUseflags()
self.cleanupSources()
self.cleanupEclasses()
self.cleanupNeeded()
self.cleanupDependencies()
self.cleanupChangelogs()
def cleanupUseflags(self):
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM useflagsreference
WHERE idflag NOT IN (SELECT idflag FROM useflags)""")
def cleanupSources(self):
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM sourcesreference
WHERE idsource NOT IN (SELECT idsource FROM sources)""")
def cleanupEclasses(self):
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM eclassesreference
WHERE idclass NOT IN (SELECT idclass FROM eclasses)""")
def cleanupNeeded(self):
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM neededreference
WHERE idneeded NOT IN (SELECT idneeded FROM needed)""")
def cleanupDependencies(self):
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM dependenciesreference
WHERE iddependency NOT IN (SELECT iddependency FROM dependencies)""")
def cleanupChangelogs(self):
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM packagechangelogs
WHERE category || "/" || name NOT IN
(SELECT categories.category || "/" || baseinfo.name FROM baseinfo,categories
WHERE baseinfo.idcategory = categories.idcategory
)""")
def getNewNegativeCounter(self):
counter = -2
try:
self.cursor.execute('SELECT min(counter) FROM counters')
dbcounter = self.cursor.fetchone()
mycounter = 0
if dbcounter:
mycounter = dbcounter[0]
if mycounter >= -1:
counter = -2
else:
counter = mycounter-1
except:
pass
return counter
def getApi(self):
self.cursor.execute('SELECT max(etpapi) FROM baseinfo')
api = self.cursor.fetchone()
if api: api = api[0]
else: api = -1
return api
def getCategory(self, idcategory):
self.cursor.execute('SELECT category from categories WHERE idcategory = (?)', (idcategory,))
cat = self.cursor.fetchone()
if cat: cat = cat[0]
return cat
def get_category_description_from_disk(self, category):
if not self.ServiceInterface:
return {}
return self.ServiceInterface.SpmService.get_category_description_data(category)
def getIDPackage(self, atom, branch = None):
branch_string = ''
params = [atom]
if branch:
branch_string = ' AND branch = (?)'
params.append(branch)
self.cursor.execute('SELECT idpackage FROM baseinfo WHERE atom = (?)'+branch_string, params)
idpackage = self.cursor.fetchone()
if idpackage: return idpackage[0]
return -1
def getIDPackageFromDownload(self, download_relative_path, endswith = False):
if endswith:
self.cursor.execute("""
SELECT baseinfo.idpackage FROM baseinfo,extrainfo
WHERE extrainfo.download LIKE (?)""", ("%"+download_relative_path,))
else:
self.cursor.execute("""
SELECT baseinfo.idpackage FROM baseinfo,extrainfo
WHERE extrainfo.download = (?)""", (download_relative_path,))
idpackage = self.cursor.fetchone()
if idpackage: return idpackage[0]
return -1
def getIDPackagesFromFile(self, file):
self.cursor.execute('SELECT idpackage FROM content WHERE file = (?)', (file,))
return self.fetchall2list(self.cursor.fetchall())
def getIDCategory(self, category):
self.cursor.execute('SELECT "idcategory" FROM categories WHERE category = (?)', (category,))
idcat = self.cursor.fetchone()
if idcat: return idcat[0]
return -1
def getVersioningData(self, idpackage):
self.cursor.execute('SELECT version,versiontag,revision FROM baseinfo WHERE idpackage = (?)', (idpackage,))
return self.cursor.fetchone()
def getStrictData(self, idpackage):
self.cursor.execute("""
SELECT categories.category || "/" || baseinfo.name,
baseinfo.slot,baseinfo.version,baseinfo.versiontag,
baseinfo.revision,baseinfo.atom FROM baseinfo,categories
WHERE baseinfo.idpackage = (?) AND
baseinfo.idcategory = categories.idcategory""", (idpackage,))
return self.cursor.fetchone()
def getStrictScopeData(self, idpackage):
self.cursor.execute("""
SELECT atom,slot,revision FROM baseinfo
WHERE idpackage = (?)""", (idpackage,))
rslt = self.cursor.fetchone()
return rslt
def getScopeData(self, idpackage):
self.cursor.execute("""
SELECT
baseinfo.atom,
categories.category,
baseinfo.name,
baseinfo.version,
baseinfo.slot,
baseinfo.versiontag,
baseinfo.revision,
baseinfo.branch,
baseinfo.etpapi
FROM
baseinfo,
categories
WHERE
baseinfo.idpackage = (?)
and baseinfo.idcategory = categories.idcategory
""", (idpackage,))
return self.cursor.fetchone()
def getBaseData(self, idpackage):
sql = """
SELECT
baseinfo.atom,
baseinfo.name,
baseinfo.version,
baseinfo.versiontag,
extrainfo.description,
categories.category,
flags.chost,
flags.cflags,
flags.cxxflags,
extrainfo.homepage,
licenses.license,
baseinfo.branch,
extrainfo.download,
extrainfo.digest,
baseinfo.slot,
baseinfo.etpapi,
extrainfo.datecreation,
extrainfo.size,
baseinfo.revision
FROM
baseinfo,
extrainfo,
categories,
flags,
licenses
WHERE
baseinfo.idpackage = (?)
and baseinfo.idpackage = extrainfo.idpackage
and baseinfo.idcategory = categories.idcategory
and extrainfo.idflags = flags.idflags
and baseinfo.idlicense = licenses.idlicense
"""
self.cursor.execute(sql, (idpackage,))
return self.cursor.fetchone()
def getTriggerInfo(self, idpackage):
atom, category, name, \
version, slot, versiontag, \
revision, branch, etpapi = self.getScopeData(idpackage)
chost, cflags, cxxflags = self.retrieveCompileFlags(idpackage)
data = {
'atom': atom,
'category': category,
'name': name,
'version': version,
'versiontag': versiontag,
'revision': revision,
'branch': branch,
'chost': chost,
'cflags': cflags,
'cxxflags': cxxflags,
'etpapi': etpapi,
'trigger': self.retrieveTrigger(idpackage),
'eclasses': self.retrieveEclasses(idpackage),
'content': self.retrieveContent(idpackage),
'spm_phases': self.retrieveSpmPhases(idpackage),
}
return data
def getPackageData(self, idpackage, get_content = True,
content_insert_formatted = False, trigger_unicode = True):
data = {}
try:
atom, name, version, versiontag, \
description, category, chost, \
cflags, cxxflags,homepage, \
mylicense, branch, download, \
digest, slot, etpapi, \
datecreation, size, revision = self.getBaseData(idpackage)
except TypeError:
return None
content = {}
if get_content:
content = self.retrieveContent(
idpackage, extended = True,
formatted = True, insert_formatted = content_insert_formatted
)
sources = self.retrieveSources(idpackage)
mirrornames = set()
for x in sources:
if x.startswith("mirror://"):
mirrornames.add(x.split("/")[2])
data = {
'atom': atom,
'name': name,
'version': version,
'versiontag':versiontag,
'description': description,
'category': category,
'chost': chost,
'cflags': cflags,
'cxxflags': cxxflags,
'homepage': homepage,
'license': mylicense,
'branch': branch,
'download': download,
'digest': digest,
'slot': slot,
'etpapi': etpapi,
'datecreation': datecreation,
'size': size,
'revision': revision,
# risky to add to the sql above, still
'counter': self.retrieveCounter(idpackage),
'messages': self.retrieveMessages(idpackage),
'trigger': self.retrieveTrigger(idpackage, get_unicode = trigger_unicode),
'disksize': self.retrieveOnDiskSize(idpackage),
'changelog': self.retrieveChangelog(idpackage),
'injected': self.isInjected(idpackage),
'systempackage': self.isSystemPackage(idpackage),
'config_protect': self.retrieveProtect(idpackage),
'config_protect_mask': self.retrieveProtectMask(idpackage),
'useflags': self.retrieveUseflags(idpackage),
'keywords': self.retrieveKeywords(idpackage),
'sources': sources,
'eclasses': self.retrieveEclasses(idpackage),
'needed': self.retrieveNeeded(idpackage, extended = True),
'provide': self.retrieveProvide(idpackage),
'conflicts': self.retrieveConflicts(idpackage),
'licensedata': self.retrieveLicensedata(idpackage),
'content': content,
'dependencies': dict((x, y,) for x, y in \
self.retrieveDependencies(idpackage, extended = True)),
'mirrorlinks': [[x,self.retrieveMirrorInfo(x)] for x in mirrornames],
'signatures': self.retrieveSignatures(idpackage),
'spm_phases': self.retrieveSpmPhases(idpackage),
}
return data
def fetchall2set(self, item):
mycontent = set()
for x in item:
mycontent |= set(x)
return mycontent
def fetchall2list(self, item):
content = []
for x in item:
content += list(x)
return content
def fetchone2list(self, item):
return list(item)
def fetchone2set(self, item):
return set(item)
def clearCache(self, depends = False):
self.live_cache.clear()
def do_clear(name):
dump_path = os.path.join(etpConst['dumpstoragedir'], name)
dump_dir = os.path.dirname(dump_path)
if os.path.isdir(dump_dir):
for item in os.listdir(dump_dir):
try: os.remove(os.path.join(dump_dir, item))
except OSError: pass
do_clear("%s/%s/" % (self.dbMatchCacheKey, self.dbname,))
do_clear("%s/%s/" % (self.dbSearchCacheKey, self.dbname,))
if depends:
do_clear(etpCache['depends_tree'])
do_clear(etpCache['dep_tree'])
do_clear(etpCache['filter_satisfied_deps'])
def fetchSearchCache(self, key, function, extra_hash = 0):
if self.xcache:
c_hash = "%s/%s/%s/%s" % (self.dbSearchCacheKey, self.dbname, key, "%s%s" % (hash(function), extra_hash,),)
cached = self.Cacher.pop(c_hash)
if cached != None: return cached
def storeSearchCache(self, key, function, search_cache_data, extra_hash = 0):
if self.xcache:
c_hash = "%s/%s/%s/%s" % (self.dbSearchCacheKey, self.dbname, key, "%s%s" % (hash(function), extra_hash,),)
self.Cacher.push(c_hash, search_cache_data)
def retrieveRepositoryUpdatesDigest(self, repository):
if not self.doesTableExist("treeupdates"):
return -1
self.cursor.execute('SELECT digest FROM treeupdates WHERE repository = (?)', (repository,))
mydigest = self.cursor.fetchone()
if mydigest:
return mydigest[0]
else:
return -1
def listAllTreeUpdatesActions(self, no_ids_repos = False):
if no_ids_repos:
self.cursor.execute('SELECT command,branch,date FROM treeupdatesactions')
else:
self.cursor.execute('SELECT * FROM treeupdatesactions')
return self.cursor.fetchall()
def retrieveTreeUpdatesActions(self, repository, forbranch = None):
if not self.doesTableExist("treeupdatesactions"): return []
if forbranch == None: forbranch = self.db_branch
params = [repository]
branch_string = ''
if forbranch:
branch_string = 'and branch = (?)'
params.append(forbranch)
self.cursor.execute("""
SELECT command FROM treeupdatesactions WHERE
repository = (?) %s order by date""" % (branch_string,), params)
return self.fetchall2list(self.cursor.fetchall())
# mainly used to restore a previous table, used by reagent in --initialize
def bumpTreeUpdatesActions(self, updates):
with self.__write_mutex:
self.cursor.execute('DELETE FROM treeupdatesactions')
self.cursor.executemany('INSERT INTO treeupdatesactions VALUES (?,?,?,?,?)', updates)
self.commitChanges()
def removeTreeUpdatesActions(self, repository):
with self.__write_mutex:
self.cursor.execute('DELETE FROM treeupdatesactions WHERE repository = (?)', (repository,))
self.commitChanges()
def insertTreeUpdatesActions(self, updates, repository):
with self.__write_mutex:
myupdates = [[repository]+list(x) for x in updates]
self.cursor.executemany('INSERT INTO treeupdatesactions VALUES (NULL,?,?,?,?)', myupdates)
self.commitChanges()
def setRepositoryUpdatesDigest(self, repository, digest):
with self.__write_mutex:
self.cursor.execute('DELETE FROM treeupdates where repository = (?)', (repository,)) # doing it for safety
self.cursor.execute('INSERT INTO treeupdates VALUES (?,?)', (repository, digest,))
def addRepositoryUpdatesActions(self, repository, actions, branch):
mytime = str(self.entropyTools.get_current_unix_time())
with self.__write_mutex:
myupdates = [
(repository, x, branch, mytime,) for x in actions \
if not self.doesTreeupdatesActionExist(repository, x, branch)
]
self.cursor.executemany('INSERT INTO treeupdatesactions VALUES (NULL,?,?,?,?)', myupdates)
def doesTreeupdatesActionExist(self, repository, command, branch):
self.cursor.execute("""
SELECT * FROM treeupdatesactions
WHERE repository = (?) and command = (?) and branch = (?)""", (repository, command, branch,))
result = self.cursor.fetchone()
if result:
return True
return False
def clearPackageSets(self):
self.cursor.execute('DELETE FROM packagesets')
def insertPackageSets(self, sets_data):
mysets = []
for setname in sorted(sets_data.keys()):
for dependency in sorted(sets_data[setname]):
try:
mysets.append((unicode(setname), unicode(dependency),))
except (UnicodeDecodeError, UnicodeEncodeError,):
continue
with self.__write_mutex:
self.cursor.executemany('INSERT INTO packagesets VALUES (?,?)', mysets)
def retrievePackageSets(self):
if not self.doesTableExist("packagesets"): return {}
self.cursor.execute('SELECT setname,dependency FROM packagesets')
data = self.cursor.fetchall()
sets = {}
for setname, dependency in data:
if not sets.has_key(setname):
sets[setname] = set()
sets[setname].add(dependency)
return sets
def retrievePackageSet(self, setname):
self.cursor.execute('SELECT dependency FROM packagesets WHERE setname = (?)', (setname,))
return self.fetchall2set(self.cursor.fetchall())
def retrieveSystemPackages(self):
self.cursor.execute('SELECT idpackage FROM systempackages')
return self.fetchall2set(self.cursor.fetchall())
def retrieveAtom(self, idpackage):
self.cursor.execute('SELECT atom FROM baseinfo WHERE idpackage = (?)', (idpackage,))
atom = self.cursor.fetchone()
if atom: return atom[0]
def retrieveBranch(self, idpackage):
self.cursor.execute('SELECT branch FROM baseinfo WHERE idpackage = (?)', (idpackage,))
br = self.cursor.fetchone()
if br: return br[0]
def retrieveTrigger(self, idpackage, get_unicode = False):
self.cursor.execute('SELECT data FROM triggers WHERE idpackage = (?)', (idpackage,))
trigger = self.cursor.fetchone()
if not trigger:
return '' # FIXME backward compatibility with <=0.52.x
if not get_unicode:
return trigger[0]
return unicode(trigger[0], 'raw_unicode_escape')
def retrieveDownloadURL(self, idpackage):
self.cursor.execute('SELECT download FROM extrainfo WHERE idpackage = (?)', (idpackage,))
download = self.cursor.fetchone()
if download: return download[0]
def retrieveDescription(self, idpackage):
self.cursor.execute('SELECT description FROM extrainfo WHERE idpackage = (?)', (idpackage,))
description = self.cursor.fetchone()
if description: return description[0]
def retrieveHomepage(self, idpackage):
self.cursor.execute('SELECT homepage FROM extrainfo WHERE idpackage = (?)', (idpackage,))
home = self.cursor.fetchone()
if home: return home[0]
def retrieveCounter(self, idpackage):
self.cursor.execute("""
SELECT counters.counter FROM counters,baseinfo
WHERE counters.idpackage = (?) AND
baseinfo.idpackage = counters.idpackage AND
baseinfo.branch = counters.branch""", (idpackage,))
mycounter = self.cursor.fetchone()
if mycounter: return mycounter[0]
return -1
def retrieveMessages(self, idpackage):
self.cursor.execute('SELECT message FROM messages WHERE idpackage = (?)', (idpackage,))
return self.fetchall2list(self.cursor.fetchall())
# in bytes
def retrieveSize(self, idpackage):
self.cursor.execute('SELECT size FROM extrainfo WHERE idpackage = (?)', (idpackage,))
size = self.cursor.fetchone()
if size: return size[0]
# in bytes
def retrieveOnDiskSize(self, idpackage):
self.cursor.execute('SELECT size FROM sizes WHERE idpackage = (?)', (idpackage,))
size = self.cursor.fetchone() # do not use [0]!
if not size: size = 0
else: size = size[0]
return size
def retrieveDigest(self, idpackage):
self.cursor.execute('SELECT digest FROM extrainfo WHERE idpackage = (?)', (idpackage,))
digest = self.cursor.fetchone()
if digest: return digest[0]
def retrieveSignatures(self, idpackage):
mydict = {
'sha1': None,
'sha256': None,
'sha512': None,
}
# FIXME: remove this check in future
if self.doesTableExist('packagesignatures'):
self.cursor.execute("""
SELECT sha1, sha256, sha512 FROM packagesignatures
WHERE idpackage = (?)""", (idpackage,))
data = self.cursor.fetchone()
if data:
mydict['sha1'], mydict['sha256'], mydict['sha512'] = data
return mydict
def retrieveName(self, idpackage):
self.cursor.execute('SELECT name FROM baseinfo WHERE idpackage = (?)', (idpackage,))
name = self.cursor.fetchone()
if name: return name[0]
def retrieveKeySlot(self, idpackage):
self.cursor.execute("""
SELECT categories.category || "/" || baseinfo.name,baseinfo.slot FROM baseinfo,categories
WHERE baseinfo.idpackage = (?) and baseinfo.idcategory = categories.idcategory""", (idpackage,))
data = self.cursor.fetchone()
return data
def retrieveKeySlotAggregated(self, idpackage):
self.cursor.execute("""
SELECT categories.category || "/" || baseinfo.name || ":" || baseinfo.slot FROM baseinfo,categories
WHERE baseinfo.idpackage = (?) and baseinfo.idcategory = categories.idcategory""", (idpackage,))
data = self.cursor.fetchone()
if data: return data[0]
def retrieveKeySlotTag(self, idpackage):
self.cursor.execute("""
SELECT categories.category || "/" || baseinfo.name,baseinfo.slot,baseinfo.versiontag FROM baseinfo,categories
WHERE baseinfo.idpackage = (?) and baseinfo.idcategory = categories.idcategory""", (idpackage,))
data = self.cursor.fetchone()
return data
def retrieveVersion(self, idpackage):
self.cursor.execute('SELECT version FROM baseinfo WHERE idpackage = (?)', (idpackage,))
ver = self.cursor.fetchone()
if ver: return ver[0]
def retrieveRevision(self, idpackage):
self.cursor.execute('SELECT revision FROM baseinfo WHERE idpackage = (?)', (idpackage,))
rev = self.cursor.fetchone()
if rev: return rev[0]
def retrieveDateCreation(self, idpackage):
self.cursor.execute('SELECT datecreation FROM extrainfo WHERE idpackage = (?)', (idpackage,))
date = self.cursor.fetchone()
if date: return date[0]
def retrieveApi(self, idpackage):
self.cursor.execute('SELECT etpapi FROM baseinfo WHERE idpackage = (?)', (idpackage,))
api = self.cursor.fetchone()
if api: return api[0]
def retrieveUseflags(self, idpackage):
self.cursor.execute("""
SELECT flagname FROM useflags,useflagsreference
WHERE useflags.idpackage = (?) AND
useflags.idflag = useflagsreference.idflag""", (idpackage,))
return self.fetchall2set(self.cursor.fetchall())
def retrieveEclasses(self, idpackage):
self.cursor.execute("""
SELECT classname FROM eclasses,eclassesreference
WHERE eclasses.idpackage = (?) AND
eclasses.idclass = eclassesreference.idclass""", (idpackage,))
return self.fetchall2set(self.cursor.fetchall())
def retrieveSpmPhases(self, idpackage):
# FIXME: remove this check in future:
if not self.doesTableExist('packagespmphases'):
return None
self.cursor.execute("""
SELECT phases FROM packagespmphases
WHERE idpackage = (?)
""", (idpackage,))
rslt = self.cursor.fetchone()
if rslt: return rslt[0]
def retrieveNeededRaw(self, idpackage):
self.cursor.execute("""
SELECT library FROM needed,neededreference
WHERE needed.idpackage = (?) AND
needed.idneeded = neededreference.idneeded""", (idpackage,))
return self.fetchall2set(self.cursor.fetchall())
def retrieveNeeded(self, idpackage, extended = False, format = False):
if extended:
self.cursor.execute("""
SELECT library,elfclass FROM needed,neededreference
WHERE needed.idpackage = (?) AND
needed.idneeded = neededreference.idneeded order by library""", (idpackage,))
needed = self.cursor.fetchall()
else:
self.cursor.execute("""
SELECT library FROM needed,neededreference
WHERE needed.idpackage = (?) AND
needed.idneeded = neededreference.idneeded ORDER BY library""", (idpackage,))
needed = self.fetchall2list(self.cursor.fetchall())
if extended and format:
data = {}
for lib, elfclass in needed:
data[lib] = elfclass
needed = data
return needed
def retrieveConflicts(self, idpackage):
self.cursor.execute('SELECT conflict FROM conflicts WHERE idpackage = (?)', (idpackage,))
return self.fetchall2set(self.cursor.fetchall())
def retrieveProvide(self, idpackage):
self.cursor.execute('SELECT atom FROM provide WHERE idpackage = (?)', (idpackage,))
return self.fetchall2set(self.cursor.fetchall())
def retrieveDependenciesList(self, idpackage):
self.cursor.execute("""
SELECT dependenciesreference.dependency FROM dependencies,dependenciesreference
WHERE dependencies.idpackage = (?) AND
dependencies.iddependency = dependenciesreference.iddependency
UNION SELECT "!" || conflict FROM conflicts
WHERE idpackage = (?)""", (idpackage, idpackage,))
return self.fetchall2set(self.cursor.fetchall())
def retrievePostDependencies(self, idpackage, extended = False):
return self.retrieveDependencies(idpackage, extended = extended, deptype = etpConst['spm']['pdepend_id'])
def retrieveManualDependencies(self, idpackage, extended = False):
return self.retrieveDependencies(idpackage, extended = extended, deptype = etpConst['spm']['mdepend_id'])
def retrieveDependencies(self, idpackage, extended = False, deptype = None,
exclude_deptypes = None):
searchdata = [idpackage]
depstring = ''
if deptype != None:
depstring = ' and dependencies.type = (?)'
searchdata.append(deptype)
excluded_deptypes_query = ""
if exclude_deptypes != None:
for dep_type in exclude_deptypes:
excluded_deptypes_query += " AND dependencies.type != %s" % (
dep_type,)
if extended:
self.cursor.execute("""
SELECT dependenciesreference.dependency,dependencies.type
FROM dependencies,dependenciesreference
WHERE dependencies.idpackage = (?) AND
dependencies.iddependency = dependenciesreference.iddependency %s %s""" % (
depstring,excluded_deptypes_query,), searchdata)
deps = self.cursor.fetchall()
else:
self.cursor.execute("""
SELECT dependenciesreference.dependency
FROM dependencies,dependenciesreference
WHERE dependencies.idpackage = (?) AND
dependencies.iddependency = dependenciesreference.iddependency %s %s""" % (
depstring,excluded_deptypes_query,), searchdata)
deps = self.fetchall2set(self.cursor.fetchall())
return deps
def retrieveIdDependencies(self, idpackage):
self.cursor.execute('SELECT iddependency FROM dependencies WHERE idpackage = (?)', (idpackage,))
return self.fetchall2set(self.cursor.fetchall())
def retrieveDependencyFromIddependency(self, iddependency):
self.cursor.execute('SELECT dependency FROM dependenciesreference WHERE iddependency = (?)', (iddependency,))
dep = self.cursor.fetchone()
if dep: dep = dep[0]
return dep
def retrieveKeywords(self, idpackage):
self.cursor.execute("""
SELECT keywordname FROM keywords,keywordsreference
WHERE keywords.idpackage = (?) AND
keywords.idkeyword = keywordsreference.idkeyword""", (idpackage,))
return self.fetchall2set(self.cursor.fetchall())
def retrieveProtect(self, idpackage):
self.cursor.execute("""
SELECT protect FROM configprotect,configprotectreference
WHERE configprotect.idpackage = (?) AND
configprotect.idprotect = configprotectreference.idprotect""", (idpackage,))
protect = self.cursor.fetchone()
if not protect: protect = ''
else: protect = protect[0]
return protect
def retrieveProtectMask(self, idpackage):
self.cursor.execute("""
SELECT protect FROM configprotectmask,configprotectreference
WHERE idpackage = (?) AND
configprotectmask.idprotect = configprotectreference.idprotect""", (idpackage,))
protect = self.cursor.fetchone()
if not protect: protect = ''
else: protect = protect[0]
return protect
def retrieveSources(self, idpackage, extended = False):
self.cursor.execute("""
SELECT sourcesreference.source FROM sources,sourcesreference
WHERE idpackage = (?) AND
sources.idsource = sourcesreference.idsource""", (idpackage,))
sources = self.fetchall2set(self.cursor.fetchall())
if not extended:
return sources
source_data = {}
mirror_str = "mirror://"
for source in sources:
source_data[source] = set()
if source.startswith(mirror_str):
mirrorname = source.split("/")[2]
mirror_url = source.split("/", 3)[3:][0]
source_data[source] |= set([os.path.join(url, mirror_url) for url in self.retrieveMirrorInfo(mirrorname)])
else:
source_data[source].add(source)
return source_data
def retrieveAutomergefiles(self, idpackage, get_dict = False):
if not self.doesTableExist('automergefiles'):
self.createAutomergefilesTable()
# like portage does
self.connection.text_factory = lambda x: unicode(x, "raw_unicode_escape")
self.cursor.execute('SELECT configfile, md5 FROM automergefiles WHERE idpackage = (?)', (idpackage,))
data = self.cursor.fetchall()
if get_dict:
data = dict(((x, y,) for x, y in data))
return data
def retrieveContent(self, idpackage, extended = False, contentType = None, formatted = False, insert_formatted = False, order_by = ''):
extstring = ''
if extended:
extstring = ",type"
extstring_idpackage = ''
if insert_formatted:
extstring_idpackage = 'idpackage,'
searchkeywords = [idpackage]
contentstring = ''
if contentType:
searchkeywords.append(contentType)
contentstring = ' and type = (?)'
order_by_string = ''
if order_by:
order_by_string = ' order by %s' % (order_by,)
did_try = False
while 1:
try:
self.cursor.execute('SELECT %s file%s FROM content WHERE idpackage = (?) %s%s' % (
extstring_idpackage, extstring, contentstring, order_by_string,),
searchkeywords)
if extended and insert_formatted:
fl = self.cursor.fetchall()
elif extended and formatted:
fl = {}
items = self.cursor.fetchone()
while items:
fl[items[0]] = items[1]
items = self.cursor.fetchone()
elif extended:
fl = self.cursor.fetchall()
else:
if order_by:
fl = self.fetchall2list(self.cursor.fetchall())
else:
fl = self.fetchall2set(self.cursor.fetchall())
break
except (self.dbapi2.OperationalError,):
if did_try:
raise
did_try = True
# XXX support for old entropy db entries, which were
# not inserted in utf-8
self.connection.text_factory = lambda x: unicode(x, "raw_unicode_escape")
continue
return fl
def retrieveChangelog(self, idpackage):
if not self.doesTableExist('packagechangelogs'):
return None
self.cursor.execute("""
SELECT packagechangelogs.changelog FROM packagechangelogs,baseinfo,categories
WHERE baseinfo.idpackage = (?) AND
baseinfo.idcategory = categories.idcategory AND
packagechangelogs.name = baseinfo.name AND
packagechangelogs.category = categories.category""", (idpackage,))
changelog = self.cursor.fetchone()
if changelog:
changelog = changelog[0]
try:
return unicode(changelog, 'raw_unicode_escape')
except UnicodeDecodeError:
return unicode(changelog, 'utf-8')
def retrieveChangelogByKey(self, category, name):
if not self.doesTableExist('packagechangelogs'):
return None
self.connection.text_factory = lambda x: unicode(x, "raw_unicode_escape")
self.cursor.execute('SELECT changelog FROM packagechangelogs WHERE category = (?) AND name = (?)', (category, name,))
changelog = self.cursor.fetchone()
if changelog: return unicode(changelog[0], 'raw_unicode_escape')
def retrieveSlot(self, idpackage):
self.cursor.execute('SELECT slot FROM baseinfo WHERE idpackage = (?)', (idpackage,))
slot = self.cursor.fetchone()
if slot: return slot[0]
def retrieveVersionTag(self, idpackage):
self.cursor.execute('SELECT versiontag FROM baseinfo WHERE idpackage = (?)', (idpackage,))
vtag = self.cursor.fetchone()
if vtag: return vtag[0]
def retrieveMirrorInfo(self, mirrorname):
self.cursor.execute('SELECT mirrorlink FROM mirrorlinks WHERE mirrorname = (?)', (mirrorname,))
mirrorlist = self.fetchall2set(self.cursor.fetchall())
return mirrorlist
def retrieveCategory(self, idpackage):
self.cursor.execute("""
SELECT category FROM baseinfo,categories
WHERE baseinfo.idpackage = (?) AND
baseinfo.idcategory = categories.idcategory""", (idpackage,))
cat = self.cursor.fetchone()
if cat: return cat[0]
def retrieveCategoryDescription(self, category):
data = {}
if not self.doesTableExist("categoriesdescription"):
return data
self.cursor.execute('SELECT description,locale FROM categoriesdescription WHERE category = (?)', (category,))
description_data = self.cursor.fetchall()
for description, locale in description_data:
data[locale] = description
return data
def retrieveLicensedata(self, idpackage):
# insert license information
if not self.doesTableExist("licensedata"):
return {}
licenses = self.retrieveLicense(idpackage)
if licenses == None:
return {}
licenses = licenses.split()
licdata = {}
for licname in licenses:
licname = licname.strip()
if not self.entropyTools.is_valid_string(licname):
continue
self.cursor.execute('SELECT text FROM licensedata WHERE licensename = (?)', (licname,))
lictext = self.cursor.fetchone()
if lictext != None:
lictext = lictext[0]
try:
licdata[licname] = unicode(lictext, 'raw_unicode_escape')
except UnicodeDecodeError:
licdata[licname] = unicode(lictext, 'utf-8')
return licdata
def retrieveLicensedataKeys(self, idpackage):
if not self.doesTableExist("licensedata"):
return set()
licenses = self.retrieveLicense(idpackage)
if licenses == None:
return set()
licenses = licenses.split()
licdata = set()
for licname in licenses:
licname = licname.strip()
if not self.entropyTools.is_valid_string(licname):
continue
self.cursor.execute('SELECT licensename FROM licensedata WHERE licensename = (?)', (licname,))
licidentifier = self.cursor.fetchone()
if licidentifier:
licdata.add(licidentifier[0])
return licdata
def retrieveLicenseText(self, license_name):
if not self.doesTableExist("licensedata"):
return None
self.connection.text_factory = lambda x: unicode(x, "raw_unicode_escape")
self.cursor.execute('SELECT text FROM licensedata WHERE licensename = (?)', (license_name,))
text = self.cursor.fetchone()
if not text:
return None
return str(text[0])
def retrieveLicense(self, idpackage):
self.cursor.execute("""
SELECT license FROM baseinfo,licenses
WHERE baseinfo.idpackage = (?) AND
baseinfo.idlicense = licenses.idlicense""", (idpackage,))
licname = self.cursor.fetchone()
if licname: return licname[0]
def retrieveCompileFlags(self, idpackage):
self.cursor.execute("""
SELECT chost,cflags,cxxflags FROM flags,extrainfo
WHERE extrainfo.idpackage = (?) AND
extrainfo.idflags = flags.idflags""", (idpackage,))
flags = self.cursor.fetchone()
if not flags:
flags = ("N/A", "N/A", "N/A",)
return flags
def retrieveDepends(self, idpackage, atoms = False, key_slot = False,
exclude_deptypes = None):
# WARNING: never remove this, otherwise equo.db
# (client database) dependstable will be always broken (trust me)
# sanity check on the table
if not self.isDependsTableSane(): # is empty, need generation
self.regenerateDependsTable(output = False)
excluded_deptypes_query = ""
if exclude_deptypes != None:
for dep_type in exclude_deptypes:
excluded_deptypes_query += " AND dependencies.type != %s" % (
dep_type,)
if atoms:
self.cursor.execute("""
SELECT baseinfo.atom FROM dependstable,dependencies,baseinfo
WHERE dependstable.idpackage = (?) AND
dependstable.iddependency = dependencies.iddependency AND
baseinfo.idpackage = dependencies.idpackage %s""" % (
excluded_deptypes_query,), (idpackage,))
result = self.fetchall2set(self.cursor.fetchall())
elif key_slot:
self.cursor.execute("""
SELECT categories.category || "/" || baseinfo.name,baseinfo.slot
FROM baseinfo,categories,dependstable,dependencies
WHERE dependstable.idpackage = (?) AND
dependstable.iddependency = dependencies.iddependency AND
baseinfo.idpackage = dependencies.idpackage AND
categories.idcategory = baseinfo.idcategory %s""" % (
excluded_deptypes_query,), (idpackage,))
result = self.cursor.fetchall()
else:
self.cursor.execute("""
SELECT dependencies.idpackage FROM dependstable,dependencies
WHERE dependstable.idpackage = (?) AND
dependstable.iddependency = dependencies.iddependency %s""" % (
excluded_deptypes_query,), (idpackage,))
result = self.fetchall2set(self.cursor.fetchall())
return result
def retrieveUnusedIdpackages(self):
# WARNING: never remove this, otherwise equo.db (client database) dependstable will be always broken (trust me)
# sanity check on the table
if not self.isDependsTableSane(): # is empty, need generation
self.regenerateDependsTable(output = False)
self.cursor.execute("""
SELECT idpackage FROM baseinfo
WHERE idpackage NOT IN (SELECT idpackage FROM dependstable) ORDER BY atom
""")
return self.fetchall2list(self.cursor.fetchall())
# You must provide the full atom to this function
# WARNING: this function does not support branches
def isPackageAvailable(self, pkgatom):
pkgatom = self.entropyTools.remove_package_operators(pkgatom)
self.cursor.execute('SELECT idpackage FROM baseinfo WHERE atom = (?)', (pkgatom,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isIDPackageAvailable(self, idpackage):
self.cursor.execute('SELECT idpackage FROM baseinfo WHERE idpackage = (?)', (idpackage,))
result = self.cursor.fetchone()
if not result:
return False
return True
def areIDPackagesAvailable(self, idpackages):
sql = 'SELECT count(idpackage) FROM baseinfo WHERE idpackage IN (%s)' % (','.join([str(x) for x in set(idpackages)]),)
self.cursor.execute(sql)
count = self.cursor.fetchone()[0]
if count != len(idpackages):
return False
return True
def isCategoryAvailable(self, category):
self.cursor.execute('SELECT idcategory FROM categories WHERE category = (?)', (category,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isProtectAvailable(self, protect):
self.cursor.execute('SELECT idprotect FROM configprotectreference WHERE protect = (?)', (protect,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isFileAvailable(self, myfile, get_id = False):
self.cursor.execute('SELECT idpackage FROM content WHERE file = (?)', (myfile,))
result = self.cursor.fetchall()
if get_id:
return self.fetchall2set(result)
elif result:
return True
return False
def resolveNeeded(self, needed, elfclass = -1):
cache = self.fetchSearchCache(needed, 'resolveNeeded')
if cache != None: return cache
ldpaths = self.entropyTools.collect_linker_paths()
mypaths = [os.path.join(x, needed) for x in ldpaths]
query = """
SELECT idpackage,file FROM content WHERE content.file IN (%s)
""" % ( ('?,'*len(mypaths))[:-1], )
self.cursor.execute(query, mypaths)
results = self.cursor.fetchall()
if elfclass == -1:
mydata = set(results)
else:
mydata = set()
for data in results:
if not os.access(data[1], os.R_OK):
continue
myclass = self.entropyTools.read_elf_class(data[1])
if myclass == elfclass:
mydata.add(data)
self.storeSearchCache(needed, 'resolveNeeded', mydata)
return mydata
def isSourceAvailable(self, source):
self.cursor.execute('SELECT idsource FROM sourcesreference WHERE source = (?)', (source,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isDependencyAvailable(self, dependency):
self.cursor.execute('SELECT iddependency FROM dependenciesreference WHERE dependency = (?)', (dependency,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isKeywordAvailable(self, keyword):
self.cursor.execute('SELECT idkeyword FROM keywordsreference WHERE keywordname = (?)', (keyword,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isUseflagAvailable(self, useflag):
self.cursor.execute('SELECT idflag FROM useflagsreference WHERE flagname = (?)', (useflag,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isEclassAvailable(self, eclass):
self.cursor.execute('SELECT idclass FROM eclassesreference WHERE classname = (?)', (eclass,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isNeededAvailable(self, needed):
self.cursor.execute('SELECT idneeded FROM neededreference WHERE library = (?)', (needed,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isCounterAvailable(self, counter, branch = None, branch_operator = "="):
params = [counter]
branch_string = ''
if branch:
branch_string = ' and branch '+branch_operator+' (?)'
params = [counter, branch]
self.cursor.execute('SELECT counter FROM counters WHERE counter = (?)'+branch_string, params)
result = self.cursor.fetchone()
if result: return True
return False
def isCounterTrashed(self, counter):
self.cursor.execute('SELECT counter FROM trashedcounters WHERE counter = (?)', (counter,))
result = self.cursor.fetchone()
if result: return True
return False
def isLicensedataKeyAvailable(self, license_name):
if not self.doesTableExist("licensedata"):
return True
self.cursor.execute('SELECT licensename FROM licensedata WHERE licensename = (?)', (license_name,))
result = self.cursor.fetchone()
if not result:
return False
return True
def isLicenseAccepted(self, license_name):
self.cursor.execute('SELECT licensename FROM licenses_accepted WHERE licensename = (?)', (license_name,))
result = self.cursor.fetchone()
if not result:
return False
return True
def acceptLicense(self, license_name):
if self.readOnly or (not self.entropyTools.is_user_in_entropy_group()):
return
if self.isLicenseAccepted(license_name):
return
with self.__write_mutex:
self.cursor.execute('INSERT INTO licenses_accepted VALUES (?)', (license_name,))
self.commitChanges()
def isLicenseAvailable(self, pkglicense):
if not self.entropyTools.is_valid_string(pkglicense):
pkglicense = ' '
self.cursor.execute('SELECT idlicense FROM licenses WHERE license = (?)', (pkglicense,))
result = self.cursor.fetchone()
if result: return result[0]
return -1
def isSystemPackage(self, idpackage):
self.cursor.execute('SELECT idpackage FROM systempackages WHERE idpackage = (?)', (idpackage,))
result = self.cursor.fetchone()
if result:
return True
return False
def isInjected(self, idpackage):
self.cursor.execute('SELECT idpackage FROM injected WHERE idpackage = (?)', (idpackage,))
result = self.cursor.fetchone()
if result:
return True
return False
def areCompileFlagsAvailable(self, chost, cflags, cxxflags):
self.cursor.execute('SELECT idflags FROM flags WHERE chost = (?) AND cflags = (?) AND cxxflags = (?)',
(chost, cflags, cxxflags,)
)
result = self.cursor.fetchone()
if result: return result[0]
return -1
def searchBelongs(self, file, like = False, branch = None, branch_operator = "="):
branchstring = ''
searchkeywords = [file]
if branch:
searchkeywords.append(branch)
branchstring = ' and baseinfo.branch '+branch_operator+' (?)'
if like:
self.cursor.execute("""
SELECT content.idpackage FROM content,baseinfo
WHERE file LIKE (?) AND
content.idpackage = baseinfo.idpackage %s""" % (branchstring,), searchkeywords)
else:
self.cursor.execute("""SELECT content.idpackage FROM content,baseinfo
WHERE file = (?) AND
content.idpackage = baseinfo.idpackage %s""" % (branchstring,), searchkeywords)
return self.fetchall2set(self.cursor.fetchall())
''' search packages that uses the eclass provided '''
def searchEclassedPackages(self, eclass, atoms = False): # atoms = return atoms directly
if atoms:
self.cursor.execute("""
SELECT baseinfo.atom,eclasses.idpackage FROM baseinfo,eclasses,eclassesreference
WHERE eclassesreference.classname = (?) AND
eclassesreference.idclass = eclasses.idclass AND
eclasses.idpackage = baseinfo.idpackage""", (eclass,))
return self.cursor.fetchall()
else:
self.cursor.execute('SELECT idpackage FROM baseinfo WHERE versiontag = (?)', (eclass,))
return self.fetchall2set(self.cursor.fetchall())
''' search packages whose versiontag matches the one provided '''
def searchTaggedPackages(self, tag, atoms = False): # atoms = return atoms directly
if atoms:
self.cursor.execute('SELECT atom,idpackage FROM baseinfo WHERE versiontag = (?)', (tag,))
return self.cursor.fetchall()
else:
self.cursor.execute('SELECT idpackage FROM baseinfo WHERE versiontag = (?)', (tag,))
return self.fetchall2set(self.cursor.fetchall())
def searchLicenses(self, mylicense, caseSensitive = False, atoms = False):
if not self.entropyTools.is_valid_string(mylicense):
return []
request = "baseinfo.idpackage"
if atoms:
request = "baseinfo.atom,baseinfo.idpackage"
if caseSensitive:
self.cursor.execute("""
SELECT %s FROM baseinfo,licenses
WHERE licenses.license LIKE (?) AND
licenses.idlicense = baseinfo.idlicense""" % (request,), ("%"+mylicense+"%",))
else:
self.cursor.execute("""
SELECT %s FROM baseinfo,licenses
WHERE LOWER(licenses.license) LIKE (?) AND
licenses.idlicense = baseinfo.idlicense""" % (request,), ("%"+mylicense+"%".lower(),))
if atoms:
return self.cursor.fetchall()
return self.fetchall2set(self.cursor.fetchall())
''' search packages whose slot matches the one provided '''
def searchSlottedPackages(self, slot, atoms = False): # atoms = return atoms directly
if atoms:
self.cursor.execute('SELECT atom,idpackage FROM baseinfo WHERE slot = (?)', (slot,))
return self.cursor.fetchall()
else:
self.cursor.execute('SELECT idpackage FROM baseinfo WHERE slot = (?)', (slot,))
return self.fetchall2set(self.cursor.fetchall())
def searchKeySlot(self, key, slot, branch = None):
branchstring = ''
cat, name = key.split("/")
params = [cat, name, slot]
if branch:
params.append(branch)
branchstring = 'and baseinfo.branch = (?)'
self.cursor.execute("""
SELECT idpackage FROM baseinfo,categories
WHERE baseinfo.idcategory = categories.idcategory AND
categories.category = (?) AND
baseinfo.name = (?) AND
baseinfo.slot = (?) %s""" % (branchstring,), params)
return self.cursor.fetchall()
''' search packages that need the specified library (in neededreference table) specified by keyword '''
def searchNeeded(self, keyword, like = False):
if like:
self.cursor.execute("""
SELECT needed.idpackage FROM needed,neededreference
WHERE library LIKE (?) AND
needed.idneeded = neededreference.idneeded""", (keyword,))
else:
self.cursor.execute("""
SELECT needed.idpackage FROM needed,neededreference
WHERE library = (?) AND
needed.idneeded = neededreference.idneeded""", (keyword,))
return self.fetchall2set(self.cursor.fetchall())
''' search dependency string inside dependenciesreference table and retrieve iddependency '''
def searchDependency(self, dep, like = False, multi = False, strings = False):
sign = "="
if like:
sign = "LIKE"
dep = "%"+dep+"%"
item = 'iddependency'
if strings:
item = 'dependency'
self.cursor.execute('SELECT %s FROM dependenciesreference WHERE dependency %s (?)' % (item, sign,), (dep,))
if multi:
return self.fetchall2set(self.cursor.fetchall())
else:
iddep = self.cursor.fetchone()
if iddep:
iddep = iddep[0]
else:
iddep = -1
return iddep
''' search iddependency inside dependencies table and retrieve idpackages '''
def searchIdpackageFromIddependency(self, iddep):
self.cursor.execute('SELECT idpackage FROM dependencies WHERE iddependency = (?)', (iddep,))
return self.fetchall2set(self.cursor.fetchall())
def searchSets(self, keyword):
self.cursor.execute('SELECT DISTINCT(setname) FROM packagesets WHERE setname LIKE (?)', ("%"+keyword+"%",))
return self.fetchall2set(self.cursor.fetchall())
def searchSimilarPackages(self, mystring, atom = False):
s_item = 'name'
if atom: s_item = 'atom'
self.cursor.execute("""
SELECT idpackage FROM baseinfo
WHERE soundex(%s) = soundex((?)) ORDER BY %s""" % (s_item, s_item,), (mystring,))
return self.fetchall2list(self.cursor.fetchall())
def searchPackages(self, keyword, sensitive = False, slot = None, tag = None, branch = None, order_by = 'atom', just_id = False):
searchkeywords = ["%"+keyword+"%"]
slotstring = ''
if slot:
searchkeywords.append(slot)
slotstring = ' and slot = (?)'
tagstring = ''
if tag:
searchkeywords.append(tag)
tagstring = ' and versiontag = (?)'
branchstring = ''
if branch:
searchkeywords.append(branch)
branchstring = ' and branch = (?)'
order_by_string = ''
if order_by in ("atom", "idpackage", "branch",):
order_by_string = ' order by %s' % (order_by,)
search_elements = 'atom,idpackage,branch'
if just_id: search_elements = 'idpackage'
if sensitive:
self.cursor.execute("""
SELECT %s FROM baseinfo WHERE atom LIKE (?) %s %s %s %s""" % (
search_elements,slotstring,tagstring,branchstring,order_by_string,),
searchkeywords
)
else:
self.cursor.execute("""
SELECT %s FROM baseinfo WHERE
LOWER(atom) LIKE (?) %s %s %s %s""" % (
search_elements,slotstring,tagstring,branchstring,order_by_string,),
searchkeywords
)
if just_id:
return self.fetchall2list(self.cursor.fetchall())
return self.cursor.fetchall()
def searchProvide(self, keyword, slot = None, tag = None, branch = None, justid = False):
slotstring = ''
searchkeywords = [keyword]
if slot:
searchkeywords.append(slot)
slotstring = ' and baseinfo.slot = (?)'
tagstring = ''
if tag:
searchkeywords.append(tag)
tagstring = ' and baseinfo.versiontag = (?)'
branchstring = ''
if branch:
searchkeywords.append(branch)
branchstring = ' and baseinfo.branch = (?)'
atomstring = ''
if not justid:
atomstring = 'baseinfo.atom,'
self.cursor.execute("""
SELECT %s baseinfo.idpackage FROM baseinfo,provide
WHERE provide.atom = (?) AND
provide.idpackage = baseinfo.idpackage %s %s %s""" % (
atomstring,slotstring,tagstring,branchstring,),
searchkeywords
)
if justid:
results = self.fetchall2list(self.cursor.fetchall())
else:
results = self.cursor.fetchall()
return results
def searchPackagesByDescription(self, keyword):
self.cursor.execute("""
SELECT baseinfo.atom,baseinfo.idpackage FROM extrainfo,baseinfo
WHERE LOWER(extrainfo.description) LIKE (?) AND
baseinfo.idpackage = extrainfo.idpackage""", ("%"+keyword.lower()+"%",))
return self.cursor.fetchall()
def searchPackagesByName(self, keyword, sensitive = False, branch = None, justid = False):
if sensitive:
searchkeywords = [keyword]
else:
searchkeywords = [keyword.lower()]
branchstring = ''
atomstring = ''
if not justid:
atomstring = 'atom,'
if branch:
searchkeywords.append(branch)
branchstring = ' and branch = (?)'
if sensitive:
self.cursor.execute("""
SELECT %s idpackage FROM baseinfo
WHERE name = (?) %s""" % (atomstring, branchstring,), searchkeywords)
else:
self.cursor.execute("""
SELECT %s idpackage FROM baseinfo
WHERE LOWER(name) = (?) %s""" % (atomstring, branchstring,), searchkeywords)
if justid:
results = self.fetchall2list(self.cursor.fetchall())
else:
results = self.cursor.fetchall()
return results
def searchPackagesByCategory(self, keyword, like = False, branch = None):
searchkeywords = [keyword]
branchstring = ''
if branch:
searchkeywords.append(branch)
branchstring = 'and branch = (?)'
if like:
self.cursor.execute("""
SELECT baseinfo.atom,baseinfo.idpackage FROM baseinfo,categories
WHERE categories.category LIKE (?) AND
baseinfo.idcategory = categories.idcategory %s""" % (branchstring,), searchkeywords)
else:
self.cursor.execute("""
SELECT baseinfo.atom,baseinfo.idpackage FROM baseinfo,categories
WHERE categories.category = (?) AND
baseinfo.idcategory = categories.idcategory %s""" % (branchstring,), searchkeywords)
return self.cursor.fetchall()
def searchPackagesByNameAndCategory(self, name, category, sensitive = False, branch = None, justid = False):
myname = name
mycat = category
if not sensitive:
myname = name.lower()
mycat = category.lower()
searchkeywords = [myname, mycat]
branchstring = ''
if branch:
searchkeywords.append(branch)
branchstring = ' and branch = (?)'
atomstring = ''
if not justid:
atomstring = 'atom,'
if sensitive:
self.cursor.execute("""
SELECT %s idpackage FROM baseinfo
WHERE name = (?) AND
idcategory IN (
SELECT idcategory FROM categories
WHERE category = (?)
) %s""" % (atomstring, branchstring,), searchkeywords)
else:
self.cursor.execute("""
SELECT %s idpackage FROM baseinfo
WHERE LOWER(name) = (?) AND
idcategory IN (
SELECT idcategory FROM categories
WHERE LOWER(category) = (?)
) %s""" % (atomstring, branchstring,), searchkeywords)
if justid:
results = self.fetchall2list(self.cursor.fetchall())
else:
results = self.cursor.fetchall()
return results
def isPackageScopeAvailable(self, atom, slot, revision):
searchdata = (atom, slot, revision,)
self.cursor.execute('SELECT idpackage FROM baseinfo where atom = (?) and slot = (?) and revision = (?)', searchdata)
rslt = self.cursor.fetchone()
idreason = 0
idpackage = -1
if rslt:
# check if it's masked
idpackage, idreason = self.idpackageValidator(rslt[0])
return idpackage, idreason
def listAllPackages(self, get_scope = False, order_by = None, branch = None, branch_operator = "="):
branchstring = ''
searchkeywords = []
if branch:
searchkeywords = [branch]
branchstring = ' where branch %s (?)' % (branch_operator,)
order_txt = ''
if order_by:
order_txt = ' order by %s' % (order_by,)
if get_scope:
self.cursor.execute('SELECT idpackage,atom,slot,revision FROM baseinfo'+order_txt+branchstring, searchkeywords)
else:
self.cursor.execute('SELECT atom,idpackage,branch FROM baseinfo'+order_txt+branchstring, searchkeywords)
return self.cursor.fetchall()
def listAllInjectedPackages(self, justFiles = False):
self.cursor.execute('SELECT idpackage FROM injected')
injecteds = self.fetchall2set(self.cursor.fetchall())
results = set()
# get download
for injected in injecteds:
download = self.retrieveDownloadURL(injected)
if justFiles:
results.add(download)
else:
results.add((download, injected))
return results
def listAllCounters(self, onlycounters = False, branch = None, branch_operator = "="):
branchstring = ''
if branch:
branchstring = ' WHERE branch '+branch_operator+' "'+str(branch)+'"'
if onlycounters:
self.cursor.execute('SELECT counter FROM counters'+branchstring)
return self.fetchall2set(self.cursor.fetchall())
else:
self.cursor.execute('SELECT counter,idpackage FROM counters'+branchstring)
return self.cursor.fetchall()
def listAllIdpackages(self, branch = None, branch_operator = "=", order_by = None):
branchstring = ''
orderbystring = ''
searchkeywords = []
if branch:
searchkeywords.append(branch)
branchstring = ' where branch %s (?)' % (str(branch_operator),)
if order_by:
orderbystring = ' order by '+order_by
self.cursor.execute('SELECT idpackage FROM baseinfo'+branchstring+orderbystring, searchkeywords)
try:
if order_by:
results = self.fetchall2list(self.cursor.fetchall())
else:
results = self.fetchall2set(self.cursor.fetchall())
return results
except self.dbapi2.OperationalError:
if order_by:
return []
return set()
def listAllDependencies(self, only_deps = False):
if only_deps:
self.cursor.execute('SELECT dependency FROM dependenciesreference')
return self.fetchall2set(self.cursor.fetchall())
else:
self.cursor.execute('SELECT * FROM dependenciesreference')
return self.cursor.fetchall()
def listAllBranches(self):
cache = self.live_cache.get('listAllBranches')
if cache != None:
return cache
self.cursor.execute('SELECT distinct branch FROM baseinfo')
results = self.fetchall2set(self.cursor.fetchall())
self.live_cache['listAllBranches'] = results.copy()
return results
def listIdPackagesInIdcategory(self, idcategory, order_by = 'atom'):
order_by_string = ''
if order_by in ("atom", "name", "version",):
order_by_string = ' ORDER BY %s' % (order_by,)
self.cursor.execute('SELECT idpackage FROM baseinfo where idcategory = (?)'+order_by_string, (idcategory,))
return self.fetchall2set(self.cursor.fetchall())
def listIdpackageDependencies(self, idpackage):
self.cursor.execute("""
SELECT dependenciesreference.iddependency,dependenciesreference.dependency FROM dependenciesreference,dependencies
WHERE dependencies.idpackage = (?) AND
dependenciesreference.iddependency = dependencies.iddependency""", (idpackage,))
return set(self.cursor.fetchall())
def listBranchPackagesTbz2(self, branch, do_sort = True, full_path = False):
order_string = ''
if do_sort: order_string = 'ORDER BY extrainfo.download'
self.cursor.execute("""
SELECT extrainfo.download FROM baseinfo,extrainfo
WHERE baseinfo.branch = (?) AND
baseinfo.idpackage = extrainfo.idpackage %s""" % (order_string,), (branch,))
if do_sort: results = self.fetchall2list(self.cursor.fetchall())
else: results = self.fetchall2set(self.cursor.fetchall())
if not full_path: results = [os.path.basename(x) for x in results]
if do_sort: return results
return set(results)
def listAllFiles(self, clean = False, count = False):
self.connection.text_factory = lambda x: unicode(x, "raw_unicode_escape")
if count:
self.cursor.execute('SELECT count(file) FROM content')
else:
self.cursor.execute('SELECT file FROM content')
if count:
return self.cursor.fetchone()[0]
else:
if clean:
return self.fetchall2set(self.cursor.fetchall())
else:
return self.fetchall2list(self.cursor.fetchall())
def listAllCategories(self, order_by = ''):
order_by_string = ''
if order_by: order_by_string = ' order by %s' % (order_by,)
self.cursor.execute('SELECT idcategory,category FROM categories %s' % (
order_by_string,))
return self.cursor.fetchall()
def listConfigProtectDirectories(self, mask = False):
mask_t = ''
if mask: mask_t = 'mask'
self.cursor.execute("""
SELECT DISTINCT(protect) FROM configprotectreference
WHERE idprotect >= 1 AND
idprotect <= (SELECT max(idprotect) FROM configprotect%s)
ORDER BY protect""" % (mask_t,))
results = self.fetchall2set(self.cursor.fetchall())
dirs = set()
for mystr in results:
dirs |= set(map(unicode, mystr.split()))
return sorted(list(dirs))
def switchBranch(self, idpackage, tobranch):
key, slot = self.retrieveKeySlot(idpackage)
# if there are entries already, remove idpackage directly
my_idpackage, result = self.atomMatch(key, matchSlot = slot,
matchBranches = (tobranch,))
if my_idpackage != -1: return False
# otherwise, update the old one (set the new branch)
with self.__write_mutex:
self.cursor.execute("""
UPDATE baseinfo SET branch = (?)
WHERE idpackage = (?)""", (tobranch, idpackage,))
self.commitChanges()
self.clearCache()
return True
def databaseStructureUpdates(self):
old_readonly = self.readOnly
self.readOnly = False
if not self.doesTableExist("licensedata"):
self.createLicensedataTable()
if not self.doesTableExist("licenses_accepted") and \
(self.dbname == etpConst['clientdbid']):
self.createLicensesAcceptedTable()
if not self.doesTableExist("trashedcounters"):
self.createTrashedcountersTable()
if not self.doesTableExist("counters"):
self.createCountersTable()
if not self.doesTableExist("installedtable") and \
(self.dbname == etpConst['clientdbid']):
self.createInstalledTable()
if self.doesTableExist("installedtable") and \
not self.doesColumnInTableExist("installedtable","source"):
self.createInstalledTableSource()
if not self.doesTableExist("categoriesdescription"):
self.createCategoriesdescriptionTable()
if not self.doesTableExist('packagesets'):
self.createPackagesetsTable()
if not self.doesTableExist('packagechangelogs'):
self.createPackagechangelogsTable()
if not self.doesTableExist('automergefiles'):
self.createAutomergefilesTable()
if not self.doesTableExist('packagesignatures'):
self.createPackagesignaturesTable()
if not self.doesTableExist('packagespmphases'):
self.createPackagespmphases()
self.readOnly = old_readonly
self.connection.commit()
def validateDatabase(self):
self.cursor.execute('select name from SQLITE_MASTER where type = (?) and name = (?)', ("table", "baseinfo"))
rslt = self.cursor.fetchone()
if rslt == None:
mytxt = _("baseinfo table not found. Either does not exist or corrupted.")
raise SystemDatabaseError("SystemDatabaseError: %s" % (mytxt,))
self.cursor.execute('select name from SQLITE_MASTER where type = (?) and name = (?)', ("table", "extrainfo"))
rslt = self.cursor.fetchone()
if rslt == None:
mytxt = _("extrainfo table not found. Either does not exist or corrupted.")
raise SystemDatabaseError("SystemDatabaseError: %s" % (mytxt,))
def getIdpackagesDifferences(self, foreign_idpackages):
myids = self.listAllIdpackages()
if isinstance(foreign_idpackages, (list, tuple,)):
outids = set(foreign_idpackages)
else:
outids = foreign_idpackages
added_ids = outids - myids
removed_ids = myids - outids
return added_ids, removed_ids
def uniformBranch(self, branch):
with self.__write_mutex:
self.cursor.execute('UPDATE baseinfo SET branch = (?)', (branch,))
self.commitChanges()
self.clearCache()
def alignDatabases(self, dbconn, force = False, output_header = " ", align_limit = 300):
added_ids, removed_ids = self.getIdpackagesDifferences(dbconn.listAllIdpackages())
if not force:
if len(added_ids) > align_limit: # too much hassle
return 0
if len(removed_ids) > align_limit: # too much hassle
return 0
if not added_ids and not removed_ids:
return -1
mytxt = red("%s, %s ...") % (_("Syncing current database"), _("please wait"),)
self.updateProgress(
mytxt,
importance = 1,
type = "info",
header = output_header,
back = True
)
maxcount = len(removed_ids)
mycount = 0
for idpackage in removed_ids:
mycount += 1
mytxt = "%s: %s" % (red(_("Removing entry")), blue(str(self.retrieveAtom(idpackage))),)
self.updateProgress(
mytxt,
importance = 0,
type = "info",
header = output_header,
back = True,
count = (mycount, maxcount)
)
self.removePackage(idpackage, do_cleanup = False, do_commit = False)
maxcount = len(added_ids)
mycount = 0
for idpackage in added_ids:
mycount += 1
mytxt = "%s: %s" % (red(_("Adding entry")), blue(str(dbconn.retrieveAtom(idpackage))),)
self.updateProgress(
mytxt,
importance = 0,
type = "info",
header = output_header,
back = True,
count = (mycount, maxcount)
)
mydata = dbconn.getPackageData(idpackage, get_content = True, content_insert_formatted = True)
self.addPackage(
mydata,
revision = mydata['revision'],
idpackage = idpackage,
do_remove = False,
do_commit = False,
formatted_content = True
)
# do some cleanups
self.doCleanups()
# clear caches
self.clearCache()
self.commitChanges()
self.regenerateDependsTable(output = False)
dbconn.clearCache()
# verify both checksums, if they don't match, bomb out
mycheck = self.database_checksum(do_order = True, strict = False)
outcheck = dbconn.database_checksum(do_order = True, strict = False)
if mycheck == outcheck:
return 1
return 0
def checkDatabaseApi(self):
dbapi = self.getApi()
if int(dbapi) > int(etpConst['etpapi']):
self.updateProgress(
red(_("Repository EAPI > Entropy EAPI. Please update Equo/Entropy as soon as possible !")),
importance = 1,
type = "warning",
header = " * ! * ! * ! * "
)
def doDatabaseImport(self, dumpfile, dbfile):
sqlite3_exec = "/usr/bin/sqlite3 %s < %s" % (dbfile, dumpfile,)
retcode = subprocess.call(sqlite3_exec, shell = True)
return retcode
def doDatabaseExport(self, dumpfile, gentle_with_tables = True):
dumpfile.write("BEGIN TRANSACTION;\n")
self.cursor.execute("SELECT name, type, sql FROM sqlite_master WHERE sql NOT NULL AND type=='table'")
for name, x, sql in self.cursor.fetchall():
self.updateProgress(
red("%s " % (_("Exporting database table"),) )+"["+blue(str(name))+"]",
importance = 0,
type = "info",
back = True,
header = " "
)
if name == "sqlite_sequence":
dumpfile.write("DELETE FROM sqlite_sequence;\n")
elif name == "sqlite_stat1":
dumpfile.write("ANALYZE sqlite_master;\n")
elif name.startswith("sqlite_"):
continue
else:
t_cmd = "CREATE TABLE"
if sql.startswith(t_cmd) and gentle_with_tables:
sql = "CREATE TABLE IF NOT EXISTS"+sql[len(t_cmd):]
dumpfile.write("%s;\n" % sql)
self.cursor.execute("PRAGMA table_info('%s')" % name)
cols = [str(r[1]) for r in self.cursor.fetchall()]
q = "SELECT 'INSERT INTO \"%(tbl_name)s\" VALUES("
q += ", ".join(["'||quote(" + x + ")||'" for x in cols])
q += ")' FROM '%(tbl_name)s'"
self.cursor.execute(q % {'tbl_name': name})
self.connection.text_factory = lambda x: unicode(x, "raw_unicode_escape")
for row in self.cursor:
dumpfile.write("%s;\n" % str(row[0].encode('raw_unicode_escape')))
self.cursor.execute("SELECT name, type, sql FROM sqlite_master WHERE sql NOT NULL AND type!='table' AND type!='meta'")
for name, x, sql in self.cursor.fetchall():
dumpfile.write("%s;\n" % sql)
dumpfile.write("COMMIT;\n")
try:
dumpfile.flush()
except:
pass
self.updateProgress(
red(_("Database Export completed.")),
importance = 0,
type = "info",
header = " "
)
# remember to close the file
def listAllTables(self):
self.cursor.execute("""
SELECT name FROM SQLITE_MASTER WHERE type = "table"
""")
return self.fetchall2list(self.cursor.fetchall())
def doesTableExist(self, table):
self.cursor.execute('select name from SQLITE_MASTER where type = "table" and name = (?)', (table,))
rslt = self.cursor.fetchone()
if rslt == None:
return False
return True
def doesColumnInTableExist(self, table, column):
self.cursor.execute('PRAGMA table_info( %s )' % (table,))
rslt = (x[1] for x in self.cursor.fetchall())
if column in rslt:
return True
return False
def database_checksum(self, do_order = False, strict = True, strings = False):
c_tup = ("database_checksum", do_order, strict, strings,)
cache = self.live_cache.get(c_tup)
if cache != None: return cache
idpackage_order = ''
category_order = ''
license_order = ''
flags_order = ''
if do_order:
idpackage_order = 'order by idpackage'
category_order = 'order by category'
license_order = 'order by license'
flags_order = 'order by chost'
def do_update_md5(m, cursor):
mydata = cursor.fetchall()
for record in mydata:
for item in record:
m.update(str(item))
if strings:
import hashlib
m = hashlib.md5()
self.cursor.execute("""
SELECT idpackage,atom,name,version,versiontag,
revision,branch,slot,etpapi,trigger FROM
baseinfo %s""" % (idpackage_order,))
if strings:
do_update_md5(m, self.cursor)
else:
a_hash = hash(tuple(self.cursor.fetchall()))
self.cursor.execute("""
SELECT idpackage,description,homepage,
download,size,digest,datecreation FROM
extrainfo %s""" % (idpackage_order,))
if strings:
do_update_md5(m, self.cursor)
else:
b_hash = hash(tuple(self.cursor.fetchall()))
self.cursor.execute('select category from categories %s' % (category_order,))
if strings:
do_update_md5(m, self.cursor)
else:
c_hash = hash(tuple(self.cursor.fetchall()))
d_hash = '0'
e_hash = '0'
if strict:
self.cursor.execute('select * from licenses %s' % (license_order,))
if strings:
do_update_md5(m, self.cursor)
else:
d_hash = hash(tuple(self.cursor.fetchall()))
self.cursor.execute('select * from flags %s' % (flags_order,))
if strings:
do_update_md5(m, self.cursor)
else:
e_hash = hash(tuple(self.cursor.fetchall()))
if strings:
result = m.hexdigest()
else:
result = "%s:%s:%s:%s:%s" % (a_hash, b_hash, c_hash, d_hash, e_hash,)
self.live_cache[c_tup] = result[:]
return result
########################################################
####
## Client Database API / but also used by server part
#
def updateInstalledTableSource(self, idpackage, source):
with self.__write_mutex:
self.cursor.execute("""
UPDATE installedtable SET source = (?) WHERE idpackage = (?)
""", (source, idpackage,))
def addPackageToInstalledTable(self, idpackage, repoid, source = 0):
with self.__write_mutex:
self.cursor.execute('INSERT into installedtable VALUES (?,?,?)',
(idpackage, repoid, source,))
# self.commitChanges()
def retrievePackageFromInstalledTable(self, idpackage):
with self.__write_mutex:
try:
self.cursor.execute("""
SELECT repositoryname FROM installedtable
WHERE idpackage = (?)""", (idpackage,))
return self.cursor.fetchone()[0]
except (self.dbapi2.OperationalError,TypeError,):
return 'Not available'
def removePackageFromInstalledTable(self, idpackage):
with self.__write_mutex:
self.cursor.execute("""
DELETE FROM installedtable
WHERE idpackage = (?)""", (idpackage,))
def removePackageFromDependsTable(self, idpackage):
with self.__write_mutex:
try:
self.cursor.execute('DELETE FROM dependstable WHERE idpackage = (?)', (idpackage,))
return 0
except (self.dbapi2.OperationalError,):
return 1 # need reinit
def createDependsTable(self):
with self.__write_mutex:
self.cursor.executescript("""
DROP TABLE IF EXISTS dependstable;
CREATE TABLE dependstable ( iddependency INTEGER PRIMARY KEY, idpackage INTEGER );
INSERT into dependstable VALUES (-1,-1);
""")
if self.indexing:
self.cursor.execute('CREATE INDEX IF NOT EXISTS dependsindex_idpackage ON dependstable ( idpackage )')
self.commitChanges()
def sanitizeDependsTable(self):
with self.__write_mutex:
self.cursor.execute('DELETE FROM dependstable where iddependency = -1')
self.commitChanges()
def isDependsTableSane(self):
try:
self.cursor.execute('SELECT iddependency FROM dependstable WHERE iddependency = -1')
except (self.dbapi2.OperationalError,):
return False # table does not exist, please regenerate and re-run
status = self.cursor.fetchone()
if status: return False
self.cursor.execute('select count(*) from dependstable')
dependstable_count = self.cursor.fetchone()
if dependstable_count < 2:
return False
return True
def createXpakTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE xpakdata ( idpackage INTEGER PRIMARY KEY, data BLOB );')
self.commitChanges()
def storeXpakMetadata(self, idpackage, blob):
with self.__write_mutex:
self.cursor.execute('INSERT into xpakdata VALUES (?,?)', (int(idpackage), buffer(blob),))
self.commitChanges()
def retrieveXpakMetadata(self, idpackage):
try:
self.cursor.execute('SELECT data from xpakdata where idpackage = (?)', (idpackage,))
mydata = self.cursor.fetchone()
if not mydata:
return ""
return mydata[0]
except:
return ""
def createCountersTable(self):
with self.__write_mutex:
self.cursor.execute("CREATE TABLE IF NOT EXISTS counters ( counter INTEGER, idpackage INTEGER PRIMARY KEY, branch VARCHAR );")
def dropAllIndexes(self):
self.cursor.execute('SELECT name FROM SQLITE_MASTER WHERE type = "index"')
indexes = self.fetchall2set(self.cursor.fetchall())
with self.__write_mutex:
for index in indexes:
if not index.startswith("sqlite"):
self.cursor.execute('DROP INDEX IF EXISTS %s' % (index,))
def listAllIndexes(self, only_entropy = True):
self.cursor.execute('SELECT name FROM SQLITE_MASTER WHERE type = "index"')
indexes = self.fetchall2set(self.cursor.fetchall())
if not only_entropy:
return indexes
myindexes = set()
for index in indexes:
if index.startswith("sqlite"):
continue
myindexes.add(index)
return myindexes
def createAllIndexes(self):
self.createContentIndex()
self.createBaseinfoIndex()
self.createKeywordsIndex()
self.createDependenciesIndex()
self.createProvideIndex()
self.createConflictsIndex()
self.createExtrainfoIndex()
self.createNeededIndex()
self.createUseflagsIndex()
self.createLicensedataIndex()
self.createLicensesIndex()
self.createConfigProtectReferenceIndex()
self.createMessagesIndex()
self.createSourcesIndex()
self.createCountersIndex()
self.createEclassesIndex()
self.createCategoriesIndex()
self.createCompileFlagsIndex()
self.createPackagesetsIndex()
self.createAutomergefilesIndex()
def createPackagesetsIndex(self):
if self.indexing:
with self.__write_mutex:
try:
self.cursor.execute('CREATE INDEX IF NOT EXISTS packagesetsindex ON packagesets ( setname )')
self.commitChanges()
except self.dbapi2.OperationalError:
pass
def createAutomergefilesIndex(self):
if self.indexing:
with self.__write_mutex:
try:
self.cursor.execute("""
CREATE INDEX IF NOT EXISTS automergefiles_idpackage
ON automergefiles ( idpackage )
""")
self.cursor.execute("""
CREATE INDEX IF NOT EXISTS automergefiles_file_md5
ON automergefiles ( configfile, md5 )
""")
except self.dbapi2.OperationalError:
pass
def createNeededIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS neededindex ON neededreference ( library );
CREATE INDEX IF NOT EXISTS neededindex_idneeded ON needed ( idneeded );
CREATE INDEX IF NOT EXISTS neededindex_idpackage ON needed ( idpackage );
CREATE INDEX IF NOT EXISTS neededindex_elfclass ON needed ( elfclass );
""")
def createMessagesIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.execute('CREATE INDEX IF NOT EXISTS messagesindex ON messages ( idpackage )')
def createCompileFlagsIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.execute('CREATE INDEX IF NOT EXISTS flagsindex ON flags ( chost,cflags,cxxflags )')
def createUseflagsIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS useflagsindex_useflags_idpackage ON useflags ( idpackage );
CREATE INDEX IF NOT EXISTS useflagsindex_useflags_idflag ON useflags ( idflag );
CREATE INDEX IF NOT EXISTS useflagsindex ON useflagsreference ( flagname );
""")
def createContentIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS contentindex_couple ON content ( idpackage );
CREATE INDEX IF NOT EXISTS contentindex_file ON content ( file );
""")
def createConfigProtectReferenceIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.execute('CREATE INDEX IF NOT EXISTS configprotectreferenceindex ON configprotectreference ( protect )')
def createBaseinfoIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS baseindex_atom ON baseinfo ( atom );
CREATE INDEX IF NOT EXISTS baseindex_branch_name ON baseinfo ( name,branch );
CREATE INDEX IF NOT EXISTS baseindex_branch_name_idcategory ON baseinfo ( name,idcategory,branch );
CREATE INDEX IF NOT EXISTS baseindex_idcategory ON baseinfo ( idcategory );
""")
def createLicensedataIndex(self):
if self.indexing:
if not self.doesTableExist("licensedata"):
return
with self.__write_mutex:
self.cursor.execute('CREATE INDEX IF NOT EXISTS licensedataindex ON licensedata ( licensename )')
def createLicensesIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.execute('CREATE INDEX IF NOT EXISTS licensesindex ON licenses ( license )')
def createCategoriesIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.execute('CREATE INDEX IF NOT EXISTS categoriesindex_category ON categories ( category )')
def createKeywordsIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS keywordsreferenceindex ON keywordsreference ( keywordname );
CREATE INDEX IF NOT EXISTS keywordsindex_idpackage ON keywords ( idpackage );
CREATE INDEX IF NOT EXISTS keywordsindex_idkeyword ON keywords ( idkeyword );
""")
def createDependenciesIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS dependenciesindex_idpackage ON dependencies ( idpackage );
CREATE INDEX IF NOT EXISTS dependenciesindex_iddependency ON dependencies ( iddependency );
CREATE INDEX IF NOT EXISTS dependenciesreferenceindex_dependency ON dependenciesreference ( dependency );
""")
def createCountersIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS countersindex_idpackage ON counters ( idpackage );
CREATE INDEX IF NOT EXISTS countersindex_counter ON counters ( counter );
""")
def createSourcesIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS sourcesindex_idpackage ON sources ( idpackage );
CREATE INDEX IF NOT EXISTS sourcesindex_idsource ON sources ( idsource );
CREATE INDEX IF NOT EXISTS sourcesreferenceindex_source ON sourcesreference ( source );
""")
def createProvideIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS provideindex_idpackage ON provide ( idpackage );
CREATE INDEX IF NOT EXISTS provideindex_atom ON provide ( atom );
""")
def createConflictsIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS conflictsindex_idpackage ON conflicts ( idpackage );
CREATE INDEX IF NOT EXISTS conflictsindex_atom ON conflicts ( conflict );
""")
def createExtrainfoIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.execute('CREATE INDEX IF NOT EXISTS extrainfoindex ON extrainfo ( description )')
self.cursor.execute('CREATE INDEX IF NOT EXISTS extrainfoindex_pkgindex ON extrainfo ( idpackage )')
def createEclassesIndex(self):
if self.indexing:
with self.__write_mutex:
self.cursor.executescript("""
CREATE INDEX IF NOT EXISTS eclassesindex_idpackage ON eclasses ( idpackage );
CREATE INDEX IF NOT EXISTS eclassesindex_idclass ON eclasses ( idclass );
CREATE INDEX IF NOT EXISTS eclassesreferenceindex_classname ON eclassesreference ( classname );
""")
def regenerateCountersTable(self, vdb_path, output = False):
self.createCountersTable()
# this is necessary now, counters table should be empty
self.cursor.execute("DELETE FROM counters;")
# assign a counter to an idpackage
myids = self.listAllIdpackages()
counter_path = etpConst['spm']['xpak_entries']['counter']
for myid in myids:
# get atom
myatom = self.retrieveAtom(myid)
mybranch = self.retrieveBranch(myid)
myatom = self.entropyTools.remove_tag(myatom)
myatomcounterpath = "%s%s/%s" % (vdb_path, myatom, counter_path,)
if os.path.isfile(myatomcounterpath):
try:
with open(myatomcounterpath, "r") as f:
counter = int(f.readline().strip())
except:
if output:
mytxt = "%s: %s: %s" % (
bold(_("ATTENTION")),
red(_("cannot open Spm counter file for")),
bold(myatom),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning"
)
continue
# insert id+counter
with self.__write_mutex:
try:
self.cursor.execute(
'INSERT into counters VALUES '
'(?,?,?)', ( counter, myid, mybranch )
)
except self.dbapi2.IntegrityError:
if output:
mytxt = "%s: %s: %s" % (
bold(_("ATTENTION")),
red(_("counter for atom is duplicated, ignoring")),
bold(myatom),
)
self.updateProgress(
mytxt,
importance = 1,
type = "warning"
)
continue
# don't trust counters, they might not be unique
self.commitChanges()
def clearTreeupdatesEntries(self, repository):
if not self.doesTableExist("treeupdates"):
self.createTreeupdatesTable()
# treeupdates
with self.__write_mutex:
self.cursor.execute("DELETE FROM treeupdates WHERE repository = (?)", (repository,))
self.commitChanges()
def resetTreeupdatesDigests(self):
with self.__write_mutex:
self.cursor.execute('UPDATE treeupdates SET digest = "-1"')
self.commitChanges()
def migrateCountersTable(self):
with self.__write_mutex:
self._migrateCountersTable()
def _migrateCountersTable(self):
self.cursor.execute('DROP TABLE IF EXISTS counterstemp;')
self.cursor.execute('CREATE TABLE counterstemp ( counter INTEGER, idpackage INTEGER, branch VARCHAR, PRIMARY KEY(idpackage,branch) );')
self.cursor.execute('select * from counters')
countersdata = self.cursor.fetchall()
self.cursor.executemany('INSERT INTO counterstemp VALUES (?,?,?)', countersdata)
self.cursor.execute('DROP TABLE counters')
self.cursor.execute('ALTER TABLE counterstemp RENAME TO counters')
self.commitChanges()
def createInstalledTableSource(self):
with self.__write_mutex:
self.cursor.execute('ALTER TABLE installedtable ADD source INTEGER;')
self.cursor.execute("""
UPDATE installedtable SET source = (?)
""", (etpConst['install_sources']['unknown'],))
def createPackagechangelogsTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE packagechangelogs ( category VARCHAR, name VARCHAR, changelog BLOB, PRIMARY KEY (category, name));')
def createAutomergefilesTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE automergefiles ( idpackage INTEGER, configfile VARCHAR, md5 VARCHAR );')
def createPackagesignaturesTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE packagesignatures ( idpackage INTEGER PRIMARY KEY, sha1 VARCHAR, sha256 VARCHAR, sha512 VARCHAR );')
def createPackagespmphases(self):
with self.__write_mutex:
self.cursor.execute("""
CREATE TABLE packagespmphases (
idpackage INTEGER PRIMARY KEY,
phases VARCHAR
);
""")
def createPackagesetsTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE packagesets ( setname VARCHAR, dependency VARCHAR );')
def createCategoriesdescriptionTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE categoriesdescription ( category VARCHAR, locale VARCHAR, description VARCHAR );')
def createTreeupdatesTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE treeupdates ( repository VARCHAR PRIMARY KEY, digest VARCHAR );')
def createLicensedataTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE licensedata ( licensename VARCHAR UNIQUE, text BLOB, compressed INTEGER );')
def createLicensesAcceptedTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE licenses_accepted ( licensename VARCHAR UNIQUE );')
def createTrashedcountersTable(self):
with self.__write_mutex:
self.cursor.execute('CREATE TABLE trashedcounters ( counter INTEGER );')
def createInstalledTable(self):
with self.__write_mutex:
self.cursor.execute('DROP TABLE IF EXISTS installedtable;')
self.cursor.execute('CREATE TABLE installedtable ( idpackage INTEGER PRIMARY KEY, repositoryname VARCHAR, source INTEGER );')
def addDependsRelationToDependsTable(self, iterable):
with self.__write_mutex:
self.cursor.executemany('INSERT into dependstable VALUES (?,?)', iterable)
if (self.entropyTools.is_user_in_entropy_group()) and \
(self.dbname.startswith(etpConst['serverdbid'])):
# force commit even if readonly, this will allow to automagically fix dependstable server side
self.connection.commit() # we don't care much about syncing the database since it's quite trivial
def clearDependsTable(self):
if not self.doesTableExist("dependstable"): return
self.cursor.execute("DROP TABLE IF EXISTS dependstable")
'''
@description: recreate dependstable table in the chosen database, it's used for caching searchDepends requests
@input Nothing
@output: Nothing
'''
def regenerateDependsTable(self, output = True):
depends = self.listAllDependencies()
self.createDependsTable()
count = 0
total = len(depends)
mydata = set()
am = self.atomMatch
up = self.updateProgress
for iddep, atom in depends:
count += 1
if output and ((count == 0) or (count % 150 == 0) or \
(count == total)):
up( red("Resolving %s") % (atom,), importance = 0,
type = "info", back = True, count = (count, total)
)
idpackage, rc = am(atom)
if idpackage == -1: continue
mydata.add((iddep, idpackage))
if mydata: self.addDependsRelationToDependsTable(mydata)
# now validate dependstable
self.sanitizeDependsTable()
def moveCountersToBranch(self, to_branch):
with self.__write_mutex:
self.cursor.execute('UPDATE counters SET branch = (?)', to_branch)
self.commitChanges()
self.clearCache()
def atomMatchFetchCache(self, *args):
if self.xcache:
cached = self.dumpTools.loadobj("%s/%s/%s" % (self.dbMatchCacheKey, self.dbname, hash(tuple(args)),))
if cached != None: return cached
def atomMatchStoreCache(self, *args, **kwargs):
if self.xcache:
self.Cacher.push("%s/%s/%s" % (
self.dbMatchCacheKey,self.dbname,hash(tuple(args)),),
kwargs.get('result')
)
def atomMatchValidateCache(self, cached_obj, multiMatch, extendedResults):
# time wasted for a reason
data, rc = cached_obj
if rc != 0: return cached_obj
if (not extendedResults) and (not multiMatch):
if not self.isIDPackageAvailable(data): return None
elif extendedResults and (not multiMatch):
# ((idpackage,0,version,versiontag,revision,),0)
if not self.isIDPackageAvailable(data[0]): return None
elif extendedResults and multiMatch:
# (set([(idpackage,0,version,version_tag,revision) for x in dbpkginfo]),0)
idpackages = set([x[0] for x in data])
if not self.areIDPackagesAvailable(idpackages): return None
elif (not extendedResults) and multiMatch:
# (set([x[0] for x in dbpkginfo]),0)
idpackages = set(data)
if not self.areIDPackagesAvailable(idpackages): return None
return cached_obj
def _idpackageValidator_live(self, idpackage, reponame):
if (idpackage, reponame) in self.SystemSettings['live_packagemasking']['mask_matches']:
# do not cache this
return -1, self.SystemSettings['pkg_masking_reference']['user_live_mask']
elif (idpackage, reponame) in self.SystemSettings['live_packagemasking']['unmask_matches']:
return idpackage, self.SystemSettings['pkg_masking_reference']['user_live_unmask']
def _idpackageValidator_user_package_mask(self, idpackage, reponame, live):
# check if user package.mask needs it masked
mykw = "%smask_ids" % (reponame,)
user_package_mask_ids = self.SystemSettings.get(mykw)
if not isinstance(user_package_mask_ids, set):
user_package_mask_ids = set()
for atom in self.SystemSettings['mask']:
matches, r = self.atomMatch(atom, multiMatch = True, packagesFilter = False)
if r != 0:
continue
user_package_mask_ids |= set(matches)
self.SystemSettings[mykw] = user_package_mask_ids
if idpackage in user_package_mask_ids:
# sorry, masked
myr = self.SystemSettings['pkg_masking_reference']['user_package_mask']
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
validator_cache[(idpackage, reponame, live)] = -1, myr
except KeyError: # system settings client plugin not found
pass
return -1, myr
def _idpackageValidator_user_package_unmask(self, idpackage, reponame, live):
# see if we can unmask by just lookin into user package.unmask stuff -> self.SystemSettings['unmask']
mykw = "%sunmask_ids" % (reponame,)
user_package_unmask_ids = self.SystemSettings.get(mykw)
if not isinstance(user_package_unmask_ids, set):
user_package_unmask_ids = set()
for atom in self.SystemSettings['unmask']:
matches, r = self.atomMatch(atom, multiMatch = True, packagesFilter = False)
if r != 0:
continue
user_package_unmask_ids |= set(matches)
self.SystemSettings[mykw] = user_package_unmask_ids
if idpackage in user_package_unmask_ids:
myr = self.SystemSettings['pkg_masking_reference']['user_package_unmask']
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
validator_cache[(idpackage, reponame, live)] = idpackage, myr
except KeyError: # system settings client plugin not found
pass
return idpackage, myr
def _idpackageValidator_packages_db_mask(self, idpackage, reponame, live):
# check if repository packages.db.mask needs it masked
repos_mask = self.SystemSettings['repos_mask']
repomask = repos_mask.get(reponame)
if isinstance(repomask, set):
# first, seek into generic masking, all branches
mask_repo_id = "%s_ids@@:of:%s" % (reponame, reponame,) # avoid issues with repository names
repomask_ids = repos_mask.get(mask_repo_id)
if not isinstance(repomask_ids, set):
repomask_ids = set()
for atom in repomask:
matches, r = self.atomMatch(atom, multiMatch = True, packagesFilter = False)
if r != 0:
continue
repomask_ids |= set(matches)
repos_mask[mask_repo_id] = repomask_ids
if idpackage in repomask_ids:
myr = self.SystemSettings['pkg_masking_reference']['repository_packages_db_mask']
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
validator_cache[(idpackage, reponame, live)] = -1, myr
except KeyError: # system settings client plugin not found
pass
return -1, myr
def _idpackageValidator_package_license_mask(self, idpackage, reponame, live):
if self.SystemSettings['license_mask']:
mylicenses = self.retrieveLicense(idpackage)
mylicenses = mylicenses.strip().split()
lic_mask = self.SystemSettings['license_mask']
for mylicense in mylicenses:
if mylicense not in lic_mask: continue
myr = self.SystemSettings['pkg_masking_reference']['user_license_mask']
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
validator_cache[(idpackage, reponame, live)] = -1, myr
except KeyError: # system settings client plugin not found
pass
return -1, myr
def _idpackageValidator_keyword_mask(self, idpackage, reponame, live):
mykeywords = self.retrieveKeywords(idpackage)
# WORKAROUND for buggy entries
if not mykeywords: mykeywords = [''] # ** is fine then
# firstly, check if package keywords are in etpConst['keywords']
# (universal keywords have been merged from package.mask)
for key in etpConst['keywords']:
if key not in mykeywords: continue
myr = self.SystemSettings['pkg_masking_reference']['system_keyword']
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
validator_cache[(idpackage, reponame, live)] = idpackage, myr
except KeyError: # system settings client plugin not found
pass
return idpackage, myr
# if we get here, it means we didn't find mykeywords in etpConst['keywords']
# we need to seek self.SystemSettings['keywords']
# seek in repository first
if reponame in self.SystemSettings['keywords']['repositories']:
for keyword in self.SystemSettings['keywords']['repositories'][reponame]:
if keyword not in mykeywords: continue
keyword_data = self.SystemSettings['keywords']['repositories'][reponame].get(keyword)
if not keyword_data: continue
if "*" in keyword_data: # all packages in this repo with keyword "keyword" are ok
myr = self.SystemSettings['pkg_masking_reference']['user_repo_package_keywords_all']
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
validator_cache[(idpackage, reponame, live)] = idpackage, myr
except KeyError: # system settings client plugin not found
pass
return idpackage, myr
kwd_key = "%s_ids" % (keyword,)
keyword_data_ids = self.SystemSettings['keywords']['repositories'][reponame].get(kwd_key)
if not isinstance(keyword_data_ids, set):
keyword_data_ids = set()
for atom in keyword_data:
matches, r = self.atomMatch(atom, multiMatch = True, packagesFilter = False)
if r != 0:
continue
keyword_data_ids |= matches
self.SystemSettings['keywords']['repositories'][reponame][kwd_key] = keyword_data_ids
if idpackage in keyword_data_ids:
myr = self.SystemSettings['pkg_masking_reference']['user_repo_package_keywords']
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
validator_cache[(idpackage, reponame, live)] = idpackage, myr
except KeyError: # system settings client plugin not found
pass
return idpackage, myr
# if we get here, it means we didn't find a match in repositories
# so we scan packages, last chance
for keyword in self.SystemSettings['keywords']['packages']:
# first of all check if keyword is in mykeywords
if keyword not in mykeywords: continue
keyword_data = self.SystemSettings['keywords']['packages'].get(keyword)
if not keyword_data: continue
kwd_key = "%s_ids" % (keyword,)
keyword_data_ids = self.SystemSettings['keywords']['packages'].get(reponame+kwd_key)
if not isinstance(keyword_data_ids, set):
keyword_data_ids = set()
for atom in keyword_data:
# match atom
matches, r = self.atomMatch(atom, multiMatch = True, packagesFilter = False)
if r != 0:
continue
keyword_data_ids |= matches
self.SystemSettings['keywords']['packages'][reponame+kwd_key] = keyword_data_ids
if idpackage in keyword_data_ids:
# valid!
myr = self.SystemSettings['pkg_masking_reference']['user_package_keywords']
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
validator_cache[(idpackage, reponame, live)] = idpackage, myr
except KeyError: # system settings client plugin not found
pass
return idpackage, myr
# function that validate one atom by reading keywords settings
# validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
def idpackageValidator(self, idpackage, live = True):
if self.dbname == etpConst['clientdbid']:
return idpackage, 0
elif self.dbname.startswith(etpConst['serverdbid']):
return idpackage, 0
reponame = self.dbname[len(etpConst['dbnamerepoprefix']):]
try:
validator_cache = self.SystemSettings[self.client_settings_plugin_id]['masking_validation']['cache']
cached = validator_cache.get((idpackage, reponame, live))
if cached != None:
return cached
# avoid memleaks
if len(validator_cache) > 10000:
validator_cache.clear()
except KeyError: # plugin does not exist
pass
if live:
data = self._idpackageValidator_live(idpackage, reponame)
if data: return data
data = self._idpackageValidator_user_package_mask(idpackage, reponame, live)
if data: return data
data = self._idpackageValidator_user_package_unmask(idpackage, reponame, live)
if data: return data
data = self._idpackageValidator_packages_db_mask(idpackage, reponame, live)
if data: return data
data = self._idpackageValidator_package_license_mask(idpackage, reponame, live)
if data: return data
data = self._idpackageValidator_keyword_mask(idpackage, reponame, live)
if data: return data
# holy crap, can't validate
myr = self.SystemSettings['pkg_masking_reference']['completely_masked']
validator_cache[(idpackage, reponame, live)] = -1, myr
return -1, myr
# packages filter used by atomMatch, input must me foundIDs, a list like this:
# [608,1867]
def packagesFilter(self, results):
# keywordsFilter ONLY FILTERS results if
# self.dbname.startswith(etpConst['dbnamerepoprefix']) => repository database is open
if not self.dbname.startswith(etpConst['dbnamerepoprefix']):
return results
newresults = set()
for idpackage in results:
idpackage, reason = self.idpackageValidator(idpackage)
if idpackage == -1: continue
newresults.add(idpackage)
return newresults
def __filterSlot(self, idpackage, slot):
if slot == None:
return idpackage
dbslot = self.retrieveSlot(idpackage)
if str(dbslot) == str(slot):
return idpackage
def __filterTag(self, idpackage, tag, operators):
if tag == None:
return idpackage
dbtag = self.retrieveVersionTag(idpackage)
compare = cmp(tag, dbtag)
if not operators or operators == "=":
if compare == 0:
return idpackage
else:
return self.__do_operator_compare(idpackage, operators, compare)
def __filterUse(self, idpackage, use):
if not use:
return idpackage
pkguse = self.retrieveUseflags(idpackage)
disabled = set([x[1:] for x in use if x.startswith("-")])
enabled = set([x for x in use if not x.startswith("-")])
enabled_not_satisfied = enabled - pkguse
# check enabled
if enabled_not_satisfied:
return None
# check disabled
disabled_not_satisfied = disabled - pkguse
if len(disabled_not_satisfied) != len(disabled):
return None
return idpackage
def __do_operator_compare(self, token, operators, compare):
if operators == ">" and compare == -1:
return token
elif operators == ">=" and compare < 1:
return token
elif operators == "<" and compare == 1:
return token
elif operators == "<=" and compare > -1:
return token
def __filterSlotTagUse(self, foundIDs, slot, tag, use, operators):
def myfilter(idpackage):
idpackage = self.__filterSlot(idpackage, slot)
if not idpackage:
return False
idpackage = self.__filterUse(idpackage, use)
if not idpackage:
return False
idpackage = self.__filterTag(idpackage, tag, operators)
if not idpackage:
return False
return True
return set(filter(myfilter, foundIDs))
'''
@description: matches the user chosen package name+ver, if possibile, in a single repository
@input atom: string, atom to match
@input caseSensitive: bool, should the atom be parsed case sensitive?
@input matchSlot: string, match atoms with the provided slot
@input multiMatch: bool, return all the available atoms
@input matchBranches: tuple or list, match packages only in the specified branches
@input matchTag: match packages only for the specified tag
@input matchUse: match packages only if it owns the specified use flags
@input packagesFilter: enable/disable package.mask/.keywords/.unmask filter
@output: the package id, if found, otherwise -1 plus the status, 0 = ok, 1 = error
'''
def atomMatch(self, atom, caseSensitive = True, matchSlot = None, multiMatch = False,
matchBranches = (), matchTag = None, matchUse = (), packagesFilter = True,
matchRevision = None, extendedResults = False, useCache = True ):
if not atom:
return -1, 1
if useCache:
cached = self.atomMatchFetchCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults
)
if isinstance(cached, tuple):
try:
cached = self.atomMatchValidateCache(cached, multiMatch, extendedResults)
except (TypeError, ValueError, IndexError, KeyError,):
cached = None
if isinstance(cached, tuple):
return cached
atomTag = self.entropyTools.dep_gettag(atom)
try:
atomUse = self.entropyTools.dep_getusedeps(atom)
except InvalidAtom:
atomUse = ()
atomSlot = self.entropyTools.dep_getslot(atom)
atomRev = self.entropyTools.dep_get_entropy_revision(atom)
if isinstance(atomRev, (int, long,)):
if atomRev < 0: atomRev = None
# use match
scan_atom = self.entropyTools.remove_usedeps(atom)
if (not matchUse) and (atomUse):
matchUse = atomUse
# tag match
scan_atom = self.entropyTools.remove_tag(scan_atom)
if (matchTag == None) and (atomTag != None):
matchTag = atomTag
# slot match
scan_atom = self.entropyTools.remove_slot(scan_atom)
if (matchSlot == None) and (atomSlot != None):
matchSlot = atomSlot
# revision match
scan_atom = self.entropyTools.remove_entropy_revision(scan_atom)
if (matchRevision == None) and (atomRev != None):
matchRevision = atomRev
branch_list = ()
direction = ''
justname = True
pkgkey = ''
strippedAtom = ''
foundIDs = []
dbpkginfo = set()
if scan_atom:
while 1:
pkgversion = ''
# check for direction
strippedAtom = self.entropyTools.dep_getcpv(scan_atom)
if scan_atom[-1] == "*":
strippedAtom += "*"
direction = scan_atom[0:len(scan_atom)-len(strippedAtom)]
justname = self.entropyTools.isjustname(strippedAtom)
pkgkey = strippedAtom
if justname == 0:
# get version
data = self.entropyTools.catpkgsplit(strippedAtom)
if data == None: break # badly formatted
pkgversion = data[2]+"-"+data[3]
pkgkey = self.entropyTools.dep_getkey(strippedAtom)
splitkey = pkgkey.split("/")
if (len(splitkey) == 2):
pkgname = splitkey[1]
pkgcat = splitkey[0]
else:
pkgname = splitkey[0]
pkgcat = "null"
branch_list = (self.db_branch,)
if matchBranches:
# force to tuple for security
branch_list = tuple(matchBranches)
break
if branch_list:
# IDs found in the database that match our search
foundIDs = self.__generate_found_ids_match(branch_list, pkgkey, pkgname, pkgcat, caseSensitive, multiMatch)
### FILTERING
# filter slot and tag
if foundIDs:
foundIDs = self.__filterSlotTagUse(foundIDs, matchSlot, matchTag, matchUse, direction)
if packagesFilter:
foundIDs = self.packagesFilter(foundIDs)
### END FILTERING
if foundIDs:
dbpkginfo = self.__handle_found_ids_match(foundIDs, direction, matchTag, matchRevision, justname, strippedAtom, pkgversion)
if not dbpkginfo:
if extendedResults:
if multiMatch:
x = set()
else:
x = (-1, 1, None, None, None,)
self.atomMatchStoreCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults, result = (x, 1)
)
return x, 1
else:
if multiMatch:
x = set()
else:
x = -1
self.atomMatchStoreCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults, result = (x, 1)
)
return x, 1
if multiMatch:
if extendedResults:
x = set([(x[0], 0, x[1], self.retrieveVersionTag(x[0]), self.retrieveRevision(x[0])) for x in dbpkginfo])
self.atomMatchStoreCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults, result = (x, 0)
)
return x, 0
else:
x = set([x[0] for x in dbpkginfo])
self.atomMatchStoreCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults, result = (x, 0)
)
return x, 0
if len(dbpkginfo) == 1:
x = dbpkginfo.pop()
if extendedResults:
x = (x[0], 0, x[1], self.retrieveVersionTag(x[0]), self.retrieveRevision(x[0]))
self.atomMatchStoreCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults, result = (x, 0)
)
return x, 0
else:
self.atomMatchStoreCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults, result = (x[0], 0)
)
return x[0], 0
dbpkginfo = list(dbpkginfo)
pkgdata = {}
versions = set()
for x in dbpkginfo:
info_tuple = (x[1], self.retrieveVersionTag(x[0]), self.retrieveRevision(x[0]))
versions.add(info_tuple)
pkgdata[info_tuple] = x[0]
newer = self.entropyTools.get_entropy_newer_version(list(versions))[0]
x = pkgdata[newer]
if extendedResults:
x = (x, 0, newer[0], newer[1], newer[2])
self.atomMatchStoreCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults, result = (x, 0)
)
return x, 0
else:
self.atomMatchStoreCache(
atom, caseSensitive, matchSlot,
multiMatch, matchBranches, matchTag,
matchUse, packagesFilter, matchRevision,
extendedResults, result = (x, 0)
)
return x, 0
def __generate_found_ids_match(self, branch_list, pkgkey, pkgname, pkgcat, caseSensitive, multiMatch):
foundIDs = set()
for idx in branch_list:
if pkgcat == "null":
results = self.searchPackagesByName(
pkgname, sensitive = caseSensitive,
branch = idx, justid = True
)
else:
results = self.searchPackagesByNameAndCategory(
name = pkgname, category = pkgcat, branch = idx,
sensitive = caseSensitive, justid = True
)
mypkgcat = pkgcat
mypkgname = pkgname
virtual = False
# if it's a PROVIDE, search with searchProvide
# there's no package with that name
if (not results) and (mypkgcat == "virtual"):
virtuals = self.searchProvide(pkgkey, branch = idx, justid = True)
if virtuals:
virtual = True
mypkgname = self.retrieveName(virtuals[0])
mypkgcat = self.retrieveCategory(virtuals[0])
results = virtuals
# now validate
if not results:
continue # search into a stabler branch
elif (len(results) > 1):
# if it's because category differs, it's a problem
foundCat = None
cats = set()
for idpackage in results:
cat = self.retrieveCategory(idpackage)
cats.add(cat)
if (cat == mypkgcat) or ((not virtual) and (mypkgcat == "virtual") and (cat == mypkgcat)):
# in case of virtual packages only (that they're not stored as provide)
foundCat = cat
# if we found something at least...
if (not foundCat) and (len(cats) == 1) and (mypkgcat in ("virtual", "null")):
foundCat = sorted(cats)[0]
if not foundCat:
# got the issue
continue
# we can use foundCat
mypkgcat = foundCat
# we need to search using the category
if (not multiMatch) and (pkgcat == "null" or virtual):
# we searched by name, we need to search using category
results = self.searchPackagesByNameAndCategory(
name = mypkgname, category = mypkgcat,
branch = idx, sensitive = caseSensitive, justid = True
)
# validate again
if not results:
continue # search into another branch
# if we get here, we have found the needed IDs
foundIDs |= set(results)
break
else:
idpackage = results[0]
# if mypkgcat is virtual, we can force
if (mypkgcat == "virtual") and (not virtual):
# in case of virtual packages only (that they're not stored as provide)
mypkgcat = self.retrieveCategory(idpackage)
# check if category matches
if mypkgcat != "null":
foundCat = self.retrieveCategory(idpackage)
if mypkgcat == foundCat:
foundIDs.add(idpackage)
continue
foundIDs.add(idpackage)
break
return foundIDs
def __handle_found_ids_match(self, foundIDs, direction, matchTag, matchRevision, justname, strippedAtom, pkgversion):
dbpkginfo = set()
# now we have to handle direction
if ((direction) or ((not direction) and (not justname)) or ((not direction) and (not justname) and strippedAtom.endswith("*"))) and foundIDs:
if (not justname) and \
((direction == "~") or (direction == "=") or \
(direction == '' and not justname) or (direction == '' and not justname and strippedAtom.endswith("*"))):
# any revision within the version specified OR the specified version
if (direction == '' and not justname):
direction = "="
# remove gentoo revision (-r0 if none)
if (direction == "="):
if (pkgversion.split("-")[-1] == "r0"):
pkgversion = self.entropyTools.remove_revision(pkgversion)
if (direction == "~"):
pkgrevision = self.entropyTools.dep_get_portage_revision(pkgversion)
pkgversion = self.entropyTools.remove_revision(pkgversion)
for idpackage in foundIDs:
dbver = self.retrieveVersion(idpackage)
if (direction == "~"):
myrev = self.entropyTools.dep_get_portage_revision(dbver)
myver = self.entropyTools.remove_revision(dbver)
if myver == pkgversion and pkgrevision <= myrev:
# found
dbpkginfo.add((idpackage, dbver))
else:
# media-libs/test-1.2* support
if pkgversion[-1] == "*":
if dbver.startswith(pkgversion[:-1]):
dbpkginfo.add((idpackage, dbver))
elif (matchRevision != None) and (pkgversion == dbver):
dbrev = self.retrieveRevision(idpackage)
if dbrev == matchRevision:
dbpkginfo.add((idpackage, dbver))
elif (pkgversion == dbver) and (matchRevision == None):
dbpkginfo.add((idpackage, dbver))
elif (direction.find(">") != -1) or (direction.find("<") != -1):
if not justname:
# remove revision (-r0 if none)
if pkgversion.endswith("r0"):
# remove
self.entropyTools.remove_revision(pkgversion)
for idpackage in foundIDs:
revcmp = 0
tagcmp = 0
if matchRevision != None:
dbrev = self.retrieveRevision(idpackage)
revcmp = cmp(matchRevision, dbrev)
if matchTag != None:
dbtag = self.retrieveVersionTag(idpackage)
tagcmp = cmp(matchTag, dbtag)
dbver = self.retrieveVersion(idpackage)
pkgcmp = self.entropyTools.compare_versions(pkgversion, dbver)
if pkgcmp == None:
import warnings
warnings.warn("WARNING, invalid version string stored in %s: %s <-> %s" % (self.dbname, pkgversion, dbver,))
continue
if direction == ">":
if pkgcmp < 0:
dbpkginfo.add((idpackage, dbver))
elif (matchRevision != None) and pkgcmp <= 0 and revcmp < 0:
dbpkginfo.add((idpackage, dbver))
elif (matchTag != None) and tagcmp < 0:
dbpkginfo.add((idpackage, dbver))
elif direction == "<":
if pkgcmp > 0:
dbpkginfo.add((idpackage, dbver))
elif (matchRevision != None) and pkgcmp >= 0 and revcmp > 0:
dbpkginfo.add((idpackage, dbver))
elif (matchTag != None) and tagcmp > 0:
dbpkginfo.add((idpackage, dbver))
elif direction == ">=":
if (matchRevision != None) and pkgcmp <= 0:
if pkgcmp == 0:
if revcmp <= 0:
dbpkginfo.add((idpackage, dbver))
else:
dbpkginfo.add((idpackage, dbver))
elif pkgcmp <= 0 and matchRevision == None:
dbpkginfo.add((idpackage, dbver))
elif (matchTag != None) and tagcmp <= 0:
dbpkginfo.add((idpackage, dbver))
elif direction == "<=":
if (matchRevision != None) and pkgcmp >= 0:
if pkgcmp == 0:
if revcmp >= 0:
dbpkginfo.add((idpackage, dbver))
else:
dbpkginfo.add((idpackage, dbver))
elif pkgcmp >= 0 and matchRevision == None:
dbpkginfo.add((idpackage, dbver))
elif (matchTag != None) and tagcmp >= 0:
dbpkginfo.add((idpackage, dbver))
else: # just the key
dbpkginfo = set([(x, self.retrieveVersion(x),) for x in foundIDs])
return dbpkginfo