@@ -41,6 +41,8 @@ try: | |||||
except ImportError: | except ImportError: | ||||
yaml = None | yaml = None | ||||
from earwigbot.config.formatter import BotFormatter | |||||
from earwigbot.config.node import ConfigNode | |||||
from earwigbot.exceptions import NoConfigError | from earwigbot.exceptions import NoConfigError | ||||
__all__ = ["BotConfig"] | __all__ = ["BotConfig"] | ||||
@@ -80,12 +82,12 @@ class BotConfig(object): | |||||
self._decryption_cipher = None | self._decryption_cipher = None | ||||
self._data = None | self._data = None | ||||
self._components = _ConfigNode() | |||||
self._wiki = _ConfigNode() | |||||
self._irc = _ConfigNode() | |||||
self._commands = _ConfigNode() | |||||
self._tasks = _ConfigNode() | |||||
self._metadata = _ConfigNode() | |||||
self._components = ConfigNode() | |||||
self._wiki = ConfigNode() | |||||
self._irc = ConfigNode() | |||||
self._commands = ConfigNode() | |||||
self._tasks = ConfigNode() | |||||
self._metadata = ConfigNode() | |||||
self._nodes = [self._components, self._wiki, self._irc, self._commands, | self._nodes = [self._components, self._wiki, self._irc, self._commands, | ||||
self._tasks, self._metadata] | self._tasks, self._metadata] | ||||
@@ -123,8 +125,8 @@ class BotConfig(object): | |||||
logger = logging.getLogger("earwigbot") | logger = logging.getLogger("earwigbot") | ||||
logger.handlers = [] # Remove any handlers already attached to us | logger.handlers = [] # Remove any handlers already attached to us | ||||
logger.setLevel(logging.DEBUG) | logger.setLevel(logging.DEBUG) | ||||
color_formatter = _BotFormatter(color=True) | |||||
formatter = _BotFormatter() | |||||
color_formatter = BotFormatter(color=True) | |||||
formatter = BotFormatter() | |||||
if self.metadata.get("enableLogging"): | if self.metadata.get("enableLogging"): | ||||
hand = logging.handlers.TimedRotatingFileHandler | hand = logging.handlers.TimedRotatingFileHandler | ||||
@@ -253,7 +255,7 @@ class BotConfig(object): | |||||
exit. | exit. | ||||
Data from the config file is stored in six | Data from the config file is stored in six | ||||
:py:class:`~earwigbot.config._ConfigNode`\ s (:py:attr:`components`, | |||||
:py:class:`~earwigbot.config.ConfigNode`\ s (:py:attr:`components`, | |||||
:py:attr:`wiki`, :py:attr:`irc`, :py:attr:`commands`, :py:attr:`tasks`, | :py:attr:`wiki`, :py:attr:`irc`, :py:attr:`commands`, :py:attr:`tasks`, | ||||
:py:attr:`metadata`) for easy access (as well as the lower-level | :py:attr:`metadata`) for easy access (as well as the lower-level | ||||
:py:attr:`data` attribute). If passwords are encrypted, we'll use | :py:attr:`data` attribute). If passwords are encrypted, we'll use | ||||
@@ -342,81 +344,3 @@ class BotConfig(object): | |||||
pass | pass | ||||
return tasks | return tasks | ||||
class _ConfigNode(object): | |||||
def __iter__(self): | |||||
for key in self.__dict__: | |||||
yield key | |||||
def __getitem__(self, item): | |||||
return self.__dict__.__getitem__(item) | |||||
def _dump(self): | |||||
data = self.__dict__.copy() | |||||
for key, val in data.iteritems(): | |||||
if isinstance(val, _ConfigNode): | |||||
data[key] = val._dump() | |||||
return data | |||||
def _load(self, data): | |||||
self.__dict__ = data.copy() | |||||
def _decrypt(self, cipher, intermediates, item): | |||||
base = self.__dict__ | |||||
for inter in intermediates: | |||||
try: | |||||
base = base[inter] | |||||
except KeyError: | |||||
return | |||||
if item in base: | |||||
ciphertext = base[item].decode("hex") | |||||
base[item] = cipher.decrypt(ciphertext).rstrip("\x00") | |||||
def get(self, *args, **kwargs): | |||||
return self.__dict__.get(*args, **kwargs) | |||||
def keys(self): | |||||
return self.__dict__.keys() | |||||
def values(self): | |||||
return self.__dict__.values() | |||||
def items(self): | |||||
return self.__dict__.items() | |||||
def iterkeys(self): | |||||
return self.__dict__.iterkeys() | |||||
def itervalues(self): | |||||
return self.__dict__.itervalues() | |||||
def iteritems(self): | |||||
return self.__dict__.iteritems() | |||||
class _BotFormatter(logging.Formatter): | |||||
def __init__(self, color=False): | |||||
self._format = super(_BotFormatter, self).format | |||||
if color: | |||||
fmt = "[%(asctime)s %(lvl)s] %(name)s: %(message)s" | |||||
self.format = lambda record: self._format(self.format_color(record)) | |||||
else: | |||||
fmt = "[%(asctime)s %(levelname)-8s] %(name)s: %(message)s" | |||||
self.format = self._format | |||||
datefmt = "%Y-%m-%d %H:%M:%S" | |||||
super(_BotFormatter, self).__init__(fmt=fmt, datefmt=datefmt) | |||||
def format_color(self, record): | |||||
l = record.levelname.ljust(8) | |||||
if record.levelno == logging.DEBUG: | |||||
record.lvl = l.join(("\x1b[34m", "\x1b[0m")) # Blue | |||||
if record.levelno == logging.INFO: | |||||
record.lvl = l.join(("\x1b[32m", "\x1b[0m")) # Green | |||||
if record.levelno == logging.WARNING: | |||||
record.lvl = l.join(("\x1b[33m", "\x1b[0m")) # Yellow | |||||
if record.levelno == logging.ERROR: | |||||
record.lvl = l.join(("\x1b[31m", "\x1b[0m")) # Red | |||||
if record.levelno == logging.CRITICAL: | |||||
record.lvl = l.join(("\x1b[1m\x1b[31m", "\x1b[0m")) # Bold red | |||||
return record |
@@ -0,0 +1,51 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# | |||||
# Copyright (C) 2009-2012 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
# | |||||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
# of this software and associated documentation files (the "Software"), to deal | |||||
# in the Software without restriction, including without limitation the rights | |||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
# copies of the Software, and to permit persons to whom the Software is | |||||
# furnished to do so, subject to the following conditions: | |||||
# | |||||
# The above copyright notice and this permission notice shall be included in | |||||
# all copies or substantial portions of the Software. | |||||
# | |||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
# SOFTWARE. | |||||
import logging | |||||
__all__ = ["BotFormatter"] | |||||
class BotFormatter(logging.Formatter): | |||||
def __init__(self, color=False): | |||||
self._format = super(BotFormatter, self).format | |||||
if color: | |||||
fmt = "[%(asctime)s %(lvl)s] %(name)s: %(message)s" | |||||
self.format = lambda rec: self._format(self.format_color(rec)) | |||||
else: | |||||
fmt = "[%(asctime)s %(levelname)-8s] %(name)s: %(message)s" | |||||
self.format = self._format | |||||
datefmt = "%Y-%m-%d %H:%M:%S" | |||||
super(BotFormatter, self).__init__(fmt=fmt, datefmt=datefmt) | |||||
def format_color(self, record): | |||||
l = record.levelname.ljust(8) | |||||
if record.levelno == logging.DEBUG: | |||||
record.lvl = l.join(("\x1b[34m", "\x1b[0m")) # Blue | |||||
if record.levelno == logging.INFO: | |||||
record.lvl = l.join(("\x1b[32m", "\x1b[0m")) # Green | |||||
if record.levelno == logging.WARNING: | |||||
record.lvl = l.join(("\x1b[33m", "\x1b[0m")) # Yellow | |||||
if record.levelno == logging.ERROR: | |||||
record.lvl = l.join(("\x1b[31m", "\x1b[0m")) # Red | |||||
if record.levelno == logging.CRITICAL: | |||||
record.lvl = l.join(("\x1b[1m\x1b[31m", "\x1b[0m")) # Bold red | |||||
return record |
@@ -0,0 +1,73 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# | |||||
# Copyright (C) 2009-2012 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
# | |||||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
# of this software and associated documentation files (the "Software"), to deal | |||||
# in the Software without restriction, including without limitation the rights | |||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
# copies of the Software, and to permit persons to whom the Software is | |||||
# furnished to do so, subject to the following conditions: | |||||
# | |||||
# The above copyright notice and this permission notice shall be included in | |||||
# all copies or substantial portions of the Software. | |||||
# | |||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
# SOFTWARE. | |||||
__all__ = ["ConfigNode"] | |||||
class ConfigNode(object): | |||||
def __iter__(self): | |||||
for key in self.__dict__: | |||||
yield key | |||||
def __getitem__(self, item): | |||||
return self.__dict__.__getitem__(item) | |||||
def _dump(self): | |||||
data = self.__dict__.copy() | |||||
for key, val in data.iteritems(): | |||||
if isinstance(val, ConfigNode): | |||||
data[key] = val._dump() | |||||
return data | |||||
def _load(self, data): | |||||
self.__dict__ = data.copy() | |||||
def _decrypt(self, cipher, intermediates, item): | |||||
base = self.__dict__ | |||||
for inter in intermediates: | |||||
try: | |||||
base = base[inter] | |||||
except KeyError: | |||||
return | |||||
if item in base: | |||||
ciphertext = base[item].decode("hex") | |||||
base[item] = cipher.decrypt(ciphertext).rstrip("\x00") | |||||
def get(self, *args, **kwargs): | |||||
return self.__dict__.get(*args, **kwargs) | |||||
def keys(self): | |||||
return self.__dict__.keys() | |||||
def values(self): | |||||
return self.__dict__.values() | |||||
def items(self): | |||||
return self.__dict__.items() | |||||
def iterkeys(self): | |||||
return self.__dict__.iterkeys() | |||||
def itervalues(self): | |||||
return self.__dict__.itervalues() | |||||
def iteritems(self): | |||||
return self.__dict__.iteritems() |