| 1 | diff --git a/deluge/common.py b/deluge/common.py
|
| 2 | index 7b76d245c..4631a6a93 100644
|
| 3 | |
| 4 | |
| 5 | @@ -33,10 +33,7 @@
|
| 6 | from deluge.decorators import deprecated
|
| 7 | from deluge.error import InvalidPathError
|
| 8 |
|
| 9 | -try:
|
| 10 | - from importlib.metadata import distribution
|
| 11 | -except ImportError:
|
| 12 | - from pkg_resources import get_distribution as distribution
|
| 13 | +from importlib.metadata import distribution
|
| 14 |
|
| 15 |
|
| 16 | try:
|
| 17 | diff --git a/deluge/pluginmanagerbase.py b/deluge/pluginmanagerbase.py
|
| 18 | index 52dae615b..77985715d 100644
|
| 19 | |
| 20 | |
| 21 | @@ -11,9 +11,10 @@
|
| 22 |
|
| 23 | import email
|
| 24 | import logging
|
| 25 | -import os.path
|
| 26 | +import os
|
| 27 | +import sys
|
| 28 | +from importlib.metadata import Distribution
|
| 29 |
|
| 30 | -import pkg_resources
|
| 31 | from twisted.internet import defer
|
| 32 | from twisted.python.failure import Failure
|
| 33 |
|
| 34 | @@ -102,21 +103,40 @@ def scan_for_plugins(self):
|
| 35 | ]
|
| 36 | plugin_dirs = [base_dir, user_dir] + base_subdir
|
| 37 |
|
| 38 | - for dirname in plugin_dirs:
|
| 39 | - pkg_resources.working_set.add_entry(dirname)
|
| 40 | - self.pkg_env = pkg_resources.Environment(
|
| 41 | - plugin_dirs, platform=None, python=None
|
| 42 | - )
|
| 43 | -
|
| 44 | + self._plugin_dists = {}
|
| 45 | self.available_plugins = []
|
| 46 | - for name in self.pkg_env:
|
| 47 | - log.debug(
|
| 48 | - 'Found plugin: %s %s at %s',
|
| 49 | - self.pkg_env[name][0].project_name,
|
| 50 | - self.pkg_env[name][0].version,
|
| 51 | - self.pkg_env[name][0].location,
|
| 52 | - )
|
| 53 | - self.available_plugins.append(self.pkg_env[name][0].project_name)
|
| 54 | +
|
| 55 | + for plugin_dir in plugin_dirs:
|
| 56 | + if not os.path.isdir(plugin_dir):
|
| 57 | + continue
|
| 58 | + if plugin_dir not in sys.path:
|
| 59 | + sys.path.insert(0, plugin_dir)
|
| 60 | +
|
| 61 | + for item in os.listdir(plugin_dir):
|
| 62 | + item_path = os.path.join(plugin_dir, item)
|
| 63 | + dist = None
|
| 64 | +
|
| 65 | + if item.endswith('.egg') and os.path.isdir(item_path):
|
| 66 | + # Add .egg directory to sys.path for imports
|
| 67 | + if item_path not in sys.path:
|
| 68 | + sys.path.insert(0, item_path)
|
| 69 | + egg_info = os.path.join(item_path, 'EGG-INFO')
|
| 70 | + if os.path.isdir(egg_info):
|
| 71 | + dist = Distribution.at(egg_info)
|
| 72 | + elif item.endswith(('.egg-info', '.dist-info')) and os.path.isdir(item_path):
|
| 73 | + dist = Distribution.at(item_path)
|
| 74 | +
|
| 75 | + if dist:
|
| 76 | + name = dist.metadata['Name']
|
| 77 | + if name not in self._plugin_dists:
|
| 78 | + self._plugin_dists[name] = dist
|
| 79 | + self.available_plugins.append(name)
|
| 80 | + log.debug(
|
| 81 | + 'Found plugin: %s %s at %s',
|
| 82 | + name,
|
| 83 | + dist.version,
|
| 84 | + plugin_dir,
|
| 85 | + )
|
| 86 |
|
| 87 | def enable_plugin(self, plugin_name):
|
| 88 | """Enable a plugin.
|
| 89 | @@ -138,28 +158,27 @@ def enable_plugin(self, plugin_name):
|
| 90 | return defer.succeed(True)
|
| 91 |
|
| 92 | plugin_name = plugin_name.replace(' ', '-')
|
| 93 | - egg = self.pkg_env[plugin_name][0]
|
| 94 | - # Activate is required by non-namespace plugins.
|
| 95 | - egg.activate()
|
| 96 | + dist = self._plugin_dists[plugin_name]
|
| 97 | return_d = defer.succeed(True)
|
| 98 |
|
| 99 | - for name in egg.get_entry_map(self.entry_name):
|
| 100 | + entry_points = [ep for ep in dist.entry_points if ep.group == self.entry_name]
|
| 101 | + for ep in entry_points:
|
| 102 | try:
|
| 103 | - cls = egg.load_entry_point(self.entry_name, name)
|
| 104 | + cls = ep.load()
|
| 105 | instance = cls(plugin_name.replace('-', '_'))
|
| 106 | except component.ComponentAlreadyRegistered as ex:
|
| 107 | log.error(ex)
|
| 108 | return defer.succeed(False)
|
| 109 | except Exception as ex:
|
| 110 | log.error(
|
| 111 | - 'Unable to instantiate plugin %r from %r!', name, egg.location
|
| 112 | + 'Unable to instantiate plugin %r from %r!', ep.name, dist.metadata['Name']
|
| 113 | )
|
| 114 | log.exception(ex)
|
| 115 | continue
|
| 116 | try:
|
| 117 | return_d = defer.maybeDeferred(instance.enable)
|
| 118 | except Exception as ex:
|
| 119 | - log.error('Unable to enable plugin: %s', name)
|
| 120 | + log.error('Unable to enable plugin: %s', ep.name)
|
| 121 | log.exception(ex)
|
| 122 | return_d = defer.fail(False)
|
| 123 |
|
| 124 | @@ -167,7 +186,7 @@ def enable_plugin(self, plugin_name):
|
| 125 | import warnings
|
| 126 |
|
| 127 | warnings.warn_explicit(
|
| 128 | - DEPRECATION_WARNING % name,
|
| 129 | + DEPRECATION_WARNING % ep.name,
|
| 130 | DeprecationWarning,
|
| 131 | instance.__module__,
|
| 132 | 0,
|
| 133 | @@ -257,14 +276,14 @@ def on_disabled(result):
|
| 134 | def get_plugin_info(self, name):
|
| 135 | """Returns a dictionary of plugin info from the metadata"""
|
| 136 |
|
| 137 | - if not self.pkg_env[name]:
|
| 138 | + if name not in self._plugin_dists:
|
| 139 | log.warning('Failed to retrieve info for plugin: %s', name)
|
| 140 | info = {}.fromkeys(METADATA_KEYS, '')
|
| 141 | info['Name'] = info['Version'] = 'not available'
|
| 142 | return info
|
| 143 |
|
| 144 | - pkg_info = self.pkg_env[name][0].get_metadata('PKG-INFO')
|
| 145 | - return self.parse_pkg_info(pkg_info)
|
| 146 | + metadata = self._plugin_dists[name].metadata
|
| 147 | + return {key: metadata.get(key, '') for key in METADATA_KEYS}
|
| 148 |
|
| 149 | @staticmethod
|
| 150 | def parse_pkg_info(pkg_info):
|
| 151 | diff --git a/deluge/ui/ui_entry.py b/deluge/ui/ui_entry.py
|
| 152 | index f0a983106..2cf7e4b4e 100644
|
| 153 | |
| 154 | |
| 155 | @@ -16,8 +16,7 @@
|
| 156 | import logging
|
| 157 | import os
|
| 158 | import sys
|
| 159 | -
|
| 160 | -import pkg_resources
|
| 161 | +from importlib.metadata import entry_points
|
| 162 |
|
| 163 | import deluge.common
|
| 164 | import deluge.configmanager
|
| 165 | @@ -35,7 +34,7 @@ def start_ui():
|
| 166 |
|
| 167 | # Get the registered UI entry points
|
| 168 | ui_entrypoints = {}
|
| 169 | - for entrypoint in pkg_resources.iter_entry_points('deluge.ui'):
|
| 170 | + for entrypoint in entry_points(group='deluge.ui'):
|
| 171 | try:
|
| 172 | ui_entrypoints[entrypoint.name] = entrypoint.load()
|
| 173 | except ImportError:
|