Better communicate issues with load/unload/reload of modules

This commit is contained in:
jesopo 2018-09-24 13:10:39 +01:00
parent 7522b0fae2
commit b7f7c9342b
2 changed files with 65 additions and 42 deletions

View file

@ -2,6 +2,23 @@ import glob, imp, inspect, os, sys, uuid
BITBOT_HOOKS_MAGIC = "__bitbot_hooks" BITBOT_HOOKS_MAGIC = "__bitbot_hooks"
class ModuleException(Exception):
pass
class ModuleWarning(Exception):
pass
class ModuleNotFoundException(ModuleException):
pass
class ModuleNameCollisionException(ModuleException):
pass
class ModuleLoadException(ModuleException):
pass
class ModuleUnloadException(ModuleException):
pass
class ModuleNotLoadedWarning(ModuleWarning):
pass
class BaseModule(object): class BaseModule(object):
def __init__(self, bot, events, exports): def __init__(self, bot, events, exports):
pass pass
@ -33,28 +50,32 @@ class ModuleManager(object):
# this is a hashflag # this is a hashflag
if line == "#--ignore": if line == "#--ignore":
# nope, ignore this module. # nope, ignore this module.
return None raise ModuleNotLoadedWarning("module ignored")
elif line_split[0] == "#--require-config" and len( elif line_split[0] == "#--require-config" and len(
line_split) > 1: line_split) > 1:
if not line_split[1].lower() in self.bot.config or not self.bot.config[ if not line_split[1].lower() in self.bot.config or not self.bot.config[
line_split[1].lower()]: line_split[1].lower()]:
# nope, required config option not present. # nope, required config option not present.
return None raise ModuleNotLoadedWarning(
"required config not present")
elif line_split[0] == "#--require-module" and len( elif line_split[0] == "#--require-module" and len(
line_split) > 1: line_split) > 1:
if not "bitbot_%s" % line_split[1].lower() in sys.modules: if not "bitbot_%s" % line_split[1].lower() in sys.modules:
if not line_split[1].lower() in self.waiting_requirement: if not line_split[1].lower() in self.waiting_requirement:
self.waiting_requirement[line_split[1].lower()] = set([]) self.waiting_requirement[line_split[1].lower()] = set([])
self.waiting_requirement[line_split[1].lower()].add(path) self.waiting_requirement[line_split[1].lower()].add(path)
return None raise ModuleNotLoadedWarning(
"waiting for requirement")
else: else:
break break
module = imp.load_source(name, path) module = imp.load_source(name, path)
if not hasattr(module, "Module"): if not hasattr(module, "Module"):
raise ImportError("module '%s' doesn't have a Module class.") raise ModuleLoadException("module '%s' doesn't have a "
"'Module' class.")
if not inspect.isclass(module.Module): if not inspect.isclass(module.Module):
raise ImportError("module '%s' has a Module attribute but it is not a class.") raise ModuleLoadException("module '%s' has a 'Module' attribute "
"but it is not a class.")
context = str(uuid.uuid4()) context = str(uuid.uuid4())
context_events = self.events.new_context(context) context_events = self.events.new_context(context)
@ -83,26 +104,32 @@ class ModuleManager(object):
def load_module(self, name): def load_module(self, name):
try: try:
module = self._load_module(name) module = self._load_module(name)
except ImportError as e: except ModuleWarning as warning:
self.bot.log.error("failed to load module \"%s\": %s",
[name, e.msg])
return
if module:
self.modules[module._import_name] = module
if name in self.waiting_requirement:
for requirement_name in self.waiting_requirement:
self.load_module(requirement_name)
self.bot.log.info("Module '%s' loaded", [name])
else:
self.bot.log.error("Module '%s' not loaded", [name]) self.bot.log.error("Module '%s' not loaded", [name])
raise
except Exception as e:
self.bot.log.error("Failed to load module \"%s\": %s",
[name, e.msg])
raise
self.modules[module._import_name] = module
if name in self.waiting_requirement:
for requirement_name in self.waiting_requirement:
self.load_module(requirement_name)
self.bot.log.info("Module '%s' loaded", [name])
def load_modules(self, whitelist=[], blacklist=[]): def load_modules(self, whitelist=[], blacklist=[]):
for path in self.list_modules(): for path in self.list_modules():
name = self._module_name(path) name = self._module_name(path)
if name in whitelist or (not whitelist and not name in blacklist): if name in whitelist or (not whitelist and not name in blacklist):
self.load_module(name) try:
self.load_module(name)
except ModuleWarning:
pass
def unload_module(self, name): def unload_module(self, name):
if not name in self.modules:
raise ModuleNotFoundException()
module = self.modules[name] module = self.modules[name]
del self.modules[name] del self.modules[name]

View file

@ -1,10 +1,8 @@
import ModuleManager
class Module(object): class Module(object):
def __init__(self, bot, events, exports): def __init__(self, bot, events, exports):
self.bot = bot self.bot = bot
self.module_name = False
self.silent = False
events.on("received.command.loadmodule").hook(self.load, events.on("received.command.loadmodule").hook(self.load,
min_args=1, permission="load-module", help="Load a module", min_args=1, permission="load-module", help="Load a module",
@ -43,37 +41,35 @@ class Module(object):
self.bot.modules.unload_module(name) self.bot.modules.unload_module(name)
event["stdout"].write("Unloaded '%s'" % name) event["stdout"].write("Unloaded '%s'" % name)
def reload(self, event): def _reload(self, name):
name = self.module_name if self.module_name != False else event[
"args_split"][0].lower()
if not name in self.bot.modules.modules:
if self.silent == False:
event["stderr"].write("Module '%s' isn't loaded" % name)
return
self.bot.modules.unload_module(name) self.bot.modules.unload_module(name)
self.bot.modules.load_module(name) self.bot.modules.load_module(name)
if self.silent == False: def reload(self, event):
event["stdout"].write("Reloaded '%s'" % name) name = event["args_split"][0].lower()
try:
self._reload(name)
except ModuleManager.ModuleNotFoundException:
event["stderr"].write("Module '%s' isn't loaded" % name)
return
event["stdout"].write("Reloaded '%s'" % name)
def reload_all(self, event): def reload_all(self, event):
modules_reloaded = [] reloaded = []
self.silent = True failed = []
for name in self.bot.modules.modules.keys():
for name, value in self.bot.modules.modules.items(): try:
if name in modules_reloaded: self._reload(name)
pass except ModuleManager.ModuleNotFoundException:
failed.append
self.module_name = name if not self._reload(event):
self.reload(event) failed.append(name)
modules_reloaded.append(name) else:
reloaded.append(name)
event["stdout"].write("Reloaded modules: %s" % \ event["stdout"].write("Reloaded modules: %s" % \
" ".join(modules_reloaded)) " ".join(modules_reloaded))
self.silent = False
self.module_name = False
def enable(self, event): def enable(self, event):
name = event["args_split"][0].lower() name = event["args_split"][0].lower()
blacklist = self.bot.get_setting("module-blacklist", []) blacklist = self.bot.get_setting("module-blacklist", [])