64 @signal pluginDeactivated(moduleName, pluginObject) emitted just after |
66 @signal pluginDeactivated(moduleName, pluginObject) emitted just after |
65 a plugin was deactivated |
67 a plugin was deactivated |
66 @signal pluginRepositoryFileDownloaded() emitted to indicate a completed |
68 @signal pluginRepositoryFileDownloaded() emitted to indicate a completed |
67 download of the plugin repository file |
69 download of the plugin repository file |
68 """ |
70 """ |
|
71 |
69 shutdown = pyqtSignal() |
72 shutdown = pyqtSignal() |
70 pluginAboutToBeActivated = pyqtSignal(str, object) |
73 pluginAboutToBeActivated = pyqtSignal(str, object) |
71 pluginActivated = pyqtSignal(str, object) |
74 pluginActivated = pyqtSignal(str, object) |
72 allPlugginsActivated = pyqtSignal() |
75 allPlugginsActivated = pyqtSignal() |
73 pluginAboutToBeDeactivated = pyqtSignal(str, object) |
76 pluginAboutToBeDeactivated = pyqtSignal(str, object) |
74 pluginDeactivated = pyqtSignal(str, object) |
77 pluginDeactivated = pyqtSignal(str, object) |
75 pluginRepositoryFileDownloaded = pyqtSignal() |
78 pluginRepositoryFileDownloaded = pyqtSignal() |
76 |
79 |
77 def __init__(self, parent=None, disabledPlugins=None, doLoadPlugins=True, |
80 def __init__( |
78 develPlugin=None): |
81 self, parent=None, disabledPlugins=None, doLoadPlugins=True, develPlugin=None |
|
82 ): |
79 """ |
83 """ |
80 Constructor |
84 Constructor |
81 |
85 |
82 The Plugin Manager deals with three different plugin directories. |
86 The Plugin Manager deals with three different plugin directories. |
83 The first is the one, that is part of eric7 (eric7/Plugins). The |
87 The first is the one, that is part of eric7 (eric7/Plugins). The |
84 second one is the global plugin directory called 'eric7plugins', |
88 second one is the global plugin directory called 'eric7plugins', |
85 which is located inside the site-packages directory. The last one |
89 which is located inside the site-packages directory. The last one |
86 is the user plugin directory located inside the .eric7 directory |
90 is the user plugin directory located inside the .eric7 directory |
87 of the users home directory. |
91 of the users home directory. |
88 |
92 |
89 @param parent reference to the parent object |
93 @param parent reference to the parent object |
90 @type QObject |
94 @type QObject |
91 @param disabledPlugins list of plug-ins that have been disabled via |
95 @param disabledPlugins list of plug-ins that have been disabled via |
92 the command line parameters '--disable-plugin=' |
96 the command line parameters '--disable-plugin=' |
93 @type list of str |
97 @type list of str |
100 @exception PluginPathError raised to indicate an invalid plug-in path |
104 @exception PluginPathError raised to indicate an invalid plug-in path |
101 @exception PluginModulesError raised to indicate the absence of |
105 @exception PluginModulesError raised to indicate the absence of |
102 plug-in modules |
106 plug-in modules |
103 """ |
107 """ |
104 super().__init__(parent) |
108 super().__init__(parent) |
105 |
109 |
106 self.__ui = parent |
110 self.__ui = parent |
107 self.__develPluginFile = develPlugin |
111 self.__develPluginFile = develPlugin |
108 self.__develPluginName = None |
112 self.__develPluginName = None |
109 if disabledPlugins is not None: |
113 if disabledPlugins is not None: |
110 self.__disabledPlugins = disabledPlugins[:] |
114 self.__disabledPlugins = disabledPlugins[:] |
111 else: |
115 else: |
112 self.__disabledPlugins = [] |
116 self.__disabledPlugins = [] |
113 |
117 |
114 self.__inactivePluginsKey = "PluginManager/InactivePlugins" |
118 self.__inactivePluginsKey = "PluginManager/InactivePlugins" |
115 |
119 |
116 self.pluginDirs = { |
120 self.pluginDirs = { |
117 "eric7": os.path.join(getConfig('ericDir'), "Plugins"), |
121 "eric7": os.path.join(getConfig("ericDir"), "Plugins"), |
118 "global": os.path.join(Utilities.getPythonLibraryDirectory(), |
122 "global": os.path.join( |
119 "eric7plugins"), |
123 Utilities.getPythonLibraryDirectory(), "eric7plugins" |
|
124 ), |
120 "user": os.path.join(Utilities.getConfigDir(), "eric7plugins"), |
125 "user": os.path.join(Utilities.getConfigDir(), "eric7plugins"), |
121 } |
126 } |
122 self.__priorityOrder = ["eric7", "global", "user"] |
127 self.__priorityOrder = ["eric7", "global", "user"] |
123 |
128 |
124 self.__defaultDownloadDir = os.path.join( |
129 self.__defaultDownloadDir = os.path.join(Utilities.getConfigDir(), "Downloads") |
125 Utilities.getConfigDir(), "Downloads") |
130 |
126 |
|
127 self.__activePlugins = {} |
131 self.__activePlugins = {} |
128 self.__inactivePlugins = {} |
132 self.__inactivePlugins = {} |
129 self.__onDemandActivePlugins = {} |
133 self.__onDemandActivePlugins = {} |
130 self.__onDemandInactivePlugins = {} |
134 self.__onDemandInactivePlugins = {} |
131 self.__activeModules = {} |
135 self.__activeModules = {} |
132 self.__inactiveModules = {} |
136 self.__inactiveModules = {} |
133 self.__onDemandActiveModules = {} |
137 self.__onDemandActiveModules = {} |
134 self.__onDemandInactiveModules = {} |
138 self.__onDemandInactiveModules = {} |
135 self.__failedModules = {} |
139 self.__failedModules = {} |
136 |
140 |
137 self.__foundCoreModules = [] |
141 self.__foundCoreModules = [] |
138 self.__foundGlobalModules = [] |
142 self.__foundGlobalModules = [] |
139 self.__foundUserModules = [] |
143 self.__foundUserModules = [] |
140 |
144 |
141 self.__modulesCount = 0 |
145 self.__modulesCount = 0 |
142 |
146 |
143 pdirsExist, msg = self.__pluginDirectoriesExist() |
147 pdirsExist, msg = self.__pluginDirectoriesExist() |
144 if not pdirsExist: |
148 if not pdirsExist: |
145 raise PluginPathError(msg) |
149 raise PluginPathError(msg) |
146 |
150 |
147 if doLoadPlugins: |
151 if doLoadPlugins: |
148 if not self.__pluginModulesExist(): |
152 if not self.__pluginModulesExist(): |
149 raise PluginModulesError |
153 raise PluginModulesError |
150 |
154 |
151 self.__insertPluginsPaths() |
155 self.__insertPluginsPaths() |
152 |
156 |
153 self.__loadPlugins() |
157 self.__loadPlugins() |
154 |
158 |
155 self.__checkPluginsDownloadDirectory() |
159 self.__checkPluginsDownloadDirectory() |
156 |
160 |
157 self.pluginRepositoryFile = os.path.join(Utilities.getConfigDir(), |
161 self.pluginRepositoryFile = os.path.join( |
158 "PluginRepository") |
162 Utilities.getConfigDir(), "PluginRepository" |
159 |
163 ) |
|
164 |
160 # attributes for the network objects |
165 # attributes for the network objects |
161 self.__networkManager = QNetworkAccessManager(self) |
166 self.__networkManager = QNetworkAccessManager(self) |
162 self.__networkManager.proxyAuthenticationRequired.connect( |
167 self.__networkManager.proxyAuthenticationRequired.connect( |
163 proxyAuthenticationRequired) |
168 proxyAuthenticationRequired |
|
169 ) |
164 if SSL_AVAILABLE: |
170 if SSL_AVAILABLE: |
165 self.__sslErrorHandler = EricSslErrorHandler(self) |
171 self.__sslErrorHandler = EricSslErrorHandler(self) |
166 self.__networkManager.sslErrors.connect(self.__sslErrors) |
172 self.__networkManager.sslErrors.connect(self.__sslErrors) |
167 self.__replies = [] |
173 self.__replies = [] |
168 |
174 |
169 def finalizeSetup(self): |
175 def finalizeSetup(self): |
170 """ |
176 """ |
171 Public method to finalize the setup of the plugin manager. |
177 Public method to finalize the setup of the plugin manager. |
172 """ |
178 """ |
173 for module in ( |
179 for module in list(self.__onDemandInactiveModules.values()) + list( |
174 list(self.__onDemandInactiveModules.values()) + |
180 self.__onDemandActiveModules.values() |
175 list(self.__onDemandActiveModules.values()) |
|
176 ): |
181 ): |
177 if hasattr(module, "moduleSetup"): |
182 if hasattr(module, "moduleSetup"): |
178 module.moduleSetup() |
183 module.moduleSetup() |
179 |
184 |
180 def getPluginDir(self, key): |
185 def getPluginDir(self, key): |
181 """ |
186 """ |
182 Public method to get the path of a plugin directory. |
187 Public method to get the path of a plugin directory. |
183 |
188 |
184 @param key key of the plug-in directory (string) |
189 @param key key of the plug-in directory (string) |
185 @return path of the requested plugin directory (string) |
190 @return path of the requested plugin directory (string) |
186 """ |
191 """ |
187 if key not in ["global", "user"]: |
192 if key not in ["global", "user"]: |
188 return None |
193 return None |
189 else: |
194 else: |
190 try: |
195 try: |
191 return self.pluginDirs[key] |
196 return self.pluginDirs[key] |
192 except KeyError: |
197 except KeyError: |
193 return None |
198 return None |
194 |
199 |
195 def __pluginDirectoriesExist(self): |
200 def __pluginDirectoriesExist(self): |
196 """ |
201 """ |
197 Private method to check, if the plugin folders exist. |
202 Private method to check, if the plugin folders exist. |
198 |
203 |
199 If the plugin folders don't exist, they are created (if possible). |
204 If the plugin folders don't exist, they are created (if possible). |
200 |
205 |
201 @return tuple of a flag indicating existence of any of the plugin |
206 @return tuple of a flag indicating existence of any of the plugin |
202 directories (boolean) and a message (string) |
207 directories (boolean) and a message (string) |
203 """ |
208 """ |
204 if self.__develPluginFile: |
209 if self.__develPluginFile: |
205 path = Utilities.splitPath(self.__develPluginFile)[0] |
210 path = Utilities.splitPath(self.__develPluginFile)[0] |
209 with open(fname, "w"): |
214 with open(fname, "w"): |
210 pass |
215 pass |
211 except OSError: |
216 except OSError: |
212 return ( |
217 return ( |
213 False, |
218 False, |
214 self.tr("Could not create a package for {0}.") |
219 self.tr("Could not create a package for {0}.").format( |
215 .format(self.__develPluginFile)) |
220 self.__develPluginFile |
216 |
221 ), |
|
222 ) |
|
223 |
217 fname = os.path.join(self.pluginDirs["user"], "__init__.py") |
224 fname = os.path.join(self.pluginDirs["user"], "__init__.py") |
218 if not os.path.exists(fname): |
225 if not os.path.exists(fname): |
219 if not os.path.exists(self.pluginDirs["user"]): |
226 if not os.path.exists(self.pluginDirs["user"]): |
220 os.mkdir(self.pluginDirs["user"], 0o755) |
227 os.mkdir(self.pluginDirs["user"], 0o755) |
221 try: |
228 try: |
222 with open(fname, "w"): |
229 with open(fname, "w"): |
223 pass |
230 pass |
224 except OSError: |
231 except OSError: |
225 del self.pluginDirs["user"] |
232 del self.pluginDirs["user"] |
226 |
233 |
227 if not os.path.exists(self.pluginDirs["global"]): |
234 if not os.path.exists(self.pluginDirs["global"]): |
228 try: |
235 try: |
229 # create the global plugins directory |
236 # create the global plugins directory |
230 os.mkdir(self.pluginDirs["global"], 0o755) |
237 os.mkdir(self.pluginDirs["global"], 0o755) |
231 fname = os.path.join(self.pluginDirs["global"], "__init__.py") |
238 fname = os.path.join(self.pluginDirs["global"], "__init__.py") |
232 with open(fname, "w", encoding="utf-8") as f: |
239 with open(fname, "w", encoding="utf-8") as f: |
233 f.write('# -*- coding: utf-8 -*-' + "\n") |
240 f.write("# -*- coding: utf-8 -*-" + "\n") |
234 f.write("\n") |
241 f.write("\n") |
235 f.write('"""' + "\n") |
242 f.write('"""' + "\n") |
236 f.write('Package containing the global plugins.' + "\n") |
243 f.write("Package containing the global plugins." + "\n") |
237 f.write('"""' + "\n") |
244 f.write('"""' + "\n") |
238 except OSError: |
245 except OSError: |
239 del self.pluginDirs["global"] |
246 del self.pluginDirs["global"] |
240 |
247 |
241 if not os.path.exists(self.pluginDirs["eric7"]): |
248 if not os.path.exists(self.pluginDirs["eric7"]): |
242 return ( |
249 return ( |
243 False, |
250 False, |
244 self.tr( |
251 self.tr( |
245 "The internal plugin directory <b>{0}</b>" |
252 "The internal plugin directory <b>{0}</b>" " does not exits." |
246 " does not exits.").format(self.pluginDirs["eric7"])) |
253 ).format(self.pluginDirs["eric7"]), |
247 |
254 ) |
|
255 |
248 return (True, "") |
256 return (True, "") |
249 |
257 |
250 def __pluginModulesExist(self): |
258 def __pluginModulesExist(self): |
251 """ |
259 """ |
252 Private method to check, if there are plugins available. |
260 Private method to check, if there are plugins available. |
253 |
261 |
254 @return flag indicating the availability of plugins (boolean) |
262 @return flag indicating the availability of plugins (boolean) |
255 """ |
263 """ |
256 if ( |
264 if self.__develPluginFile and not os.path.exists(self.__develPluginFile): |
257 self.__develPluginFile and |
|
258 not os.path.exists(self.__develPluginFile) |
|
259 ): |
|
260 return False |
265 return False |
261 |
266 |
262 self.__foundCoreModules = self.getPluginModules( |
267 self.__foundCoreModules = self.getPluginModules(self.pluginDirs["eric7"]) |
263 self.pluginDirs["eric7"]) |
|
264 if Preferences.getPluginManager("ActivateExternal"): |
268 if Preferences.getPluginManager("ActivateExternal"): |
265 if "global" in self.pluginDirs: |
269 if "global" in self.pluginDirs: |
266 self.__foundGlobalModules = self.getPluginModules( |
270 self.__foundGlobalModules = self.getPluginModules( |
267 self.pluginDirs["global"]) |
271 self.pluginDirs["global"] |
|
272 ) |
268 if "user" in self.pluginDirs: |
273 if "user" in self.pluginDirs: |
269 self.__foundUserModules = self.getPluginModules( |
274 self.__foundUserModules = self.getPluginModules(self.pluginDirs["user"]) |
270 self.pluginDirs["user"]) |
275 |
271 |
276 return ( |
272 return len(self.__foundCoreModules + self.__foundGlobalModules + |
277 len( |
273 self.__foundUserModules) > 0 |
278 self.__foundCoreModules |
274 |
279 + self.__foundGlobalModules |
|
280 + self.__foundUserModules |
|
281 ) |
|
282 > 0 |
|
283 ) |
|
284 |
275 def getPluginModules(self, pluginPath): |
285 def getPluginModules(self, pluginPath): |
276 """ |
286 """ |
277 Public method to get a list of plugin modules. |
287 Public method to get a list of plugin modules. |
278 |
288 |
279 @param pluginPath name of the path to search (string) |
289 @param pluginPath name of the path to search (string) |
280 @return list of plugin module names (list of string) |
290 @return list of plugin module names (list of string) |
281 """ |
291 """ |
282 pluginFiles = [f[:-3] for f in os.listdir(pluginPath) |
292 pluginFiles = [ |
283 if self.isValidPluginName(f)] |
293 f[:-3] for f in os.listdir(pluginPath) if self.isValidPluginName(f) |
|
294 ] |
284 return pluginFiles[:] |
295 return pluginFiles[:] |
285 |
296 |
286 def isValidPluginName(self, pluginName): |
297 def isValidPluginName(self, pluginName): |
287 """ |
298 """ |
288 Public method to check, if a file name is a valid plugin name. |
299 Public method to check, if a file name is a valid plugin name. |
289 |
300 |
290 Plugin modules must start with "Plugin" and have the extension ".py". |
301 Plugin modules must start with "Plugin" and have the extension ".py". |
291 |
302 |
292 @param pluginName name of the file to be checked (string) |
303 @param pluginName name of the file to be checked (string) |
293 @return flag indicating a valid plugin name (boolean) |
304 @return flag indicating a valid plugin name (boolean) |
294 """ |
305 """ |
295 return pluginName.startswith("Plugin") and pluginName.endswith(".py") |
306 return pluginName.startswith("Plugin") and pluginName.endswith(".py") |
296 |
307 |
297 def __insertPluginsPaths(self): |
308 def __insertPluginsPaths(self): |
298 """ |
309 """ |
299 Private method to insert the valid plugin paths intos the search path. |
310 Private method to insert the valid plugin paths intos the search path. |
300 """ |
311 """ |
301 for key in self.__priorityOrder: |
312 for key in self.__priorityOrder: |
302 if key in self.pluginDirs: |
313 if key in self.pluginDirs: |
303 if self.pluginDirs[key] not in sys.path: |
314 if self.pluginDirs[key] not in sys.path: |
304 sys.path.insert(2, self.pluginDirs[key]) |
315 sys.path.insert(2, self.pluginDirs[key]) |
305 UI.PixmapCache.addSearchPath(self.pluginDirs[key]) |
316 UI.PixmapCache.addSearchPath(self.pluginDirs[key]) |
306 |
317 |
307 if self.__develPluginFile: |
318 if self.__develPluginFile: |
308 path = Utilities.splitPath(self.__develPluginFile)[0] |
319 path = Utilities.splitPath(self.__develPluginFile)[0] |
309 if path not in sys.path: |
320 if path not in sys.path: |
310 sys.path.insert(2, path) |
321 sys.path.insert(2, path) |
311 UI.PixmapCache.addSearchPath(path) |
322 UI.PixmapCache.addSearchPath(path) |
312 |
323 |
313 def __loadPlugins(self): |
324 def __loadPlugins(self): |
314 """ |
325 """ |
315 Private method to load the plugins found. |
326 Private method to load the plugins found. |
316 """ |
327 """ |
317 develPluginName = "" |
328 develPluginName = "" |
318 if self.__develPluginFile: |
329 if self.__develPluginFile: |
319 develPluginPath, develPluginName = Utilities.splitPath( |
330 develPluginPath, develPluginName = Utilities.splitPath( |
320 self.__develPluginFile) |
331 self.__develPluginFile |
|
332 ) |
321 if self.isValidPluginName(develPluginName): |
333 if self.isValidPluginName(develPluginName): |
322 develPluginName = develPluginName[:-3] |
334 develPluginName = develPluginName[:-3] |
323 |
335 |
324 for pluginName in self.__foundGlobalModules: |
336 for pluginName in self.__foundGlobalModules: |
325 # user and core plug-ins have priority |
337 # user and core plug-ins have priority |
326 if ( |
338 if ( |
327 pluginName not in self.__foundUserModules and |
339 pluginName not in self.__foundUserModules |
328 pluginName not in self.__foundCoreModules and |
340 and pluginName not in self.__foundCoreModules |
329 pluginName != develPluginName |
341 and pluginName != develPluginName |
330 ): |
342 ): |
331 self.loadPlugin(pluginName, self.pluginDirs["global"]) |
343 self.loadPlugin(pluginName, self.pluginDirs["global"]) |
332 |
344 |
333 for pluginName in self.__foundUserModules: |
345 for pluginName in self.__foundUserModules: |
334 # core plug-ins have priority |
346 # core plug-ins have priority |
335 if ( |
347 if ( |
336 pluginName not in self.__foundCoreModules and |
348 pluginName not in self.__foundCoreModules |
337 pluginName != develPluginName |
349 and pluginName != develPluginName |
338 ): |
350 ): |
339 self.loadPlugin(pluginName, self.pluginDirs["user"]) |
351 self.loadPlugin(pluginName, self.pluginDirs["user"]) |
340 |
352 |
341 for pluginName in self.__foundCoreModules: |
353 for pluginName in self.__foundCoreModules: |
342 # plug-in under development has priority |
354 # plug-in under development has priority |
343 if pluginName != develPluginName: |
355 if pluginName != develPluginName: |
344 self.loadPlugin(pluginName, self.pluginDirs["eric7"]) |
356 self.loadPlugin(pluginName, self.pluginDirs["eric7"]) |
345 |
357 |
346 if develPluginName: |
358 if develPluginName: |
347 self.loadPlugin(develPluginName, develPluginPath) |
359 self.loadPlugin(develPluginName, develPluginPath) |
348 self.__develPluginName = develPluginName |
360 self.__develPluginName = develPluginName |
349 |
361 |
350 def loadDocumentationSetPlugins(self): |
362 def loadDocumentationSetPlugins(self): |
351 """ |
363 """ |
352 Public method to load just the documentation sets plugins. |
364 Public method to load just the documentation sets plugins. |
353 |
365 |
354 @exception PluginModulesError raised to indicate the absence of |
366 @exception PluginModulesError raised to indicate the absence of |
355 plug-in modules |
367 plug-in modules |
356 """ |
368 """ |
357 if not self.__pluginModulesExist(): |
369 if not self.__pluginModulesExist(): |
358 raise PluginModulesError |
370 raise PluginModulesError |
359 |
371 |
360 self.__insertPluginsPaths() |
372 self.__insertPluginsPaths() |
361 |
373 |
362 for pluginName in self.__foundGlobalModules: |
374 for pluginName in self.__foundGlobalModules: |
363 # user and core plug-ins have priority |
375 # user and core plug-ins have priority |
364 if ( |
376 if ( |
365 pluginName not in self.__foundUserModules and |
377 pluginName not in self.__foundUserModules |
366 pluginName not in self.__foundCoreModules and |
378 and pluginName not in self.__foundCoreModules |
367 pluginName.startswith("PluginDocumentationSets") |
379 and pluginName.startswith("PluginDocumentationSets") |
368 ): |
380 ): |
369 self.loadPlugin(pluginName, self.pluginDirs["global"]) |
381 self.loadPlugin(pluginName, self.pluginDirs["global"]) |
370 |
382 |
371 for pluginName in self.__foundUserModules: |
383 for pluginName in self.__foundUserModules: |
372 # core plug-ins have priority |
384 # core plug-ins have priority |
373 if ( |
385 if pluginName not in self.__foundCoreModules and pluginName.startswith( |
374 pluginName not in self.__foundCoreModules and |
386 "PluginDocumentationSets" |
375 pluginName.startswith("PluginDocumentationSets") |
|
376 ): |
387 ): |
377 self.loadPlugin(pluginName, self.pluginDirs["user"]) |
388 self.loadPlugin(pluginName, self.pluginDirs["user"]) |
378 |
389 |
379 for pluginName in self.__foundCoreModules: |
390 for pluginName in self.__foundCoreModules: |
380 # plug-in under development has priority |
391 # plug-in under development has priority |
381 if pluginName.startswith("PluginDocumentationSets"): |
392 if pluginName.startswith("PluginDocumentationSets"): |
382 self.loadPlugin(pluginName, self.pluginDirs["eric7"]) |
393 self.loadPlugin(pluginName, self.pluginDirs["eric7"]) |
383 |
394 |
384 def loadPlugin(self, name, directory, reload_=False, install=False): |
395 def loadPlugin(self, name, directory, reload_=False, install=False): |
385 """ |
396 """ |
386 Public method to load a plugin module. |
397 Public method to load a plugin module. |
387 |
398 |
388 Initially all modules are inactive. Modules that are requested on |
399 Initially all modules are inactive. Modules that are requested on |
389 demand are sorted out and are added to the on demand list. Some |
400 demand are sorted out and are added to the on demand list. Some |
390 basic validity checks are performed as well. Modules failing these |
401 basic validity checks are performed as well. Modules failing these |
391 checks are added to the failed modules list. |
402 checks are added to the failed modules list. |
392 |
403 |
393 @param name name of the module to be loaded |
404 @param name name of the module to be loaded |
394 @type str |
405 @type str |
395 @param directory name of the plugin directory |
406 @param directory name of the plugin directory |
396 @type str |
407 @type str |
397 @param reload_ flag indicating to reload the module |
408 @param reload_ flag indicating to reload the module |
429 else: |
440 else: |
430 self.__onDemandInactiveModules[name] = module |
441 self.__onDemandInactiveModules[name] = module |
431 module.eric7PluginModuleName = name |
442 module.eric7PluginModuleName = name |
432 module.eric7PluginModuleFilename = fname |
443 module.eric7PluginModuleFilename = fname |
433 if ( |
444 if ( |
434 (install or |
445 install or Preferences.getPluginManager("AutoInstallDependencies") |
435 Preferences.getPluginManager("AutoInstallDependencies")) and |
446 ) and hasattr(module, "installDependencies"): |
436 hasattr(module, "installDependencies") |
|
437 ): |
|
438 # ask the module to install its dependencies |
447 # ask the module to install its dependencies |
439 module.installDependencies(self.pipInstall) |
448 module.installDependencies(self.pipInstall) |
440 self.__modulesCount += 1 |
449 self.__modulesCount += 1 |
441 if reload_: |
450 if reload_: |
442 importlib.reload(module) |
451 importlib.reload(module) |
443 self.initOnDemandPlugin(name) |
452 self.initOnDemandPlugin(name) |
444 with contextlib.suppress(KeyError, AttributeError): |
453 with contextlib.suppress(KeyError, AttributeError): |
445 pluginObject = self.__onDemandInactivePlugins[name] |
454 pluginObject = self.__onDemandInactivePlugins[name] |
446 pluginObject.initToolbar( |
455 pluginObject.initToolbar( |
447 self.__ui, ericApp().getObject("ToolbarManager")) |
456 self.__ui, ericApp().getObject("ToolbarManager") |
|
457 ) |
448 except PluginLoadError: |
458 except PluginLoadError: |
449 print("Error loading plug-in module:", name) |
459 print("Error loading plug-in module:", name) |
450 except Exception as err: |
460 except Exception as err: |
451 module = types.ModuleType(name) |
461 module = types.ModuleType(name) |
452 module.error = self.tr( |
462 module.error = self.tr("Module failed to load. Error: {0}").format(str(err)) |
453 "Module failed to load. Error: {0}").format(str(err)) |
|
454 self.__failedModules[name] = module |
463 self.__failedModules[name] = module |
455 print("Error loading plug-in module:", name) |
464 print("Error loading plug-in module:", name) |
456 print(str(err)) |
465 print(str(err)) |
457 |
466 |
458 def unloadPlugin(self, name): |
467 def unloadPlugin(self, name): |
459 """ |
468 """ |
460 Public method to unload a plugin module. |
469 Public method to unload a plugin module. |
461 |
470 |
462 @param name name of the module to be unloaded (string) |
471 @param name name of the module to be unloaded (string) |
463 @return flag indicating success (boolean) |
472 @return flag indicating success (boolean) |
464 """ |
473 """ |
465 if name in self.__onDemandActiveModules: |
474 if name in self.__onDemandActiveModules: |
466 # cannot unload an ondemand plugin, that is in use |
475 # cannot unload an ondemand plugin, that is in use |
467 return False |
476 return False |
468 |
477 |
469 if name in self.__activeModules: |
478 if name in self.__activeModules: |
470 self.deactivatePlugin(name) |
479 self.deactivatePlugin(name) |
471 |
480 |
472 if name in self.__inactiveModules: |
481 if name in self.__inactiveModules: |
473 with contextlib.suppress(KeyError): |
482 with contextlib.suppress(KeyError): |
474 pluginObject = self.__inactivePlugins[name] |
483 pluginObject = self.__inactivePlugins[name] |
475 with contextlib.suppress(AttributeError): |
484 with contextlib.suppress(AttributeError): |
476 pluginObject.prepareUnload() |
485 pluginObject.prepareUnload() |
552 pluginObject.eric7PluginName = className |
557 pluginObject.eric7PluginName = className |
553 pluginObject.eric7PluginVersion = version |
558 pluginObject.eric7PluginVersion = version |
554 self.__onDemandInactivePlugins[name] = pluginObject |
559 self.__onDemandInactivePlugins[name] = pluginObject |
555 except PluginActivationError: |
560 except PluginActivationError: |
556 return |
561 return |
557 |
562 |
558 def initPluginToolbars(self, toolbarManager): |
563 def initPluginToolbars(self, toolbarManager): |
559 """ |
564 """ |
560 Public method to initialize plug-in toolbars. |
565 Public method to initialize plug-in toolbars. |
561 |
566 |
562 @param toolbarManager reference to the toolbar manager object |
567 @param toolbarManager reference to the toolbar manager object |
563 (EricToolBarManager) |
568 (EricToolBarManager) |
564 """ |
569 """ |
565 self.initOnDemandPlugins() |
570 self.initOnDemandPlugins() |
566 for pluginObject in self.__onDemandInactivePlugins.values(): |
571 for pluginObject in self.__onDemandInactivePlugins.values(): |
567 with contextlib.suppress(AttributeError): |
572 with contextlib.suppress(AttributeError): |
568 pluginObject.initToolbar(self.__ui, toolbarManager) |
573 pluginObject.initToolbar(self.__ui, toolbarManager) |
569 |
574 |
570 def activatePlugins(self): |
575 def activatePlugins(self): |
571 """ |
576 """ |
572 Public method to activate all plugins having the "autoactivate" |
577 Public method to activate all plugins having the "autoactivate" |
573 attribute set to True. |
578 attribute set to True. |
574 """ |
579 """ |
575 savedInactiveList = Preferences.getSettings().value( |
580 savedInactiveList = Preferences.getSettings().value(self.__inactivePluginsKey) |
576 self.__inactivePluginsKey) |
|
577 inactiveList = self.__disabledPlugins[:] |
581 inactiveList = self.__disabledPlugins[:] |
578 if savedInactiveList is not None: |
582 if savedInactiveList is not None: |
579 inactiveList += [p for p in savedInactiveList |
583 inactiveList += [ |
580 if p not in self.__disabledPlugins] |
584 p for p in savedInactiveList if p not in self.__disabledPlugins |
|
585 ] |
581 if ( |
586 if ( |
582 self.__develPluginName is not None and |
587 self.__develPluginName is not None |
583 self.__develPluginName in inactiveList |
588 and self.__develPluginName in inactiveList |
584 ): |
589 ): |
585 inactiveList.remove(self.__develPluginName) |
590 inactiveList.remove(self.__develPluginName) |
586 names = sorted(self.__inactiveModules.keys()) |
591 names = sorted(self.__inactiveModules.keys()) |
587 for name in names: |
592 for name in names: |
588 if name not in inactiveList: |
593 if name not in inactiveList: |
589 self.activatePlugin(name) |
594 self.activatePlugin(name) |
590 self.allPlugginsActivated.emit() |
595 self.allPlugginsActivated.emit() |
591 |
596 |
592 def activatePlugin(self, name, onDemand=False): |
597 def activatePlugin(self, name, onDemand=False): |
593 """ |
598 """ |
594 Public method to activate a plugin. |
599 Public method to activate a plugin. |
595 |
600 |
596 @param name name of the module to be activated |
601 @param name name of the module to be activated |
597 @param onDemand flag indicating activation of an |
602 @param onDemand flag indicating activation of an |
598 on demand plugin (boolean) |
603 on demand plugin (boolean) |
599 @return reference to the initialized plugin object |
604 @return reference to the initialized plugin object |
600 @exception PluginActivationError raised to indicate an issue during the |
605 @exception PluginActivationError raised to indicate an issue during the |
655 self.__activePlugins[name] = pluginObject |
659 self.__activePlugins[name] = pluginObject |
656 self.__activeModules[name] = module |
660 self.__activeModules[name] = module |
657 return obj |
661 return obj |
658 except PluginActivationError: |
662 except PluginActivationError: |
659 return None |
663 return None |
660 |
664 |
661 def __canActivatePlugin(self, module): |
665 def __canActivatePlugin(self, module): |
662 """ |
666 """ |
663 Private method to check, if a plugin can be activated. |
667 Private method to check, if a plugin can be activated. |
664 |
668 |
665 @param module reference to the module to be activated |
669 @param module reference to the module to be activated |
666 @return flag indicating, if the module satisfies all requirements |
670 @return flag indicating, if the module satisfies all requirements |
667 for being activated (boolean) |
671 for being activated (boolean) |
668 @exception PluginModuleFormatError raised to indicate an invalid |
672 @exception PluginModuleFormatError raised to indicate an invalid |
669 plug-in module format |
673 plug-in module format |
670 @exception PluginClassFormatError raised to indicate an invalid |
674 @exception PluginClassFormatError raised to indicate an invalid |
671 plug-in class format |
675 plug-in class format |
672 """ |
676 """ |
673 try: |
677 try: |
674 if not hasattr(module, "version"): |
678 if not hasattr(module, "version"): |
675 raise PluginModuleFormatError( |
679 raise PluginModuleFormatError(module.eric7PluginModuleName, "version") |
676 module.eric7PluginModuleName, "version") |
|
677 if not hasattr(module, "className"): |
680 if not hasattr(module, "className"): |
678 raise PluginModuleFormatError( |
681 raise PluginModuleFormatError(module.eric7PluginModuleName, "className") |
679 module.eric7PluginModuleName, "className") |
|
680 className = getattr(module, "className", "") |
682 className = getattr(module, "className", "") |
681 if not className or not hasattr(module, className): |
683 if not className or not hasattr(module, className): |
682 raise PluginModuleFormatError( |
684 raise PluginModuleFormatError(module.eric7PluginModuleName, className) |
683 module.eric7PluginModuleName, className) |
|
684 pluginClass = getattr(module, className) |
685 pluginClass = getattr(module, className) |
685 if not hasattr(pluginClass, "__init__"): |
686 if not hasattr(pluginClass, "__init__"): |
686 raise PluginClassFormatError( |
687 raise PluginClassFormatError( |
687 module.eric7PluginModuleName, |
688 module.eric7PluginModuleName, className, "__init__" |
688 className, "__init__") |
689 ) |
689 if not hasattr(pluginClass, "activate"): |
690 if not hasattr(pluginClass, "activate"): |
690 raise PluginClassFormatError( |
691 raise PluginClassFormatError( |
691 module.eric7PluginModuleName, |
692 module.eric7PluginModuleName, className, "activate" |
692 className, "activate") |
693 ) |
693 if not hasattr(pluginClass, "deactivate"): |
694 if not hasattr(pluginClass, "deactivate"): |
694 raise PluginClassFormatError( |
695 raise PluginClassFormatError( |
695 module.eric7PluginModuleName, |
696 module.eric7PluginModuleName, className, "deactivate" |
696 className, "deactivate") |
697 ) |
697 return True |
698 return True |
698 except PluginModuleFormatError as e: |
699 except PluginModuleFormatError as e: |
699 print(repr(e)) |
700 print(repr(e)) |
700 return False |
701 return False |
701 except PluginClassFormatError as e: |
702 except PluginClassFormatError as e: |
702 print(repr(e)) |
703 print(repr(e)) |
703 return False |
704 return False |
704 |
705 |
705 def deactivatePlugin(self, name, onDemand=False): |
706 def deactivatePlugin(self, name, onDemand=False): |
706 """ |
707 """ |
707 Public method to deactivate a plugin. |
708 Public method to deactivate a plugin. |
708 |
709 |
709 @param name name of the module to be deactivated |
710 @param name name of the module to be deactivated |
710 @param onDemand flag indicating deactivation of an |
711 @param onDemand flag indicating deactivation of an |
711 on demand plugin (boolean) |
712 on demand plugin (boolean) |
712 """ |
713 """ |
713 try: |
714 try: |
714 module = ( |
715 module = ( |
715 self.__onDemandActiveModules[name] |
716 self.__onDemandActiveModules[name] |
716 if onDemand else |
717 if onDemand |
717 self.__activeModules[name] |
718 else self.__activeModules[name] |
718 ) |
719 ) |
719 except KeyError: |
720 except KeyError: |
720 return |
721 return |
721 |
722 |
722 if self.__canDeactivatePlugin(module): |
723 if self.__canDeactivatePlugin(module): |
723 pluginObject = None |
724 pluginObject = None |
724 if onDemand and name in self.__onDemandActivePlugins: |
725 if onDemand and name in self.__onDemandActivePlugins: |
725 pluginObject = self.__onDemandActivePlugins[name] |
726 pluginObject = self.__onDemandActivePlugins[name] |
726 elif not onDemand and name in self.__activePlugins: |
727 elif not onDemand and name in self.__activePlugins: |
727 pluginObject = self.__activePlugins[name] |
728 pluginObject = self.__activePlugins[name] |
728 if pluginObject: |
729 if pluginObject: |
729 self.pluginAboutToBeDeactivated.emit(name, pluginObject) |
730 self.pluginAboutToBeDeactivated.emit(name, pluginObject) |
730 pluginObject.deactivate() |
731 pluginObject.deactivate() |
731 self.pluginDeactivated.emit(name, pluginObject) |
732 self.pluginDeactivated.emit(name, pluginObject) |
732 |
733 |
733 if onDemand: |
734 if onDemand: |
734 self.__onDemandActiveModules.pop(name) |
735 self.__onDemandActiveModules.pop(name) |
735 self.__onDemandActivePlugins.pop(name) |
736 self.__onDemandActivePlugins.pop(name) |
736 self.__onDemandInactivePlugins[name] = pluginObject |
737 self.__onDemandInactivePlugins[name] = pluginObject |
737 self.__onDemandInactiveModules[name] = module |
738 self.__onDemandInactiveModules[name] = module |
739 self.__activeModules.pop(name) |
740 self.__activeModules.pop(name) |
740 with contextlib.suppress(KeyError): |
741 with contextlib.suppress(KeyError): |
741 self.__activePlugins.pop(name) |
742 self.__activePlugins.pop(name) |
742 self.__inactivePlugins[name] = pluginObject |
743 self.__inactivePlugins[name] = pluginObject |
743 self.__inactiveModules[name] = module |
744 self.__inactiveModules[name] = module |
744 |
745 |
745 def __canDeactivatePlugin(self, module): |
746 def __canDeactivatePlugin(self, module): |
746 """ |
747 """ |
747 Private method to check, if a plugin can be deactivated. |
748 Private method to check, if a plugin can be deactivated. |
748 |
749 |
749 @param module reference to the module to be deactivated |
750 @param module reference to the module to be deactivated |
750 @return flag indicating, if the module satisfies all requirements |
751 @return flag indicating, if the module satisfies all requirements |
751 for being deactivated (boolean) |
752 for being deactivated (boolean) |
752 """ |
753 """ |
753 return getattr(module, "deactivateable", True) |
754 return getattr(module, "deactivateable", True) |
754 |
755 |
755 def getPluginObject(self, type_, typename, maybeActive=False): |
756 def getPluginObject(self, type_, typename, maybeActive=False): |
756 """ |
757 """ |
757 Public method to activate an ondemand plugin given by type and |
758 Public method to activate an ondemand plugin given by type and |
758 typename. |
759 typename. |
759 |
760 |
760 @param type_ type of the plugin to be activated (string) |
761 @param type_ type of the plugin to be activated (string) |
761 @param typename name of the plugin within the type category (string) |
762 @param typename name of the plugin within the type category (string) |
762 @param maybeActive flag indicating, that the plugin may be active |
763 @param maybeActive flag indicating, that the plugin may be active |
763 already (boolean) |
764 already (boolean) |
764 @return reference to the initialized plugin object |
765 @return reference to the initialized plugin object |
765 """ |
766 """ |
766 for name, module in list(self.__onDemandInactiveModules.items()): |
767 for name, module in list(self.__onDemandInactiveModules.items()): |
767 if ( |
768 if ( |
768 getattr(module, "pluginType", "") == type_ and |
769 getattr(module, "pluginType", "") == type_ |
769 getattr(module, "pluginTypename", "") == typename |
770 and getattr(module, "pluginTypename", "") == typename |
770 ): |
771 ): |
771 return self.activatePlugin(name, onDemand=True) |
772 return self.activatePlugin(name, onDemand=True) |
772 |
773 |
773 if maybeActive: |
774 if maybeActive: |
774 for name, module in list(self.__onDemandActiveModules.items()): |
775 for name, module in list(self.__onDemandActiveModules.items()): |
775 if ( |
776 if ( |
776 getattr(module, "pluginType", "") == type_ and |
777 getattr(module, "pluginType", "") == type_ |
777 getattr(module, "pluginTypename", "") == typename |
778 and getattr(module, "pluginTypename", "") == typename |
778 ): |
779 ): |
779 self.deactivatePlugin(name, onDemand=True) |
780 self.deactivatePlugin(name, onDemand=True) |
780 return self.activatePlugin(name, onDemand=True) |
781 return self.activatePlugin(name, onDemand=True) |
781 |
782 |
782 return None |
783 return None |
783 |
784 |
784 def getPluginInfos(self): |
785 def getPluginInfos(self): |
785 """ |
786 """ |
786 Public method to get infos about all loaded plug-ins. |
787 Public method to get infos about all loaded plug-ins. |
787 |
788 |
788 @return list of dictionaries with keys "module_name", "plugin_name", |
789 @return list of dictionaries with keys "module_name", "plugin_name", |
789 "version", "auto_activate", "active", "short_desc", "error" |
790 "version", "auto_activate", "active", "short_desc", "error" |
790 @rtype list of dict ("module_name": str, "plugin_name": str, |
791 @rtype list of dict ("module_name": str, "plugin_name": str, |
791 "version": str, "auto_activate": bool, "active": bool, |
792 "version": str, "auto_activate": bool, "active": bool, |
792 "short_desc": str, "error": bool) |
793 "short_desc": str, "error": bool) |
793 """ |
794 """ |
794 infos = [] |
795 infos = [] |
795 |
796 |
796 # 1. active, non-on-demand modules |
797 # 1. active, non-on-demand modules |
797 for name in list(self.__activeModules.keys()): |
798 for name in list(self.__activeModules.keys()): |
798 info = self.__getShortInfo(self.__activeModules[name]) |
799 info = self.__getShortInfo(self.__activeModules[name]) |
799 info.update({ |
800 info.update( |
800 "module_name": name, |
801 { |
801 "auto_activate": True, |
802 "module_name": name, |
802 "active": True, |
803 "auto_activate": True, |
803 }) |
804 "active": True, |
|
805 } |
|
806 ) |
804 infos.append(info) |
807 infos.append(info) |
805 |
808 |
806 # 2. inactive, non-on-demand modules |
809 # 2. inactive, non-on-demand modules |
807 for name in list(self.__inactiveModules.keys()): |
810 for name in list(self.__inactiveModules.keys()): |
808 info = self.__getShortInfo(self.__inactiveModules[name]) |
811 info = self.__getShortInfo(self.__inactiveModules[name]) |
809 info.update({ |
812 info.update( |
810 "module_name": name, |
813 { |
811 "auto_activate": True, |
814 "module_name": name, |
812 "active": False, |
815 "auto_activate": True, |
813 }) |
816 "active": False, |
|
817 } |
|
818 ) |
814 infos.append(info) |
819 infos.append(info) |
815 |
820 |
816 # 3. active, on-demand modules |
821 # 3. active, on-demand modules |
817 for name in list(self.__onDemandActiveModules.keys()): |
822 for name in list(self.__onDemandActiveModules.keys()): |
818 info = self.__getShortInfo(self.__onDemandActiveModules[name]) |
823 info = self.__getShortInfo(self.__onDemandActiveModules[name]) |
819 info.update({ |
824 info.update( |
820 "module_name": name, |
825 { |
821 "auto_activate": False, |
826 "module_name": name, |
822 "active": True, |
827 "auto_activate": False, |
823 }) |
828 "active": True, |
|
829 } |
|
830 ) |
824 infos.append(info) |
831 infos.append(info) |
825 |
832 |
826 # 4. inactive, non-on-demand modules |
833 # 4. inactive, non-on-demand modules |
827 for name in list(self.__onDemandInactiveModules.keys()): |
834 for name in list(self.__onDemandInactiveModules.keys()): |
828 info = self.__getShortInfo(self.__onDemandInactiveModules[name]) |
835 info = self.__getShortInfo(self.__onDemandInactiveModules[name]) |
829 info.update({ |
836 info.update( |
830 "module_name": name, |
837 { |
831 "auto_activate": False, |
838 "module_name": name, |
832 "active": False, |
839 "auto_activate": False, |
833 }) |
840 "active": False, |
|
841 } |
|
842 ) |
834 infos.append(info) |
843 infos.append(info) |
835 |
844 |
836 # 5. failed modules |
845 # 5. failed modules |
837 for name in list(self.__failedModules.keys()): |
846 for name in list(self.__failedModules.keys()): |
838 info = self.__getShortInfo(self.__failedModules[name]) |
847 info = self.__getShortInfo(self.__failedModules[name]) |
839 info.update({ |
848 info.update( |
840 "module_name": name, |
849 { |
841 "auto_activate": False, |
850 "module_name": name, |
842 "active": False, |
851 "auto_activate": False, |
843 }) |
852 "active": False, |
|
853 } |
|
854 ) |
844 infos.append(info) |
855 infos.append(info) |
845 |
856 |
846 return infos |
857 return infos |
847 |
858 |
848 def __getShortInfo(self, module): |
859 def __getShortInfo(self, module): |
849 """ |
860 """ |
850 Private method to extract the short info from a module. |
861 Private method to extract the short info from a module. |
851 |
862 |
852 @param module module to extract short info from |
863 @param module module to extract short info from |
853 @return dictionay containing plug-in data |
864 @return dictionay containing plug-in data |
854 @rtype dict ("plugin_name": str, "version": str, "short_desc": str, |
865 @rtype dict ("plugin_name": str, "version": str, "short_desc": str, |
855 "error": bool) |
866 "error": bool) |
856 """ |
867 """ |
893 # try stripping of a postfix |
904 # try stripping of a postfix |
894 return self.getPluginDetails(name.rsplit("_", 1)[0]) |
905 return self.getPluginDetails(name.rsplit("_", 1)[0]) |
895 else: |
906 else: |
896 # should not happen |
907 # should not happen |
897 return None |
908 return None |
898 |
909 |
899 details["moduleName"] = name |
910 details["moduleName"] = name |
900 details["moduleFileName"] = getattr( |
911 details["moduleFileName"] = getattr(module, "eric7PluginModuleFilename", "") |
901 module, "eric7PluginModuleFilename", "") |
|
902 details["pluginName"] = getattr(module, "name", "") |
912 details["pluginName"] = getattr(module, "name", "") |
903 details["version"] = getattr(module, "version", "") |
913 details["version"] = getattr(module, "version", "") |
904 details["author"] = getattr(module, "author", "") |
914 details["author"] = getattr(module, "author", "") |
905 details["description"] = getattr(module, "longDescription", "") |
915 details["description"] = getattr(module, "longDescription", "") |
906 details["autoactivate"] = autoactivate |
916 details["autoactivate"] = autoactivate |
907 details["active"] = active |
917 details["active"] = active |
908 details["error"] = getattr(module, "error", "") |
918 details["error"] = getattr(module, "error", "") |
909 |
919 |
910 return details |
920 return details |
911 |
921 |
912 def doShutdown(self): |
922 def doShutdown(self): |
913 """ |
923 """ |
914 Public method called to perform actions upon shutdown of the IDE. |
924 Public method called to perform actions upon shutdown of the IDE. |
915 """ |
925 """ |
916 names = [] |
926 names = [] |
917 for name in list(self.__inactiveModules.keys()): |
927 for name in list(self.__inactiveModules.keys()): |
918 names.append(name) |
928 names.append(name) |
919 Preferences.getSettings().setValue(self.__inactivePluginsKey, names) |
929 Preferences.getSettings().setValue(self.__inactivePluginsKey, names) |
920 |
930 |
921 self.shutdown.emit() |
931 self.shutdown.emit() |
922 |
932 |
923 def getPluginDisplayStrings(self, type_): |
933 def getPluginDisplayStrings(self, type_): |
924 """ |
934 """ |
925 Public method to get the display strings of all plugins of a specific |
935 Public method to get the display strings of all plugins of a specific |
926 type. |
936 type. |
927 |
937 |
928 @param type_ type of the plugins (string) |
938 @param type_ type of the plugins (string) |
929 @return dictionary with name as key and display string as value |
939 @return dictionary with name as key and display string as value |
930 (dictionary of string) |
940 (dictionary of string) |
931 """ |
941 """ |
932 pluginDict = {} |
942 pluginDict = {} |
933 |
943 |
934 for module in ( |
944 for module in list(self.__onDemandActiveModules.values()) + list( |
935 list(self.__onDemandActiveModules.values()) + |
945 self.__onDemandInactiveModules.values() |
936 list(self.__onDemandInactiveModules.values()) |
|
937 ): |
946 ): |
938 if ( |
947 if ( |
939 getattr(module, "pluginType", "") == type_ and |
948 getattr(module, "pluginType", "") == type_ |
940 getattr(module, "error", "") == "" |
949 and getattr(module, "error", "") == "" |
941 ): |
950 ): |
942 plugin_name = getattr(module, "pluginTypename", "") |
951 plugin_name = getattr(module, "pluginTypename", "") |
943 if plugin_name: |
952 if plugin_name: |
944 if hasattr(module, "displayString"): |
953 if hasattr(module, "displayString"): |
945 try: |
954 try: |
948 disp = getattr(module, "displayString", "") |
957 disp = getattr(module, "displayString", "") |
949 if disp != "": |
958 if disp != "": |
950 pluginDict[plugin_name] = disp |
959 pluginDict[plugin_name] = disp |
951 else: |
960 else: |
952 pluginDict[plugin_name] = plugin_name |
961 pluginDict[plugin_name] = plugin_name |
953 |
962 |
954 return pluginDict |
963 return pluginDict |
955 |
964 |
956 def getPluginPreviewPixmap(self, type_, name): |
965 def getPluginPreviewPixmap(self, type_, name): |
957 """ |
966 """ |
958 Public method to get a preview pixmap of a plugin of a specific type. |
967 Public method to get a preview pixmap of a plugin of a specific type. |
959 |
968 |
960 @param type_ type of the plugin (string) |
969 @param type_ type of the plugin (string) |
961 @param name name of the plugin type (string) |
970 @param name name of the plugin type (string) |
962 @return preview pixmap (QPixmap) |
971 @return preview pixmap (QPixmap) |
963 """ |
972 """ |
964 for module in ( |
973 for module in list(self.__onDemandActiveModules.values()) + list( |
965 list(self.__onDemandActiveModules.values()) + |
974 self.__onDemandInactiveModules.values() |
966 list(self.__onDemandInactiveModules.values()) |
|
967 ): |
975 ): |
968 if ( |
976 if ( |
969 getattr(module, "pluginType", "") == type_ and |
977 getattr(module, "pluginType", "") == type_ |
970 getattr(module, "pluginTypename", "") == name |
978 and getattr(module, "pluginTypename", "") == name |
971 ): |
979 ): |
972 if hasattr(module, "previewPix"): |
980 if hasattr(module, "previewPix"): |
973 return module.previewPix() |
981 return module.previewPix() |
974 else: |
982 else: |
975 return QPixmap() |
983 return QPixmap() |
976 |
984 |
977 return QPixmap() |
985 return QPixmap() |
978 |
986 |
979 def getPluginApiFiles(self, language): |
987 def getPluginApiFiles(self, language): |
980 """ |
988 """ |
981 Public method to get the list of API files installed by a plugin. |
989 Public method to get the list of API files installed by a plugin. |
982 |
990 |
983 @param language language of the requested API files (string) |
991 @param language language of the requested API files (string) |
984 @return list of API filenames (list of string) |
992 @return list of API filenames (list of string) |
985 """ |
993 """ |
986 apis = [] |
994 apis = [] |
987 |
995 |
988 for module in ( |
996 for module in list(self.__activeModules.values()) + list( |
989 list(self.__activeModules.values()) + |
997 self.__onDemandActiveModules.values() |
990 list(self.__onDemandActiveModules.values()) |
|
991 ): |
998 ): |
992 if hasattr(module, "apiFiles"): |
999 if hasattr(module, "apiFiles"): |
993 apis.extend(module.apiFiles(language)) |
1000 apis.extend(module.apiFiles(language)) |
994 |
1001 |
995 return apis |
1002 return apis |
996 |
1003 |
997 def getPluginQtHelpFiles(self): |
1004 def getPluginQtHelpFiles(self): |
998 """ |
1005 """ |
999 Public method to get the list of QtHelp documentation files provided |
1006 Public method to get the list of QtHelp documentation files provided |
1000 by a plug-in. |
1007 by a plug-in. |
1001 |
1008 |
1002 @return dictionary with documentation type as key and list of files |
1009 @return dictionary with documentation type as key and list of files |
1003 as value |
1010 as value |
1004 @rtype dict (key: str, value: list of str) |
1011 @rtype dict (key: str, value: list of str) |
1005 """ |
1012 """ |
1006 helpFiles = {} |
1013 helpFiles = {} |
1007 for module in ( |
1014 for module in list(self.__activeModules.values()) + list( |
1008 list(self.__activeModules.values()) + |
1015 self.__onDemandActiveModules.values() |
1009 list(self.__onDemandActiveModules.values()) |
|
1010 ): |
1016 ): |
1011 if hasattr(module, "helpFiles"): |
1017 if hasattr(module, "helpFiles"): |
1012 helpFiles.update(module.helpFiles()) |
1018 helpFiles.update(module.helpFiles()) |
1013 |
1019 |
1014 return helpFiles |
1020 return helpFiles |
1015 |
1021 |
1016 def getPluginExeDisplayData(self): |
1022 def getPluginExeDisplayData(self): |
1017 """ |
1023 """ |
1018 Public method to get data to display information about a plugins |
1024 Public method to get data to display information about a plugins |
1019 external tool. |
1025 external tool. |
1020 |
1026 |
1021 @return list of dictionaries containing the data. Each dictionary must |
1027 @return list of dictionaries containing the data. Each dictionary must |
1022 either contain data for the determination or the data to be |
1028 either contain data for the determination or the data to be |
1023 displayed.<br /> |
1029 displayed.<br /> |
1024 A dictionary of the first form must have the following entries: |
1030 A dictionary of the first form must have the following entries: |
1025 <ul> |
1031 <ul> |
1095 toplevel entry.</dd> |
1099 toplevel entry.</dd> |
1096 <dt>reference to configuration page</dt> |
1100 <dt>reference to configuration page</dt> |
1097 <dd>This will be used by the configuration dialog and must always |
1101 <dd>This will be used by the configuration dialog and must always |
1098 be None</dd> |
1102 be None</dd> |
1099 </dl> |
1103 </dl> |
1100 |
1104 |
1101 @return plug-in configuration data |
1105 @return plug-in configuration data |
1102 """ |
1106 """ |
1103 configData = {} |
1107 configData = {} |
1104 for module in ( |
1108 for module in ( |
1105 list(self.__activeModules.values()) + |
1109 list(self.__activeModules.values()) |
1106 list(self.__onDemandActiveModules.values()) + |
1110 + list(self.__onDemandActiveModules.values()) |
1107 list(self.__onDemandInactiveModules.values()) |
1111 + list(self.__onDemandInactiveModules.values()) |
1108 ): |
1112 ): |
1109 if hasattr(module, 'getConfigData'): |
1113 if hasattr(module, "getConfigData"): |
1110 configData.update(module.getConfigData()) |
1114 configData.update(module.getConfigData()) |
1111 return configData |
1115 return configData |
1112 |
1116 |
1113 def isPluginLoaded(self, pluginName): |
1117 def isPluginLoaded(self, pluginName): |
1114 """ |
1118 """ |
1115 Public method to check, if a certain plugin is loaded. |
1119 Public method to check, if a certain plugin is loaded. |
1116 |
1120 |
1117 @param pluginName name of the plugin to check for (string) |
1121 @param pluginName name of the plugin to check for (string) |
1118 @return flag indicating, if the plugin is loaded (boolean) |
1122 @return flag indicating, if the plugin is loaded (boolean) |
1119 """ |
1123 """ |
1120 return ( |
1124 return ( |
1121 pluginName in self.__activeModules or |
1125 pluginName in self.__activeModules |
1122 pluginName in self.__inactiveModules or |
1126 or pluginName in self.__inactiveModules |
1123 pluginName in self.__onDemandActiveModules or |
1127 or pluginName in self.__onDemandActiveModules |
1124 pluginName in self.__onDemandInactiveModules |
1128 or pluginName in self.__onDemandInactiveModules |
1125 ) |
1129 ) |
1126 |
1130 |
1127 def isPluginActive(self, pluginName): |
1131 def isPluginActive(self, pluginName): |
1128 """ |
1132 """ |
1129 Public method to check, if a certain plugin is active. |
1133 Public method to check, if a certain plugin is active. |
1130 |
1134 |
1131 @param pluginName name of the plugin to check for (string) |
1135 @param pluginName name of the plugin to check for (string) |
1132 @return flag indicating, if the plugin is active (boolean) |
1136 @return flag indicating, if the plugin is active (boolean) |
1133 """ |
1137 """ |
1134 return ( |
1138 return ( |
1135 pluginName in self.__activeModules or |
1139 pluginName in self.__activeModules |
1136 pluginName in self.__onDemandActiveModules |
1140 or pluginName in self.__onDemandActiveModules |
1137 ) |
1141 ) |
1138 |
1142 |
1139 ########################################################################### |
1143 ########################################################################### |
1140 ## Specialized plug-in module handling methods below |
1144 ## Specialized plug-in module handling methods below |
1141 ########################################################################### |
1145 ########################################################################### |
1142 |
1146 |
1143 ########################################################################### |
1147 ########################################################################### |
1144 ## VCS related methods below |
1148 ## VCS related methods below |
1145 ########################################################################### |
1149 ########################################################################### |
1146 |
1150 |
1147 def getVcsSystemIndicators(self): |
1151 def getVcsSystemIndicators(self): |
1148 """ |
1152 """ |
1149 Public method to get the Vcs System indicators. |
1153 Public method to get the Vcs System indicators. |
1150 |
1154 |
1151 Plugins supporting this functionality must support the module function |
1155 Plugins supporting this functionality must support the module function |
1152 getVcsSystemIndicator returning a dictionary with indicator as key and |
1156 getVcsSystemIndicator returning a dictionary with indicator as key and |
1153 a tuple with the vcs name (string) and vcs display string (string). |
1157 a tuple with the vcs name (string) and vcs display string (string). |
1154 |
1158 |
1155 @return dictionary with indicator as key and a list of tuples as |
1159 @return dictionary with indicator as key and a list of tuples as |
1156 values. Each tuple contains the vcs name (string) and vcs display |
1160 values. Each tuple contains the vcs name (string) and vcs display |
1157 string (string). |
1161 string (string). |
1158 """ |
1162 """ |
1159 vcsDict = {} |
1163 vcsDict = {} |
1160 |
1164 |
1161 for module in ( |
1165 for module in list(self.__onDemandActiveModules.values()) + list( |
1162 list(self.__onDemandActiveModules.values()) + |
1166 self.__onDemandInactiveModules.values() |
1163 list(self.__onDemandInactiveModules.values()) |
|
1164 ): |
1167 ): |
1165 if ( |
1168 if getattr(module, "pluginType", "") == "version_control" and hasattr( |
1166 getattr(module, "pluginType", "") == "version_control" and |
1169 module, "getVcsSystemIndicator" |
1167 hasattr(module, "getVcsSystemIndicator") |
|
1168 ): |
1170 ): |
1169 res = module.getVcsSystemIndicator() |
1171 res = module.getVcsSystemIndicator() |
1170 for indicator, vcsData in list(res.items()): |
1172 for indicator, vcsData in list(res.items()): |
1171 if indicator in vcsDict: |
1173 if indicator in vcsDict: |
1172 vcsDict[indicator].append(vcsData) |
1174 vcsDict[indicator].append(vcsData) |
1173 else: |
1175 else: |
1174 vcsDict[indicator] = [vcsData] |
1176 vcsDict[indicator] = [vcsData] |
1175 |
1177 |
1176 return vcsDict |
1178 return vcsDict |
1177 |
1179 |
1178 def deactivateVcsPlugins(self): |
1180 def deactivateVcsPlugins(self): |
1179 """ |
1181 """ |
1180 Public method to deactivated all activated VCS plugins. |
1182 Public method to deactivated all activated VCS plugins. |
1181 """ |
1183 """ |
1182 for name, module in list(self.__onDemandActiveModules.items()): |
1184 for name, module in list(self.__onDemandActiveModules.items()): |
1183 if getattr(module, "pluginType", "") == "version_control": |
1185 if getattr(module, "pluginType", "") == "version_control": |
1184 self.deactivatePlugin(name, True) |
1186 self.deactivatePlugin(name, True) |
1185 |
1187 |
1186 ######################################################################## |
1188 ######################################################################## |
1187 ## Methods for the creation of the plug-ins download directory |
1189 ## Methods for the creation of the plug-ins download directory |
1188 ######################################################################## |
1190 ######################################################################## |
1189 |
1191 |
1190 def __checkPluginsDownloadDirectory(self): |
1192 def __checkPluginsDownloadDirectory(self): |
1191 """ |
1193 """ |
1192 Private slot to check for the existence of the plugins download |
1194 Private slot to check for the existence of the plugins download |
1193 directory. |
1195 directory. |
1194 """ |
1196 """ |
1195 downloadDir = Preferences.getPluginManager("DownloadPath") |
1197 downloadDir = Preferences.getPluginManager("DownloadPath") |
1196 if not downloadDir: |
1198 if not downloadDir: |
1197 downloadDir = self.__defaultDownloadDir |
1199 downloadDir = self.__defaultDownloadDir |
1198 |
1200 |
1199 if not os.path.exists(downloadDir): |
1201 if not os.path.exists(downloadDir): |
1200 try: |
1202 try: |
1201 os.mkdir(downloadDir, 0o755) |
1203 os.mkdir(downloadDir, 0o755) |
1202 except OSError: |
1204 except OSError: |
1203 # try again with (possibly) new default |
1205 # try again with (possibly) new default |
1211 self.tr("Plugin Manager Error"), |
1213 self.tr("Plugin Manager Error"), |
1212 self.tr( |
1214 self.tr( |
1213 """<p>The plugin download directory""" |
1215 """<p>The plugin download directory""" |
1214 """ <b>{0}</b> could not be created. Please""" |
1216 """ <b>{0}</b> could not be created. Please""" |
1215 """ configure it via the configuration""" |
1217 """ configure it via the configuration""" |
1216 """ dialog.</p><p>Reason: {1}</p>""") |
1218 """ dialog.</p><p>Reason: {1}</p>""" |
1217 .format(downloadDir, str(err))) |
1219 ).format(downloadDir, str(err)), |
|
1220 ) |
1218 downloadDir = "" |
1221 downloadDir = "" |
1219 |
1222 |
1220 Preferences.setPluginManager("DownloadPath", downloadDir) |
1223 Preferences.setPluginManager("DownloadPath", downloadDir) |
1221 |
1224 |
1222 def preferencesChanged(self): |
1225 def preferencesChanged(self): |
1223 """ |
1226 """ |
1224 Public slot to react to changes in configuration. |
1227 Public slot to react to changes in configuration. |
1225 """ |
1228 """ |
1226 self.__checkPluginsDownloadDirectory() |
1229 self.__checkPluginsDownloadDirectory() |
1227 |
1230 |
1228 ######################################################################## |
1231 ######################################################################## |
1229 ## Methods for automatic plug-in update check below |
1232 ## Methods for automatic plug-in update check below |
1230 ######################################################################## |
1233 ######################################################################## |
1231 |
1234 |
1232 def checkPluginUpdatesAvailable(self): |
1235 def checkPluginUpdatesAvailable(self): |
1233 """ |
1236 """ |
1234 Public method to check the availability of updates of plug-ins. |
1237 Public method to check the availability of updates of plug-ins. |
1235 """ |
1238 """ |
1236 period = Preferences.getPluginManager("UpdatesCheckInterval") |
1239 period = Preferences.getPluginManager("UpdatesCheckInterval") |
1237 # 0 = off |
1240 # 0 = off |
1238 # 1 = daily |
1241 # 1 = daily |
1239 # 2 = weekly |
1242 # 2 = weekly |
1240 # 3 = monthly |
1243 # 3 = monthly |
1241 # 4 = always |
1244 # 4 = always |
1242 |
1245 |
1243 if ( |
1246 if period == 0 or (self.__ui is not None and not self.__ui.isOnline()): |
1244 period == 0 or |
|
1245 (self.__ui is not None and not self.__ui.isOnline()) |
|
1246 ): |
|
1247 return |
1247 return |
1248 |
1248 |
1249 elif period in [1, 2, 3] and pathlib.Path(self.pluginRepositoryFile).exists(): |
1249 elif period in [1, 2, 3] and pathlib.Path(self.pluginRepositoryFile).exists(): |
1250 lastModified = datetime.datetime.fromtimestamp( |
1250 lastModified = datetime.datetime.fromtimestamp( |
1251 pathlib.Path(self.pluginRepositoryFile).stat().st_mtime |
1251 pathlib.Path(self.pluginRepositoryFile).stat().st_mtime |
1252 ) |
1252 ) |
1253 now = datetime.datetime.now() |
1253 now = datetime.datetime.now() |
1254 delta = now - lastModified |
1254 delta = now - lastModified |
1255 if ( |
1255 if ( |
1256 (period == 1 and lastModified.date().day == now.date().day) or |
1256 (period == 1 and lastModified.date().day == now.date().day) |
1257 (period == 2 and delta.days < 7) or |
1257 or (period == 2 and delta.days < 7) |
1258 (period == 3 and delta.days < 30) |
1258 or (period == 3 and delta.days < 30) |
1259 ): |
1259 ): |
1260 # daily, weekly, monthly |
1260 # daily, weekly, monthly |
1261 return |
1261 return |
1262 |
1262 |
1263 self.downLoadRepositoryFile() |
1263 self.downLoadRepositoryFile() |
1264 |
1264 |
1265 def downLoadRepositoryFile(self, url=None): |
1265 def downLoadRepositoryFile(self, url=None): |
1266 """ |
1266 """ |
1267 Public method to download the plugin repository file. |
1267 Public method to download the plugin repository file. |
1268 |
1268 |
1269 @param url URL to get the plugin repository file from |
1269 @param url URL to get the plugin repository file from |
1270 (defaults to None) |
1270 (defaults to None) |
1271 @type QUrl or str (optional) |
1271 @type QUrl or str (optional) |
1272 """ |
1272 """ |
1273 self.__updateAvailable = False |
1273 self.__updateAvailable = False |
1274 |
1274 |
1275 if url is None: |
1275 if url is None: |
1276 url = Preferences.getUI("PluginRepositoryUrl7") |
1276 url = Preferences.getUI("PluginRepositoryUrl7") |
1277 request = QNetworkRequest(QUrl(url)) |
1277 request = QNetworkRequest(QUrl(url)) |
1278 request.setAttribute( |
1278 request.setAttribute( |
1279 QNetworkRequest.Attribute.CacheLoadControlAttribute, |
1279 QNetworkRequest.Attribute.CacheLoadControlAttribute, |
1280 QNetworkRequest.CacheLoadControl.AlwaysNetwork) |
1280 QNetworkRequest.CacheLoadControl.AlwaysNetwork, |
|
1281 ) |
1281 reply = self.__networkManager.get(request) |
1282 reply = self.__networkManager.get(request) |
1282 reply.finished.connect( |
1283 reply.finished.connect(lambda: self.__downloadRepositoryFileDone(reply)) |
1283 lambda: self.__downloadRepositoryFileDone(reply)) |
|
1284 self.__replies.append(reply) |
1284 self.__replies.append(reply) |
1285 |
1285 |
1286 def __downloadRepositoryFileDone(self, reply): |
1286 def __downloadRepositoryFileDone(self, reply): |
1287 """ |
1287 """ |
1288 Private method called after the repository file was downloaded. |
1288 Private method called after the repository file was downloaded. |
1289 |
1289 |
1290 @param reply reference to the reply object of the download |
1290 @param reply reference to the reply object of the download |
1291 @type QNetworkReply |
1291 @type QNetworkReply |
1292 """ |
1292 """ |
1293 if reply in self.__replies: |
1293 if reply in self.__replies: |
1294 self.__replies.remove(reply) |
1294 self.__replies.remove(reply) |
1295 |
1295 |
1296 if reply.error() != QNetworkReply.NetworkError.NoError: |
1296 if reply.error() != QNetworkReply.NetworkError.NoError: |
1297 EricMessageBox.warning( |
1297 EricMessageBox.warning( |
1298 None, |
1298 None, |
1299 self.tr("Error downloading file"), |
1299 self.tr("Error downloading file"), |
1300 self.tr( |
1300 self.tr( |
1301 """<p>Could not download the requested file""" |
1301 """<p>Could not download the requested file""" |
1302 """ from {0}.</p><p>Error: {1}</p>""" |
1302 """ from {0}.</p><p>Error: {1}</p>""" |
1303 ).format(Preferences.getUI("PluginRepositoryUrl7"), |
1303 ).format( |
1304 reply.errorString()) |
1304 Preferences.getUI("PluginRepositoryUrl7"), reply.errorString() |
|
1305 ), |
1305 ) |
1306 ) |
1306 reply.deleteLater() |
1307 reply.deleteLater() |
1307 return |
1308 return |
1308 |
1309 |
1309 ioDevice = QFile(self.pluginRepositoryFile + ".tmp") |
1310 ioDevice = QFile(self.pluginRepositoryFile + ".tmp") |
1310 ioDevice.open(QIODevice.OpenModeFlag.WriteOnly) |
1311 ioDevice.open(QIODevice.OpenModeFlag.WriteOnly) |
1311 ioDevice.write(reply.readAll()) |
1312 ioDevice.write(reply.readAll()) |
1312 ioDevice.close() |
1313 ioDevice.close() |
1313 if QFile.exists(self.pluginRepositoryFile): |
1314 if QFile.exists(self.pluginRepositoryFile): |
1314 QFile.remove(self.pluginRepositoryFile) |
1315 QFile.remove(self.pluginRepositoryFile) |
1315 ioDevice.rename(self.pluginRepositoryFile) |
1316 ioDevice.rename(self.pluginRepositoryFile) |
1316 reply.deleteLater() |
1317 reply.deleteLater() |
1317 |
1318 |
1318 if os.path.exists(self.pluginRepositoryFile): |
1319 if os.path.exists(self.pluginRepositoryFile): |
1319 f = QFile(self.pluginRepositoryFile) |
1320 f = QFile(self.pluginRepositoryFile) |
1320 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
1321 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
1321 # save current URL |
1322 # save current URL |
1322 url = Preferences.getUI("PluginRepositoryUrl7") |
1323 url = Preferences.getUI("PluginRepositoryUrl7") |
1323 |
1324 |
1324 # read the repository file |
1325 # read the repository file |
1325 from EricXML.PluginRepositoryReader import ( |
1326 from EricXML.PluginRepositoryReader import PluginRepositoryReader |
1326 PluginRepositoryReader |
1327 |
1327 ) |
|
1328 reader = PluginRepositoryReader(f, self.checkPluginEntry) |
1328 reader = PluginRepositoryReader(f, self.checkPluginEntry) |
1329 reader.readXML() |
1329 reader.readXML() |
1330 if url != Preferences.getUI("PluginRepositoryUrl7"): |
1330 if url != Preferences.getUI("PluginRepositoryUrl7"): |
1331 # redo if it is a redirect |
1331 # redo if it is a redirect |
1332 self.checkPluginUpdatesAvailable() |
1332 self.checkPluginUpdatesAvailable() |
1333 return |
1333 return |
1334 |
1334 |
1335 if self.__updateAvailable: |
1335 if self.__updateAvailable: |
1336 self.__ui and self.__ui.activatePluginRepositoryViewer() |
1336 self.__ui and self.__ui.activatePluginRepositoryViewer() |
1337 else: |
1337 else: |
1338 self.pluginRepositoryFileDownloaded.emit() |
1338 self.pluginRepositoryFileDownloaded.emit() |
1339 |
1339 |
1340 def checkPluginEntry(self, name, short, description, url, author, version, |
1340 def checkPluginEntry( |
1341 filename, status): |
1341 self, name, short, description, url, author, version, filename, status |
|
1342 ): |
1342 """ |
1343 """ |
1343 Public method to check a plug-in's data for an update. |
1344 Public method to check a plug-in's data for an update. |
1344 |
1345 |
1345 @param name data for the name field (string) |
1346 @param name data for the name field (string) |
1346 @param short data for the short field (string) |
1347 @param short data for the short field (string) |
1347 @param description data for the description field (list of strings) |
1348 @param description data for the description field (list of strings) |
1348 @param url data for the url field (string) |
1349 @param url data for the url field (string) |
1349 @param author data for the author field (string) |
1350 @param author data for the author field (string) |
1353 """ |
1354 """ |
1354 # ignore hidden plug-ins |
1355 # ignore hidden plug-ins |
1355 pluginName = os.path.splitext(url.rsplit("/", 1)[1])[0] |
1356 pluginName = os.path.splitext(url.rsplit("/", 1)[1])[0] |
1356 if pluginName in Preferences.getPluginManager("HiddenPlugins"): |
1357 if pluginName in Preferences.getPluginManager("HiddenPlugins"): |
1357 return |
1358 return |
1358 |
1359 |
1359 archive = os.path.join(Preferences.getPluginManager("DownloadPath"), |
1360 archive = os.path.join(Preferences.getPluginManager("DownloadPath"), filename) |
1360 filename) |
1361 |
1361 |
|
1362 # Check against installed/loaded plug-ins |
1362 # Check against installed/loaded plug-ins |
1363 pluginDetails = self.getPluginDetails(pluginName) |
1363 pluginDetails = self.getPluginDetails(pluginName) |
1364 if pluginDetails is None: |
1364 if pluginDetails is None: |
1365 if not Preferences.getPluginManager("CheckInstalledOnly"): |
1365 if not Preferences.getPluginManager("CheckInstalledOnly"): |
1366 self.__updateAvailable = True |
1366 self.__updateAvailable = True |
1367 return |
1367 return |
1368 |
1368 |
1369 versionTuple = Globals.versionToTuple(version)[:3] |
1369 versionTuple = Globals.versionToTuple(version)[:3] |
1370 pluginVersionTuple = Globals.versionToTuple( |
1370 pluginVersionTuple = Globals.versionToTuple(pluginDetails["version"])[:3] |
1371 pluginDetails["version"])[:3] |
1371 |
1372 |
|
1373 if pluginVersionTuple < versionTuple: |
1372 if pluginVersionTuple < versionTuple: |
1374 self.__updateAvailable = True |
1373 self.__updateAvailable = True |
1375 return |
1374 return |
1376 |
1375 |
1377 if not Preferences.getPluginManager("CheckInstalledOnly"): |
1376 if not Preferences.getPluginManager("CheckInstalledOnly"): |
1378 # Check against downloaded plugin archives |
1377 # Check against downloaded plugin archives |
1379 # 1. Check, if the archive file exists |
1378 # 1. Check, if the archive file exists |
1380 if not os.path.exists(archive): |
1379 if not os.path.exists(archive): |
1381 if pluginDetails["moduleName"] != pluginName: |
1380 if pluginDetails["moduleName"] != pluginName: |
1382 self.__updateAvailable = True |
1381 self.__updateAvailable = True |
1383 return |
1382 return |
1384 |
1383 |
1385 # 2. Check, if the archive is a valid zip file |
1384 # 2. Check, if the archive is a valid zip file |
1386 if not zipfile.is_zipfile(archive): |
1385 if not zipfile.is_zipfile(archive): |
1387 self.__updateAvailable = True |
1386 self.__updateAvailable = True |
1388 return |
1387 return |
1389 |
1388 |
1390 # 3. Check the version of the archive file |
1389 # 3. Check the version of the archive file |
1391 zipFile = zipfile.ZipFile(archive, "r") |
1390 zipFile = zipfile.ZipFile(archive, "r") |
1392 try: |
1391 try: |
1393 aversion = zipFile.read("VERSION").decode("utf-8") |
1392 aversion = zipFile.read("VERSION").decode("utf-8") |
1394 except KeyError: |
1393 except KeyError: |
1395 aversion = "0.0.0" |
1394 aversion = "0.0.0" |
1396 zipFile.close() |
1395 zipFile.close() |
1397 |
1396 |
1398 aversionTuple = Globals.versionToTuple(aversion)[:3] |
1397 aversionTuple = Globals.versionToTuple(aversion)[:3] |
1399 if aversionTuple != versionTuple: |
1398 if aversionTuple != versionTuple: |
1400 self.__updateAvailable = True |
1399 self.__updateAvailable = True |
1401 |
1400 |
1402 def __sslErrors(self, reply, errors): |
1401 def __sslErrors(self, reply, errors): |
1403 """ |
1402 """ |
1404 Private slot to handle SSL errors. |
1403 Private slot to handle SSL errors. |
1405 |
1404 |
1406 @param reply reference to the reply object (QNetworkReply) |
1405 @param reply reference to the reply object (QNetworkReply) |
1407 @param errors list of SSL errors (list of QSslError) |
1406 @param errors list of SSL errors (list of QSslError) |
1408 """ |
1407 """ |
1409 ignored = self.__sslErrorHandler.sslErrorsReply(reply, errors)[0] |
1408 ignored = self.__sslErrorHandler.sslErrorsReply(reply, errors)[0] |
1410 if ignored == EricSslErrorState.NOT_IGNORED: |
1409 if ignored == EricSslErrorState.NOT_IGNORED: |
1411 self.__downloadCancelled = True |
1410 self.__downloadCancelled = True |
1412 |
1411 |
1413 ######################################################################## |
1412 ######################################################################## |
1414 ## Methods to clear private data of plug-ins below |
1413 ## Methods to clear private data of plug-ins below |
1415 ######################################################################## |
1414 ######################################################################## |
1416 |
1415 |
1417 def clearPluginsPrivateData(self, type_): |
1416 def clearPluginsPrivateData(self, type_): |
1418 """ |
1417 """ |
1419 Public method to clear the private data of plug-ins of a specified |
1418 Public method to clear the private data of plug-ins of a specified |
1420 type. |
1419 type. |
1421 |
1420 |
1422 Plugins supporting this functionality must support the module function |
1421 Plugins supporting this functionality must support the module function |
1423 clearPrivateData() and have the module level attribute pluginType. |
1422 clearPrivateData() and have the module level attribute pluginType. |
1424 |
1423 |
1425 @param type_ type of the plugin to clear private data for (string) |
1424 @param type_ type of the plugin to clear private data for (string) |
1426 """ |
1425 """ |
1427 for module in ( |
1426 for module in ( |
1428 list(self.__onDemandActiveModules.values()) + |
1427 list(self.__onDemandActiveModules.values()) |
1429 list(self.__onDemandInactiveModules.values()) + |
1428 + list(self.__onDemandInactiveModules.values()) |
1430 list(self.__activeModules.values()) + |
1429 + list(self.__activeModules.values()) |
1431 list(self.__inactiveModules.values()) |
1430 + list(self.__inactiveModules.values()) |
1432 ): |
1431 ): |
1433 if ( |
1432 if getattr(module, "pluginType", "") == type_ and hasattr( |
1434 getattr(module, "pluginType", "") == type_ and |
1433 module, "clearPrivateData" |
1435 hasattr(module, "clearPrivateData") |
|
1436 ): |
1434 ): |
1437 module.clearPrivateData() |
1435 module.clearPrivateData() |
1438 |
1436 |
1439 ######################################################################## |
1437 ######################################################################## |
1440 ## Methods to install a plug-in module dependency via pip |
1438 ## Methods to install a plug-in module dependency via pip |
1441 ######################################################################## |
1439 ######################################################################## |
1442 |
1440 |
1443 def pipInstall(self, packages): |
1441 def pipInstall(self, packages): |
1444 """ |
1442 """ |
1445 Public method to install the given package via pip. |
1443 Public method to install the given package via pip. |
1446 |
1444 |
1447 @param packages list of packages to install |
1445 @param packages list of packages to install |
1448 @type list of str |
1446 @type list of str |
1449 """ |
1447 """ |
1450 try: |
1448 try: |
1451 pip = ericApp().getObject("Pip") |
1449 pip = ericApp().getObject("Pip") |
1452 except KeyError: |
1450 except KeyError: |
1453 # Installation is performed via the plug-in installation script. |
1451 # Installation is performed via the plug-in installation script. |
1454 from PipInterface.Pip import Pip |
1452 from PipInterface.Pip import Pip |
|
1453 |
1455 pip = Pip(self) |
1454 pip = Pip(self) |
1456 pip.installPackages(packages, |
1455 pip.installPackages(packages, interpreter=Globals.getPythonExecutable()) |
1457 interpreter=Globals.getPythonExecutable()) |
1456 |
1458 |
1457 |
1459 # |
1458 # |
1460 # eflag: noqa = M801 |
1459 # eflag: noqa = M801 |