Better communicate issues with load/unload/reload of modules
This commit is contained in:
parent
7522b0fae2
commit
b7f7c9342b
2 changed files with 65 additions and 42 deletions
|
@ -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]
|
||||||
|
|
||||||
|
|
|
@ -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", [])
|
||||||
|
|
Loading…
Reference in a new issue