cli: print traceback for unknown exceptions
[deliverable/barectf.git] / barectf / cli.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2014-2016 Philippe Proulx <pproulx@efficios.com>
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.
22
23 from pkg_resources import resource_filename
24 from termcolor import cprint, colored
25 import barectf.tsdl182gen
26 import barectf.config
27 import barectf.gen
28 import argparse
29 import os.path
30 import barectf
31 import sys
32 import os
33 import re
34
35
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)
40
41
42 def _pconfig_error(exc):
43 cprint('Error:', 'red', file=sys.stderr)
44
45 for ctx in reversed(exc.ctx):
46 if ctx.msg is not None:
47 msg = ' {}'.format(ctx.msg)
48 else:
49 msg = ''
50 cprint(' {}:{}'.format(ctx.name, msg), 'red', attrs=['bold'],
51 file=sys.stderr)
52
53 sys.exit(1)
54
55
56 def _psuccess(msg):
57 cprint('{}'.format(msg), 'green', attrs=['bold'])
58
59
60 def _parse_args():
61 ap = argparse.ArgumentParser()
62
63 ap.add_argument('-c', '--code-dir', metavar='DIR', action='store',
64 default=os.getcwd(),
65 help='output directory of C source file')
66 ap.add_argument('--dump-config', action='store_true',
67 help='also dump the effective YAML configuration file used for generation')
68 ap.add_argument('-H', '--headers-dir', metavar='DIR', action='store',
69 default=os.getcwd(),
70 help='output directory of C header files')
71 ap.add_argument('-I', '--include-dir', metavar='DIR', action='append',
72 default=[],
73 help='add directory DIR to the list of directories to be searched for include files')
74 ap.add_argument('--ignore-include-not-found', action='store_true',
75 help='continue to process the configuration file when included files are not found')
76 ap.add_argument('-m', '--metadata-dir', metavar='DIR', action='store',
77 default=os.getcwd(),
78 help='output directory of CTF metadata')
79 ap.add_argument('-p', '--prefix', metavar='PREFIX', action='store',
80 help='override configuration\'s prefix')
81 ap.add_argument('-V', '--version', action='version',
82 version='%(prog)s {}'.format(barectf.__version__))
83 ap.add_argument('config', metavar='CONFIG', action='store',
84 help='barectf YAML configuration file')
85
86 # parse args
87 args = ap.parse_args()
88
89 # validate output directories
90 for d in [args.code_dir, args.headers_dir, args.metadata_dir] + args.include_dir:
91 if not os.path.isdir(d):
92 _perror('"{}" is not an existing directory'.format(d))
93
94 # validate that configuration file exists
95 if not os.path.isfile(args.config):
96 _perror('"{}" is not an existing, regular file'.format(args.config))
97
98 # append current working directory and provided include directory
99 args.include_dir += [os.getcwd(), resource_filename(__name__, 'include')]
100
101 return args
102
103
104 def _write_file(d, name, content):
105 with open(os.path.join(d, name), 'w') as f:
106 f.write(content)
107
108
109 def run():
110 # parse arguments
111 args = _parse_args()
112
113 # create configuration
114 try:
115 config = barectf.config.from_yaml_file(args.config, args.include_dir,
116 args.ignore_include_not_found,
117 args.dump_config)
118 except barectf.config.ConfigError as e:
119 _pconfig_error(e)
120 except Exception as e:
121 import traceback
122
123 traceback.print_exc()
124 _perror('unknown exception: {}'.format(e))
125
126 # replace prefix if needed
127 if args.prefix:
128 try:
129 config.prefix = args.prefix
130 except barectf.config.ConfigError as e:
131 _pconfig_error(e)
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 e:
139 _perror('cannot write metadata file: {}'.format(e))
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 e:
153 _perror('cannot write header files: {}'.format(e))
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 e:
162 _perror('cannot write C source file: {}'.format(e))
This page took 0.033941 seconds and 5 git commands to generate.