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