1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
#!/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()
|