feat(hotreload): handle multiple observers
Some checks failed
Actions / Build Documentation (MkDocs) (push) Successful in 42s
Actions / Lint Code (Ruff & Pylint) (push) Failing after 47s

This commit is contained in:
cswimr 2025-01-26 15:18:05 +00:00
parent ccf9389e13
commit b22d81f514
Signed by: cswimr
GPG key ID: 0EC431A8DA8F8087

View file

@ -6,9 +6,9 @@ from red_commons.logging import RedTraceLogger, getLogger
from redbot.core import Config, checks, commands
from redbot.core.bot import Red
from redbot.core.core_commands import CoreLogic
from redbot.core.utils.chat_formatting import bold, humanize_list
from redbot.core.utils.chat_formatting import bold, box, humanize_list
from watchdog.events import FileSystemEvent, FileSystemMovedEvent, RegexMatchingEventHandler
from watchdog.observers import Observer
from watchdog.observers import Observer, ObserverType
class HotReload(commands.Cog):
@ -16,7 +16,7 @@ class HotReload(commands.Cog):
__author__ = ["[cswimr](https://www.coastalcommits.com/cswimr)"]
__git__ = "https://www.coastalcommits.com/cswimr/SeaCogs"
__version__ = "1.2.0"
__version__ = "1.3.0"
__documentation__ = "https://seacogs.coastalcommits.com/hotreload/"
def __init__(self, bot: Red) -> None:
@ -24,7 +24,7 @@ class HotReload(commands.Cog):
self.bot: Red = bot
self.config = Config.get_conf(self, identifier=294518358420750336, force_registration=True)
self.logger: RedTraceLogger = getLogger(name="red.SeaCogs.HotReload")
self.observer = None
self.observers: list[ObserverType] = []
self.config.register_global(notify_channel=None)
watchdog_loggers = [getLogger(name="watchdog.observers.inotify_buffer")]
for watchdog_logger in watchdog_loggers:
@ -36,9 +36,9 @@ class HotReload(commands.Cog):
async def cog_unload(self) -> None:
"""Stop the observer when the cog is unloaded."""
if self.observer:
self.observer.stop()
self.observer.join()
for observer in self.observers:
observer.stop()
observer.join()
self.logger.info("Stopped observer. No longer watching for file changes.")
def format_help_for_context(self, ctx: commands.Context) -> str:
@ -60,12 +60,20 @@ class HotReload(commands.Cog):
async def start_observer(self) -> None:
"""Start the observer to watch for file changes."""
self.observer = Observer()
self.observers.append(Observer())
paths = await self.get_paths()
for path in paths:
self.observer.schedule(event_handler=HotReloadHandler(cog=self, path=path), path=path, recursive=True)
self.observer.start()
self.logger.info("Started observer. Watching for file changes.")
is_first = True
for observer in self.observers:
if not is_first:
observer.stop()
observer.join()
self.logger.debug("Stopped hanging observer.")
continue
for path in paths:
observer.schedule(event_handler=HotReloadHandler(cog=self, path=path), path=path, recursive=True)
observer.start()
self.logger.info("Started observer. Watching for file changes.")
is_first = False
@checks.is_owner()
@commands.group(name="hotreload")
@ -79,6 +87,14 @@ class HotReload(commands.Cog):
await self.config.notify_channel.set(channel.id)
await ctx.send(f"Notifications will be sent to {channel.mention}.")
@hotreload_group.command(name="list")
async def hotreload_list(self, ctx: commands.Context) -> None:
"""List the currently active observers."""
if not self.observers:
await ctx.send("No observers are currently active.")
return
await ctx.send(f"Currently active observers (If there are more than one of these, report an issue): {box(humanize_list(self.observers, style='unit'))}")
class HotReloadHandler(RegexMatchingEventHandler):
"""Handler for file changes."""