File: matrix.py

package info (click to toggle)
thunderbird 1%3A144.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 4,725,312 kB
  • sloc: cpp: 7,869,225; javascript: 5,974,276; ansic: 3,946,747; python: 1,421,062; xml: 654,642; asm: 474,045; java: 183,117; sh: 110,973; makefile: 20,398; perl: 14,362; objc: 13,086; yacc: 4,583; pascal: 3,448; lex: 1,720; ruby: 999; exp: 762; sql: 731; awk: 580; php: 436; lisp: 430; sed: 69; csh: 10
file content (112 lines) | stat: -rw-r--r-- 3,454 bytes parent folder | download | duplicates (3)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
# 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/.

"""
Transforms used to split one task definition into many tasks, governed by a
matrix defined in the definition.
"""

from copy import deepcopy
from textwrap import dedent

from voluptuous import ALLOW_EXTRA, Extra, Optional, Required

from taskgraph.transforms.base import TransformSequence
from taskgraph.util.schema import Schema
from taskgraph.util.templates import substitute_task_fields

#: Schema for matrix transforms
MATRIX_SCHEMA = Schema(
    {
        Required("name"): str,
        Optional("matrix"): {
            Optional(
                "exclude",
                description=dedent(
                    """
                Exclude the specified combination(s) of matrix values from the
                final list of tasks.

                If only a subset of the possible rows are present in the
                exclusion rule, then *all* combinations including that subset
                subset will be excluded.
                """.lstrip()
                ),
            ): [{str: str}],
            Optional(
                "set-name",
                description=dedent(
                    """
                Sets the task name to the specified format string.

                Useful for cases where the default of joining matrix values by
                a dash is not desired.
                """.lstrip()
                ),
            ): str,
            Optional(
                "substitution-fields",
                description=dedent(
                    """
                List of fields in the task definition to substitute matrix values into.

                If not specified, all fields in the task definition will be
                substituted.
                """
                ),
            ): [str],
            Extra: [str],
        },
    },
    extra=ALLOW_EXTRA,
)

transforms = TransformSequence()
transforms.add_validate(MATRIX_SCHEMA)


def _resolve_matrix(tasks, key, values, exclude):
    for task in tasks:
        for value in values:
            new_task = deepcopy(task)
            new_task["name"] = f"{new_task['name']}-{value}"

            matrix = new_task.setdefault("attributes", {}).setdefault("matrix", {})
            matrix[key] = value

            for rule in exclude:
                if all(matrix.get(k) == v for k, v in rule.items()):
                    break
            else:
                yield new_task


@transforms.add
def split_matrix(config, tasks):
    for task in tasks:
        if "matrix" not in task:
            yield task
            continue

        matrix = task.pop("matrix")
        set_name = matrix.pop("set-name", None)
        fields = matrix.pop("substitution-fields", task.keys())
        exclude = matrix.pop("exclude", {})

        new_tasks = [task]
        for key, values in matrix.items():
            new_tasks = _resolve_matrix(new_tasks, key, values, exclude)

        for new_task in new_tasks:
            if set_name:
                if "name" not in fields:
                    fields.append("name")
                new_task["name"] = set_name

            substitute_task_fields(
                new_task,
                fields,
                matrix=new_task["attributes"]["matrix"],
            )
            yield new_task