• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2014-2016 Intel Corporation.   All Rights Reserved.
2#
3# Permission is hereby granted, free of charge, to any person obtaining a
4# copy of this software and associated documentation files (the "Software"),
5# to deal in the Software without restriction, including without limitation
6# the rights to use, copy, modify, merge, publish, distribute, sublicense,
7# and/or sell copies of the Software, and to permit persons to whom the
8# Software is furnished to do so, subject to the following conditions:
9#
10# The above copyright notice and this permission notice (including the next
11# paragraph) shall be included in all copies or substantial portions of the
12# Software.
13#
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20# IN THE SOFTWARE.
21
22# Python source
23from __future__ import print_function
24import os
25import errno
26import sys
27import argparse
28from mako.template import Template
29from mako.exceptions import RichTraceback
30
31
32#==============================================================================
33class MakoTemplateWriter:
34    '''
35        MakoTemplateWriter - Class (namespace) for functions to generate strings
36        or files using the Mako template module.
37
38        See http://docs.makotemplates.org/en/latest/ for
39        mako documentation.
40   '''
41
42    @staticmethod
43    def to_string(template_filename, **kwargs):
44        '''
45            Write template data to a string object and return the string
46        '''
47        from mako.template      import Template
48        from mako.exceptions    import RichTraceback
49
50        try:
51            template = Template(filename=template_filename)
52            # Split + Join fixes line-endings for whatever platform you are using
53            return '\n'.join(template.render(**kwargs).splitlines())
54        except:
55            traceback = RichTraceback()
56            for (filename, lineno, function, line) in traceback.traceback:
57                print('File %s, line %s, in %s' % (filename, lineno, function))
58                print(line, '\n')
59            print('%s: %s' % (str(traceback.error.__class__.__name__), traceback.error))
60
61    @staticmethod
62    def to_file(template_filename, output_filename, **kwargs):
63        '''
64            Write template data to a file
65        '''
66        if not os.path.exists(os.path.dirname(output_filename)):
67            try:
68                os.makedirs(os.path.dirname(output_filename))
69            except OSError as err:
70                if err.errno != errno.EEXIST:
71                    raise
72        with open(output_filename, 'w') as outfile:
73            print(MakoTemplateWriter.to_string(template_filename, **kwargs), file=outfile)
74
75
76#==============================================================================
77class ArgumentParser(argparse.ArgumentParser):
78    '''
79    Subclass of argparse.ArgumentParser
80
81    Allow parsing from command files that start with @
82    Example:
83      >bt run @myargs.txt
84
85    Contents of myargs.txt:
86      -m <machine>
87      --target cdv_win7
88
89    The below function allows multiple args to be placed on the same text-file line.
90    The default is one token per line, which is a little cumbersome.
91
92    Also allow all characters after a '#' character to be ignored.
93    '''
94
95    #==============================================================================
96    class _HelpFormatter(argparse.RawTextHelpFormatter):
97        ''' Better help formatter for argument parser '''
98
99        def _split_lines(self, text, width):
100            ''' optimized split lines algorighm, indents split lines '''
101            lines = text.splitlines()
102            out_lines = []
103            if len(lines):
104                out_lines.append(lines[0])
105                for line in lines[1:]:
106                    out_lines.append('  ' + line)
107            return out_lines
108
109    #==============================================================================
110    def __init__(self, *args, **kwargs):
111        ''' Constructor.  Compatible with argparse.ArgumentParser(),
112            but with some modifications for better usage and help display.
113        '''
114        super(ArgumentParser, self).__init__(
115                *args,
116                fromfile_prefix_chars='@',
117                formatter_class=ArgumentParser._HelpFormatter,
118                **kwargs)
119
120    #==========================================================================
121    def convert_arg_line_to_args(self, arg_line):
122        ''' convert one line of parsed file to arguments '''
123        arg_line = arg_line.split('#', 1)[0]
124        if sys.platform == 'win32':
125            arg_line = arg_line.replace('\\', '\\\\')
126        for arg in shlex.split(arg_line):
127            if not arg.strip():
128                continue
129            yield arg
130
131    #==========================================================================
132    def _read_args_from_files(self, arg_strings):
133        ''' read arguments from files '''
134        # expand arguments referencing files
135        new_arg_strings = []
136        for arg_string in arg_strings:
137
138            # for regular arguments, just add them back into the list
139            if arg_string[0] not in self.fromfile_prefix_chars:
140                new_arg_strings.append(arg_string)
141
142            # replace arguments referencing files with the file content
143            else:
144                filename = arg_string[1:]
145
146                # Search in sys.path
147                if not os.path.exists(filename):
148                    for path in sys.path:
149                        filename = os.path.join(path, arg_string[1:])
150                        if os.path.exists(filename):
151                            break
152
153                try:
154                    args_file = open(filename)
155                    try:
156                        arg_strings = []
157                        for arg_line in args_file.read().splitlines():
158                            for arg in self.convert_arg_line_to_args(arg_line):
159                                arg_strings.append(arg)
160                        arg_strings = self._read_args_from_files(arg_strings)
161                        new_arg_strings.extend(arg_strings)
162                    finally:
163                        args_file.close()
164                except IOError:
165                    err = sys.exc_info()[1]
166                    self.error(str(err))
167
168        # return the modified argument list
169        return new_arg_strings
170