1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
# 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
import attr
@attr.s
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)
- optimization: optimization 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': 'docker-image-desktop-test'}
- soft_dependencies: tasks this one may depend on if they are available post
optimisation. They are set as a list of tasks label.
- if_dependencies: only run this task if at least one of these dependencies
are present.
And later, as the task-graph processing proceeds:
- task_id -- TaskCluster taskId under which this task will be created
This class is just a convenience wrapper for the data type and managing
display, comparison, serialization, etc. It has no functionality of its own.
"""
kind = attr.ib()
label = attr.ib()
attributes = attr.ib()
task = attr.ib()
description = attr.ib(default="")
task_id = attr.ib(default=None, init=False)
optimization = attr.ib(default=None)
dependencies = attr.ib(factory=dict)
soft_dependencies = attr.ib(factory=list)
if_dependencies = attr.ib(factory=list)
release_artifacts = attr.ib(
converter=attr.converters.optional(frozenset),
default=None,
)
def __attrs_post_init__(self):
self.attributes["kind"] = self.kind
@property
def name(self):
if self.label.startswith(self.kind + "-"):
return self.label[len(self.kind) + 1 :]
else:
raise AttributeError("Task {} does not have a name.".format(self.label))
def to_json(self):
rv = {
"kind": self.kind,
"label": self.label,
"description": self.description,
"attributes": self.attributes,
"dependencies": self.dependencies,
"soft_dependencies": sorted(self.soft_dependencies),
"if_dependencies": self.if_dependencies,
"optimization": self.optimization,
"task": self.task,
}
if self.task_id:
rv["task_id"] = self.task_id
if self.release_artifacts:
rv["release_artifacts"] = sorted(self.release_artifacts)
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"],
description=task_dict.get("description", ""),
attributes=task_dict["attributes"],
task=task_dict["task"],
optimization=task_dict["optimization"],
dependencies=task_dict.get("dependencies"),
soft_dependencies=task_dict.get("soft_dependencies"),
if_dependencies=task_dict.get("if_dependencies"),
release_artifacts=task_dict.get("release-artifacts"),
)
if "task_id" in task_dict:
rv.task_id = task_dict["task_id"]
return rv
|