| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 from __future__ import print_function |
| 7 |
| 8 import argparse |
| 9 import ast |
| 10 import os |
| 11 import re |
| 12 import sys |
| 13 |
| 14 |
| 15 TOOLS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| 16 SCRIPTS_DIR = os.path.dirname(TOOLS_DIR) |
| 17 BASE_DIR = os.path.dirname(SCRIPTS_DIR) |
| 18 |
| 19 # This adjusts sys.path, so must be done before we import other modules. |
| 20 if not SCRIPTS_DIR in sys.path: |
| 21 sys.path.append(SCRIPTS_DIR) |
| 22 |
| 23 from common import filesystem |
| 24 |
| 25 |
| 26 TEMPLATE_SUBPATH = os.path.join('scripts', 'tools', 'buildbot_tool_templates') |
| 27 TEMPLATE_DIR = os.path.join(BASE_DIR, TEMPLATE_SUBPATH) |
| 28 |
| 29 BUILDER_TEMPLATE = """\ |
| 30 c['builders'].append({ |
| 31 'name': '%(builder_name)s', |
| 32 'factory': m_annotator.BaseFactory('%(recipe)s'), |
| 33 'slavebuilddir': '%(slavebuilddir)s'}) |
| 34 """ |
| 35 |
| 36 |
| 37 SLAVE_TEMPLATE = """\ |
| 38 { |
| 39 'master': '%(master_classname)s', |
| 40 'hostname': '%(hostname)s', |
| 41 'builder': '%(builder_name)s', |
| 42 'os': '%(os)s', |
| 43 'version': '%(version)s', |
| 44 'bits': '%(bits)s', |
| 45 }, |
| 46 """ |
| 47 |
| 48 |
| 49 def main(argv, fs): |
| 50 args = parse_args(argv) |
| 51 return args.func(args, fs) |
| 52 |
| 53 |
| 54 def parse_args(argv): |
| 55 parser = argparse.ArgumentParser() |
| 56 subps = parser.add_subparsers() |
| 57 |
| 58 subp = subps.add_parser('gen', help=run_gen.__doc__) |
| 59 subp.add_argument('master_dirname', nargs=1, |
| 60 help='Path to master config directory (must contain ' |
| 61 'a builders.py file).') |
| 62 subp.set_defaults(func=run_gen) |
| 63 |
| 64 subp = subps.add_parser('help', help=run_help.__doc__) |
| 65 subp.add_argument(nargs='?', action='store', dest='subcommand', |
| 66 help='The command to get help for.') |
| 67 subp.set_defaults(func=run_help) |
| 68 |
| 69 return parser.parse_args(argv) |
| 70 |
| 71 |
| 72 def run_gen(args, fs): |
| 73 """Generate a new master config.""" |
| 74 |
| 75 master_dirname = args.master_dirname[0] |
| 76 master_subpath = fs.relpath(master_dirname, BASE_DIR) |
| 77 builders_path = fs.join(BASE_DIR, master_subpath, 'builders.py') |
| 78 |
| 79 if not fs.exists(builders_path): |
| 80 print("%s not found" % master_dirname, file=sys.stderr) |
| 81 return 1 |
| 82 |
| 83 values = _values_from_file(fs, builders_path) |
| 84 |
| 85 for filename in fs.listfiles(TEMPLATE_DIR): |
| 86 template = fs.read_text_file(fs.join(TEMPLATE_DIR, filename)) |
| 87 contents = _expand(template, values, |
| 88 '%s/%s' % (TEMPLATE_SUBPATH, filename), |
| 89 master_subpath) |
| 90 fs.write_text_file(fs.join(BASE_DIR, master_subpath, filename), contents) |
| 91 print("Wrote %s." % filename) |
| 92 |
| 93 return 0 |
| 94 |
| 95 |
| 96 def run_help(args, fs): |
| 97 """Get help on a subcommand.""" |
| 98 |
| 99 if args.subcommand: |
| 100 return main([args.subcommand, '--help'], fs) |
| 101 return main(['--help'], fs) |
| 102 |
| 103 |
| 104 def _values_from_file(fs, builders_path): |
| 105 builders = ast.literal_eval(fs.read_text_file(builders_path)) |
| 106 master_dirname = fs.basename(fs.dirname(builders_path)) |
| 107 master_name_comps = master_dirname.split('.')[1:] |
| 108 master_classname = ''.join(c[0].upper() + c[1:] for c in master_name_comps) |
| 109 |
| 110 builders_block = "" |
| 111 slaves_block = "slaves = [\n" |
| 112 |
| 113 for builder_name, builder_vals in builders['builders'].items(): |
| 114 builders_block += BUILDER_TEMPLATE % { |
| 115 'builder_name': builder_name, |
| 116 'recipe': builder_vals['recipe'], |
| 117 'slavebuilddir': builder_vals['slavebuilddir'] |
| 118 } |
| 119 |
| 120 for pool_name in builder_vals['slave_pools']: |
| 121 pool = builders['slave_pools'][pool_name] |
| 122 slave_data = pool['slave_data'] |
| 123 slaves = pool['slaves'] |
| 124 for slave in slaves: |
| 125 slaves_block += SLAVE_TEMPLATE % { |
| 126 'master_classname': master_classname, |
| 127 'hostname': slave, |
| 128 'builder_name': builder_name, |
| 129 'os': slave_data['os'], |
| 130 'version': slave_data['version'], |
| 131 'bits': slave_data['bits'], |
| 132 } |
| 133 |
| 134 slaves_block += "]" |
| 135 |
| 136 v = {} |
| 137 v['builders_block'] = builders_block |
| 138 v['git_repo_url'] = builders['git_repo_url'] |
| 139 v['master_dirname'] = master_dirname |
| 140 v['master_classname'] = master_classname |
| 141 v['master_base_class'] = builders['master_base_class'] |
| 142 v['master_port'] = builders['master_port'] |
| 143 v['master_port_alt'] = builders['master_port_alt'] |
| 144 v['slave_port'] = builders['slave_port'] |
| 145 v['slaves_block'] = slaves_block |
| 146 return v |
| 147 |
| 148 |
| 149 def _expand(template, values, source, master_subpath): |
| 150 try: |
| 151 contents = template % values |
| 152 except: |
| 153 print("Error populating template %s" % source, file=sys.stderr) |
| 154 raise |
| 155 return _update_generated_file_disclaimer(contents, source, master_subpath) |
| 156 |
| 157 |
| 158 def _update_generated_file_disclaimer(contents, source, master_subpath): |
| 159 pattern = '# This file is used by scripts/tools/buildbot-tool.*' |
| 160 replacement = ('# This file was generated from\n' |
| 161 '# %s\n' |
| 162 '# by "scripts/tools/buildbot-tool gen %s".\n' |
| 163 '# DO NOT EDIT BY HAND!\n' % |
| 164 (source, master_subpath)) |
| 165 return re.sub(pattern, replacement, contents) |
| 166 |
| 167 |
| 168 if __name__ == '__main__': # pragma: no cover |
| 169 sys.exit(main(sys.argv[1:], filesystem.Filesystem())) |
| OLD | NEW |