1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5 6""" Utilities for dealing with builder names. This module obtains its attributes 7dynamically from builder_name_schema.json. """ 8 9 10import json 11import os 12 13 14# All of these global variables are filled in by _LoadSchema(). 15 16# The full schema. 17BUILDER_NAME_SCHEMA = None 18 19# Character which separates parts of a builder name. 20BUILDER_NAME_SEP = None 21 22# Builder roles. 23BUILDER_ROLE_CANARY = 'Canary' 24BUILDER_ROLE_BUILD = 'Build' 25BUILDER_ROLE_HOUSEKEEPER = 'Housekeeper' 26BUILDER_ROLE_INFRA = 'Infra' 27BUILDER_ROLE_PERF = 'Perf' 28BUILDER_ROLE_TEST = 'Test' 29BUILDER_ROLES = (BUILDER_ROLE_CANARY, 30 BUILDER_ROLE_BUILD, 31 BUILDER_ROLE_HOUSEKEEPER, 32 BUILDER_ROLE_INFRA, 33 BUILDER_ROLE_PERF, 34 BUILDER_ROLE_TEST) 35 36 37def _LoadSchema(): 38 """ Load the builder naming schema from the JSON file. """ 39 40 def _UnicodeToStr(obj): 41 """ Convert all unicode strings in obj to Python strings. """ 42 if isinstance(obj, unicode): 43 return str(obj) 44 elif isinstance(obj, dict): 45 return dict(map(_UnicodeToStr, obj.iteritems())) 46 elif isinstance(obj, list): 47 return list(map(_UnicodeToStr, obj)) 48 elif isinstance(obj, tuple): 49 return tuple(map(_UnicodeToStr, obj)) 50 51 builder_name_json_filename = os.path.join( 52 os.path.dirname(__file__), 'builder_name_schema.json') 53 builder_name_schema_json = json.load(open(builder_name_json_filename)) 54 55 global BUILDER_NAME_SCHEMA 56 BUILDER_NAME_SCHEMA = _UnicodeToStr( 57 builder_name_schema_json['builder_name_schema']) 58 59 global BUILDER_NAME_SEP 60 BUILDER_NAME_SEP = _UnicodeToStr( 61 builder_name_schema_json['builder_name_sep']) 62 63 # Since the builder roles are dictionary keys, just assert that the global 64 # variables above account for all of them. 65 assert len(BUILDER_ROLES) == len(BUILDER_NAME_SCHEMA) 66 for role in BUILDER_ROLES: 67 assert role in BUILDER_NAME_SCHEMA 68 69 70_LoadSchema() 71 72 73def MakeBuilderName(role, extra_config=None, **kwargs): 74 schema = BUILDER_NAME_SCHEMA.get(role) 75 if not schema: 76 raise ValueError('%s is not a recognized role.' % role) 77 for k, v in kwargs.iteritems(): 78 if BUILDER_NAME_SEP in v: 79 raise ValueError('%s not allowed in %s.' % (BUILDER_NAME_SEP, v)) 80 if not k in schema: 81 raise ValueError('Schema does not contain "%s": %s' %(k, schema)) 82 if extra_config and BUILDER_NAME_SEP in extra_config: 83 raise ValueError('%s not allowed in %s.' % (BUILDER_NAME_SEP, 84 extra_config)) 85 name_parts = [role] 86 name_parts.extend([kwargs[attribute] for attribute in schema]) 87 if extra_config: 88 name_parts.append(extra_config) 89 return BUILDER_NAME_SEP.join(name_parts) 90 91 92def DictForBuilderName(builder_name): 93 """Makes a dictionary containing details about the builder from its name.""" 94 split_name = builder_name.split(BUILDER_NAME_SEP) 95 96 def pop_front(): 97 try: 98 return split_name.pop(0) 99 except: 100 raise ValueError('Invalid builder name: %s' % builder_name) 101 102 result = {} 103 if split_name[0] in BUILDER_NAME_SCHEMA.keys(): 104 key_list = BUILDER_NAME_SCHEMA[split_name[0]] 105 result['role'] = pop_front() 106 for key in key_list: 107 result[key] = pop_front() 108 if split_name: 109 result['extra_config'] = pop_front() 110 if split_name: 111 raise ValueError('Invalid builder name: %s' % builder_name) 112 else: 113 raise ValueError('Invalid builder name: %s' % builder_name) 114 return result 115 116 117