| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 json |
| 7 import os | 7 import os |
| 8 import subprocess | 8 import subprocess |
| 9 import sys | 9 import sys |
| 10 import tempfile | 10 import tempfile |
| 11 | 11 |
| 12 | 12 |
| 13 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | 13 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 14 | 14 |
| 15 | 15 |
| 16 sys.path.insert(0, os.path.join(BASE_DIR, 'scripts')) | |
| 17 sys.path.insert(0, os.path.join(BASE_DIR, 'scripts', 'slave', 'recipes')) | |
| 18 sys.path.insert( | |
| 19 0, os.path.join(BASE_DIR, 'scripts', 'slave', 'recipe_modules')) | |
| 20 sys.path.insert(0, os.path.join(BASE_DIR, 'third_party')) | |
| 21 | |
| 22 import chromium_trybot | |
| 23 from chromium_tests.builders import BUILDERS | |
| 24 | |
| 25 | |
| 26 MAIN_WATERFALL_MASTERS = [ | 16 MAIN_WATERFALL_MASTERS = [ |
| 27 'master.chromium.chrome', | 17 'master.chromium.chrome', |
| 28 'master.chromium.chromiumos', | 18 'master.chromium.chromiumos', |
| 29 'master.chromium.gpu', | 19 'master.chromium.gpu', |
| 30 'master.chromium.linux', | 20 'master.chromium.linux', |
| 31 'master.chromium.mac', | 21 'master.chromium.mac', |
| 32 'master.chromium.memory', | 22 'master.chromium.memory', |
| 33 'master.chromium.win', | 23 'master.chromium.win', |
| 34 ] | 24 ] |
| 35 | 25 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 ], | 85 ], |
| 96 } | 86 } |
| 97 | 87 |
| 98 UNUSED_MAIN_WATERFALL_BUILDERS = { | 88 UNUSED_MAIN_WATERFALL_BUILDERS = { |
| 99 'master.chromium.linux': [ | 89 'master.chromium.linux': [ |
| 100 'Android x86 Builder (dbg)', | 90 'Android x86 Builder (dbg)', |
| 101 ], | 91 ], |
| 102 } | 92 } |
| 103 | 93 |
| 104 | 94 |
| 95 def getBuilders(recipe_name): |
| 96 """Asks the given recipe to dump its BUILDERS dictionary. |
| 97 |
| 98 This must be implemented by the recipe in question. |
| 99 """ |
| 100 (fh, builders_file) = tempfile.mkstemp('.json') |
| 101 os.close(fh) |
| 102 try: |
| 103 subprocess.check_call([ |
| 104 os.path.join(BASE_DIR, 'scripts', 'slave', 'recipes.py'), |
| 105 'run', recipe_name, 'dump_builders=%s' % builders_file]) |
| 106 with open(builders_file) as fh: |
| 107 return json.load(fh) |
| 108 finally: |
| 109 os.remove(builders_file) |
| 110 |
| 111 |
| 105 def getMasterConfig(master): | 112 def getMasterConfig(master): |
| 106 with tempfile.NamedTemporaryFile() as f: | 113 with tempfile.NamedTemporaryFile() as f: |
| 107 subprocess.check_call([ | 114 subprocess.check_call([ |
| 108 os.path.join(BASE_DIR, 'scripts', 'tools', 'runit.py'), | 115 os.path.join(BASE_DIR, 'scripts', 'tools', 'runit.py'), |
| 109 os.path.join(BASE_DIR, 'scripts', 'tools', 'dump_master_cfg.py'), | 116 os.path.join(BASE_DIR, 'scripts', 'tools', 'dump_master_cfg.py'), |
| 110 os.path.join(BASE_DIR, 'masters/%s' % master), | 117 os.path.join(BASE_DIR, 'masters/%s' % master), |
| 111 f.name]) | 118 f.name]) |
| 112 return json.load(f) | 119 return json.load(f) |
| 113 | 120 |
| 114 | 121 |
| 115 def getBuildersAndRecipes(master): | 122 def getBuildersAndRecipes(master): |
| 116 return { | 123 return { |
| 117 builder['name'] : builder['factory']['properties'].get( | 124 builder['name'] : builder['factory']['properties'].get( |
| 118 'recipe', [None])[0] | 125 'recipe', [None])[0] |
| 119 for builder in getMasterConfig(master)['builders'] | 126 for builder in getMasterConfig(master)['builders'] |
| 120 } | 127 } |
| 121 | 128 |
| 122 | 129 |
| 123 def mutualDifference(a, b): | 130 def mutualDifference(a, b): |
| 124 return a - b, b - a | 131 return a - b, b - a |
| 125 | 132 |
| 126 | 133 |
| 127 def main(argv): | 134 def main(argv): |
| 128 chromium_recipe_builders = {} | 135 chromium_recipe_builders = {} |
| 129 covered_builders = set() | 136 covered_builders = set() |
| 130 all_builders = set() | 137 all_builders = set() |
| 131 | 138 |
| 132 exit_code = 0 | 139 exit_code = 0 |
| 133 | 140 |
| 141 chromium_trybot_BUILDERS = getBuilders('chromium_trybot') |
| 142 chromium_BUILDERS = getBuilders('chromium') |
| 143 |
| 134 for master in MAIN_WATERFALL_MASTERS: | 144 for master in MAIN_WATERFALL_MASTERS: |
| 135 builders = getBuildersAndRecipes(master) | 145 builders = getBuildersAndRecipes(master) |
| 136 all_builders.update((master, b) for b in builders) | 146 all_builders.update((master, b) for b in builders) |
| 137 | 147 |
| 138 # We only have a standardized way to mirror builders using the chromium | 148 # We only have a standardized way to mirror builders using the chromium |
| 139 # recipe on the tryserver. | 149 # recipe on the tryserver. |
| 140 chromium_recipe_builders[master] = [b for b in builders | 150 chromium_recipe_builders[master] = [b for b in builders |
| 141 if builders[b] == 'chromium'] | 151 if builders[b] == 'chromium'] |
| 142 | 152 |
| 143 # TODO(phajdan.jr): Also consider it an error if configured builders | 153 # TODO(phajdan.jr): Also consider it an error if configured builders |
| 144 # are not using chromium recipe. This might make it harder to experiment | 154 # are not using chromium recipe. This might make it harder to experiment |
| 145 # with switching bots over to chromium recipe though, so it may be better | 155 # with switching bots over to chromium recipe though, so it may be better |
| 146 # to just wait until the switch is done. | 156 # to just wait until the switch is done. |
| 147 recipe_side_builders = BUILDERS.get( | 157 recipe_side_builders = chromium_BUILDERS.get( |
| 148 master.replace('master.', ''), {}).get('builders') | 158 master.replace('master.', ''), {}).get('builders') |
| 149 if recipe_side_builders is not None: | 159 if recipe_side_builders is not None: |
| 150 bogus_builders = set(recipe_side_builders.keys()).difference( | 160 bogus_builders = set(recipe_side_builders.keys()).difference( |
| 151 set(builders.keys())) | 161 set(builders.keys())) |
| 152 bogus_builders, unused = mutualDifference( | 162 bogus_builders, unused = mutualDifference( |
| 153 bogus_builders, | 163 bogus_builders, |
| 154 set(UNUSED_MAIN_WATERFALL_BUILDERS.get(master, []))) | 164 set(UNUSED_MAIN_WATERFALL_BUILDERS.get(master, []))) |
| 155 # TODO(phajdan.jr): Clean up bogus chromiumos builders. | 165 # TODO(phajdan.jr): Clean up bogus chromiumos builders. |
| 156 if bogus_builders and master != 'master.chromium.chromiumos': | 166 if bogus_builders and master != 'master.chromium.chromiumos': |
| 157 exit_code = 1 | 167 exit_code = 1 |
| 158 print 'The following builders from chromium recipe' | 168 print 'The following builders from chromium recipe' |
| 159 print 'do not exist in master config for %s:' % master | 169 print 'do not exist in master config for %s:' % master |
| 160 print '\n'.join('\t%s' % b for b in sorted(bogus_builders)) | 170 print '\n'.join('\t%s' % b for b in sorted(bogus_builders)) |
| 161 if unused: | 171 if unused: |
| 162 exit_code = 1 | 172 exit_code = 1 |
| 163 print 'The following unused declarations are superfluous ' | 173 print 'The following unused declarations are superfluous ' |
| 164 print 'on %s' % master | 174 print 'on %s' % master |
| 165 print '\n'.join('\t%s' % b for b in sorted(unused)) | 175 print '\n'.join('\t%s' % b for b in sorted(unused)) |
| 166 | 176 |
| 167 | 177 |
| 168 for master in TRYSERVER_MASTERS: | 178 for master in TRYSERVER_MASTERS: |
| 169 builders = getBuildersAndRecipes(master) | 179 builders = getBuildersAndRecipes(master) |
| 170 recipe_side_builders = chromium_trybot.BUILDERS[ | 180 recipe_side_builders = chromium_trybot_BUILDERS[ |
| 171 master.replace('master.', '')]['builders'] | 181 master.replace('master.', '')]['builders'] |
| 172 | 182 |
| 173 bogus_builders = set(recipe_side_builders.keys()).difference( | 183 bogus_builders = set(recipe_side_builders.keys()).difference( |
| 174 set(builders.keys())) | 184 set(builders.keys())) |
| 175 if bogus_builders: | 185 if bogus_builders: |
| 176 exit_code = 1 | 186 exit_code = 1 |
| 177 print 'The following builders from chromium_trybot recipe' | 187 print 'The following builders from chromium_trybot recipe' |
| 178 print 'do not exist in master config for %s:' % master | 188 print 'do not exist in master config for %s:' % master |
| 179 print '\n'.join('\t%s' % b for b in sorted(bogus_builders)) | 189 print '\n'.join('\t%s' % b for b in sorted(bogus_builders)) |
| 180 | 190 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 exit_code = 1 | 230 exit_code = 1 |
| 221 print 'Unused suppressions:' | 231 print 'Unused suppressions:' |
| 222 print '\n'.join(sorted( | 232 print '\n'.join(sorted( |
| 223 '\t%s:%s' % (b[0], b[1]) for b in unused_suppressions)) | 233 '\t%s:%s' % (b[0], b[1]) for b in unused_suppressions)) |
| 224 | 234 |
| 225 return exit_code | 235 return exit_code |
| 226 | 236 |
| 227 | 237 |
| 228 if __name__ == '__main__': | 238 if __name__ == '__main__': |
| 229 sys.exit(main(sys.argv[1:])) | 239 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |