xref: /openbmc/qemu/tests/qemu-iotests/297 (revision a4bde736295bd0951005d7292b99086825f74f8a)
159aec869SMax Reitz#!/usr/bin/env python3
29dd003a9SVladimir Sementsov-Ogievskiy# group: meta
319b7868eSKevin Wolf#
419b7868eSKevin Wolf# Copyright (C) 2020 Red Hat, Inc.
519b7868eSKevin Wolf#
619b7868eSKevin Wolf# This program is free software; you can redistribute it and/or modify
719b7868eSKevin Wolf# it under the terms of the GNU General Public License as published by
819b7868eSKevin Wolf# the Free Software Foundation; either version 2 of the License, or
919b7868eSKevin Wolf# (at your option) any later version.
1019b7868eSKevin Wolf#
1119b7868eSKevin Wolf# This program is distributed in the hope that it will be useful,
1219b7868eSKevin Wolf# but WITHOUT ANY WARRANTY; without even the implied warranty of
1319b7868eSKevin Wolf# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1419b7868eSKevin Wolf# GNU General Public License for more details.
1519b7868eSKevin Wolf#
1619b7868eSKevin Wolf# You should have received a copy of the GNU General Public License
1719b7868eSKevin Wolf# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1819b7868eSKevin Wolf
1959aec869SMax Reitzimport os
2059aec869SMax Reitzimport re
2159aec869SMax Reitzimport shutil
2259aec869SMax Reitzimport subprocess
2359aec869SMax Reitzimport sys
242d804f55SJohn Snowfrom typing import List, Mapping, Optional
2519b7868eSKevin Wolf
2659aec869SMax Reitzimport iotests
2719b7868eSKevin Wolf
2819b7868eSKevin Wolf
2959aec869SMax Reitz# TODO: Empty this list!
3059aec869SMax ReitzSKIP_FILES = (
3159aec869SMax Reitz    '030', '040', '041', '044', '045', '055', '056', '057', '065', '093',
32636aa64dSMax Reitz    '096', '118', '124', '132', '136', '139', '147', '148', '149',
3326db7b23SHanna Reitz    '151', '152', '155', '163', '165', '194', '196', '202',
3459aec869SMax Reitz    '203', '205', '206', '207', '208', '210', '211', '212', '213', '216',
35f08ef043SVladimir Sementsov-Ogievskiy    '218', '219', '224', '228', '234', '235', '236', '237', '238',
3659aec869SMax Reitz    '240', '242', '245', '246', '248', '255', '256', '257', '258', '260',
3759aec869SMax Reitz    '262', '264', '266', '274', '277', '280', '281', '295', '296', '298',
3859c9466dSMax Reitz    '299', '302', '303', '304', '307',
3959aec869SMax Reitz    'nbd-fault-injector.py', 'qcow2.py', 'qcow2_format.py', 'qed.py'
4059aec869SMax Reitz)
4119b7868eSKevin Wolf
4219b7868eSKevin Wolf
4359aec869SMax Reitzdef is_python_file(filename):
4459aec869SMax Reitz    if not os.path.isfile(filename):
4559aec869SMax Reitz        return False
4619b7868eSKevin Wolf
4759aec869SMax Reitz    if filename.endswith('.py'):
4859aec869SMax Reitz        return True
4959aec869SMax Reitz
5081dcb9caSHanna Reitz    with open(filename, encoding='utf-8') as f:
5159aec869SMax Reitz        try:
5259aec869SMax Reitz            first_line = f.readline()
5359aec869SMax Reitz            return re.match('^#!.*python', first_line) is not None
5459aec869SMax Reitz        except UnicodeDecodeError:  # Ignore binary files
5559aec869SMax Reitz            return False
5659aec869SMax Reitz
5759aec869SMax Reitz
583c1d5012SJohn Snowdef get_test_files() -> List[str]:
59098d983eSHanna Reitz    named_tests = [f'tests/{entry}' for entry in os.listdir('tests')]
60098d983eSHanna Reitz    check_tests = set(os.listdir('.') + named_tests) - set(SKIP_FILES)
613c1d5012SJohn Snow    return list(filter(is_python_file, check_tests))
623c1d5012SJohn Snow
633c1d5012SJohn Snow
64*a4bde736SJohn Snowdef run_linter(
65*a4bde736SJohn Snow        tool: str,
66*a4bde736SJohn Snow        args: List[str],
672d804f55SJohn Snow        env: Optional[Mapping[str, str]] = None,
68*a4bde736SJohn Snow        suppress_output: bool = False,
692d804f55SJohn Snow) -> None:
70*a4bde736SJohn Snow    """
71*a4bde736SJohn Snow    Run a python-based linting tool.
7259aec869SMax Reitz
73*a4bde736SJohn Snow    If suppress_output is True, capture stdout/stderr of the child
74*a4bde736SJohn Snow    process and only print that information back to stdout if the child
75*a4bde736SJohn Snow    process's return code was non-zero.
76*a4bde736SJohn Snow    """
77*a4bde736SJohn Snow    p = subprocess.run(
78*a4bde736SJohn Snow        ('python3', '-m', tool, *args),
7959aec869SMax Reitz        env=env,
8059aec869SMax Reitz        check=False,
81*a4bde736SJohn Snow        stdout=subprocess.PIPE if suppress_output else None,
82*a4bde736SJohn Snow        stderr=subprocess.STDOUT if suppress_output else None,
83*a4bde736SJohn Snow        universal_newlines=True,
84*a4bde736SJohn Snow    )
8559aec869SMax Reitz
86*a4bde736SJohn Snow    if suppress_output and p.returncode != 0:
8759aec869SMax Reitz        print(p.stdout)
8859aec869SMax Reitz
8959aec869SMax Reitz
90447aebdaSJohn Snowdef main() -> None:
9159aec869SMax Reitz    for linter in ('pylint-3', 'mypy'):
9259aec869SMax Reitz        if shutil.which(linter) is None:
9359aec869SMax Reitz            iotests.notrun(f'{linter} not found')
9459aec869SMax Reitz
952d804f55SJohn Snow    files = get_test_files()
962d804f55SJohn Snow
972d804f55SJohn Snow    iotests.logger.debug('Files to be checked:')
982d804f55SJohn Snow    iotests.logger.debug(', '.join(sorted(files)))
992d804f55SJohn Snow
1002d804f55SJohn Snow    env = os.environ.copy()
1012d804f55SJohn Snow    env['MYPYPATH'] = env['PYTHONPATH']
1022d804f55SJohn Snow
1032d804f55SJohn Snow    print('=== pylint ===')
1042d804f55SJohn Snow    sys.stdout.flush()
105*a4bde736SJohn Snow    run_linter('pylint', files, env=env)
1062d804f55SJohn Snow
1072d804f55SJohn Snow    print('=== mypy ===')
1082d804f55SJohn Snow    sys.stdout.flush()
109*a4bde736SJohn Snow    run_linter('mypy', files, env=env, suppress_output=True)
110447aebdaSJohn Snow
111447aebdaSJohn Snow
112447aebdaSJohn Snowiotests.script_main(main)
113