1# MIT License 2# 3# Copyright The SCons Foundation 4# 5# Permission is hereby granted, free of charge, to any person obtaining 6# a copy of this software and associated documentation files (the 7# "Software"), to deal in the Software without restriction, including 8# without limitation the rights to use, copy, modify, merge, publish, 9# distribute, sublicense, and/or sell copies of the Software, and to 10# permit persons to whom the Software is furnished to do so, subject to 11# the following conditions: 12# 13# The above copyright notice and this permission notice shall be included 14# in all copies or substantial portions of the Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24"""SCons exception classes. 25 26Used to handle internal and user errors in SCons. 27 28""" 29 30import shutil 31import SCons.Util 32 33 34class BuildError(Exception): 35 """SCons Errors that can occur while building. 36 37 Attributes: 38 Information about the cause of the build error : 39 40 errstr: a description of the error message 41 42 status: the return code of the action that caused the build error. 43 Must be set to a non-zero value even if the build error is not due 44 to an action returning a non-zero returned code. 45 46 exitstatus: SCons exit status due to this build error. 47 Must be nonzero unless due to an explicit Exit() 48 call. Not always the same as status, since 49 actions return a status code that should be 50 respected, but SCons typically exits with 2 51 irrespective of the return value of the failed 52 action. 53 54 filename: The name of the file or directory that caused the 55 build error. Set to None if no files are associated with 56 this error. This might be different from the target 57 being built. For example, failure to create the 58 directory in which the target file will appear. It 59 can be None if the error is not due to a particular 60 filename. 61 62 exc_info: Info about exception that caused the build 63 error. Set to (None, None, None) if this build 64 error is not due to an exception. 65 66 Information about the what caused the build error : 67 68 node: the error occurred while building this target node(s) 69 70 executor: the executor that caused the build to fail (might 71 be None if the build failures is not due to the 72 executor failing) 73 74 action: the action that caused the build to fail (might be 75 None if the build failures is not due to the an 76 action failure) 77 78 command: the command line for the action that caused the 79 build to fail (might be None if the build failures 80 is not due to the an action failure) 81 82 """ 83 84 def __init__(self, 85 node=None, errstr="Unknown error", status=2, exitstatus=2, 86 filename=None, executor=None, action=None, command=None, 87 exc_info=(None, None, None)): 88 89 # py3: errstr should be string and not bytes. 90 91 self.errstr = SCons.Util.to_String(errstr) 92 self.status = status 93 self.exitstatus = exitstatus 94 self.filename = filename 95 self.exc_info = exc_info 96 97 self.node = node 98 self.executor = executor 99 self.action = action 100 self.command = command 101 102 Exception.__init__(self, node, errstr, status, exitstatus, filename, 103 executor, action, command, exc_info) 104 105 def __str__(self): 106 if self.filename: 107 return self.filename + ': ' + self.errstr 108 else: 109 return self.errstr 110 111class InternalError(Exception): 112 pass 113 114class UserError(Exception): 115 pass 116 117class StopError(Exception): 118 pass 119 120class SConsEnvironmentError(Exception): 121 pass 122 123class MSVCError(IOError): 124 pass 125 126class ExplicitExit(Exception): 127 def __init__(self, node=None, status=None, *args): 128 self.node = node 129 self.status = status 130 self.exitstatus = status 131 Exception.__init__(self, *args) 132 133def convert_to_BuildError(status, exc_info=None): 134 """Convert a return code to a BuildError Exception. 135 136 The `buildError.status` we set here will normally be 137 used as the exit status of the "scons" process. 138 139 Args: 140 status: can either be a return code or an Exception. 141 exc_info (tuple, optional): explicit exception information. 142 143 """ 144 145 if not exc_info and isinstance(status, Exception): 146 exc_info = (status.__class__, status, None) 147 148 149 if isinstance(status, BuildError): 150 buildError = status 151 buildError.exitstatus = 2 # always exit with 2 on build errors 152 elif isinstance(status, ExplicitExit): 153 status = status.status 154 errstr = 'Explicit exit, status %s' % status 155 buildError = BuildError( 156 errstr=errstr, 157 status=status, # might be 0, OK here 158 exitstatus=status, # might be 0, OK here 159 exc_info=exc_info) 160 elif isinstance(status, (StopError, UserError)): 161 buildError = BuildError( 162 errstr=str(status), 163 status=2, 164 exitstatus=2, 165 exc_info=exc_info) 166 elif isinstance(status, shutil.SameFileError): 167 # PY3 has a exception for when copying file to itself 168 # It's object provides info differently than below 169 try: 170 filename = status.filename 171 except AttributeError: 172 filename = None 173 174 buildError = BuildError( 175 errstr=status.args[0], 176 status=status.errno, 177 exitstatus=2, 178 filename=filename, 179 exc_info=exc_info) 180 181 elif isinstance(status, (SConsEnvironmentError, OSError, IOError)): 182 # If an IOError/OSError happens, raise a BuildError. 183 # Report the name of the file or directory that caused the 184 # error, which might be different from the target being built 185 # (for example, failure to create the directory in which the 186 # target file will appear). 187 filename = getattr(status, 'filename', None) 188 strerror = getattr(status, 'strerror', str(status)) 189 errno = getattr(status, 'errno', 2) 190 191 buildError = BuildError( 192 errstr=strerror, 193 status=errno, 194 exitstatus=2, 195 filename=filename, 196 exc_info=exc_info) 197 elif isinstance(status, Exception): 198 buildError = BuildError( 199 errstr='%s : %s' % (status.__class__.__name__, status), 200 status=2, 201 exitstatus=2, 202 exc_info=exc_info) 203 elif SCons.Util.is_String(status): 204 buildError = BuildError( 205 errstr=status, 206 status=2, 207 exitstatus=2) 208 else: 209 buildError = BuildError( 210 errstr="Error %s" % status, 211 status=status, 212 exitstatus=2) 213 214 #import sys 215 #sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)\n"%(status,buildError.errstr, buildError.status)) 216 return buildError 217 218# Local Variables: 219# tab-width:4 220# indent-tabs-mode:nil 221# End: 222# vim: set expandtab tabstop=4 shiftwidth=4: 223