scripts:Update database file w/ api column
This adds two columns to the error database file.
The first is the Vulkan api call that the error is related to.
The second is a free txt field for "notes" as the last column.
The spec.py script in this commit is a slightly hacky version that
was used to generate the updated database file. In follow-on commit
I'll update the spec.py file to correctly handle the updated database
file format.
diff --git a/layers/spec.py b/layers/spec.py
index ec266c5..b30869c 100644
--- a/layers/spec.py
+++ b/layers/spec.py
@@ -25,7 +25,10 @@
#
# TODO:
# 1. Improve string matching to add more automation for figuring out which messages are changed vs. completely new
-#
+# Temp hack path:
+# 1. Read in spec w/ API info
+# 2. Read in database file
+# 3. Write out updated DB file w/ API/Notes columns
#
#############################
@@ -63,7 +66,7 @@
class Specification:
def __init__(self):
self.tree = None
- self.val_error_dict = {} # string for enum is key that references text for output message
+ self.val_error_dict = {} # string for enum is key that references 'error_msg' and 'api'
self.error_db_dict = {} # dict of previous error values read in from database file
self.delimiter = '~^~' # delimiter for db file
self.copyright = """/* THIS FILE IS GENERATED. DO NOT EDIT. */
@@ -119,6 +122,7 @@
#print "ROOT: %s" % self.root
prev_heading = '' # Last seen section heading or sub-heading
prev_link = '' # Last seen link id within the spec
+ api_function = '' # API call that a check appears under
error_strings = set() # Flag any exact duplicate error strings and skip them
for tag in self.root.iter(): # iterate down tree
# Grab most recent section heading and link
@@ -136,6 +140,13 @@
if tag.get('id') != None:
prev_link = tag.get('id')
#print "Updated prev link to %s" % (prev_link)
+ elif tag.tag == '{http://www.w3.org/1999/xhtml}pre' and tag.get('class') == 'programlisting':
+ # Check and see if this is API function
+ code_text = "".join(tag.itertext()).replace('\n', '')
+ code_text_list = code_text.split()
+ if len(code_text_list) > 1 and code_text_list[1].startswith('vk'):
+ api_function = code_text_list[1].strip('(')
+ print "Found API function: %s" % (api_function)
elif tag.tag == '{http://www.w3.org/1999/xhtml}div' and tag.get('class') == 'sidebar':
# parse down sidebar to check for valid usage cases
valid_usage = False
@@ -152,7 +163,9 @@
error_strings.add(error_msg_str)
enum_str = "%s%05d" % (validation_error_enum_name, unique_enum_id)
# TODO : '\' chars in spec error messages are most likely bad spec txt that needs to be updated
- self.val_error_dict[enum_str] = error_msg_str.encode("ascii", "ignore").replace("\\", "/")
+ self.val_error_dict[enum_str] = {}
+ self.val_error_dict[enum_str]['error_msg'] = error_msg_str.encode("ascii", "ignore").replace("\\", "/")
+ self.val_error_dict[enum_str]['api'] = api_function
unique_enum_id = unique_enum_id + 1
#print "Validation Error Dict has a total of %d unique errors and contents are:\n%s" % (unique_enum_id, self.val_error_dict)
def genHeader(self, header_file):
@@ -171,10 +184,10 @@
for enum in sorted(self.val_error_dict):
#print "Header enum is %s" % (enum)
enum_decl.append(' %s = %d,' % (enum, int(enum.split('_')[-1])))
- error_string_map.append(' {%s, "%s"},' % (enum, self.val_error_dict[enum]))
+ error_string_map.append(' {%s, "%s"},' % (enum, self.val_error_dict[enum]['error_msg']))
enum_decl.append(' %sMAX_ENUM = %d,' % (validation_error_enum_name, int(enum.split('_')[-1]) + 1))
enum_decl.append('};')
- error_string_map.append('};')
+ error_string_map.append('};\n')
file_contents.extend(enum_decl)
file_contents.append('\n// Mapping from unique validation error enum to the corresponding error message')
file_contents.append('// The error message should be appended to the end of a custom error message that is passed')
@@ -189,7 +202,7 @@
str_count_dict = {}
unique_id_count = 0
for enum in self.val_error_dict:
- err_str = self.val_error_dict[enum]
+ err_str = self.val_error_dict[enum]['error_msg']
if err_str in str_count_dict:
print "Found repeat error string"
str_count_dict[err_str] = str_count_dict[err_str] + 1
@@ -210,11 +223,13 @@
db_lines.append("# This is a database file with validation error check information")
db_lines.append("# Comments are denoted with '#' char")
db_lines.append("# The format of the lines is:")
- db_lines.append("# <error_enum>%s<check_implemented>%s<testname>%s<errormsg>" % (self.delimiter, self.delimiter, self.delimiter))
+ db_lines.append("# <error_enum>%s<check_implemented>%s<testname>%s<api>%s<errormsg>%s<note>" % (self.delimiter, self.delimiter, self.delimiter, self.delimiter, self.delimiter))
db_lines.append("# error_enum: Unique error enum for this check of format %s<uniqueid>" % validation_error_enum_name)
db_lines.append("# check_implemented: 'Y' if check has been implemented in layers, 'U' for unknown, or 'N' for not implemented")
db_lines.append("# testname: Name of validation test for this check, 'Unknown' for unknown, or 'None' if not implmented")
+ db_lines.append("# api: Vulkan API function that this check is related to")
db_lines.append("# errormsg: The unique error message for this check that includes spec language and link")
+ db_lines.append("# note: Free txt field with any custom notes related to the check in question")
for enum in sorted(self.val_error_dict):
# Default to unknown if check or test are implemented, then update below if appropriate
implemented = 'U'
@@ -225,10 +240,11 @@
testname = self.error_db_dict[enum]['testname']
#print "delimiter: %s, id: %s, str: %s" % (self.delimiter, enum, self.val_error_dict[enum])
# No existing entry so default to N for implemented and None for testname
- db_lines.append("%s%s%s%s%s%s%s" % (enum, self.delimiter, implemented, self.delimiter, testname, self.delimiter, self.val_error_dict[enum]))
+ db_lines.append("%s%s%s%s%s%s%s%s%s%s" % (enum, self.delimiter, implemented, self.delimiter, testname, self.delimiter, self.val_error_dict[enum]['api'], self.delimiter, self.val_error_dict[enum]['error_msg'], self.delimiter))
print "Generating database file %s" % (db_file)
with open(db_file, "w") as outfile:
outfile.write("\n".join(db_lines))
+ outfile.write("\n")
def readDB(self, db_file):
"""Read a db file into a dict, format of each line is <enum><implemented Y|N?><testname><errormsg>"""
db_dict = {} # This is a simple db of just enum->errormsg, the same as is created from spec
@@ -262,72 +278,78 @@
# 4. If new id in original, but error strings don't match then:
# 4a. If error string has exact match in original, update new to use original
# 4b. If error string not in original, may be updated error message, manually address
- def compareDB(self, orig_db_dict, max_id):
+ def compareDB(self, orig_error_msg_dict, max_id):
"""Compare orig database dict to new dict, report out findings, and return potential new dict for parsed spec"""
# First create reverse dicts of err_strings to IDs
next_id = max_id + 1
orig_err_to_id_dict = {}
# Create an updated dict in-place that will be assigned to self.val_error_dict when done
updated_val_error_dict = {}
- for enum in orig_db_dict:
- orig_err_to_id_dict[orig_db_dict[enum]] = enum
+ for enum in orig_error_msg_dict:
+ orig_err_to_id_dict[orig_error_msg_dict[enum]] = enum
new_err_to_id_dict = {}
for enum in self.val_error_dict:
- new_err_to_id_dict[self.val_error_dict[enum]] = enum
+ new_err_to_id_dict[self.val_error_dict[enum]['error_msg']] = enum
ids_parsed = 0
+ # Values to be used for the update dict
+ update_enum = ''
+ update_msg = ''
+ update_api = ''
# Now parse through new dict and figure out what to do with non-matching things
for enum in sorted(self.val_error_dict):
ids_parsed = ids_parsed + 1
enum_list = enum.split('_') # grab sections of enum for use below
+ # Default update values to be the same
+ update_enum = enum
+ update_msg = self.val_error_dict[enum]['error_msg']
+ update_api = self.val_error_dict[enum]['api']
# Any user-forced remap takes precendence
if enum_list[-1] in remap_dict:
enum_list[-1] = remap_dict[enum_list[-1]]
new_enum = "_".join(enum_list)
print "NOTE: Using user-supplied remap to force %s to be %s" % (enum, new_enum)
- updated_val_error_dict[new_enum] = self.val_error_dict[enum]
- elif enum in orig_db_dict:
- if self.val_error_dict[enum] == orig_db_dict[enum]:
+ update_enum = new_enum
+ elif enum in orig_error_msg_dict:
+ if self.val_error_dict[enum]['error_msg'] == orig_error_msg_dict[enum]:
print "Exact match for enum %s" % (enum)
# Nothing to see here
if enum in updated_val_error_dict:
print "ERROR: About to overwrite entry for %s" % (enum)
- updated_val_error_dict[enum] = self.val_error_dict[enum]
- elif self.val_error_dict[enum] in orig_err_to_id_dict:
+ elif self.val_error_dict[enum]['error_msg'] in orig_err_to_id_dict:
# Same value w/ different error id, need to anchor to original id
- print "Need to switch new id %s to original id %s" % (enum, orig_err_to_id_dict[self.val_error_dict[enum]])
+ print "Need to switch new id %s to original id %s" % (enum, orig_err_to_id_dict[self.val_error_dict[enum]['error_msg']])
# Update id at end of new enum to be same id from original enum
- enum_list[-1] = orig_err_to_id_dict[self.val_error_dict[enum]].split('_')[-1]
+ enum_list[-1] = orig_err_to_id_dict[self.val_error_dict[enum]['error_msg']].split('_')[-1]
new_enum = "_".join(enum_list)
if new_enum in updated_val_error_dict:
print "ERROR: About to overwrite entry for %s" % (new_enum)
- updated_val_error_dict[new_enum] = self.val_error_dict[enum]
+ update_enum = new_enum
else:
# No error match:
# First check if only link has changed, in which case keep ID but update message
- orig_msg_list = orig_db_dict[enum].split('(', 1)
- new_msg_list = self.val_error_dict[enum].split('(', 1)
+ orig_msg_list = orig_error_msg_dict[enum].split('(', 1)
+ new_msg_list = self.val_error_dict[enum]['error_msg'].split('(', 1)
if orig_msg_list[0] == new_msg_list[0]: # Msg is same bug link has changed, keep enum & update msg
print "NOTE: Found that only spec link changed for %s so keeping same id w/ new link" % (enum)
- updated_val_error_dict[enum] = self.val_error_dict[enum]
# This seems to be a new error so need to pick it up from end of original unique ids & flag for review
else:
enum_list[-1] = "%05d" % (next_id)
new_enum = "_".join(enum_list)
next_id = next_id + 1
print "MANUALLY VERIFY: Updated new enum %s to be unique %s. Make sure new error msg is actually unique and not just changed" % (enum, new_enum)
- print " New error string: %s" % (self.val_error_dict[enum])
+ print " New error string: %s" % (self.val_error_dict[enum]['error_msg'])
if new_enum in updated_val_error_dict:
print "ERROR: About to overwrite entry for %s" % (new_enum)
- updated_val_error_dict[new_enum] = self.val_error_dict[enum]
+ update_enum = new_enum
else: # new enum is not in orig db
- if self.val_error_dict[enum] in orig_err_to_id_dict:
- print "New enum %s not in orig dict, but exact error message matches original unique id %s" % (enum, orig_err_to_id_dict[self.val_error_dict[enum]])
+ if self.val_error_dict[enum]['error_msg'] in orig_err_to_id_dict:
+ print "New enum %s not in orig dict, but exact error message matches original unique id %s" % (enum, orig_err_to_id_dict[self.val_error_dict[enum]['error_msg']])
# Update new unique_id to use original
- enum_list[-1] = orig_err_to_id_dict[self.val_error_dict[enum]].split('_')[-1]
+ enum_list[-1] = orig_err_to_id_dict[self.val_error_dict[enum]['error_msg']].split('_')[-1]
new_enum = "_".join(enum_list)
if new_enum in updated_val_error_dict:
print "ERROR: About to overwrite entry for %s" % (new_enum)
- updated_val_error_dict[new_enum] = self.val_error_dict[enum]
+ update_enum = new_enum
else:
enum_list[-1] = "%05d" % (next_id)
new_enum = "_".join(enum_list)
@@ -335,7 +357,10 @@
print "Completely new id and error code, update new id from %s to unique %s" % (enum, new_enum)
if new_enum in updated_val_error_dict:
print "ERROR: About to overwrite entry for %s" % (new_enum)
- updated_val_error_dict[new_enum] = self.val_error_dict[enum]
+ update_enum = new_enum
+ updated_val_error_dict[update_enum] = {}
+ updated_val_error_dict[update_enum]['error_msg'] = update_msg
+ updated_val_error_dict[update_enum]['api'] = update_api
# Assign parsed dict to be the udpated dict based on db compare
print "In compareDB parsed %d entries" % (ids_parsed)
return updated_val_error_dict
@@ -417,9 +442,9 @@
spec.analyze()
if (spec_compare):
# Read in old spec info from db file
- (orig_db_dict, max_id) = spec.readDB(db_filename)
+ (orig_err_msg_dict, max_id) = spec.readDB(db_filename)
# New spec data should already be read into self.val_error_dict
- updated_dict = spec.compareDB(orig_db_dict, max_id)
+ updated_dict = spec.compareDB(orig_err_msg_dict, max_id)
update_valid = spec.validateUpdateDict(updated_dict)
if update_valid:
spec.updateDict(updated_dict)