blob: 3a98b0ced83a33951118ac82c80c18268aa16544 [file] [log] [blame]
import struct
from sqlalchemy import *
from sqlalchemy.orm import relation, relationship
from sqlalchemy.ext.declarative import declarative_base
# DB Declaration
Base = declarative_base()
class KeyName(Base):
__tablename__ = "key_names"
id = Column(Integer, nullable=False, primary_key=True)
name = Column('key', String, nullable=False)
def __repr__(self):
return "%s%r" % (
self.__class__.__name__, (self.id, self.name))
class RuleResult(Base):
__tablename__ = "rule_results"
id = Column(Integer, nullable=False, primary_key=True)
key_id = Column(Integer, ForeignKey(KeyName.id),
nullable=False)
value_bytes = Column("value", Binary, nullable=False)
built_at = Column(Integer, nullable=False)
computed_at = Column(Integer, nullable=False)
key = relation(KeyName)
dependencies_bytes = Column("dependencies", Binary, nullable=True)
def __repr__(self):
return "%s%r" % (
self.__class__.__name__, (self.id, self.key, self.value,
self.built_at, self.computed_at))
@property
def value(self):
return BuildValue(self.value_bytes)
@property
def dependencies(self):
if self.dependencies_bytes is None:
return []
else :
num_dependencies = len(self.dependencies_bytes) / 8
return struct.unpack("<" + str(num_dependencies) + "Q",
self.dependencies_bytes)
###
class BuildValue(object):
# FIXME: This is a manually Python translation of the C++
# llbuild::buildsystem::BuildValue type, which is unfortunate, but it isn't
# available via an API we can access directly yet.
kinds = [
"Invalid",
"VirtualInput", "ExistingInput", "MissingInput",
"DirectoryContents", "DirectoryTreeSignature",
"StaleFileRemoval", "MissingOutput", "FailedInput",
"SuccessfulCommand", "FailedCommand",
"PropagatedFailureCommand", "CancelledCommand", "SkippedCommand",
"Target",
]
def __init__(self, data):
bytes = str(data)
# The first byte is the kind.
if bytes:
self.kind = self.__class__.kinds[struct.unpack("<B", bytes[0])[0]]
bytes = bytes[1:]
else:
self.kind = "Invalid"
# The next item is the signature, if used.
if self.hasCommandSignature:
self.signature = struct.unpack("<Q", bytes[:8])[0]
bytes = bytes[8:]
else:
self.signature = None
# The outputs follow, if used.
if self.hasOutputInfo:
numOutputs = struct.unpack("<I", bytes[:4])[0]
bytes = bytes[4:]
self.outputs = []
for i in range(numOutputs):
# Read the file information.
self.outputs.append(FileInfo(bytes[:48]))
bytes = bytes[48:]
else:
self.outputs = None
# The strings follow, if used.
if self.hasStringList:
stringsLength = struct.unpack("<Q", bytes[:8])[0]
bytes = bytes[8:]
if stringsLength == 0:
self.strings = []
else:
stringData = bytes[:stringsLength]
bytes = bytes[stringsLength:]
assert len(stringData) == stringsLength
assert stringData[-1] == '\0'
self.strings = stringData[:-1].split("\0")
else:
self.strings = None
assert len(bytes) == 0
@property
def hasCommandSignature(self):
return self.kind in ("SuccessfulCommand", "DirectoryTreeSignature")
@property
def hasStringList(self):
return self.kind in ("DirectoryContents", "StaleFileRemoval")
@property
def hasOutputInfo(self):
return self.kind in ("ExistingInput", "SuccessfulCommand",
"DirectoryContents")
def __repr__(self):
output = "BuildValue(kind=%r" % self.kind
if self.signature is not None:
output += ", signature=%0x" % self.signature
if self.outputs is not None:
output += ", outputs=%r" % self.outputs
if self.strings is not None:
output += ", strings=%r" % self.strings
output += ")"
return output
class FileInfo(object):
def __init__(self, bytes):
(self.device, self.inode, self.mode, self.size,
modTimeSec, modTimeNano) = struct.unpack("<QQQQQQ", bytes)
self.modTime = (modTimeSec, modTimeNano)
def __repr__(self):
return "FileInfo(device=%r, inode=%#0x, mode=%r, size=%r, mtime=(%r, %r))" % (
self.device, self.inode, self.mode, self.size,
self.modTime[0], self.modTime[1])