# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Runs the validator of Web IDL files using web_idl.Database.
"""
import optparse
import sys
import validator
import validator.rules
import web_idl
def parse_options():
parser = optparse.OptionParser()
parser.add_option("--web_idl_database",
type="string",
help="filepath of the input database")
parser.add_option("--idl_syntax_known_issues",
type="string",
help="filepath of the idl errors already known")
parser.add_option("--output",
type="string",
help="filepath of the file for the purpose of timestamp")
options, args = parser.parse_args()
required_option_names = [
"web_idl_database",
"idl_syntax_known_issues",
]
for required_option_name in required_option_names:
if getattr(options, required_option_name) is None:
parser.error(
"--{} is a required option.".format(required_option_name))
return options, args
def create_known_issues(filepath):
known_issues = {}
with open(filepath) as file_obj:
for line_number, line in enumerate(file_obj):
comment_start = line.find("#")
if comment_start != -1:
line = line[:comment_start]
blocks = line.split()
if not blocks:
continue
assert len(blocks) == 2, (
"{}: {}\n"
"A line should have exactly 2 items, "
"RULE_NAME and DOTTED_IDL_NAME (except for a comment with '#')"
.format(filepath, line_number + 1))
rule_name = blocks[0]
target_path = blocks[1]
known_issues.setdefault(target_path, []).append(rule_name)
return known_issues
def should_suppress_error(known_issues, rule, target_path):
return rule.__class__.__name__ in known_issues.get(target_path, [])
def main():
options, args = parse_options()
known_issues = create_known_issues(options.idl_syntax_known_issues)
error_counts = [0]
skipped_error_counts = [0]
def report_error(rule, target, target_type, error_message):
error_counts[0] += 1
target_path = target_type.get_target_path(target)
if should_suppress_error(known_issues, rule, target_path):
skipped_error_counts[0] += 1
else:
debug_infos = target_type.get_debug_info_list(target)
sys.stderr.write("violated rule: {}\n".format(
rule.__class__.__name__))
sys.stderr.write("target path : {}\n".format(target_path))
for i, debug_info in enumerate(debug_infos):
if i == 0:
sys.stderr.write("related files: {}\n".format(
str(debug_info.location)))
else:
sys.stderr.write(" {}\n".format(
str(debug_info.location)))
sys.stderr.write("error message: {}\n\n".format(error_message))
# Register rules
rule_store = validator.RuleStore()
validator.rules.register_all_rules(rule_store)
# Validate
database = web_idl.file_io.read_pickle_file(options.web_idl_database)
validator_instance = validator.Validator(database)
validator_instance.execute(rule_store, report_error)
# Report errors
if error_counts[0] - skipped_error_counts[0] > 0:
sys.exit("Error: Some IDL files violate the Web IDL rules")
# Create a file for the purpose of timestamp of a successful completion.
if options.output:
with open(options.output, mode="w") as file_obj:
file_obj.write("""\
# This file was created just for the purpose of timestamp of a successful
# completion, mainly in order to corporate with a build system.
""")
file_obj.write("Command line arguments:\n")
file_obj.write(" --web_idl_database = {}\n".format(
options.web_idl_database))
file_obj.write(" --idl_syntax_known_issues = {}\n".format(
options.idl_syntax_known_issues))
file_obj.write("Results:\n No new error\n")
if __name__ == '__main__':
main()