#!/usr/bin/env python r""" This script will parse error log yaml file(s) and generate a header file which will then be used by the error logging client and server to collect and validate the error information generated by the openbmc software components. This code uses a mako template to provide the basic template of the header file we're going to generate. We then call it with information from the yaml to generate the header file. """ from mako.template import Template from optparse import OptionParser import yaml import sys import os def get_error_yaml_files(i_yaml_dir): yaml_files = filter( lambda file: file.endswith('.errors.yaml'), os.listdir(i_yaml_dir)) return yaml_files def get_meta_yaml_file(i_error_yaml_file): # the meta data will be defined in file name where we replace # .errors.yaml with .metadata.yaml meta_yaml = i_error_yaml_file.replace("errors", "metadata") return meta_yaml def get_cpp_type(i_type): typeMap = { 'int16': 'int16_t', 'int32': 'int32_t', 'int64': 'int64_t', 'uint16': 'uint16_t', 'uint32': 'uint32_t', 'uint64': 'uint64_t', 'double': 'double', # const char* aids usage of constexpr 'string': 'const char*'} return typeMap[i_type] def gen_elog_hpp(i_yaml_dir, i_output_hpp, i_template_dir, i_elog_mako, i_error_namespace): r""" Read yaml file(s) under input yaml dir, grab the relevant data and call the mako template to generate the output header file. Description of arguments: i_yaml_dir directory containing error yaml files i_output_hpp name of the to be generated output hpp i_template_dir directory containing error mako templates i_elog_mako error mako template to render """ # Input parameters to mako template errors = list() # Main error codes error_msg = dict() # Error msg that corresponds to error code error_lvl = dict() # Error code log level (debug, info, error, ...) meta = list() # The meta data names associated (ERRNO, FILE_NAME, ...) meta_data = dict() # The meta data info (type, format) error_yamls = get_error_yaml_files(i_yaml_dir) for error_yaml in error_yamls: # Verify the error yaml file error_yaml = "/".join((i_yaml_dir, error_yaml)) if (not (os.path.isfile(error_yaml))): print "Can not find input yaml file " + error_yaml exit(1) # Verify the metadata yaml file meta_yaml = get_meta_yaml_file(error_yaml) if (not (os.path.isfile(meta_yaml))): print "Can not find meta yaml file " + meta_yaml exit(1) # Verify the input mako file template_path = "/".join((i_template_dir, i_elog_mako)) if (not (os.path.isfile(template_path))): print "Can not find input template file " + template_path exit(1) get_elog_data(error_yaml, meta_yaml, # 3rd arg is a tuple (errors, error_msg, error_lvl, meta, meta_data)) # Load the mako template and call it with the required data yaml_dir = i_yaml_dir.strip("./") yaml_dir = yaml_dir.strip("../") template = Template(filename=template_path) f = open(i_output_hpp, 'w') f.write(template.render( errors=errors, error_msg=error_msg, error_lvl=error_lvl, meta=meta, meta_data=meta_data, error_namespace=i_error_namespace)) f.close() def get_elog_data(i_elog_yaml, i_elog_meta_yaml, o_elog_data): r""" Parse the error and metadata yaml files in order to pull out error metadata. Description of arguments: i_elog_yaml error yaml file i_elog_meta_yaml metadata yaml file o_elog_data error metadata """ errors, error_msg, error_lvl, meta, meta_data = o_elog_data ifile = yaml.safe_load(open(i_elog_yaml)) mfile = yaml.safe_load(open(i_elog_meta_yaml)) for i in ifile: match = None # Find the corresponding meta data for this entry for m in mfile: if m['name'] == i['name']: match = m break if (match is None): print "Error - Did not find meta data for " + i['name'] exit(1) # Grab the main error and it's info errors.append(i['name']) error_msg[i['name']] = i['description'] error_lvl[i['name']] = match['level'] tmp_meta = [] # grab all the meta data fields and info for j in match['meta']: str_short = j['str'].split('=')[0] tmp_meta.append(str_short) meta_data[str_short] = {} meta_data[str_short]['str'] = j['str'] meta_data[str_short]['str_short'] = str_short meta_data[str_short]['type'] = get_cpp_type(j['type']) meta.append(tmp_meta) # Debug # for i in errors: # print "ERROR: " + errors[i] # print " MSG: " + error_msg[errors[i]] # print " LVL: " + error_lvl[errors[i]] # print " META: " # print meta[i] def main(i_args): parser = OptionParser() parser.add_option("-m", "--mako", dest="elog_mako", default="elog-gen-template.mako.hpp", help="input mako template file to use") parser.add_option("-o", "--output", dest="output_hpp", default="elog-gen.hpp", help="output hpp to generate, elog-gen.hpp is default") parser.add_option("-y", "--yamldir", dest="yamldir", default="./example/xyz/openbmc_project/Example", help="Base directory of yaml files to process") parser.add_option("-t", "--templatedir", dest="templatedir", default="phosphor-logging/templates/", help="Base directory of files to process") parser.add_option("-n", "--namespace", dest="error_namespace", default="example/xyz/openbmc_project/Example", help="Error d-bus namespace") (options, args) = parser.parse_args(i_args) gen_elog_hpp(options.yamldir, options.output_hpp, options.templatedir, options.elog_mako, options.error_namespace) # Only run if it's a script if __name__ == '__main__': main(sys.argv[1:])