Add add-on installation hooks (#2523)

* Add add-on installation hooks

* Fix GUI code run in background thread

deleteAddon() is run in the background in the update routine so it
shouldn't containg any GUI code.

* Add a hint to the docstrings (dae)
This commit is contained in:
Abdo 2023-05-29 12:47:49 +03:00 committed by GitHub
parent 93e1a6be22
commit c87f62487b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 20 deletions

View file

@ -426,7 +426,9 @@ class AddonManager:
conflicts = manifest.get("conflicts", [])
found_conflicts = self._disableConflicting(package, conflicts)
meta = self.addonMeta(package)
gui_hooks.addon_manager_will_install_addon(self, package)
self._install(package, zfile)
gui_hooks.addon_manager_did_install_addon(self, package)
schema = self._manifest_schema["properties"]
manifest_meta = {
@ -450,10 +452,11 @@ class AddonManager:
base = self.addonsFolder(module)
if os.path.exists(base):
self.backupUserFiles(module)
if not self.deleteAddon(module):
try:
self.deleteAddon(module)
except Exception:
self.restoreUserFiles(module)
return
raise
os.mkdir(base)
self.restoreUserFiles(module)
@ -469,17 +472,8 @@ class AddonManager:
continue
zfile.extract(n, base)
# true on success
def deleteAddon(self, module: str) -> bool:
try:
send_to_trash(Path(self.addonsFolder(module)))
return True
except OSError as e:
showWarning(
tr.addons_unable_to_update_or_delete_addon(val=str(e)),
textFormat="plain",
)
return False
def deleteAddon(self, module: str) -> None:
send_to_trash(Path(self.addonsFolder(module)))
# Processing local add-on files
######################################################################
@ -912,12 +906,17 @@ class AddonsDialog(QDialog):
if not askUser(tr.addons_delete_the_numd_selected_addon(count=len(selected))):
return
gui_hooks.addons_dialog_will_delete_addons(self, selected)
for module in selected:
# doing this before deleting, as `enabled` is always True afterwards
if self.mgr.addon_meta(module).enabled:
self._require_restart = True
if not self.mgr.deleteAddon(module):
break
try:
for module in selected:
# doing this before deleting, as `enabled` is always True afterwards
if self.mgr.addon_meta(module).enabled:
self._require_restart = True
self.mgr.deleteAddon(module)
except OSError as e:
showWarning(
tr.addons_unable_to_update_or_delete_addon(val=str(e)),
textFormat="plain",
)
self.form.addonList.clearSelection()
self.redrawAddons()

View file

@ -1211,6 +1211,22 @@ gui_hooks.webview_did_inject_style_into_page.append(mytest)
args=["dialog: aqt.addons.AddonsDialog", "ids: list[str]"],
doc="""Allows doing an action before an add-on is deleted.""",
),
Hook(
name="addon_manager_will_install_addon",
args=["manager: aqt.addons.AddonManager", "module: str"],
doc="""Called before installing or updating an addon.
Can be used to release DB connections or open files that
would prevent an update from succeeding.""",
),
Hook(
name="addon_manager_did_install_addon",
args=["manager: aqt.addons.AddonManager", "module: str"],
doc="""Called after installing or updating an addon.
Can be used to restore DB connections or open files after
an add-on has been updated.""",
),
# Model
###################
Hook(