| Index: tools/builder_name_schema.py
|
| diff --git a/tools/builder_name_schema.py b/tools/builder_name_schema.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..990aa6447cba9f50c33b0682f80b56847219204c
|
| --- /dev/null
|
| +++ b/tools/builder_name_schema.py
|
| @@ -0,0 +1,194 @@
|
| +# Copyright 2014 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +
|
| +""" Utilities for dealing with builder names. This module obtains its attributes
|
| +dynamically from builder_name_schema.json. """
|
| +
|
| +
|
| +import json
|
| +import os
|
| +
|
| +
|
| +# All of these global variables are filled in by _LoadSchema().
|
| +
|
| +# The full schema.
|
| +BUILDER_NAME_SCHEMA = None
|
| +
|
| +# Character which separates parts of a builder name.
|
| +BUILDER_NAME_SEP = None
|
| +
|
| +# Builder roles.
|
| +BUILDER_ROLE_CANARY = 'Canary'
|
| +BUILDER_ROLE_BUILD = 'Build'
|
| +BUILDER_ROLE_HOUSEKEEPER = 'Housekeeper'
|
| +BUILDER_ROLE_PERF = 'Perf'
|
| +BUILDER_ROLE_TEST = 'Test'
|
| +BUILDER_ROLES = (BUILDER_ROLE_CANARY,
|
| + BUILDER_ROLE_BUILD,
|
| + BUILDER_ROLE_HOUSEKEEPER,
|
| + BUILDER_ROLE_PERF,
|
| + BUILDER_ROLE_TEST)
|
| +
|
| +# Suffix which distinguishes trybots from normal bots.
|
| +TRYBOT_NAME_SUFFIX = None
|
| +
|
| +
|
| +def _LoadSchema():
|
| + """ Load the builder naming schema from the JSON file. """
|
| +
|
| + def _UnicodeToStr(obj):
|
| + """ Convert all unicode strings in obj to Python strings. """
|
| + if isinstance(obj, unicode):
|
| + return str(obj)
|
| + elif isinstance(obj, dict):
|
| + return dict(map(_UnicodeToStr, obj.iteritems()))
|
| + elif isinstance(obj, list):
|
| + return list(map(_UnicodeToStr, obj))
|
| + elif isinstance(obj, tuple):
|
| + return tuple(map(_UnicodeToStr, obj))
|
| + else:
|
| + return obj
|
| +
|
| + builder_name_json_filename = os.path.join(
|
| + os.path.dirname(__file__), 'builder_name_schema.json')
|
| + builder_name_schema_json = json.load(open(builder_name_json_filename))
|
| +
|
| + global BUILDER_NAME_SCHEMA
|
| + BUILDER_NAME_SCHEMA = _UnicodeToStr(
|
| + builder_name_schema_json['builder_name_schema'])
|
| +
|
| + global BUILDER_NAME_SEP
|
| + BUILDER_NAME_SEP = _UnicodeToStr(
|
| + builder_name_schema_json['builder_name_sep'])
|
| +
|
| + global TRYBOT_NAME_SUFFIX
|
| + TRYBOT_NAME_SUFFIX = _UnicodeToStr(
|
| + builder_name_schema_json['trybot_name_suffix'])
|
| +
|
| + # Since the builder roles are dictionary keys, just assert that the global
|
| + # variables above account for all of them.
|
| + assert len(BUILDER_ROLES) == len(BUILDER_NAME_SCHEMA)
|
| + for role in BUILDER_ROLES:
|
| + assert role in BUILDER_NAME_SCHEMA
|
| +
|
| +
|
| +_LoadSchema()
|
| +
|
| +
|
| +def MakeBuilderName(role, extra_config=None, is_trybot=False, **kwargs):
|
| + schema = BUILDER_NAME_SCHEMA.get(role)
|
| + if not schema:
|
| + raise ValueError('%s is not a recognized role.' % role)
|
| + for k, v in kwargs.iteritems():
|
| + if BUILDER_NAME_SEP in v:
|
| + raise ValueError('%s not allowed in %s.' % (BUILDER_NAME_SEP, v))
|
| + if not k in schema:
|
| + raise ValueError('Schema does not contain "%s": %s' %(k, schema))
|
| + if extra_config and BUILDER_NAME_SEP in extra_config:
|
| + raise ValueError('%s not allowed in %s.' % (BUILDER_NAME_SEP,
|
| + extra_config))
|
| + name_parts = [role]
|
| + name_parts.extend([kwargs[attribute] for attribute in schema])
|
| + if extra_config:
|
| + name_parts.append(extra_config)
|
| + if is_trybot:
|
| + name_parts.append(TRYBOT_NAME_SUFFIX)
|
| + return BUILDER_NAME_SEP.join(name_parts)
|
| +
|
| +
|
| +def BuilderNameFromObject(obj, is_trybot=False):
|
| + """Create a builder name based on properties of the given object.
|
| +
|
| + Args:
|
| + obj: the object from which to create the builder name. The object must
|
| + have as properties:
|
| + - A valid builder role, as defined in the JSON file
|
| + - All properties listed in the JSON file for that role
|
| + - Optionally, an extra_config property
|
| + is_trybot: bool; whether or not the builder is a trybot.
|
| + Returns:
|
| + string which combines the properties of the given object into a valid
|
| + builder name.
|
| + """
|
| + schema = BUILDER_NAME_SCHEMA.get(obj.role)
|
| + if not schema:
|
| + raise ValueError('%s is not a recognized role.' % obj.role)
|
| + name_parts = [obj.role]
|
| + for attr_name in schema:
|
| + attr_val = getattr(obj, attr_name)
|
| + name_parts.append(attr_val)
|
| + extra_config = getattr(obj, 'extra_config', None)
|
| + if extra_config:
|
| + name_parts.append(extra_config)
|
| + if is_trybot:
|
| + name_parts.append(TRYBOT_NAME_SUFFIX)
|
| + return BUILDER_NAME_SEP.join(name_parts)
|
| +
|
| +
|
| +def IsTrybot(builder_name):
|
| + """ Returns true if builder_name refers to a trybot (as opposed to a
|
| + waterfall bot). """
|
| + return builder_name.endswith(TRYBOT_NAME_SUFFIX)
|
| +
|
| +
|
| +def GetWaterfallBot(builder_name):
|
| + """Returns the name of the waterfall bot for this builder. If it is not a
|
| + trybot, builder_name is returned unchanged. If it is a trybot the name is
|
| + returned without the trybot suffix."""
|
| + if not IsTrybot(builder_name):
|
| + return builder_name
|
| + return _WithoutSuffix(builder_name, BUILDER_NAME_SEP + TRYBOT_NAME_SUFFIX)
|
| +
|
| +
|
| +def TrybotName(builder_name):
|
| + """Returns the name of the trybot clone of this builder.
|
| +
|
| + If the given builder is a trybot, the name is returned unchanged. If not, the
|
| + TRYBOT_NAME_SUFFIX is appended.
|
| + """
|
| + if builder_name.endswith(TRYBOT_NAME_SUFFIX):
|
| + return builder_name
|
| + return builder_name + BUILDER_NAME_SEP + TRYBOT_NAME_SUFFIX
|
| +
|
| +
|
| +def _WithoutSuffix(string, suffix):
|
| + """ Returns a copy of string 'string', but with suffix 'suffix' removed.
|
| + Raises ValueError if string does not end with suffix. """
|
| + if not string.endswith(suffix):
|
| + raise ValueError('_WithoutSuffix: string %s does not end with suffix %s' % (
|
| + string, suffix))
|
| + return string[:-len(suffix)]
|
| +
|
| +
|
| +def DictForBuilderName(builder_name):
|
| + """Makes a dictionary containing details about the builder from its name."""
|
| + split_name = builder_name.split(BUILDER_NAME_SEP)
|
| +
|
| + def pop_front():
|
| + try:
|
| + return split_name.pop(0)
|
| + except:
|
| + raise ValueError('Invalid builder name: %s' % builder_name)
|
| +
|
| + result = {'is_trybot': False}
|
| +
|
| + if split_name[-1] == TRYBOT_NAME_SUFFIX:
|
| + result['is_trybot'] = True
|
| + split_name.pop()
|
| +
|
| + if split_name[0] in BUILDER_NAME_SCHEMA.keys():
|
| + key_list = BUILDER_NAME_SCHEMA[split_name[0]]
|
| + result['role'] = pop_front()
|
| + for key in key_list:
|
| + result[key] = pop_front()
|
| + if split_name:
|
| + result['extra_config'] = pop_front()
|
| + if split_name:
|
| + raise ValueError('Invalid builder name: %s' % builder_name)
|
| + else:
|
| + raise ValueError('Invalid builder name: %s' % builder_name)
|
| + return result
|
| +
|
| +
|
|
|