blob: ab6f0b3c6a65589feb0e409539a9f83abf1ae016 [file] [log] [blame]
Brian Norrise4a085a2020-04-01 16:40:04 -07001#!/usr/bin/env vpython
2
3# [VPYTHON:BEGIN]
4# # Third party dependencies. These are only listed because pylint itself needs
5# # them. Feel free to add/remove anything here.
6#
7# wheel: <
8# name: "infra/python/wheels/configparser-py2_py3"
9# version: "version:3.5.0"
10# >
11# wheel: <
12# name: "infra/python/wheels/futures-py2_py3"
13# version: "version:3.1.1"
14# >
15# wheel: <
16# name: "infra/python/wheels/isort-py2_py3"
17# version: "version:4.3.4"
18# >
19# wheel: <
20# name: "infra/python/wheels/wrapt/${vpython_platform}"
21# version: "version:1.10.11"
22# >
23# wheel: <
24# name: "infra/python/wheels/backports_functools_lru_cache-py2_py3"
25# version: "version:1.5"
26# >
27# wheel: <
28# name: "infra/python/wheels/lazy-object-proxy/${vpython_platform}"
29# version: "version:1.3.1"
30# >
31# wheel: <
32# name: "infra/python/wheels/singledispatch-py2_py3"
33# version: "version:3.4.0.3"
34# >
35# wheel: <
36# name: "infra/python/wheels/enum34-py2"
37# version: "version:1.1.6"
38# >
39# wheel: <
40# name: "infra/python/wheels/mccabe-py2_py3"
41# version: "version:0.6.1"
42# >
43# wheel: <
44# name: "infra/python/wheels/six-py2_py3"
45# version: "version:1.10.0"
46# >
47#
48# # Pylint dependencies.
49#
50# wheel: <
51# name: "infra/python/wheels/astroid-py2_py3"
52# version: "version:1.6.6"
53# >
54#
55# wheel: <
56# name: "infra/python/wheels/pylint-py2_py3"
57# version: "version:1.9.5-45a720817e4de1df2f173c7e4029e176"
58# >
59# [VPYTHON:END]
60
beeps48fc6f52013-01-07 14:36:40 -080061"""
62Wrapper to patch pylint library functions to suit autotest.
63
64This script is invoked as part of the presubmit checks for autotest python
65files. It runs pylint on a list of files that it obtains either through
66the command line or from an environment variable set in pre-upload.py.
67
68Example:
69run_pylint.py filename.py
70"""
mbligh99d2ded2008-06-23 16:17:36 +000071
Prashanth Balasubramanianbaabef22014-11-04 12:38:44 -080072import fnmatch
73import logging
74import os
75import re
76import sys
mbligh99d2ded2008-06-23 16:17:36 +000077
beeps98365d82013-02-20 20:08:07 -080078import common
79from autotest_lib.client.common_lib import autotemp, revision_control
beeps48fc6f52013-01-07 14:36:40 -080080
81# Do a basic check to see if pylint is even installed.
mbligh65e06b12008-08-22 18:12:49 +000082try:
83 import pylint
Eric Li861b2d52011-02-04 14:50:35 -080084 from pylint.__pkginfo__ import version as pylint_version
mbligh65e06b12008-08-22 18:12:49 +000085except ImportError:
beeps48fc6f52013-01-07 14:36:40 -080086 print ("Unable to import pylint, it may need to be installed."
87 " Run 'sudo aptitude install pylint' if you haven't already.")
mbligh65e06b12008-08-22 18:12:49 +000088 sys.exit(1)
89
Kazuhiro Inaba0e7bd162019-06-07 16:24:45 +090090pylint_version_parsed = tuple(map(int, pylint_version.split('.')))
mbligh99d2ded2008-06-23 16:17:36 +000091
beeps48fc6f52013-01-07 14:36:40 -080092# some files make pylint blow up, so make sure we ignore them
Greg Edelston4511c482020-11-02 10:31:43 -070093SKIPLIST = ['/site-packages/*', '/contrib/*', '/frontend/afe/management.py']
jadmanski94a64932008-07-22 14:03:10 +000094
Mike Frysingercb574632019-09-20 10:43:45 -040095import astroid
mbligh99d2ded2008-06-23 16:17:36 +000096import pylint.lint
beeps2c669642013-01-14 18:30:57 -080097from pylint.checkers import base, imports, variables
mbligh99d2ded2008-06-23 16:17:36 +000098
99# need to put autotest root dir on sys.path so pylint will be happy
100autotest_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
101sys.path.insert(0, autotest_root)
102
103# patch up pylint import checker to handle our importing magic
beeps48fc6f52013-01-07 14:36:40 -0800104ROOT_MODULE = 'autotest_lib.'
beepse19d3032013-05-30 09:22:07 -0700105
106# A list of modules for pylint to ignore, specifically, these modules
107# are imported for their side-effects and are not meant to be used.
Prashanth B2d8047e2014-04-27 18:54:47 -0700108_IGNORE_MODULES=['common', 'frontend_test_utils',
109 'setup_django_environment',
Keyar Hoodf9a36512013-06-13 18:39:56 -0700110 'setup_django_lite_environment',
Prashanth B2d8047e2014-04-27 18:54:47 -0700111 'setup_django_readonly_environment', 'setup_test_environment',]
beeps48fc6f52013-01-07 14:36:40 -0800112
113
beeps98365d82013-02-20 20:08:07 -0800114class pylint_error(Exception):
115 """
116 Error raised when pylint complains about a file.
117 """
118
119
120class run_pylint_error(pylint_error):
121 """
122 Error raised when an assumption made in this file is violated.
123 """
124
125
beeps48fc6f52013-01-07 14:36:40 -0800126def patch_modname(modname):
127 """
128 Patches modname so we can make sense of autotest_lib modules.
129
130 @param modname: name of a module, contains '.'
131 @return modified modname string.
132 """
133 if modname.startswith(ROOT_MODULE) or modname.startswith(ROOT_MODULE[:-1]):
134 modname = modname[len(ROOT_MODULE):]
135 return modname
136
137
138def patch_consumed_list(to_consume=None, consumed=None):
139 """
beepse19d3032013-05-30 09:22:07 -0700140 Patches the consumed modules list to ignore modules with side effects.
beeps48fc6f52013-01-07 14:36:40 -0800141
beepse19d3032013-05-30 09:22:07 -0700142 Autotest relies on importing certain modules solely for their side
143 effects. Pylint doesn't understand this and flags them as unused, since
144 they're not referenced anywhere in the code. To overcome this we need
145 to transplant said modules into the dictionary of modules pylint has
146 already seen, before pylint checks it.
beeps48fc6f52013-01-07 14:36:40 -0800147
beeps48fc6f52013-01-07 14:36:40 -0800148 @param to_consume: a dictionary of names pylint needs to see referenced.
149 @param consumed: a dictionary of names that pylint has seen referenced.
beeps48fc6f52013-01-07 14:36:40 -0800150 """
beepse19d3032013-05-30 09:22:07 -0700151 ignore_modules = []
152 if (to_consume is not None and consumed is not None):
153 ignore_modules = [module_name for module_name in _IGNORE_MODULES
154 if module_name in to_consume]
155
156 for module_name in ignore_modules:
157 consumed[module_name] = to_consume[module_name]
158 del to_consume[module_name]
beeps48fc6f52013-01-07 14:36:40 -0800159
mbligh99d2ded2008-06-23 16:17:36 +0000160
161class CustomImportsChecker(imports.ImportsChecker):
beeps48fc6f52013-01-07 14:36:40 -0800162 """Modifies stock imports checker to suit autotest."""
Ryo Hashimotod35d5632018-08-01 15:53:42 +0900163 def visit_importfrom(self, node):
Allen Li4c275d22017-07-19 11:56:24 -0700164 """Patches modnames so pylints understands autotest_lib."""
beeps48fc6f52013-01-07 14:36:40 -0800165 node.modname = patch_modname(node.modname)
Ryo Hashimotod35d5632018-08-01 15:53:42 +0900166 return super(CustomImportsChecker, self).visit_importfrom(node)
beeps48fc6f52013-01-07 14:36:40 -0800167
168
169class CustomVariablesChecker(variables.VariablesChecker):
170 """Modifies stock variables checker to suit autotest."""
171
172 def visit_module(self, node):
173 """
174 Unflag 'import common'.
175
176 _to_consume eg: [({to reference}, {referenced}, 'scope type')]
177 Enteries are appended to this list as we drill deeper in scope.
beepse19d3032013-05-30 09:22:07 -0700178 If we ever come across a module to ignore, we immediately move it
beeps48fc6f52013-01-07 14:36:40 -0800179 to the consumed list.
180
181 @param node: node of the ast we're currently checking.
182 """
183 super(CustomVariablesChecker, self).visit_module(node)
184 scoped_names = self._to_consume.pop()
Kazuhiro Inaba0e7bd162019-06-07 16:24:45 +0900185 # The type of the object has changed in pylint 1.8.2
186 if pylint_version_parsed >= (1, 8, 2):
187 patch_consumed_list(scoped_names.to_consume,scoped_names.consumed)
188 else:
189 patch_consumed_list(scoped_names[0],scoped_names[1])
beeps48fc6f52013-01-07 14:36:40 -0800190 self._to_consume.append(scoped_names)
191
Ryo Hashimotod35d5632018-08-01 15:53:42 +0900192 def visit_importfrom(self, node):
beeps48fc6f52013-01-07 14:36:40 -0800193 """Patches modnames so pylints understands autotest_lib."""
194 node.modname = patch_modname(node.modname)
Ryo Hashimotod35d5632018-08-01 15:53:42 +0900195 return super(CustomVariablesChecker, self).visit_importfrom(node)
mbligh99d2ded2008-06-23 16:17:36 +0000196
Mike Frysingercb574632019-09-20 10:43:45 -0400197 def visit_expr(self, node):
198 """
199 Flag exceptions instantiated but not used.
200
201 https://crbug.com/1005893
202 """
203 if not isinstance(node.value, astroid.Call):
204 return
205 func = node.value.func
206 try:
207 cls = next(func.infer())
208 except astroid.InferenceError:
209 return
210 if not isinstance(cls, astroid.ClassDef):
211 return
212 if any(x for x in cls.ancestors() if x.name == 'BaseException'):
213 self.add_message('W0104', node=node, line=node.fromlineno)
214
beeps2c669642013-01-14 18:30:57 -0800215
216class CustomDocStringChecker(base.DocStringChecker):
217 """Modifies stock docstring checker to suit Autotest doxygen style."""
218
beeps1b6433b2013-01-31 17:46:50 -0800219 def visit_module(self, node):
220 """
221 Don't visit imported modules when checking for docstrings.
222
223 @param node: the node we're visiting.
224 """
225 pass
226
227
Ryo Hashimotod35d5632018-08-01 15:53:42 +0900228 def visit_functiondef(self, node):
beeps98365d82013-02-20 20:08:07 -0800229 """
230 Don't request docstrings for commonly overridden autotest functions.
231
232 @param node: node of the ast we're currently checking.
233 """
beepsc38decc2013-04-29 19:42:06 -0700234
235 # Even plain functions will have a parent, which is the
236 # module they're in, and a frame, which is the context
237 # of said module; They need not however, always have
238 # ancestors.
beeps98365d82013-02-20 20:08:07 -0800239 if (node.name in ('run_once', 'initialize', 'cleanup') and
beepsc38decc2013-04-29 19:42:06 -0700240 hasattr(node.parent.frame(), 'ancestors') and
beeps98365d82013-02-20 20:08:07 -0800241 any(ancestor.name == 'base_test' for ancestor in
242 node.parent.frame().ancestors())):
243 return
244
Prathmesh Prabhua9980672017-07-13 15:52:02 -0700245 if _is_test_case_method(node):
246 return
247
Ryo Hashimotod35d5632018-08-01 15:53:42 +0900248 super(CustomDocStringChecker, self).visit_functiondef(node)
beeps98365d82013-02-20 20:08:07 -0800249
250
Chris Sosaae6acd92013-02-06 15:08:04 -0800251 @staticmethod
252 def _should_skip_arg(arg):
beeps98365d82013-02-20 20:08:07 -0800253 """
Greg Edelston4511c482020-11-02 10:31:43 -0700254 @return: True if the argument given by arg is allowlisted, and does
beeps98365d82013-02-20 20:08:07 -0800255 not require a "@param" docstring.
256 """
Chris Sosaae6acd92013-02-06 15:08:04 -0800257 return arg in ('self', 'cls', 'args', 'kwargs', 'dargs')
258
beeps2c669642013-01-14 18:30:57 -0800259base.DocStringChecker = CustomDocStringChecker
mbligh99d2ded2008-06-23 16:17:36 +0000260imports.ImportsChecker = CustomImportsChecker
beeps48fc6f52013-01-07 14:36:40 -0800261variables.VariablesChecker = CustomVariablesChecker
mbligh99d2ded2008-06-23 16:17:36 +0000262
263
beeps98365d82013-02-20 20:08:07 -0800264def batch_check_files(file_paths, base_opts):
265 """
266 Run pylint on a list of files so we get consolidated errors.
267
268 @param file_paths: a list of file paths.
269 @param base_opts: a list of pylint config options.
270
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700271 @returns pylint return code
272
beeps98365d82013-02-20 20:08:07 -0800273 @raises: pylint_error if pylint finds problems with a file
274 in this commit.
275 """
beeps12a3c882013-04-22 13:42:04 -0700276 if not file_paths:
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700277 return 0
beeps12a3c882013-04-22 13:42:04 -0700278
beeps98365d82013-02-20 20:08:07 -0800279 pylint_runner = pylint.lint.Run(list(base_opts) + list(file_paths),
280 exit=False)
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700281 return pylint_runner.linter.msg_status
beeps98365d82013-02-20 20:08:07 -0800282
283
284def should_check_file(file_path):
285 """
Greg Edelston4511c482020-11-02 10:31:43 -0700286 Don't check skiplisted or non .py files.
beeps98365d82013-02-20 20:08:07 -0800287
288 @param file_path: abs path of file to check.
Greg Edelston4511c482020-11-02 10:31:43 -0700289 @return: True if this file is a non-skiplisted python file.
beeps98365d82013-02-20 20:08:07 -0800290 """
291 file_path = os.path.abspath(file_path)
292 if file_path.endswith('.py'):
293 return all(not fnmatch.fnmatch(file_path, '*' + pattern)
Greg Edelston4511c482020-11-02 10:31:43 -0700294 for pattern in SKIPLIST)
beeps98365d82013-02-20 20:08:07 -0800295 return False
296
297
beeps48fc6f52013-01-07 14:36:40 -0800298def check_file(file_path, base_opts):
299 """
300 Invokes pylint on files after confirming that they're not black listed.
301
beeps2c669642013-01-14 18:30:57 -0800302 @param base_opts: pylint base options.
beeps48fc6f52013-01-07 14:36:40 -0800303 @param file_path: path to the file we need to run pylint on.
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700304
305 @returns pylint return code
beeps48fc6f52013-01-07 14:36:40 -0800306 """
beeps98365d82013-02-20 20:08:07 -0800307 if not isinstance(file_path, basestring):
308 raise TypeError('expected a string as filepath, got %s'%
309 type(file_path))
310
311 if should_check_file(file_path):
312 pylint_runner = pylint.lint.Run(base_opts + [file_path], exit=False)
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700313
314 return pylint_runner.linter.msg_status
315
316 return 0
mbligh99d2ded2008-06-23 16:17:36 +0000317
318
319def visit(arg, dirname, filenames):
beeps48fc6f52013-01-07 14:36:40 -0800320 """
321 Visit function invoked in check_dir.
322
323 @param arg: arg from os.walk.path
324 @param dirname: dir from os.walk.path
325 @param filenames: files in dir from os.walk.path
326 """
mbligh99d2ded2008-06-23 16:17:36 +0000327 for filename in filenames:
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700328 arg.append(os.path.join(dirname, filename))
mbligh99d2ded2008-06-23 16:17:36 +0000329
330
beeps48fc6f52013-01-07 14:36:40 -0800331def check_dir(dir_path, base_opts):
332 """
333 Calls visit on files in dir_path.
334
beeps2c669642013-01-14 18:30:57 -0800335 @param base_opts: pylint base options.
beeps48fc6f52013-01-07 14:36:40 -0800336 @param dir_path: path to directory.
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700337
338 @returns pylint return code
beeps48fc6f52013-01-07 14:36:40 -0800339 """
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700340 files = []
341
342 os.path.walk(dir_path, visit, files)
343
344 return batch_check_files(files, base_opts)
mbligh99d2ded2008-06-23 16:17:36 +0000345
346
beeps48fc6f52013-01-07 14:36:40 -0800347def extend_baseopts(base_opts, new_opt):
348 """
349 Replaces an argument in base_opts with a cmd line argument.
350
351 @param base_opts: original pylint_base_opts.
352 @param new_opt: new cmd line option.
353 """
354 for args in base_opts:
355 if new_opt in args:
356 base_opts.remove(args)
357 base_opts.append(new_opt)
358
359
360def get_cmdline_options(args_list, pylint_base_opts, rcfile):
361 """
362 Parses args_list and extends pylint_base_opts.
363
364 Command line arguments might include options mixed with files.
365 Go through this list and filter out the options, if the options are
366 specified in the pylintrc file we cannot replace them and the file
367 needs to be edited. If the options are already a part of
368 pylint_base_opts we replace them, and if not we append to
369 pylint_base_opts.
370
371 @param args_list: list of files/pylint args passed in through argv.
372 @param pylint_base_opts: default pylint options.
373 @param rcfile: text from pylint_rc.
374 """
375 for args in args_list:
376 if args.startswith('--'):
377 opt_name = args[2:].split('=')[0]
Raul E Rangeld214c092019-01-30 16:48:43 -0700378 extend_baseopts(pylint_base_opts, args)
379 args_list.remove(args)
beeps48fc6f52013-01-07 14:36:40 -0800380
beeps98365d82013-02-20 20:08:07 -0800381
382def git_show_to_temp_file(commit, original_file, new_temp_file):
383 """
384 'Git shows' the file in original_file to a tmp file with
385 the name new_temp_file. We need to preserve the filename
386 as it gets reflected in pylints error report.
387
388 @param commit: commit hash of the commit we're running repo upload on.
389 @param original_file: the path to the original file we'd like to run
390 'git show' on.
391 @param new_temp_file: new_temp_file is the path to a temp file we write the
392 output of 'git show' into.
393 """
394 git_repo = revision_control.GitRepo(common.autotest_dir, None, None,
395 common.autotest_dir)
396
397 with open(new_temp_file, 'w') as f:
398 output = git_repo.gitcmd('show --no-ext-diff %s:%s'
399 % (commit, original_file),
400 ignore_status=False).stdout
401 f.write(output)
402
403
404def check_committed_files(work_tree_files, commit, pylint_base_opts):
405 """
406 Get a list of files corresponding to the commit hash.
407
408 The contents of a file in the git work tree can differ from the contents
409 of a file in the commit we mean to upload. To work around this we run
410 pylint on a temp file into which we've 'git show'n the committed version
411 of each file.
412
413 @param work_tree_files: list of files in this commit specified by their
414 absolute path.
415 @param commit: hash of the commit this upload applies to.
416 @param pylint_base_opts: a list of pylint config options.
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700417
418 @returns pylint return code
beeps98365d82013-02-20 20:08:07 -0800419 """
420 files_to_check = filter(should_check_file, work_tree_files)
421
422 # Map the absolute path of each file so it's relative to the autotest repo.
423 # All files that are a part of this commit should have an abs path within
424 # the autotest repo, so this regex should never fail.
425 work_tree_files = [re.search(r'%s/(.*)' % common.autotest_dir, f).group(1)
426 for f in files_to_check]
427
428 tempdir = None
429 try:
430 tempdir = autotemp.tempdir()
431 temp_files = [os.path.join(tempdir.name, file_path.split('/')[-1:][0])
432 for file_path in work_tree_files]
433
434 for file_tuple in zip(work_tree_files, temp_files):
435 git_show_to_temp_file(commit, *file_tuple)
436 # Only check if we successfully git showed all files in the commit.
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700437 return batch_check_files(temp_files, pylint_base_opts)
beeps98365d82013-02-20 20:08:07 -0800438 finally:
439 if tempdir:
440 tempdir.clean()
441
442
Prathmesh Prabhua9980672017-07-13 15:52:02 -0700443def _is_test_case_method(node):
444 """Determine if the given function node is a method of a TestCase.
445
446 We simply check for 'TestCase' being one of the parent classes in the mro of
447 the containing class.
448
449 @params node: A function node.
450 """
451 if not hasattr(node.parent.frame(), 'ancestors'):
452 return False
453
454 parent_class_names = {x.name for x in node.parent.frame().ancestors()}
455 return 'TestCase' in parent_class_names
456
457
beeps48fc6f52013-01-07 14:36:40 -0800458def main():
459 """Main function checks each file in a commit for pylint violations."""
460
beeps1b6433b2013-01-31 17:46:50 -0800461 # For now all error/warning/refactor/convention exceptions except those in
462 # the enable string are disabled.
463 # W0611: All imported modules (except common) need to be used.
464 # W1201: Logging methods should take the form
465 # logging.<loggingmethod>(format_string, format_args...); and not
466 # logging.<loggingmethod>(format_string % (format_args...))
467 # C0111: Docstring needed. Also checks @param for each arg.
468 # C0112: Non-empty Docstring needed.
beeps48fc6f52013-01-07 14:36:40 -0800469 # Ideally we would like to enable as much as we can, but if we did so at
470 # this stage anyone who makes a tiny change to a file will be tasked with
471 # cleaning all the lint in it. See chromium-os:37364.
472
beepse19d3032013-05-30 09:22:07 -0700473 # Note:
474 # 1. There are three major sources of E1101/E1103/E1120 false positives:
475 # * common_lib.enum.Enum objects
476 # * DB model objects (scheduler models are the worst, but Django models
477 # also generate some errors)
478 # 2. Docstrings are optional on private methods, and any methods that begin
479 # with either 'set_' or 'get_'.
beeps48fc6f52013-01-07 14:36:40 -0800480 pylint_rc = os.path.join(os.path.dirname(os.path.abspath(__file__)),
481 'pylintrc')
beepse19d3032013-05-30 09:22:07 -0700482
483 no_docstring_rgx = r'((_.*)|(set_.*)|(get_.*))'
Kazuhiro Inaba0e7bd162019-06-07 16:24:45 +0900484 if pylint_version_parsed >= (0, 21):
beeps48fc6f52013-01-07 14:36:40 -0800485 pylint_base_opts = ['--rcfile=%s' % pylint_rc,
486 '--reports=no',
beeps55532562013-01-16 12:13:46 -0800487 '--disable=W,R,E,C,F',
Mike Frysingercb574632019-09-20 10:43:45 -0400488 '--enable=W0104,W0611,W1201,C0111,C0112,E0602,'
489 'W0601,E0633',
beepse19d3032013-05-30 09:22:07 -0700490 '--no-docstring-rgx=%s' % no_docstring_rgx,]
beeps48fc6f52013-01-07 14:36:40 -0800491 else:
492 all_failures = 'error,warning,refactor,convention'
493 pylint_base_opts = ['--disable-msg-cat=%s' % all_failures,
494 '--reports=no',
495 '--include-ids=y',
beeps1b6433b2013-01-31 17:46:50 -0800496 '--ignore-docstrings=n',
beepse19d3032013-05-30 09:22:07 -0700497 '--no-docstring-rgx=%s' % no_docstring_rgx,]
beeps48fc6f52013-01-07 14:36:40 -0800498
499 # run_pylint can be invoked directly with command line arguments,
500 # or through a presubmit hook which uses the arguments in pylintrc. In the
501 # latter case no command line arguments are passed. If it is invoked
502 # directly without any arguments, it should check all files in the cwd.
503 args_list = sys.argv[1:]
504 if args_list:
505 get_cmdline_options(args_list,
506 pylint_base_opts,
507 open(pylint_rc).read())
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700508 return batch_check_files(args_list, pylint_base_opts)
beeps98365d82013-02-20 20:08:07 -0800509 elif os.environ.get('PRESUBMIT_FILES') is not None:
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700510 return check_committed_files(
beeps98365d82013-02-20 20:08:07 -0800511 os.environ.get('PRESUBMIT_FILES').split('\n'),
512 os.environ.get('PRESUBMIT_COMMIT'),
513 pylint_base_opts)
beeps48fc6f52013-01-07 14:36:40 -0800514 else:
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700515 return check_dir('.', pylint_base_opts)
beeps48fc6f52013-01-07 14:36:40 -0800516
517
518if __name__ == '__main__':
Prashanth Balasubramanianbaabef22014-11-04 12:38:44 -0800519 try:
Raul E Rangel67d9cfc2019-01-30 16:28:16 -0700520 ret = main()
521
522 sys.exit(ret)
Prathmesh Prabhu7e107082017-01-11 17:16:41 -0800523 except pylint_error as e:
Prashanth Balasubramanianbaabef22014-11-04 12:38:44 -0800524 logging.error(e)
525 sys.exit(1)