OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # |
| 3 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 |
| 8 '''Generate buildbot specs for all buildbots.''' |
| 9 |
| 10 |
| 11 import datetime |
| 12 import imp |
| 13 import json |
| 14 import os |
| 15 import re |
| 16 import subprocess |
| 17 import sys |
| 18 import tempfile |
| 19 |
| 20 |
| 21 SKIA_DIR = os.path.abspath(os.path.join( |
| 22 os.path.dirname(os.path.realpath(__file__)), |
| 23 os.pardir, os.pardir)) |
| 24 |
| 25 BUILDBOT_SPEC_FILE = os.path.join(SKIA_DIR, 'tools', 'buildbot_spec.py') |
| 26 |
| 27 SKIA_RECIPES = [ |
| 28 'swarm_compile.py', |
| 29 'swarm_housekeeper.py', |
| 30 'swarm_perf.py', |
| 31 'swarm_RecreateSKPs.py', |
| 32 'swarm_test.py', |
| 33 'swarm_trigger.py' |
| 34 ] |
| 35 |
| 36 |
| 37 def prettier_print(obj, indent, stream=sys.stdout, max_line_length=80): |
| 38 """Pretty-print the object, in a nicer format than pprint.""" |
| 39 |
| 40 def _breakline(line): |
| 41 """Break the line to fit under N characters.""" |
| 42 # If we're under the limit, just return. |
| 43 if len(line) <= max_line_length: |
| 44 return [line] |
| 45 |
| 46 # Dict entries. |
| 47 m = re.match(r'^(\s+)(.+): (.+)$', line) |
| 48 if m: |
| 49 return (_breakline(m.groups()[0] + m.groups()[1] + ':') + |
| 50 _breakline(m.groups()[0] + ' ' + m.groups()[2])) |
| 51 |
| 52 # List entries and dict keys. |
| 53 m = re.match(r"^(\s+)'(.+)'([:,])$", line) |
| 54 if m: |
| 55 prefix = m.groups()[0] |
| 56 content = m.groups()[1] |
| 57 max_len = max_line_length - len(prefix) - len("(''):") |
| 58 parts = [] |
| 59 while len(content) > max_len: |
| 60 parts.append(content[:max_len]) |
| 61 content = content[max_len:] |
| 62 parts.append(content) |
| 63 lines = _breakline(prefix + "('" + parts[0] + "'") |
| 64 for p in parts[1:-1]: |
| 65 lines.extend(_breakline(prefix + " '" + p + "'")) |
| 66 lines.extend(_breakline(prefix + " '" + parts[-1] + "')" + m.groups()[2])) |
| 67 return lines |
| 68 |
| 69 class LineBreakingStream(object): |
| 70 """Stream wrapper which writes line-by-line, breaking them as needed.""" |
| 71 def __init__(self, backing_stream): |
| 72 self._backing_stream = backing_stream |
| 73 self._current_line = '' |
| 74 |
| 75 def _writeline(self, line): |
| 76 for l in _breakline(line): |
| 77 self._backing_stream.write(l + '\n') |
| 78 |
| 79 def write(self, s): |
| 80 self._current_line += s |
| 81 split = self._current_line.split('\n') |
| 82 for w in split[:-1]: |
| 83 self._writeline(w) |
| 84 self._current_line = split[len(split)-1] |
| 85 |
| 86 def flush(self): |
| 87 self._writeline(self._current_line) |
| 88 |
| 89 def _pprint(obj, indent, stream): |
| 90 indent_str = ' ' * indent |
| 91 if isinstance(obj, dict): |
| 92 stream.write('{\n') |
| 93 for k in sorted(obj.iterkeys()): |
| 94 stream.write(indent_str + '\'%s\': ' % k) |
| 95 _pprint(obj[k], indent + 2, stream=stream) |
| 96 stream.write(',\n') |
| 97 stream.write(' ' * (indent-2) + '}') |
| 98 elif isinstance(obj, list): |
| 99 stream.write('[\n') |
| 100 for v in obj: |
| 101 stream.write(indent_str) |
| 102 _pprint(v, indent + 2, stream=stream) |
| 103 stream.write(',\n') |
| 104 stream.write(' ' * (indent-2) + ']') |
| 105 elif isinstance(obj, basestring): |
| 106 stream.write('\'%s\'' % obj) |
| 107 elif isinstance(obj, bool): |
| 108 if obj: |
| 109 stream.write('True') |
| 110 else: |
| 111 stream.write('False') |
| 112 else: |
| 113 stream.write(obj) |
| 114 |
| 115 s = LineBreakingStream(stream) |
| 116 _pprint(obj, indent, stream=s) |
| 117 s.flush() |
| 118 |
| 119 |
| 120 def get_bots(): |
| 121 """Find all of the bots referenced in Skia recipes.""" |
| 122 recipes = os.path.join(SKIA_DIR, 'infra', 'bots', 'recipes') |
| 123 bots = [] |
| 124 for skia_recipe in SKIA_RECIPES: |
| 125 skia_recipe = os.path.join(recipes, skia_recipe) |
| 126 skia = imp.load_source('skia', skia_recipe) |
| 127 for _, slaves in skia.TEST_BUILDERS.iteritems(): |
| 128 for _, builders in slaves.iteritems(): |
| 129 bots.extend(builders) |
| 130 bots.sort() |
| 131 return bots |
| 132 |
| 133 |
| 134 def main(): |
| 135 """Generate a spec for each of the above bots. Dump them all to a file.""" |
| 136 # Get the list of bots. |
| 137 bots = get_bots() |
| 138 |
| 139 # Create the fake specs. |
| 140 specs = {} |
| 141 tmp_spec_file = tempfile.NamedTemporaryFile(delete=False) |
| 142 tmp_spec_file.close() |
| 143 try: |
| 144 for bot in bots: |
| 145 subprocess.check_call(['python', BUILDBOT_SPEC_FILE, |
| 146 tmp_spec_file.name, bot]) |
| 147 with open(tmp_spec_file.name) as f: |
| 148 spec = json.load(f) |
| 149 spec['dm_flags'] = ['--dummy-flags'] |
| 150 spec['nanobench_flags'] = ['--dummy-flags'] |
| 151 specs[bot] = spec |
| 152 finally: |
| 153 os.remove(tmp_spec_file.name) |
| 154 |
| 155 out = os.path.join( |
| 156 SKIA_DIR, 'infra', 'bots', 'recipe_modules', 'skia', 'fake_specs.py') |
| 157 |
| 158 with open(out, 'w') as f: |
| 159 f.write('''# Copyright 2016 The Chromium Authors. All rights reserved. |
| 160 # Use of this source code is governed by a BSD-style license that can be |
| 161 # found in the LICENSE file. |
| 162 |
| 163 # This file is generated by the %s script. |
| 164 |
| 165 FAKE_SPECS = ''' % sys.argv[0]) |
| 166 prettier_print(specs, indent=2, stream=f) |
| 167 |
| 168 print 'Wrote output to %s' % out |
| 169 |
| 170 |
| 171 if __name__ == '__main__': |
| 172 main() |
OLD | NEW |