Bug 1264831 - Work around issues with the exec statement in older python 2.7 versions. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 15 Apr 2016 10:41:52 +0900
changeset 331237 6b915bf8df2a3cbf7810d05d910c74372eb2df19
parent 331236 cc9627a61ab171c0dc58e080a6f004f26107ad0f
child 331238 dc27fd8f2c4e88c87771bc3654cf113bc21c9b9e
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1264831
milestone48.0a1
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 1264831 - Work around issues with the exec statement in older python 2.7 versions. r=gps
python/mozbuild/mozbuild/configure/__init__.py
python/mozbuild/mozbuild/frontend/sandbox.py
python/mozbuild/mozbuild/util.py
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -23,20 +23,22 @@ from mozbuild.configure.options import (
     PositiveOptionValue,
 )
 from mozbuild.configure.help import HelpFormatter
 from mozbuild.configure.util import (
     ConfigureOutputHandler,
     LineIO,
 )
 from mozbuild.util import (
+    exec_,
     memoize,
     ReadOnlyDict,
     ReadOnlyNamespace,
 )
+
 import mozpack.path as mozpath
 
 
 class ConfigureError(Exception):
     pass
 
 
 class DependsFunction(object):
@@ -195,17 +197,17 @@ class ConfigureSandbox(dict):
                 'Cannot include `%s` because it was included already.' % path)
         self._paths.append(path)
         self._all_paths.add(path)
 
         source = open(path, 'rb').read()
 
         code = compile(source, path, 'exec')
 
-        exec(code, self)
+        exec_(code, self)
 
         self._paths.pop(-1)
 
     def run(self, path=None):
         '''Executes the given file within the sandbox, as well as everything
         pending from any other included file, and ensure the overall
         consistency of the executed script(s).'''
         if path:
@@ -565,20 +567,17 @@ class ConfigureSandbox(dict):
             # Until this proves to be a performance problem, just construct an
             # import statement and execute it.
             import_line = ''
             if _from:
                 import_line += 'from %s ' % _from
             import_line += 'import %s' % _import
             if _as:
                 import_line += ' as %s' % _as
-            # Some versions of python fail with "SyntaxError: unqualified exec
-            # is not allowed in function '_apply_imports' it contains a nested
-            # function with free variable" when using the exec function.
-            exec import_line in {}, glob
+            exec_(import_line, {}, glob)
 
     def _resolve_and_set(self, data, name, value):
         # Don't set anything when --help was on the command line
         if self._help:
             return
         name = self._resolve(name, need_help_dependency=False)
         if name is None:
             return
--- a/python/mozbuild/mozbuild/frontend/sandbox.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox.py
@@ -18,17 +18,20 @@ user-friendly error messages in the case
 """
 
 from __future__ import absolute_import, unicode_literals
 
 import os
 import sys
 import weakref
 
-from mozbuild.util import ReadOnlyDict
+from mozbuild.util import (
+    exec_,
+    ReadOnlyDict,
+)
 from .context import Context
 from mozpack.files import FileFinder
 
 
 default_finder = FileFinder('/', find_executables=False)
 
 
 def alphabetical_sorted(iterable, cmp=None, key=lambda x: x.lower(),
@@ -169,21 +172,17 @@ class Sandbox(dict):
             # do want Unicode literals.
             code = compile(source, path, 'exec')
             # We use ourself as the global namespace for the execution. There
             # is no need for a separate local namespace as moz.build execution
             # is flat, namespace-wise.
             old_source = self._current_source
             self._current_source = source
             try:
-                # Ideally, we'd use exec(code, self), but that yield the
-                # following error:
-                # SyntaxError: unqualified exec is not allowed in function
-                # 'execute' it is a nested function.
-                exec code in self
+                exec_(code, self)
             finally:
                 self._current_source = old_source
 
         self.exec_function(execute, path=path)
 
     def exec_function(self, func, args=(), kwargs={}, path='',
                       becomes_current_path=True):
         """Execute function with the given arguments in the sandbox.
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -1,16 +1,16 @@
 # 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/.
 
 # This file contains miscellaneous utility functions that don't belong anywhere
 # in particular.
 
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, unicode_literals, print_function
 
 import argparse
 import collections
 import ctypes
 import difflib
 import errno
 import functools
 import hashlib
@@ -37,16 +37,32 @@ if sys.version_info[0] == 3:
 else:
     str_type = basestring
 
 if sys.platform == 'win32':
     _kernel32 = ctypes.windll.kernel32
     _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
 
 
+def exec_(object, globals=None, locals=None):
+    """Wrapper around the exec statement to avoid bogus errors like:
+
+    SyntaxError: unqualified exec is not allowed in function ...
+    it is a nested function.
+
+    or
+
+    SyntaxError: unqualified exec is not allowed in function ...
+    it contains a nested function with free variable
+
+    which happen with older versions of python 2.7.
+    """
+    exec(object, globals, locals)
+
+
 def hash_file(path, hasher=None):
     """Hashes a file specified by the path given and returns the hex digest."""
 
     # If the default hashing function changes, this may invalidate
     # lots of cached data.  Don't change it lightly.
     h = hasher or hashlib.sha1()
 
     with open(path, 'rb') as fh: