Bug 1126228 - Directory (--directory) argument for |mach warnings-list| and |mach warnings-summary|. r=gps
authorMitchell Field <mitchell.field@live.com.au>
Tue, 27 Jan 2015 21:13:28 +1100
changeset 254649 8e3baacbe31ba2ec3f1b9cf65053ec16a154a8be
parent 254648 3741aa98b8918c7d18116cd42f9f5c82d6e13048
child 254650 ee746a325426739058c9f734e598646683cdc0b0
push id29108
push userryanvm@gmail.com
push dateMon, 27 Jul 2015 14:12:01 +0000
treeherdermozilla-central@27ae736ef960 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1126228
milestone42.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 1126228 - Directory (--directory) argument for |mach warnings-list| and |mach warnings-summary|. r=gps
python/mozbuild/mozbuild/compilation/warnings.py
python/mozbuild/mozbuild/mach_commands.py
--- a/python/mozbuild/mozbuild/compilation/warnings.py
+++ b/python/mozbuild/mozbuild/compilation/warnings.py
@@ -7,16 +7,17 @@
 from __future__ import absolute_import, unicode_literals
 
 import errno
 import json
 import os
 import re
 
 from mozbuild.util import hash_file
+import mozpack.path as mozpath
 
 
 # Regular expression to strip ANSI color sequences from a string. This is
 # needed to properly analyze Clang compiler output, which may be colorized.
 # It assumes ANSI escape sequences.
 RE_STRIP_COLORS = re.compile(r'\x1b\[[\d;]+m')
 
 # This captures Clang diagnostics with the standard formatting.
@@ -142,27 +143,29 @@ class WarningsDatabase(object):
 
     @property
     def warnings(self):
         """All the CompilerWarning instances in this database."""
         for value in self._files.values():
             for w in value['warnings']:
                 yield w
 
-    @property
-    def type_counts(self):
+    def type_counts(self, dirpath=None):
         """Returns a mapping of warning types to their counts."""
 
         types = {}
         for value in self._files.values():
             for warning in value['warnings']:
-                count = types.get(warning['flag'], 0)
+                if dirpath and not mozpath.normsep(warning['filename']).startswith(dirpath):
+                    continue
+                flag = warning['flag']
+                count = types.get(flag, 0)
                 count += 1
 
-                types[warning['flag']] = count
+                types[flag] = count
 
         return types
 
     def has_file(self, filename):
         """Whether we have any warnings for the specified file."""
         return filename in self._files
 
     def warnings_for_file(self, filename):
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -652,56 +652,97 @@ class Warnings(MachCommandBase):
 
         if os.path.exists(path):
             database.load_from_file(path)
 
         return database
 
     @Command('warnings-summary', category='post-build',
         description='Show a summary of compiler warnings.')
+    @CommandArgument('-C', '--directory', default=None,
+        help='Change to a subdirectory of the build directory first.')
     @CommandArgument('report', default=None, nargs='?',
         help='Warnings report to display. If not defined, show the most '
             'recent report.')
-    def summary(self, report=None):
+    def summary(self, directory=None, report=None):
         database = self.database
 
-        type_counts = database.type_counts
+        if directory:
+            dirpath = self.join_ensure_dir(self.topsrcdir, directory)
+            if not dirpath:
+                return 1
+        else:
+            dirpath = None
+
+        type_counts = database.type_counts(dirpath)
         sorted_counts = sorted(type_counts.iteritems(),
             key=operator.itemgetter(1))
 
         total = 0
         for k, v in sorted_counts:
             print('%d\t%s' % (v, k))
             total += v
 
         print('%d\tTotal' % total)
 
     @Command('warnings-list', category='post-build',
         description='Show a list of compiler warnings.')
+    @CommandArgument('-C', '--directory', default=None,
+        help='Change to a subdirectory of the build directory first.')
+    @CommandArgument('--flags', default=None, nargs='+',
+        help='Which warnings flags to match.')
     @CommandArgument('report', default=None, nargs='?',
         help='Warnings report to display. If not defined, show the most '
             'recent report.')
-    def list(self, report=None):
+    def list(self, directory=None, flags=None, report=None):
         database = self.database
 
         by_name = sorted(database.warnings)
 
-        for warning in by_name:
-            filename = warning['filename']
+        topsrcdir = mozpath.normpath(self.topsrcdir)
+
+        if directory:
+            directory = mozpath.normsep(directory)
+            dirpath = self.join_ensure_dir(topsrcdir, directory)
+            if not dirpath:
+                return 1
+
+        if flags:
+            # Flatten lists of flags.
+            flags = set(itertools.chain(*[flaglist.split(',') for flaglist in flags]))
 
-            if filename.startswith(self.topsrcdir):
-                filename = filename[len(self.topsrcdir) + 1:]
+        for warning in by_name:
+            filename = mozpath.normsep(warning['filename'])
+
+            if filename.startswith(topsrcdir):
+                filename = filename[len(topsrcdir) + 1:]
+
+            if directory and not filename.startswith(directory):
+                continue
+
+            if flags and warning['flag'] not in flags:
+                continue
 
             if warning['column'] is not None:
                 print('%s:%d:%d [%s] %s' % (filename, warning['line'],
                     warning['column'], warning['flag'], warning['message']))
             else:
                 print('%s:%d [%s] %s' % (filename, warning['line'],
                     warning['flag'], warning['message']))
 
+    def join_ensure_dir(self, dir1, dir2):
+        dir1 = mozpath.normpath(dir1)
+        dir2 = mozpath.normsep(dir2)
+        joined_path = mozpath.join(dir1, dir2)
+        if os.path.isdir(joined_path):
+            return joined_path
+        else:
+            print('Specified directory not found.')
+            return None
+
 @CommandProvider
 class GTestCommands(MachCommandBase):
     @Command('gtest', category='testing',
         description='Run GTest unit tests (C++ tests).')
     @CommandArgument('gtest_filter', default=b"*", nargs='?', metavar='gtest_filter',
         help="test_filter is a ':'-separated list of wildcard patterns (called the positive patterns),"
              "optionally followed by a '-' and another ':'-separated pattern list (called the negative patterns).")
     @CommandArgument('--jobs', '-j', default='1', nargs='?', metavar='jobs', type=int,