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
5
6import re
7
8
9def attrmatch(attributes, **kwargs):
10    """Determine whether the given set of task attributes matches.  The
11    conditions are given as keyword arguments, where each keyword names an
12    attribute.  The keyword value can be a literal, a set, or a callable.  A
13    literal must match the attribute exactly.  Given a set, the attribute value
14    must be in the set.  A callable is called with the attribute value.  If an
15    attribute is specified as a keyword argument but not present in the
16    attributes, the result is False."""
17    for kwkey, kwval in kwargs.items():
18        if kwkey not in attributes:
19            return False
20        attval = attributes[kwkey]
21        if isinstance(kwval, set):
22            if attval not in kwval:
23                return False
24        elif callable(kwval):
25            if not kwval(attval):
26                return False
27        elif kwval != attributes[kwkey]:
28            return False
29    return True
30
31
32def keymatch(attributes, target):
33    """Determine if any keys in attributes are a match to target, then return
34    a list of matching values. First exact matches will be checked. Failing
35    that, regex matches and finally a default key.
36    """
37    # exact match
38    if target in attributes:
39        return [attributes[target]]
40
41    # regular expression match
42    matches = [v for k, v in attributes.items() if re.match(k + "$", target)]
43    if matches:
44        return matches
45
46    # default
47    if "default" in attributes:
48        return [attributes["default"]]
49
50    return []
51
52
53def _match_run_on(key, run_on):
54    """
55    Determine whether the given parameter is included in the corresponding `run-on-attribute`.
56    """
57    if "all" in run_on:
58        return True
59    return key in run_on
60
61
62match_run_on_projects = _match_run_on
63match_run_on_tasks_for = _match_run_on
64
65
66def match_run_on_git_branches(git_branch, run_on_git_branches):
67    """
68    Determine whether the given project is included in the `run-on-git-branches` parameter.
69    Allows 'all'.
70    """
71    if "all" in run_on_git_branches:
72        return True
73
74    for expected_git_branch_pattern in run_on_git_branches:
75        if re.match(expected_git_branch_pattern, git_branch):
76            return True
77
78    return False
79
80
81def sorted_unique_list(*args):
82    """Join one or more lists, and return a sorted list of unique members"""
83    combined = set().union(*args)
84    return sorted(combined)
85