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 get_interfaces(args): 24 interfaces_dir = os.path.join(args.inputdir, 'interfaces.d') 25 yaml_files = filter( 26 lambda x: x.endswith('.yaml'), 27 os.listdir(interfaces_dir)) 28 29 interfaces = [] 30 for x in yaml_files: 31 with open(os.path.join(interfaces_dir, x), 'r') as fd: 32 for i in yaml.load(fd.read()): 33 interfaces.append(i) 34 35 return interfaces 36 37 38def list_interfaces(args): 39 print ' '.join(get_interfaces(args)) 40 41 42def generate_cpp(args): 43 # Aggregate all the event YAML in the events.d directory 44 # into a single list of events. 45 events_dir = os.path.join(args.inputdir, 'events.d') 46 yaml_files = filter( 47 lambda x: x.endswith('.yaml'), 48 os.listdir(events_dir)) 49 50 events = [] 51 for x in yaml_files: 52 with open(os.path.join(events_dir, x), 'r') as fd: 53 for e in yaml.load(fd.read()).get('events', {}): 54 events.append(parse_event(e)) 55 56 # Aggregate all the interface YAML in the interfaces.d 57 # directory into a single list of interfaces. 58 template = os.path.join(script_dir, 'generated.mako.cpp') 59 t = Template(filename=template) 60 61 interfaces = get_interfaces(args) 62 63 # Render the template with the provided events and interfaces. 64 template = os.path.join(script_dir, 'generated.mako.cpp') 65 t = Template(filename=template) 66 with open(os.path.join(args.outputdir, 'generated.cpp'), 'w') as fd: 67 fd.write( 68 t.render( 69 interfaces=interfaces, 70 events=events)) 71 72 # Invoke sdbus++ to generate any extra interface bindings for 73 # extra interfaces that aren't defined externally. 74 yaml_files = [] 75 extra_ifaces_dir = os.path.join(args.inputdir, 'extra_interfaces.d') 76 if os.path.exists(extra_ifaces_dir): 77 for directory, _, files in os.walk(extra_ifaces_dir): 78 if not files: 79 continue 80 81 yaml_files += map( 82 lambda f: os.path.relpath( 83 os.path.join(directory, f), 84 extra_ifaces_dir), 85 filter(lambda f: f.endswith('.interface.yaml'), files)) 86 87 genfiles = { 88 'server-cpp': lambda x: '%s.cpp' % ( 89 x.replace(os.sep, '.')), 90 'server-header': lambda x: os.path.join( 91 os.path.join( 92 *x.split('.')), 'server.hpp') 93 } 94 95 for i in yaml_files: 96 iface = i.replace('.interface.yaml', '').replace(os.sep, '.') 97 for process, f in genfiles.iteritems(): 98 99 dest = os.path.join(args.outputdir, f(iface)) 100 parent = os.path.dirname(dest) 101 if parent and not os.path.exists(parent): 102 os.makedirs(parent) 103 104 with open(dest, 'w') as fd: 105 subprocess.call([ 106 'sdbus++', 107 '-r', 108 extra_ifaces_dir, 109 'interface', 110 process, 111 iface], 112 stdout=fd) 113 114 115if __name__ == '__main__': 116 script_dir = os.path.dirname(os.path.realpath(__file__)) 117 valid_commands = { 118 'generate-cpp': 'generate_cpp', 119 'list-interfaces': 'list_interfaces'} 120 121 parser = argparse.ArgumentParser( 122 description='Phosphor Inventory Manager (PIM) YAML ' 123 'scanner and code generator.') 124 parser.add_argument( 125 '-o', '--output-dir', dest='outputdir', 126 default='.', help='Output directory.') 127 parser.add_argument( 128 '-d', '--dir', dest='inputdir', 129 default=os.path.join(script_dir, 'example'), 130 help='Location of files to process.') 131 parser.add_argument( 132 'command', metavar='COMMAND', type=str, 133 choices=valid_commands.keys(), 134 help='Command to run.') 135 136 args = parser.parse_args() 137 function = getattr(sys.modules[__name__], valid_commands[args.command]) 138 function(args) 139 140 141# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 142