# Copyright 2022-2025 The Ramble Authors
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
import sys
import inspect
from ramble.util.logger import logger
#: whether we should write stack traces or short error messages
#: this is module-scoped because it needs to be set very early
debug = False
[docs]
class RambleError(Exception):
"""This is the superclass for all Ramble errors.
Subclasses can be found in the modules they have to do with.
"""
def __init__(self, message, long_message=None):
super().__init__()
self.message = message
self._long_message = long_message
# for exceptions raised from child build processes, we save the
# traceback as a string and print it in the parent.
self.traceback = None
# we allow exceptions to print debug info via print_context()
# before they are caught at the top level. If they *haven't*
# printed context early, we do it by default when die() is
# called, so we need to remember whether it's been called.
self.printed = False
@property
def long_message(self):
return self._long_message
[docs]
def print_context(self):
"""Print extended debug information about this exception.
This is usually printed when the top-level Ramble error handler
calls ``die()``, but it can be called separately beforehand if a
lower-level error handler needs to print error context and
continue without raising the exception to the top level.
"""
if self.printed:
return
# basic debug message
logger.error(self.message)
if self.long_message:
sys.stderr.write(self.long_message)
sys.stderr.write("\n")
# stack trace, etc. in debug mode.
if debug:
if self.traceback:
# exception came from a build child, already got
# traceback in child, so print it.
sys.stderr.write(self.traceback)
else:
# run parent exception hook.
sys.excepthook(*sys.exc_info())
sys.stderr.flush()
self.printed = True
[docs]
def die(self):
self.print_context()
sys.exit(1)
def __str__(self):
msg = self.message
if self._long_message:
msg += "\n %s" % self._long_message
return msg
def __repr__(self):
args = [repr(self.message), repr(self.long_message)]
args = ",".join(args)
qualified_name = inspect.getmodule(self).__name__ + "." + type(self).__name__
return qualified_name + "(" + args + ")"
def __reduce__(self):
return type(self), (self.message, self.long_message)
[docs]
class SpecError(RambleError):
"""Superclass for all errors that occur while constructing specs."""
[docs]
class RambleCommandError(Exception):
"""Raised when RambleCommand execution fails."""