Make configuration and metadata objects immutable
[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_file(args.config, args.include_dir,
116 args.ignore_include_not_found,
117 args.dump_config)
118 except barectf.config.ConfigParseError 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 config = barectf.config.Config(config.metadata,
129 args.prefix,
130 config.options)
131
132 # generate metadata
133 metadata = barectf.tsdl182gen.from_metadata(config.metadata)
134
135 try:
136 _write_file(args.metadata_dir, 'metadata', metadata)
137 except Exception as e:
138 _perror('Cannot write metadata file: {}'.format(e))
139
140 # create generator
141 generator = barectf.gen.CCodeGenerator(config)
142
143 # generate C headers
144 header = generator.generate_header()
145 bitfield_header = generator.generate_bitfield_header()
146
147 try:
148 _write_file(args.headers_dir, generator.get_header_filename(), header)
149 _write_file(args.headers_dir, generator.get_bitfield_header_filename(),
150 bitfield_header)
151 except Exception as e:
152 _perror('Cannot write header files: {}'.format(e))
153
154 # generate C source
155 c_src = generator.generate_c_src()
156
157 try:
158 _write_file(args.code_dir, '{}.c'.format(config.prefix.rstrip('_')),
159 c_src)
160 except Exception as e:
161 _perror('Cannot write C source file: {}'.format(e))
This page took 0.034376 seconds and 5 git commands to generate.