Skip to content

Commit

Permalink
Don't delete "all" when there's active components
Browse files Browse the repository at this point in the history
It's not the first time I've accidentally nuked my entire modlist while
trying to merely delete my downloads, but it will be my last.

Don't allow deleting "all" if any of the visible components are enabled.
This works for mods and plugins. Since downloads don't get enabled or
disabled, they can still be deleted without restriction.
  • Loading branch information
cyberrumor committed Mar 19, 2024
1 parent 35fb306 commit 8cbb4ad
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 6 deletions.
11 changes: 11 additions & 0 deletions ammo/mod_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,12 @@ def delete(self, component: DeleteEnum, index: Union[int, str]) -> None:
if index == "all":
deleted_mods = ""
visible_mods = [i for i in self.mods if i.visible]
# Don't allow deleting mods with "all" unless they're inactive.
for mod in visible_mods:
if mod.enabled:
raise Warning(
"You must deactivate all visible components of that type before deleting them with all."
)
for mod in visible_mods:
self.deactivate(ComponentEnum.MOD, self.mods.index(mod))
for mod in visible_mods:
Expand Down Expand Up @@ -757,6 +763,11 @@ def get_plugin_files(plugin):
if index == "all":
deleted_plugins = ""
visible_plugins = [i for i in self.plugins if i.visible]
for plugin in visible_plugins:
if plugin.enabled:
raise Warning(
"You must deactivate all visible components of that type before deleting them with all."
)

for plugin in visible_plugins:
if plugin.mod is None or plugin.name in (
Expand Down
13 changes: 10 additions & 3 deletions test/test_conflict_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,24 @@ def test_conflicting_plugins_mult_delete_plugin():
install_mod(controller, mod)

controller.delete(DeleteEnum.PLUGIN, 0)
files = controller.mods[[i.name for i in controller.mods].index("plugin_wrong_spot")].files
files = controller.mods[
[i.name for i in controller.mods].index("plugin_wrong_spot")
].files
file = controller.game.ammo_mods_dir / "plugin_wrong_spot/Data/test/plugin.esp"
# Check that we didn't delete a plugin that wasn't in Data
assert file in files

files = controller.mods[[i.name for i in controller.mods].index("mult_plugins_same_name")].files
files = controller.mods[
[i.name for i in controller.mods].index("mult_plugins_same_name")
].files
file = controller.game.ammo_mods_dir / "mult_plugins_same_name/Data/plugin.esp"
# Check that we deleted what we intended to
assert file not in files

file = controller.game.ammo_mods_dir / "mult_plugins_same_name/Data/test/plugin.esp"
file = (
controller.game.ammo_mods_dir
/ "mult_plugins_same_name/Data/test/plugin.esp"
)
# Check that we didn't delete a plugin that wasn't in Data
assert file in files

Expand Down
35 changes: 35 additions & 0 deletions test/test_controller_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,38 @@ def test_controller_plugin_wrong_spot():
controller.rename(ComponentEnum.MOD, 0, "new_name")
assert controller.mods[0].plugins == []


def test_no_delete_all_if_mod_active():
"""
It's not the first time I've done this on accident, but
it will be the last. Test that deleting all mods fails if
any visible mod is still enabled. In other words, deleting
all mods is only allowed if all visible mods are inactive.
"""
with AmmoController() as controller:
install_mod(controller, "conflict_1")
extract_mod(controller, "conflict_2")

expected = "You must deactivate all visible components of that type before deleting them with all."

with pytest.raises(Warning) as warning:
controller.delete(DeleteEnum.MOD, "all")
assert warning.value.args == (expected,)


def test_no_delete_all_if_plugin_active():
"""
Test that all target plugins are deactivated before
deleting them with all. If there's an active one,
prompt the user to deactivate it before allowing this operation.
"""
with AmmoController() as controller:
install_mod(controller, "conflict_1")
install_mod(controller, "normal_mod")
controller.activate(ComponentEnum.PLUGIN, 1)

expected = "You must deactivate all visible components of that type before deleting them with all."

with pytest.raises(Warning) as warning:
controller.delete(DeleteEnum.PLUGIN, "all")
assert warning.value.args == (expected,)
6 changes: 3 additions & 3 deletions test/test_find.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ def test_find_delete_all_mods():
then deleting all will only delete visible mods.
"""
with AmmoController() as controller:
install_mod(controller, "normal_mod")
install_mod(controller, "conflict_1")
install_mod(controller, "no_data_folder_plugin")
extract_mod(controller, "normal_mod")
extract_mod(controller, "conflict_1")
extract_mod(controller, "no_data_folder_plugin")

controller.find("normal", "conflict")
controller.delete(DeleteEnum.MOD, "all")
Expand Down

0 comments on commit 8cbb4ad

Please sign in to comment.