Bug 1132771 - Optionally don't export variables when reading moz.build files draft
authorGregory Szorc <gps@mozilla.com>
Thu, 12 Feb 2015 18:58:37 -0800
changeset 243052 473f3239c79f42de5eba1b4b8e34ca29d7e1a8de
parent 243051 cd9997e4f538b5882e65beb19d3418584136df3a
child 243053 cfe32922599a48121ec58255f51db351a6de1f80
push id698
push usergszorc@mozilla.com
push dateMon, 16 Feb 2015 20:34:37 +0000
bugs1132771
milestone38.0a1
Bug 1132771 - Optionally don't export variables when reading moz.build files Exporting the same variable twice in a stack of traversals results in an error. Since we don't need exported variables when in manual moz.build traversal mode, add an option to disable it and disable it in our manual traversal mode.
python/mozbuild/mozbuild/frontend/reader.py
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -870,17 +870,18 @@ class BuildReader(object):
 
             tree = ast.parse(source, full)
             Visitor().visit(tree)
 
             for name, key, value in assignments:
                 yield p, name, key, value
 
     def read_mozbuild(self, path, config, read_tiers=False, descend=True,
-                      read_gyp=True, explicit_dirs=None, metadata={}):
+                      read_gyp=True, explicit_dirs=None, process_exports=True,
+                      metadata={}):
         """Read and process a mozbuild file, descending into children.
 
         This starts with a single mozbuild file, executes it, and descends into
         other referenced files per our traversal logic.
 
         The traversal logic is to iterate over the *DIRS variables, treating
         each element as a relative directory path. For each encountered
         directory, we will open the moz.build file located in that
@@ -900,28 +901,32 @@ class BuildReader(object):
         sequence. The default behavior is for *DIRS variables in evaluated
         moz.build to control what gets executed next. When this argument is
         defined as a dictionary, keys in the dictionary corresponding to the
         path of the evaluated moz.build file and values are an iterable of
         directories to evaluate next. Keys should be absolute paths. Values
         are relative from the key paths. This effectively replaces DIRS
         values after sandbox execution.
 
+        process_exports controls whether export functions in moz.build files
+        should be honored during traversal. It is enabled by default.
+
         Arbitrary metadata in the form of a dict can be passed into this
         function. This feature is intended to facilitate the build reader
         injecting state and annotations into moz.build files that is
         independent of the sandbox's execution context.
 
         Traversal is performed depth first (for no particular reason).
         """
         self._execution_stack.append(path)
         try:
             for s in self._read_mozbuild(path, config, read_tiers=read_tiers,
                 descend=descend, read_gyp=read_gyp,
-                explicit_dirs=explicit_dirs, metadata=metadata):
+                explicit_dirs=explicit_dirs, process_exports=process_exports,
+                metadata=metadata):
                 yield s
 
         except BuildReaderError as bre:
             raise bre
 
         except SandboxCalledError as sce:
             raise BuildReaderError(list(self._execution_stack),
                 sys.exc_info()[2], sandbox_called_error=sce)
@@ -938,17 +943,17 @@ class BuildReader(object):
             raise BuildReaderError(list(self._execution_stack),
                 sys.exc_info()[2], validation_error=ve)
 
         except Exception as e:
             raise BuildReaderError(list(self._execution_stack),
                 sys.exc_info()[2], other_error=e)
 
     def _read_mozbuild(self, path, config, read_tiers, descend, read_gyp,
-                       explicit_dirs, metadata):
+                       explicit_dirs, process_exports, metadata):
         path = mozpath.normpath(path)
         log(self._log, logging.DEBUG, 'read_mozbuild', {'path': path},
             'Reading file: {path}')
 
         if path in self._read_files:
             log(self._log, logging.WARNING, 'read_already', {'path': path},
                 'File already read. Skipping: {path}')
             return
@@ -1053,17 +1058,17 @@ class BuildReader(object):
                     raise SandboxValidationError(
                         'Directory (%s) registered multiple times in %s' % (
                             mozpath.relpath(d, context.srcdir), var), context)
 
                 recurse_info[d] = {}
                 if 'templates' in sandbox.metadata:
                     recurse_info[d]['templates'] = dict(
                         sandbox.metadata['templates'])
-                if 'exports' in sandbox.metadata:
+                if process_exports and 'exports' in sandbox.metadata:
                     sandbox.recompute_exports()
                     recurse_info[d]['exports'] = dict(sandbox.metadata['exports'])
 
         for path, child_metadata in recurse_info.items():
             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,
@@ -1074,17 +1079,17 @@ class BuildReader(object):
                     'Attempting to process file outside of allowed paths: %s' %
                         child_path, context)
 
             if not descend:
                 continue
 
             for res in self.read_mozbuild(child_path, context.config,
                 read_tiers=False, read_gyp=read_gyp,
-                explicit_dirs=explicit_dirs,
+                explicit_dirs=explicit_dirs, process_exports=process_exports,
                 metadata=child_metadata):
                 yield res
 
         self._execution_stack.pop()
 
     def _find_relevant_mozbuilds(self, paths):
         """Given a set of filesystem paths, find all relevant moz.build files.
 
@@ -1173,17 +1178,18 @@ class BuildReader(object):
                 d = mozpath.normpath(mozpath.join(topsrcdir, mbpath))
                 t = dirs.setdefault(d, set())
                 t.add(mozpath.relpath(target_dir, source_dir))
 
         contexts = {}
         all_contexts = []
         for context in self.read_mozbuild(mozpath.join(topsrcdir, 'moz.build'),
                                           self.config, read_tiers=False,
-                                          read_gyp=False, explicit_dirs=dirs):
+                                          read_gyp=False, explicit_dirs=dirs,
+                                          process_exports=False):
             contexts[context.main_path] = context
             all_contexts.append(context)
 
         result = {}
         for path, paths in path_mozbuilds.items():
             result[path] = [contexts[p] for p in paths]
 
         return result, all_contexts