-
-
Notifications
You must be signed in to change notification settings - Fork 621
/
install.py
99 lines (85 loc) · 3.36 KB
/
install.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2022-2023 NV Access Limited
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
from os import (
PathLike,
)
from typing import (
TYPE_CHECKING,
cast,
Optional,
)
import systemUtils
from logHandler import log
from .dataManager import (
addonDataManager,
)
if TYPE_CHECKING:
from addonHandler import AddonBundle, Addon as AddonHandlerModel # noqa: F401
def _getAddonBundleToInstallIfValid(addonPath: str) -> "AddonBundle":
"""
@param addonPath: path to the 'nvda-addon' file.
@return: the addonBundle, if valid
@raise DisplayableError if the addon bundle is invalid / incompatible.
"""
from addonHandler import AddonBundle, AddonError
from gui.message import DisplayableError
try:
bundle = AddonBundle(addonPath)
except AddonError:
log.error("Error opening addon bundle from %s" % addonPath, exc_info=True)
raise DisplayableError(
displayMessage=pgettext(
"addonStore",
# Translators: The message displayed when an error occurs when opening an add-on package for adding.
# The %s will be replaced with the path to the add-on that could not be opened.
"Failed to open add-on package file at {filePath} - missing file or invalid file format"
).format(filePath=addonPath)
)
if not bundle.isCompatible and not (
bundle.canOverrideCompatibility and bundle._hasOverriddenCompat
):
# This should not happen, only compatible or overridable add-ons are
# intended to be presented in the add-on store.
raise DisplayableError(
displayMessage=pgettext(
"addonStore",
# Translators: The message displayed when an add-on is not supported by this version of NVDA.
# The %s will be replaced with the path to the add-on that is not supported.
"Add-on not supported %s"
) % addonPath
)
return bundle
def _getPreviouslyInstalledAddonById(addon: "AddonBundle") -> Optional["AddonHandlerModel"]:
assert addonDataManager
installedAddon = addonDataManager._installedAddonsCache.installedAddons.get(addon.name)
if installedAddon is None or installedAddon.isPendingRemove:
return None
return installedAddon
def installAddon(addonPath: PathLike) -> None:
""" Installs the addon at path.
Any error messages / warnings are presented to the user via a GUI message box.
If attempting to install an addon that is pending removal, it will no longer be pending removal.
@note See also L{gui.addonGui.installAddon}
@raise DisplayableError on failure
"""
from addonHandler import AddonError, installAddonBundle
from gui.message import DisplayableError
addonPath = cast(str, addonPath)
bundle = _getAddonBundleToInstallIfValid(addonPath)
prevAddon = _getPreviouslyInstalledAddonById(bundle)
try:
systemUtils.ExecAndPump(installAddonBundle, bundle)
if prevAddon:
prevAddon.requestRemove()
except AddonError: # Handle other exceptions as they are known
log.error("Error installing addon bundle from %s" % addonPath, exc_info=True)
raise DisplayableError(
displayMessage=pgettext(
"addonStore",
# Translators: The message displayed when an error occurs when installing an add-on package.
# The %s will be replaced with the path to the add-on that could not be installed.
"Failed to install add-on from %s"
) % addonPath
)