1#!/usr/bin/env python3 2# -*- coding:utf-8 -*- 3# Copyright 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Wrapper to run pylint with the right settings.""" 18 19from __future__ import print_function 20 21import argparse 22import errno 23import os 24import shutil 25import sys 26import subprocess 27 28 29assert (sys.version_info.major, sys.version_info.minor) >= (3, 5), ( 30 'Python 3.5 or newer is required; found %s' % (sys.version,)) 31 32 33DEFAULT_PYLINTRC_PATH = os.path.join( 34 os.path.dirname(os.path.realpath(__file__)), 'pylintrc') 35 36 37def is_pylint3(pylint): 38 """See whether |pylint| supports Python 3.""" 39 # Make sure pylint is using Python 3. 40 result = subprocess.run([pylint, '--version'], stdout=subprocess.PIPE, 41 check=True) 42 if b'Python 3' not in result.stdout: 43 print('%s: unable to locate a Python 3 version of pylint; Python 3 ' 44 'support cannot be guaranteed' % (__file__,), file=sys.stderr) 45 return False 46 47 return True 48 49 50def find_pylint3(): 51 """Figure out the name of the pylint tool for Python 3. 52 53 It keeps changing with Python 2->3 migrations. Fun. 54 """ 55 # Prefer pylint3 as that's what we want. 56 if shutil.which('pylint3'): 57 return 'pylint3' 58 59 # If there's no pylint, give up. 60 if not shutil.which('pylint'): 61 print('%s: unable to locate pylint; please install:\n' 62 'sudo apt-get install pylint' % (__file__,), file=sys.stderr) 63 sys.exit(1) 64 65 return 'pylint' 66 67 68def get_parser(): 69 """Return a command line parser.""" 70 parser = argparse.ArgumentParser(description=__doc__) 71 parser.add_argument('--init-hook', help='Init hook commands to run.') 72 parser.add_argument('--py3', action='store_true', 73 help='Force Python 3 mode') 74 parser.add_argument('--executable-path', 75 help='The path of the pylint executable.') 76 parser.add_argument('--no-rcfile', 77 help='Specify to use the executable\'s default ' 78 'configuration.', 79 action='store_true') 80 parser.add_argument('files', nargs='+') 81 return parser 82 83 84def main(argv): 85 """The main entry.""" 86 parser = get_parser() 87 opts, unknown = parser.parse_known_args(argv) 88 89 pylint = opts.executable_path 90 if pylint is None: 91 if opts.py3: 92 pylint = find_pylint3() 93 else: 94 pylint = 'pylint' 95 96 # Make sure pylint is using Python 3. 97 if opts.py3: 98 is_pylint3(pylint) 99 100 cmd = [pylint] 101 if not opts.no_rcfile: 102 # We assume pylint is running in the top directory of the project, 103 # so load the pylintrc file from there if it's available. 104 pylintrc = os.path.abspath('pylintrc') 105 if not os.path.exists(pylintrc): 106 pylintrc = DEFAULT_PYLINTRC_PATH 107 # If we pass a non-existent rcfile to pylint, it'll happily ignore 108 # it. 109 assert os.path.exists(pylintrc), 'Could not find %s' % pylintrc 110 cmd += ['--rcfile', pylintrc] 111 112 cmd += unknown + opts.files 113 114 if opts.init_hook: 115 cmd += ['--init-hook', opts.init_hook] 116 117 try: 118 os.execvp(cmd[0], cmd) 119 return 0 120 except OSError as e: 121 if e.errno == errno.ENOENT: 122 print('%s: unable to run `%s`: %s' % (__file__, cmd[0], e), 123 file=sys.stderr) 124 print('%s: Try installing pylint: sudo apt-get install %s' % 125 (__file__, os.path.basename(cmd[0])), file=sys.stderr) 126 return 1 127 128 raise 129 130 131if __name__ == '__main__': 132 sys.exit(main(sys.argv[1:])) 133