diff --git a/git_cl.py b/git_cl.py index 57519296f4..1e2f675cb0 100755 --- a/git_cl.py +++ b/git_cl.py @@ -52,6 +52,7 @@ import setup_color import split_cl import subcommand import subprocess2 +import swift_format import watchlists from third_party import six @@ -5143,6 +5144,33 @@ def _RunRustFmt(opts, rust_diff_files, top_dir, upstream_commit): return 0 +def _RunSwiftFormat(opts, swift_diff_files, top_dir, upstream_commit): + """Runs swift-format. Just like _RunClangFormatDiff returns 2 to indicate + that presubmit checks have failed (and returns 0 otherwise).""" + + if not swift_diff_files: + return 0 + + # Locate the swift-format binary. + try: + swift_format_tool = swift_format.FindSwiftFormatToolInChromiumTree() + except swift_format.NotFoundError as e: + DieWithError(e) + + cmd = [swift_format_tool] + if opts.dry_run: + cmd.append('lint') + else: + cmd += ['format', '-i'] + cmd += swift_diff_files + swift_format_exitcode = subprocess2.call(cmd) + + if opts.presubmit and swift_format_exitcode != 0: + return 2 + + return 0 + + def MatchingFileType(file_name, extensions): """Returns True if the file name ends with one of the given extensions.""" return bool([ext for ext in extensions if file_name.lower().endswith(ext)]) @@ -5155,6 +5183,7 @@ def CMDformat(parser, args): CLANG_EXTS = ['.cc', '.cpp', '.h', '.m', '.mm', '.proto', '.java'] GN_EXTS = ['.gn', '.gni', '.typemap'] RUST_EXTS = ['.rs'] + SWIFT_EXTS = ['.swift'] parser.add_option('--full', action='store_true', help='Reformat the full content of all touched files') parser.add_option('--upstream', help='Branch to check against') @@ -5200,6 +5229,19 @@ def CMDformat(parser, args): action='store_false', help='Disables formatting of Rust file types using rustfmt.') + parser.add_option( + '--swift-format', + dest='use_swift_format', + action='store_true', + default=False, + help='Enables formatting of Swift file types using swift-format ' + '(macOS host only).') + parser.add_option( + '--no-swift-format', + dest='use_swift_format', + action='store_false', + help='Disables formatting of Swift file types using swift-format.') + opts, args = parser.parse_args(args) if opts.python is not None and opts.no_python: @@ -5250,6 +5292,7 @@ def CMDformat(parser, args): ] python_diff_files = [x for x in diff_files if MatchingFileType(x, ['.py'])] rust_diff_files = [x for x in diff_files if MatchingFileType(x, RUST_EXTS)] + swift_diff_files = [x for x in diff_files if MatchingFileType(x, SWIFT_EXTS)] gn_diff_files = [x for x in diff_files if MatchingFileType(x, GN_EXTS)] top_dir = settings.GetRoot() @@ -5263,6 +5306,14 @@ def CMDformat(parser, args): if rust_fmt_return_value == 2: return_value = 2 + if opts.use_swift_format: + if sys.platform != 'darwin': + DieWithError('swift-format is only supported on macOS.') + swift_format_return_value = _RunSwiftFormat(opts, swift_diff_files, top_dir, + upstream_commit) + if swift_format_return_value == 2: + return_value = 2 + # Similar code to above, but using yapf on .py files rather than clang-format # on C/C++ files py_explicitly_disabled = opts.python is not None and not opts.python diff --git a/swift-format b/swift-format new file mode 100755 index 0000000000..b0162db17a --- /dev/null +++ b/swift-format @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright 2022 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/swift_format.py" "$@" diff --git a/swift_format.py b/swift_format.py new file mode 100644 index 0000000000..50536fe5e9 --- /dev/null +++ b/swift_format.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# Copyright 2022 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 swift-format present in the Chrome tree. + +Swift format binaries are pulled down from CIPD whenever you sync Chrome. +This script knows how to locate those tools, assuming the script is +invoked from inside a Chromium checkout.""" + +import gclient_paths +import os +import subprocess +import sys + + +class NotFoundError(Exception): + """A file could not be found.""" + + def __init__(self, e): + Exception.__init__( + self, + 'Problem while looking for swift-format in Chromium source tree:\n' + '%s' % e) + + +def FindSwiftFormatToolInChromiumTree(): + """Return a path to the rustfmt executable, or die trying.""" + chromium_src_path = gclient_paths.GetPrimarySolutionPath() + if not chromium_src_path: + raise NotFoundError( + 'Could not find checkout in any parent of the current path.\n' + 'Set CHROMIUM_BUILDTOOLS_PATH to use outside of a chromium checkout.') + + tool_path = os.path.join(chromium_src_path, 'third_party', 'swift-format', + 'swift-format') + if not os.path.exists(tool_path): + raise NotFoundError('File does not exist: %s' % tool_path) + return tool_path + + +def IsSwiftFormatSupported(): + try: + FindSwiftFormatToolInChromiumTree() + return True + except NotFoundError: + return False + + +def main(args): + try: + tool = FindSwiftFormatToolInChromiumTree() + except NotFoundError as e: + sys.stderr.write("%s\n" % str(e)) + return 1 + + # Add some visibility to --help showing where the tool lives, since this + # redirection can be a little opaque. + help_syntax = ('-h', '--help', '-help', '-help-list', '--help-list') + if any(match in args for match in help_syntax): + print('\nDepot tools redirects you to the swift-format at:\n %s\n' % + tool) + + return subprocess.call([tool] + args) + + +if __name__ == '__main__': + try: + sys.exit(main(sys.argv[1:])) + except KeyboardInterrupt: + sys.stderr.write('interrupted\n') + sys.exit(1)