Skip to content

Commit

Permalink
addonHandler: don't make NVDA fail on restart if an addon cannot be r…
Browse files Browse the repository at this point in the history
…emoved because its directory is currently in use by another application. Fixes #2860.

Specifically:
	* Addon.completeRemove: always rename the directory to a temp directory with a delete sufix before trying to actually remove the directory. If the rename does not work, then there's nothing we can do for now. Just raise an error.
	* CompletePendingAddonRemovals: When walking through the set of add-ons, copy the list so that the set can be mutated while walking. Catch an error from Addon.completeRemove and just skip over it. Remove the addonName from the pendingRemoves set for each addon, as long as no error occured when calling Addon.completeRemove. This keeps addons that failed removal and couldn't be renamed for deletion in the pendingRemove state meaning that the GUI will reflect this, and on a subsiquent restart it will try to be removed again.
  • Loading branch information
michaelDCurran committed Dec 10, 2012
1 parent 30bc46e commit 27349d8
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 5 deletions.
17 changes: 12 additions & 5 deletions source/addonHandler.py
Expand Up @@ -65,12 +65,16 @@ def completePendingAddonRemoves():
"""Removes any addons that could not be removed on the last run of NVDA"""
user_addons = os.path.abspath(os.path.join(globalVars.appArgs.configPath, "addons"))
pendingRemovesSet=state['pendingRemovesSet']
for addonName in pendingRemovesSet:
for addonName in list(pendingRemovesSet):
addonPath=os.path.join(user_addons,addonName)
if os.path.isdir(addonPath):
addon=Addon(addonPath)
addon.completeRemove()
pendingRemovesSet.clear()
try:
addon.completeRemove()
except RuntimeError:
log.exception("Failed to remove %s add-on"%addonName)
continue
pendingRemovesSet.discard(addonName)

def completePendingAddonInstalls():
user_addons = os.path.abspath(os.path.join(globalVars.appArgs.configPath, "addons"))
Expand Down Expand Up @@ -225,11 +229,14 @@ def completeRemove(self,runUninstallTask=True):
log.error("task 'onUninstall' on addon '%s' failed"%self.name,exc_info=True)
finally:
del _availableAddons[self.path]
tempPath=tempfile.mktemp(suffix=DELETEDIR_SUFFIX,dir=os.path.dirname(self.path))
try:
os.rename(self.path,tempPath)
except (WindowsError,IOError):
raise RuntimeError("Cannot rename add-on path for deletion")
shutil.rmtree(self.path,ignore_errors=True)
if os.path.exists(self.path):
log.error("Error removing addon directory %s, deferring until next NVDA restart"%self.path)
tempPath=tempfile.mktemp(suffix=DELETEDIR_SUFFIX,dir=os.path.dirname(self.path))
os.rename(self.path,tempPath)

@property
def name(self):
Expand Down
1 change: 1 addition & 0 deletions user_docs/en/changes.t2t
Expand Up @@ -27,6 +27,7 @@
- The candidate list in the Chinese Simplified Microsoft Pinyin input method under Windows 7 is now correctly read when changing pages with left and right arrow, and when first opening it with Home.
- When custom symbol pronunciation information is saved, the advanced "preserve" field is no longer removed. (#2852)
- When disabling automatic checking for updates, NVDA no longer has to be restarted in order for the change to fully take effect.
- NVDA no longer fails to start if an add-on cannot be removed due to its directory currently being in use by another application. (#2860)


== Changes for Developers ==
Expand Down

0 comments on commit 27349d8

Please sign in to comment.