mirror of
git://git.yoctoproject.org/poky.git
synced 2025-07-19 21:09:03 +02:00

This adds the SPDX-License-Identifier license headers to the majority of our source files to make it clearer exactly which license files are under. The bulk of the files are under GPL v2.0 with one found to be under V2.0 or later, some under MIT and some have dual license. There are some files which are potentially harder to classify where we've imported upstream code and those can be handled specifically in later commits. The COPYING file is replaced with LICENSE.X files which contain the full license texts. (Bitbake rev: ff237c33337f4da2ca06c3a2c49699bc26608a6b) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
281 lines
10 KiB
Python
281 lines
10 KiB
Python
#
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
#
|
|
|
|
import logging
|
|
import os.path
|
|
import errno
|
|
import prserv
|
|
import time
|
|
|
|
try:
|
|
import sqlite3
|
|
except ImportError:
|
|
from pysqlite2 import dbapi2 as sqlite3
|
|
|
|
logger = logging.getLogger("BitBake.PRserv")
|
|
|
|
sqlversion = sqlite3.sqlite_version_info
|
|
if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3):
|
|
raise Exception("sqlite3 version 3.3.0 or later is required.")
|
|
|
|
#
|
|
# "No History" mode - for a given query tuple (version, pkgarch, checksum),
|
|
# the returned value will be the largest among all the values of the same
|
|
# (version, pkgarch). This means the PR value returned can NOT be decremented.
|
|
#
|
|
# "History" mode - Return a new higher value for previously unseen query
|
|
# tuple (version, pkgarch, checksum), otherwise return historical value.
|
|
# Value can decrement if returning to a previous build.
|
|
#
|
|
|
|
class PRTable(object):
|
|
def __init__(self, conn, table, nohist):
|
|
self.conn = conn
|
|
self.nohist = nohist
|
|
self.dirty = False
|
|
if nohist:
|
|
self.table = "%s_nohist" % table
|
|
else:
|
|
self.table = "%s_hist" % table
|
|
|
|
self._execute("CREATE TABLE IF NOT EXISTS %s \
|
|
(version TEXT NOT NULL, \
|
|
pkgarch TEXT NOT NULL, \
|
|
checksum TEXT NOT NULL, \
|
|
value INTEGER, \
|
|
PRIMARY KEY (version, pkgarch, checksum));" % self.table)
|
|
|
|
def _execute(self, *query):
|
|
"""Execute a query, waiting to acquire a lock if necessary"""
|
|
start = time.time()
|
|
end = start + 20
|
|
while True:
|
|
try:
|
|
return self.conn.execute(*query)
|
|
except sqlite3.OperationalError as exc:
|
|
if 'is locked' in str(exc) and end > time.time():
|
|
continue
|
|
raise exc
|
|
|
|
def sync(self):
|
|
self.conn.commit()
|
|
self._execute("BEGIN EXCLUSIVE TRANSACTION")
|
|
|
|
def sync_if_dirty(self):
|
|
if self.dirty:
|
|
self.sync()
|
|
self.dirty = False
|
|
|
|
def _getValueHist(self, version, pkgarch, checksum):
|
|
data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table,
|
|
(version, pkgarch, checksum))
|
|
row=data.fetchone()
|
|
if row != None:
|
|
return row[0]
|
|
else:
|
|
#no value found, try to insert
|
|
try:
|
|
self._execute("INSERT INTO %s VALUES (?, ?, ?, (select ifnull(max(value)+1,0) from %s where version=? AND pkgarch=?));"
|
|
% (self.table,self.table),
|
|
(version,pkgarch, checksum,version, pkgarch))
|
|
except sqlite3.IntegrityError as exc:
|
|
logger.error(str(exc))
|
|
|
|
self.dirty = True
|
|
|
|
data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table,
|
|
(version, pkgarch, checksum))
|
|
row=data.fetchone()
|
|
if row != None:
|
|
return row[0]
|
|
else:
|
|
raise prserv.NotFoundError
|
|
|
|
def _getValueNohist(self, version, pkgarch, checksum):
|
|
data=self._execute("SELECT value FROM %s \
|
|
WHERE version=? AND pkgarch=? AND checksum=? AND \
|
|
value >= (select max(value) from %s where version=? AND pkgarch=?);"
|
|
% (self.table, self.table),
|
|
(version, pkgarch, checksum, version, pkgarch))
|
|
row=data.fetchone()
|
|
if row != None:
|
|
return row[0]
|
|
else:
|
|
#no value found, try to insert
|
|
try:
|
|
self._execute("INSERT OR REPLACE INTO %s VALUES (?, ?, ?, (select ifnull(max(value)+1,0) from %s where version=? AND pkgarch=?));"
|
|
% (self.table,self.table),
|
|
(version, pkgarch, checksum, version, pkgarch))
|
|
except sqlite3.IntegrityError as exc:
|
|
logger.error(str(exc))
|
|
self.conn.rollback()
|
|
|
|
self.dirty = True
|
|
|
|
data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table,
|
|
(version, pkgarch, checksum))
|
|
row=data.fetchone()
|
|
if row != None:
|
|
return row[0]
|
|
else:
|
|
raise prserv.NotFoundError
|
|
|
|
def getValue(self, version, pkgarch, checksum):
|
|
if self.nohist:
|
|
return self._getValueNohist(version, pkgarch, checksum)
|
|
else:
|
|
return self._getValueHist(version, pkgarch, checksum)
|
|
|
|
def _importHist(self, version, pkgarch, checksum, value):
|
|
val = None
|
|
data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table,
|
|
(version, pkgarch, checksum))
|
|
row = data.fetchone()
|
|
if row != None:
|
|
val=row[0]
|
|
else:
|
|
#no value found, try to insert
|
|
try:
|
|
self._execute("INSERT INTO %s VALUES (?, ?, ?, ?);" % (self.table),
|
|
(version, pkgarch, checksum, value))
|
|
except sqlite3.IntegrityError as exc:
|
|
logger.error(str(exc))
|
|
|
|
self.dirty = True
|
|
|
|
data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table,
|
|
(version, pkgarch, checksum))
|
|
row = data.fetchone()
|
|
if row != None:
|
|
val = row[0]
|
|
return val
|
|
|
|
def _importNohist(self, version, pkgarch, checksum, value):
|
|
try:
|
|
#try to insert
|
|
self._execute("INSERT INTO %s VALUES (?, ?, ?, ?);" % (self.table),
|
|
(version, pkgarch, checksum,value))
|
|
except sqlite3.IntegrityError as exc:
|
|
#already have the record, try to update
|
|
try:
|
|
self._execute("UPDATE %s SET value=? WHERE version=? AND pkgarch=? AND checksum=? AND value<?"
|
|
% (self.table),
|
|
(value,version,pkgarch,checksum,value))
|
|
except sqlite3.IntegrityError as exc:
|
|
logger.error(str(exc))
|
|
|
|
self.dirty = True
|
|
|
|
data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=? AND value>=?;" % self.table,
|
|
(version,pkgarch,checksum,value))
|
|
row=data.fetchone()
|
|
if row != None:
|
|
return row[0]
|
|
else:
|
|
return None
|
|
|
|
def importone(self, version, pkgarch, checksum, value):
|
|
if self.nohist:
|
|
return self._importNohist(version, pkgarch, checksum, value)
|
|
else:
|
|
return self._importHist(version, pkgarch, checksum, value)
|
|
|
|
def export(self, version, pkgarch, checksum, colinfo):
|
|
metainfo = {}
|
|
#column info
|
|
if colinfo:
|
|
metainfo['tbl_name'] = self.table
|
|
metainfo['core_ver'] = prserv.__version__
|
|
metainfo['col_info'] = []
|
|
data = self._execute("PRAGMA table_info(%s);" % self.table)
|
|
for row in data:
|
|
col = {}
|
|
col['name'] = row['name']
|
|
col['type'] = row['type']
|
|
col['notnull'] = row['notnull']
|
|
col['dflt_value'] = row['dflt_value']
|
|
col['pk'] = row['pk']
|
|
metainfo['col_info'].append(col)
|
|
|
|
#data info
|
|
datainfo = []
|
|
|
|
if self.nohist:
|
|
sqlstmt = "SELECT T1.version, T1.pkgarch, T1.checksum, T1.value FROM %s as T1, \
|
|
(SELECT version,pkgarch,max(value) as maxvalue FROM %s GROUP BY version,pkgarch) as T2 \
|
|
WHERE T1.version=T2.version AND T1.pkgarch=T2.pkgarch AND T1.value=T2.maxvalue " % (self.table, self.table)
|
|
else:
|
|
sqlstmt = "SELECT * FROM %s as T1 WHERE 1=1 " % self.table
|
|
sqlarg = []
|
|
where = ""
|
|
if version:
|
|
where += "AND T1.version=? "
|
|
sqlarg.append(str(version))
|
|
if pkgarch:
|
|
where += "AND T1.pkgarch=? "
|
|
sqlarg.append(str(pkgarch))
|
|
if checksum:
|
|
where += "AND T1.checksum=? "
|
|
sqlarg.append(str(checksum))
|
|
|
|
sqlstmt += where + ";"
|
|
|
|
if len(sqlarg):
|
|
data = self._execute(sqlstmt, tuple(sqlarg))
|
|
else:
|
|
data = self._execute(sqlstmt)
|
|
for row in data:
|
|
if row['version']:
|
|
col = {}
|
|
col['version'] = row['version']
|
|
col['pkgarch'] = row['pkgarch']
|
|
col['checksum'] = row['checksum']
|
|
col['value'] = row['value']
|
|
datainfo.append(col)
|
|
return (metainfo, datainfo)
|
|
|
|
def dump_db(self, fd):
|
|
writeCount = 0
|
|
for line in self.conn.iterdump():
|
|
writeCount = writeCount + len(line) + 1
|
|
fd.write(line)
|
|
fd.write('\n')
|
|
return writeCount
|
|
|
|
class PRData(object):
|
|
"""Object representing the PR database"""
|
|
def __init__(self, filename, nohist=True):
|
|
self.filename=os.path.abspath(filename)
|
|
self.nohist=nohist
|
|
#build directory hierarchy
|
|
try:
|
|
os.makedirs(os.path.dirname(self.filename))
|
|
except OSError as e:
|
|
if e.errno != errno.EEXIST:
|
|
raise e
|
|
self.connection=sqlite3.connect(self.filename, isolation_level="EXCLUSIVE", check_same_thread = False)
|
|
self.connection.row_factory=sqlite3.Row
|
|
self.connection.execute("pragma synchronous = off;")
|
|
self.connection.execute("PRAGMA journal_mode = WAL;")
|
|
self._tables={}
|
|
|
|
def disconnect(self):
|
|
self.connection.close()
|
|
|
|
def __getitem__(self,tblname):
|
|
if not isinstance(tblname, str):
|
|
raise TypeError("tblname argument must be a string, not '%s'" %
|
|
type(tblname))
|
|
if tblname in self._tables:
|
|
return self._tables[tblname]
|
|
else:
|
|
tableobj = self._tables[tblname] = PRTable(self.connection, tblname, self.nohist)
|
|
return tableobj
|
|
|
|
def __delitem__(self, tblname):
|
|
if tblname in self._tables:
|
|
del self._tables[tblname]
|
|
logger.info("drop table %s" % (tblname))
|
|
self.connection.execute("DROP TABLE IF EXISTS %s;" % tblname)
|