Fix wrong info being loaded into InstalledModule (#6720)

This commit is contained in:
Jakub Kuczys
2026-05-24 20:55:15 +02:00
committed by GitHub
parent 174237ae06
commit 443fa9f64f
5 changed files with 55 additions and 27 deletions
+5 -4
View File
@@ -154,9 +154,10 @@ async def installed_cogs() -> Tuple[InstalledModule, ...]:
""" """
installed = await _config.installed_cogs() installed = await _config.installed_cogs()
install_path = await _cog_mgr.install_path()
# noinspection PyTypeChecker # noinspection PyTypeChecker
return tuple( return tuple(
InstalledModule.from_json(cog_json, _repo_manager) InstalledModule.from_json(cog_json, _repo_manager, base_target_dir=install_path)
for repo_json in installed.values() for repo_json in installed.values()
for cog_json in repo_json.values() for cog_json in repo_json.values()
) )
@@ -174,7 +175,7 @@ async def installed_libraries() -> Tuple[InstalledModule, ...]:
installed = await _config.installed_libraries() installed = await _config.installed_libraries()
# noinspection PyTypeChecker # noinspection PyTypeChecker
return tuple( return tuple(
InstalledModule.from_json(lib_json, _repo_manager) InstalledModule.from_json(lib_json, _repo_manager, base_target_dir=SHAREDLIB_PATH)
for repo_json in installed.values() for repo_json in installed.values()
for lib_json in repo_json.values() for lib_json in repo_json.values()
) )
@@ -388,8 +389,8 @@ async def _install_cogs(
for commit, cogs_to_install in cogs_by_commit.items(): for commit, cogs_to_install in cogs_by_commit.items():
await repo.checkout(commit) await repo.checkout(commit)
for cog in cogs_to_install: for cog in cogs_to_install:
if await cog.copy_to(await _cog_mgr.install_path()): if install_location := await cog.copy_to(await _cog_mgr.install_path()):
installed.append(InstalledModule.from_installable(cog)) installed.append(InstalledModule.from_installable(cog, install_location))
else: else:
failed.append(cog) failed.append(cog)
await repo.checkout(exit_to_commit) await repo.checkout(exit_to_commit)
+40 -15
View File
@@ -67,7 +67,14 @@ class Installable(RepoJSONMixin):
""" """
def __init__(self, location: Path, repo: Optional[Repo] = None, commit: str = ""): def __init__(
self,
location: Path,
repo: Optional[Repo] = None,
commit: str = "",
*,
info_file: Optional[Path] = None,
):
"""Base installable initializer. """Base installable initializer.
Parameters Parameters
@@ -97,7 +104,7 @@ class Installable(RepoJSONMixin):
self.tags: Tuple[str, ...] self.tags: Tuple[str, ...]
self.type: InstallableType self.type: InstallableType
super().__init__(location) super().__init__(location, info_file=info_file)
def __eq__(self, other: Any) -> bool: def __eq__(self, other: Any) -> bool:
# noinspection PyProtectedMember # noinspection PyProtectedMember
@@ -111,14 +118,14 @@ class Installable(RepoJSONMixin):
"""`str` : The name of this package.""" """`str` : The name of this package."""
return self._location.stem return self._location.stem
async def copy_to(self, target_dir: Path) -> bool: async def copy_to(self, target_dir: Path) -> Optional[Path]:
""" """
Copies this cog/shared_lib to the given directory. This Copies this cog/shared_lib to the given directory. This
will overwrite any files in the target directory. will overwrite any files in the target directory.
:param pathlib.Path target_dir: The installation directory to install to. :param pathlib.Path target_dir: The installation directory to install to.
:return: Status of installation :return: Install location of the cog or None in case of copy failure.
:rtype: bool :rtype: `Path`, optional
""" """
copy_func: Callable[..., Any] copy_func: Callable[..., Any]
if self._location.is_file(): if self._location.is_file():
@@ -126,13 +133,14 @@ class Installable(RepoJSONMixin):
else: else:
copy_func = functools.partial(shutil.copytree, dirs_exist_ok=True) copy_func = functools.partial(shutil.copytree, dirs_exist_ok=True)
dst = target_dir / self._location.name
# noinspection PyBroadException # noinspection PyBroadException
try: try:
copy_func(src=str(self._location), dst=str(target_dir / self._location.name)) copy_func(src=str(self._location), dst=str(dst))
except: # noqa: E722 except: # noqa: E722
log.exception("Error occurred when copying path: %s", self._location) log.exception("Error occurred when copying path: %s", self._location)
return False return None
return True return dst
def _read_info_file(self) -> None: def _read_info_file(self) -> None:
super()._read_info_file() super()._read_info_file()
@@ -160,8 +168,13 @@ class InstalledModule(Installable):
commit: str = "", commit: str = "",
pinned: bool = False, pinned: bool = False,
json_repo_name: str = "", json_repo_name: str = "",
*,
info_file: Optional[Path] = None,
install_location: Path,
): ):
super().__init__(location=location, repo=repo, commit=commit) info_file = info_file or install_location / self.INFO_FILE_NAME
super().__init__(location=location, repo=repo, commit=commit, info_file=info_file)
self._install_location = install_location
self.pinned: bool = pinned if self.type is InstallableType.COG else False self.pinned: bool = pinned if self.type is InstallableType.COG else False
# this is here so that Downloader could use real repo name instead of "MISSING_REPO" # this is here so that Downloader could use real repo name instead of "MISSING_REPO"
self._json_repo_name = json_repo_name self._json_repo_name = json_repo_name
@@ -178,10 +191,10 @@ class InstalledModule(Installable):
@classmethod @classmethod
def from_json( def from_json(
cls, data: Dict[str, Union[str, bool]], repo_mgr: RepoManager cls, data: Dict[str, Union[str, bool]], repo_mgr: RepoManager, *, base_target_dir: Path
) -> InstalledModule: ) -> InstalledModule:
repo_name = cast(str, data["repo_name"]) repo_name = cast(str, data["repo_name"])
cog_name = cast(str, data["module_name"]) module_name = cast(str, data["module_name"])
commit = cast(str, data.get("commit", "")) commit = cast(str, data.get("commit", ""))
pinned = cast(bool, data.get("pinned", False)) pinned = cast(bool, data.get("pinned", False))
@@ -192,14 +205,26 @@ class InstalledModule(Installable):
else: else:
repo_folder = repo_mgr.repos_folder / "MISSING_REPO" repo_folder = repo_mgr.repos_folder / "MISSING_REPO"
location = repo_folder / cog_name location = repo_folder / module_name
install_location = base_target_dir / module_name
return cls( return cls(
location=location, repo=repo, commit=commit, pinned=pinned, json_repo_name=repo_name location=location,
repo=repo,
commit=commit,
pinned=pinned,
json_repo_name=repo_name,
install_location=install_location,
) )
@classmethod @classmethod
def from_installable(cls, module: Installable, *, pinned: bool = False) -> InstalledModule: def from_installable(
cls, module: Installable, install_location: Path, *, pinned: bool = False
) -> InstalledModule:
return cls( return cls(
location=module._location, repo=module.repo, commit=module.commit, pinned=pinned location=module._location,
repo=module.repo,
commit=module.commit,
pinned=pinned,
install_location=install_location,
) )
+3 -3
View File
@@ -1,6 +1,6 @@
import json import json
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Tuple from typing import Any, Dict, Optional, Tuple
from .info_schemas import REPO_SCHEMA, update_mixin from .info_schemas import REPO_SCHEMA, update_mixin
from .log import log from .log import log
@@ -9,7 +9,7 @@ from .log import log
class RepoJSONMixin: class RepoJSONMixin:
INFO_FILE_NAME = "info.json" INFO_FILE_NAME = "info.json"
def __init__(self, repo_folder: Path): def __init__(self, repo_folder: Path, *, info_file: Optional[Path] = None):
self._repo_folder = repo_folder self._repo_folder = repo_folder
self.author: Tuple[str, ...] self.author: Tuple[str, ...]
@@ -17,7 +17,7 @@ class RepoJSONMixin:
self.short: str self.short: str
self.description: str self.description: str
self._info_file = repo_folder / self.INFO_FILE_NAME self._info_file = info_file or repo_folder / self.INFO_FILE_NAME
self._info: Dict[str, Any] self._info: Dict[str, Any]
self._read_info_file() self._read_info_file()
+5 -4
View File
@@ -866,10 +866,11 @@ class Repo(RepoJSONMixin):
if not target_dir.exists(): if not target_dir.exists():
raise ValueError("That target directory does not exist.") raise ValueError("That target directory does not exist.")
if not await cog.copy_to(target_dir=target_dir): install_location = await cog.copy_to(target_dir=target_dir)
if not install_location:
raise errors.CopyingError("There was an issue during copying of cog's files") raise errors.CopyingError("There was an issue during copying of cog's files")
return InstalledModule.from_installable(cog) return InstalledModule.from_installable(cog, install_location)
async def install_libraries( async def install_libraries(
self, target_dir: Path, req_target_dir: Path, libraries: Iterable[Installable] = () self, target_dir: Path, req_target_dir: Path, libraries: Iterable[Installable] = ()
@@ -907,11 +908,11 @@ class Repo(RepoJSONMixin):
for lib in libraries: for lib in libraries:
if not ( if not (
await self.install_requirements(cog=lib, target_dir=req_target_dir) await self.install_requirements(cog=lib, target_dir=req_target_dir)
and await lib.copy_to(target_dir=target_dir) and (install_location := await lib.copy_to(target_dir=target_dir))
): ):
failed.append(lib) failed.append(lib)
else: else:
installed.append(InstalledModule.from_installable(lib)) installed.append(InstalledModule.from_installable(lib, install_location))
return (tuple(installed), tuple(failed)) return (tuple(installed), tuple(failed))
return ((), ()) return ((), ())
+2 -1
View File
@@ -129,8 +129,9 @@ def installed_cog(tmpdir):
cog_path = tmpdir.mkdir("test_repo").mkdir("test_installed_cog") cog_path = tmpdir.mkdir("test_repo").mkdir("test_installed_cog")
info_path = cog_path.join("info.json") info_path = cog_path.join("info.json")
info_path.write_text(json.dumps(INFO_JSON), "utf-8") info_path.write_text(json.dumps(INFO_JSON), "utf-8")
location = Path(str(cog_path))
cog_info = InstalledModule(Path(str(cog_path))) cog_info = InstalledModule(location, install_location=location)
return cog_info return cog_info