mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1023790 - [manifestparser] Add support for parent link. r=hskupin, r=jmaher
This commit is contained in:
parent
0a58c01b3c
commit
76452a6326
@ -124,6 +124,13 @@ You can also include other manifests:
|
||||
|
||||
[include:subdir/anothermanifest.ini]
|
||||
|
||||
And reference parent manifests to inherit keys and values from the DEFAULT
|
||||
section, without adding possible included tests.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
[parent:../manifest.ini]
|
||||
|
||||
Manifests are included relative to the directory of the manifest with
|
||||
the `[include:]` directive unless they are absolute paths.
|
||||
|
||||
@ -140,6 +147,22 @@ must start on a new line, inline comments are not supported.
|
||||
In the example above, the 'color' property will have the value 'red #
|
||||
not a valid comment'.
|
||||
|
||||
Special variable server-root
|
||||
````````````````````````````
|
||||
There is a special variable called `server-root` used for paths on the system.
|
||||
This variable is deemed a path and will be expanded into its absolute form.
|
||||
|
||||
Because of the inheritant nature of the key/value pairs, if one requires a
|
||||
system path, it must be absolute for it to be of any use in any included file.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
[DEFAULTS]
|
||||
server-root = ../data
|
||||
|
||||
[test1.js]
|
||||
server-root = test1/data
|
||||
|
||||
Manifest Conditional Expressions
|
||||
````````````````````````````````
|
||||
The conditional expressions used in manifests are parsed using the *ExpressionParser* class.
|
||||
|
@ -386,6 +386,13 @@ def read_ini(fp, variables=None, default='DEFAULT',
|
||||
local_dict['skip-if'] = "(%s) || (%s)" % (variables['skip-if'].split('#')[0], local_dict['skip-if'].split('#')[0])
|
||||
variables.update(local_dict)
|
||||
|
||||
# server-root is an os path declared relative to the manifest file.
|
||||
# inheritance demands we expand it as absolute
|
||||
if 'server-root' in variables:
|
||||
root = os.path.join(os.path.dirname(fp.name),
|
||||
variables['server-root'])
|
||||
variables['server-root'] = os.path.abspath(root)
|
||||
|
||||
return variables
|
||||
|
||||
sections = [(i, interpret_variables(variables, j)) for i, j in sections]
|
||||
@ -399,6 +406,7 @@ class ManifestParser(object):
|
||||
|
||||
def __init__(self, manifests=(), defaults=None, strict=True):
|
||||
self._defaults = defaults or {}
|
||||
self._ancestor_defaults = {}
|
||||
self.tests = []
|
||||
self.manifest_defaults = {}
|
||||
self.strict = strict
|
||||
@ -412,7 +420,30 @@ class ManifestParser(object):
|
||||
|
||||
### methods for reading manifests
|
||||
|
||||
def _read(self, root, filename, defaults):
|
||||
def _read(self, root, filename, defaults, defaults_only=False):
|
||||
"""
|
||||
Internal recursive method for reading and parsing manifests.
|
||||
Stores all found tests in self.tests
|
||||
:param root: The base path
|
||||
:param filename: File object or string path for the base manifest file
|
||||
:param defaults: Options that apply to all items
|
||||
:param defaults_only: If True will only gather options, not include
|
||||
tests. Used for upstream parent includes
|
||||
(default False)
|
||||
"""
|
||||
def read_file(type):
|
||||
include_file = section.split(type, 1)[-1]
|
||||
include_file = normalize_path(include_file)
|
||||
if not os.path.isabs(include_file):
|
||||
include_file = os.path.join(self.getRelativeRoot(here), include_file)
|
||||
if not os.path.exists(include_file):
|
||||
message = "Included file '%s' does not exist" % include_file
|
||||
if self.strict:
|
||||
raise IOError(message)
|
||||
else:
|
||||
sys.stderr.write("%s\n" % message)
|
||||
return
|
||||
return include_file
|
||||
|
||||
# get directory of this file if not file-like object
|
||||
if isinstance(filename, string):
|
||||
@ -442,26 +473,32 @@ class ManifestParser(object):
|
||||
if 'subsuite' in data:
|
||||
subsuite = data['subsuite']
|
||||
|
||||
# read the parent manifest if specified
|
||||
if section.startswith('parent:'):
|
||||
include_file = read_file('parent:')
|
||||
if include_file:
|
||||
self._read(root, include_file, {}, True)
|
||||
continue
|
||||
|
||||
# If this is a parent include we only load the defaults into ancestor
|
||||
if defaults_only:
|
||||
self._ancestor_defaults = dict(data.items() + self._ancestor_defaults.items())
|
||||
break
|
||||
|
||||
# a file to include
|
||||
# TODO: keep track of included file structure:
|
||||
# self.manifests = {'manifest.ini': 'relative/path.ini'}
|
||||
if section.startswith('include:'):
|
||||
include_file = section.split('include:', 1)[-1]
|
||||
include_file = normalize_path(include_file)
|
||||
if not os.path.isabs(include_file):
|
||||
include_file = os.path.join(self.getRelativeRoot(here), include_file)
|
||||
if not os.path.exists(include_file):
|
||||
message = "Included file '%s' does not exist" % include_file
|
||||
if self.strict:
|
||||
raise IOError(message)
|
||||
else:
|
||||
sys.stderr.write("%s\n" % message)
|
||||
continue
|
||||
include_defaults = data.copy()
|
||||
self._read(root, include_file, include_defaults)
|
||||
include_file = read_file('include:')
|
||||
if include_file:
|
||||
include_defaults = data.copy()
|
||||
self._read(root, include_file, include_defaults)
|
||||
continue
|
||||
|
||||
# otherwise an item
|
||||
# apply ancestor defaults, while maintaining current file priority
|
||||
data = dict(self._ancestor_defaults.items() + data.items())
|
||||
|
||||
test = data
|
||||
test['name'] = section
|
||||
|
||||
|
1
testing/mozbase/manifestparser/tests/include-invalid.ini
Normal file
1
testing/mozbase/manifestparser/tests/include-invalid.ini
Normal file
@ -0,0 +1 @@
|
||||
[include:invalid.ini]
|
@ -0,0 +1,5 @@
|
||||
[DEFAULT]
|
||||
x = level_1
|
||||
|
||||
[test_1]
|
||||
[test_2]
|
@ -0,0 +1,5 @@
|
||||
[DEFAULT]
|
||||
server-root = ../root
|
||||
other-root = ../root
|
||||
|
||||
[test_1]
|
@ -0,0 +1,3 @@
|
||||
[parent:../level_1.ini]
|
||||
|
||||
[test_2]
|
@ -0,0 +1,3 @@
|
||||
[parent:../level_1_server-root.ini]
|
||||
|
||||
[test_2]
|
@ -0,0 +1,3 @@
|
||||
[parent:../level_2.ini]
|
||||
|
||||
[test_3]
|
@ -0,0 +1,6 @@
|
||||
[parent:../level_2.ini]
|
||||
|
||||
[DEFAULT]
|
||||
x = level_3
|
||||
|
||||
[test_3]
|
@ -0,0 +1,3 @@
|
||||
[parent:../level_2_server-root.ini]
|
||||
|
||||
[test_3]
|
@ -0,0 +1 @@
|
||||
# dummy spot for "test_3" test
|
@ -0,0 +1 @@
|
||||
# dummy spot for "test_2" test
|
@ -0,0 +1 @@
|
||||
# dummy spot for "test_1" test
|
@ -106,6 +106,83 @@ class TestManifestParser(unittest.TestCase):
|
||||
self.assertEqual(buffer.getvalue().strip(),
|
||||
'[DEFAULT]\nfoo = bar\n\n[fleem]\nsubsuite = \n\n[include/flowers]\nblue = ocean\nred = roses\nsubsuite = \nyellow = submarine')
|
||||
|
||||
def test_invalid_path(self):
|
||||
"""
|
||||
Test invalid path should not throw when not strict
|
||||
"""
|
||||
manifest = os.path.join(here, 'include-invalid.ini')
|
||||
parser = ManifestParser(manifests=(manifest,), strict=False)
|
||||
|
||||
def test_parent_inheritance(self):
|
||||
"""
|
||||
Test parent manifest variable inheritance
|
||||
Specifically tests that inherited variables from parent includes
|
||||
properly propagate downstream
|
||||
"""
|
||||
parent_example = os.path.join(here, 'parent', 'level_1', 'level_2',
|
||||
'level_3', 'level_3.ini')
|
||||
parser = ManifestParser(manifests=(parent_example,))
|
||||
|
||||
# Parent manifest test should not be included
|
||||
self.assertEqual(parser.get('name'),
|
||||
['test_3'])
|
||||
self.assertEqual([(test['name'], os.path.basename(test['manifest'])) for test in parser.tests],
|
||||
[('test_3', 'level_3.ini')])
|
||||
|
||||
# DEFAULT values should be the ones from level 1
|
||||
self.assertEqual(parser.get('name', x='level_1'),
|
||||
['test_3'])
|
||||
|
||||
# Write the output to a manifest:
|
||||
buffer = StringIO()
|
||||
parser.write(fp=buffer, global_kwargs={'x': 'level_1'})
|
||||
self.assertEqual(buffer.getvalue().strip(),
|
||||
'[DEFAULT]\nx = level_1\n\n[test_3]\nsubsuite =')
|
||||
|
||||
def test_parent_defaults(self):
|
||||
"""
|
||||
Test downstream variables should overwrite upstream variables
|
||||
"""
|
||||
parent_example = os.path.join(here, 'parent', 'level_1', 'level_2',
|
||||
'level_3', 'level_3_default.ini')
|
||||
parser = ManifestParser(manifests=(parent_example,))
|
||||
|
||||
# Parent manifest test should not be included
|
||||
self.assertEqual(parser.get('name'),
|
||||
['test_3'])
|
||||
self.assertEqual([(test['name'], os.path.basename(test['manifest'])) for test in parser.tests],
|
||||
[('test_3', 'level_3_default.ini')])
|
||||
|
||||
# DEFAULT values should be the ones from level 3
|
||||
self.assertEqual(parser.get('name', x='level_3'),
|
||||
['test_3'])
|
||||
|
||||
# Write the output to a manifest:
|
||||
buffer = StringIO()
|
||||
parser.write(fp=buffer, global_kwargs={'x': 'level_3'})
|
||||
self.assertEqual(buffer.getvalue().strip(),
|
||||
'[DEFAULT]\nx = level_3\n\n[test_3]\nsubsuite =')
|
||||
|
||||
def test_server_root(self):
|
||||
"""
|
||||
Test server_root properly expands as an absolute path
|
||||
"""
|
||||
server_example = os.path.join(here, 'parent', 'level_1', 'level_2',
|
||||
'level_3', 'level_3_server-root.ini')
|
||||
parser = ManifestParser(manifests=(server_example,))
|
||||
|
||||
# A regular variable will inherit its value directly
|
||||
self.assertEqual(parser.get('name', **{'other-root': '../root'}),
|
||||
['test_3'])
|
||||
|
||||
# server-root will expand its value as an absolute path
|
||||
# we will not find anything for the original value
|
||||
self.assertEqual(parser.get('name', **{'server-root': '../root'}), [])
|
||||
|
||||
# check that the path has expanded
|
||||
self.assertEqual(parser.get('server-root')[0],
|
||||
os.path.join(here, 'parent', 'root'))
|
||||
|
||||
def test_copy(self):
|
||||
"""Test our ability to copy a set of manifests"""
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user