--- a/scripts/install.py Thu Nov 09 09:37:23 2023 +0100 +++ b/scripts/install.py Thu Nov 09 11:23:48 2023 +0100 @@ -9,11 +9,11 @@ Installation script for the eric IDE and all eric related tools. """ +import argparse import compileall import contextlib import datetime import fnmatch -import getopt import getpass import glob import importlib @@ -32,7 +32,6 @@ from functools import partial # Define the globals. -progName = None currDir = os.getcwd() modDir = None pyModDir = None @@ -113,87 +112,6 @@ sys.exit(rcode) -def usage(rcode=2): - """ - Display a usage message and exit. - - @param rcode the return code passed back to the calling process. - """ - global progName, modDir, distDir, apisDir - global macAppBundleName, macAppBundlePath, macPythonExe - - print() - print("Usage:") - if sys.platform == "darwin": - print( - " {0} [-chvxz] [-a dir] [-b dir] [-d dir] [-f file] [-i dir]" - " [-m name] [-n path] [-p python] [--help] [--no-apis]" - " [--no-info] [--with-tools] [--verbose] [--yes]".format(progName) - ) - elif sys.platform.startswith(("win", "cygwin")): - print( - " {0} [-chvxz] [-a dir] [-b dir] [-d dir] [-f file]" - " [--clean-desktop] [--help] [--no-apis] [--no-info]" - " [--with-tools] [--verbose] [--yes]".format(progName) - ) - else: - print( - " {0} [-chvxz] [-a dir] [-b dir] [-d dir] [-f file] [-i dir]" - " [--help] [--no-apis] [--no-info] [--with-tools] [--verbose]" - " [--yes]".format(progName) - ) - print("where:") - print(" -h, --help display this help message") - print(" -a dir where the API files will be installed") - if apisDir: - print(" (default: {0})".format(apisDir)) - else: - print(" (no default value)") - print(" --no-apis don't install API files") - print(" -b dir where the binaries will be installed") - print(" (default: {0})".format(platBinDir)) - print(" -d dir where eric python files will be installed") - print(" (default: {0})".format(modDir)) - print(" -f file configuration file naming the various installation paths") - if not sys.platform.startswith(("win", "cygwin")): - print(" -i dir temporary install prefix") - print(" (default: {0})".format(distDir)) - if sys.platform == "darwin": - print(" -m name name of the Mac app bundle") - print(" (default: {0})".format(macAppBundleName)) - print(" -n path path of the directory the Mac app bundle will") - print(" be created in") - print(" (default: {0})".format(macAppBundlePath)) - print(" -p python path of the python executable") - print(" (default: {0})".format(macPythonExe)) - print(" -c don't cleanup old installation first") - print(" -v, --verbose print some more information") - print(" -x don't perform dependency checks (use on your own risk)") - print(" -z don't compile the installed python files") - print(" --yes answer 'yes' to all questions") - print() - if sys.platform.startswith(("win", "cygwin")): - print(" --clean-desktop delete desktop links before installation") - print(" --no-info don't create the install info file") - print(" --with-tools install qt6-applications") - print() - print("The file given to the -f option must be valid Python code defining a") - print( - "dictionary called 'cfg' with the keys 'ericDir', 'ericPixDir'," - " 'ericIconDir'," - ) - print("'ericDTDDir', 'ericCSSDir', 'ericStylesDir', 'ericThemesDir',") - print(" 'ericDocDir', ericExamplesDir',") - print("'ericTranslationsDir', 'ericTemplatesDir', 'ericCodeTemplatesDir',") - print("'ericOthersDir','bindir', 'mdir' and 'apidir.") - print( - "These define the directories for the installation of the various" - " parts of eric." - ) - - exit(rcode) - - def initGlobals(): """ Module function to set the values of globals that need more than a @@ -677,9 +595,7 @@ macAppBundleName = getConfig("macAppBundleName") except AttributeError: macAppBundlePath = ( - defaultMacAppBundlePath - if os.getpid() == 0 - else defaultMacUserAppBundlePath + defaultMacAppBundlePath if os.getpid() == 0 else defaultMacUserAppBundlePath ) macAppBundleName = defaultMacAppBundleName for bundlePath in [ @@ -2182,6 +2098,130 @@ return "eric7 (Python {0}.{1})".format(majorVersion, minorVersion) +def createArgumentParser(): + """ + Function to create an argument parser. + + @return created argument parser object + @rtype argparse.ArgumentParser + """ + parser = argparse.ArgumentParser( + description="Install eric7 from the source code tree.", + epilog="The file given to the -f option must be valid Python code defining a" + "dictionary called 'cfg' with the keys 'ericDir', 'ericPixDir', ericIconDir'," + " 'ericDTDDir', 'ericCSSDir', 'ericStylesDir', 'ericThemesDir', ericDocDir'," + " ericExamplesDir', ericTranslationsDir', 'ericTemplatesDir'," + " 'ericCodeTemplatesDir', ericOthersDir','bindir', 'mdir' and 'apidir." + "These define the directories for the installation of the various parts of" + " eric.", + ) + + parser.add_argument( + "-a", + metavar="dir", + default=apisDir if apisDir else None, + help="directory where the API files will be installed ({0})".format( + "default: {0}".format(apisDir) if apisDir else "no default value" + ), + ) + parser.add_argument( + "--no-apis", + action="store_true", + help="don't install API files", + ) + parser.add_argument( + "-b", + metavar="dir", + default=platBinDir, + help="directory where the binaries will be installed (default: {0})".format( + platBinDir + ), + ) + parser.add_argument( + "-d", + metavar="dir", + default=modDir, + help="directory where eric Python files will be installed" + " (default: {0})".format(modDir), + ) + parser.add_argument( + "-f", + metavar="file", + help="configuration file naming the various installation paths", + ) + if not sys.platform.startswith(("win", "cygwin")): + parser.add_argument( + "-i", + metavar="dir", + default=distDir, + help="temporary install prefix (default: {0})".format(distDir), + ) + if sys.platform == "darwin": + parser.add_argument( + "-m", + metavar="name", + default=macAppBundleName, + help="name of the Mac app bundle (default: {0})".format(macAppBundleName), + ) + parser.add_argument( + "-n", + metavar="path", + default=macAppBundlePath, + help="path of the directory the Mac app bundle will be created in" + " (default: {0})".format(macAppBundlePath), + ) + parser.add_argument( + "-p", + metavar="python", + default=macPythonExe, + help="path of the python executable (default: {0})".format(macPythonExe), + ) + parser.add_argument( + "-c", + action="store_false", + help="don't cleanup old installation first", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="print some more information", + ) + parser.add_argument( + "-x", + action="store_false", + help="don't perform dependency checks (use on your own risk)", + ) + parser.add_argument( + "-z", + action="store_false", + help="don't compile the installed python files", + ) + parser.add_argument( + "--yes", + action="store_true", + help="answer 'yes' to all questions", + ) + if sys.platform.startswith(("win", "cygwin")): + parser.add_argument( + "--clean-desktop", + action="store_true", + help="delete desktop links before installation", + ) + parser.add_argument( + "--no-info", + action="store_true", + help="don't create the install info file", + ) + parser.add_argument( + "--with-tools", + action="store_true", + help="install the 'qt6-applications' package", + ) + + return parser + + def main(argv): """ The main function of the script. @@ -2189,9 +2229,8 @@ @param argv list of command line arguments @type list of str """ - # Parse the command line. - global progName, modDir, doCleanup, doCompile, distDir, cfg, apisDir - global sourceDir, eric7SourceDir, configName + global modDir, doCleanup, doCompile, distDir, cfg, apisDir + global sourceDir, eric7SourceDir, configName, platBinDir global macAppBundlePath, macAppBundleName, macPythonExe global installApis, doCleanDesktopLinks, yes2All global createInstallInfoFile, installCwd @@ -2202,8 +2241,6 @@ print("Sorry, eric requires at least Python 3.8 for running.") exit(5) - progName = os.path.basename(argv[0]) - installCwd = os.getcwd() if os.path.dirname(argv[0]): @@ -2211,95 +2248,48 @@ initGlobals() - try: - if sys.platform.startswith(("win", "cygwin")): - optlist, args = getopt.getopt( - argv[1:], - "chvxza:b:d:f:", - [ - "clean-desktop", - "help", - "no-apis", - "no-info", - "verbose", - "with-tools", - "yes", - ], - ) - elif sys.platform == "darwin": - optlist, args = getopt.getopt( - argv[1:], - "chvxza:b:d:f:i:m:n:p:", - ["help", "no-apis", "no-info", "with-tools", "verbose", "yes"], - ) - else: - optlist, args = getopt.getopt( - argv[1:], - "chvxza:b:d:f:i:", - ["help", "no-apis", "no-info", "with-tools", "verbose", "yes"], - ) - except getopt.GetoptError as err: - print(err) - usage() - - global platBinDir - - depChecks = True + parser = createArgumentParser() + args = parser.parse_args() - for opt, arg in optlist: - if opt in ["-h", "--help"]: - usage(0) - elif opt == "-a": - apisDir = arg - elif opt == "-b": - platBinDir = arg - elif opt == "-d": - modDir = arg - elif opt == "-i": - distDir = os.path.normpath(arg) - elif opt == "-x": - depChecks = False - elif opt == "-c": - doCleanup = False - elif opt == "-z": - doCompile = False - elif opt == "-f": - with open(arg) as f: - try: - exec(compile(f.read(), arg, "exec"), globals()) - # secok - if len(cfg) != configLength: - print( - "The configuration dictionary in '{0}' is" - " incorrect. Aborting".format(arg) - ) - exit(6) - except Exception as exc: + apisDir = args.a + platBinDir = args.b + modDir = args.d + depChecks = args.x + doCleanup = args.c + doCompile = args.z + installApis = not args.no_apis + yes2All = args.yes + withPyqt6Tools = args.with_tools + createInstallInfoFile = not args.no_info + verbose = args.verbose + if sys.platform == "darwin": + macAppBundleName = args.m + macAppBundlePath = args.n + macPythonExe = args.p + if sys.platform.startswith(("win", "cygwin")): + doCleanDesktopLinks = args.clean_desktop + else: + if args.i: + distDir = os.path.normpath(args.i) + if args.f: + with open(args.f) as f: + try: + exec(compile(f.read(), args.f, "exec"), globals()) + # secok + if len(cfg) != configLength: print( - "The configuration file '{0}' is not valid Python source." - " It will be ignored. Installation will be performed with" - " defaults.".format(arg) + "The configuration dictionary in '{0}' is" + " incorrect. Aborting".format(args.f) ) - print("ERROR: {0}".format(str(exc))) - cfg = {} - elif opt == "-m" and sys.platform == "darwin": - macAppBundleName = arg - elif opt == "-n" and sys.platform == "darwin": - macAppBundlePath = arg - elif opt == "-p" and sys.platform == "darwin": - macPythonExe = arg - elif opt == "--no-apis": - installApis = False - elif opt == "--clean-desktop": - doCleanDesktopLinks = True - elif opt == "--yes": - yes2All = True - elif opt == "--with-tools": - withPyqt6Tools = True - elif opt == "--no-info": - createInstallInfoFile = False - elif opt in ["-v", "--verbose"]: - verbose = True + exit(6) + except Exception as exc: + print( + "The configuration file '{0}' is not valid Python source." + " It will be ignored. Installation will be performed with" + " defaults.".format(args.f) + ) + print("ERROR: {0}".format(str(exc))) + cfg = {} infoName = "" installFromSource = not os.path.isdir(sourceDir)