summaryrefslogtreecommitdiffstats
path: root/pimgen.py
blob: c21c418abf2d1d59f0c33e07751e7462277d0fb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/env python

import sys
import os
import re
import argparse
import yaml

valid_c_name_pattern = re.compile('[\W_]+')
ignore_list = ['description']
all_names = []


def get_parser(x, fmt, lmbda=lambda x: x.capitalize()):
    try:
        return getattr(
            sys.modules[__name__],
            '%s' % (fmt.format(lmbda(x))))
    except AttributeError:
        raise NotImplementedError("Don't know how to parse '%s'" % x)


class RenderList(list):
    def __init__(self, renderers):
        self.extend(renderers)

    def __call__(self, fd):
        for x in self:
            x(fd)


class ParseList(list):
    def __init__(self, parsers):
        self.extend(parsers)

    def __call__(self):
        return RenderList([x() for x in self])


class MatchRender(object):
    def __init__(self, name, signature, fltr, action):
        self.name = valid_c_name_pattern.sub('_', name).lower()
        self.signature = signature
        self.fltr = fltr
        self.action = action

        if self.name in all_names:
            raise RuntimeError('The name "%s" is not unique.' % name)
        else:
            all_names.append(self.name)

    def __call__(self, fd):
        sig = ['%s=\'%s\'' % (k, v) for k, v in self.signature.iteritems()]
        sig = ['%s,' % x for x in sig[:-1]] + [sig[-1]]
        sig = ['"%s"' % x for x in sig]
        sig = ['%s\n' % x for x in sig[:-1]] + [sig[-1]]

        fd.write('    {\n')
        fd.write('        "%s",\n' % self.name)
        fd.write('        std::make_tuple(\n')
        for s in sig:
            fd.write('            %s' % s)
        fd.write(',\n')
        self.fltr(fd)
        fd.write(',\n')
        self.action(fd)
        fd.write('\n')
        fd.write('        ),\n')
        fd.write('    },\n')


class FilterRender(object):
    namespace = 'filters'
    default = 'none'

    def __init__(self, fltr):
        self.args = None
        if fltr is None:
            self.name = self.default
        else:
            self.name = fltr.get('type')
            self.args = fltr.get('args')

    def __call__(self, fd):
        def fmt(x):
            if x.get('type') is None:
                return '"%s"' % x['value']
            return str(x['value'])

        fd.write('            %s::%s' % (self.namespace, self.name))
        if self.args:
            fd.write('(')
            buf = ','.join(([fmt(x) for x in self.args]))
            fd.write(buf)
            fd.write(')')


class ActionRender(FilterRender):
    namespace = 'actions'
    default = 'noop'

    def __init__(self, action):
        FilterRender.__init__(self, action)


class MatchEventParse(object):
    def __init__(self, match):
        self.name = match['name']
        self.signature = match['signature']
        self.fltr = match.get('filter')
        self.action = match.get('action')

    def __call__(self):
        return MatchRender(
            self.name,
            self.signature,
            FilterRender(self.fltr),
            ActionRender(self.action))


class EventsParse(object):
    def __init__(self, event):
        self.delegate = None
        cls = event['type']
        if cls not in ignore_list:
            fmt = '{0}EventParse'
            self.delegate = get_parser(cls, fmt)(event)

    def __call__(self):
        if self.delegate:
            return self.delegate()
        return lambda x: None


class DictParse(ParseList):
    def __init__(self, data):
        fmt = '{0}Parse'
        parse = set(data.iterkeys()).difference(ignore_list)
        ParseList.__init__(
            self, [get_parser(x, fmt)(*data[x]) for x in parse])


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Phosphor Inventory Manager (PIM) YAML '
        'scanner and code generator.')
    parser.add_argument(
        '-o', '--output', dest='output',
        default='generated.cpp', help='Output file name.')
    parser.add_argument(
        '-d', '--dir', dest='inputdir',
        default=os.path.join('example', 'events'),
        help='Location of files to process.')

    args = parser.parse_args()

    yaml_files = filter(
        lambda x: x.endswith('.yaml'),
        os.listdir(args.inputdir))

    def get_parsers(x):
        with open(os.path.join(args.inputdir, x), 'r') as fd:
            return DictParse(yaml.load(fd.read()))

    head = """// This file was auto generated.  Do not edit.

#include "manager.hpp"

namespace phosphor
{
namespace inventory
{
namespace manager
{

const Manager::Events Manager::_events{
"""

    tail = """};

} // namespace manager
} // namespace inventory
} // namespace phosphor
"""

    r = ParseList([get_parsers(x) for x in yaml_files])()
    r.insert(0, lambda x: x.write(head))
    r.append(lambda x: x.write(tail))

    with open(args.output, 'w') as fd:
        r(fd)

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
OpenPOWER on IntegriCloud