Bug 1063437 - Use SourcePath smart type for sandbox includes. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 02 Oct 2014 09:14:08 +0900
changeset 231505 8e70d430c86a6d9653756e8c1090f610bf2dc17f
parent 231504 729b1324a3ce5938856a8bcf79026067ee2bd5fd
child 231506 3f9e0be6d08f51e87aa4b0aacf9022bf844f6128
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1063437 - Use SourcePath smart type for sandbox includes. r=gps
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -334,16 +334,26 @@ class SourcePath(ContextDerivedValue, Us
         objdir (aka pseudo-rework), this is needed.
         if self.value.startswith('/'):
             ret = mozpath.join(self.context.config.topobjdir, self.value[1:])
             ret = mozpath.join(self.context.objdir, self.value)
         return mozpath.normpath(ret)
+    def join(self, *p):
+        """Lazy mozpath.join(self, *p), returning a new SourcePath instance.
+        In an ideal world, this wouldn't be required, but with the
+        external_source_dir business, and the fact that comm-central and
+        mozilla-central have directories in common, resolving a SourcePath
+        before doing mozpath.join doesn't work out properly.
+        """
+        return SourcePath(self.context, mozpath.join(self.value, *p))
 def ContextDerivedTypedList(type, base_class=List):
     """Specialized TypedList for use with ContextDerivedValue types.
     assert issubclass(type, ContextDerivedValue)
     class _TypedList(ContextDerivedValue, TypedList(type, base_class)):
         def __init__(self, context, iterable=[]):
@@ -1152,17 +1162,17 @@ for name in TEMPLATE_VARIABLES:
 # Each entry is a tuple of:
 #  (function returning the corresponding function from a given sandbox,
 #   (argument types), docs)
 # The first element is an attribute on Sandbox that should be a function type.
-    'include': (lambda self: self._include, (str,),
+    'include': (lambda self: self._include, (SourcePath,),
         """Include another mozbuild file in the context of this one.
         This is similar to a ``#include`` in C languages. The filename passed to
         the function will be read and its contents will be evaluated within the
         context of the calling file.
         If a relative path is given, it is evaluated as relative to the file
         currently being processed. If there is a chain of multiple include(),
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -273,18 +273,18 @@ class MozbuildSandbox(Sandbox):
         if 'exports' in self.metadata:
             for key in self.metadata['exports']:
                 self.metadata['exports'][key] = self[key]
     def _include(self, path):
         """Include and exec another file within the context of this one."""
-        # exec_file() handles normalization and verification of the path.
-        self.exec_file(path)
+        # path is a SourcePath, and needs to be coerced to unicode.
+        self.exec_file(unicode(path), filesystem_absolute=True)
     def _warning(self, message):
         # FUTURE consider capturing warnings in a variable instead of printing.
         print('WARNING: %s' % message, file=sys.stderr)
     def _error(self, message):
         raise SandboxCalledError(self._context.source_stack, message)
@@ -973,17 +973,17 @@ class BuildReader(object):
                 if 'templates' in sandbox.metadata:
                     recurse_info[d]['templates'] = dict(
                 if 'exports' in sandbox.metadata:
                     recurse_info[d]['exports'] = dict(sandbox.metadata['exports'])
         for path, child_metadata in recurse_info.items():
-            child_path = mozpath.join(path, 'moz.build')
+            child_path = path.join('moz.build')
             # Ensure we don't break out of the topsrcdir. We don't do realpath
             # because it isn't necessary. If there are symlinks in the srcdir,
             # that's not our problem. We're not a hosted application: we don't
             # need to worry about security too much.
             if not is_read_allowed(child_path, context.config):
                 raise SandboxValidationError(
                     'Attempting to process file outside of allowed paths: %s' %
--- a/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
@@ -228,17 +228,18 @@ class TestMozbuildSandbox(unittest.TestC
         self.assertEqual(len(sandbox._context.all_paths), 2)
     def test_include_outside_topsrcdir(self):
         sandbox = self.sandbox(data_path='include-outside-topsrcdir')
         with self.assertRaises(SandboxLoadError) as se:
-        self.assertEqual(se.exception.illegal_path, '../moz.build')
+        self.assertEqual(se.exception.illegal_path,
+            sandbox.normalize_path('../moz.build'))
     def test_include_error_stack(self):
         # Ensure the path stack is reported properly in exceptions.
         sandbox = self.sandbox(data_path='include-file-stack')
         with self.assertRaises(SandboxExecutionError) as se: