Commit | Line | Data |
---|---|---|
dcdbb941 PP |
1 | # The MIT License (MIT) |
2 | # | |
13405819 | 3 | # Copyright (c) 2014-2016 Philippe Proulx <pproulx@efficios.com> |
dcdbb941 PP |
4 | # |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | # of this software and associated documentation files (the "Software"), to deal | |
7 | # in the Software without restriction, including without limitation the rights | |
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | # copies of the Software, and to permit persons to whom the Software is | |
10 | # furnished to do so, subject to the following conditions: | |
11 | # | |
12 | # The above copyright notice and this permission notice shall be included in | |
13 | # all copies or substantial portions of the Software. | |
14 | # | |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
21 | # THE SOFTWARE. | |
0f5c653b | 22 | |
79750125 | 23 | from pkg_resources import resource_filename |
dcdbb941 | 24 | from termcolor import cprint, colored |
e5aa0be3 PP |
25 | import barectf.tsdl182gen |
26 | import barectf.config | |
27 | import barectf.gen | |
e9094528 | 28 | import argparse |
e5aa0be3 | 29 | import os.path |
0f5c653b | 30 | import barectf |
dcdbb941 PP |
31 | import sys |
32 | import os | |
33 | import re | |
34 | ||
35 | ||
e5aa0be3 PP |
36 | def _perror(msg): |
37 | cprint('Error: ', 'red', end='', file=sys.stderr) | |
38 | cprint(msg, 'red', attrs=['bold'], file=sys.stderr) | |
39 | sys.exit(1) | |
dcdbb941 PP |
40 | |
41 | ||
e5aa0be3 PP |
42 | def _pconfig_error(e): |
43 | lines = [] | |
44 | ||
45 | while True: | |
46 | if e is None: | |
47 | break | |
48 | ||
49 | lines.append(str(e)) | |
50 | ||
51 | if not hasattr(e, 'prev'): | |
52 | break | |
53 | ||
54 | e = e.prev | |
55 | ||
56 | if len(lines) == 1: | |
57 | _perror(lines[0]) | |
58 | ||
59 | cprint('Error:', 'red', file=sys.stderr) | |
60 | ||
61 | for i, line in enumerate(lines): | |
62 | suf = ':' if i < len(lines) - 1 else '' | |
63 | cprint(' ' + line + suf, 'red', attrs=['bold'], file=sys.stderr) | |
64 | ||
65 | sys.exit(1) | |
6b1365c7 PP |
66 | |
67 | ||
68 | def _psuccess(msg): | |
69 | cprint('{}'.format(msg), 'green', attrs=['bold']) | |
dcdbb941 PP |
70 | |
71 | ||
72 | def _parse_args(): | |
73 | ap = argparse.ArgumentParser() | |
74 | ||
e5aa0be3 PP |
75 | ap.add_argument('-c', '--code-dir', metavar='DIR', action='store', |
76 | default=os.getcwd(), | |
77 | help='output directory of C source file') | |
f58be68f PP |
78 | ap.add_argument('--dump-config', action='store_true', |
79 | help='also dump the effective YAML configuration file used for generation') | |
e5aa0be3 PP |
80 | ap.add_argument('-H', '--headers-dir', metavar='DIR', action='store', |
81 | default=os.getcwd(), | |
82 | help='output directory of C header files') | |
f58be68f PP |
83 | ap.add_argument('-I', '--include-dir', metavar='DIR', action='append', |
84 | default=[], | |
85 | help='add directory DIR to the list of directories to be searched for include files') | |
86 | ap.add_argument('--ignore-include-not-found', action='store_true', | |
87 | help='continue to process the configuration file when included files are not found') | |
e5aa0be3 | 88 | ap.add_argument('-m', '--metadata-dir', metavar='DIR', action='store', |
dcdbb941 | 89 | default=os.getcwd(), |
e5aa0be3 | 90 | help='output directory of CTF metadata') |
dcdbb941 | 91 | ap.add_argument('-p', '--prefix', metavar='PREFIX', action='store', |
e5aa0be3 | 92 | help='override configuration\'s prefix') |
0f5c653b | 93 | ap.add_argument('-V', '--version', action='version', |
e5aa0be3 PP |
94 | version='%(prog)s {}'.format(barectf.__version__)) |
95 | ap.add_argument('config', metavar='CONFIG', action='store', | |
96 | help='barectf YAML configuration file') | |
dcdbb941 PP |
97 | |
98 | # parse args | |
99 | args = ap.parse_args() | |
100 | ||
e5aa0be3 | 101 | # validate output directories |
f58be68f | 102 | for d in [args.code_dir, args.headers_dir, args.metadata_dir] + args.include_dir: |
e5aa0be3 PP |
103 | if not os.path.isdir(d): |
104 | _perror('"{}" is not an existing directory'.format(d)) | |
dcdbb941 | 105 | |
e5aa0be3 PP |
106 | # validate that configuration file exists |
107 | if not os.path.isfile(args.config): | |
91126475 | 108 | _perror('"{}" is not an existing, regular file'.format(args.config)) |
dcdbb941 | 109 | |
79750125 PP |
110 | # append current working directory and provided include directory |
111 | args.include_dir += [os.getcwd(), resource_filename(__name__, 'include')] | |
112 | ||
dcdbb941 PP |
113 | return args |
114 | ||
115 | ||
e5aa0be3 PP |
116 | def _write_file(d, name, content): |
117 | with open(os.path.join(d, name), 'w') as f: | |
118 | f.write(content) | |
e9094528 | 119 | |
67bd189f | 120 | |
e5aa0be3 PP |
121 | def run(): |
122 | # parse arguments | |
123 | args = _parse_args() | |
8a70d9fb | 124 | |
e5aa0be3 PP |
125 | # create configuration |
126 | try: | |
f58be68f PP |
127 | config = barectf.config.from_yaml_file(args.config, args.include_dir, |
128 | args.ignore_include_not_found, | |
129 | args.dump_config) | |
e5aa0be3 PP |
130 | except barectf.config.ConfigError as e: |
131 | _pconfig_error(e) | |
132 | except Exception as e: | |
133 | _perror('unknown exception: {}'.format(e)) | |
6b1365c7 | 134 | |
e5aa0be3 PP |
135 | # replace prefix if needed |
136 | if args.prefix: | |
14e69d6b | 137 | try: |
e5aa0be3 PP |
138 | config.prefix = args.prefix |
139 | except barectf.config.ConfigError as e: | |
140 | _pconfig_error(e) | |
141 | ||
142 | # generate metadata | |
143 | metadata = barectf.tsdl182gen.from_metadata(config.metadata) | |
144 | ||
145 | try: | |
146 | _write_file(args.metadata_dir, 'metadata', metadata) | |
147 | except Exception as e: | |
148 | _perror('cannot write metadata file: {}'.format(e)) | |
149 | ||
150 | # create generator | |
151 | generator = barectf.gen.CCodeGenerator(config) | |
152 | ||
153 | # generate C headers | |
154 | header = generator.generate_header() | |
155 | bitfield_header = generator.generate_bitfield_header() | |
156 | ||
157 | try: | |
158 | _write_file(args.headers_dir, generator.get_header_filename(), header) | |
159 | _write_file(args.headers_dir, generator.get_bitfield_header_filename(), | |
160 | bitfield_header) | |
161 | except Exception as e: | |
162 | _perror('cannot write header files: {}'.format(e)) | |
163 | ||
164 | # generate C source | |
165 | c_src = generator.generate_c_src() | |
166 | ||
167 | try: | |
168 | _write_file(args.code_dir, '{}.c'.format(config.prefix.rstrip('_')), | |
169 | c_src) | |
170 | except Exception as e: | |
171 | _perror('cannot write C source file: {}'.format(e)) |