Bug 1410969 - Add support for writing JSON from `mach file-info`; r?ahal draft
authorGregory Szorc <gps@mozilla.com>
Mon, 23 Oct 2017 11:01:00 -0700
changeset 685487 0a8eb90576c6e80e9093665054815704f7751370
parent 685486 8b2151c9d49d87a41bac2eca57dc83cd432191e8
child 685488 edece5fe0f0cde87892cb092de49093c85e9e462
push id85942
push usergszorc@mozilla.com
push dateTue, 24 Oct 2017 17:18:32 +0000
reviewersahal
bugs1410969
milestone58.0a1
Bug 1410969 - Add support for writing JSON from `mach file-info`; r?ahal The feature should be pretty self-explanatory. It will enable easier machine readable output. MozReview-Commit-ID: GK148VCcNjm
python/mozbuild/mozbuild/frontend/mach_commands.py
--- a/python/mozbuild/mozbuild/frontend/mach_commands.py
+++ b/python/mozbuild/mozbuild/frontend/mach_commands.py
@@ -1,16 +1,18 @@
 # 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
 
 from collections import defaultdict
+import json
 import os
+import sys
 
 from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
     SubCommand,
 )
 
@@ -91,52 +93,91 @@ class MozbuildFileCommands(MachCommandBa
         moz.build files contain "Files" sub-contexts for declaring metadata
         against file patterns. This command suite is used to query that data.
         """
 
     @SubCommand('file-info', 'bugzilla-component',
                 'Show Bugzilla component info for files listed.')
     @CommandArgument('-r', '--rev',
                      help='Version control revision to look up info from')
+    @CommandArgument('--format', choices={'json', 'plain'}, default='plain',
+                     help='Output format', dest='fmt')
     @CommandArgument('paths', nargs='+',
                      help='Paths whose data to query')
-    def file_info_bugzilla(self, paths, rev=None):
+    def file_info_bugzilla(self, paths, rev=None, fmt=None):
         """Show Bugzilla component for a set of files.
 
         Given a requested set of files (which can be specified using
         wildcards), print the Bugzilla component for each file.
         """
         components = defaultdict(set)
         try:
             for p, m in self._get_files_info(paths, rev=rev).items():
                 components[m.get('BUG_COMPONENT')].add(p)
         except InvalidPathException as e:
             print(e.message)
             return 1
 
-        for component, files in sorted(components.items(), key=lambda x: (x is None, x)):
-            print('%s :: %s' % (component.product, component.component) if component else 'UNKNOWN')
-            for f in sorted(files):
-                print('  %s' % f)
+        if fmt == 'json':
+            data = {}
+            for component, files in components.items():
+                if not component:
+                    continue
+                for f in files:
+                    data[f] = [component.product, component.component]
+
+            json.dump(data, sys.stdout, sort_keys=True, indent=2)
+            return
+        elif fmt == 'plain':
+            data = sorted(components.items(),
+                          key=lambda x: (x is None, x))
+            for component, files in data:
+                if component:
+                    s = '%s :: %s' % (component.product, component.component)
+                else:
+                    s = 'UNKNOWN'
+
+                print(s)
+                for f in sorted(files):
+                    print('  %s' % f)
+        else:
+            print('unhandled output format: %s' % fmt)
+            return 1
 
     @SubCommand('file-info', 'missing-bugzilla',
                 'Show files missing Bugzilla component info')
     @CommandArgument('-r', '--rev',
                      help='Version control revision to look up info from')
+    @CommandArgument('--format', choices={'json', 'plain'}, dest='fmt',
+                     default='plain',
+                     help='Output format')
     @CommandArgument('paths', nargs='+',
                      help='Paths whose data to query')
-    def file_info_missing_bugzilla(self, paths, rev=None):
+    def file_info_missing_bugzilla(self, paths, rev=None, fmt=None):
+        missing = set()
+
         try:
-            for p, m in sorted(self._get_files_info(paths, rev=rev).items()):
+            for p, m in self._get_files_info(paths, rev=rev).items():
                 if 'BUG_COMPONENT' not in m:
-                    print(p)
+                    missing.add(p)
         except InvalidPathException as e:
             print(e.message)
             return 1
 
+        if fmt == 'json':
+            json.dump({'missing': sorted(missing)}, sys.stdout,
+                      indent=2)
+            return
+        elif fmt == 'plain':
+            for f in sorted(missing):
+                print(f)
+        else:
+            print('unhandled output format: %s' % fmt)
+            return 1
+
     @SubCommand('file-info', 'dep-tests',
                 'Show test files marked as dependencies of these source files.')
     @CommandArgument('-r', '--rev',
                      help='Version control revision to look up info from')
     @CommandArgument('paths', nargs='+',
                      help='Paths whose data to query')
     def file_info_test_deps(self, paths, rev=None):
         try: