diff options
| -rw-r--r-- | py_modules/lsfg_vk/flatpak_service.py | 76 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/plugin.py | 3 | ||||
| -rw-r--r-- | src/api/lsfgApi.ts | 17 | ||||
| -rw-r--r-- | src/components/SetupTab.tsx | 76 | ||||
| -rw-r--r-- | tests/test_flatpak_service.py | 26 |
5 files changed, 33 insertions, 165 deletions
diff --git a/py_modules/lsfg_vk/flatpak_service.py b/py_modules/lsfg_vk/flatpak_service.py index c0a9c0c..11f1a82 100644 --- a/py_modules/lsfg_vk/flatpak_service.py +++ b/py_modules/lsfg_vk/flatpak_service.py @@ -202,11 +202,8 @@ class FlatpakService(BaseService): extension_id=self.EXTENSION_ID, supported_branches=list(self.SUPPORTED_RUNTIMES), installed_branches=[], - owned_branches=[], - ownership_uncertain=False, ) installed = self._installed_extension_branches() - owned, uncertain = self._read_owned_branches() return self._success_response( dict, "Flatpak runtime extension status retrieved", @@ -214,8 +211,6 @@ class FlatpakService(BaseService): extension_id=self.EXTENSION_ID, supported_branches=list(self.SUPPORTED_RUNTIMES), installed_branches=sorted(installed), - owned_branches=sorted(owned), - ownership_uncertain=uncertain, ) except Exception as error: return self._error_response( @@ -225,8 +220,6 @@ class FlatpakService(BaseService): extension_id=self.EXTENSION_ID, supported_branches=list(self.SUPPORTED_RUNTIMES), installed_branches=[], - owned_branches=[], - ownership_uncertain=False, ) def get_flatpak_support_status(self) -> Dict[str, Any]: @@ -294,18 +287,12 @@ class FlatpakService(BaseService): ) def install_extension(self, version: str) -> Dict[str, Any]: - """Install one missing branch and record ownership only after readback.""" + """Install one branch, treating an already-installed branch as success.""" try: version = self._validate_runtime(version) if not self.check_flatpak_available(): raise FileNotFoundError("Flatpak is not available on this system") with self._lock: - owned, uncertain = self._read_owned_branches() - if uncertain: - raise RuntimeError( - "Flatpak ownership metadata is uncertain; refusing to install " - "until it is repaired" - ) installed_before = self._installed_extension_branches() if version in installed_before: return self._success_response( @@ -314,8 +301,6 @@ class FlatpakService(BaseService): runtime_branch=version, installed=True, enabled=True, - owned_by_plugin=version in owned, - preserved=version not in owned, ) bundle_path = self._bundled_extension_path(version) if not bundle_path.is_file(): @@ -341,16 +326,16 @@ class FlatpakService(BaseService): f"Flatpak install completed but {self._extension_ref(version)} " "was not visible afterwards" ) - owned.add(version) - self._write_owned_branches(owned) + owned, uncertain = self._read_owned_branches() + if not uncertain: + owned.add(version) + self._write_owned_branches(owned) return self._success_response( dict, f"lsfg-vk {version} runtime extension installed", runtime_branch=version, installed=True, enabled=True, - owned_by_plugin=True, - preserved=False, ) except Exception as error: return self._error_response( @@ -359,8 +344,6 @@ class FlatpakService(BaseService): runtime_branch=version, installed=False, enabled=False, - owned_by_plugin=False, - preserved=False, ) def ensure_extension(self, version: str) -> Dict[str, Any]: @@ -384,7 +367,6 @@ class FlatpakService(BaseService): f"lsfg-vk {version} runtime extension is ready", runtime_branch=version, installed=True, - owned_by_plugin=version in status.get("owned_branches", []), ) return self.install_extension(version) @@ -419,41 +401,15 @@ class FlatpakService(BaseService): ) def uninstall_extension(self, version: str) -> Dict[str, Any]: - """Uninstall only when explicitly requested for a plugin-owned branch.""" + """Uninstall one branch, treating an already-absent branch as success.""" try: version = self._validate_runtime(version) if not self.check_flatpak_available(): raise FileNotFoundError("Flatpak is not available on this system") with self._lock: - owned, uncertain = self._read_owned_branches() - if uncertain: - raise RuntimeError( - "Flatpak ownership metadata is uncertain; refusing to uninstall" - ) installed = self._installed_extension_branches() - if version not in owned: - if version in installed: - return self._success_response( - dict, - f"Preserved Flatpak extension {version}; it is not plugin-owned", - runtime_branch=version, - removed=False, - installed=True, - enabled=True, - owned_by_plugin=False, - preserved=True, - ) - return self._success_response( - dict, - f"Flatpak extension {version} is already not installed", - runtime_branch=version, - removed=False, - installed=False, - enabled=False, - owned_by_plugin=False, - preserved=False, - ) - if version in installed: + was_installed = version in installed + if was_installed: result = self._run_flatpak_command( [ "uninstall", @@ -471,17 +427,17 @@ class FlatpakService(BaseService): f"Flatpak uninstall completed but {self._extension_ref(version)} " "is still installed" ) - owned.remove(version) - self._write_owned_branches(owned) + owned, uncertain = self._read_owned_branches() + if not uncertain and version in owned: + owned.remove(version) + self._write_owned_branches(owned) return self._success_response( dict, - f"Plugin-owned lsfg-vk {version} runtime extension removed", + f"lsfg-vk {version} runtime extension uninstalled", runtime_branch=version, - removed=True, + removed=was_installed, installed=False, enabled=False, - owned_by_plugin=False, - preserved=False, ) except Exception as error: return self._error_response( @@ -491,8 +447,6 @@ class FlatpakService(BaseService): removed=False, installed=False, enabled=False, - owned_by_plugin=False, - preserved=False, ) def set_extension_enabled(self, version: str, enabled: bool) -> Dict[str, Any]: @@ -504,8 +458,6 @@ class FlatpakService(BaseService): runtime_branch=version, installed=False, enabled=False, - owned_by_plugin=False, - preserved=False, ) return self.install_extension(version) if enabled else self.uninstall_extension(version) diff --git a/py_modules/lsfg_vk/plugin.py b/py_modules/lsfg_vk/plugin.py index 76a4250..c576cc2 100644 --- a/py_modules/lsfg_vk/plugin.py +++ b/py_modules/lsfg_vk/plugin.py @@ -162,9 +162,6 @@ class Plugin: async def set_flatpak_extension_enabled(self, version: str, enabled: bool) -> Dict[str, Any]: return self.flatpak_service.set_extension_enabled(version, enabled) - - async def remove_plugin_owned_flatpak_extensions(self) -> Dict[str, Any]: - return self.flatpak_service.remove_plugin_owned_extensions() async def _main(self): """ diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts index 16b6eab..8179ef9 100644 --- a/src/api/lsfgApi.ts +++ b/src/api/lsfgApi.ts @@ -124,17 +124,6 @@ export interface FlatpakExtensionStatus { extension_id: string; supported_branches: string[]; installed_branches: string[]; - owned_branches: string[]; - ownership_uncertain: boolean; -} - -export interface FlatpakCleanupResult { - success: boolean; - message: string; - error?: string | null; - removed_branches: string[]; - preserved_branches: string[]; - ownership_uncertain: boolean; } export interface FlatpakExtensionToggleResult { @@ -144,8 +133,6 @@ export interface FlatpakExtensionToggleResult { runtime_branch: string; enabled: boolean; installed: boolean; - owned_by_plugin: boolean; - preserved: boolean; } // API functions @@ -162,10 +149,6 @@ export const setFlatpakExtensionEnabled = callable< [string, boolean], FlatpakExtensionToggleResult >("set_flatpak_extension_enabled"); -export const removePluginOwnedFlatpakExtensions = callable< - [], - FlatpakCleanupResult ->("remove_plugin_owned_flatpak_extensions"); export const getGameConfigs = callable<[], GameConfigsResult>("get_game_configs"); export const getInstalledGames = callable<[], InstalledGamesResult>("get_installed_games"); diff --git a/src/components/SetupTab.tsx b/src/components/SetupTab.tsx index df43c5e..aec0e93 100644 --- a/src/components/SetupTab.tsx +++ b/src/components/SetupTab.tsx @@ -1,8 +1,7 @@ -import { ButtonItem, ConfirmModal, Field, PanelSection, PanelSectionRow, ToggleField, showModal } from "@decky/ui"; +import { ButtonItem, Field, PanelSection, PanelSectionRow, ToggleField } from "@decky/ui"; import { useEffect, useState } from "react"; import { getFlatpakSupportStatus, - removePluginOwnedFlatpakExtensions, setFlatpakExtensionEnabled, type FlatpakExtensionStatus, type SteamBranchStatus, @@ -41,8 +40,6 @@ function FlatpakSupportDiagnostics({ relevant }: { relevant: boolean }) { extension_id: "", supported_branches: [], installed_branches: [], - owned_branches: [], - ownership_uncertain: false, }); } }; @@ -67,61 +64,10 @@ function FlatpakSupportDiagnostics({ relevant }: { relevant: boolean }) { } }; - const confirmDisable = (version: string) => { - showModal( - <ConfirmModal - strTitle={`Disable Flatpak runtime ${version}?`} - strDescription="Only runtime extensions installed by this plugin can be removed. Pre-existing extensions are preserved." - strOKButtonText="Disable" - strCancelButtonText="Cancel" - onOK={() => void runExtensionOperation(version, false)} - onCancel={() => {}} - />, - ); - }; - const handleExtensionToggle = (version: string, enabled: boolean) => { - const installed = status.installed_branches.includes(version); - const owned = status.owned_branches.includes(version); - if (!enabled && installed && !owned) { - showErrorToast( - "Flatpak runtime preserved", - `${version} was not installed by this plugin, so it will remain installed.`, - ); - void refresh(); - return; - } - if (!enabled && installed && owned) { - confirmDisable(version); - return; - } void runExtensionOperation(version, enabled); }; - const confirmCleanup = () => { - showModal( - <ConfirmModal - strTitle="Remove plugin-installed Flatpak extensions?" - strDescription="Shared runtime branches recorded as installed by this plugin will be removed. Existing unowned branches are preserved." - strOKButtonText="Remove extensions" - strCancelButtonText="Cancel" - onOK={async () => { - setOperation("cleanup"); - try { - const result = await removePluginOwnedFlatpakExtensions(); - if (!result.success) throw new Error(result.error || result.message || "Flatpak cleanup failed"); - await refresh(); - } catch (error) { - showErrorToast("Flatpak cleanup failed", String(error)); - } finally { - setOperation(null); - } - }} - onCancel={() => {}} - />, - ); - }; - return ( <PanelSection title="Flatpak support"> <PanelSectionRow> @@ -147,31 +93,15 @@ function FlatpakSupportDiagnostics({ relevant }: { relevant: boolean }) { : operation === `disable-${branch}` ? "Uninstalling..." : status.installed_branches.includes(branch) - ? status.owned_branches.includes(branch) - ? "Installed · plugin-owned" - : "Installed · pre-existing (preserved)" + ? "Installed" : "Not installed" } checked={status.installed_branches.includes(branch)} onChange={(enabled) => handleExtensionToggle(branch, enabled)} - disabled={operation !== null || status.ownership_uncertain} + disabled={operation !== null} /> </PanelSectionRow> ))} - {status.ownership_uncertain && ( - <PanelSectionRow> - <Field label="Ownership metadata is uncertain" description="Cleanup is disabled until the metadata is repaired." /> - </PanelSectionRow> - )} - <PanelSectionRow> - <ButtonItem - layout="below" - disabled={operation !== null || status.ownership_uncertain || status.owned_branches.length === 0} - onClick={confirmCleanup} - > - {operation === "cleanup" ? "Removing..." : "Remove plugin-installed extensions"} - </ButtonItem> - </PanelSectionRow> </> )} </PanelSection> diff --git a/tests/test_flatpak_service.py b/tests/test_flatpak_service.py index 274c0c5..70ba228 100644 --- a/tests/test_flatpak_service.py +++ b/tests/test_flatpak_service.py @@ -93,7 +93,8 @@ class FlatpakServiceTests(unittest.TestCase): response = self.service.install_extension("24.08") self.assertTrue(response["success"]) - self.assertTrue(response["owned_by_plugin"]) + self.assertTrue(response["enabled"]) + self.assertTrue(response["installed"]) install_args = self.service._run_flatpak_command.call_args_list[1].args[0] self.assertEqual(install_args[:4], ["install", "--user", "--noninteractive", "--or-update"]) self.assertEqual( @@ -110,28 +111,33 @@ class FlatpakServiceTests(unittest.TestCase): cleanup_response = self.service.remove_plugin_owned_extensions() self.assertTrue(install_response["success"]) - self.assertFalse(install_response["owned_by_plugin"]) + self.assertTrue(install_response["enabled"]) + self.assertTrue(install_response["installed"]) self.assertFalse(self.service.ownership_path.exists()) self.assertTrue(cleanup_response["success"]) self.assertEqual(self.service._run_flatpak_command.call_count, 1) - def test_extension_toggle_is_idempotent_and_preserves_preexisting_branch(self): - self.service._run_flatpak_command.return_value = self._result( - self._extension_line("24.08") - ) + def test_extension_toggle_installs_and_uninstalls_preexisting_branch(self): + self.service._run_flatpak_command.side_effect = [ + self._result(self._extension_line("24.08")), + self._result(self._extension_line("24.08")), + self._result(""), + self._result(""), + ] enable_response = self.service.set_extension_enabled("24.08", True) disable_response = self.service.set_extension_enabled("24.08", False) self.assertTrue(enable_response["success"]) self.assertTrue(enable_response["enabled"]) + self.assertTrue(enable_response["installed"]) self.assertTrue(disable_response["success"]) - self.assertTrue(disable_response["enabled"]) - self.assertTrue(disable_response["preserved"]) - self.assertFalse(disable_response["owned_by_plugin"]) + self.assertFalse(disable_response["enabled"]) + self.assertFalse(disable_response["installed"]) + self.assertTrue(disable_response["removed"]) self.assertEqual( [call.args[0][0] for call in self.service._run_flatpak_command.call_args_list], - ["list", "list"], + ["list", "list", "uninstall", "list"], ) def test_extension_toggle_removes_owned_branch_and_can_repeat_disable(self): |
