mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 18:51:29 +00:00
add metrics_xml_formatter
git cl format supports formatting certain xml files under tools/metrics. This CL adds metrics_xml_formatter so that the formatter can be run with git cl format. Bug: b/369827156 Change-Id: I5922cd79304aa8e06917aacc9f2d9bd3ed548c2f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/6072565 Reviewed-by: Josip Sokcevic <sokcevic@chromium.org> Commit-Queue: Scott Lee <ddoman@chromium.org>
This commit is contained in:
32
git_cl.py
32
git_cl.py
@@ -58,6 +58,7 @@ import git_new_branch
|
|||||||
import google_java_format
|
import google_java_format
|
||||||
import metrics
|
import metrics
|
||||||
import metrics_utils
|
import metrics_utils
|
||||||
|
import metrics_xml_format
|
||||||
import newauth
|
import newauth
|
||||||
import owners_client
|
import owners_client
|
||||||
import owners_finder
|
import owners_finder
|
||||||
@@ -6765,7 +6766,7 @@ def _RunMojomFormat(opts, paths, top_dir, upstream_commit):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def _FormatXml(opts, paths, top_dir, upstream_commit):
|
def _RunMetricsXMLFormat(opts, paths, top_dir, upstream_commit):
|
||||||
# Skip the metrics formatting from the global presubmit hook. These files
|
# Skip the metrics formatting from the global presubmit hook. These files
|
||||||
# have a separate presubmit hook that issues an error if the files need
|
# have a separate presubmit hook that issues an error if the files need
|
||||||
# formatting, whereas the top-level presubmit script merely issues a
|
# formatting, whereas the top-level presubmit script merely issues a
|
||||||
@@ -6776,14 +6777,11 @@ def _FormatXml(opts, paths, top_dir, upstream_commit):
|
|||||||
|
|
||||||
return_value = 0
|
return_value = 0
|
||||||
for path in paths:
|
for path in paths:
|
||||||
xml_dir = GetMetricsDir(path)
|
pretty_print_tool = metrics_xml_format.FindMetricsXMLFormatterTool(path)
|
||||||
if not xml_dir:
|
if not pretty_print_tool:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
tool_dir = os.path.join(top_dir, xml_dir.replace('/', os.path.sep))
|
|
||||||
pretty_print_tool = os.path.join(tool_dir, 'pretty_print.py')
|
|
||||||
cmd = [shutil.which('vpython3'), pretty_print_tool, '--non-interactive']
|
cmd = [shutil.which('vpython3'), pretty_print_tool, '--non-interactive']
|
||||||
|
|
||||||
# If the XML file is histograms.xml or enums.xml, add the xml path
|
# If the XML file is histograms.xml or enums.xml, add the xml path
|
||||||
# to the command as histograms/pretty_print.py now needs a relative
|
# to the command as histograms/pretty_print.py now needs a relative
|
||||||
# path argument after splitting the histograms into multiple
|
# path argument after splitting the histograms into multiple
|
||||||
@@ -6792,13 +6790,8 @@ def _FormatXml(opts, paths, top_dir, upstream_commit):
|
|||||||
# tools/metrics/histogrmas, pretty-print should be run with an
|
# tools/metrics/histogrmas, pretty-print should be run with an
|
||||||
# additional relative path argument, like: $ python pretty_print.py
|
# additional relative path argument, like: $ python pretty_print.py
|
||||||
# metadata/UMA/histograms.xml $ python pretty_print.py enums.xml
|
# metadata/UMA/histograms.xml $ python pretty_print.py enums.xml
|
||||||
if xml_dir == 'tools/metrics/histograms':
|
if metrics_xml_format.GetMetricsDir(path) == 'tools/metrics/histograms':
|
||||||
if os.path.basename(path) not in ('histograms.xml', 'enums.xml',
|
|
||||||
'histogram_suffixes_list.xml'):
|
|
||||||
# Skip this XML file if it's not one of the known types.
|
|
||||||
continue
|
|
||||||
cmd.append(path.replace('/', os.path.sep))
|
cmd.append(path.replace('/', os.path.sep))
|
||||||
|
|
||||||
if opts.dry_run or opts.diff:
|
if opts.dry_run or opts.diff:
|
||||||
cmd.append('--diff')
|
cmd.append('--diff')
|
||||||
|
|
||||||
@@ -6935,7 +6928,7 @@ def CMDformat(parser, args):
|
|||||||
|
|
||||||
formatters = [
|
formatters = [
|
||||||
(GN_EXTS, _RunGnFormat),
|
(GN_EXTS, _RunGnFormat),
|
||||||
(['.xml'], _FormatXml),
|
(['.xml'], _RunMetricsXMLFormat),
|
||||||
]
|
]
|
||||||
if not opts.no_java:
|
if not opts.no_java:
|
||||||
formatters += [(['.java'], _RunGoogleJavaFormat)]
|
formatters += [(['.java'], _RunGoogleJavaFormat)]
|
||||||
@@ -6962,19 +6955,6 @@ def CMDformat(parser, args):
|
|||||||
return return_value
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
def GetMetricsDir(diff_xml):
|
|
||||||
metrics_xml_dirs = [
|
|
||||||
'tools/metrics/actions',
|
|
||||||
'tools/metrics/histograms',
|
|
||||||
'tools/metrics/structured',
|
|
||||||
'tools/metrics/ukm',
|
|
||||||
]
|
|
||||||
for xml_dir in metrics_xml_dirs:
|
|
||||||
if diff_xml.startswith(xml_dir):
|
|
||||||
return xml_dir
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@subcommand.usage('<codereview url or issue id>')
|
@subcommand.usage('<codereview url or issue id>')
|
||||||
@metrics.collector.collect_metrics('git cl checkout')
|
@metrics.collector.collect_metrics('git cl checkout')
|
||||||
def CMDcheckout(parser, args):
|
def CMDcheckout(parser, args):
|
||||||
|
|||||||
8
metrics-xml-format
Executable file
8
metrics-xml-format
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright 2024 The Chromium Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
base_dir=$(dirname "$0")
|
||||||
|
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 exec python3 "$base_dir/metrics_xml_format.py" "$@"
|
||||||
121
metrics_xml_format.py
Executable file
121
metrics_xml_format.py
Executable file
@@ -0,0 +1,121 @@
|
|||||||
|
#!/usr/bin/env vpython3
|
||||||
|
# Copyright (c) 2024 The Chromium Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
"""Redirects to the version of the metrics XML formatter in the Chromium tree.
|
||||||
|
"""
|
||||||
|
import gclient_paths
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def GetMetricsDir(path):
|
||||||
|
metrics_xml_dirs = [
|
||||||
|
'tools/metrics/actions',
|
||||||
|
'tools/metrics/histograms',
|
||||||
|
'tools/metrics/structured',
|
||||||
|
'tools/metrics/ukm',
|
||||||
|
]
|
||||||
|
normalized_abs_dirname = os.path.dirname(os.path.abspath(path)).replace(
|
||||||
|
os.sep, '/')
|
||||||
|
for xml_dir in metrics_xml_dirs:
|
||||||
|
if normalized_abs_dirname.endswith(xml_dir):
|
||||||
|
return xml_dir
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def IsSupportedHistogramsXML(path):
|
||||||
|
supported_xmls = set([
|
||||||
|
'histograms.xml',
|
||||||
|
'enums.xml',
|
||||||
|
'histogram_suffixes_list.xml',
|
||||||
|
])
|
||||||
|
return os.path.basename(path) in supported_xmls
|
||||||
|
|
||||||
|
|
||||||
|
def log(msg, verbose):
|
||||||
|
if verbose:
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def FindMetricsXMLFormatterTool(path, verbose=False):
|
||||||
|
"""Returns a path to the metrics XML formatter executable."""
|
||||||
|
top_dir = gclient_paths.GetPrimarySolutionPath()
|
||||||
|
if not top_dir:
|
||||||
|
log('Not executed in a Chromium checkout; skip formatting', verbose)
|
||||||
|
return ''
|
||||||
|
xml_dir = GetMetricsDir(path)
|
||||||
|
if not xml_dir:
|
||||||
|
log(f'{path} is not a metric XML; skip formatting', verbose)
|
||||||
|
return ''
|
||||||
|
# Just to ensure that the given file is located in the current checkout
|
||||||
|
# folder. If not, skip the formatting.
|
||||||
|
if not os.path.abspath(path).startswith(os.path.abspath(top_dir)):
|
||||||
|
log(
|
||||||
|
f'{path} is not located in the current Chromium checkout; '
|
||||||
|
'skip formatting', verbose)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
if xml_dir == 'tools/metrics/histograms':
|
||||||
|
# Skips the formatting, if the XML file is not one of the known types.
|
||||||
|
if not IsSupportedHistogramsXML(path):
|
||||||
|
log(f'{path} is not a supported histogram XML; skip formatting',
|
||||||
|
verbose)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# top_dir is already formatted with the OS specific path separator, whereas
|
||||||
|
# xml_dir is not yet.
|
||||||
|
tool_dir = os.path.join(top_dir, xml_dir.replace('/', os.path.sep))
|
||||||
|
return os.path.join(tool_dir, 'pretty_print.py')
|
||||||
|
|
||||||
|
|
||||||
|
usage_text = """Usage: %s [option] filepath
|
||||||
|
|
||||||
|
Format a given metrics XML file with the metrics XML formatters in the Chromium
|
||||||
|
checkout. Noop, if executed out of a Chromium checkout.
|
||||||
|
|
||||||
|
Note that not all the options are understood by all the formatters.
|
||||||
|
Find the formatter binaries for all the options supported by each formatter.
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
filepath if the path is not under tools/metrics,
|
||||||
|
no formatter will be run.
|
||||||
|
|
||||||
|
options:,
|
||||||
|
-h, --help show this help message and exit'
|
||||||
|
--presubmit
|
||||||
|
--diff"""
|
||||||
|
|
||||||
|
|
||||||
|
def _print_help():
|
||||||
|
print(usage_text % sys.argv[0])
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
path = next((arg for arg in args if not arg.startswith('-')), None)
|
||||||
|
if not path:
|
||||||
|
_print_help()
|
||||||
|
return 0
|
||||||
|
if not os.path.exists(path):
|
||||||
|
raise FileNotFoundError(f'{path} does not exist.')
|
||||||
|
|
||||||
|
tool = FindMetricsXMLFormatterTool(path, verbose=True)
|
||||||
|
if not tool:
|
||||||
|
# Fail (almost) silently.
|
||||||
|
return 0
|
||||||
|
|
||||||
|
subprocess.run([
|
||||||
|
shutil.which('vpython3'),
|
||||||
|
tool,
|
||||||
|
] + args)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.stderr.write('interrupted\n')
|
||||||
|
sys.exit(1)
|
||||||
113
tests/metrics_xml_format_test.py
Executable file
113
tests/metrics_xml_format_test.py
Executable file
@@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/env vpython3
|
||||||
|
# coding=utf-8
|
||||||
|
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
import gclient_paths_test
|
||||||
|
import metrics_xml_format
|
||||||
|
|
||||||
|
norm = lambda path: path.replace('/', os.sep)
|
||||||
|
join = os.path.join
|
||||||
|
|
||||||
|
|
||||||
|
class TestBase(gclient_paths_test.TestBase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
|
||||||
|
# os.path.abspath() doesn't seem to use os.path.getcwd() to compute
|
||||||
|
# the abspath of a given path.
|
||||||
|
#
|
||||||
|
# This mock os.path.abspath such that it uses the mocked getcwd().
|
||||||
|
mock.patch('os.path.abspath', self.abspath).start()
|
||||||
|
# gclient_paths.GetPrimarysolutionPath() defaults to src.
|
||||||
|
self.make_file_tree({'.gclient': ''})
|
||||||
|
self.cwd = join(self.cwd, 'src')
|
||||||
|
|
||||||
|
def abspath(self, path):
|
||||||
|
if os.path.isabs(path):
|
||||||
|
return path
|
||||||
|
|
||||||
|
return join(self.getcwd(), path)
|
||||||
|
|
||||||
|
|
||||||
|
class GetMetricsDirTest(TestBase):
|
||||||
|
|
||||||
|
def testWithAbsolutePath(self):
|
||||||
|
get = lambda path: metrics_xml_format.GetMetricsDir(norm(path))
|
||||||
|
self.assertTrue(get('/src/tools/metrics/actions/abc.xml'))
|
||||||
|
self.assertTrue(get('/src/tools/metrics/histograms/abc.xml'))
|
||||||
|
self.assertTrue(get('/src/tools/metrics/structured/abc.xml'))
|
||||||
|
self.assertTrue(get('/src/tools/metrics/ukm/abc.xml'))
|
||||||
|
|
||||||
|
self.assertFalse(get('/src/tools/metrics/actions/next/abc.xml'))
|
||||||
|
self.assertFalse(get('/src/tools/metrics/histograms/next/abc.xml'))
|
||||||
|
self.assertFalse(get('/src/tools/metrics/structured/next/abc.xml'))
|
||||||
|
self.assertFalse(get('/src/tools/metrics/ukm/next/abc.xml'))
|
||||||
|
|
||||||
|
def testWithRelativePaths(self):
|
||||||
|
get = lambda path: metrics_xml_format.GetMetricsDir(norm(path))
|
||||||
|
self.cwd = join(self.cwd, 'tools')
|
||||||
|
self.assertFalse(get('abc.xml'))
|
||||||
|
self.assertTrue(get('metrics/actions/abc.xml'))
|
||||||
|
|
||||||
|
|
||||||
|
class FindMetricsXMLFormatTool(TestBase):
|
||||||
|
|
||||||
|
def testWithMetricsXML(self):
|
||||||
|
findTool = metrics_xml_format.FindMetricsXMLFormatterTool
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
findTool(norm('tools/metrics/actions/abc.xml')),
|
||||||
|
join(self.getcwd(), norm('tools/metrics/actions/pretty_print.py')),
|
||||||
|
)
|
||||||
|
|
||||||
|
# same test, but with an absolute path.
|
||||||
|
self.assertEqual(
|
||||||
|
findTool(join(self.getcwd(),
|
||||||
|
norm('tools/metrics/actions/abc.xml'))),
|
||||||
|
join(self.getcwd(), norm('tools/metrics/actions/pretty_print.py')),
|
||||||
|
)
|
||||||
|
|
||||||
|
def testWthNonMetricsXML(self):
|
||||||
|
findTool = metrics_xml_format.FindMetricsXMLFormatterTool
|
||||||
|
self.assertEqual(findTool('tools/metrics/actions/next/abc.xml'), '')
|
||||||
|
|
||||||
|
def testWithNonCheckout(self):
|
||||||
|
findTool = metrics_xml_format.FindMetricsXMLFormatterTool
|
||||||
|
self.cwd = self.root
|
||||||
|
self.assertEqual(findTool('tools/metrics/actions/abc.xml'), '')
|
||||||
|
|
||||||
|
def testWithDifferentCheckout(self):
|
||||||
|
findTool = metrics_xml_format.FindMetricsXMLFormatterTool
|
||||||
|
checkout2 = join(self.root, '..', self._testMethodName + '2', 'src')
|
||||||
|
self.assertEqual(
|
||||||
|
# this is the case the tool was given a file path that is located
|
||||||
|
# in a different checkout folder.
|
||||||
|
findTool(join(checkout2, norm('tools/metrics/actions/abc.xml'))),
|
||||||
|
'',
|
||||||
|
)
|
||||||
|
|
||||||
|
def testSupportedHistogramsXML(self):
|
||||||
|
findTool = metrics_xml_format.FindMetricsXMLFormatterTool
|
||||||
|
self.assertEqual(
|
||||||
|
findTool(norm('tools/metrics/histograms/enums.xml')),
|
||||||
|
join(self.getcwd(),
|
||||||
|
norm('tools/metrics/histograms/pretty_print.py')),
|
||||||
|
)
|
||||||
|
|
||||||
|
def testNotSupportedHistogramsXML(self):
|
||||||
|
findTool = metrics_xml_format.FindMetricsXMLFormatterTool
|
||||||
|
self.assertEqual(findTool(norm('tools/metrics/histograms/NO.xml')), '')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user