1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5from __future__ import absolute_import, print_function, unicode_literals
6
7import abc
8
9
10class Task(object):
11    """
12    Representation of a task in a TaskGraph.  Each Task has, at creation:
13
14    - kind: the name of the task kind
15    - label; the label for this task
16    - attributes: a dictionary of attributes for this task (used for filtering)
17    - task: the task definition (JSON-able dictionary)
18
19    And later, as the task-graph processing proceeds:
20
21    - task_id -- TaskCluster taskId under which this task will be created
22    - optimized -- true if this task need not be performed
23
24    A kind represents a collection of tasks that share common characteristics.
25    For example, all build jobs.  Each instance of a kind is intialized with a
26    path from which it draws its task configuration.  The instance is free to
27    store as much local state as it needs.
28    """
29    __metaclass__ = abc.ABCMeta
30
31    def __init__(self, kind, label, attributes, task):
32        self.kind = kind
33        self.label = label
34        self.attributes = attributes
35        self.task = task
36
37        self.task_id = None
38        self.optimized = False
39
40        self.attributes['kind'] = kind
41
42    def __eq__(self, other):
43        return self.kind == other.kind and \
44            self.label == other.label and \
45            self.attributes == other.attributes and \
46            self.task == other.task and \
47            self.task_id == other.task_id
48
49    @classmethod
50    @abc.abstractmethod
51    def load_tasks(cls, kind, path, config, parameters, loaded_tasks):
52        """
53        Load the tasks for a given kind.
54
55        The `kind` is the name of the kind; the configuration for that kind
56        named this class.
57
58        The `path` is the path to the configuration directory for the kind.  This
59        can be used to load extra data, templates, etc.
60
61        The `parameters` give details on which to base the task generation.
62        See `taskcluster/docs/parameters.rst` for details.
63
64        At the time this method is called, all kinds on which this kind depends
65        (that is, specified in the `kind-dependencies` key in `self.config`
66        have already loaded their tasks, and those tasks are available in
67        the list `loaded_tasks`.
68
69        The return value is a list of Task instances.
70        """
71
72    @abc.abstractmethod
73    def get_dependencies(self, taskgraph):
74        """
75        Get the set of task labels this task depends on, by querying the full
76        task set, given as `taskgraph`.
77
78        Returns a list of (task_label, dependency_name) pairs describing the
79        dependencies.
80        """
81
82    def optimize(self, params):
83        """
84        Determine whether this task can be optimized, and if it can, what taskId
85        it should be replaced with.
86
87        The return value is a tuple `(optimized, taskId)`.  If `optimized` is
88        true, then the task will be optimized (in other words, not included in
89        the task graph).  If the second argument is a taskid, then any
90        dependencies on this task will isntead depend on that taskId.  It is an
91        error to return no taskId for a task on which other tasks depend.
92
93        The default never optimizes.
94        """
95        return False, None
96
97    @classmethod
98    def from_json(cls, task_dict):
99        """
100        Given a data structure as produced by taskgraph.to_json, re-construct
101        the original Task object.  This is used to "resume" the task-graph
102        generation process, for example in Action tasks.
103        """
104        return cls(
105            kind=task_dict['attributes']['kind'],
106            label=task_dict['label'],
107            attributes=task_dict['attributes'],
108            task=task_dict['task'])
109