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