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 |
+ |
+ |