blob: efa1517a9aece7527efdda2bba5c73b193905cd9 [file] [log] [blame]
#!/usr/bin/env python
"""
This script can be used to create "dummy" .ninja files, which replicate the
dependency structure of a build but eliminate all of the other details). This is
useful for constructing self contained .ninja files for use in performance
tests.
"""
import argparse
import sqlalchemy
import sqlalchemy.ext.declarative
from sqlalchemy import *
from sqlalchemy.orm import *
# DB Declaration
Base = sqlalchemy.ext.declarative.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 = Column(Integer, nullable=False)
built_at = Column(Integer, nullable=False)
computed_at = Column(Integer, nullable=False)
key = relation(KeyName)
dependencies = relationship('RuleDependency')
def __repr__(self):
return "%s%r" % (
self.__class__.__name__, (self.id, self.key, self.value,
self.built_at, self.computed_at))
class RuleDependency(Base):
__tablename__ = "rule_dependencies"
rule_id = Column(Integer, ForeignKey(RuleResult.id),
nullable=False, primary_key=True)
key_id = Column(Integer, ForeignKey(KeyName.id),
nullable=False, primary_key=True)
rule = relation(RuleResult)
key = relation(KeyName)
def __repr__(self):
return "%s%r" % (
self.__class__.__name__, (self.rule_id, self.key))
def main():
parser = argparse.ArgumentParser()
parser.add_argument('path', metavar='path', type=str,
help='path to the database')
parser.add_argument('--show-mapping', action='store_true',
help='show name to node-name mapping')
args = parser.parse_args()
# Create the database engine.
engine = sqlalchemy.create_engine("sqlite:///" + args.path)
# Create a session.
session = sqlalchemy.orm.sessionmaker(engine)()
# We create a dummy build file with one target "make-inputs", which creates
# dummy input files, and all the other rules just cat those files together.
print "rule CAT"
print " command = cat ${in} > ${out}"
print " description = ${command}"
print
node_names = {}
def get_key_name(key):
name = node_names.get(key)
if name is None:
node_names[key] = name = 'N%d' % (
len(node_names) - len(input_rules),)
return name
# First, find all the "inputs" (leaf nodes).
input_rules = [rule
for rule in session.query(RuleResult)
if not rule.dependencies]
# Assign all of the inputs special names.
node_names.update((rule.key, "I%d" % (i,))
for i,rule in enumerate(input_rules))
seen_rules = set()
seen_inputs = set()
seen_nodes = set()
for rule in session.query(RuleResult):
name = get_key_name(rule.key)
dep_names = [get_key_name(dep.key)
for dep in rule.dependencies]
if not dep_names:
seen_inputs.add(name)
else:
print "build %s: CAT %s" % (name, " ".join(dep_names))
seen_rules.add(name)
seen_nodes.update(dep_names)
print
# Write a build statement to create all the inputs, so we can actually
# execute the build.
print "rule make-inputs"
print " command = touch %s" % " ".join(sorted(seen_inputs))
print "build make-inputs: make-inputs"
print
# Write out a default target with the roots.
roots = seen_rules - seen_nodes
print "default %s" % (" ".join(roots),)
# Write the mappings, if requested.
if args.show_mapping:
print
for key,name in sorted(node_names.items()):
print "# %s -> %s" % (key, name)
if __name__ == '__main__':
main()