Ability to update plugins on startup from a download folder
This commit is contained in:
		
							parent
							
								
									ff0e02685a
								
							
						
					
					
						commit
						00c8e5c01d
					
				
					 2 changed files with 53 additions and 6 deletions
				
			
		| 
						 | 
					@ -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…
	
	Add table
		
		Reference in a new issue