Bug 1312520 - Add an option to the manifestparser to prevent defaults from propagating to individual section definitions. r=ahal
Consumers will be expected to process defaults themselves through the
"manifest_defaults" member variable instead.
MozReview-Commit-ID: IGnOj3zEJfE
--- a/testing/mozbase/manifestparser/manifestparser/ini.py
+++ b/testing/mozbase/manifestparser/manifestparser/ini.py
@@ -3,27 +3,28 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.
import os
__all__ = ['read_ini']
def read_ini(fp, variables=None, default='DEFAULT', defaults_only=False,
- comments=';#', separators=('=', ':'),
- strict=True):
+ comments=';#', separators=('=', ':'), strict=True,
+ handle_defaults=True):
"""
read an .ini file and return a list of [(section, values)]
- fp : file pointer or path to read
- variables : default set of variables
- default : name of the section for the default section
- defaults_only : if True, return the default section only
- comments : characters that if they start a line denote a comment
- separators : strings that denote key, value separation in order
- strict : whether to be strict about parsing
+ - handle_defaults : whether to incorporate defaults into each section
"""
# variables
variables = variables or {}
sections = []
key = value = None
section_names = set()
if isinstance(fp, basestring):
@@ -106,18 +107,22 @@ def read_ini(fp, variables=None, default
root = os.path.join(os.path.dirname(fp.name),
variables['server-root'])
variables['server-root'] = os.path.abspath(root)
# return the default section only if requested
if defaults_only:
return [(default, variables)]
- # interpret the variables
+ # Interpret the variables in the context of inherited defaults if
+ # requested.
def interpret_variables(global_dict, local_dict):
+ if not handle_defaults:
+ return local_dict
+
variables = global_dict.copy()
# These variables are combinable when they appear both in default
# and per-entry.
for field_name, pattern in (('skip-if', '(%s) || (%s)'),
('support-files', '%s %s')):
local_value, global_value = local_dict.get(field_name), variables.get(field_name)
if local_value and global_value:
--- a/testing/mozbase/manifestparser/manifestparser/manifestparser.py
+++ b/testing/mozbase/manifestparser/manifestparser/manifestparser.py
@@ -41,17 +41,17 @@ def denormalize_path(path):
# objects for parsing manifests
class ManifestParser(object):
"""read .ini manifests"""
def __init__(self, manifests=(), defaults=None, strict=True, rootdir=None,
- finder=None):
+ finder=None, omit_defaults=False):
"""Creates a ManifestParser from the given manifest files.
:param manifests: An iterable of file paths or file objects corresponding
to manifests. If a file path refers to a manifest file that
does not exist, an IOError is raised.
:param defaults: Variables to pre-define in the environment for evaluating
expressions in manifests.
:param strict: If False, the provided manifests may contain references to
@@ -61,25 +61,30 @@ class ManifestParser(object):
section names, redefining variables, and defining empty
variables.
:param rootdir: The directory used as the basis for conversion to and from
relative paths during manifest reading.
:param finder: If provided, this finder object will be used for filesystem
interactions. Finder objects are part of the mozpack package,
documented at
http://gecko.readthedocs.org/en/latest/python/mozpack.html#module-mozpack.files
+ :param omit_defaults: If set, do not propagate manifest defaults to individual
+ test objects. Callers are expected to manage per-manifest
+ defaults themselves via the manifest_defaults member
+ variable in this case.
"""
self._defaults = defaults or {}
self._ancestor_defaults = {}
self.tests = []
self.manifest_defaults = {}
self.strict = strict
self.rootdir = rootdir
self.relativeRoot = None
self.finder = finder
+ self._omit_defaults = omit_defaults
if manifests:
self.read(*manifests)
def path_exists(self, path):
if self.finder:
return self.finder.get(path) is not None
return os.path.exists(path)
@@ -134,17 +139,18 @@ class ManifestParser(object):
# the microoptimization used below.
if self.rootdir is None:
rootdir = ""
else:
assert os.path.isabs(self.rootdir)
rootdir = self.rootdir + os.path.sep
# read the configuration
- sections = read_ini(fp=fp, variables=defaults, strict=self.strict)
+ sections = read_ini(fp=fp, variables=defaults, strict=self.strict,
+ handle_defaults=not self._omit_defaults)
self.manifest_defaults[filename] = defaults
parent_section_found = False
# get the tests
for section, data in sections:
subsuite = ''
if 'subsuite' in data:
--- a/testing/mozbase/manifestparser/tests/default-suppfiles.ini
+++ b/testing/mozbase/manifestparser/tests/default-suppfiles.ini
@@ -1,9 +1,9 @@
[DEFAULT]
support-files = foo.js # a comment
-[test1]
-[test2]
+[test7]
+[test8]
support-files = bar.js # another comment
-[test3]
+[test9]
foo = bar
--- a/testing/mozbase/manifestparser/tests/test_default_overrides.py
+++ b/testing/mozbase/manifestparser/tests/test_default_overrides.py
@@ -37,19 +37,61 @@ class TestDefaultSkipif(unittest.TestCas
class TestDefaultSupportFiles(unittest.TestCase):
"""Tests combining support-files field in [DEFAULT] with the value for a test"""
def test_defaults(self):
default = os.path.join(here, 'default-suppfiles.ini')
parser = ManifestParser(manifests=(default,))
expected_supp_files = {
- 'test1': 'foo.js # a comment',
- 'test2': 'foo.js bar.js ',
- 'test3': 'foo.js # a comment',
+ 'test7': 'foo.js # a comment',
+ 'test8': 'foo.js bar.js ',
+ 'test9': 'foo.js # a comment',
}
for test in parser.tests:
expected = expected_supp_files[test['name']]
self.assertEqual(test['support-files'], expected)
+class TestOmitDefaults(unittest.TestCase):
+ """Tests passing omit-defaults prevents defaults from propagating to definitions.
+ """
+
+ def test_defaults(self):
+ manifests = (os.path.join(here, 'default-suppfiles.ini'),
+ os.path.join(here, 'default-skipif.ini'))
+ parser = ManifestParser(manifests=manifests, omit_defaults=True)
+ expected_supp_files = {
+ 'test8': 'bar.js # another comment',
+ }
+ expected_skip_ifs = {
+ 'test1': "debug",
+ 'test2': "os == 'linux'",
+ 'test3': "os == 'win'",
+ 'test4': "os == 'win' && debug",
+ 'test6': "debug # a second pesky comment",
+ }
+ for test in parser.tests:
+ for field, expectations in (('support-files', expected_supp_files),
+ ('skip-if', expected_skip_ifs)):
+ expected = expectations.get(test['name'])
+ if not expected:
+ self.assertNotIn(field, test)
+ else:
+ self.assertEqual(test[field], expected)
+
+ expected_defaults = {
+ os.path.join(here, 'default-suppfiles.ini'): {
+ "support-files": "foo.js # a comment",
+ },
+ os.path.join(here, 'default-skipif.ini'): {
+ "skip-if": "os == 'win' && debug # a pesky comment",
+ },
+ }
+ for path, defaults in expected_defaults.items():
+ self.assertIn(path, parser.manifest_defaults)
+ actual_defaults = parser.manifest_defaults[path]
+ for key, value in defaults.items():
+ self.assertIn(key, actual_defaults)
+ self.assertEqual(value, actual_defaults[key])
+
if __name__ == '__main__':
unittest.main()