mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 11:18:54 -05:00
[CogManager] Removal of implicit paths and general cleanup (#2345)
- Removed memory-sided `CogManager._paths` attribute, as it has no practical use. - `[p]removepath` now removes the actual path displayed with the index specified in `[p]paths`. - New method for retreiving a deduplicated list of user-defined paths as `Path` objects - General cleanup so we don't have to do so much head-scratching next time an issue arises here Signed-off-by: Toby Harradine <tobyharradine@gmail.com>
This commit is contained in:
parent
aa854cf1f9
commit
dde5582669
@ -111,7 +111,7 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin):
|
|||||||
|
|
||||||
self.main_dir = bot_dir
|
self.main_dir = bot_dir
|
||||||
|
|
||||||
self.cog_mgr = CogManager(paths=(str(self.main_dir / "cogs"),))
|
self.cog_mgr = CogManager()
|
||||||
|
|
||||||
super().__init__(*args, formatter=Help(), **kwargs)
|
super().__init__(*args, formatter=Help(), **kwargs)
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import pkgutil
|
|||||||
from importlib import import_module, invalidate_caches
|
from importlib import import_module, invalidate_caches
|
||||||
from importlib.machinery import ModuleSpec
|
from importlib.machinery import ModuleSpec
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Tuple, Union, List, Optional
|
from typing import Union, List, Optional
|
||||||
|
|
||||||
import redbot.cogs
|
import redbot.cogs
|
||||||
from redbot.core.utils import deduplicate_iterables
|
from redbot.core.utils import deduplicate_iterables
|
||||||
@ -25,8 +25,6 @@ class NoSuchCog(ImportError):
|
|||||||
Different from ImportError because some ImportErrors can happen inside cogs.
|
Different from ImportError because some ImportErrors can happen inside cogs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CogManager:
|
class CogManager:
|
||||||
"""Directory manager for Red's cogs.
|
"""Directory manager for Red's cogs.
|
||||||
@ -39,30 +37,27 @@ class CogManager:
|
|||||||
|
|
||||||
CORE_PATH = Path(redbot.cogs.__path__[0])
|
CORE_PATH = Path(redbot.cogs.__path__[0])
|
||||||
|
|
||||||
def __init__(self, paths: Tuple[str] = ()):
|
def __init__(self):
|
||||||
self.conf = Config.get_conf(self, 2938473984732, True)
|
self.conf = Config.get_conf(self, 2938473984732, True)
|
||||||
tmp_cog_install_path = cog_data_path(self) / "cogs"
|
tmp_cog_install_path = cog_data_path(self) / "cogs"
|
||||||
tmp_cog_install_path.mkdir(parents=True, exist_ok=True)
|
tmp_cog_install_path.mkdir(parents=True, exist_ok=True)
|
||||||
self.conf.register_global(paths=[], install_path=str(tmp_cog_install_path))
|
self.conf.register_global(paths=[], install_path=str(tmp_cog_install_path))
|
||||||
self._paths = [Path(p) for p in paths]
|
|
||||||
|
|
||||||
async def paths(self) -> Tuple[Path, ...]:
|
async def paths(self) -> List[Path]:
|
||||||
"""Get all currently valid path directories.
|
"""Get all currently valid path directories, in order of priority
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
`tuple` of `pathlib.Path`
|
List[pathlib.Path]
|
||||||
All valid cog paths.
|
A list of paths where cog packages can be found. The
|
||||||
|
install path is highest priority, followed by the
|
||||||
|
user-defined paths, and the core path has the lowest
|
||||||
|
priority.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
conf_paths = [Path(p) for p in await self.conf.paths()]
|
return deduplicate_iterables(
|
||||||
other_paths = self._paths
|
[await self.install_path()], await self.user_defined_paths(), [self.CORE_PATH]
|
||||||
|
)
|
||||||
all_paths = deduplicate_iterables(conf_paths, other_paths, [self.CORE_PATH])
|
|
||||||
|
|
||||||
if self.install_path not in all_paths:
|
|
||||||
all_paths.insert(0, await self.install_path())
|
|
||||||
return tuple(p.resolve() for p in all_paths if p.is_dir())
|
|
||||||
|
|
||||||
async def install_path(self) -> Path:
|
async def install_path(self) -> Path:
|
||||||
"""Get the install path for 3rd party cogs.
|
"""Get the install path for 3rd party cogs.
|
||||||
@ -73,8 +68,20 @@ class CogManager:
|
|||||||
The path to the directory where 3rd party cogs are stored.
|
The path to the directory where 3rd party cogs are stored.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
p = Path(await self.conf.install_path())
|
return Path(await self.conf.install_path()).resolve()
|
||||||
return p.resolve()
|
|
||||||
|
async def user_defined_paths(self) -> List[Path]:
|
||||||
|
"""Get a list of user-defined cog paths.
|
||||||
|
|
||||||
|
All paths will be absolute and unique, in order of priority.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
List[pathlib.Path]
|
||||||
|
A list of user-defined paths.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return list(map(Path, deduplicate_iterables(await self.conf.paths())))
|
||||||
|
|
||||||
async def set_install_path(self, path: Path) -> Path:
|
async def set_install_path(self, path: Path) -> Path:
|
||||||
"""Set the install path for 3rd party cogs.
|
"""Set the install path for 3rd party cogs.
|
||||||
@ -125,11 +132,10 @@ class CogManager:
|
|||||||
path = Path(path)
|
path = Path(path)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
async def add_path(self, path: Union[Path, str]):
|
async def add_path(self, path: Union[Path, str]) -> None:
|
||||||
"""Add a cog path to current list.
|
"""Add a cog path to current list.
|
||||||
|
|
||||||
This will ignore duplicates. Does have a side effect of removing all
|
This will ignore duplicates.
|
||||||
invalid paths from the saved path list.
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -156,11 +162,12 @@ class CogManager:
|
|||||||
if path == self.CORE_PATH:
|
if path == self.CORE_PATH:
|
||||||
raise ValueError("Cannot add the core path as an additional path.")
|
raise ValueError("Cannot add the core path as an additional path.")
|
||||||
|
|
||||||
async with self.conf.paths() as paths:
|
current_paths = await self.user_defined_paths()
|
||||||
if not any(Path(p) == path for p in paths):
|
if path not in current_paths:
|
||||||
paths.append(str(path))
|
current_paths.append(path)
|
||||||
|
await self.set_paths(current_paths)
|
||||||
|
|
||||||
async def remove_path(self, path: Union[Path, str]) -> Tuple[Path, ...]:
|
async def remove_path(self, path: Union[Path, str]) -> None:
|
||||||
"""Remove a path from the current paths list.
|
"""Remove a path from the current paths list.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -168,21 +175,13 @@ class CogManager:
|
|||||||
path : `pathlib.Path` or `str`
|
path : `pathlib.Path` or `str`
|
||||||
Path to remove.
|
Path to remove.
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
`tuple` of `pathlib.Path`
|
|
||||||
Tuple of new valid paths.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
path = self._ensure_path_obj(path).resolve()
|
path = self._ensure_path_obj(path).resolve()
|
||||||
|
paths = await self.user_defined_paths()
|
||||||
|
|
||||||
paths = [Path(p) for p in await self.conf.paths()]
|
|
||||||
if path in paths:
|
|
||||||
paths.remove(path)
|
paths.remove(path)
|
||||||
await self.set_paths(paths)
|
await self.set_paths(paths)
|
||||||
|
|
||||||
return tuple(paths)
|
|
||||||
|
|
||||||
async def set_paths(self, paths_: List[Path]):
|
async def set_paths(self, paths_: List[Path]):
|
||||||
"""Set the current paths list.
|
"""Set the current paths list.
|
||||||
|
|
||||||
@ -192,7 +191,7 @@ class CogManager:
|
|||||||
List of paths to set.
|
List of paths to set.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
str_paths = [str(p) for p in paths_]
|
str_paths = list(map(str, paths_))
|
||||||
await self.conf.paths.set(str_paths)
|
await self.conf.paths.set(str_paths)
|
||||||
|
|
||||||
async def _find_ext_cog(self, name: str) -> ModuleSpec:
|
async def _find_ext_cog(self, name: str) -> ModuleSpec:
|
||||||
@ -213,9 +212,9 @@ class CogManager:
|
|||||||
------
|
------
|
||||||
NoSuchCog
|
NoSuchCog
|
||||||
When no cog with the requested name was found.
|
When no cog with the requested name was found.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
resolved_paths = await self.paths()
|
real_paths = list(map(str, [await self.install_path()] + await self.user_defined_paths()))
|
||||||
real_paths = [str(p) for p in resolved_paths if p != self.CORE_PATH]
|
|
||||||
|
|
||||||
for finder, module_name, _ in pkgutil.iter_modules(real_paths):
|
for finder, module_name, _ in pkgutil.iter_modules(real_paths):
|
||||||
if name == module_name:
|
if name == module_name:
|
||||||
@ -287,10 +286,8 @@ class CogManager:
|
|||||||
return await self._find_core_cog(name)
|
return await self._find_core_cog(name)
|
||||||
|
|
||||||
async def available_modules(self) -> List[str]:
|
async def available_modules(self) -> List[str]:
|
||||||
"""Finds the names of all available modules to load.
|
"""Finds the names of all available modules to load."""
|
||||||
"""
|
paths = list(map(str, await self.paths()))
|
||||||
paths = (await self.install_path(),) + await self.paths()
|
|
||||||
paths = [str(p) for p in paths]
|
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
for finder, module_name, _ in pkgutil.iter_modules(paths):
|
for finder, module_name, _ in pkgutil.iter_modules(paths):
|
||||||
@ -314,13 +311,6 @@ _ = Translator("CogManagerUI", __file__)
|
|||||||
class CogManagerUI(commands.Cog):
|
class CogManagerUI(commands.Cog):
|
||||||
"""Commands to interface with Red's cog manager."""
|
"""Commands to interface with Red's cog manager."""
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def visible_paths(ctx):
|
|
||||||
install_path = await ctx.bot.cog_mgr.install_path()
|
|
||||||
cog_paths = await ctx.bot.cog_mgr.paths()
|
|
||||||
cog_paths = [p for p in cog_paths if p != install_path]
|
|
||||||
return cog_paths
|
|
||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
@checks.is_owner()
|
@checks.is_owner()
|
||||||
async def paths(self, ctx: commands.Context):
|
async def paths(self, ctx: commands.Context):
|
||||||
@ -330,8 +320,7 @@ class CogManagerUI(commands.Cog):
|
|||||||
cog_mgr = ctx.bot.cog_mgr
|
cog_mgr = ctx.bot.cog_mgr
|
||||||
install_path = await cog_mgr.install_path()
|
install_path = await cog_mgr.install_path()
|
||||||
core_path = cog_mgr.CORE_PATH
|
core_path = cog_mgr.CORE_PATH
|
||||||
cog_paths = await cog_mgr.paths()
|
cog_paths = await cog_mgr.user_defined_paths()
|
||||||
cog_paths = [p for p in cog_paths if p not in (install_path, core_path)]
|
|
||||||
|
|
||||||
msg = _("Install Path: {install_path}\nCore Path: {core_path}\n\n").format(
|
msg = _("Install Path: {install_path}\nCore Path: {core_path}\n\n").format(
|
||||||
install_path=install_path, core_path=core_path
|
install_path=install_path, core_path=core_path
|
||||||
@ -369,7 +358,11 @@ class CogManagerUI(commands.Cog):
|
|||||||
from !paths
|
from !paths
|
||||||
"""
|
"""
|
||||||
path_number -= 1
|
path_number -= 1
|
||||||
cog_paths = await self.visible_paths(ctx)
|
if path_number < 0:
|
||||||
|
await ctx.send(_("Path numbers must be positive."))
|
||||||
|
return
|
||||||
|
|
||||||
|
cog_paths = await ctx.bot.cog_mgr.user_defined_paths()
|
||||||
try:
|
try:
|
||||||
to_remove = cog_paths.pop(path_number)
|
to_remove = cog_paths.pop(path_number)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
@ -388,8 +381,11 @@ class CogManagerUI(commands.Cog):
|
|||||||
# Doing this because in the paths command they're 1 indexed
|
# Doing this because in the paths command they're 1 indexed
|
||||||
from_ -= 1
|
from_ -= 1
|
||||||
to -= 1
|
to -= 1
|
||||||
|
if from_ < 0 or to < 0:
|
||||||
|
await ctx.send(_("Path numbers must be positive."))
|
||||||
|
return
|
||||||
|
|
||||||
all_paths = await self.visible_paths(ctx)
|
all_paths = await ctx.bot.cog_mgr.user_defined_paths()
|
||||||
try:
|
try:
|
||||||
to_move = all_paths.pop(from_)
|
to_move = all_paths.pop(from_)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user