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