Bug 1298210 - Move remove objdir code into clobber.py so that autoclobber and clobber command share the same code. r?gps draft
authorXidorn Quan <xidorn+moz@upsuper.org>
Mon, 29 Aug 2016 10:02:42 +1000
changeset 406562 ac44ec85b5f01849311f65c58548dc61bf2bc390
parent 406560 26c6e9994ce2f7421fd537c3f8cb1bcb7bcf1635
child 529687 0d09421ea4067b6e83e0f40b7bb6618b59479597
push id27760
push userxquan@mozilla.com
push dateMon, 29 Aug 2016 00:04:53 +0000
reviewersgps
bugs1298210
milestone51.0a1
Bug 1298210 - Move remove objdir code into clobber.py so that autoclobber and clobber command share the same code. r?gps MozReview-Commit-ID: 5X1AQac8Fqi
python/mozbuild/mozbuild/base.py
python/mozbuild/mozbuild/controller/clobber.py
python/mozbuild/mozbuild/mach_commands.py
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -1,29 +1,26 @@
 # 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/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
-import errno
 import json
 import logging
 import mozpack.path as mozpath
 import multiprocessing
 import os
 import subprocess
 import sys
 import which
 
 from mach.mixin.logging import LoggingMixin
 from mach.mixin.process import ProcessExecutionMixin
 
-from mozfile.mozfile import remove as mozfileremove
-
 from .backend.configenvironment import ConfigEnvironment
 from .controller.clobber import Clobberer
 from .mozconfig import (
     MozconfigFindException,
     MozconfigLoadException,
     MozconfigLoader,
 )
 from .util import memoized_property
@@ -284,65 +281,16 @@ class MozbuildObject(ProcessExecutionMix
                             env[key] = value
         return env
 
     def is_clobber_needed(self):
         if not os.path.exists(self.topobjdir):
             return False
         return Clobberer(self.topsrcdir, self.topobjdir).clobber_needed()
 
-    def have_winrm(self):
-        # `winrm -h` should print 'winrm version ...' and exit 1
-        try:
-            p = subprocess.Popen(['winrm.exe', '-h'],
-                                 stdout=subprocess.PIPE,
-                                 stderr=subprocess.STDOUT)
-            return p.wait() == 1 and p.stdout.read().startswith('winrm')
-        except:
-            return False
-
-    def remove_objdir(self, full=True):
-        """Remove the object directory.
-
-        ``full`` controls whether to fully delete the objdir. If False,
-        some directories (e.g. Visual Studio Project Files) will not be
-        deleted.
-        """
-        # Top-level files and directories to not clobber by default.
-        no_clobber = {
-            '.mozbuild',
-            'msvc',
-        }
-
-        if full:
-            # mozfile doesn't like unicode arguments (bug 818783).
-            paths = [self.topobjdir.encode('utf-8')]
-        else:
-            try:
-                paths = []
-                for p in os.listdir(self.topobjdir):
-                    if p not in no_clobber:
-                        paths.append(os.path.join(self.topobjdir, p).encode('utf-8'))
-            except OSError as e:
-                if e.errno != errno.ENOENT:
-                    raise
-                return
-
-        procs = []
-        for p in sorted(paths):
-            path = os.path.join(self.topobjdir, p)
-            if sys.platform.startswith('win') and self.have_winrm() and os.path.isdir(path):
-                procs.append(subprocess.Popen(['winrm', '-rf', path]))
-            else:
-                # We use mozfile because it is faster than shutil.rmtree().
-                mozfileremove(path)
-
-        for p in procs:
-            p.wait()
-
     def get_binary_path(self, what='app', validate_exists=True, where='default'):
         """Obtain the path to a compiled binary for this build configuration.
 
         The what argument is the program or tool being sought after. See the
         code implementation for supported values.
 
         If validate_exists is True (the default), we will ensure the found path
         exists before returning, raising an exception if it doesn't.
--- a/python/mozbuild/mozbuild/controller/clobber.py
+++ b/python/mozbuild/mozbuild/controller/clobber.py
@@ -1,20 +1,22 @@
 # 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/.
 
 from __future__ import absolute_import, print_function
 
 r'''This module contains code for managing clobbering of the tree.'''
 
+import errno
 import os
+import subprocess
 import sys
 
-from mozfile.mozfile import rmtree
+from mozfile.mozfile import remove as mozfileremove
 from textwrap import TextWrapper
 
 
 CLOBBER_MESSAGE = ''.join([TextWrapper().fill(line) + '\n' for line in
 '''
 The CLOBBER file has been updated, indicating that an incremental build since \
 your last build will probably not work. A full/clobber build is required.
 
@@ -80,16 +82,65 @@ class Clobberer(object):
 
         This returns a list of lines describing why the clobber was required.
         Each line is stripped of leading and trailing whitespace.
         """
         with open(self.src_clobber, 'rt') as fh:
             lines = [l.strip() for l in fh.readlines()]
             return [l for l in lines if l and not l.startswith('#')]
 
+    def have_winrm(self):
+        # `winrm -h` should print 'winrm version ...' and exit 1
+        try:
+            p = subprocess.Popen(['winrm.exe', '-h'],
+                                 stdout=subprocess.PIPE,
+                                 stderr=subprocess.STDOUT)
+            return p.wait() == 1 and p.stdout.read().startswith('winrm')
+        except:
+            return False
+
+    def remove_objdir(self, full=True):
+        """Remove the object directory.
+
+        ``full`` controls whether to fully delete the objdir. If False,
+        some directories (e.g. Visual Studio Project Files) will not be
+        deleted.
+        """
+        # Top-level files and directories to not clobber by default.
+        no_clobber = {
+            '.mozbuild',
+            'msvc',
+        }
+
+        if full:
+            # mozfile doesn't like unicode arguments (bug 818783).
+            paths = [self.topobjdir.encode('utf-8')]
+        else:
+            try:
+                paths = []
+                for p in os.listdir(self.topobjdir):
+                    if p not in no_clobber:
+                        paths.append(os.path.join(self.topobjdir, p).encode('utf-8'))
+            except OSError as e:
+                if e.errno != errno.ENOENT:
+                    raise
+                return
+
+        procs = []
+        for p in sorted(paths):
+            path = os.path.join(self.topobjdir, p)
+            if sys.platform.startswith('win') and self.have_winrm() and os.path.isdir(path):
+                procs.append(subprocess.Popen(['winrm', '-rf', path]))
+            else:
+                # We use mozfile because it is faster than shutil.rmtree().
+                mozfileremove(path)
+
+        for p in procs:
+            p.wait()
+
     def ensure_objdir_state(self):
         """Ensure the CLOBBER file in the objdir exists.
 
         This is called as part of the build to ensure the clobber information
         is configured properly for the objdir.
         """
         if not os.path.exists(self.topobjdir):
             os.makedirs(self.topobjdir)
@@ -135,28 +186,17 @@ class Clobberer(object):
                               'mozconfig).')
 
         if cwd.startswith(self.topobjdir) and cwd != self.topobjdir:
             return True, False, self._message(
                 'Cannot clobber while the shell is inside the object directory.')
 
         print('Automatically clobbering %s' % self.topobjdir, file=fh)
         try:
-            if cwd == self.topobjdir:
-                for entry in os.listdir(self.topobjdir):
-                    full = os.path.join(self.topobjdir, entry)
-
-                    if os.path.isdir(full):
-                        rmtree(full)
-                    else:
-                        os.unlink(full)
-
-            else:
-                rmtree(self.topobjdir)
-
+            self.remove_objdir(False)
             self.ensure_objdir_state()
             print('Successfully completed auto clobber.', file=fh)
             return True, True, None
         except (IOError) as error:
             return True, False, self._message(
                 'Error when automatically clobbering: ' + str(error))
 
     def _message(self, reason):
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -30,16 +30,17 @@ from mozbuild.base import (
     BuildEnvironmentNotFoundException,
     MachCommandBase,
     MachCommandConditions as conditions,
     MozbuildObject,
     MozconfigFindException,
     MozconfigLoadException,
     ObjdirMismatchException,
 )
+from mozbuild.controller.clobber import Clobberer
 
 from mozpack.manifests import (
     InstallManifest,
 )
 
 from mozbuild.backend import backends
 from mozbuild.shellutil import quote as shell_quote
 
@@ -637,17 +638,17 @@ class Clobber(MachCommandBase):
         invalid = set(what) - set(self.CLOBBER_CHOICES)
         if invalid:
             print('Unknown clobber target(s): {}'.format(', '.join(invalid)))
             return 1
 
         ret = 0
         if 'objdir' in what:
             try:
-                self.remove_objdir(full=full)
+                Clobberer(self.topsrcdir, self.topobjdir).remove_objdir(full)
             except OSError as e:
                 if sys.platform.startswith('win'):
                     if isinstance(e, WindowsError) and e.winerror in (5,32):
                         self.log(logging.ERROR, 'file_access_error', {'error': e},
                             "Could not clobber because a file was in use. If the "
                             "application is running, try closing it. {error}")
                         return 1
                 raise