Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: scripts/slave/annotated_run.py

Issue 1183563003: Re-land "Modify annotated_run to read factory configs from the slave checkout." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: fix sys.path in dump_master_cfg, improve logging Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | scripts/tools/dump_master_cfg.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
19 from common import master_cfg_utils
18 from slave import recipe_universe 20 from slave import recipe_universe
19 21
20 from recipe_engine import main as recipe_main 22 from recipe_engine import main as recipe_main
21 23
22 24
23 def get_recipe_properties(factory_properties, build_properties): 25 def get_recipe_properties(factory_properties, build_properties,
26 master_overrides_slave):
24 """Constructs the recipe's properties from buildbot's properties. 27 """Constructs the recipe's properties from buildbot's properties.
25 28
26 This merges factory_properties and build_properties. Furthermore, it 29 This retrieves the current factory properties from the master_config
27 tries to reconstruct the 'recipe' property from builders.pyl if it isn't 30 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. 31 master might be out of date), and merges in the build properties.
32
33 Using the values from the checkout allows us to do things like change
34 the recipe and other factory properties for a builder without needing
35 a master restart.
29 """ 36 """
30 properties = factory_properties.copy() 37 master_properties = factory_properties.copy()
31 properties.update(build_properties) 38 master_properties.update(build_properties)
32 39
33 # Try to reconstruct the recipe from builders.pyl if not given. 40 mastername = master_properties['mastername']
34 if 'recipe' not in properties: 41 buildername = master_properties['buildername']
35 mastername = properties['mastername'] 42 if mastername and buildername:
36 buildername = properties['buildername'] 43 slave_properties = get_factory_properties_from_disk(mastername, buildername)
44 else:
45 slave_properties = {}
37 46
38 master_path = chromium_utils.MasterPath(mastername) 47 properties = master_properties.copy()
39 builders_file = os.path.join(master_path, 'builders.pyl') 48 conflicting_properties = {}
40 if os.path.isfile(builders_file): 49 for name in slave_properties:
41 builders = chromium_utils.ReadBuildersFile(builders_file) 50 if master_properties.get(name) != slave_properties[name]:
42 assert buildername in builders['builders'], ( 51 conflicting_properties[name] = (master_properties.get(name),
43 'buildername %s is not listed in %s' % (buildername, builders_file)) 52 slave_properties[name])
44 builder = builders['builders'][buildername]
45 53
46 # Update properties with builders.pyl data. 54 if conflicting_properties:
47 properties['recipe'] = builder['recipe'] 55 print 'The following build properties differ between master and slave:'
48 properties.update(builder.get('properties', {})) 56 for name, (master_value, slave_value) in conflicting_properties.items():
49 else: 57 print (' "%s": master: "%s", slave: "%s"' % (
50 raise LookupError('Cannot find recipe for %s on %s' % 58 name,
51 (build_properties['buildername'], 59 "<unset>" if (master_value is None) else master_value,
52 build_properties['mastername'])) 60 slave_value))
61 print ("Using the values from the %s." %
62 ("master" if master_overrides_slave else "slave"))
63
64 if not master_overrides_slave:
65 for name, (_, slave_value) in conflicting_properties.items():
66 properties[name] = slave_value
67
53 return properties 68 return properties
54 69
55 70
71 def get_factory_properties_from_disk(mastername, buildername):
72 master_list = master_cfg_utils.GetMasters()
73 master_path = None
74 for name, path in master_list:
75 if name == mastername:
76 master_path = path
77
78 if not master_path:
79 raise LookupError('master "%s" not found.' % mastername)
80
81 script_path = os.path.join(BUILD_ROOT, 'scripts', 'tools',
82 'dump_master_cfg.py')
83 dump_cmd = [sys.executable,
84 script_path,
85 master_path, '-']
86 proc = subprocess.Popen(dump_cmd, cwd=BUILD_ROOT, stdout=subprocess.PIPE,
87 stderr=subprocess.PIPE)
88 out, err = proc.communicate()
89 exit_code = proc.returncode
90
91 if exit_code:
92 raise LookupError('Failed to get the master config; dump_master_cfg %s'
93 'returned %d):\n%s\n%s\n'% (
94 mastername, exit_code, out, err))
95
96 config = json.loads(out)
97
98 # Now extract just the factory properties for the requested builder
99 # from the master config.
100 props = {}
101 for builder_dict in config['builders']:
102 if builder_dict['name'] == buildername:
103 factory_properties = builder_dict['factory']['properties']
104 for name, (value, _) in factory_properties.items():
105 props[name] = value
106
107 if not props:
108 raise LookupError('builder "%s" not found on in master "%s"' %
109 (buildername, mastername))
110
111 if 'recipe' not in props:
112 raise LookupError('Cannot find recipe for %s on %s' %
113 (buildername, mastername))
114
115 return props
116
117
56 def get_args(argv): 118 def get_args(argv):
57 """Process command-line arguments.""" 119 """Process command-line arguments."""
58 120
59 parser = optparse.OptionParser( 121 parser = optparse.OptionParser(
60 description='Entry point for annotated builds.') 122 description='Entry point for annotated builds.')
61 parser.add_option('--build-properties', 123 parser.add_option('--build-properties',
62 action='callback', callback=chromium_utils.convert_json, 124 action='callback', callback=chromium_utils.convert_json,
63 type='string', default={}, 125 type='string', default={},
64 help='build properties in JSON format') 126 help='build properties in JSON format')
65 parser.add_option('--factory-properties', 127 parser.add_option('--factory-properties',
66 action='callback', callback=chromium_utils.convert_json, 128 action='callback', callback=chromium_utils.convert_json,
67 type='string', default={}, 129 type='string', default={},
68 help='factory properties in JSON format') 130 help='factory properties in JSON format')
69 parser.add_option('--build-properties-gz', 131 parser.add_option('--build-properties-gz',
70 action='callback', callback=chromium_utils.convert_gz_json, 132 action='callback', callback=chromium_utils.convert_gz_json,
71 type='string', default={}, dest='build_properties', 133 type='string', default={}, dest='build_properties',
72 help='build properties in b64 gz JSON format') 134 help='build properties in b64 gz JSON format')
73 parser.add_option('--factory-properties-gz', 135 parser.add_option('--factory-properties-gz',
74 action='callback', callback=chromium_utils.convert_gz_json, 136 action='callback', callback=chromium_utils.convert_gz_json,
75 type='string', default={}, dest='factory_properties', 137 type='string', default={}, dest='factory_properties',
76 help='factory properties in b64 gz JSON format') 138 help='factory properties in b64 gz JSON format')
77 parser.add_option('--keep-stdin', action='store_true', default=False, 139 parser.add_option('--keep-stdin', action='store_true', default=False,
78 help='don\'t close stdin when running recipe steps') 140 help='don\'t close stdin when running recipe steps')
141 parser.add_option('--master-overrides-slave', action='store_true',
142 help='use the property values given on the command line '
143 'from the master, not the ones looked up on the slave')
79 return parser.parse_args(argv) 144 return parser.parse_args(argv)
80 145
81 146
82 def update_scripts(): 147 def update_scripts():
83 if os.environ.get('RUN_SLAVE_UPDATED_SCRIPTS'): 148 if os.environ.get('RUN_SLAVE_UPDATED_SCRIPTS'):
84 os.environ.pop('RUN_SLAVE_UPDATED_SCRIPTS') 149 os.environ.pop('RUN_SLAVE_UPDATED_SCRIPTS')
85 return False 150 return False
86 151
87 stream = annotator.StructuredAnnotationStream() 152 stream = annotator.StructuredAnnotationStream()
88 153
(...skipping 17 matching lines...) Expand all
106 # After running update scripts, set PYTHONIOENCODING=UTF-8 for the real 171 # After running update scripts, set PYTHONIOENCODING=UTF-8 for the real
107 # annotated_run. 172 # annotated_run.
108 os.environ['PYTHONIOENCODING'] = 'UTF-8' 173 os.environ['PYTHONIOENCODING'] = 'UTF-8'
109 174
110 return True 175 return True
111 176
112 177
113 def main(argv): 178 def main(argv):
114 opts, _ = get_args(argv) 179 opts, _ = get_args(argv)
115 properties = get_recipe_properties( 180 properties = get_recipe_properties(
116 opts.factory_properties, opts.build_properties) 181 opts.factory_properties, opts.build_properties,
182 opts.master_overrides_slave)
117 stream = annotator.StructuredAnnotationStream() 183 stream = annotator.StructuredAnnotationStream()
118 ret = recipe_main.run_steps(properties, stream, 184 ret = recipe_main.run_steps(properties, stream,
119 universe=recipe_universe.get_universe()) 185 universe=recipe_universe.get_universe())
120 return ret.status_code 186 return ret.status_code
121 187
122 188
123 def shell_main(argv): 189 def shell_main(argv):
124 if update_scripts(): 190 if update_scripts():
125 return subprocess.call([sys.executable] + argv) 191 return subprocess.call([sys.executable] + argv)
126 else: 192 else:
127 return main(argv) 193 return main(argv)
128 194
129 if __name__ == '__main__': 195 if __name__ == '__main__':
130 sys.exit(shell_main(sys.argv)) 196 sys.exit(shell_main(sys.argv))
OLDNEW
« no previous file with comments | « no previous file | scripts/tools/dump_master_cfg.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698