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