1#!/usr/bin/env python3 2 3# 4# Copyright 2017, The Android Open Source Project 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19"""Script that is used by developers to run style checks on Kotlin files.""" 20 21from __future__ import print_function 22 23import argparse 24import errno 25import os 26import subprocess 27import sys 28 29MAIN_DIRECTORY = os.path.normpath(os.path.dirname(__file__)) 30KTLINT_JAR = os.path.join(MAIN_DIRECTORY, 'ktlint-android-all.jar') 31EDITOR_CONFIG = os.path.join(MAIN_DIRECTORY, '.editorconfig') 32FORMAT_MESSAGE = """ 33********************************************************************** 34To format run: 35{}/ktlint.py --format --file {} 36********************************************************************** 37""" 38 39 40def main(args=None): 41 parser = argparse.ArgumentParser() 42 parser.add_argument('--file', '-f', nargs='*') 43 parser.add_argument('--format', '-F', dest='format', action='store_true') 44 parser.add_argument('--noformat', dest='format', action='store_false') 45 parser.add_argument( 46 '--no-verify-format', dest='verify_format', action='store_false' 47 ) 48 parser.add_argument( 49 '--disabled-rules', dest='disabled_rules' 50 ) 51 parser.add_argument('--editorconfig', default=EDITOR_CONFIG) 52 parser.set_defaults(format=False, verify_format=True) 53 args = parser.parse_args() 54 kt_files = [f for f in args.file if f.endswith('.kt') or f.endswith('.kts')] 55 if not kt_files: 56 sys.exit(0) 57 58 disabled_rules = [ 59 'indent', 60 'paren-spacing', 61 'curly-spacing', 62 'wrapping', 63 # trailing-comma requires wrapping 64 'trailing-comma-on-call-site', 65 'trailing-comma-on-declaration-site', 66 # annotations requires wrapping 67 'spacing-between-declarations-with-annotations', 68 'annotation', 69 ] 70 71 # Disable more format-related rules if we shouldn't verify the format. This is usually 72 # the case if files we are checking are already checked by ktfmt. 73 if not args.verify_format: 74 disabled_rules += [ 75 # Please keep sorted. 76 'annotation-spacing', 77 'argument-list-wrapping', 78 'block-comment-initial-star-alignment', 79 'chain-wrapping', 80 'comment-wrapping', 81 'final-newline', 82 'import-ordering', 83 # TODO(b/366424213): Enable this check again. 84 'max-line-length', 85 'multiline-if-else', 86 'no-consecutive-blank-lines', 87 'no-empty-first-line-in-method-block', 88 'parameter-list-wrapping', 89 'parameter-wrapping', 90 'spacing-between-declarations-with-comments', 91 ] 92 93 if args.disabled_rules: 94 additional_rules = args.disabled_rules.split(",") 95 disabled_rules.extend(rule for rule in additional_rules if rule not in disabled_rules) 96 97 ktlint_args = kt_files[:] 98 ktlint_args += ['--disabled_rules=' + ','.join(disabled_rules)] 99 100 # Setup editor config explicitly if defined - else will inherit from tree 101 if args.editorconfig is not None: 102 ktlint_args += ['--editorconfig', args.editorconfig] 103 104 # Automatically format files if requested. 105 if args.format: 106 ktlint_args += ['-F'] 107 108 ktlint_env = os.environ.copy() 109 ktlint_env['JAVA_CMD'] = 'java' 110 try: 111 check = subprocess.Popen( 112 [ 113 'java', 114 '--add-opens=java.base/java.lang=ALL-UNNAMED', 115 '-jar', 116 KTLINT_JAR, 117 ] 118 + ktlint_args, 119 stdout=subprocess.PIPE, 120 env=ktlint_env, 121 ) 122 stdout, _ = check.communicate() 123 if stdout: 124 print('prebuilts/ktlint found errors in files you changed:') 125 print(stdout.decode('utf-8')) 126 if args.verify_format: 127 print(FORMAT_MESSAGE.format(MAIN_DIRECTORY, ' '.join(kt_files))) 128 sys.exit(1) 129 else: 130 sys.exit(0) 131 except OSError as e: 132 if e.errno == errno.ENOENT: 133 print('Error running ktlint!') 134 sys.exit(1) 135 136 137if __name__ == '__main__': 138 main() 139