Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 1 | #!/usr/bin/python -i |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 2 | |
| 3 | import sys |
Mark Lobodzinski | 8c9633d | 2017-06-05 13:50:10 -0600 | [diff] [blame] | 4 | try: |
| 5 | import urllib.request as urllib2 |
| 6 | except ImportError: |
| 7 | import urllib2 |
Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 8 | from bs4 import BeautifulSoup |
Tobin Ehlis | 98d109a | 2017-05-11 14:42:38 -0600 | [diff] [blame] | 9 | import json |
| 10 | import vuid_mapping |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 11 | |
| 12 | ############################# |
| 13 | # spec.py script |
| 14 | # |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 15 | # Overview - this script is intended to generate validation error codes and message strings from the json spec file |
| 16 | # that contains all of the valid usage statements. In addition to generating the header file, it provides a number of |
| 17 | # corrollary services to aid in generating/updating the header. |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 18 | # |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 19 | # Ideal flow - Pull the valid usage text and IDs from the spec json, pull the IDs from the validation error database, |
| 20 | # then update the database with any new IDs from the json file and generate new database and header file. |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 21 | # |
| 22 | # TODO: |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 23 | # 1. When VUs go away (in error DB, but not in json) need to report them and remove from DB as deleted |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 24 | # |
| 25 | ############################# |
| 26 | |
| 27 | |
Mark Lobodzinski | e3787b4 | 2017-06-21 13:41:00 -0600 | [diff] [blame] | 28 | out_filename = "../layers/vk_validation_error_messages.h" # can override w/ '-out <filename>' option |
| 29 | db_filename = "../layers/vk_validation_error_database.txt" # can override w/ '-gendb <filename>' option |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 30 | json_filename = None # con pass in w/ '-json <filename> option |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 31 | gen_db = False # set to True when '-gendb <filename>' option provided |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 32 | json_compare = False # compare existing DB to json file input |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 33 | json_url = "https://www.khronos.org/registry/vulkan/specs/1.0-extensions/validation/validusage.json" |
| 34 | read_json = False |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 35 | # This is the root spec link that is used in error messages to point users to spec sections |
Tobin Ehlis | bd0a9c6 | 2016-10-14 18:06:16 -0600 | [diff] [blame] | 36 | #old_spec_url = "https://www.khronos.org/registry/vulkan/specs/1.0/xhtml/vkspec.html" |
Tobin Ehlis | a55b1d4 | 2017-04-04 12:23:48 -0600 | [diff] [blame] | 37 | spec_url = "https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html" |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 38 | core_url = "https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html" |
| 39 | ext_url = "https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html" |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 40 | # After the custom validation error message, this is the prefix for the standard message that includes the |
| 41 | # spec valid usage language as well as the link to nearest section of spec to that language |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 42 | error_msg_prefix = "The spec valid usage text states " |
Mark Lobodzinski | 629d47b | 2016-10-18 13:34:58 -0600 | [diff] [blame] | 43 | validation_error_enum_name = "VALIDATION_ERROR_" |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 44 | |
| 45 | def printHelp(): |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 46 | print ("Usage: python spec.py [-out <headerfile.h>] [-gendb <databasefile.txt>] [-update] [-json <json_file>] [-help]") |
Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 47 | print ("\n Default script behavior is to parse the specfile and generate a header of unique error enums and corresponding error messages based on the specfile.\n") |
| 48 | print (" Default specfile is from online at %s" % (spec_url)) |
| 49 | print (" Default headerfile is %s" % (out_filename)) |
| 50 | print (" Default databasefile is %s" % (db_filename)) |
| 51 | print ("\nIf '-gendb' option is specified then a database file is generated to default file or <databasefile.txt> if supplied. The database file stores") |
| 52 | print (" the list of enums and their error messages.") |
Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 53 | print ("\nIf '-update' option is specified this triggers the master flow to automate updating header and database files using default db file as baseline") |
| 54 | print (" and online spec file as the latest. The default header and database files will be updated in-place for review and commit to the git repo.") |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 55 | print ("\nIf '-json' option is used trigger the script to load in data from a json file.") |
| 56 | print ("\nIf '-json-file' option is it will point to a local json file, else '%s' is used from the web." % (json_url)) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 57 | |
Tobin Ehlis | 3c37fb3 | 2017-05-24 09:31:13 -0600 | [diff] [blame] | 58 | def get8digithex(dec_num): |
| 59 | """Convert a decimal # into an 8-digit hex""" |
| 60 | if dec_num > 4294967295: |
| 61 | print ("ERROR: Decimal # %d can't be represented in 8 hex digits" % (dec_num)) |
| 62 | sys.exit() |
| 63 | hex_num = hex(dec_num) |
| 64 | return hex_num[2:].zfill(8) |
| 65 | |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 66 | class Specification: |
| 67 | def __init__(self): |
| 68 | self.tree = None |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 69 | self.error_db_dict = {} # dict of previous error values read in from database file |
| 70 | self.delimiter = '~^~' # delimiter for db file |
Tobin Ehlis | a55b1d4 | 2017-04-04 12:23:48 -0600 | [diff] [blame] | 71 | # Global dicts used for tracking spec updates from old to new VUs |
Tobin Ehlis | a55b1d4 | 2017-04-04 12:23:48 -0600 | [diff] [blame] | 72 | self.orig_no_link_msg_dict = {} # Pair of API,Original msg w/o spec link to ID list mapping |
| 73 | self.orig_core_msg_dict = {} # Pair of API,Original core msg (no link or section) to ID list mapping |
| 74 | self.last_mapped_id = -10 # start as negative so we don't hit an accidental sequence |
| 75 | self.orig_test_imp_enums = set() # Track old enums w/ tests and/or implementation to flag any that aren't carried fwd |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 76 | # Dict of data from json DB |
| 77 | # Key is API,<short_msg> which leads to dict w/ following values |
| 78 | # 'ext' -> <core|<ext_name>> |
| 79 | # 'string_vuid' -> <string_vuid> |
| 80 | # 'number_vuid' -> <numerical_vuid> |
| 81 | self.json_db = {} |
| 82 | self.json_missing = 0 |
| 83 | self.struct_to_func_map = {} # Map structs to the API func that they fall under in the spec |
| 84 | self.duplicate_json_key_count = 0 |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 85 | self.copyright = """/* THIS FILE IS GENERATED. DO NOT EDIT. */ |
| 86 | |
| 87 | /* |
| 88 | * Vulkan |
| 89 | * |
| 90 | * Copyright (c) 2016 Google Inc. |
Mark Lobodzinski | 629d47b | 2016-10-18 13:34:58 -0600 | [diff] [blame] | 91 | * Copyright (c) 2016 LunarG, Inc. |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 92 | * |
| 93 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 94 | * you may not use this file except in compliance with the License. |
| 95 | * You may obtain a copy of the License at |
| 96 | * |
| 97 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 98 | * |
| 99 | * Unless required by applicable law or agreed to in writing, software |
| 100 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 101 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 102 | * See the License for the specific language governing permissions and |
| 103 | * limitations under the License. |
| 104 | * |
| 105 | * Author: Tobin Ehlis <tobine@google.com> |
| 106 | */""" |
Tobin Ehlis | 98d109a | 2017-05-11 14:42:38 -0600 | [diff] [blame] | 107 | |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 108 | def readJSON(self): |
Tobin Ehlis | 98d109a | 2017-05-11 14:42:38 -0600 | [diff] [blame] | 109 | """Read in JSON file""" |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 110 | if json_filename is not None: |
| 111 | with open(json_filename) as jsf: |
Mark Lobodzinski | 8c9633d | 2017-06-05 13:50:10 -0600 | [diff] [blame] | 112 | self.json_data = json.load(jsf, encoding='utf-8') |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 113 | else: |
Mark Lobodzinski | 8c9633d | 2017-06-05 13:50:10 -0600 | [diff] [blame] | 114 | response = urllib2.urlopen(json_url).read().decode('utf-8') |
| 115 | self.json_data = json.loads(response) |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 116 | |
Tobin Ehlis | 98d109a | 2017-05-11 14:42:38 -0600 | [diff] [blame] | 117 | def parseJSON(self): |
| 118 | """Parse JSON VUIDs into data struct""" |
| 119 | # Format of JSON file is: |
| 120 | # "API": { "core|EXT": [ {"vuid": "<id>", "text": "<VU txt>"}]}, |
| 121 | # "VK_KHX_external_memory" & "VK_KHX_device_group" - extension case (vs. "core") |
Tobin Ehlis | 798c139 | 2017-06-05 13:23:44 -0600 | [diff] [blame] | 122 | for top_level in sorted(self.json_data): |
| 123 | if "validation" == top_level: |
| 124 | for api in sorted(self.json_data[top_level]): |
| 125 | for ext in sorted(self.json_data[top_level][api]): |
| 126 | for vu_txt_dict in self.json_data[top_level][api][ext]: |
| 127 | print ("Looking at dict for api:ext entry %s:%s" % (api, ext)) |
| 128 | vuid = vu_txt_dict['vuid'] |
| 129 | vutxt = vu_txt_dict['text'] |
| 130 | #print ("%s:%s:%s:%s" % (api, ext, vuid, vutxt)) |
| 131 | #print ("VUTXT orig:%s" % (vutxt)) |
| 132 | just_txt = BeautifulSoup(vutxt, 'html.parser') |
| 133 | #print ("VUTXT only:%s" % (just_txt.get_text())) |
| 134 | num_vuid = vuid_mapping.convertVUID(vuid) |
| 135 | self.json_db[vuid] = {} |
| 136 | self.json_db[vuid]['ext'] = ext |
| 137 | self.json_db[vuid]['number_vuid'] = num_vuid |
| 138 | self.json_db[vuid]['struct_func'] = api |
| 139 | just_txt = just_txt.get_text().strip() |
| 140 | unicode_map = { |
| 141 | u"\u2019" : "'", |
Mark Lobodzinski | 85946ae | 2017-10-09 09:10:21 -0600 | [diff] [blame^] | 142 | u"\u201c" : "\"", |
| 143 | u"\u201d" : "\"", |
Tobin Ehlis | 798c139 | 2017-06-05 13:23:44 -0600 | [diff] [blame] | 144 | u"\u2192" : "->", |
| 145 | } |
| 146 | for um in unicode_map: |
| 147 | just_txt = just_txt.replace(um, unicode_map[um]) |
| 148 | self.json_db[vuid]['vu_txt'] = just_txt.replace("\\", "") |
| 149 | print ("Spec vu txt:%s" % (self.json_db[vuid]['vu_txt'])) |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 150 | #sys.exit() |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 151 | |
| 152 | def compareJSON(self): |
| 153 | """Compare parsed json file with existing data read in from DB file""" |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 154 | json_db_set = set() |
| 155 | for vuid in self.json_db: # pull entries out and see which fields we're missing from error_db |
| 156 | json_db_set.add(vuid) |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 157 | for enum in self.error_db_dict: |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 158 | vuid_string = self.error_db_dict[enum]['vuid_string'] |
| 159 | if vuid_string not in self.json_db: |
| 160 | #print ("Full string for %s is:%s" % (enum, full_error_string)) |
| 161 | print ("WARN: Couldn't find vuid_string in json db:%s" % (vuid_string)) |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 162 | self.json_missing = self.json_missing + 1 |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 163 | self.error_db_dict[enum]['ext'] = 'core' |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 164 | # TODO: Currently GL843 tracks 2 VUs that are missing from json incorrectly |
| 165 | # Fix will land in 1.0.51 spec. After that we should take some alternative |
| 166 | # action here to indicate that VUs have gone away. |
| 167 | # Can have a removed_enums set that we add to and report to user |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 168 | #sys.exit() |
| 169 | else: |
| 170 | json_db_set.remove(vuid_string) |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 171 | self.error_db_dict[enum]['ext'] = self.json_db[vuid_string]['ext'] |
| 172 | if 'core' == self.json_db[vuid_string]['ext'] or '!' in self.json_db[vuid_string]['ext']: |
| 173 | spec_link = "%s#%s" % (core_url, vuid_string) |
| 174 | else: |
| 175 | spec_link = "%s#%s" % (ext_url, vuid_string) |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 176 | self.error_db_dict[enum]['error_msg'] = "%s'%s' (%s)" % (error_msg_prefix, self.json_db[vuid_string]['vu_txt'], spec_link) |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 177 | print ("Updated error_db error_msg:%s" % (self.error_db_dict[enum]['error_msg'])) |
| 178 | #sys.exit() |
| 179 | print ("These json DB entries are not in error DB:") |
| 180 | for extra_vuid in json_db_set: |
| 181 | print ("\t%s" % (extra_vuid)) |
| 182 | # Add these missing entries into the error_db |
| 183 | # Create link into core or ext spec as needed |
| 184 | if 'core' == self.json_db[extra_vuid]['ext'] or '!' in self.json_db[extra_vuid]['ext']: |
| 185 | spec_link = "%s#%s" % (core_url, extra_vuid) |
| 186 | else: |
| 187 | spec_link = "%s#%s" % (ext_url, extra_vuid) |
Tobin Ehlis | 798c139 | 2017-06-05 13:23:44 -0600 | [diff] [blame] | 188 | error_enum = "%s%s" % (validation_error_enum_name, get8digithex(self.json_db[extra_vuid]['number_vuid'])) |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 189 | self.error_db_dict[error_enum] = {} |
| 190 | self.error_db_dict[error_enum]['check_implemented'] = 'N' |
| 191 | self.error_db_dict[error_enum]['testname'] = 'None' |
| 192 | self.error_db_dict[error_enum]['api'] = self.json_db[extra_vuid]['struct_func'] |
| 193 | self.error_db_dict[error_enum]['vuid_string'] = extra_vuid |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 194 | self.error_db_dict[error_enum]['error_msg'] = "%s'%s' (%s)" % (error_msg_prefix, self.json_db[extra_vuid]['vu_txt'], spec_link) |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 195 | self.error_db_dict[error_enum]['note'] = '' |
| 196 | self.error_db_dict[error_enum]['ext'] = self.json_db[extra_vuid]['ext'] |
Tobin Ehlis | 798c139 | 2017-06-05 13:23:44 -0600 | [diff] [blame] | 197 | implicit = False |
| 198 | last_segment = extra_vuid.split("-")[-1] |
| 199 | if last_segment in vuid_mapping.implicit_type_map: |
| 200 | implicit = True |
| 201 | elif not last_segment.isdigit(): # Explicit ids should only have digits in last segment |
| 202 | print ("ERROR: Found last segment of val error ID that isn't in implicit map and doesn't have numbers in last segment: %s" % (last_segment)) |
| 203 | sys.exit() |
| 204 | self.error_db_dict[error_enum]['implicit'] = implicit |
Tobin Ehlis | 98d109a | 2017-05-11 14:42:38 -0600 | [diff] [blame] | 205 | |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 206 | def genHeader(self, header_file): |
| 207 | """Generate a header file based on the contents of a parsed spec""" |
Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 208 | print ("Generating header %s..." % (header_file)) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 209 | file_contents = [] |
| 210 | file_contents.append(self.copyright) |
| 211 | file_contents.append('\n#pragma once') |
Mark Lobodzinski | 267a7cf | 2017-01-25 09:33:25 -0700 | [diff] [blame] | 212 | file_contents.append('\n// Disable auto-formatting for generated file') |
| 213 | file_contents.append('// clang-format off') |
| 214 | file_contents.append('\n#include <unordered_map>') |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 215 | file_contents.append('\n// enum values for unique validation error codes') |
| 216 | file_contents.append('// Corresponding validation error message for each enum is given in the mapping table below') |
| 217 | file_contents.append('// When a given error occurs, these enum values should be passed to the as the messageCode') |
| 218 | file_contents.append('// parameter to the PFN_vkDebugReportCallbackEXT function') |
Tobin Ehlis | 387fd63 | 2016-12-08 13:32:05 -0700 | [diff] [blame] | 219 | enum_decl = ['enum UNIQUE_VALIDATION_ERROR_CODE {\n VALIDATION_ERROR_UNDEFINED = -1,'] |
Tobin Ehlis | bf98b69 | 2016-10-06 12:58:06 -0600 | [diff] [blame] | 220 | error_string_map = ['static std::unordered_map<int, char const *const> validation_error_map{'] |
Tobin Ehlis | ce1e56f | 2017-01-25 12:42:55 -0800 | [diff] [blame] | 221 | enum_value = 0 |
Tobin Ehlis | 3c37fb3 | 2017-05-24 09:31:13 -0600 | [diff] [blame] | 222 | max_enum_val = 0 |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 223 | for enum in sorted(self.error_db_dict): |
Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 224 | #print ("Header enum is %s" % (enum)) |
Tobin Ehlis | 3c37fb3 | 2017-05-24 09:31:13 -0600 | [diff] [blame] | 225 | # TMP: Use updated value |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 226 | vuid_str = self.error_db_dict[enum]['vuid_string'] |
Tobin Ehlis | 3c37fb3 | 2017-05-24 09:31:13 -0600 | [diff] [blame] | 227 | if vuid_str in self.json_db: |
| 228 | enum_value = self.json_db[vuid_str]['number_vuid'] |
| 229 | else: |
| 230 | enum_value = vuid_mapping.convertVUID(vuid_str) |
| 231 | new_enum = "%s%s" % (validation_error_enum_name, get8digithex(enum_value)) |
| 232 | enum_decl.append(' %s = 0x%s,' % (new_enum, get8digithex(enum_value))) |
Mark Lobodzinski | 85946ae | 2017-10-09 09:10:21 -0600 | [diff] [blame^] | 233 | error_string_map.append(' {%s, "%s"},' % (new_enum, self.error_db_dict[enum]['error_msg'].replace('"', '\\"'))) |
Tobin Ehlis | 3c37fb3 | 2017-05-24 09:31:13 -0600 | [diff] [blame] | 234 | max_enum_val = max(max_enum_val, enum_value) |
Tobin Ehlis | 3c37fb3 | 2017-05-24 09:31:13 -0600 | [diff] [blame] | 235 | enum_decl.append(' %sMAX_ENUM = %d,' % (validation_error_enum_name, max_enum_val + 1)) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 236 | enum_decl.append('};') |
Tobin Ehlis | e7560e7 | 2016-10-19 15:59:38 -0600 | [diff] [blame] | 237 | error_string_map.append('};\n') |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 238 | file_contents.extend(enum_decl) |
| 239 | file_contents.append('\n// Mapping from unique validation error enum to the corresponding error message') |
| 240 | file_contents.append('// The error message should be appended to the end of a custom error message that is passed') |
| 241 | file_contents.append('// as the pMessage parameter to the PFN_vkDebugReportCallbackEXT function') |
| 242 | file_contents.extend(error_string_map) |
Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 243 | #print ("File contents: %s" % (file_contents)) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 244 | with open(header_file, "w") as outfile: |
| 245 | outfile.write("\n".join(file_contents)) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 246 | def genDB(self, db_file): |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 247 | """Generate a database of check_enum, check_coded?, testname, API, VUID_string, core|ext, error_string, notes""" |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 248 | db_lines = [] |
| 249 | # Write header for database file |
| 250 | db_lines.append("# This is a database file with validation error check information") |
| 251 | db_lines.append("# Comments are denoted with '#' char") |
| 252 | db_lines.append("# The format of the lines is:") |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 253 | db_lines.append("# <error_enum>%s<check_implemented>%s<testname>%s<api>%s<vuid_string>%s<core|ext>%s<errormsg>%s<note>" % (self.delimiter, self.delimiter, self.delimiter, self.delimiter, self.delimiter, self.delimiter, self.delimiter)) |
Mark Lobodzinski | 629d47b | 2016-10-18 13:34:58 -0600 | [diff] [blame] | 254 | db_lines.append("# error_enum: Unique error enum for this check of format %s<uniqueid>" % validation_error_enum_name) |
Mike Weiblen | fe18612 | 2017-02-03 12:44:53 -0700 | [diff] [blame] | 255 | db_lines.append("# check_implemented: 'Y' if check has been implemented in layers, or 'N' for not implemented") |
Dave Houlton | 14f7e66 | 2017-05-17 13:25:53 -0600 | [diff] [blame] | 256 | db_lines.append("# testname: Name of validation test for this check, 'Unknown' for unknown, 'None' if not implemented, or 'NotTestable' if cannot be implemented") |
Tobin Ehlis | e7560e7 | 2016-10-19 15:59:38 -0600 | [diff] [blame] | 257 | db_lines.append("# api: Vulkan API function that this check is related to") |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 258 | db_lines.append("# vuid_string: Unique string to identify this check") |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 259 | db_lines.append("# core|ext: Either 'core' for core spec or some extension string that indicates the extension required for this VU to be relevant") |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 260 | db_lines.append("# errormsg: The unique error message for this check that includes spec language and link") |
Tobin Ehlis | e7560e7 | 2016-10-19 15:59:38 -0600 | [diff] [blame] | 261 | db_lines.append("# note: Free txt field with any custom notes related to the check in question") |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 262 | for enum in sorted(self.error_db_dict): |
Tobin Ehlis | 798c139 | 2017-06-05 13:23:44 -0600 | [diff] [blame] | 263 | print ("Gen DB for enum %s" % (enum)) |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 264 | implicit = self.error_db_dict[enum]['implicit'] |
| 265 | implemented = self.error_db_dict[enum]['check_implemented'] |
| 266 | testname = self.error_db_dict[enum]['testname'] |
| 267 | note = self.error_db_dict[enum]['note'] |
| 268 | core_ext = self.error_db_dict[enum]['ext'] |
| 269 | self.error_db_dict[enum]['vuid_string'] = self.error_db_dict[enum]['vuid_string'] |
Tobin Ehlis | 2a176b1 | 2017-01-11 16:18:20 -0700 | [diff] [blame] | 270 | if implicit and 'implicit' not in note: # add implicit note |
| 271 | if '' != note: |
| 272 | note = "implicit, %s" % (note) |
| 273 | else: |
| 274 | note = "implicit" |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 275 | db_lines.append("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % (enum, self.delimiter, implemented, self.delimiter, testname, self.delimiter, self.error_db_dict[enum]['api'], self.delimiter, self.error_db_dict[enum]['vuid_string'], self.delimiter, core_ext, self.delimiter, self.error_db_dict[enum]['error_msg'], self.delimiter, note)) |
Tobin Ehlis | af75f7c | 2016-10-31 11:10:38 -0600 | [diff] [blame] | 276 | db_lines.append("\n") # newline at end of file |
Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 277 | print ("Generating database file %s" % (db_file)) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 278 | with open(db_file, "w") as outfile: |
| 279 | outfile.write("\n".join(db_lines)) |
| 280 | def readDB(self, db_file): |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 281 | """Read a db file into a dict, refer to genDB function above for format of each line""" |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 282 | with open(db_file, "r") as infile: |
| 283 | for line in infile: |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 284 | line = line.strip() |
Tobin Ehlis | f4245cb | 2016-10-31 07:55:19 -0600 | [diff] [blame] | 285 | if line.startswith('#') or '' == line: |
| 286 | continue |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 287 | db_line = line.split(self.delimiter) |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 288 | if len(db_line) != 8: |
| 289 | print ("ERROR: Bad database line doesn't have 8 elements: %s" % (line)) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 290 | error_enum = db_line[0] |
| 291 | implemented = db_line[1] |
| 292 | testname = db_line[2] |
Tobin Ehlis | 70980c0 | 2016-10-25 14:00:20 -0600 | [diff] [blame] | 293 | api = db_line[3] |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 294 | vuid_str = db_line[4] |
| 295 | core_ext = db_line[5] |
| 296 | error_str = db_line[6] |
| 297 | note = db_line[7] |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 298 | # Also read complete database contents into our class var for later use |
| 299 | self.error_db_dict[error_enum] = {} |
| 300 | self.error_db_dict[error_enum]['check_implemented'] = implemented |
| 301 | self.error_db_dict[error_enum]['testname'] = testname |
Tobin Ehlis | 70980c0 | 2016-10-25 14:00:20 -0600 | [diff] [blame] | 302 | self.error_db_dict[error_enum]['api'] = api |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 303 | self.error_db_dict[error_enum]['vuid_string'] = vuid_str |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 304 | self.error_db_dict[error_enum]['ext'] = core_ext |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 305 | self.error_db_dict[error_enum]['error_msg'] = error_str |
Tobin Ehlis | 70980c0 | 2016-10-25 14:00:20 -0600 | [diff] [blame] | 306 | self.error_db_dict[error_enum]['note'] = note |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 307 | implicit = False |
| 308 | last_segment = vuid_str.split("-")[-1] |
| 309 | if last_segment in vuid_mapping.implicit_type_map: |
| 310 | implicit = True |
| 311 | elif not last_segment.isdigit(): # Explicit ids should only have digits in last segment |
Tobin Ehlis | 798c139 | 2017-06-05 13:23:44 -0600 | [diff] [blame] | 312 | print ("ERROR: Found last segment of val error ID that isn't in implicit map and doesn't have numbers in last segment: %s" % (last_segment)) |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 313 | sys.exit() |
| 314 | self.error_db_dict[error_enum]['implicit'] = implicit |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 315 | if __name__ == "__main__": |
| 316 | i = 1 |
| 317 | use_online = True # Attempt to grab spec from online by default |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 318 | while (i < len(sys.argv)): |
| 319 | arg = sys.argv[i] |
| 320 | i = i + 1 |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 321 | if (arg == '-json-file'): |
Tobin Ehlis | 98d109a | 2017-05-11 14:42:38 -0600 | [diff] [blame] | 322 | json_filename = sys.argv[i] |
| 323 | i = i + 1 |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 324 | elif (arg == '-json'): |
| 325 | read_json = True |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 326 | elif (arg == '-json-compare'): |
| 327 | json_compare = True |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 328 | elif (arg == '-out'): |
| 329 | out_filename = sys.argv[i] |
| 330 | i = i + 1 |
| 331 | elif (arg == '-gendb'): |
| 332 | gen_db = True |
| 333 | # Set filename if supplied, else use default |
| 334 | if i < len(sys.argv) and not sys.argv[i].startswith('-'): |
| 335 | db_filename = sys.argv[i] |
| 336 | i = i + 1 |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 337 | elif (arg == '-update'): |
Tobin Ehlis | 3c37fb3 | 2017-05-24 09:31:13 -0600 | [diff] [blame] | 338 | read_json = True |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 339 | json_compare = True |
| 340 | gen_db = True |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 341 | elif (arg in ['-help', '-h']): |
| 342 | printHelp() |
| 343 | sys.exit() |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 344 | spec = Specification() |
Tobin Ehlis | 828781a | 2017-05-23 15:23:40 -0600 | [diff] [blame] | 345 | if read_json: |
| 346 | spec.readJSON() |
Tobin Ehlis | 98d109a | 2017-05-11 14:42:38 -0600 | [diff] [blame] | 347 | spec.parseJSON() |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 348 | #sys.exit() |
| 349 | if (json_compare): |
| 350 | # Read in current spec info from db file |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 351 | (orig_err_msg_dict) = spec.readDB(db_filename) |
Tobin Ehlis | 2c93213 | 2017-05-19 16:32:15 -0600 | [diff] [blame] | 352 | spec.compareJSON() |
| 353 | print ("Found %d missing db entries in json db" % (spec.json_missing)) |
| 354 | print ("Found %d duplicate json entries" % (spec.duplicate_json_key_count)) |
Tobin Ehlis | da3916c | 2017-05-24 14:13:46 -0600 | [diff] [blame] | 355 | spec.genDB(db_filename) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 356 | if (gen_db): |
| 357 | spec.genDB(db_filename) |
Tobin Ehlis | 3198ba3 | 2017-04-19 17:30:52 -0600 | [diff] [blame] | 358 | print ("Writing out file (-out) to '%s'" % (out_filename)) |
Tobin Ehlis | 5ade069 | 2016-10-05 17:18:15 -0600 | [diff] [blame] | 359 | spec.genHeader(out_filename) |