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