1############################################################################### 2# Copyright (c) 2013 INRIA 3# 4# This program is free software; you can redistribute it and/or modify 5# it under the terms of the GNU General Public License version 2 as 6# published by the Free Software Foundation; 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software 15# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16# 17# Authors: Daniel Camara <daniel.camara@inria.fr> 18# Mathieu Lacage <mathieu.lacage@sophia.inria.fr> 19############################################################################### 20''' 21 Utils.py 22 23 This file stores the utility functions that are used by the different Bake 24 modules. 25''' 26 27import subprocess 28import os 29import shutil 30import sys 31from xml.etree import ElementTree 32from xml.dom import minidom 33from bake.Exceptions import TaskError 34 35def print_backtrace(): 36 """ Prints the full trace of the exception.""" 37 38 import sys 39 import traceback 40 trace = "" 41 exception = "" 42 43 exceptionHandling = True 44 if(not sys.exc_info()[0] or not sys.exc_info()[1]): 45 exceptionHandling = False 46 47 if exceptionHandling: 48 exc_list = traceback.format_exception_only (sys.exc_info()[0],sys.exc_info()[1]) 49 50 for entry in exc_list: 51 exception += entry 52 53 tb_list = traceback.format_tb(sys.exc_info()[2]) 54 else: 55 tb_list = traceback.format_stack() 56 57 for entry in tb_list: 58 trace += entry 59 60 toWrite = "\n%s\n%s" % (exception, trace) 61 sys.stderr.write(toWrite) 62 return toWrite 63 64def split_args(stringP): 65 """ Split arguments respecting aggregate strings.""" 66 67 returnValue = [] 68 rawSplit = stringP.split() 69 compensateElement=False 70 elementStr = '' 71 for element in rawSplit: 72 if "'" in element : 73 if element.count("'") % 2 != 0 : 74 if compensateElement : 75 compensateElement = False 76 returnValue.append(elementStr + " " + str(element)) 77 elementStr = '' 78 element = None 79 elif element.find("'") == element.rfind("'") : 80 compensateElement = True 81 82 if compensateElement : 83 if len(elementStr) > 0 : 84 elementStr = elementStr + " " + element 85 else : 86 elementStr = element 87 else : 88 if element : 89 returnValue.append(element) 90 91 return returnValue 92 93def prettify(elem): 94 """ Returns a pretty-printed XML string for the Element. 95 """ 96 rough_string = ElementTree.tostring(elem, 'utf-8') 97 reparsed = minidom.parseString(rough_string) 98 string = reparsed.toprettyxml(indent=" ") 99 new_string='' 100 for line in string.split('\n'): 101 if line.strip(): 102 new_string += line + '\n' 103 104 return new_string 105 106def mergeDirs(sourcePath, destPath): 107 """ Merge two folders, creating the structure and copying the files from 108 source to destination, when these are missing, and skipping files when 109 these are already present on the destination. Pay attention that what 110 this function does is a merge of directories contents not of file 111 content. 112 """ 113 114 for root, dirs, files in os.walk(sourcePath): 115 116 #figure out where we're going 117 dest = destPath + root.replace(sourcePath, '') 118 119 #if we're in a directory that doesn't exist in the destination folder 120 #then create a new folder 121 if not os.path.isdir(dest): 122 os.mkdir(dest) 123# print 'Directory created at: ' + dest 124 125 #loop through all files in the directory 126 for f in files: 127 #compute current (old) & new file locations 128 oldLoc = root + '/' + f 129 newLoc = dest + '/' + f 130 131 if not os.path.isfile(newLoc): 132 try: 133 shutil.copy2(oldLoc, newLoc) 134# print 'File ' + f + ' copied.' 135 except IOError: 136# print 'file "' + f + '" already exists' 137 pass 138 139 140class ModuleAttribute: 141 """ Definition of the Bake attribute. An attribute is basically one of the 142 options the user can have to configure the Bake usage. 143 """ 144 145 def __init__(self, name, value, help, mandatory): 146 """ Initialization, all the fields are mandatory.""" 147 148 self._name = name 149 self.value = value 150 self._help = help 151 self._mandatory = mandatory 152 153 @property 154 def name(self): 155 """ Returns the stored name of the attribute.""" 156 157 return self._name 158 159 @property 160 def help(self): 161 """ Returns the help string attached to the attribute.""" 162 return self._help 163 164 @property 165 def is_mandatory(self): 166 """ Returns if the attribute is mandatory or not.""" 167 return self._mandatory 168 169 170class ModuleAttributeBase(object): 171 """ Definition of the Bake attribute structure. An attribute may be 172 organized in blocks, this structure stores this grouping of attributes. 173 """ 174 175 def __init__(self): 176 self._attributes = dict() 177 self._children = [] 178 179 def children(self): 180 """ Returns the children attributes attached to this attribute.""" 181 182 return self._children 183 184 def add_child(self, child, name): 185 """ Attach a child attribute to this attribute.""" 186 187 self._children.append([child, name]) 188 189 def add_attribute(self, name, value, help, mandatory = False): 190 """ Creates a new attribute attached to this one.""" 191 192 assert not name in self._attributes 193 self._attributes[name] = ModuleAttribute(name, value, help, mandatory) 194 195 def attributes(self): 196 """ Returns the list of attributes attached to this attribute block.""" 197 198 return self._attributes.values() 199 200 def attribute(self, name): 201 """ Returns a specific attribute.""" 202 203 if not name in self._attributes: 204 return None 205 else: 206 return self._attributes[name] 207 208class ColorTool: 209 """ Class responsible to handle the colored message printing.""" 210 211 OK = '\033[34m' 212 WARNING = '\033[33m' 213 FAIL = '\033[91m' 214 ENDC = '\033[0m' 215 216 @classmethod 217 def has_colours(self, stream): 218 if not hasattr(stream, "isatty"): 219 return False 220 if not stream.isatty(): 221 return False # auto color only on TTYs 222 try: 223 import curses 224 curses.setupterm() 225 return curses.tigetnum("colors") > 2 226 except: 227 # guess false in case of error 228 return False 229 230 @classmethod 231 def disable(self): 232 """ Disables the color print. """ 233 234 ColorTool.OK = '' 235 ColorTool.WARNING = '' 236 ColorTool.FAIL = '' 237 ColorTool.ENDC = '' 238 239 @classmethod 240 def cPrint(self, color, message): 241 """ Print the message with the defined color. """ 242 243 sys.stdout.write(color + message + self.ENDC) 244 sys.stdout.flush() 245 246 @classmethod 247 def cPrintln(self,color, message): 248 """ Print the message with the defined color and ends with a new line. """ 249 250 self.cPrint(color, message + os.linesep) 251 252 253 254