From c2ffeb4f3f26518178a574ff38ae0d1d78b4b541 Mon Sep 17 00:00:00 2001 From: Tobin Ehlis Date: Wed, 19 Oct 2016 15:59:38 -0600 Subject: 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. --- layers/spec.py | 89 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 32 deletions(-) (limited to 'layers/spec.py') diff --git a/layers/spec.py b/layers/spec.py index ec266c53..b30869c7 100644 --- a/layers/spec.py +++ b/layers/spec.py @@ -25,7 +25,10 @@ import urllib2 # # 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 @@ def printHelp(): 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 @@ class Specification: #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 @@ class Specification: 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 @@ class Specification: 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 @@ class Specification: 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 @@ class Specification: 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 @@ class Specification: 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("# %s%s%s" % (self.delimiter, self.delimiter, self.delimiter)) + db_lines.append("# %s%s%s%s%s" % (self.delimiter, self.delimiter, self.delimiter, self.delimiter, self.delimiter)) db_lines.append("# error_enum: Unique error enum for this check of format %s" % 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 @@ class Specification: 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 """ db_dict = {} # This is a simple db of just enum->errormsg, the same as is created from spec @@ -262,72 +278,78 @@ class Specification: # 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 @@ class Specification: 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 @@ if __name__ == "__main__": 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) -- cgit v1.2.3