1#!/usr/bin/env python 2 3import sys 4import os 5import re 6import argparse 7import yaml 8import subprocess 9from mako.template import Template 10 11valid_c_name_pattern = re.compile('[\W_]+') 12 13 14def parse_event(e): 15 e['name'] = valid_c_name_pattern.sub('_', e['name']).lower() 16 if e.get('filter') is None: 17 e.setdefault('filter', {}).setdefault('type', 'none') 18 if e.get('action') is None: 19 e.setdefault('action', {}).setdefault('type', 'noop') 20 return e 21 22 23def generate_cpp(args): 24 # Aggregate all the event YAML in the events.d directory 25 # into a single list of events. 26 events_dir = os.path.join(args.inputdir, 'events.d') 27 yaml_files = filter( 28 lambda x: x.endswith('.yaml'), 29 os.listdir(events_dir)) 30 31 events = [] 32 for x in yaml_files: 33 with open(os.path.join(events_dir, x), 'r') as fd: 34 for e in yaml.load(fd.read()).get('events', {}): 35 events.append(parse_event(e)) 36 37 # Aggregate all the interface YAML in the interfaces.d 38 # directory into a single list of interfaces. 39 template = os.path.join(script_dir, 'generated.mako.cpp') 40 t = Template(filename=template) 41 42 interfaces_dir = os.path.join(args.inputdir, 'interfaces.d') 43 yaml_files = filter( 44 lambda x: x.endswith('.yaml'), 45 os.listdir(interfaces_dir)) 46 47 interfaces = [] 48 for x in yaml_files: 49 with open(os.path.join(interfaces_dir, x), 'r') as fd: 50 for i in yaml.load(fd.read()): 51 interfaces.append(i) 52 53 # Render the template with the provided events and interfaces. 54 template = os.path.join(script_dir, 'generated.mako.cpp') 55 t = Template(filename=template) 56 with open(os.path.join(args.outputdir, 'generated.cpp'), 'w') as fd: 57 fd.write( 58 t.render( 59 interfaces=interfaces, 60 events=events)) 61 62 # Invoke sdbus++ to generate any extra interface bindings for 63 # extra interfaces that aren't defined externally. 64 yaml_files = [] 65 extra_ifaces_dir = os.path.join(args.inputdir, 'extra_interfaces.d') 66 if os.path.exists(extra_ifaces_dir): 67 for directory, _, files in os.walk(extra_ifaces_dir): 68 if not files: 69 continue 70 71 yaml_files += map( 72 lambda f: os.path.relpath( 73 os.path.join(directory, f), 74 extra_ifaces_dir), 75 filter(lambda f: f.endswith('.interface.yaml'), files)) 76 77 genfiles = { 78 'server-cpp': lambda x: '%s.cpp' % ( 79 x.replace(os.sep, '.')), 80 'server-header': lambda x: os.path.join( 81 os.path.join( 82 *x.split('.')), 'server.hpp') 83 } 84 85 for i in yaml_files: 86 iface = i.replace('.interface.yaml', '').replace(os.sep, '.') 87 for process, f in genfiles.iteritems(): 88 89 dest = os.path.join(args.outputdir, f(iface)) 90 parent = os.path.dirname(dest) 91 if parent and not os.path.exists(parent): 92 os.makedirs(parent) 93 94 with open(dest, 'w') as fd: 95 subprocess.call([ 96 'sdbus++', 97 '-r', 98 extra_ifaces_dir, 99 'interface', 100 process, 101 iface], 102 stdout=fd) 103 104 105if __name__ == '__main__': 106 script_dir = os.path.dirname(os.path.realpath(__file__)) 107 108 parser = argparse.ArgumentParser( 109 description='Phosphor Inventory Manager (PIM) YAML ' 110 'scanner and code generator.') 111 parser.add_argument( 112 '-o', '--output-dir', dest='outputdir', 113 default='.', help='Output directory.') 114 parser.add_argument( 115 '-d', '--dir', dest='inputdir', 116 default=os.path.join(script_dir, 'example'), 117 help='Location of files to process.') 118 119 args = parser.parse_args() 120 generate_cpp(args) 121 122 123# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 124