mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 08:48:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
155
taskcluster/taskgraph/util/templates.py
Normal file
155
taskcluster/taskgraph/util/templates.py
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
# 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 os
|
||||
|
||||
import pystache
|
||||
import yaml
|
||||
import copy
|
||||
|
||||
# Key used in template inheritance...
|
||||
INHERITS_KEY = '$inherits'
|
||||
|
||||
|
||||
def merge_to(source, dest):
|
||||
'''
|
||||
Merge dict and arrays (override scalar values)
|
||||
|
||||
Keys from source override keys from dest, and elements from lists in source
|
||||
are appended to lists in dest.
|
||||
|
||||
:param dict source: to copy from
|
||||
:param dict dest: to copy to (modified in place)
|
||||
'''
|
||||
|
||||
for key, value in source.items():
|
||||
# Override mismatching or empty types
|
||||
if type(value) != type(dest.get(key)): # noqa
|
||||
dest[key] = source[key]
|
||||
continue
|
||||
|
||||
# Merge dict
|
||||
if isinstance(value, dict):
|
||||
merge_to(value, dest[key])
|
||||
continue
|
||||
|
||||
if isinstance(value, list):
|
||||
dest[key] = dest[key] + source[key]
|
||||
continue
|
||||
|
||||
dest[key] = source[key]
|
||||
|
||||
return dest
|
||||
|
||||
|
||||
def merge(*objects):
|
||||
'''
|
||||
Merge the given objects, using the semantics described for merge_to, with
|
||||
objects later in the list taking precedence. From an inheritance
|
||||
perspective, "parents" should be listed before "children".
|
||||
|
||||
Returns the result without modifying any arguments.
|
||||
'''
|
||||
if len(objects) == 1:
|
||||
return copy.deepcopy(objects[0])
|
||||
return merge_to(objects[-1], merge(*objects[:-1]))
|
||||
|
||||
|
||||
class TemplatesException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Templates():
|
||||
'''
|
||||
The taskcluster integration makes heavy use of yaml to describe tasks this
|
||||
class handles the loading/rendering.
|
||||
'''
|
||||
|
||||
def __init__(self, root):
|
||||
'''
|
||||
Initialize the template render.
|
||||
|
||||
:param str root: Root path where to load yaml files.
|
||||
'''
|
||||
if not root:
|
||||
raise TemplatesException('Root is required')
|
||||
|
||||
if not os.path.isdir(root):
|
||||
raise TemplatesException('Root must be a directory')
|
||||
|
||||
self.root = root
|
||||
|
||||
def _inherits(self, path, obj, properties, seen):
|
||||
blueprint = obj.pop(INHERITS_KEY)
|
||||
seen.add(path)
|
||||
|
||||
# Resolve the path here so we can detect circular references.
|
||||
template = self.resolve_path(blueprint.get('from'))
|
||||
variables = blueprint.get('variables', {})
|
||||
|
||||
# Passed parameters override anything in the task itself.
|
||||
for key in properties:
|
||||
variables[key] = properties[key]
|
||||
|
||||
if not template:
|
||||
msg = '"{}" inheritance template missing'.format(path)
|
||||
raise TemplatesException(msg)
|
||||
|
||||
if template in seen:
|
||||
msg = 'Error while handling "{}" in "{}" circular template' + \
|
||||
'inheritance seen \n {}'
|
||||
raise TemplatesException(msg.format(path, template, seen))
|
||||
|
||||
try:
|
||||
out = self.load(template, variables, seen)
|
||||
except TemplatesException as e:
|
||||
msg = 'Error expanding parent ("{}") of "{}" original error {}'
|
||||
raise TemplatesException(msg.format(template, path, str(e)))
|
||||
|
||||
# Anything left in obj is merged into final results (and overrides)
|
||||
return merge_to(obj, out)
|
||||
|
||||
def render(self, path, content, parameters, seen):
|
||||
'''
|
||||
Renders a given yaml string.
|
||||
|
||||
:param str path: used to prevent infinite recursion in inheritance.
|
||||
:param str content: Of yaml file.
|
||||
:param dict parameters: For mustache templates.
|
||||
:param set seen: Seen files (used for inheritance)
|
||||
'''
|
||||
content = pystache.render(content, parameters)
|
||||
result = yaml.load(content)
|
||||
|
||||
# In addition to the usual template logic done by mustache we also
|
||||
# handle special '$inherit' dict keys.
|
||||
if isinstance(result, dict) and INHERITS_KEY in result:
|
||||
return self._inherits(path, result, parameters, seen)
|
||||
|
||||
return result
|
||||
|
||||
def resolve_path(self, path):
|
||||
return os.path.join(self.root, path)
|
||||
|
||||
def load(self, path, parameters=None, seen=None):
|
||||
'''
|
||||
Load an render the given yaml path.
|
||||
|
||||
:param str path: Location of yaml file to load (relative to root).
|
||||
:param dict parameters: To template yaml file with.
|
||||
'''
|
||||
seen = seen or set()
|
||||
|
||||
if not path:
|
||||
raise TemplatesException('path is required')
|
||||
|
||||
path = self.resolve_path(path)
|
||||
|
||||
if not os.path.isfile(path):
|
||||
raise TemplatesException('"{}" is not a file'.format(path))
|
||||
|
||||
content = open(path).read()
|
||||
return self.render(path, content, parameters, seen)
|
||||
Loading…
Add table
Add a link
Reference in a new issue