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