1#!/usr/bin/env python 2 3r""" 4This script will parse error log yaml file(s) and generate 5a header file which will then be used by the error logging client and 6server to collect and validate the error information generated by the 7openbmc software components. 8 9This code uses a mako template to provide the basic template of the header 10file we're going to generate. We then call it with information from the 11yaml to generate the header file. 12""" 13 14from mako.template import Template 15from optparse import OptionParser 16import yaml 17import sys 18import os 19 20 21def get_error_yaml_files(i_yaml_dir): 22 yaml_files = filter( 23 lambda file: file.endswith('.errors.yaml'), 24 os.listdir(i_yaml_dir)) 25 return yaml_files 26 27 28def get_meta_yaml_file(i_error_yaml_file): 29 # the meta data will be defined in file name where we replace 30 # <Interface>.errors.yaml with <Interface>.metadata.yaml 31 meta_yaml = i_error_yaml_file.replace("errors", "metadata") 32 return meta_yaml 33 34 35def get_cpp_type(i_type): 36 typeMap = { 37 'int16': 'int16_t', 38 'int32': 'int32_t', 39 'int64': 'int64_t', 40 'uint16': 'uint16_t', 41 'uint32': 'uint32_t', 42 'uint64': 'uint64_t', 43 'double': 'double', 44 # const char* aids usage of constexpr 45 'string': 'const char*'} 46 47 return typeMap[i_type] 48 49 50def gen_elog_hpp(i_yaml_dir, i_output_hpp, 51 i_template_dir, i_elog_mako, i_error_namespace): 52 r""" 53 Read yaml file(s) under input yaml dir, grab the relevant data and call 54 the mako template to generate the output header file. 55 56 Description of arguments: 57 i_yaml_dir directory containing error yaml files 58 i_output_hpp name of the to be generated output hpp 59 i_template_dir directory containing error mako templates 60 i_elog_mako error mako template to render 61 """ 62 63 # Input parameters to mako template 64 errors = list() # Main error codes 65 error_msg = dict() # Error msg that corresponds to error code 66 error_lvl = dict() # Error code log level (debug, info, error, ...) 67 meta = list() # The meta data names associated (ERRNO, FILE_NAME, ...) 68 meta_data = dict() # The meta data info (type, format) 69 parents = list() 70 71 error_yamls = get_error_yaml_files(i_yaml_dir) 72 73 for error_yaml in error_yamls: 74 # Verify the error yaml file 75 error_yaml = "/".join((i_yaml_dir, error_yaml)) 76 if (not (os.path.isfile(error_yaml))): 77 print "Can not find input yaml file " + error_yaml 78 exit(1) 79 80 # Verify the metadata yaml file 81 meta_yaml = get_meta_yaml_file(error_yaml) 82 if (not (os.path.isfile(meta_yaml))): 83 print "Can not find meta yaml file " + meta_yaml 84 exit(1) 85 86 # Verify the input mako file 87 template_path = "/".join((i_template_dir, i_elog_mako)) 88 if (not (os.path.isfile(template_path))): 89 print "Can not find input template file " + template_path 90 exit(1) 91 92 get_elog_data(error_yaml, 93 meta_yaml, 94 # 3rd arg is a tuple 95 (errors, 96 error_msg, 97 error_lvl, 98 meta, 99 meta_data, 100 parents)) 101 102 # Load the mako template and call it with the required data 103 yaml_dir = i_yaml_dir.strip("./") 104 yaml_dir = yaml_dir.strip("../") 105 template = Template(filename=template_path) 106 f = open(i_output_hpp, 'w') 107 f.write(template.render( 108 errors=errors, error_msg=error_msg, 109 error_lvl=error_lvl, meta=meta, 110 meta_data=meta_data, error_namespace=i_error_namespace)) 111 f.close() 112 113 114def get_elog_data(i_elog_yaml, 115 i_elog_meta_yaml, 116 o_elog_data): 117 r""" 118 Parse the error and metadata yaml files in order to pull out 119 error metadata. 120 121 Description of arguments: 122 i_elog_yaml error yaml file 123 i_elog_meta_yaml metadata yaml file 124 o_elog_data error metadata 125 """ 126 errors, error_msg, error_lvl, meta, meta_data, parents = o_elog_data 127 ifile = yaml.safe_load(open(i_elog_yaml)) 128 mfile = yaml.safe_load(open(i_elog_meta_yaml)) 129 for i in ifile: 130 match = None 131 # Find the corresponding meta data for this entry 132 for m in mfile: 133 if m['name'] == i['name']: 134 match = m 135 break 136 if (match is None): 137 print "Error - Did not find meta data for " + i['name'] 138 exit(1) 139 # Grab the main error and it's info 140 errors.append(i['name']) 141 parent = None 142 if('inherits' in i): 143 # xyz.openbmc.Foo, we need Foo 144 # Get 0th inherited error (current support - single inheritance) 145 parent = i['inherits'][0].split(".").pop() 146 parents.append(parent) 147 error_msg[i['name']] = i['description'] 148 error_lvl[i['name']] = match['level'] 149 tmp_meta = [] 150 # grab all the meta data fields and info 151 for j in match['meta']: 152 str_short = j['str'].split('=')[0] 153 tmp_meta.append(str_short) 154 meta_data[str_short] = {} 155 meta_data[str_short]['str'] = j['str'] 156 meta_data[str_short]['str_short'] = str_short 157 meta_data[str_short]['type'] = get_cpp_type(j['type']) 158 meta.append(tmp_meta) 159 160 # Debug 161 # for i in errors: 162 # print "ERROR: " + errors[i] 163 # print " MSG: " + error_msg[errors[i]] 164 # print " LVL: " + error_lvl[errors[i]] 165 # print " META: " 166 # print meta[i] 167 168 169def main(i_args): 170 parser = OptionParser() 171 172 parser.add_option("-m", "--mako", dest="elog_mako", 173 default="elog-gen-template.mako.hpp", 174 help="input mako template file to use") 175 176 parser.add_option("-o", "--output", dest="output_hpp", 177 default="elog-gen.hpp", 178 help="output hpp to generate, elog-gen.hpp is default") 179 180 parser.add_option("-y", "--yamldir", dest="yamldir", 181 default="./example/xyz/openbmc_project/Example", 182 help="Base directory of yaml files to process") 183 184 parser.add_option("-t", "--templatedir", dest="templatedir", 185 default="phosphor-logging/templates/", 186 help="Base directory of files to process") 187 188 parser.add_option("-n", "--namespace", dest="error_namespace", 189 default="example/xyz/openbmc_project/Example", 190 help="Error d-bus namespace") 191 192 (options, args) = parser.parse_args(i_args) 193 194 gen_elog_hpp(options.yamldir, 195 options.output_hpp, 196 options.templatedir, 197 options.elog_mako, 198 options.error_namespace) 199 200# Only run if it's a script 201if __name__ == '__main__': 202 main(sys.argv[1:]) 203