fune/taskcluster/taskgraph/util/keyed_by.py
Tom Prince 9203300311 Bug 1532710: [taskgraph] Provide a function version of resolve_keyed_by that doesn't mutate; r=dustin
I'd like to use the same format for config values, that get evaluated in different contexts, so don't
to mutate the config for that.

Differential Revision: https://phabricator.services.mozilla.com/D22126

--HG--
extra : moz-landing-system : lando
2019-03-07 04:20:33 +00:00

74 lines
2.5 KiB
Python

# 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
from .attributes import keymatch
def evaluate_keyed_by(value, item_name, attributes):
"""
For values which can either accept a literal value, or be keyed by some
attributes, perform that lookup and return the result.
For example, given item::
by-test-platform:
macosx-10.11/debug: 13
win.*: 6
default: 12
a call to `evaluate_keyed_by(item, 'thing-name', {'test-platform': 'linux96')`
would return `12`.
The `item_name` parameter is used to generate useful error messages.
Items can be nested as deeply as desired::
by-test-platform:
win.*:
by-project:
ash: ..
cedar: ..
linux: 13
default: 12
"""
while True:
if not isinstance(value, dict) or len(value) != 1 or not value.keys()[0].startswith('by-'):
return value
keyed_by = value.keys()[0][3:] # strip off 'by-' prefix
key = attributes.get(keyed_by)
alternatives = value.values()[0]
if len(alternatives) == 1 and 'default' in alternatives:
# Error out when only 'default' is specified as only alternatives,
# because we don't need to by-{keyed_by} there.
raise Exception(
"Keyed-by '{}' unnecessary with only value 'default' "
"found, when determining item {}".format(
keyed_by, item_name))
if key is None:
if 'default' in alternatives:
value = alternatives['default']
continue
else:
raise Exception(
"No attribute {} and no value for 'default' found "
"while determining item {}".format(
keyed_by, item_name))
matches = keymatch(alternatives, key)
if len(matches) > 1:
raise Exception(
"Multiple matching values for {} {!r} found while "
"determining item {}".format(
keyed_by, key, item_name))
elif matches:
value = matches[0]
continue
raise Exception(
"No {} matching {!r} nor 'default' found while determining item {}".format(
keyed_by, key, item_name))