diff options
author | Xin Li <delphij@google.com> | 2022-10-06 12:01:42 -0700 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2022-10-06 12:01:42 -0700 |
commit | fb38bbe1b34149a14cd8a41d7974e6991b6116d4 (patch) | |
tree | 5a4e727181cfa721639d3246d9300ce71818b6c7 | |
parent | a241c34bc8fb779f4ebf5ba818b069884d5ac995 (diff) | |
parent | 09e4986cea73a4401745809bcf4ea91b10374a3a (diff) | |
download | ktfmt-fb38bbe1b34149a14cd8a41d7974e6991b6116d4.tar.gz |
Merge tm-qpr-dev-plus-aosp-without-vendor@9129937
Bug: 248070379
Merged-In: Iab843273db001e05d8b6ee5cbee412fac7efa244
Change-Id: I6c7dbb5ec08d139ab537bde3621c461b7e2a1a0e
-rwxr-xr-x | generate_includes_file.py | 95 | ||||
-rwxr-xr-x | ktfmt.py | 138 |
2 files changed, 233 insertions, 0 deletions
diff --git a/generate_includes_file.py b/generate_includes_file.py new file mode 100755 index 0000000..be9ebff --- /dev/null +++ b/generate_includes_file.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 + +# +# Copyright 2022, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +"""Script to generate an include file that can be passed to ktfmt.py. + +The include file is generated from one or more folders containing one or more +Kotlin files. The generated include file will exclude all Kotlin files that +currently don't follow ktfmt format. This way, we can easily start formatting +all new files in a project/directory. +""" + +import argparse +import os +import subprocess +import sys + + +def main(): + parser = argparse.ArgumentParser( + 'Generate an include file that can be passed to ktfmt.py') + parser.add_argument( + '--output', '-o', required=True, help='The output include file.') + parser.add_argument( + 'files', + nargs='*', + help='The files or directories that should be included.') + args = parser.parse_args() + + # Add a line preprended with '+' for included files/folders. + with open(args.output, 'w+') as out: + includes = args.files + includes.sort() + for include in includes: + out.write('+' + include + '\n') + + # Retrieve all Kotlin files. + kt_files = [] + for file in args.files: + if os.path.isdir(file): + for root, dirs, files in os.walk(file): + for f in files: + if is_kotlin_file(f): + kt_files += [os.path.join(root, f)] + + if is_kotlin_file(file): + kt_files += [file] + + # Check all files with ktfmt. + ktfmt_args = ['--kotlinlang-style', '--set-exit-if-changed', '--dry-run' + ] + kt_files + dir = os.path.dirname(__file__) + ktfmt_jar = os.path.normpath( + os.path.join(dir, + '../../prebuilts/build-tools/common/framework/ktfmt.jar')) + + ktlint_env = os.environ.copy() + ktlint_env['JAVA_CMD'] = 'java' + try: + process = subprocess.Popen( + ['java', '-jar', ktfmt_jar] + ktfmt_args, + stdout=subprocess.PIPE, + env=ktlint_env) + + # Add a line prepended with '-' for all files that are not correctly. + # formatted. + stdout, _ = process.communicate() + incorrect_files = stdout.decode('utf-8').splitlines() + incorrect_files.sort() + for file in incorrect_files: + out.write('-' + file + '\n') + except OSError as e: + print('Error running ktfmt') + sys.exit(1) + + +def is_kotlin_file(name): + return name.endswith('.kt') or name.endswith('.kts') + + +if __name__ == '__main__': + main() diff --git a/ktfmt.py b/ktfmt.py new file mode 100755 index 0000000..6f115f7 --- /dev/null +++ b/ktfmt.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 + +# +# Copyright 2022, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +"""Script to format or check Kotlin files.""" + +import argparse +import os +import subprocess +import sys + + +def main(): + parser = argparse.ArgumentParser( + 'Format Kotlin files or check that they are correctly formatted.') + parser.add_argument( + '--check', + '-c', + action='store_true', + default=False, + help='Perform a format check instead of formatting.') + parser.add_argument( + '--includes_file', + '-i', + default='', + help='The file containing the Kotlin files and directories that should be included/excluded, generated using generate_includes_file.py.' + ) + parser.add_argument( + 'files', + nargs='*', + help='The files to format or check. If --include_file is specified, only the files at their intersection will be formatted/checked.' + ) + args = parser.parse_args() + + ktfmt_args = ['--kotlinlang-style'] + + check = args.check + if check: + ktfmt_args += ['--set-exit-if-changed', '--dry-run'] + + kt_files = [] + for file in args.files: + if os.path.isdir(file): + for root, dirs, files in os.walk(file): + for f in files: + if is_kotlin_file(f): + kt_files += [os.path.join(root, f)] + + if is_kotlin_file(file): + kt_files += [file] + + # Only format/check files from the includes list. + includes_file = args.includes_file + if kt_files and includes_file: + f = open(includes_file, 'r') + + lines = f.read().splitlines() + included = [line[1:] for line in lines if line.startswith('+')] + included_files = set() + included_dirs = [] + for line in included: + if is_kotlin_file(line): + included_files.add(line) + else: + included_dirs += [line] + + excluded_files = [line[1:] for line in lines if line.startswith('-')] + + kt_files = [ + kt_file for kt_file in kt_files if kt_file not in excluded_files and + (kt_file in included_files or is_included(kt_file, included_dirs)) + ] + + # No need to start ktfmt if there are no files to check/format. + if not kt_files: + sys.exit(0) + + ktfmt_args += kt_files + + dir = os.path.normpath(os.path.dirname(__file__)) + ktfmt_jar = os.path.join( + dir, '../../prebuilts/build-tools/common/framework/ktfmt.jar') + + ktlint_env = os.environ.copy() + ktlint_env['JAVA_CMD'] = 'java' + try: + process = subprocess.Popen( + ['java', '-jar', ktfmt_jar] + ktfmt_args, + stdout=subprocess.PIPE, + env=ktlint_env) + stdout, _ = process.communicate() + code = process.returncode + if check and code != 0: + print( + '**********************************************************************' + ) + print( + 'Some Kotlin files are not properly formatted. Run the following command to format them:\n\n' + ) + script_path = os.path.normpath(__file__) + incorrect_files = stdout.decode('utf-8').splitlines() + print('$ ' + script_path + ' ' + ' '.join(incorrect_files) + '\n') + print( + '**********************************************************************' + ) + sys.exit(code) + else: + sys.exit(0) + except OSError as e: + print('Error running ktfmt') + sys.exit(1) + + +def is_kotlin_file(name): + return name.endswith('.kt') or name.endswith('.kts') + + +def is_included(file, dirs): + for dir in dirs: + if file.startswith(dir): + return True + + +if __name__ == '__main__': + main() |