taskcluster/taskgraph/task.py
author Nicholas Nethercote <nnethercote@mozilla.com>
Thu, 22 Jun 2017 17:08:53 +1000
changeset 414698 aa1693a26a15eb5cba24102222687dc81eeddd7b
parent 395670 033351ec3eb4257f26c7344bc584ea3832eed737
child 427782 045498bc36c4bab49853ca54d2ca3f26fc50f91e
permissions -rw-r--r--
Bug 1375392 - Tweak the PROFILER_LABEL* macros. r=mstange. This patch makes the following changes to the macros. - Removes PROFILER_LABEL_FUNC. It's only suitable for use in functions outside classes, due to PROFILER_FUNCTION_NAME not getting class names, and it was mostly misused. - Removes PROFILER_FUNCTION_NAME. It's no longer used, and __func__ is universally available now anyway. - Combines the first two string literal arguments of PROFILER_LABEL and PROFILER_LABEL_DYNAMIC into a single argument. There was no good reason for them to be separate, and it forced a '::' in the label, which isn't always appropriate. Also, the meaning of the "name_space" argument was interpreted in an interesting variety of ways. - Adds an "AUTO_" prefix to PROFILER_LABEL and PROFILER_LABEL_DYNAMIC, to make it clearer they construct RAII objects rather than just being function calls. (I myself have screwed up the scoping because of this in the past.) - Fills in the 'js::ProfileEntry::Category::' qualifier within the macro, so the caller doesn't need to. This makes a *lot* more of the uses fit onto a single line. The patch also makes the following changes to the macro uses (beyond those required by the changes described above). - Fixes a bunch of labels that had gotten out of sync with the name of the class and/or function that encloses them. - Removes a useless PROFILER_LABEL use within a trivial scope in EventStateManager::DispatchMouseOrPointerEvent(). It clearly wasn't serving any useful purpose. It also serves as extra evidence that the AUTO_ prefix is a good idea. - Tweaks DecodePool::SyncRunIf{Preferred,Possible} so that the labelling is done within them, instead of at their callsites, because that's a more standard way of doing things.

# This Source Code Form is subject to the terms of the Mozilla Public
# 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


class Task(object):
    """
    Representation of a task in a TaskGraph.  Each Task has, at creation:

    - kind: the name of the task kind
    - label; the label for this task
    - attributes: a dictionary of attributes for this task (used for filtering)
    - task: the task definition (JSON-able dictionary)
    - optimizations: optimizations to apply to the task (see taskgraph.optimize)
    - dependencies: tasks this one depends on, in the form {name: label}, for example
      {'build': 'build-linux64/opt', 'docker-image': 'build-docker-image-desktop-test'}

    And later, as the task-graph processing proceeds:

    - task_id -- TaskCluster taskId under which this task will be created
    - optimized -- true if this task need not be performed

    This class is just a convenience wraper for the data type and managing
    display, comparison, serialization, etc. It has no functionality of its own.
    """
    def __init__(self, kind, label, attributes, task,
                 optimizations=None, dependencies=None):
        self.kind = kind
        self.label = label
        self.attributes = attributes
        self.task = task

        self.task_id = None
        self.optimized = False

        self.attributes['kind'] = kind

        self.optimizations = optimizations or []
        self.dependencies = dependencies or {}

    def __eq__(self, other):
        return self.kind == other.kind and \
            self.label == other.label and \
            self.attributes == other.attributes and \
            self.task == other.task and \
            self.task_id == other.task_id and \
            self.optimizations == other.optimizations and \
            self.dependencies == other.dependencies

    def __repr__(self):
        return ('Task({kind!r}, {label!r}, {attributes!r}, {task!r}, '
                'optimizations={optimizations!r}, '
                'dependencies={dependencies!r})'.format(**self.__dict__))

    def to_json(self):
        rv = {
            'kind': self.kind,
            'label': self.label,
            'attributes': self.attributes,
            'dependencies': self.dependencies,
            'optimizations': self.optimizations,
            'task': self.task,
        }
        if self.task_id:
            rv['task_id'] = self.task_id
        return rv

    @classmethod
    def from_json(cls, task_dict):
        """
        Given a data structure as produced by taskgraph.to_json, re-construct
        the original Task object.  This is used to "resume" the task-graph
        generation process, for example in Action tasks.
        """
        rv = cls(
            kind=task_dict['kind'],
            label=task_dict['label'],
            attributes=task_dict['attributes'],
            task=task_dict['task'],
            optimizations=task_dict['optimizations'],
            dependencies=task_dict.get('dependencies'))
        if 'task_id' in task_dict:
            rv.task_id = task_dict['task_id']
        return rv