Chromium Code Reviews| Index: scripts/tools/buildbot_tool.py | 
| diff --git a/scripts/tools/buildbot_tool.py b/scripts/tools/buildbot_tool.py | 
| new file mode 100755 | 
| index 0000000000000000000000000000000000000000..1f38c8f0e96de7e10bad8018e01d67e0d0205d86 | 
| --- /dev/null | 
| +++ b/scripts/tools/buildbot_tool.py | 
| @@ -0,0 +1,149 @@ | 
| +#!/usr/bin/python | 
| +# Copyright 2014 The Chromium Authors. All rights reserved. | 
| +# Use of this source code is governed by a BSD-style license that can be | 
| +# found in the LICENSE file. | 
| + | 
| +from __future__ import print_function | 
| + | 
| +import argparse | 
| +import json | 
| +import os | 
| +import re | 
| +import sys | 
| + | 
| + | 
| +TOOLS_DIR = os.path.abspath(os.path.dirname(__file__)) | 
| +SCRIPTS_DIR = os.path.dirname(TOOLS_DIR) | 
| +BASE_DIR = os.path.dirname(SCRIPTS_DIR) | 
| + | 
| +if not SCRIPTS_DIR in sys.path: | 
| + sys.path.insert(0, SCRIPTS_DIR) | 
| + | 
| +from common import filesystem | 
| + | 
| + | 
| +TEMPLATE_SUBPATH = os.path.join('scripts', 'tools', 'buildbot_tool_templates') | 
| +TEMPLATE_DIR = os.path.join(BASE_DIR, TEMPLATE_SUBPATH) | 
| + | 
| +BUILDER_TEMPLATE = """\ | 
| +c['builders'].append({ | 
| + 'name': '%(builder_name)s', | 
| + 'factory': m_annotator.BaseFactory('%(recipe)s'), | 
| + 'slavebuilddir': '%(slavebuilddir)s'}) | 
| +""" | 
| + | 
| + | 
| +SLAVE_TEMPLATE = """\ | 
| + { | 
| + 'master': '%(master_classname)s', | 
| + 'hostname': '%(hostname)s', | 
| + 'builder': '%(builder_name)s', | 
| + 'os': '%(os)s', | 
| + 'version': '%(version)s', | 
| + 'bits': '%(bits)s', | 
| + }, | 
| +""" | 
| + | 
| + | 
| +def main(argv): | 
| + args = parse_args(argv) | 
| + return args.func(args, filesystem.Filesystem()) | 
| + | 
| + | 
| +def parse_args(argv): | 
| + parser = argparse.ArgumentParser() | 
| + subps = parser.add_subparsers() | 
| + subp = subps.add_parser("gen", help="generate a new master") | 
| + subp.add_argument('builders_json', nargs=1, | 
| + help='path to builders.json file') | 
| 
 
agable
2014/12/09 21:13:24
Yeah, path-to-master-directory makes more sense to
 
Dirk Pranke
2014/12/09 21:32:00
Acknowledged.
 
 | 
| + subp.set_defaults(func=gen) | 
| + return parser.parse_args(argv) | 
| + | 
| + | 
| +def gen(args, fs): | 
| + builders_path = fs.abspath(args.builders_json[0]) | 
| + | 
| + if not fs.exists(builders_path): | 
| + print("%s not found" % args.builders_json[0], file=sys.stderr) | 
| + return 1 | 
| + | 
| + values = _values_from_file(fs, builders_path) | 
| + | 
| + master_dir = fs.dirname(builders_path) | 
| + | 
| + for filename in fs.listfiles(TEMPLATE_DIR): | 
| + template = fs.read_text_file(fs.join(TEMPLATE_DIR, filename)) | 
| + contents = _expand(template, values, | 
| + '%s/%s' % (TEMPLATE_SUBPATH, filename)) | 
| + fs.write_text_file(fs.join(master_dir, filename), contents) | 
| + print("Wrote %s." % filename) | 
| + | 
| + return 0 | 
| + | 
| + | 
| +def _values_from_file(fs, builders_path): | 
| + builders = json.loads(fs.read_text_file(builders_path)) | 
| + master_dirname = fs.basename(fs.dirname(builders_path)) | 
| + master_name_comps = master_dirname.split('.')[1:] | 
| + master_classname = ''.join(c[0].upper() + c[1:] for c in master_name_comps) | 
| + | 
| + builders_block = "" | 
| + slaves_block = "slaves = [\n" | 
| + | 
| + for builder_name, builder_vals in builders['builders'].items(): | 
| + builders_block += BUILDER_TEMPLATE % { | 
| + 'builder_name': builder_name, | 
| + 'recipe': builder_vals['recipe'], | 
| + 'slavebuilddir': builder_vals['slavebuilddir'] | 
| + } | 
| + | 
| + for pool_name in builder_vals['slave_pools']: | 
| + pool = builders['slave_pools'][pool_name] | 
| + slave_data = pool['slave_data'] | 
| + slaves = pool['slaves'] | 
| + for slave in slaves: | 
| + slaves_block += SLAVE_TEMPLATE % { | 
| + 'master_classname': master_classname, | 
| + 'hostname': slave, | 
| + 'builder_name': builder_name, | 
| + 'os': slave_data['os'], | 
| + 'version': slave_data['version'], | 
| + 'bits': slave_data['bits'], | 
| + } | 
| + | 
| + slaves_block += "]" | 
| + | 
| + v = {} | 
| + v['builders_block'] = builders_block | 
| + v['git_repo_url'] = builders['git_repo_url'] | 
| + v['master_dirname'] = master_dirname | 
| + v['master_classname'] = master_classname | 
| + v['master_base_class'] = builders['master_base_class'] | 
| + v['master_port'] = builders['master_port'] | 
| + v['master_port_alt'] = builders['master_port_alt'] | 
| + v['slave_port'] = builders['slave_port'] | 
| + v['slaves_block'] = slaves_block | 
| + return v | 
| + | 
| + | 
| +def _expand(template, values, source): | 
| + try: | 
| + contents = template % values | 
| + except: | 
| + print("Error populating template %s" % source, file=sys.stderr) | 
| + raise | 
| + return _update_generated_file_disclaimer(contents, source) | 
| + | 
| + | 
| +def _update_generated_file_disclaimer(contents, source): | 
| + gen_msg = ('# This file was generated from\n' | 
| + '# %s\n' | 
| + '# by scripts/tools/buildbot-tool.\n' | 
| + '# DO NOT EDIT BY HAND!\n' % | 
| + source) | 
| + return re.sub('# This file is used by scripts/tools/buildbot-tool.*', | 
| + gen_msg, contents) | 
| + | 
| + | 
| +if __name__ == '__main__': | 
| + sys.exit(main(sys.argv[1:])) |