PluginManager/PluginInstallDialog.py

branch
Py2 comp.
changeset 3057
10516539f238
parent 3056
9986ec0e559a
parent 2992
dbdf27746da5
child 3060
5883ce99ee12
equal deleted inserted replaced
3056:9986ec0e559a 3057:10516539f238
19 import urllib.parse as parse 19 import urllib.parse as parse
20 except (ImportError): 20 except (ImportError):
21 import urlparse as parse 21 import urlparse as parse
22 22
23 from PyQt4.QtCore import pyqtSlot, Qt, QDir, QFileInfo 23 from PyQt4.QtCore import pyqtSlot, Qt, QDir, QFileInfo
24 from PyQt4.QtGui import QWidget, QDialogButtonBox, QAbstractButton, QApplication, \ 24 from PyQt4.QtGui import QWidget, QDialogButtonBox, QAbstractButton, \
25 QDialog, QVBoxLayout 25 QApplication, QDialog, QVBoxLayout
26 26
27 from E5Gui import E5FileDialog 27 from E5Gui import E5FileDialog
28 from E5Gui.E5MainWindow import E5MainWindow 28 from E5Gui.E5MainWindow import E5MainWindow
29 29
30 from .Ui_PluginInstallDialog import Ui_PluginInstallDialog 30 from .Ui_PluginInstallDialog import Ui_PluginInstallDialog
58 self.__external = True 58 self.__external = True
59 else: 59 else:
60 self.__pluginManager = pluginManager 60 self.__pluginManager = pluginManager
61 self.__external = False 61 self.__external = False
62 62
63 self.__backButton = \ 63 self.__backButton = self.buttonBox.addButton(
64 self.buttonBox.addButton(self.trUtf8("< Back"), QDialogButtonBox.ActionRole) 64 self.trUtf8("< Back"), QDialogButtonBox.ActionRole)
65 self.__nextButton = \ 65 self.__nextButton = self.buttonBox.addButton(
66 self.buttonBox.addButton(self.trUtf8("Next >"), QDialogButtonBox.ActionRole) 66 self.trUtf8("Next >"), QDialogButtonBox.ActionRole)
67 self.__finishButton = \ 67 self.__finishButton = self.buttonBox.addButton(
68 self.buttonBox.addButton(self.trUtf8("Install"), QDialogButtonBox.ActionRole) 68 self.trUtf8("Install"), QDialogButtonBox.ActionRole)
69 69
70 self.__closeButton = self.buttonBox.button(QDialogButtonBox.Close) 70 self.__closeButton = self.buttonBox.button(QDialogButtonBox.Close)
71 self.__cancelButton = self.buttonBox.button(QDialogButtonBox.Cancel) 71 self.__cancelButton = self.buttonBox.button(QDialogButtonBox.Cancel)
72 72
73 userDir = self.__pluginManager.getPluginDir("user") 73 userDir = self.__pluginManager.getPluginDir("user")
74 if userDir is not None: 74 if userDir is not None:
75 self.destinationCombo.addItem(self.trUtf8("User plugins directory"), 75 self.destinationCombo.addItem(
76 self.trUtf8("User plugins directory"),
76 userDir) 77 userDir)
77 78
78 globalDir = self.__pluginManager.getPluginDir("global") 79 globalDir = self.__pluginManager.getPluginDir("global")
79 if globalDir is not None and os.access(globalDir, os.W_OK): 80 if globalDir is not None and os.access(globalDir, os.W_OK):
80 self.destinationCombo.addItem(self.trUtf8("Global plugins directory"), 81 self.destinationCombo.addItem(
82 self.trUtf8("Global plugins directory"),
81 globalDir) 83 globalDir)
82 84
83 self.__installedDirs = [] 85 self.__installedDirs = []
84 self.__installedFiles = [] 86 self.__installedFiles = []
85 87
87 89
88 downloadDir = QDir(Preferences.getPluginManager("DownloadPath")) 90 downloadDir = QDir(Preferences.getPluginManager("DownloadPath"))
89 for pluginFileName in pluginFileNames: 91 for pluginFileName in pluginFileNames:
90 fi = QFileInfo(pluginFileName) 92 fi = QFileInfo(pluginFileName)
91 if fi.isRelative(): 93 if fi.isRelative():
92 pluginFileName = QFileInfo(downloadDir, fi.fileName()).absoluteFilePath() 94 pluginFileName = QFileInfo(
95 downloadDir, fi.fileName()).absoluteFilePath()
93 self.archivesList.addItem(pluginFileName) 96 self.archivesList.addItem(pluginFileName)
94 self.archivesList.sortItems() 97 self.archivesList.sortItems()
95 98
96 self.__currentIndex = 0 99 self.__currentIndex = 0
97 self.__selectPage() 100 self.__selectPage()
137 self.__nextButton.setEnabled(False) 140 self.__nextButton.setEnabled(False)
138 self.__finishButton.setEnabled(True) 141 self.__finishButton.setEnabled(True)
139 self.__closeButton.hide() 142 self.__closeButton.hide()
140 self.__cancelButton.show() 143 self.__cancelButton.show()
141 144
142 msg = self.trUtf8("Plugin ZIP-Archives:\n{0}\n\nDestination:\n{1} ({2})")\ 145 msg = self.trUtf8(
146 "Plugin ZIP-Archives:\n{0}\n\nDestination:\n{1} ({2})")\
143 .format("\n".join(self.__createArchivesList()), 147 .format("\n".join(self.__createArchivesList()),
144 self.destinationCombo.currentText(), 148 self.destinationCombo.currentText(),
145 self.destinationCombo.itemData( 149 self.destinationCombo.itemData(
146 self.destinationCombo.currentIndex()) 150 self.destinationCombo.currentIndex())
147 ) 151 )
174 @pyqtSlot() 178 @pyqtSlot()
175 def on_archivesList_itemSelectionChanged(self): 179 def on_archivesList_itemSelectionChanged(self):
176 """ 180 """
177 Private slot called, when the selection of the archives list changes. 181 Private slot called, when the selection of the archives list changes.
178 """ 182 """
179 self.removeArchivesButton.setEnabled(len(self.archivesList.selectedItems()) > 0) 183 self.removeArchivesButton.setEnabled(
184 len(self.archivesList.selectedItems()) > 0)
180 185
181 @pyqtSlot() 186 @pyqtSlot()
182 def on_removeArchivesButton_clicked(self): 187 def on_removeArchivesButton_clicked(self):
183 """ 188 """
184 Private slot to remove archives from the list. 189 Private slot to remove archives from the list.
185 """ 190 """
186 for archiveItem in self.archivesList.selectedItems(): 191 for archiveItem in self.archivesList.selectedItems():
187 itm = self.archivesList.takeItem(self.archivesList.row(archiveItem)) 192 itm = self.archivesList.takeItem(
193 self.archivesList.row(archiveItem))
188 del itm 194 del itm
189 195
190 self.__nextButton.setEnabled(self.archivesList.count() > 0) 196 self.__nextButton.setEnabled(self.archivesList.count() > 0)
191 197
192 @pyqtSlot(QAbstractButton) 198 @pyqtSlot(QAbstractButton)
193 def on_buttonBox_clicked(self, button): 199 def on_buttonBox_clicked(self, button):
194 """ 200 """
195 Private slot to handle the click of a button of the button box. 201 Private slot to handle the click of a button of the button box.
202
203 @param button reference to the button pressed (QAbstractButton)
196 """ 204 """
197 if button == self.__backButton: 205 if button == self.__backButton:
198 self.__currentIndex -= 1 206 self.__currentIndex -= 1
199 self.__selectPage() 207 self.__selectPage()
200 elif button == self.__nextButton: 208 elif button == self.__nextButton:
213 @return flag indicating success (boolean) 221 @return flag indicating success (boolean)
214 """ 222 """
215 res = True 223 res = True
216 self.summaryEdit.clear() 224 self.summaryEdit.clear()
217 for archive in self.__createArchivesList(): 225 for archive in self.__createArchivesList():
218 self.summaryEdit.append(self.trUtf8("Installing {0} ...").format(archive)) 226 self.summaryEdit.append(
227 self.trUtf8("Installing {0} ...").format(archive))
219 ok, msg, restart = self.__installPlugin(archive) 228 ok, msg, restart = self.__installPlugin(archive)
220 res = res and ok 229 res = res and ok
221 if ok: 230 if ok:
222 self.summaryEdit.append(self.trUtf8(" ok")) 231 self.summaryEdit.append(self.trUtf8(" ok"))
223 else: 232 else:
245 of the IDE is required (boolean) 254 of the IDE is required (boolean)
246 """ 255 """
247 installedPluginName = "" 256 installedPluginName = ""
248 257
249 archive = archiveFilename 258 archive = archiveFilename
250 destination = \ 259 destination = self.destinationCombo.itemData(
251 self.destinationCombo.itemData(self.destinationCombo.currentIndex()) 260 self.destinationCombo.currentIndex())
252 261
253 # check if archive is a local url 262 # check if archive is a local url
254 url = parse.urlparse(archive) 263 url = parse.urlparse(archive)
255 if url[0].lower() == 'file': 264 if url[0].lower() == 'file':
256 archive = url[2] 265 archive = url[2]
257 266
258 # check, if the archive exists 267 # check, if the archive exists
259 if not os.path.exists(archive): 268 if not os.path.exists(archive):
260 return False, \ 269 return False, \
261 self.trUtf8("""<p>The archive file <b>{0}</b> does not exist. """ 270 self.trUtf8(
262 """Aborting...</p>""").format(archive), \ 271 """<p>The archive file <b>{0}</b> does not exist. """
272 """Aborting...</p>""").format(archive), \
263 False 273 False
264 274
265 # check, if the archive is a valid zip file 275 # check, if the archive is a valid zip file
266 if not zipfile.is_zipfile(archive): 276 if not zipfile.is_zipfile(archive):
267 return False, \ 277 return False, \
268 self.trUtf8("""<p>The file <b>{0}</b> is not a valid plugin """ 278 self.trUtf8(
269 """ZIP-archive. Aborting...</p>""").format(archive), \ 279 """<p>The file <b>{0}</b> is not a valid plugin """
280 """ZIP-archive. Aborting...</p>""").format(archive), \
270 False 281 False
271 282
272 # check, if the destination is writeable 283 # check, if the destination is writeable
273 if not os.access(destination, os.W_OK): 284 if not os.access(destination, os.W_OK):
274 return False, \ 285 return False, \
275 self.trUtf8("""<p>The destination directory <b>{0}</b> is not """ 286 self.trUtf8(
276 """writeable. Aborting...</p>""").format(destination), \ 287 """<p>The destination directory <b>{0}</b> is not """
288 """writeable. Aborting...</p>""").format(destination), \
277 False 289 False
278 290
279 zip = zipfile.ZipFile(archive, "r") 291 zip = zipfile.ZipFile(archive, "r")
280 292
281 # check, if the archive contains a valid plugin 293 # check, if the archive contains a valid plugin
288 pluginFileName = name 300 pluginFileName = name
289 break 301 break
290 302
291 if not pluginFound: 303 if not pluginFound:
292 return False, \ 304 return False, \
293 self.trUtf8("""<p>The file <b>{0}</b> is not a valid plugin """ 305 self.trUtf8(
294 """ZIP-archive. Aborting...</p>""").format(archive), \ 306 """<p>The file <b>{0}</b> is not a valid plugin """
307 """ZIP-archive. Aborting...</p>""").format(archive), \
295 False 308 False
296 309
297 # parse the plugin module's plugin header 310 # parse the plugin module's plugin header
298 pluginSource = Utilities.decode(zip.read(pluginFileName))[0] 311 pluginSource = Utilities.decode(zip.read(pluginFileName))[0]
299 packageName = "" 312 packageName = ""
311 else: 324 else:
312 if tokens[1].strip() == "None": 325 if tokens[1].strip() == "None":
313 packageName = "None" 326 packageName = "None"
314 elif line.startswith("internalPackages"): 327 elif line.startswith("internalPackages"):
315 tokens = line.split("=") 328 tokens = line.split("=")
316 token = tokens[1].strip()[1:-1] # it is a comma separated string 329 token = tokens[1].strip()[1:-1]
330 # it is a comma separated string
317 internalPackages = [p.strip() for p in token.split(",")] 331 internalPackages = [p.strip() for p in token.split(",")]
318 elif line.startswith("needsRestart"): 332 elif line.startswith("needsRestart"):
319 tokens = line.split("=") 333 tokens = line.split("=")
320 needsRestart = tokens[1].strip() == "True" 334 needsRestart = tokens[1].strip() == "True"
321 elif line.startswith("pyqtApi"): 335 elif line.startswith("pyqtApi"):
331 elif line.startswith("# End-Of-Header"): 345 elif line.startswith("# End-Of-Header"):
332 break 346 break
333 347
334 if not packageName: 348 if not packageName:
335 return False, \ 349 return False, \
336 self.trUtf8("""<p>The plugin module <b>{0}</b> does not contain """ 350 self.trUtf8(
337 """a 'packageName' attribute. Aborting...</p>""")\ 351 """<p>The plugin module <b>{0}</b> does not contain """
352 """a 'packageName' attribute. Aborting...</p>""")\
338 .format(pluginFileName), \ 353 .format(pluginFileName), \
339 False 354 False
340 355
341 if pyqtApi < 2: 356 if pyqtApi < 2:
342 return False, \ 357 return False, \
343 self.trUtf8("""<p>The plugin module <b>{0}</b> does not conform""" 358 self.trUtf8(
344 """ with the PyQt v2 API. Aborting...</p>""")\ 359 """<p>The plugin module <b>{0}</b> does not conform"""
360 """ with the PyQt v2 API. Aborting...</p>""")\
345 .format(pluginFileName), \ 361 .format(pluginFileName), \
346 False 362 False
347 363
348 # check, if it is a plugin, that collides with others 364 # check, if it is a plugin, that collides with others
349 if not os.path.exists(os.path.join(destination, pluginFileName)) and \ 365 if not os.path.exists(os.path.join(destination, pluginFileName)) and \
365 False 381 False
366 382
367 activatePlugin = False 383 activatePlugin = False
368 if not self.__external: 384 if not self.__external:
369 activatePlugin = \ 385 activatePlugin = \
370 not self.__pluginManager.isPluginLoaded(installedPluginName) or \ 386 not self.__pluginManager.isPluginLoaded(
387 installedPluginName) or \
371 (self.__pluginManager.isPluginLoaded(installedPluginName) and \ 388 (self.__pluginManager.isPluginLoaded(installedPluginName) and \
372 self.__pluginManager.isPluginActive(installedPluginName)) 389 self.__pluginManager.isPluginActive(installedPluginName))
373 # try to unload a plugin with the same name 390 # try to unload a plugin with the same name
374 self.__pluginManager.unloadPlugin(installedPluginName) 391 self.__pluginManager.unloadPlugin(installedPluginName)
375 392
423 f.close() 440 f.close()
424 self.__installedFiles.append(outname) 441 self.__installedFiles.append(outname)
425 except os.error as why: 442 except os.error as why:
426 self.__rollback() 443 self.__rollback()
427 return False, \ 444 return False, \
428 self.trUtf8("Error installing plugin. Reason: {0}").format(str(why)), \ 445 self.trUtf8(
446 "Error installing plugin. Reason: {0}").format(str(why)), \
429 False 447 False
430 except IOError as why: 448 except IOError as why:
431 self.__rollback() 449 self.__rollback()
432 return False, \ 450 return False, \
433 self.trUtf8("Error installing plugin. Reason: {0}").format(str(why)), \ 451 self.trUtf8(
452 "Error installing plugin. Reason: {0}").format(str(why)), \
434 False 453 False
435 except OSError as why: 454 except OSError as why:
436 self.__rollback() 455 self.__rollback()
437 return False, \ 456 return False, \
438 self.trUtf8("Error installing plugin. Reason: {0}").format(str(why)), \ 457 self.trUtf8(
458 "Error installing plugin. Reason: {0}").format(str(why)), \
439 False 459 False
440 except: 460 except:
441 sys.stderr.write("Unspecific exception installing plugin.\n") 461 sys.stderr.write("Unspecific exception installing plugin.\n")
442 self.__rollback() 462 self.__rollback()
443 return False, \ 463 return False, \
444 self.trUtf8("Unspecific exception installing plugin."), \ 464 self.trUtf8("Unspecific exception installing plugin."), \
445 False 465 False
446 466
447 # now compile the plugins 467 # now compile the plugins
448 if doCompile: 468 if doCompile:
449 compileall.compile_dir(os.path.join(destination, packageName), quiet=True) 469 compileall.compile_dir(
450 compileall.compile_file(os.path.join(destination, pluginFileName), quiet=True) 470 os.path.join(destination, packageName), quiet=True)
471 compileall.compile_file(
472 os.path.join(destination, pluginFileName), quiet=True)
451 473
452 if not self.__external: 474 if not self.__external:
453 # now load and activate the plugin 475 # now load and activate the plugin
454 self.__pluginManager.loadPlugin(installedPluginName, destination, reload_) 476 self.__pluginManager.loadPlugin(installedPluginName, destination,
477 reload_)
455 if activatePlugin: 478 if activatePlugin:
456 self.__pluginManager.activatePlugin(installedPluginName) 479 self.__pluginManager.activatePlugin(installedPluginName)
457 480
458 return True, "", needsRestart 481 return True, "", needsRestart
459 482
481 head, tail = os.path.split(name) 504 head, tail = os.path.split(name)
482 if not tail: 505 if not tail:
483 head, tail = os.path.split(head) 506 head, tail = os.path.split(head)
484 if head and tail and not os.path.exists(head): 507 if head and tail and not os.path.exists(head):
485 self.__makedirs(head, mode) 508 self.__makedirs(head, mode)
486 if tail == os.curdir: # xxx/newdir/. exists if xxx/newdir exists 509 if tail == os.curdir:
510 # xxx/newdir/. exists if xxx/newdir exists
487 return 511 return
488 os.mkdir(name, mode) 512 os.mkdir(name, mode)
489 self.__installedDirs.append(name) 513 self.__installedDirs.append(name)
490 514
491 def __uninstallPackage(self, destination, pluginFileName, packageName): 515 def __uninstallPackage(self, destination, pluginFileName, packageName):
513 537
514 fnamec = "{0}c".format(pluginFile) 538 fnamec = "{0}c".format(pluginFile)
515 if os.path.exists(fnamec): 539 if os.path.exists(fnamec):
516 os.remove(fnamec) 540 os.remove(fnamec)
517 541
518 pluginDirCache = os.path.join(os.path.dirname(pluginFile), "__pycache__") 542 pluginDirCache = os.path.join(
543 os.path.dirname(pluginFile), "__pycache__")
519 if os.path.exists(pluginDirCache): 544 if os.path.exists(pluginDirCache):
520 pluginFileName = os.path.splitext(os.path.basename(pluginFile))[0] 545 pluginFileName = os.path.splitext(
546 os.path.basename(pluginFile))[0]
521 for fnameo in glob.glob( 547 for fnameo in glob.glob(
522 os.path.join(pluginDirCache, "{0}*.pyo".format(pluginFileName))): 548 os.path.join(pluginDirCache,
549 "{0}*.pyo".format(pluginFileName))):
523 os.remove(fnameo) 550 os.remove(fnameo)
524 for fnamec in glob.glob( 551 for fnamec in glob.glob(
525 os.path.join(pluginDirCache, "{0}*.pyc".format(pluginFileName))): 552 os.path.join(pluginDirCache,
553 "{0}*.pyc".format(pluginFileName))):
526 os.remove(fnamec) 554 os.remove(fnamec)
527 555
528 os.remove(pluginFile) 556 os.remove(pluginFile)
529 except (IOError, OSError, os.error): 557 except (IOError, OSError, os.error):
530 # ignore some exceptions 558 # ignore some exceptions
584 self.cw = PluginInstallWidget(None, pluginFileNames, self) 612 self.cw = PluginInstallWidget(None, pluginFileNames, self)
585 size = self.cw.size() 613 size = self.cw.size()
586 self.setCentralWidget(self.cw) 614 self.setCentralWidget(self.cw)
587 self.resize(size) 615 self.resize(size)
588 616
589 self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet")) 617 self.setStyle(Preferences.getUI("Style"),
618 Preferences.getUI("StyleSheet"))
590 619
591 self.cw.buttonBox.accepted[()].connect(self.close) 620 self.cw.buttonBox.accepted[()].connect(self.close)
592 self.cw.buttonBox.rejected[()].connect(self.close) 621 self.cw.buttonBox.rejected[()].connect(self.close)

eric ide

mercurial