1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Linter to verify that all flags reported by GHC's --show-options mode
are documented in the user's guide.
"""
import sys
import subprocess
from typing import Set
from pathlib import Path
# A list of known-undocumented flags. This should be considered to be a to-do
# list of flags that need to be documented.
EXPECTED_UNDOCUMENTED_PATH = \
Path(__file__).parent / 'expected-undocumented-flags.txt'
EXPECTED_UNDOCUMENTED = \
{line for line in EXPECTED_UNDOCUMENTED_PATH.read_text().split()}
def expected_undocumented(flag: str) -> bool:
if flag in EXPECTED_UNDOCUMENTED:
return True
if flag.startswith('-Werror'):
return True
if flag.startswith('-Wno-') \
or flag.startswith('-dno') \
or flag.startswith('-fno') \
or flag.startswith('-XNo'):
return True
if flag.startswith('-Wwarn=') \
or flag.startswith('-Wno-warn='):
return True
return False
def read_documented_flags(doc_flags) -> Set[str]:
# Map characters that mark the end of a flag
# to whitespace.
trans = str.maketrans({
'=': ' ',
'[': ' ',
'⟨': ' ',
})
return {line.translate(trans).split()[0]
for line in doc_flags.read().split('\n')
if line != ''}
def read_ghc_flags(ghc_path: str) -> Set[str]:
ghc_output = subprocess.check_output([ghc_path, '--show-options'])
ghci_output = subprocess.check_output([ghc_path, '--interactive', '--show-options'])
return {flag
for flag in ghc_output.decode('UTF-8').splitlines() +
ghci_output.decode('UTF-8').splitlines()
if not expected_undocumented(flag)
if flag != ''}
def error(s: str):
print(s, file=sys.stderr)
def main() -> None:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--ghc', type=argparse.FileType('r'),
help='path of GHC executable',
required=True)
parser.add_argument('--doc-flags', type=argparse.FileType(mode='r', encoding='UTF-8'),
help='path of ghc-flags.txt output from Sphinx',
required=True)
args = parser.parse_args()
doc_flags = read_documented_flags(args.doc_flags)
ghc_flags = read_ghc_flags(args.ghc.name)
failed = False
undocumented = ghc_flags - doc_flags
if len(undocumented) > 0:
error('Found {len_undoc} flags not documented in the users guide:'.format(len_undoc=len(undocumented)), )
error('\n'.join(' {}'.format(flag) for flag in sorted(undocumented)))
error('')
failed = True
now_documented = EXPECTED_UNDOCUMENTED.intersection(doc_flags)
if len(now_documented) > 0:
error('Found flags that are documented yet listed in {}:'.format(EXPECTED_UNDOCUMENTED_PATH))
error('\n'.join(' {}'.format(flag) for flag in sorted(now_documented)))
error('')
failed = True
if failed:
sys.exit(1)
if __name__ == '__main__':
main()
|