Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import json | |
| 6 import optparse | 7 import optparse |
| 7 import os | 8 import os |
| 8 import subprocess | 9 import subprocess |
| 9 import sys | 10 import sys |
| 10 | 11 |
| 11 BUILD_ROOT = os.path.dirname(os.path.dirname(os.path.dirname( | 12 BUILD_ROOT = os.path.dirname(os.path.dirname(os.path.dirname( |
| 12 os.path.abspath(__file__)))) | 13 os.path.abspath(__file__)))) |
| 13 sys.path.append(os.path.join(BUILD_ROOT, 'scripts')) | 14 sys.path.append(os.path.join(BUILD_ROOT, 'scripts')) |
| 14 sys.path.append(os.path.join(BUILD_ROOT, 'third_party')) | 15 sys.path.append(os.path.join(BUILD_ROOT, 'third_party')) |
| 15 | 16 |
| 16 from common import annotator | 17 from common import annotator |
| 17 from common import chromium_utils | 18 from common import chromium_utils |
| 18 from slave import recipe_universe | 19 from slave import recipe_universe |
| 19 | 20 |
| 20 from recipe_engine import main as recipe_main | 21 from recipe_engine import main as recipe_main |
| 21 | 22 |
| 22 | 23 |
| 23 def get_recipe_properties(factory_properties, build_properties): | 24 def get_recipe_properties(factory_properties, build_properties, |
| 25 override_lookup): | |
| 24 """Constructs the recipe's properties from buildbot's properties. | 26 """Constructs the recipe's properties from buildbot's properties. |
| 25 | 27 |
| 26 This merges factory_properties and build_properties. Furthermore, it | 28 This retrieves the current factory properties from the master_config |
| 27 tries to reconstruct the 'recipe' property from builders.pyl if it isn't | 29 in the slave's checkout (the factory properties handed to us from the |
| 28 already there, and in that case merges in properties form builders.pyl. | 30 master might be out of date), and merges in the build properties. |
| 31 | |
| 32 Using the values from the checkout allows us to do things like change | |
| 33 the recipe and other factory properties for a builder without needing | |
| 34 a master restart. | |
| 29 """ | 35 """ |
| 30 properties = factory_properties.copy() | 36 mastername = factory_properties['mastername'] |
| 37 buildername = factory_properties['buildername'] | |
| 38 | |
| 39 properties = {} | |
| 40 | |
| 41 if mastername and buildername: | |
| 42 properties = get_on_disk_factory_properties(mastername, buildername) | |
| 43 | |
| 44 if override_lookup: | |
| 45 if properties['recipe'] != factory_properties['recipe']: | |
| 46 print >> sys.stderr, ( | |
| 47 'WARNING: Using recipe "%s" given on the command line ' | |
| 48 'command line, rather than "%s" as listed in the master.cfg' % | |
| 49 (properties['recipe'], factory_properties['recipe'])) | |
|
Dirk Pranke
2015/06/11 22:40:21
I don't warn about other factory properties also o
iannucci
2015/06/11 23:01:49
I'd err on the side of enumerating the mismatches
Dirk Pranke
2015/06/11 23:22:47
Ok. It's easy enough to do.
| |
| 50 properties.update(factory_properties) | |
| 51 else: | |
| 52 properties = factory_properties.copy() | |
| 53 | |
| 31 properties.update(build_properties) | 54 properties.update(build_properties) |
| 55 return properties | |
| 32 | 56 |
| 33 # Try to reconstruct the recipe from builders.pyl if not given. | |
| 34 if 'recipe' not in properties: | |
| 35 mastername = properties['mastername'] | |
| 36 buildername = properties['buildername'] | |
| 37 | 57 |
| 38 master_path = chromium_utils.MasterPath(mastername) | 58 def get_on_disk_factory_properties(mastername, buildername): |
| 39 builders_file = os.path.join(master_path, 'builders.pyl') | 59 script_path = os.path.join(BUILD_ROOT, 'scripts', 'tools', |
| 40 if os.path.isfile(builders_file): | 60 'dump_master_cfg.py') |
| 41 builders = chromium_utils.ReadBuildersFile(builders_file) | 61 dump_cmd = [sys.executable, |
| 42 assert buildername in builders['builders'], ( | 62 script_path, |
| 43 'buildername %s is not listed in %s' % (buildername, builders_file)) | 63 mastername] |
| 44 builder = builders['builders'][buildername] | 64 proc = subprocess.Popen(dump_cmd, cwd=BUILD_ROOT, stdout=subprocess.PIPE) |
| 65 out, _ = proc.communicate() | |
| 66 exit_code = proc.returncode | |
| 45 | 67 |
| 46 # Update properties with builders.pyl data. | 68 if exit_code: |
| 47 properties['recipe'] = builder['recipe'] | 69 raise LookupError('Failed to get the master config; dump_master_cfg %s' |
| 48 properties.update(builder.get('properties', {})) | 70 'returned %d):\n%s\n'% ( |
| 49 else: | 71 mastername, exit_code, out)) |
| 50 raise LookupError('Cannot find recipe for %s on %s' % | 72 |
| 51 (build_properties['buildername'], | 73 config = json.loads(out) |
| 52 build_properties['mastername'])) | 74 |
| 53 return properties | 75 # Now extract just the factory properties for the requested builder |
| 76 # from the master config. | |
| 77 props = None | |
| 78 for builder_dict in config['builders']: | |
| 79 if builder_dict['name'] == buildername: | |
| 80 props = dict((k, v) for k, v, _ in | |
| 81 builder_dict['factory'].properties.asList()) | |
|
iannucci
2015/06/11 23:01:49
hm... isn't config json though? I don't think ther
Dirk Pranke
2015/06/11 23:22:47
Yeah, that's probably true. I need to run this, be
| |
| 82 | |
| 83 if not props: | |
| 84 raise LookupError('builder "%s" not found on in master "%s"' % | |
| 85 (buildername, mastername)) | |
| 86 | |
| 87 if 'recipe' not in props: | |
| 88 raise LookupError('Cannot find recipe for %s on %s' % | |
| 89 (buildername, mastername)) | |
| 90 | |
| 91 return props | |
| 54 | 92 |
| 55 | 93 |
| 56 def get_args(argv): | 94 def get_args(argv): |
| 57 """Process command-line arguments.""" | 95 """Process command-line arguments.""" |
| 58 | 96 |
| 59 parser = optparse.OptionParser( | 97 parser = optparse.OptionParser( |
| 60 description='Entry point for annotated builds.') | 98 description='Entry point for annotated builds.') |
| 61 parser.add_option('--build-properties', | 99 parser.add_option('--build-properties', |
| 62 action='callback', callback=chromium_utils.convert_json, | 100 action='callback', callback=chromium_utils.convert_json, |
| 63 type='string', default={}, | 101 type='string', default={}, |
| 64 help='build properties in JSON format') | 102 help='build properties in JSON format') |
| 65 parser.add_option('--factory-properties', | 103 parser.add_option('--factory-properties', |
| 66 action='callback', callback=chromium_utils.convert_json, | 104 action='callback', callback=chromium_utils.convert_json, |
| 67 type='string', default={}, | 105 type='string', default={}, |
| 68 help='factory properties in JSON format') | 106 help='factory properties in JSON format') |
| 69 parser.add_option('--build-properties-gz', | 107 parser.add_option('--build-properties-gz', |
| 70 action='callback', callback=chromium_utils.convert_gz_json, | 108 action='callback', callback=chromium_utils.convert_gz_json, |
| 71 type='string', default={}, dest='build_properties', | 109 type='string', default={}, dest='build_properties', |
| 72 help='build properties in b64 gz JSON format') | 110 help='build properties in b64 gz JSON format') |
| 73 parser.add_option('--factory-properties-gz', | 111 parser.add_option('--factory-properties-gz', |
| 74 action='callback', callback=chromium_utils.convert_gz_json, | 112 action='callback', callback=chromium_utils.convert_gz_json, |
| 75 type='string', default={}, dest='factory_properties', | 113 type='string', default={}, dest='factory_properties', |
| 76 help='factory properties in b64 gz JSON format') | 114 help='factory properties in b64 gz JSON format') |
| 77 parser.add_option('--keep-stdin', action='store_true', default=False, | 115 parser.add_option('--keep-stdin', action='store_true', default=False, |
| 78 help='don\'t close stdin when running recipe steps') | 116 help='don\'t close stdin when running recipe steps') |
| 117 parser.add_option('--override-lookup', action='store_true', | |
| 118 help='use the recipe and other factory properties ' | |
| 119 'given on the command line rather than the ' | |
| 120 'properties in the master.cfg') | |
|
iannucci
2015/06/11 23:01:49
IIRC, run_recipe passes all args as build properti
Dirk Pranke
2015/06/11 23:22:47
looks like run_recipe passes all args as both, jus
| |
| 79 return parser.parse_args(argv) | 121 return parser.parse_args(argv) |
| 80 | 122 |
| 81 | 123 |
| 82 def update_scripts(): | 124 def update_scripts(): |
| 83 if os.environ.get('RUN_SLAVE_UPDATED_SCRIPTS'): | 125 if os.environ.get('RUN_SLAVE_UPDATED_SCRIPTS'): |
| 84 os.environ.pop('RUN_SLAVE_UPDATED_SCRIPTS') | 126 os.environ.pop('RUN_SLAVE_UPDATED_SCRIPTS') |
| 85 return False | 127 return False |
| 86 | 128 |
| 87 stream = annotator.StructuredAnnotationStream() | 129 stream = annotator.StructuredAnnotationStream() |
| 88 | 130 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 106 # After running update scripts, set PYTHONIOENCODING=UTF-8 for the real | 148 # After running update scripts, set PYTHONIOENCODING=UTF-8 for the real |
| 107 # annotated_run. | 149 # annotated_run. |
| 108 os.environ['PYTHONIOENCODING'] = 'UTF-8' | 150 os.environ['PYTHONIOENCODING'] = 'UTF-8' |
| 109 | 151 |
| 110 return True | 152 return True |
| 111 | 153 |
| 112 | 154 |
| 113 def main(argv): | 155 def main(argv): |
| 114 opts, _ = get_args(argv) | 156 opts, _ = get_args(argv) |
| 115 properties = get_recipe_properties( | 157 properties = get_recipe_properties( |
| 116 opts.factory_properties, opts.build_properties) | 158 opts.factory_properties, opts.build_properties, opts.override_lookup) |
| 117 stream = annotator.StructuredAnnotationStream() | 159 stream = annotator.StructuredAnnotationStream() |
| 118 ret = recipe_main.run_steps(properties, stream, | 160 ret = recipe_main.run_steps(properties, stream, |
| 119 universe=recipe_universe.get_universe()) | 161 universe=recipe_universe.get_universe()) |
| 120 return ret.status_code | 162 return ret.status_code |
| 121 | 163 |
| 122 | 164 |
| 123 def shell_main(argv): | 165 def shell_main(argv): |
| 124 if update_scripts(): | 166 if update_scripts(): |
| 125 return subprocess.call([sys.executable] + argv) | 167 return subprocess.call([sys.executable] + argv) |
| 126 else: | 168 else: |
| 127 return main(argv) | 169 return main(argv) |
| 128 | 170 |
| 129 if __name__ == '__main__': | 171 if __name__ == '__main__': |
| 130 sys.exit(shell_main(sys.argv)) | 172 sys.exit(shell_main(sys.argv)) |
| OLD | NEW |