Changeset View
Changeset View
Standalone View
Standalone View
test/lint/check-doc.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2015-2016 The Bitcoin Core developers | # Copyright (c) 2015-2016 The Bitcoin Core developers | ||||
# Copyright (c) 2019 The Bitcoin developers | # Copyright (c) 2019 The Bitcoin developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
''' | ''' | ||||
This checks if all command line args are documented. | This checks if all command line args are documented. | ||||
Return value is 0 to indicate no error. | Return value is 0 to indicate no error. | ||||
Author: @MarcoFalke | Author: @MarcoFalke | ||||
''' | ''' | ||||
from subprocess import check_output | from subprocess import check_output | ||||
from pprint import PrettyPrinter | from pprint import PrettyPrinter | ||||
import glob | |||||
import re | import re | ||||
FOLDER_SRC = 'src' | TOP_LEVEL = 'git rev-parse --show-toplevel' | ||||
FOLDER_TEST = 'test' | FOLDER_SRC = '/src/**/' | ||||
PATH_SRC = '`git rev-parse --show-toplevel`/{}'.format(FOLDER_SRC) | FOLDER_TEST = '/src/**/test/' | ||||
EXTENSIONS = ["*.c", "*.h", "*.cpp", "*.cc", "*.hpp"] | |||||
REGEX_ARG = '(?:ForceSet|SoftSet|Get|Is)(?:Bool)?Args?(?:Set)?\(\s*"(-[^"]+)"' | REGEX_ARG = '(?:ForceSet|SoftSet|Get|Is)(?:Bool)?Args?(?:Set)?\(\s*"(-[^"]+)"' | ||||
REGEX_DOC = 'HelpMessageOpt\(\s*"(-[^"=]+?)(?:=|")' | REGEX_DOC = 'HelpMessageOpt\(\s*"(-[^"=]+?)(?:=|")' | ||||
CMD_GREP_ARGS_SRC = r"grep -rIPzo '{}' {} --exclude-dir={}".format( | |||||
REGEX_ARG, PATH_SRC, FOLDER_TEST) | |||||
CMD_GREP_DOCS = r"grep -rIPzo '{}' {}".format(REGEX_DOC, PATH_SRC) | |||||
# list unsupported, deprecated and duplicate args as they need no documentation | # list unsupported, deprecated and duplicate args as they need no documentation | ||||
SET_DOC_OPTIONAL = set(['-benchmark', | SET_DOC_OPTIONAL = set(['-benchmark', | ||||
'-blockminsize', | '-blockminsize', | ||||
'-dbcrashratio', | '-dbcrashratio', | ||||
'-debugnet', | '-debugnet', | ||||
'-forcecompactdb', | '-forcecompactdb', | ||||
# TODO remove after the may 2019 fork | # TODO remove after the may 2019 fork | ||||
'-greatwallactivationtime', | '-greatwallactivationtime', | ||||
Show All 11 Lines | |||||
SET_FALSE_POSITIVE_UNKNOWNS = set(['-nodebug', | SET_FALSE_POSITIVE_UNKNOWNS = set(['-nodebug', | ||||
'-zmqpubhashblock', | '-zmqpubhashblock', | ||||
'-zmqpubhashtx', | '-zmqpubhashtx', | ||||
'-zmqpubrawblock', | '-zmqpubrawblock', | ||||
'-zmqpubrawtx']) | '-zmqpubrawtx']) | ||||
def main(): | def main(): | ||||
used = check_output(CMD_GREP_ARGS_SRC, shell=True).decode() | top_level = check_output(TOP_LEVEL, shell=True).decode().strip() | ||||
docd = check_output(CMD_GREP_DOCS, shell=True).decode() | source_files = [] | ||||
test_files = [] | |||||
for extension in EXTENSIONS: | |||||
source_files += glob.glob(top_level + | |||||
FOLDER_SRC + extension, recursive=True) | |||||
test_files += glob.glob(top_level + FOLDER_TEST + | |||||
extension, recursive=True) | |||||
files = set(source_files) - set(test_files) | |||||
args_used = set() | |||||
args_docd = set() | |||||
for file in files: | |||||
with open(file, 'r') as f: | |||||
content = f.read() | |||||
args_used |= set(re.findall(re.compile(REGEX_ARG), content)) | |||||
args_docd |= set(re.findall(re.compile(REGEX_DOC), content)) | |||||
args_used = set(re.findall(REGEX_ARG, used)) | |||||
args_used |= SET_FALSE_POSITIVE_UNKNOWNS | args_used |= SET_FALSE_POSITIVE_UNKNOWNS | ||||
args_docd = set(re.findall(REGEX_DOC, docd)) | |||||
args_need_doc = args_used - args_docd - SET_DOC_OPTIONAL | args_need_doc = args_used - args_docd - SET_DOC_OPTIONAL | ||||
args_unknown = args_docd - args_used | args_unknown = args_docd - args_used | ||||
pp = PrettyPrinter() | pp = PrettyPrinter() | ||||
print("Args used : {}".format(len(args_used))) | print("Args used : {}".format(len(args_used))) | ||||
print("Args documented : {}".format(len(args_docd))) | print("Args documented : {}".format(len(args_docd))) | ||||
print("Args undocumented: {} ({} don't need documentation)".format( | print("Args undocumented: {} ({} don't need documentation)".format( | ||||
len(args_need_doc), len(SET_DOC_OPTIONAL))) | len(args_need_doc), len(SET_DOC_OPTIONAL))) | ||||
pp.pprint(args_need_doc) | pp.pprint(args_need_doc) | ||||
print("Args unknown : {}".format(len(args_unknown))) | print("Args unknown : {}".format(len(args_unknown))) | ||||
pp.pprint(args_unknown) | pp.pprint(args_unknown) | ||||
if __name__ == "__main__": | if __name__ == "__main__": | ||||
main() | main() |