From 55ba434ecb12b9683240ff8d45298a4525c1ac26 Mon Sep 17 00:00:00 2001 From: Tim Abbott Date: Sat, 4 Aug 2018 14:33:19 -0700 Subject: [PATCH] zulint: Extract LinterConfig class to zulint. --- tools/lint | 79 ++++++++++------------------------------- tools/zulint/command.py | 59 +++++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 66 deletions(-) diff --git a/tools/lint b/tools/lint index efb9490d6d..820f17bb29 100755 --- a/tools/lint +++ b/tools/lint @@ -5,16 +5,13 @@ import logging import os import sys import argparse -import subprocess - -from linter_lib.printer import print_err, colors # check for the venv from lib import sanity_check sanity_check.check_venv(__file__) from zulint import lister -from zulint.command import add_default_linter_arguments, do_lint +from zulint.command import add_default_linter_arguments, LinterConfig from typing import cast, Callable, Dict, Iterator, List @@ -87,87 +84,47 @@ def run(): check_custom_checks_py, check_custom_checks_nonpy = build_custom_checkers(by_lang) - lint_functions = {} # type: Dict[str, Callable[[], int]] - - def lint(func): - # type: (Callable[[], int]) -> Callable[[], int] - lint_functions[func.__name__] = func - return func - - def external_linter(name, command, target_langs=[]): - # type: (str, List[str], List[str]) -> None - """Registers an external linter program to be run as part of the - linter. This program will be passed the subset of files being - linted that have extensions in target_langs. If there are no - such files, exits without doing anything. - - If target_langs is empty, just runs the linter unconditionally. - """ - color = next(colors) - - def run_linter(): - # type: () -> int - targets = [] # type: List[str] - if len(target_langs) != 0: - targets = [target for lang in target_langs for target in by_lang[lang]] - if len(targets) == 0: - # If this linter has a list of languages, and - # no files in those languages are to be checked, - # then we can safely return success without - # invoking the external linter. - return 0 - - p = subprocess.Popen(command + targets, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - - assert p.stdout # use of subprocess.PIPE indicates non-None - for line in iter(p.stdout.readline, b''): - print_err(name, color, line) - - return p.wait() # Linter exit code - - lint_functions[name] = run_linter - - external_linter('add_class', ['tools/find-add-class'], ['js']) - external_linter('css', ['node', 'node_modules/.bin/stylelint'], ['css', 'scss']) - external_linter('eslint', ['node', 'node_modules/.bin/eslint', '--quiet', '--cache'], ['js']) - external_linter('tslint', ['node', 'node_modules/.bin/tslint', '-c', - 'static/ts/tslint.json'], ['ts']) - external_linter('puppet', ['puppet', 'parser', 'validate'], ['pp']) - external_linter('templates', ['tools/check-templates'], ['handlebars', 'html']) - external_linter('urls', ['tools/check-urls'], ['py']) - external_linter('swagger', ['node', 'tools/check-swagger'], ['yaml']) + linter_config = LinterConfig(by_lang) + linter_config.external_linter('add_class', ['tools/find-add-class'], ['js']) + linter_config.external_linter('css', ['node', 'node_modules/.bin/stylelint'], ['css', 'scss']) + linter_config.external_linter('eslint', ['node', 'node_modules/.bin/eslint', + '--quiet', '--cache'], ['js']) + linter_config.external_linter('tslint', ['node', 'node_modules/.bin/tslint', '-c', + 'static/ts/tslint.json'], ['ts']) + linter_config.external_linter('puppet', ['puppet', 'parser', 'validate'], ['pp']) + linter_config.external_linter('templates', ['tools/check-templates'], ['handlebars', 'html']) + linter_config.external_linter('urls', ['tools/check-urls'], ['py']) + linter_config.external_linter('swagger', ['node', 'tools/check-swagger'], ['yaml']) # Disabled check for imperative mood until it is stabilized if not args.no_gitlint: - external_linter('commit_messages', ['tools/commit-message-lint']) + linter_config.external_linter('commit_messages', ['tools/commit-message-lint']) - @lint + @linter_config.lint def custom_py(): # type: () -> int failed = check_custom_checks_py() return 1 if failed else 0 - @lint + @linter_config.lint def custom_nonpy(): # type: () -> int failed = check_custom_checks_nonpy() return 1 if failed else 0 - @lint + @linter_config.lint def pyflakes(): # type: () -> int failed = check_pyflakes(args, by_lang) return 1 if failed else 0 - @lint + @linter_config.lint def pep8(): # type: () -> int failed = check_pep8(by_lang['py']) return 1 if failed else 0 - do_lint(lint_functions) + linter_config.do_lint() if __name__ == '__main__': run() diff --git a/tools/zulint/command.py b/tools/zulint/command.py index b71f6965eb..1e38891d42 100644 --- a/tools/zulint/command.py +++ b/tools/zulint/command.py @@ -6,9 +6,11 @@ from __future__ import absolute_import import argparse import logging import os +import subprocess import sys +from typing import Any, Callable, Dict, List, Optional -from typing import Any, Callable, Dict, List +from linter_lib.printer import print_err, colors def add_default_linter_arguments(parser): # type: (argparse.ArgumentParser) -> None @@ -43,7 +45,54 @@ def run_parallel(lint_functions): failed = True return failed -def do_lint(lint_functions): - # type: (Dict[str, Callable[[], int]]) -> None - failed = run_parallel(lint_functions) - sys.exit(1 if failed else 0) +class LinterConfig: + lint_functions = {} # type: Dict[str, Callable[[], int]] + + def __init__(self, by_lang): + # type: (Any) -> None + self.by_lang = by_lang + + def lint(self, func): + # type: (Callable[[], int]) -> Callable[[], int] + self.lint_functions[func.__name__] = func + return func + + def external_linter(self, name, command, target_langs=[]): + # type: (str, List[str], List[str]) -> None + """Registers an external linter program to be run as part of the + linter. This program will be passed the subset of files being + linted that have extensions in target_langs. If there are no + such files, exits without doing anything. + + If target_langs is empty, just runs the linter unconditionally. + """ + color = next(colors) + + def run_linter(): + # type: () -> int + targets = [] # type: List[str] + if len(target_langs) != 0: + targets = [target for lang in target_langs for target in self.by_lang[lang]] + if len(targets) == 0: + # If this linter has a list of languages, and + # no files in those languages are to be checked, + # then we can safely return success without + # invoking the external linter. + return 0 + + p = subprocess.Popen(command + targets, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + assert p.stdout # use of subprocess.PIPE indicates non-None + for line in iter(p.stdout.readline, b''): + print_err(name, color, line) + + return p.wait() # Linter exit code + + self.lint_functions[name] = run_linter + + def do_lint(self): + # type: () -> None + failed = run_parallel(self.lint_functions) + sys.exit(1 if failed else 0)