[CogManager] Correctly separate core, install and other cog paths (#1983)

* [CogManager] Correctly manage core and install paths

This keeps the core and install paths separate from those set in the
config.

It also displays the core path separately in `[p]paths`

Resolves #1982.

* [CogManager] Fix old reference to method removed in previous commit

Also did a bit of a general cleanup of cog_manager.py's code

* Make the core path a class attribute

* [CogManager] Paths should default to a list
This commit is contained in:
Toby Harradine 2018-08-11 13:31:26 +10:00 committed by GitHub
parent 75ed749cb3
commit 47350328e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -35,12 +35,13 @@ class CogManager:
bot directory. bot directory.
""" """
CORE_PATH = Path(redbot.cogs.__path__[0])
def __init__(self, paths: Tuple[str] = ()): def __init__(self, paths: Tuple[str] = ()):
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] self._paths = [Path(p) for p in paths]
async def paths(self) -> Tuple[Path, ...]: async def paths(self) -> Tuple[Path, ...]:
@ -54,18 +55,13 @@ class CogManager:
""" """
conf_paths = [Path(p) for p in await self.conf.paths()] conf_paths = [Path(p) for p in await self.conf.paths()]
other_paths = self._paths other_paths = self._paths
core_paths = await self.core_paths()
all_paths = _deduplicate(list(conf_paths) + list(other_paths) + core_paths) all_paths = _deduplicate(list(conf_paths) + list(other_paths) + [self.CORE_PATH])
if self.install_path not in all_paths: if self.install_path not in all_paths:
all_paths.insert(0, await self.install_path()) all_paths.insert(0, await self.install_path())
return tuple(p.resolve() for p in all_paths if p.is_dir()) return tuple(p.resolve() for p in all_paths if p.is_dir())
async def core_paths(self) -> List[Path]:
core_paths = [Path(p) for p in redbot.cogs.__path__]
return core_paths
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.
@ -155,10 +151,12 @@ class CogManager:
if path == await self.install_path(): if path == await self.install_path():
raise ValueError("Cannot add the install path as an additional path.") raise ValueError("Cannot add the install path as an additional path.")
if path == self.CORE_PATH:
raise ValueError("Cannot add the core path as an additional path.")
all_paths = _deduplicate(await self.paths() + (path,)) async with self.conf.paths() as paths:
# noinspection PyTypeChecker if not any(Path(p) == path for p in paths):
await self.set_paths(all_paths) paths.append(str(path))
async def remove_path(self, path: Union[Path, str]) -> Tuple[Path, ...]: async def remove_path(self, path: Union[Path, str]) -> Tuple[Path, ...]:
"""Remove a path from the current paths list. """Remove a path from the current paths list.
@ -174,12 +172,14 @@ class CogManager:
Tuple of new valid paths. Tuple of new valid paths.
""" """
path = self._ensure_path_obj(path) path = self._ensure_path_obj(path).resolve()
all_paths = list(await self.paths())
if path in all_paths: paths = [Path(p) for p in await self.conf.paths()]
all_paths.remove(path) # Modifies in place if path in paths:
await self.set_paths(all_paths) paths.remove(path)
return tuple(all_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.
@ -213,9 +213,8 @@ class CogManager:
When no matching spec can be found. When no matching spec can be found.
""" """
resolved_paths = _deduplicate(await self.paths()) resolved_paths = _deduplicate(await self.paths())
core_paths = _deduplicate(await self.core_paths())
real_paths = [str(p) for p in resolved_paths if p not in core_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:
@ -228,7 +227,8 @@ class CogManager:
" in any available path.".format(name) " in any available path.".format(name)
) )
async def _find_core_cog(self, name: str) -> ModuleSpec: @staticmethod
async def _find_core_cog(name: str) -> ModuleSpec:
""" """
Attempts to find a spec for a core cog. Attempts to find a spec for a core cog.
@ -310,7 +310,8 @@ _ = Translator("CogManagerUI", __file__)
class CogManagerUI: class CogManagerUI:
"""Commands to interface with Red's cog manager.""" """Commands to interface with Red's cog manager."""
async def visible_paths(self, ctx): @staticmethod
async def visible_paths(ctx):
install_path = await ctx.bot.cog_mgr.install_path() install_path = await ctx.bot.cog_mgr.install_path()
cog_paths = await ctx.bot.cog_mgr.paths() cog_paths = await ctx.bot.cog_mgr.paths()
cog_paths = [p for p in cog_paths if p != install_path] cog_paths = [p for p in cog_paths if p != install_path]
@ -322,11 +323,15 @@ class CogManagerUI:
""" """
Lists current cog paths in order of priority. Lists current cog paths in order of priority.
""" """
install_path = await ctx.bot.cog_mgr.install_path() cog_mgr = ctx.bot.cog_mgr
cog_paths = await ctx.bot.cog_mgr.paths() install_path = await cog_mgr.install_path()
cog_paths = [p for p in cog_paths if p != install_path] core_path = cog_mgr.CORE_PATH
cog_paths = await cog_mgr.paths()
cog_paths = [p for p in cog_paths if p not in (install_path, core_path)]
msg = _("Install Path: {}\n\n").format(install_path) msg = _("Install Path: {install_path}\nCore Path: {core_path}\n\n").format(
install_path=install_path, core_path=core_path
)
partial = [] partial = []
for i, p in enumerate(cog_paths, start=1): for i, p in enumerate(cog_paths, start=1):
@ -428,16 +433,16 @@ class CogManagerUI:
""" """
loaded = set(ctx.bot.extensions.keys()) loaded = set(ctx.bot.extensions.keys())
all = set(await ctx.bot.cog_mgr.available_modules()) all_cogs = set(await ctx.bot.cog_mgr.available_modules())
unloaded = all - loaded unloaded = all_cogs - loaded
loaded = sorted(list(loaded), key=str.lower) loaded = sorted(list(loaded), key=str.lower)
unloaded = sorted(list(unloaded), key=str.lower) unloaded = sorted(list(unloaded), key=str.lower)
if await ctx.embed_requested(): if await ctx.embed_requested():
loaded = ("**{} loaded:**\n").format(len(loaded)) + ", ".join(loaded) loaded = _("**{} loaded:**\n").format(len(loaded)) + ", ".join(loaded)
unloaded = ("**{} unloaded:**\n").format(len(unloaded)) + ", ".join(unloaded) unloaded = _("**{} unloaded:**\n").format(len(unloaded)) + ", ".join(unloaded)
for page in pagify(loaded, delims=[", ", "\n"], page_length=1800): for page in pagify(loaded, delims=[", ", "\n"], page_length=1800):
e = discord.Embed(description=page, colour=discord.Colour.dark_green()) e = discord.Embed(description=page, colour=discord.Colour.dark_green())
@ -447,9 +452,9 @@ class CogManagerUI:
e = discord.Embed(description=page, colour=discord.Colour.dark_red()) e = discord.Embed(description=page, colour=discord.Colour.dark_red())
await ctx.send(embed=e) await ctx.send(embed=e)
else: else:
loaded_count = "**{} loaded:**\n".format(len(loaded)) loaded_count = _("**{} loaded:**\n").format(len(loaded))
loaded = ", ".join(loaded) loaded = ", ".join(loaded)
unloaded_count = "**{} unloaded:**\n".format(len(unloaded)) unloaded_count = _("**{} unloaded:**\n").format(len(unloaded))
unloaded = ", ".join(unloaded) unloaded = ", ".join(unloaded)
loaded_count_sent = False loaded_count_sent = False
unloaded_count_sent = False unloaded_count_sent = False