diff --git a/app/logic/game_support.py b/app/logic/game_support.py index ce9805f6..da2489ef 100644 --- a/app/logic/game_support.py +++ b/app/logic/game_support.py @@ -213,7 +213,7 @@ class GameSupport: package.is_confirmed = True return package.supported_games - def on_update(self, package: GSPackage): + def on_update(self, package: GSPackage, old_provides: Optional[set[str]] = None): to_update = {package} checked = set() @@ -224,7 +224,11 @@ class GameSupport: current_package.detected_supported_games = [] self._get_supported_games(current_package, []) - for modname in current_package.provides: + provides = current_package.provides + if current_package == package and old_provides is not None: + provides = provides.union(old_provides) + + for modname in provides: for depending_package in self.get_all_that_depend_on(modname): if depending_package not in checked: to_update.add(depending_package) @@ -310,12 +314,12 @@ def _persist(session: sqlalchemy.orm.Session, support: GameSupport): session.add(new_support) -def game_support_update(session: sqlalchemy.orm.Session, package: Package) -> set[str]: +def game_support_update(session: sqlalchemy.orm.Session, package: Package, old_provides: Optional[set[str]]) -> set[str]: support = _create_instance(session) gs_package = support.get(package.get_id()) if gs_package is None: gs_package = _convert_package(support, package) - support.on_update(gs_package) + support.on_update(gs_package, old_provides) _persist(session, support) return gs_package.errors diff --git a/app/tasks/importtasks.py b/app/tasks/importtasks.py index 12185b02..b76188e4 100644 --- a/app/tasks/importtasks.py +++ b/app/tasks/importtasks.py @@ -97,7 +97,7 @@ def update_all_game_support(): @celery.task() def update_package_game_support(package_id: int): package = Package.query.get(package_id) - game_support_update(db.session, package) + game_support_update(db.session, package, None) db.session.commit() @@ -123,14 +123,14 @@ def post_release_check_update(self, release: PackageRelease, path): provides = tree.get_mod_names() package = release.package - old_modnames = set([x.name for x in package.provides]) + old_provided_names = set([x.name for x in package.provides]) package.provides.clear() # If new mods were added, add to audit log if package.state == PackageState.APPROVED: new_provides = [] for modname in provides: - if modname not in old_modnames: + if modname not in old_provided_names: new_provides.append(modname) if len(new_provides) > 0: @@ -218,7 +218,7 @@ def post_release_check_update(self, release: PackageRelease, path): game_support_set(db.session, package, game_is_supported, 10) if package.type == PackageType.MOD: - errors = game_support_update(db.session, package) + errors = game_support_update(db.session, package, old_provided_names) if len(errors) != 0: raise TaskError("Error validating game support:\n\n" + "\n".join([f"- {x}" for x in errors])) diff --git a/app/tests/unit/logic/test_game_support.py b/app/tests/unit/logic/test_game_support.py index 1c1bac3f..a657635f 100644 --- a/app/tests/unit/logic/test_game_support.py +++ b/app/tests/unit/logic/test_game_support.py @@ -313,6 +313,45 @@ def test_update_new_mod(): assert len(lib.detected_supported_games) == 0 +def test_update_remove_mod(): + """ + Test that removing a mod from provides will update mods that depended on the modname + """ + support = GameSupport() + support.add(make_game("game1", ["default"])) + game2 = support.add(make_game("game2", ["core", "mod_b"])) + modB = support.add(make_mod("mod_b", ["mod_b"], ["default"])) + lib = support.add(make_mod("lib", ["lib"], [])) + modA = support.add(make_mod("mod_a", ["mod_a"], ["mod_b", "lib"])) + support.on_first_run() + + assert not support.has_errors + + assert modA.is_confirmed + assert modA.detected_supported_games == {"game1", "game2"} + + assert modB.is_confirmed + assert modB.detected_supported_games == {"game1"} + + assert lib.is_confirmed + assert len(lib.detected_supported_games) == 0 + + old_provides = game2.provides.copy() + game2.provides.remove("mod_b") + support.on_update(game2, old_provides) + + assert not support.has_errors + + assert modA.is_confirmed + assert modA.detected_supported_games == {"game1"} + + assert modB.is_confirmed + assert modB.detected_supported_games == {"game1"} + + assert lib.is_confirmed + assert len(lib.detected_supported_games) == 0 + + def test_update_cycle(): """ Test that updating a package with a cycle depending on it doesn't break