Skip to content

Commit f0cb54c

Browse files
committed
Make plugin loading load all subdirs as well
1 parent bf07869 commit f0cb54c

3 files changed

Lines changed: 33 additions & 19 deletions

File tree

cloudbot/bot.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os
77
import gc
88
from operator import attrgetter
9+
from pathlib import Path
910

1011
from sqlalchemy import create_engine
1112

@@ -59,6 +60,7 @@ class CloudBot:
5960

6061
def __init__(self, loop=asyncio.get_event_loop()):
6162
# basic variables
63+
self.base_dir = Path().resolve()
6264
self.loop = loop
6365
self.start_time = time.time()
6466
self.running = True

cloudbot/plugin.py

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from collections import defaultdict
99
from operator import attrgetter
1010
from itertools import chain
11+
from pathlib import Path
1112

1213
import sqlalchemy
1314

@@ -119,7 +120,10 @@ def load_all(self, plugin_dir):
119120
120121
:type plugin_dir: str
121122
"""
122-
path_list = glob.iglob(os.path.join(plugin_dir, '*.py'))
123+
plugin_dir = Path(plugin_dir)
124+
# Load all .py files in the plugins directory and any subdirectory
125+
# But ignore files starting with _
126+
path_list = plugin_dir.rglob("[!_]*.py")
123127
# Load plugins asynchronously :O
124128
yield from asyncio.gather(*[self.load_plugin(path) for path in path_list], loop=self.bot.loop)
125129

@@ -136,27 +140,30 @@ def load_plugin(self, path):
136140
137141
Won't load any plugins listed in "disabled_plugins".
138142
139-
:type path: str
143+
:type path: str | Path
140144
"""
141145

142-
file_path = os.path.abspath(path)
143-
file_name = os.path.basename(path)
144-
title = os.path.splitext(file_name)[0]
146+
path = Path(path)
147+
file_path = path.resolve()
148+
file_name = file_path.name
149+
# Resolve the path relative to the current directory
150+
plugin_path = file_path.relative_to(self.bot.base_dir)
151+
title = '.'.join(plugin_path.parts[1:]).rsplit('.', 1)[0]
145152

146153
if "plugin_loading" in self.bot.config:
147154
pl = self.bot.config.get("plugin_loading")
148155

149156
if pl.get("use_whitelist", False):
150157
if title not in pl.get("whitelist", []):
151-
logger.info('Not loading plugin module "{}": plugin not whitelisted'.format(file_name))
158+
logger.info('Not loading plugin module "{}": plugin not whitelisted'.format(title))
152159
return
153160
else:
154161
if title in pl.get("blacklist", []):
155-
logger.info('Not loading plugin module "{}": plugin blacklisted'.format(file_name))
162+
logger.info('Not loading plugin module "{}": plugin blacklisted'.format(title))
156163
return
157164

158165
# make sure to unload the previously loaded plugin from this path, if it was loaded.
159-
if file_name in self.plugins:
166+
if file_path in self.plugins:
160167
yield from self.unload_plugin(file_path)
161168

162169
module_name = "plugins.{}".format(title)
@@ -166,11 +173,11 @@ def load_plugin(self, path):
166173
if hasattr(plugin_module, "_cloudbot_loaded"):
167174
importlib.reload(plugin_module)
168175
except Exception:
169-
logger.exception("Error loading {}:".format(file_name))
176+
logger.exception("Error loading {}:".format(title))
170177
return
171178

172179
# create the plugin
173-
plugin = Plugin(file_path, file_name, title, plugin_module)
180+
plugin = Plugin(str(file_path), file_name, title, plugin_module)
174181

175182
# proceed to register hooks
176183

@@ -187,7 +194,7 @@ def load_plugin(self, path):
187194
plugin.unregister_tables(self.bot)
188195
return
189196

190-
self.plugins[plugin.file_name] = plugin
197+
self.plugins[plugin.file_path] = plugin
191198

192199
for on_cap_available_hook in plugin.on_cap_available:
193200
for cap in on_cap_available_hook.caps:
@@ -275,21 +282,26 @@ def unload_plugin(self, path):
275282
276283
Returns True if the plugin was unloaded, False if the plugin wasn't loaded in the first place.
277284
278-
:type path: str
285+
:type path: str | Path
279286
:rtype: bool
280287
"""
281-
file_name = os.path.basename(path)
282-
title = os.path.splitext(file_name)[0]
288+
path = Path(path)
289+
file_path = path.resolve()
290+
plugin_path = file_path.relative_to(self.bot.base_dir)
291+
292+
title = '.'.join(plugin_path.parts[1:]).rsplit('.', 1)[0]
283293
if "disabled_plugins" in self.bot.config and title in self.bot.config['disabled_plugins']:
284294
# this plugin hasn't been loaded, so no need to unload it
285295
return False
286296

297+
module_name = "plugins.{}".format(title)
298+
287299
# make sure this plugin is actually loaded
288-
if not file_name in self.plugins:
300+
if str(file_path) not in self.plugins:
289301
return False
290302

291303
# get the loaded plugin
292-
plugin = self.plugins[file_name]
304+
plugin = self.plugins[str(file_path)]
293305

294306
for task in plugin.tasks:
295307
task.cancel()
@@ -358,10 +370,10 @@ def unload_plugin(self, path):
358370
plugin.unregister_tables(self.bot)
359371

360372
# remove last reference to plugin
361-
del self.plugins[plugin.file_name]
373+
del self.plugins[plugin.file_path]
362374

363375
if self.bot.config.get("logging", {}).get("show_plugin_loading", True):
364-
logger.info("Unloaded all plugins from {}.py".format(plugin.title))
376+
logger.info("Unloaded all plugins from {}".format(plugin.title))
365377

366378
return True
367379

cloudbot/reloader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def start(self, module_path):
1919
"""Starts the plugin reloader
2020
:type module_path: str
2121
"""
22-
self.observer.schedule(self.event_handler, module_path, recursive=False)
22+
self.observer.schedule(self.event_handler, module_path, recursive=True)
2323
self.observer.start()
2424

2525
def stop(self):

0 commit comments

Comments
 (0)