Ability to update plugins on startup from a download folder
This commit is contained in:
parent
ff0e02685a
commit
00c8e5c01d
|
@ -214,6 +214,7 @@ class ConfigPaths:
|
||||||
# Data paths
|
# Data paths
|
||||||
('LOG_DB', 'logs.db', PathLocation.DATA, PathType.FILE),
|
('LOG_DB', 'logs.db', PathLocation.DATA, PathType.FILE),
|
||||||
('MY_CACERTS', 'cacerts.pem', PathLocation.DATA, PathType.FILE),
|
('MY_CACERTS', 'cacerts.pem', PathLocation.DATA, PathType.FILE),
|
||||||
|
('PLUGINS_DOWNLOAD', 'plugins_download', PathLocation.CACHE, PathType.FOLDER),
|
||||||
('PLUGINS_USER', 'plugins', PathLocation.DATA, PathType.FOLDER),
|
('PLUGINS_USER', 'plugins', PathLocation.DATA, PathType.FOLDER),
|
||||||
('MY_EMOTS',
|
('MY_EMOTS',
|
||||||
'emoticons', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
|
'emoticons', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
|
||||||
|
|
|
@ -27,7 +27,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import zipfile
|
import zipfile
|
||||||
from shutil import rmtree
|
from shutil import rmtree, move
|
||||||
import configparser
|
import configparser
|
||||||
from pkg_resources import parse_version
|
from pkg_resources import parse_version
|
||||||
|
|
||||||
|
@ -109,6 +109,8 @@ class PluginManager(metaclass=Singleton):
|
||||||
Registered names with instances of encryption Plugins.
|
Registered names with instances of encryption Plugins.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
self.update_plugins()
|
||||||
|
|
||||||
for path in reversed(configpaths.get_plugin_dirs()):
|
for path in reversed(configpaths.get_plugin_dirs()):
|
||||||
pc = self.scan_dir_for_plugins(path)
|
pc = self.scan_dir_for_plugins(path)
|
||||||
self.add_plugins(pc)
|
self.add_plugins(pc)
|
||||||
|
@ -126,6 +128,47 @@ class PluginManager(metaclass=Singleton):
|
||||||
def _remove_plugin_entry_in_global_config(self, plugin):
|
def _remove_plugin_entry_in_global_config(self, plugin):
|
||||||
app.config.del_per('plugins', plugin.short_name)
|
app.config.del_per('plugins', plugin.short_name)
|
||||||
|
|
||||||
|
@log_calls('PluginManager')
|
||||||
|
def update_plugins(self, replace=True, activate=False, plugin_name=None):
|
||||||
|
'''
|
||||||
|
Move plugins from the downloaded folder to the user plugin folder
|
||||||
|
|
||||||
|
:param replace: replace plugin files if they already exist.
|
||||||
|
:type replace: boolean
|
||||||
|
:param activate: load and activate the plugin
|
||||||
|
:type activate: boolean
|
||||||
|
:param plugin_name: if provided, update only this plugin
|
||||||
|
:type plugin_name: str
|
||||||
|
:return: list of updated plugins (files have been installed)
|
||||||
|
:rtype: [] of str
|
||||||
|
'''
|
||||||
|
updated_plugins = []
|
||||||
|
user_dir = configpaths.get('PLUGINS_USER')
|
||||||
|
dl_dir = configpaths.get('PLUGINS_DOWNLOAD')
|
||||||
|
to_update = [plugin_name] if plugin_name else next(os.walk(dl_dir))[1]
|
||||||
|
for directory in to_update:
|
||||||
|
src_dir = os.path.join(dl_dir, directory)
|
||||||
|
dst_dir = os.path.join(user_dir, directory)
|
||||||
|
try:
|
||||||
|
if os.path.exists(dst_dir):
|
||||||
|
if not replace:
|
||||||
|
continue
|
||||||
|
self.delete_plugin_files(dst_dir)
|
||||||
|
move(src_dir, dst_dir)
|
||||||
|
except Exception:
|
||||||
|
log.exception('Upgrade of plugin %s failed. Impossible to move '
|
||||||
|
'files from "%s" to "%s"', directory, src_dir, dst_dir)
|
||||||
|
continue
|
||||||
|
updated_plugins.append(directory)
|
||||||
|
if activate:
|
||||||
|
pc = self.scan_dir_for_plugins(dst_dir, scan_dirs=True,
|
||||||
|
package=True)
|
||||||
|
self.add_plugin(pc[0])
|
||||||
|
plugin = self.plugins[-1]
|
||||||
|
self.activate_plugin(plugin)
|
||||||
|
return updated_plugins
|
||||||
|
|
||||||
|
|
||||||
@log_calls('PluginManager')
|
@log_calls('PluginManager')
|
||||||
def init_plugins(self):
|
def init_plugins(self):
|
||||||
self._activate_all_plugins_from_global_config()
|
self._activate_all_plugins_from_global_config()
|
||||||
|
@ -725,10 +768,7 @@ class PluginManager(metaclass=Singleton):
|
||||||
plugin = self.plugins[-1]
|
plugin = self.plugins[-1]
|
||||||
return plugin
|
return plugin
|
||||||
|
|
||||||
def uninstall_plugin(self, plugin):
|
def delete_plugin_files(self, plugin_path):
|
||||||
'''
|
|
||||||
Deactivate and remove plugin from `plugins` list
|
|
||||||
'''
|
|
||||||
def on_error(func, path, error):
|
def on_error(func, path, error):
|
||||||
if func == os.path.islink:
|
if func == os.path.islink:
|
||||||
# if symlink
|
# if symlink
|
||||||
|
@ -737,9 +777,15 @@ class PluginManager(metaclass=Singleton):
|
||||||
# access is denied or other
|
# access is denied or other
|
||||||
raise PluginsystemError(error[1][1])
|
raise PluginsystemError(error[1][1])
|
||||||
|
|
||||||
|
rmtree(plugin_path, False, on_error)
|
||||||
|
|
||||||
|
def uninstall_plugin(self, plugin):
|
||||||
|
'''
|
||||||
|
Deactivate and remove plugin from `plugins` list
|
||||||
|
'''
|
||||||
if plugin:
|
if plugin:
|
||||||
self.remove_plugin(plugin)
|
self.remove_plugin(plugin)
|
||||||
rmtree(plugin.__path__, False, on_error)
|
self.delete_plugin_files(plugin.__path__)
|
||||||
if self._plugin_has_entry_in_global_config(plugin):
|
if self._plugin_has_entry_in_global_config(plugin):
|
||||||
self._remove_plugin_entry_in_global_config(plugin)
|
self._remove_plugin_entry_in_global_config(plugin)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue