| # |
| # -*- coding: utf-8 -*- |
| # |
| # This file is part of reclass (http://github.com/madduck/reclass) |
| # |
| # Copyright © 2007–14 martin f. krafft <madduck@madduck.net> |
| # Released under the terms of the Artistic Licence 2.0 |
| # |
| |
| import posix, sys |
| import traceback |
| |
| from reclass.defaults import PARAMETER_INTERPOLATION_SENTINELS |
| |
| class ReclassException(Exception): |
| |
| def __init__(self, rc=posix.EX_SOFTWARE, msg=None): |
| super(ReclassException, self).__init__() |
| self._rc = rc |
| self._msg = msg |
| self._traceback = traceback.format_exc() |
| |
| message = property(lambda self: self._get_message()) |
| rc = property(lambda self: self._rc) |
| |
| def __str__(self): |
| return self.message + '\n' + super(ReclassException, self).__str__() |
| |
| def _get_message(self): |
| if self._msg: |
| return self._msg |
| else: |
| return 'No error message provided.' |
| |
| def exit_with_message(self, out=sys.stderr): |
| print >>out, self.message |
| if self._traceback: |
| print >>out, self._traceback |
| sys.exit(self.rc) |
| |
| |
| class PermissionError(ReclassException): |
| |
| def __init__(self, msg, rc=posix.EX_NOPERM): |
| super(PermissionError, self).__init__(rc=rc, msg=msg) |
| |
| |
| class InvocationError(ReclassException): |
| |
| def __init__(self, msg, rc=posix.EX_USAGE): |
| super(InvocationError, self).__init__(rc=rc, msg=msg) |
| |
| |
| class ConfigError(ReclassException): |
| |
| def __init__(self, msg, rc=posix.EX_CONFIG): |
| super(ConfigError, self).__init__(rc=rc, msg=msg) |
| |
| |
| class DuplicateUriError(ConfigError): |
| |
| def __init__(self, nodes_uri, classes_uri): |
| super(DuplicateUriError, self).__init__(msg=None) |
| self._nodes_uri = nodes_uri |
| self._classes_uri = classes_uri |
| |
| def _get_message(self): |
| return "The inventory URIs must not be the same " \ |
| "for nodes and classes: {0}".format(self._nodes_uri) |
| |
| |
| class UriOverlapError(ConfigError): |
| |
| def __init__(self, nodes_uri, classes_uri): |
| super(UriOverlapError, self).__init__(msg=None) |
| self._nodes_uri = nodes_uri |
| self._classes_uri = classes_uri |
| |
| def _get_message(self): |
| msg = "The URIs for the nodes and classes inventories must not " \ |
| "overlap, but {0} and {1} do." |
| return msg.format(self._nodes_uri, self._classes_uri) |
| |
| |
| class NotFoundError(ReclassException): |
| |
| def __init__(self, msg, rc=posix.EX_IOERR): |
| super(NotFoundError, self).__init__(rc=rc, msg=msg) |
| |
| |
| class NodeNotFound(NotFoundError): |
| |
| def __init__(self, storage, nodename, uri): |
| super(NodeNotFound, self).__init__(msg=None) |
| self._storage = storage |
| self._name = nodename |
| self._uri = uri |
| |
| def _get_message(self): |
| msg = "Node '{0}' not found under {1}://{2}" |
| return msg.format(self._name, self._storage, self._uri) |
| |
| |
| class ClassNotFound(NotFoundError): |
| |
| def __init__(self, storage, classname, uri, nodename=None): |
| super(ClassNotFound, self).__init__(msg=None) |
| self._storage = storage |
| self._name = classname |
| self._uri = uri |
| self._nodename = nodename |
| |
| def _get_message(self): |
| if self._nodename: |
| msg = "Class '{0}' (in ancestry of node '{1}') not found " \ |
| "under {2}://{3}" |
| else: |
| msg = "Class '{0}' not found under {2}://{3}" |
| return msg.format(self._name, self._nodename, self._storage, self._uri) |
| |
| def set_nodename(self, nodename): |
| self._nodename = nodename |
| |
| |
| class InterpolationError(ReclassException): |
| |
| def __init__(self, msg, rc=posix.EX_DATAERR): |
| super(InterpolationError, self).__init__(rc=rc, msg=msg) |
| |
| |
| class UndefinedVariableError(InterpolationError): |
| |
| def __init__(self, var, context=None): |
| super(UndefinedVariableError, self).__init__(msg=None) |
| self._var = var |
| self._context = context |
| var = property(lambda self: self._var) |
| context = property(lambda self: self._context) |
| |
| def _get_message(self): |
| msg = "Cannot resolve " + self._var.join(PARAMETER_INTERPOLATION_SENTINELS) |
| if self._context: |
| msg += ' in the context of %s' % self._context |
| return msg |
| |
| def set_context(self, context): |
| self._context = context |
| |
| |
| class IncompleteInterpolationError(InterpolationError): |
| |
| def __init__(self, string, end_sentinel): |
| super(IncompleteInterpolationError, self).__init__(msg=None) |
| self._ref = string.join(PARAMETER_INTERPOLATION_SENTINELS) |
| self._end_sentinel = end_sentinel |
| |
| def _get_message(self): |
| msg = "Missing '{0}' to end reference: {1}" |
| return msg.format(self._end_sentinel, self._ref) |
| |
| |
| class InfiniteRecursionError(InterpolationError): |
| |
| def __init__(self, path, ref): |
| super(InfiniteRecursionError, self).__init__(msg=None) |
| self._path = path |
| self._ref = ref.join(PARAMETER_INTERPOLATION_SENTINELS) |
| |
| def _get_message(self): |
| msg = "Infinite recursion while resolving {0} at {1}" |
| return msg.format(self._ref, self._path) |
| |
| |
| class MappingError(ReclassException): |
| |
| def __init__(self, msg, rc=posix.EX_DATAERR): |
| super(MappingError, self).__init__(rc=rc, msg=msg) |
| |
| |
| class MappingFormatError(MappingError): |
| |
| def __init__(self, msg): |
| super(MappingFormatError, self).__init__(msg) |
| |
| |
| class NameError(ReclassException): |
| |
| def __init__(self, msg, rc=posix.EX_DATAERR): |
| super(NameError, self).__init__(rc=rc, msg=msg) |
| |
| |
| class InvalidClassnameError(NameError): |
| |
| def __init__(self, invalid_character, classname): |
| super(InvalidClassnameError, self).__init__(msg=None) |
| self._char = invalid_character |
| self._classname = classname |
| |
| def _get_message(self): |
| msg = "Invalid character '{0}' in class name '{1}'." |
| return msg.format(self._char, self._classname) |
| |
| |
| class DuplicateNodeNameError(NameError): |
| |
| def __init__(self, storage, name, uri1, uri2): |
| super(DuplicateNodeNameError, self).__init__(msg=None) |
| self._storage = storage |
| self._name = name |
| self._uris = (uri1, uri2) |
| |
| def _get_message(self): |
| msg = "{0}: Definition of node '{1}' in '{2}' collides with " \ |
| "definition in '{3}'. Nodes can only be defined once " \ |
| "per inventory." |
| return msg.format(self._storage, self._name, self._uris[1], self._uris[0]) |