Bug 1463522 - only read .taskcluster.yml once; r?tomprince draft
authorDustin J. Mitchell <dustin@mozilla.com>
Tue, 22 May 2018 18:11:23 +0000
changeset 800066 6d87a3b0fed4435bdb5050aa07780ae692127586
parent 798084 b75acf9652937ce79a9bf02de843c100db0e5ec7
child 800067 6ef97f9ce2a73b832154c8f2779a68cb60f56c17
push id111252
push userdmitchell@mozilla.com
push dateFri, 25 May 2018 20:15:14 +0000
reviewerstomprince
bugs1463522
milestone62.0a1
Bug 1463522 - only read .taskcluster.yml once; r?tomprince PyYAML is not fast, so the fewer times we parse the same file, the better MozReview-Commit-ID: KuYKFY7hFXp
taskcluster/taskgraph/actions/registry.py
--- a/taskcluster/taskgraph/actions/registry.py
+++ b/taskcluster/taskgraph/actions/registry.py
@@ -4,24 +4,24 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import json
 import os
 import re
-import yaml
 from slugid import nice as slugid
 from types import FunctionType
 from collections import namedtuple
 from taskgraph import create
 from taskgraph.config import load_graph_config
-from taskgraph.util import taskcluster
+from taskgraph.util import taskcluster, yaml
 from taskgraph.parameters import Parameters
+from mozbuild.util import memoize
 
 
 actions = []
 callbacks = {}
 
 Action = namedtuple('Action', ['order', 'action_builder'])
 
 
@@ -29,16 +29,22 @@ def is_json(data):
     """ Return ``True``, if ``data`` is a JSON serializable data structure. """
     try:
         json.dumps(data)
     except ValueError:
         return False
     return True
 
 
+@memoize
+def read_taskcluster_yml(filename):
+    '''Load and parse .taskcluster.yml, memoized to save some time'''
+    return yaml.load_yaml(*os.path.split(filename))
+
+
 def register_callback_action(name, title, symbol, description, order=10000,
                              context=[], available=lambda parameters: True,
                              schema=None, kind='task', generic=True):
     """
     Register an action callback that can be triggered from supporting
     user interfaces, such as Treeherder.
 
     This function is to be used as a decorator for a callback that takes
@@ -162,32 +168,29 @@ def register_callback_action(name, title
                 'context': context,
             }
             if schema:
                 rv['schema'] = schema(graph_config=graph_config) if callable(schema) else schema
 
             # for kind=task, we embed the task from .taskcluster.yml in the action, with
             # suitable context
             if kind == 'task':
-                template = graph_config.taskcluster_yml
-
                 # tasks get all of the scopes the original push did, yuck; this is not
                 # done with kind = hook.
                 repo_scope = 'assume:repo:{}/{}:branch:default'.format(
                     match.group(1), match.group(2))
                 action['repo_scope'] = repo_scope
 
-                with open(template, 'r') as f:
-                    taskcluster_yml = yaml.safe_load(f)
-                    if taskcluster_yml['version'] != 1:
-                        raise Exception(
-                            'actions.json must be updated to work with .taskcluster.yml')
-                    if not isinstance(taskcluster_yml['tasks'], list):
-                        raise Exception(
-                            '.taskcluster.yml "tasks" must be a list for action tasks')
+                taskcluster_yml = read_taskcluster_yml(graph_config.taskcluster_yml)
+                if taskcluster_yml['version'] != 1:
+                    raise Exception(
+                        'actions.json must be updated to work with .taskcluster.yml')
+                if not isinstance(taskcluster_yml['tasks'], list):
+                    raise Exception(
+                        '.taskcluster.yml "tasks" must be a list for action tasks')
 
                 rv.update({
                     'kind': 'task',
                     'task': {
                         '$let': {
                             'tasks_for': 'action',
                             'repository': repository,
                             'push': push,