Bug 924977 - More proper current working directory handling in mach; r=ahal
authorGregory Szorc <gps@mozilla.com>
Fri, 11 Oct 2013 12:44:15 -0700
changeset 165305 c1c61b305ce0b58450ec0092457f98cd7119d4ee
parent 165304 348066ccaa45ae741f6b6268ed9a86c9e6418b62
child 165306 b784c6dafa7da581970d474fe8f35685a140c5a1
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahal
bugs924977
milestone27.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 924977 - More proper current working directory handling in mach; r=ahal
build/mach_bootstrap.py
mach
python/mach/mach/base.py
python/mach/mach/main.py
python/mozbuild/mozbuild/base.py
python/mozbuild/mozbuild/mach_commands.py
python/mozbuild/mozbuild/test/test_base.py
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -167,18 +167,19 @@ def bootstrap(topsrcdir, mozilla_dir=Non
     try:
         import mach.main
     except ImportError:
         sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS]
         import mach.main
 
     def populate_context(context):
         context.state_dir = state_dir
+        context.topdir = topsrcdir
 
-    mach = mach.main.Mach(topsrcdir)
+    mach = mach.main.Mach(os.getcwd())
     mach.populate_context_handler = populate_context
 
     for category, meta in CATEGORIES.items():
         mach.define_category(category, meta['short'], meta['long'],
             meta['priority'])
 
     for path in MACH_MODULES:
         mach.load_commands_from_file(os.path.join(mozilla_dir, path))
--- a/mach
+++ b/mach
@@ -15,36 +15,41 @@ def ancestors(path):
         if child == "":
             break
 
 def load_mach(topsrcdir):
     sys.path[0:0] = [os.path.join(topsrcdir, "build")]
     import mach_bootstrap
     return mach_bootstrap.bootstrap(topsrcdir)
 
-# Check whether the current directory is within a mach src or obj dir.
-for dir_path in ancestors(os.getcwd()):
-    # If we find a "mozinfo.json" file, we are in the objdir.
-    mozinfo_path = os.path.join(dir_path, "mozinfo.json")
-    if os.path.isfile(mozinfo_path):
-        import json
-        info = json.load(open(mozinfo_path))
-        if "mozconfig" in info and "MOZCONFIG" not in os.environ:
-            # If the MOZCONFIG environment variable is not already set, set it
-            # to the value from mozinfo.json.  This will tell the build system
-            # to look for a config file at the path in $MOZCONFIG rather than
-            # its default locations.
-            #
-            # Note: subprocess requires native strings in os.environ on Windows
-            os.environ[b"MOZCONFIG"] = str(info["mozconfig"])
+def main(args):
+    # Check whether the current directory is within a mach src or obj dir.
+    for dir_path in ancestors(os.getcwd()):
+        # If we find a "mozinfo.json" file, we are in the objdir.
+        mozinfo_path = os.path.join(dir_path, 'mozinfo.json')
+        if os.path.isfile(mozinfo_path):
+            import json
+            info = json.load(open(mozinfo_path))
+            if 'mozconfig' in info and 'MOZCONFIG' not in os.environ:
+                # If the MOZCONFIG environment variable is not already set, set it
+                # to the value from mozinfo.json.  This will tell the build system
+                # to look for a config file at the path in $MOZCONFIG rather than
+                # its default locations.
+                #
+                # Note: subprocess requires native strings in os.environ on Windows
+                os.environ[b'MOZCONFIG'] = str(info['mozconfig'])
 
-        if "topsrcdir" in info:
-            # Continue searching for mach_bootstrap in the source directory.
-            dir_path = info["topsrcdir"]
+            if 'topsrcdir' in info:
+                # Continue searching for mach_bootstrap in the source directory.
+                dir_path = info['topsrcdir']
 
-    # If we find the mach bootstrap module, we are in the srcdir.
-    mach_path = os.path.join(dir_path, "build/mach_bootstrap.py")
-    if os.path.isfile(mach_path):
-        mach = load_mach(dir_path)
-        sys.exit(mach.run(sys.argv[1:]))
+        # If we find the mach bootstrap module, we are in the srcdir.
+        mach_path = os.path.join(dir_path, 'build/mach_bootstrap.py')
+        if os.path.isfile(mach_path):
+            mach = load_mach(dir_path)
+            sys.exit(mach.run(args[1:]))
 
-print("Could not run mach: No mach source directory found")
-sys.exit(1)
+    print('Could not run mach: No mach source directory found.')
+    sys.exit(1)
+
+
+if __name__ == '__main__':
+    main(sys.argv)
--- a/python/mach/mach/base.py
+++ b/python/mach/mach/base.py
@@ -2,19 +2,18 @@
 # 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/.
 
 from __future__ import unicode_literals
 
 
 class CommandContext(object):
     """Holds run-time state so it can easily be passed to command providers."""
-    def __init__(self, topdir=None, cwd=None, settings=None, log_manager=None,
+    def __init__(self, cwd=None, settings=None, log_manager=None,
         commands=None):
-        self.topdir = topdir
         self.cwd = cwd
         self.settings = settings
         self.log_manager = log_manager
         self.commands = commands
 
 
 class MachError(Exception):
     """Base class for all errors raised by mach itself."""
--- a/python/mach/mach/main.py
+++ b/python/mach/mach/main.py
@@ -284,17 +284,17 @@ To see more help for a specific command,
             return 1
 
         finally:
             sys.stdin = orig_stdin
             sys.stdout = orig_stdout
             sys.stderr = orig_stderr
 
     def _run(self, argv):
-        context = CommandContext(topdir=self.cwd, cwd=self.cwd,
+        context = CommandContext(cwd=self.cwd,
             settings=self.settings, log_manager=self.log_manager,
             commands=Registrar)
 
         if self.populate_context_handler:
             self.populate_context_handler(context)
 
         parser = self.get_argument_parser(context)
 
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -167,21 +167,23 @@ class MozbuildObject(ProcessExecutionMix
         config_topobjdir = MozbuildObject.resolve_mozconfig_topobjdir(
             topsrcdir, config)
 
         # If we're inside a objdir and the found mozconfig resolves to
         # another objdir, we abort. The reasoning here is that if you are
         # inside an objdir you probably want to perform actions on that objdir,
         # not another one. This prevents accidental usage of the wrong objdir
         # when the current objdir is ambiguous.
-        if topobjdir and config_topobjdir \
-            and not samepath(topobjdir, config_topobjdir) \
-            and not samepath(topobjdir, os.path.join(config_topobjdir, "mozilla")):
+        if topobjdir and config_topobjdir:
+            mozilla_dir = os.path.join(config_topobjdir, 'mozilla')
+            if not samepath(topobjdir, config_topobjdir) \
+                and (os.path.exists(mozilla_dir) and not samepath(topobjdir,
+                mozilla_dir)):
 
-            raise ObjdirMismatchException(topobjdir, config_topobjdir)
+                raise ObjdirMismatchException(topobjdir, config_topobjdir)
 
         topobjdir = topobjdir or config_topobjdir
         if topobjdir:
             topobjdir = os.path.normpath(topobjdir)
 
         # If we can't resolve topobjdir, oh well. The constructor will figure
         # it out via config.guess.
         return cls(topsrcdir, None, None, topobjdir=topobjdir)
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -18,16 +18,17 @@ from mach.decorators import (
 
 from mach.mixin.logging import LoggingMixin
 
 from mozbuild.base import (
     MachCommandBase,
     MozbuildObject,
     MozconfigFindException,
     MozconfigLoadException,
+    ObjdirMismatchException,
 )
 
 
 BUILD_WHAT_HELP = '''
 What to build. Can be a top-level make target or a relative directory. If
 multiple options are provided, they will be built serially. Takes dependency
 information from `topsrcdir/build/dumbmake-dependencies` to build additional
 targets as needed. BUILDING ONLY PARTS OF THE TREE CAN RESULT IN BAD TREE
@@ -829,36 +830,42 @@ class Makefiles(MachCommandBase):
 
     def _makefile_ins(self):
         for root, dirs, files in os.walk(self.topsrcdir):
             for f in files:
                 if f == 'Makefile.in':
                     yield os.path.join(root, f)
 
 @CommandProvider
-class MachDebug(object):
-    def __init__(self, context):
-        self.context = context
-
+class MachDebug(MachCommandBase):
     @Command('environment', category='build-dev',
         description='Show info about the mach and build environment.')
     @CommandArgument('--verbose', '-v', action='store_true',
         help='Print verbose output.')
     def environment(self, verbose=False):
         import platform
         print('platform:\n\t%s' % platform.platform())
         print('python version:\n\t%s' % sys.version)
         print('python prefix:\n\t%s' % sys.prefix)
-        print('mach cwd:\n\t%s' % self.context.cwd)
+        print('mach cwd:\n\t%s' % self._mach_context.cwd)
         print('os cwd:\n\t%s' % os.getcwd())
-        print('mach directory:\n\t%s' % self.context.topdir)
-        print('state directory:\n\t%s' % self.context.state_dir)
+        print('mach directory:\n\t%s' % self._mach_context.topdir)
+        print('state directory:\n\t%s' % self._mach_context.state_dir)
 
-        mb = MozbuildObject(self.context.topdir, self.context.settings,
-            self.context.log_manager)
+        try:
+            mb = MozbuildObject.from_environment(cwd=self._mach_context.cwd)
+        except ObjdirMismatchException as e:
+            print('Ambiguous object directory detected. We detected that '
+                'both %s and %s could be object directories. This is '
+                'typically caused by having a mozconfig pointing to a '
+                'different object directory from the current working '
+                'directory. To solve this problem, ensure you do not have a '
+                'default mozconfig in searched paths.' % (e.objdir1,
+                    e.objdir2))
+            return 1
 
         mozconfig = None
 
         try:
             mozconfig = mb.mozconfig
             print('mozconfig path:\n\t%s' % mozconfig['path'])
         except MozconfigFindException as e:
             print('Unable to find mozconfig: %s' % e.message)
--- a/python/mozbuild/mozbuild/test/test_base.py
+++ b/python/mozbuild/mozbuild/test/test_base.py
@@ -195,17 +195,17 @@ class TestMozbuildObject(unittest.TestCa
 
             os.chdir(topobjdir)
 
             class MockMachContext(object):
                 pass
 
             context = MockMachContext()
             context.cwd = topobjdir
-            context.topdir = topobjdir
+            context.topdir = topsrcdir
             context.settings = None
             context.log_manager = None
 
             o = MachCommandBase(context)
 
             self.assertEqual(o.topobjdir, topobjdir)
             self.assertEqual(o.topsrcdir, topsrcdir)