scripts/install.py

branch
maintenance
changeset 7824
096b3ebc1409
parent 7737
5371a22cf2aa
parent 7823
9a4e93471a06
child 7850
e64b178499da
--- a/scripts/install.py	Sat Oct 03 11:14:23 2020 +0200
+++ b/scripts/install.py	Sun Nov 01 11:15:18 2020 +0100
@@ -21,6 +21,9 @@
 import time
 import io
 import json
+import shlex
+import datetime
+import getpass
 
 # Define the globals.
 progName = None
@@ -37,6 +40,7 @@
 forceCleanDesktopLinks = False
 doCompile = True
 yes2All = False
+ignorePyqt5Tools = False
 cfg = {}
 progLanguages = ["Python", "Ruby", "QSS"]
 sourceDir = "eric"
@@ -52,6 +56,10 @@
 macAppBundlePath = defaultMacAppBundlePath
 macPythonExe = defaultMacPythonExe
 
+installInfoName = "eric6install.json"
+installInfo = {}
+installCwd = ""
+
 # Define blacklisted versions of the prerequisites
 BlackLists = {
     "sip": [],
@@ -117,11 +125,11 @@
               .format(progName))
     elif sys.platform.startswith(("win", "cygwin")):
         print("    {0} [-chxz] [-a dir] [-b dir] [-d dir] [-f file]"
-              " [--clean-desktop] [--no-apis] [--yes]"
+              " [--clean-desktop] [--no-apis] [--no-tools] [--yes]"
               .format(progName))
     else:
         print("    {0} [-chxz] [-a dir] [-b dir] [-d dir] [-f file] [-i dir]"
-              " [--no-apis] [--yes]"
+              " [--no-apis] [--no-tools] [--yes]"
               .format(progName))
     print("where:")
     print("    -h, --help display this help message")
@@ -150,7 +158,9 @@
         print("               (default: {0})".format(macPythonExe))
     print("    -c         don't cleanup old installation first")
     if sys.platform.startswith(("win", "cygwin")):
-        ("    --clean-desktop delete desktop links before installation")
+        print("    --clean-desktop delete desktop links before installation")
+    if sys.platform != "darwin":
+        print("    --no-tools don't ask for installation of pyqt5-tools")
     print("    -x         don't perform dependency checks (use on your own"
           " risk)")
     print("    -z         don't compile the installed python files")
@@ -235,9 +245,8 @@
     @param name the name of the file.
     @param text the contents to copy to the file.
     """
-    f = open(name, "w")
-    f.write(text)
-    f.close()
+    with open(name, "w") as f:
+        f.write(text)
 
 
 def copyDesktopFile(src, dst):
@@ -249,17 +258,15 @@
     """
     global cfg, platBinDir
     
-    f = open(src, "r", encoding="utf-8")
-    text = f.read()
-    f.close()
+    with open(src, "r", encoding="utf-8") as f:
+        text = f.read()
     
     text = text.replace("@BINDIR@", platBinDir)
     text = text.replace("@MARKER@", "")
     text = text.replace("@PY_MARKER@", "")
     
-    f = open(dst, "w", encoding="utf-8")
-    f.write(text)
-    f.close()
+    with open(dst, "w", encoding="utf-8") as f:
+        f.write(text)
     os.chmod(dst, 0o644)
 
 
@@ -279,9 +286,8 @@
     else:
         Version = "Unknown"
     
-    f = open(src, "r", encoding="utf-8")
-    text = f.read()
-    f.close()
+    with open(src, "r", encoding="utf-8") as f:
+        text = f.read()
     
     text = (
         text.replace("@MARKER@", "")
@@ -289,9 +295,8 @@
         .replace("@DATE@", time.strftime("%Y-%m-%d"))
     )
     
-    f = open(dst, "w", encoding="utf-8")
-    f.write(text)
-    f.close()
+    with open(dst, "w", encoding="utf-8") as f:
+        f.write(text)
     os.chmod(dst, 0o644)
 
 
@@ -424,16 +429,15 @@
     if not os.path.exists(fname):
         if not os.path.exists(pdir):
             os.mkdir(pdir, 0o755)
-        f = open(fname, "w")
-        f.write(
-            '''# -*- coding: utf-8 -*-
+        with open(fname, "w") as f:
+            f.write(
+                '''# -*- coding: utf-8 -*-
 
 """
 Package containing the global plugins.
 """
 '''
-        )
-        f.close()
+            )
         os.chmod(fname, 0o644)
 
 
@@ -717,11 +721,10 @@
     for name in ["eric6_compare", "eric6_configure", "eric6_diff",
                  "eric6_editor", "eric6_hexeditor", "eric6_iconeditor",
                  "eric6_plugininstall", "eric6_pluginrepository",
-                 "eric6_pluginuninstall", "eric6_qregexp",
-                 "eric6_qregularexpression", "eric6_re", "eric6_snap",
-                 "eric6_sqlbrowser", "eric6_tray", "eric6_trpreviewer",
-                 "eric6_uipreviewer", "eric6_unittest", "eric6_browser",
-                 "eric6_shell", "eric6"]:
+                 "eric6_pluginuninstall", "eric6_qregularexpression",
+                 "eric6_re", "eric6_snap", "eric6_sqlbrowser", "eric6_tray",
+                 "eric6_trpreviewer", "eric6_uipreviewer", "eric6_unittest",
+                 "eric6_browser", "eric6_shell", "eric6"]:
         wnames.append(createPyWrapper(cfg['ericDir'], name, scriptsDir))
     
     # set install prefix, if not None
@@ -1240,6 +1243,13 @@
                                            "MicroPython", "*.api"))):
                     apis.append(os.path.basename(apiName))
     
+    if sys.platform == "darwin":
+        macConfig = (
+            """    'macAppBundlePath': r'{0}',\n"""
+            """    'macAppBundleName': r'{1}',\n"""
+        ).format(macAppBundlePath, macAppBundleName)
+    else:
+        macConfig = ""
     config = (
         """# -*- coding: utf-8 -*-\n"""
         """#\n"""
@@ -1264,8 +1274,7 @@
         """    'mdir': r'{13}',\n"""
         """    'apidir': r'{14}',\n"""
         """    'apis': {15},\n"""
-        """    'macAppBundlePath': r'{16}',\n"""
-        """    'macAppBundleName': r'{17}',\n"""
+        """{16}"""
         """}}\n"""
         """\n"""
         """def getConfig(name):\n"""
@@ -1294,11 +1303,42 @@
         cfg['ericCodeTemplatesDir'], cfg['ericOthersDir'],
         cfg['bindir'], cfg['mdir'],
         cfg['apidir'], sorted(apis),
-        macAppBundlePath, macAppBundleName,
+        macConfig,
     )
     copyToFile(configName, config)
 
 
+def createInstallInfo():
+    """
+    Record information about the way eric6 was installed.
+    """
+    global installInfo, installCwd, cfg
+    
+    installDateTime = datetime.datetime.now(tz=None)
+    try:
+        installInfo["sudo"] = os.getuid() == 0
+    except AttributeError:
+        installInfo["sudo"] = False
+    installInfo["user"] = getpass.getuser()
+    installInfo["exe"] = sys.executable
+    installInfo["argv"] = " ".join(shlex.quote(a) for a in sys.argv[:])
+    installInfo["install_cwd"] = installCwd
+    installInfo["eric"] = cfg["ericDir"]
+    installInfo["virtualenv"] = installInfo["eric"].startswith(
+        os.path.expanduser("~"))
+    installInfo["installed"] = True
+    installInfo["installed_on"] = installDateTime.strftime(
+        "%Y-%m-%d %H:%M:%S")
+    installInfo["guessed"] = False
+    installInfo["edited"] = False
+    installInfo["pip"] = False
+    installInfo["remarks"] = ""
+    installInfo["install_cwd_edited"] = False
+    installInfo["exe_edited"] = False
+    installInfo["argv_edited"] = False
+    installInfo["eric_edited"] = False
+
+
 def pipInstall(packageName, message):
     """
     Install the given package via pip.
@@ -1376,10 +1416,15 @@
     """
     Perform some dependency checks.
     """
+    try:
+        isSudo = os.getuid() == 0
+    except AttributeError:
+        isSudo = False
+    
     print('Checking dependencies')
     
     # update pip first even if we don't need to install anything
-    if isPipOutdated():
+    if not isSudo and isPipOutdated():
         updatePip()
         print("\n")
     
@@ -1399,7 +1444,7 @@
     try:
         from PyQt5.QtCore import qVersion
     except ImportError as msg:
-        installed = pipInstall(
+        installed = not isSudo and pipInstall(
             "PyQt5",
             "'PyQt5' could not be detected.\nError: {0}".format(msg)
         )
@@ -1432,25 +1477,31 @@
         from PyQt5.QtCore import PYQT_VERSION
         if PYQT_VERSION >= 0x050c00:
             # PyQt 5.12 separated QtWebEngine into a separate wheel
-            installed = pipInstall(
-                "PyQtWebEngine",
-                "Optional 'PyQtWebEngine' could not be detected.\nError: {0}"
-                .format(msg)
-            )
+            if isSudo:
+                print("Optional 'PyQtWebEngine' could not be detected.")
+            else:
+                pipInstall(
+                    "PyQtWebEngine",
+                    "Optional 'PyQtWebEngine' could not be detected.\n"
+                    "Error: {0}".format(msg)
+                )
     
     try:
         from PyQt5 import QtChart    # __IGNORE_WARNING__
     except ImportError as msg:
-        installed = pipInstall(
-            "PyQtChart",
-            "Optional 'PyQtChart' could not be detected.\nError: {0}"
-            .format(msg)
-        )
+        if isSudo:
+            print("Optional 'PyQtChart' could not be detected.")
+        else:
+            pipInstall(
+                "PyQtChart",
+                "Optional 'PyQtChart' could not be detected.\n"
+                "Error: {0}".format(msg)
+            )
     
     try:
         from PyQt5 import Qsci      # __IGNORE_WARNING__
     except ImportError as msg:
-        installed = pipInstall(
+        installed = not isSudo and pipInstall(
             "QScintilla",
             "'QScintilla' could not be detected.\nError: {0}".format(msg)
         )
@@ -1479,6 +1530,10 @@
         # available (e.g. for 32-Bit Windows)
         (("PyQt5.QtWebEngineWidgets", ), sys.maxsize <= 2**32),
     ]
+    optionalModulesList = {}
+    if sys.platform != "darwin" and not ignorePyqt5Tools:
+        optionalModulesList["pyqt5-tools"] = "pyqt5_tools"
+    
     # check mandatory modules
     modulesOK = True
     for impModule in impModulesList:
@@ -1512,6 +1567,21 @@
                       .format(" or ".join(altModules)))
         if not altModulesOK:
             exit(1)
+    # check optional modules
+    for optPackage in optionalModulesList:
+        try:
+            __import__(optionalModulesList[optPackage])
+            print("Found", optPackage)
+        except ImportError as msg:
+            if isSudo:
+                print("Optional '{0}' could not be detected."
+                      .format(optPackage))
+            else:
+                pipInstall(
+                    optPackage,
+                    "Optional '{0}' could not be detected.\n"
+                    "Error: {1}".format(optPackage, msg)
+                )
     
     # determine the platform dependent black list
     if sys.platform.startswith(("win", "cygwin")):
@@ -1525,8 +1595,8 @@
     qtMajor = int(qVersion().split('.')[0])
     qtMinor = int(qVersion().split('.')[1])
     print("Qt Version: {0}".format(qVersion().strip()))
-    if qtMajor == 5 and qtMinor < 9:
-        print('Sorry, you must have Qt version 5.9.0 or better.')
+    if qtMajor == 5 and qtMinor < 12:
+        print('Sorry, you must have Qt version 5.12.0 or better.')
         exit(2)
     
     # check version of sip
@@ -1576,8 +1646,8 @@
         major = int(major)
         minor = int(minor)
         pat = int(pat)
-        if major == 5 and minor < 9:
-            print('Sorry, you must have PyQt 5.9.0 or better or'
+        if major == 5 and minor < 12:
+            print('Sorry, you must have PyQt 5.12.0 or better or'
                   ' a recent snapshot release.')
             exit(4)
         # check for blacklisted versions
@@ -1600,8 +1670,12 @@
         major = int(major)
         minor = int(minor)
         pat = int(pat)
-        if major < 2 or (major == 2 and minor < 9):
-            print('Sorry, you must have QScintilla 2.9.0 or higher or'
+        if (
+            major < 2 or
+            (major == 2 and minor < 11) or
+            (major == 2 and minor == 11 and pat < 1)
+        ):
+            print('Sorry, you must have QScintilla 2.11.1 or higher or'
                   ' a recent snapshot release.')
             exit(5)
         # check for blacklisted versions
@@ -1673,9 +1747,8 @@
         hgOut = hgOut.strip()
         if hgOut.endswith("+"):
             hgOut = hgOut[:-1]
-        f = open(fileName + ".orig", "r", encoding="utf-8")
-        text = f.read()
-        f.close()
+        with open(fileName + ".orig", "r", encoding="utf-8") as f:
+            text = f.read()
         text = (
             text.replace("@@REVISION@@", hgOut)
             .replace("@@VERSION@@", "rev_" + hgOut)
@@ -1797,7 +1870,8 @@
     global progName, modDir, doCleanup, doCompile, distDir, cfg, apisDir
     global sourceDir, eric6SourceDir, configName
     global macAppBundlePath, macAppBundleName, macPythonExe
-    global installApis, doCleanDesktopLinks, yes2All
+    global installApis, doCleanDesktopLinks, yes2All, installCwd
+    global ignorePyqt5Tools
     
     if sys.version_info < (3, 5, 0) or sys.version_info > (3, 99, 99):
         print('Sorry, eric6 requires at least Python 3.5 for running.')
@@ -1805,6 +1879,8 @@
     
     progName = os.path.basename(argv[0])
     
+    installCwd = os.getcwd()
+    
     if os.path.dirname(argv[0]):
         os.chdir(os.path.dirname(argv[0]))
     
@@ -1814,7 +1890,7 @@
         if sys.platform.startswith(("win", "cygwin")):
             optlist, args = getopt.getopt(
                 argv[1:], "chxza:b:d:f:",
-                ["help", "no-apis", "yes"])
+                ["help", "no-apis", "no-tools", "yes"])
         elif sys.platform == "darwin":
             optlist, args = getopt.getopt(
                 argv[1:], "chxza:b:d:f:i:m:n:p:",
@@ -1822,7 +1898,7 @@
         else:
             optlist, args = getopt.getopt(
                 argv[1:], "chxza:b:d:f:i:",
-                ["help", "no-apis", "yes"])
+                ["help", "no-apis", "no-tools", "yes"])
     except getopt.GetoptError as err:
         print(err)
         usage()
@@ -1870,6 +1946,8 @@
             doCleanDesktopLinks = True
         elif opt == "--yes":
             yes2All = True
+        elif opt == "--no-tools":
+            ignorePyqt5Tools = True
     
     infoName = ""
     installFromSource = not os.path.isdir(sourceDir)
@@ -1925,6 +2003,8 @@
     print("\nCreating configuration file ...")
     createConfig()
 
+    createInstallInfo()
+    
     # Compile .ui files
     print("\nCompiling user interface files ...")
     # step 1: remove old Ui_*.py files
@@ -1959,6 +2039,10 @@
     print("\nInstalling eric6 ...")
     res = installEric()
     
+    with open(os.path.join(cfg["ericDir"],
+                           installInfoName), "w") as installInfoFile:
+        json.dump(installInfo, installInfoFile, indent=2)
+    
     # do some cleanup
     try:
         if installFromSource:

eric ide

mercurial