diff -r c6363afe8387 -r f7788bc8c08d PluginPyInstaller.py --- a/PluginPyInstaller.py Tue Jan 16 12:04:56 2018 +0100 +++ b/PluginPyInstaller.py Tue Jan 16 14:53:10 2018 +0100 @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2018 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the PyInstaller interface plug-in. +""" + +from __future__ import unicode_literals + +import os +import platform + +from PyQt5.QtCore import QObject, QCoreApplication + +import Utilities + +# Start-Of-Header +name = "PyInstaller Plugin" +author = "Detlev Offenbach <detlev@die-offenbachs.de>" +autoactivate = True +deactivateable = True +version = "0.1.0" +className = "PyInstallerPlugin" +packageName = "PyInstaller" +shortDescription = "Show dialogs to configure and execute PyInstaller." +longDescription = ( + """This plug-in implements dialogs to configure and execute PyInstaller""" + """ for an eric project. PyInstaller must be available or must be""" + """ installed via 'pip install PyInstaller'.""" +) +needsRestart = False +pyqtApi = 2 +python2Compatible = True +# End-Of-Header + +error = "" + +exePy2 = [] +exePy3 = [] + + +def exeDisplayDataList(): + """ + Module function to support the display of some executable info. + + @return list of dictionaries containing the data to query the presence of + the executable + @rtype list of dict + """ + dataList = [] + data = { + "programEntry": True, + "header": QCoreApplication.translate( + "PyInstallerPlugin", "Packagers - PyInstaller"), + "exe": "dummyExe", + "versionCommand": "--version", + "versionStartsWith": "dummyExe", + "versionPosition": -1, + "version": "", + "versionCleanup": None, + "versionRe": "^\d", + } + + if _checkProgram(): + for exePath in (exePy2 + exePy3): + data["exe"] = exePath + data["versionStartsWith"] = "" + dataList.append(data.copy()) + else: + dataList.append(data) + return dataList + + +def _findExecutable(majorVersion): + """ + Restricted function to determine the names of the executables. + + @param majorVersion major python version + @type int + @return names of the executables + @rtype list of str + """ + # Determine Python Version + if majorVersion == 3: + minorVersions = range(10) + elif majorVersion == 2: + minorVersions = [7] # PyInstaller supports just Python 2.7 + else: + return [] + + executables = set() + if Utilities.isWindowsPlatform(): + # + # Windows + # + try: + import winreg + except ImportError: + import _winreg as winreg # __IGNORE_WARNING__ + + def getExePath(branch, access, versionStr): + exes = [] + try: + software = winreg.OpenKey(branch, 'Software', 0, access) + python = winreg.OpenKey(software, 'Python', 0, access) + pcore = winreg.OpenKey(python, 'PythonCore', 0, access) + version = winreg.OpenKey(pcore, versionStr, 0, access) + installpath = winreg.QueryValue(version, 'InstallPath') + # Look for pyinstaller.exe + exe = os.path.join(installpath, 'Scripts', 'pyinstaller.exe') + if os.access(exe, os.X_OK): + exes.append(exe) + # Look for pyi-makespec.exe + exe = os.path.join(installpath, 'Scripts', 'pyi-makespec.exe') + if os.access(exe, os.X_OK): + exes.append(exe) + except (WindowsError, OSError): # __IGNORE_WARNING__ + pass + return exes + + for minorVersion in minorVersions: + versionStr = '{0}.{1}'.format(majorVersion, minorVersion) + exePath = getExePath( + winreg.HKEY_CURRENT_USER, + winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr) + if exePath is not None: + executables.add(exePath) + + exePath = getExePath( + winreg.HKEY_LOCAL_MACHINE, + winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr) + if exePath is not None: + executables.add(exePath) + + # Even on Intel 64-bit machines it's 'AMD64' + if platform.machine() == 'AMD64': + exePath = getExePath( + winreg.HKEY_CURRENT_USER, + winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr) + if exePath is not None: + executables.add(exePath) + + exePath = getExePath( + winreg.HKEY_LOCAL_MACHINE, + winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr) + if exePath is not None: + executables.add(exePath) + else: + # + # Linux, Unix ... + pyinstallerScripts = ['pyinstaller', 'pyi-makespec'] +## scriptSuffixes = [""] +## for minorVersion in minorVersions: +## scriptSuffixes.append( +## "-python{0}.{1}".format(majorVersion, minorVersion)) + # There could be multiple pyinstaller executables in the path + # e.g. for different python variants + path = Utilities.getEnvironmentEntry('PATH') + # environment variable not defined + if path is None: + return [] + + # step 1: determine possible candidates + exes = [] + dirs = path.split(os.pathsep) + for directory in dirs: + for pyinstallerScript in pyinstallerScripts: + exe = os.path.join(directory, pyinstallerScript) + if os.access(exe, os.X_OK): + exes.append(exe) + + # step 2: determine the Python variant + if Utilities.isMacPlatform(): + checkStrings = ["Python.framework/Versions/3".lower(), + "python3"] + else: + checkStrings = ["python3"] + + _exePy2 = set() + _exePy3 = set() + for exe in exes: + try: + f = open(exe, "r") + line0 = f.readline() + for checkStr in checkStrings: + if checkStr in line0.lower(): + _exePy3.add(exe) + break + else: + _exePy2.add(exe) + finally: + f.close() + + executables = _exePy3 if majorVersion == 3 else _exePy2 + + # sort items, the probably newest topmost + executables = list(executables) + executables.sort(reverse=True) + return executables + + +def _checkProgram(): + """ + Restricted function to check the availability of pyinstaller. + + @return flag indicating availability (boolean) + """ + global error, exePy2, exePy3 + + exePy2 = _findExecutable(2) + exePy3 = _findExecutable(3) + if (exePy2 + exePy3) == []: + if Utilities.isWindowsPlatform(): + error = QCoreApplication.translate( + "PyInstallerPlugin", + "The pyinstaller.exe executable could not be found." + ) + else: + error = QCoreApplication.translate( + "PyInstallerPlugin", + "The pyinstaller executable could not be found." + ) + return False + else: + return True + + +class PyInstallerPlugin(QObject): + """ + Class documentation goes here. + """ + def __init__(self, ui): + """ + Constructor + + @param ui reference to the user interface object (UI.UserInterface) + """ + super(PyInstallerPlugin, self).__init__(ui) + self.__ui = ui + + def activate(self): + """ + Public method to activate this plugin. + + @return tuple of None and activation status (boolean) + """ + global error + error = "" # clear previous error + + return None, True + + def deactivate(self): + """ + Public method to deactivate this plugin. + """ + pass