"Fossies" - the Fresh Open Source Software Archive

Member "eric6-20.9/install.py" (5 Sep 2020, 68966 Bytes) of package /linux/misc/eric6-20.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "install.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 18.10_vs_18.11.

    1 #!/usr/bin/env python3
    2 # -*- coding: utf-8 -*-
    3 
    4 # Copyright (c) 2002 - 2020 Detlev Offenbach <detlev@die-offenbachs.de>
    5 #
    6 # This is the install script for eric6.
    7 
    8 """
    9 Installation script for the eric6 IDE and all eric6 related tools.
   10 """
   11 
   12 import sys
   13 import os
   14 import re
   15 import compileall
   16 import py_compile
   17 import glob
   18 import shutil
   19 import fnmatch
   20 import subprocess               # secok
   21 import time
   22 import io
   23 import json
   24 
   25 # Define the globals.
   26 progName = None
   27 currDir = os.getcwd()
   28 modDir = None
   29 pyModDir = None
   30 platBinDir = None
   31 platBinDirOld = None
   32 distDir = None
   33 apisDir = None
   34 installApis = True
   35 doCleanup = True
   36 doCleanDesktopLinks = False
   37 forceCleanDesktopLinks = False
   38 doCompile = True
   39 yes2All = False
   40 cfg = {}
   41 progLanguages = ["Python", "Ruby", "QSS"]
   42 sourceDir = "eric"
   43 eric6SourceDir = os.path.join(sourceDir, "eric6")
   44 configName = 'eric6config.py'
   45 defaultMacAppBundleName = "eric6.app"
   46 defaultMacAppBundlePath = "/Applications"
   47 defaultMacPythonExe = "{0}/Resources/Python.app/Contents/MacOS/Python".format(
   48     sys.exec_prefix)
   49 if not os.path.exists(defaultMacPythonExe):
   50     defaultMacPythonExe = ""
   51 macAppBundleName = defaultMacAppBundleName
   52 macAppBundlePath = defaultMacAppBundlePath
   53 macPythonExe = defaultMacPythonExe
   54 
   55 # Define blacklisted versions of the prerequisites
   56 BlackLists = {
   57     "sip": [],
   58     "PyQt5": [],
   59     "QScintilla2": [],
   60 }
   61 PlatformsBlackLists = {
   62     "windows": {
   63         "sip": [],
   64         "PyQt5": [],
   65         "QScintilla2": [],
   66     },
   67     
   68     "linux": {
   69         "sip": [],
   70         "PyQt5": [],
   71         "QScintilla2": [],
   72     },
   73     
   74     "mac": {
   75         "sip": [],
   76         "PyQt5": [],
   77         "QScintilla2": [],
   78     },
   79 }
   80 
   81 
   82 def exit(rcode=0):
   83     """
   84     Exit the install script.
   85     
   86     @param rcode result code to report back (integer)
   87     """
   88     global currDir
   89     
   90     print()
   91     
   92     if sys.platform.startswith(("win", "cygwin")):
   93         try:
   94             input("Press enter to continue...")             # secok
   95         except (EOFError, SyntaxError):
   96             pass
   97     
   98     os.chdir(currDir)
   99     
  100     sys.exit(rcode)
  101 
  102 
  103 def usage(rcode=2):
  104     """
  105     Display a usage message and exit.
  106 
  107     @param rcode the return code passed back to the calling process.
  108     """
  109     global progName, modDir, distDir, apisDir
  110     global macAppBundleName, macAppBundlePath, macPythonExe
  111 
  112     print()
  113     print("Usage:")
  114     if sys.platform == "darwin":
  115         print("    {0} [-chxz] [-a dir] [-b dir] [-d dir] [-f file] [-i dir]"
  116               " [-m name] [-n path] [-p python] [--no-apis] [--yes]"
  117               .format(progName))
  118     elif sys.platform.startswith(("win", "cygwin")):
  119         print("    {0} [-chxz] [-a dir] [-b dir] [-d dir] [-f file]"
  120               " [--clean-desktop] [--no-apis] [--yes]"
  121               .format(progName))
  122     else:
  123         print("    {0} [-chxz] [-a dir] [-b dir] [-d dir] [-f file] [-i dir]"
  124               " [--no-apis] [--yes]"
  125               .format(progName))
  126     print("where:")
  127     print("    -h, --help display this help message")
  128     print("    -a dir     where the API files will be installed")
  129     if apisDir:
  130         print("               (default: {0})".format(apisDir))
  131     else:
  132         print("               (no default value)")
  133     print("    --no-apis  don't install API files")
  134     print("    -b dir     where the binaries will be installed")
  135     print("               (default: {0})".format(platBinDir))
  136     print("    -d dir     where eric6 python files will be installed")
  137     print("               (default: {0})".format(modDir))
  138     print("    -f file    configuration file naming the various installation"
  139           " paths")
  140     if not sys.platform.startswith(("win", "cygwin")):
  141         print("    -i dir     temporary install prefix")
  142         print("               (default: {0})".format(distDir))
  143     if sys.platform == "darwin":
  144         print("    -m name    name of the Mac app bundle")
  145         print("               (default: {0})".format(macAppBundleName))
  146         print("    -n path    path of the directory the Mac app bundle will")
  147         print("               be created in")
  148         print("               (default: {0})".format(macAppBundlePath))
  149         print("    -p python  path of the python executable")
  150         print("               (default: {0})".format(macPythonExe))
  151     print("    -c         don't cleanup old installation first")
  152     if sys.platform.startswith(("win", "cygwin")):
  153         ("    --clean-desktop delete desktop links before installation")
  154     print("    -x         don't perform dependency checks (use on your own"
  155           " risk)")
  156     print("    -z         don't compile the installed python files")
  157     print("    --yes      answer 'yes' to all questions")
  158     print()
  159     print("The file given to the -f option must be valid Python code"
  160           " defining a")
  161     print("dictionary called 'cfg' with the keys 'ericDir', 'ericPixDir',"
  162           " 'ericIconDir',")
  163     print("'ericDTDDir', 'ericCSSDir', 'ericStylesDir', 'ericDocDir',"
  164           " 'ericExamplesDir',")
  165     print("'ericTranslationsDir', 'ericTemplatesDir', 'ericCodeTemplatesDir',")
  166     print("'ericOthersDir','bindir', 'mdir' and 'apidir.")
  167     print("These define the directories for the installation of the various"
  168           " parts of eric6.")
  169 
  170     exit(rcode)
  171 
  172 
  173 def initGlobals():
  174     """
  175     Module function to set the values of globals that need more than a
  176     simple assignment.
  177     """
  178     global platBinDir, modDir, pyModDir, apisDir, platBinDirOld
  179     
  180     try:
  181         import distutils.sysconfig
  182     except ImportError:
  183         print("Please install the 'distutils' package first.")
  184         exit(5)
  185     
  186     if sys.platform.startswith(("win", "cygwin")):
  187         platBinDir = sys.exec_prefix
  188         if platBinDir.endswith("\\"):
  189             platBinDir = platBinDir[:-1]
  190         platBinDirOld = platBinDir
  191         platBinDir = os.path.join(platBinDir, "Scripts")
  192         if not os.path.exists(platBinDir):
  193             platBinDir = platBinDirOld
  194     else:
  195         pyBinDir = os.path.normpath(os.path.dirname(sys.executable))
  196         if os.access(pyBinDir, os.W_OK):
  197             # install the eric scripts along the python executable
  198             platBinDir = pyBinDir
  199         else:
  200             # install them in the user's bin directory
  201             platBinDir = os.path.expanduser("~/bin")
  202         if (
  203             platBinDir != "/usr/local/bin" and
  204             os.access("/usr/local/bin", os.W_OK)
  205         ):
  206             platBinDirOld = "/usr/local/bin"
  207 
  208     modDir = distutils.sysconfig.get_python_lib(True)
  209     pyModDir = modDir
  210     
  211     pyqtDataDir = os.path.join(modDir, "PyQt5")
  212     if os.path.exists(os.path.join(pyqtDataDir, "qsci")):
  213         # it's the installer
  214         qtDataDir = pyqtDataDir
  215     elif os.path.exists(os.path.join(pyqtDataDir, "Qt", "qsci")):
  216         # it's the wheel
  217         qtDataDir = os.path.join(pyqtDataDir, "Qt")
  218     else:
  219         # determine dynamically
  220         try:
  221             from PyQt5.QtCore import QLibraryInfo
  222             qtDataDir = QLibraryInfo.location(QLibraryInfo.DataPath)
  223         except ImportError:
  224             qtDataDir = None
  225     if qtDataDir:
  226         apisDir = os.path.join(qtDataDir, "qsci", "api")
  227     else:
  228         apisDir = None
  229 
  230 
  231 def copyToFile(name, text):
  232     """
  233     Copy a string to a file.
  234 
  235     @param name the name of the file.
  236     @param text the contents to copy to the file.
  237     """
  238     f = open(name, "w")
  239     f.write(text)
  240     f.close()
  241 
  242 
  243 def copyDesktopFile(src, dst):
  244     """
  245     Modify a desktop file and write it to its destination.
  246     
  247     @param src source file name (string)
  248     @param dst destination file name (string)
  249     """
  250     global cfg, platBinDir
  251     
  252     f = open(src, "r", encoding="utf-8")
  253     text = f.read()
  254     f.close()
  255     
  256     text = text.replace("@BINDIR@", platBinDir)
  257     text = text.replace("@MARKER@", "")
  258     text = text.replace("@PY_MARKER@", "")
  259     
  260     f = open(dst, "w", encoding="utf-8")
  261     f.write(text)
  262     f.close()
  263     os.chmod(dst, 0o644)
  264 
  265 
  266 def copyAppStreamFile(src, dst):
  267     """
  268     Modify an appstream file and write it to its destination.
  269     
  270     @param src source file name (string)
  271     @param dst destination file name (string)
  272     """
  273     if os.path.exists(os.path.join("eric", "eric6", "UI", "Info.py")):
  274         # Installing from archive
  275         from eric.eric6.UI.Info import Version
  276     elif os.path.exists(os.path.join("eric6", "UI", "Info.py")):
  277         # Installing from source tree
  278         from eric6.UI.Info import Version
  279     else:
  280         Version = "Unknown"
  281     
  282     f = open(src, "r", encoding="utf-8")
  283     text = f.read()
  284     f.close()
  285     
  286     text = (
  287         text.replace("@MARKER@", "")
  288         .replace("@VERSION@", Version.split(None, 1)[0])
  289         .replace("@DATE@", time.strftime("%Y-%m-%d"))
  290     )
  291     
  292     f = open(dst, "w", encoding="utf-8")
  293     f.write(text)
  294     f.close()
  295     os.chmod(dst, 0o644)
  296 
  297 
  298 def wrapperNames(dname, wfile):
  299     """
  300     Create the platform specific names for the wrapper script.
  301     
  302     @param dname name of the directory to place the wrapper into
  303     @param wfile basename (without extension) of the wrapper script
  304     @return the names of the wrapper scripts
  305     """
  306     if sys.platform.startswith(("win", "cygwin")):
  307         wnames = (dname + "\\" + wfile + ".cmd",
  308                   dname + "\\" + wfile + ".bat")
  309     else:
  310         wnames = (dname + "/" + wfile, )
  311 
  312     return wnames
  313 
  314 
  315 def createPyWrapper(pydir, wfile, saveDir, isGuiScript=True):
  316     """
  317     Create an executable wrapper for a Python script.
  318 
  319     @param pydir the name of the directory where the Python script will
  320         eventually be installed (string)
  321     @param wfile the basename of the wrapper (string)
  322     @param saveDir directory to save the file into (string)
  323     @param isGuiScript flag indicating a wrapper script for a GUI
  324         application (boolean)
  325     @return the platform specific name of the wrapper (string)
  326     """
  327     # all kinds of Windows systems
  328     if sys.platform.startswith(("win", "cygwin")):
  329         wname = wfile + ".cmd"
  330         if isGuiScript:
  331             wrapper = (
  332                 '''@echo off\n'''
  333                 '''start "" "{2}\\pythonw.exe"'''
  334                 ''' "{0}\\{1}.pyw"'''
  335                 ''' %1 %2 %3 %4 %5 %6 %7 %8 %9\n'''.format(
  336                     pydir, wfile, os.path.dirname(sys.executable))
  337             )
  338         else:
  339             wrapper = (
  340                 '''@"{0}" "{1}\\{2}.py"'''
  341                 ''' %1 %2 %3 %4 %5 %6 %7 %8 %9\n'''.format(
  342                     sys.executable, pydir, wfile)
  343             )
  344 
  345     # Mac OS X
  346     elif sys.platform == "darwin":
  347         major = sys.version_info.major
  348         pyexec = "{0}/bin/pythonw{1}".format(sys.exec_prefix, major)
  349         if not os.path.exists(pyexec):
  350             pyexec = "{0}/bin/python{1}".format(sys.exec_prefix, major)
  351         wname = wfile
  352         wrapper = ('''#!/bin/sh\n'''
  353                    '''\n'''
  354                    '''exec "{0}" "{1}/{2}.py" "$@"\n'''
  355                    .format(pyexec, pydir, wfile))
  356 
  357     # *nix systems
  358     else:
  359         wname = wfile
  360         wrapper = ('''#!/bin/sh\n'''
  361                    '''\n'''
  362                    '''exec "{0}" "{1}/{2}.py" "$@"\n'''
  363                    .format(sys.executable, pydir, wfile))
  364     
  365     wname = os.path.join(saveDir, wname)
  366     copyToFile(wname, wrapper)
  367     os.chmod(wname, 0o755)                  # secok
  368 
  369     return wname
  370 
  371 
  372 def copyTree(src, dst, filters, excludeDirs=None, excludePatterns=None):
  373     """
  374     Copy Python, translation, documentation, wizards configuration,
  375     designer template files and DTDs of a directory tree.
  376     
  377     @param src name of the source directory
  378     @param dst name of the destination directory
  379     @param filters list of filter pattern determining the files to be copied
  380     @param excludeDirs list of (sub)directories to exclude from copying
  381     @keyparam excludePatterns list of filter pattern determining the files to
  382         be skipped
  383     """
  384     if excludeDirs is None:
  385         excludeDirs = []
  386     if excludePatterns is None:
  387         excludePatterns = []
  388     try:
  389         names = os.listdir(src)
  390     except OSError:
  391         # ignore missing directories (most probably the i18n directory)
  392         return
  393     
  394     for name in names:
  395         skipIt = False
  396         for excludePattern in excludePatterns:
  397             if fnmatch.fnmatch(name, excludePattern):
  398                 skipIt = True
  399                 break
  400         if not skipIt:
  401             srcname = os.path.join(src, name)
  402             dstname = os.path.join(dst, name)
  403             for fileFilter in filters:
  404                 if fnmatch.fnmatch(srcname, fileFilter):
  405                     if not os.path.isdir(dst):
  406                         os.makedirs(dst)
  407                     shutil.copy2(srcname, dstname)
  408                     os.chmod(dstname, 0o644)
  409                     break
  410             else:
  411                 if os.path.isdir(srcname) and srcname not in excludeDirs:
  412                     copyTree(srcname, dstname, filters,
  413                              excludePatterns=excludePatterns)
  414 
  415 
  416 def createGlobalPluginsDir():
  417     """
  418     Create the global plugins directory, if it doesn't exist.
  419     """
  420     global cfg, distDir
  421     
  422     pdir = os.path.join(cfg['mdir'], "eric6plugins")
  423     fname = os.path.join(pdir, "__init__.py")
  424     if not os.path.exists(fname):
  425         if not os.path.exists(pdir):
  426             os.mkdir(pdir, 0o755)
  427         f = open(fname, "w")
  428         f.write(
  429             '''# -*- coding: utf-8 -*-
  430 
  431 """
  432 Package containing the global plugins.
  433 """
  434 '''
  435         )
  436         f.close()
  437         os.chmod(fname, 0o644)
  438 
  439 
  440 def cleanupSource(dirName):
  441     """
  442     Cleanup the sources directory to get rid of leftover files
  443     and directories.
  444     
  445     @param dirName name of the directory to prune (string)
  446     """
  447     # step 1: delete all Ui_*.py files without a corresponding
  448     #         *.ui file
  449     dirListing = os.listdir(dirName)
  450     for formName, sourceName in [
  451         (f.replace('Ui_', "").replace(".py", ".ui"), f)
  452             for f in dirListing if fnmatch.fnmatch(f, "Ui_*.py")]:
  453         if not os.path.exists(os.path.join(dirName, formName)):
  454             os.remove(os.path.join(dirName, sourceName))
  455             if os.path.exists(os.path.join(dirName, sourceName + "c")):
  456                 os.remove(os.path.join(dirName, sourceName + "c"))
  457     
  458     # step 2: delete the __pycache__ directory and all remaining *.pyc files
  459     if os.path.exists(os.path.join(dirName, "__pycache__")):
  460         shutil.rmtree(os.path.join(dirName, "__pycache__"))
  461     for name in [f for f in os.listdir(dirName)
  462                  if fnmatch.fnmatch(f, "*.pyc")]:
  463         os.remove(os.path.join(dirName, name))
  464     
  465     # step 3: delete *.orig files
  466     for name in [f for f in os.listdir(dirName)
  467                  if fnmatch.fnmatch(f, "*.orig")]:
  468         os.remove(os.path.join(dirName, name))
  469     
  470     # step 4: descent into subdirectories and delete them if empty
  471     for name in os.listdir(dirName):
  472         name = os.path.join(dirName, name)
  473         if os.path.isdir(name):
  474             cleanupSource(name)
  475             if len(os.listdir(name)) == 0:
  476                 os.rmdir(name)
  477 
  478 
  479 def cleanUp():
  480     """
  481     Uninstall the old eric files.
  482     """
  483     global platBinDir, platBinDirOld
  484     
  485     try:
  486         from eric6config import getConfig
  487     except ImportError:
  488         # eric6 wasn't installed previously
  489         return
  490     except SyntaxError:
  491         # an incomplete or old config file was found
  492         return
  493     
  494     global pyModDir, progLanguages
  495     
  496     # Remove the menu entry for Linux systems
  497     if sys.platform.startswith("linux"):
  498         cleanUpLinuxSpecifics()
  499     # Remove the Desktop and Start Menu entries for Windows systems
  500     elif sys.platform.startswith(("win", "cygwin")):
  501         cleanUpWindowsLinks()
  502     
  503     # Remove the wrapper scripts
  504     rem_wnames = [
  505         "eric6_api", "eric6_compare",
  506         "eric6_configure", "eric6_diff",
  507         "eric6_doc", "eric6_qregularexpression",
  508         "eric6_qregexp", "eric6_re",
  509         "eric6_trpreviewer", "eric6_uipreviewer",
  510         "eric6_unittest", "eric6",
  511         "eric6_tray", "eric6_editor",
  512         "eric6_plugininstall", "eric6_pluginuninstall",
  513         "eric6_pluginrepository", "eric6_sqlbrowser",
  514         "eric6_iconeditor", "eric6_snap", "eric6_hexeditor",
  515         "eric6_browser", "eric6_shell",
  516         # from Python2 era
  517         "eric6_webbrowser",
  518     ]
  519     
  520     try:
  521         dirs = [platBinDir, getConfig('bindir')]
  522         if platBinDirOld:
  523             dirs.append(platBinDirOld)
  524         for rem_wname in rem_wnames:
  525             for d in dirs:
  526                 for rwname in wrapperNames(d, rem_wname):
  527                     if os.path.exists(rwname):
  528                         os.remove(rwname)
  529         
  530         # Cleanup our config file(s)
  531         for name in ['eric6config.py', 'eric6config.pyc', 'eric6.pth']:
  532             e6cfile = os.path.join(pyModDir, name)
  533             if os.path.exists(e6cfile):
  534                 os.remove(e6cfile)
  535             e6cfile = os.path.join(pyModDir, "__pycache__", name)
  536             path, ext = os.path.splitext(e6cfile)
  537             for f in glob.glob("{0}.*{1}".format(path, ext)):
  538                 os.remove(f)
  539             
  540         # Cleanup the install directories
  541         for name in ['ericExamplesDir', 'ericDocDir', 'ericDTDDir',
  542                      'ericCSSDir', 'ericIconDir', 'ericPixDir',
  543                      'ericTemplatesDir', 'ericCodeTemplatesDir',
  544                      'ericOthersDir', 'ericStylesDir', 'ericDir']:
  545             if os.path.exists(getConfig(name)):
  546                 shutil.rmtree(getConfig(name), True)
  547         
  548         # Cleanup translations
  549         for name in glob.glob(
  550                 os.path.join(getConfig('ericTranslationsDir'), 'eric6_*.qm')):
  551             if os.path.exists(name):
  552                 os.remove(name)
  553         
  554         # Cleanup API files
  555         try:
  556             apidir = getConfig('apidir')
  557             for progLanguage in progLanguages:
  558                 for name in getConfig('apis'):
  559                     apiname = os.path.join(apidir, progLanguage.lower(), name)
  560                     if os.path.exists(apiname):
  561                         os.remove(apiname)
  562                 for apiname in glob.glob(
  563                         os.path.join(apidir, progLanguage.lower(), "*.bas")):
  564                     if os.path.basename(apiname) != "eric6.bas":
  565                         os.remove(apiname)
  566         except AttributeError:
  567             pass
  568         
  569         if sys.platform == "darwin":
  570             # delete the Mac app bundle
  571             cleanUpMacAppBundle()
  572     except (IOError, OSError) as msg:
  573         sys.stderr.write(
  574             'Error: {0}\nTry install with admin rights.\n'.format(msg))
  575         exit(7)
  576 
  577 
  578 def cleanUpLinuxSpecifics():
  579     """
  580     Clean up Linux specific files.
  581     """
  582     if os.getuid() == 0:
  583         for name in ["/usr/share/pixmaps/eric.png",
  584                      "/usr/share/pixmaps/ericWeb.png"]:
  585             if os.path.exists(name):
  586                 os.remove(name)
  587         for name in [
  588             "/usr/share/applications/eric6.desktop",
  589             "/usr/share/appdata/eric6.appdata.xml",
  590             "/usr/share/metainfo/eric6.appdata.xml",
  591             "/usr/share/applications/eric6_browser.desktop",
  592             "/usr/share/pixmaps/eric.png",
  593             "/usr/share/pixmaps/ericWeb.png",
  594             # from Python2 era
  595             "/usr/share/applications/eric6_webbrowser.desktop",
  596         ]:
  597             if os.path.exists(name):
  598                 os.remove(name)
  599     elif os.getuid() >= 1000:
  600         # it is assumed that user ids start at 1000
  601         for name in ["~/.local/share/pixmaps/eric.png",
  602                      "~/.local/share/pixmaps/ericWeb.png"]:
  603             path = os.path.expanduser(name)
  604             if os.path.exists(path):
  605                 os.remove(path)
  606         for name in [
  607             "~/.local/share/applications/eric6.desktop",
  608             "~/.local/share/appdata/eric6.appdata.xml",
  609             "~/.local/share/metainfo/eric6.appdata.xml",
  610             "~/.local/share/applications/eric6_browser.desktop",
  611             "~/.local/share/pixmaps/eric.png",
  612             "~/.local/share/pixmaps/ericWeb.png",
  613             # from Python2 era
  614             "/usr/share/applications/eric6_webbrowser.desktop",
  615         ]:
  616             path = os.path.expanduser(name)
  617             if os.path.exists(path):
  618                 os.remove(path)
  619 
  620 
  621 def cleanUpMacAppBundle():
  622     """
  623     Uninstall the macOS application bundle.
  624     """
  625     from eric6config import getConfig
  626     try:
  627         macAppBundlePath = getConfig("macAppBundlePath")
  628         macAppBundleName = getConfig("macAppBundleName")
  629     except AttributeError:
  630         macAppBundlePath = defaultMacAppBundlePath
  631         macAppBundleName = defaultMacAppBundleName
  632     for bundlePath in [os.path.join(defaultMacAppBundlePath,
  633                                     macAppBundleName),
  634                        os.path.join(macAppBundlePath,
  635                                     macAppBundleName),
  636                        ]:
  637         if os.path.exists(bundlePath):
  638             shutil.rmtree(bundlePath)
  639 
  640 
  641 def cleanUpWindowsLinks():
  642     """
  643     Clean up the Desktop and Start Menu entries for Windows.
  644     """
  645     global doCleanDesktopLinks, forceCleanDesktopLinks
  646     
  647     try:
  648         from pywintypes import com_error        # __IGNORE_WARNING__
  649     except ImportError:
  650         # links were not created by install.py
  651         return
  652     
  653     regPath = (
  654         "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer" +
  655         "\\User Shell Folders"
  656     )
  657     
  658     if doCleanDesktopLinks or forceCleanDesktopLinks:
  659         # 1. cleanup desktop links
  660         regName = "Desktop"
  661         desktopEntry = getWinregEntry(regName, regPath)
  662         if desktopEntry:
  663             desktopFolder = os.path.normpath(os.path.expandvars(desktopEntry))
  664             for linkName in windowsDesktopNames():
  665                 linkPath = os.path.join(desktopFolder, linkName)
  666                 if os.path.exists(linkPath):
  667                     try:
  668                         os.remove(linkPath)
  669                     except EnvironmentError:
  670                         # maybe restrictions prohibited link removal
  671                         print("Could not remove '{0}'.".format(linkPath))
  672     
  673     # 2. cleanup start menu entry
  674     regName = "Programs"
  675     programsEntry = getWinregEntry(regName, regPath)
  676     if programsEntry:
  677         programsFolder = os.path.normpath(os.path.expandvars(programsEntry))
  678         eric6EntryPath = os.path.join(programsFolder, windowsProgramsEntry())
  679         if os.path.exists(eric6EntryPath):
  680             try:
  681                 shutil.rmtree(eric6EntryPath)
  682             except EnvironmentError:
  683                 # maybe restrictions prohibited link removal
  684                 print("Could not remove '{0}'.".format(eric6EntryPath))
  685 
  686 
  687 def shutilCopy(src, dst, perm=0o644):
  688     """
  689     Wrapper function around shutil.copy() to ensure the permissions.
  690     
  691     @param src source file name (string)
  692     @param dst destination file name or directory name (string)
  693     @keyparam perm permissions to be set (integer)
  694     """
  695     shutil.copy(src, dst)
  696     if os.path.isdir(dst):
  697         dst = os.path.join(dst, os.path.basename(src))
  698     os.chmod(dst, perm)
  699 
  700 
  701 def installEric():
  702     """
  703     Actually perform the installation steps.
  704     
  705     @return result code (integer)
  706     """
  707     global distDir, doCleanup, cfg, progLanguages, sourceDir, configName
  708     global installApis
  709     
  710     # Create the platform specific wrappers.
  711     scriptsDir = "install_scripts"
  712     if not os.path.isdir(scriptsDir):
  713         os.mkdir(scriptsDir)
  714     wnames = []
  715     for name in ["eric6_api", "eric6_doc"]:
  716         wnames.append(createPyWrapper(cfg['ericDir'], name, scriptsDir, False))
  717     for name in ["eric6_compare", "eric6_configure", "eric6_diff",
  718                  "eric6_editor", "eric6_hexeditor", "eric6_iconeditor",
  719                  "eric6_plugininstall", "eric6_pluginrepository",
  720                  "eric6_pluginuninstall", "eric6_qregexp",
  721                  "eric6_qregularexpression", "eric6_re", "eric6_snap",
  722                  "eric6_sqlbrowser", "eric6_tray", "eric6_trpreviewer",
  723                  "eric6_uipreviewer", "eric6_unittest", "eric6_browser",
  724                  "eric6_shell", "eric6"]:
  725         wnames.append(createPyWrapper(cfg['ericDir'], name, scriptsDir))
  726     
  727     # set install prefix, if not None
  728     if distDir:
  729         for key in list(cfg.keys()):
  730             cfg[key] = os.path.normpath(
  731                 os.path.join(distDir, cfg[key].lstrip(os.sep)))
  732     
  733     try:
  734         # Install the files
  735         # make the install directories
  736         for key in cfg.keys():
  737             if cfg[key] and not os.path.isdir(cfg[key]):
  738                 os.makedirs(cfg[key])
  739         
  740         # copy the eric6 config file
  741         if distDir:
  742             shutilCopy(configName, cfg['mdir'])
  743             if os.path.exists(configName + 'c'):
  744                 shutilCopy(configName + 'c', cfg['mdir'])
  745         else:
  746             shutilCopy(configName, modDir)
  747             if os.path.exists(configName + 'c'):
  748                 shutilCopy(configName + 'c', modDir)
  749         
  750         # copy the various parts of eric6
  751         copyTree(
  752             eric6SourceDir, cfg['ericDir'],
  753             ['*.py', '*.pyc', '*.pyo', '*.pyw'],
  754             [os.path.join(sourceDir, "Examples"),
  755              os.path.join(sourceDir, ".ropeproject")],
  756             excludePatterns=["eric6config.py*"])
  757         copyTree(
  758             os.path.join(eric6SourceDir, "Plugins"),
  759             os.path.join(cfg['ericDir'], "Plugins"),
  760             ['*.svgz', '*.svg', '*.png', '*.style', '*.tmpl', '*.txt'])
  761         copyTree(
  762             os.path.join(eric6SourceDir, "Documentation"),
  763             cfg['ericDocDir'],
  764             ['*.html', '*.qch'])
  765         copyTree(
  766             os.path.join(eric6SourceDir, "CSSs"),
  767             cfg['ericCSSDir'],
  768             ['*.css'])
  769         copyTree(
  770             os.path.join(eric6SourceDir, "Styles"),
  771             cfg['ericStylesDir'],
  772             ['*.qss', '*.e4h', '*.e6h'])
  773         copyTree(
  774             os.path.join(eric6SourceDir, "i18n"),
  775             cfg['ericTranslationsDir'],
  776             ['*.qm'])
  777         copyTree(
  778             os.path.join(eric6SourceDir, "icons"),
  779             cfg['ericIconDir'],
  780             ['*.svgz', '*.svg', '*.png', 'LICENSE*.*', 'readme.txt'])
  781         copyTree(
  782             os.path.join(eric6SourceDir, "pixmaps"),
  783             cfg['ericPixDir'],
  784             ['*.svgz', '*.svg', '*.png', '*.xpm', '*.ico', '*.gif'])
  785         copyTree(
  786             os.path.join(eric6SourceDir, "DesignerTemplates"),
  787             cfg['ericTemplatesDir'],
  788             ['*.tmpl'])
  789         copyTree(
  790             os.path.join(eric6SourceDir, "CodeTemplates"),
  791             cfg['ericCodeTemplatesDir'],
  792             ['*.tmpl'])
  793         
  794         # copy the wrappers
  795         for wname in wnames:
  796             shutilCopy(wname, cfg['bindir'], perm=0o755)
  797             os.remove(wname)
  798         shutil.rmtree(scriptsDir)
  799         
  800         # copy the license file
  801         shutilCopy(os.path.join(sourceDir, "docs", "LICENSE.GPL3"),
  802                    cfg['ericDir'])
  803         
  804         # create the global plugins directory
  805         createGlobalPluginsDir()
  806         
  807     except (IOError, OSError) as msg:
  808         sys.stderr.write(
  809             'Error: {0}\nTry install with admin rights.\n'.format(msg))
  810         return(7)
  811     
  812     # copy some text files to the doc area
  813     for name in ["LICENSE.GPL3", "THANKS", "changelog"]:
  814         try:
  815             shutilCopy(os.path.join(sourceDir, "docs", name),
  816                        cfg['ericDocDir'])
  817         except EnvironmentError:
  818             print("Could not install '{0}'.".format(
  819                 os.path.join(sourceDir, "docs", name)))
  820     for name in glob.glob(os.path.join(sourceDir, 'docs', 'README*.*')):
  821         try:
  822             shutilCopy(name, cfg['ericDocDir'])
  823         except EnvironmentError:
  824             print("Could not install '{0}'.".format(name))
  825    
  826     # copy some more stuff
  827     for name in ['default.e4k', 'default_Mac.e4k']:
  828         try:
  829             shutilCopy(os.path.join(sourceDir, "others", name),
  830                        cfg['ericOthersDir'])
  831         except EnvironmentError:
  832             print("Could not install '{0}'.".format(
  833                 os.path.join(sourceDir, "others", name)))
  834     
  835     # install the API file
  836     if installApis:
  837         for progLanguage in progLanguages:
  838             apidir = os.path.join(cfg['apidir'], progLanguage.lower())
  839             print("Installing {0} API files to '{1}'.".format(
  840                 progLanguage, apidir))
  841             if not os.path.exists(apidir):
  842                 os.makedirs(apidir)
  843             for apiName in glob.glob(os.path.join(eric6SourceDir, "APIs",
  844                                                   progLanguage, "*.api")):
  845                 try:
  846                     shutilCopy(apiName, apidir)
  847                 except EnvironmentError:
  848                     print("Could not install '{0}' (no permission)."
  849                           .format(apiName))
  850             for apiName in glob.glob(os.path.join(eric6SourceDir, "APIs",
  851                                                   progLanguage, "*.bas")):
  852                 try:
  853                     shutilCopy(apiName, apidir)
  854                 except EnvironmentError:
  855                     print("Could not install '{0}' (no permission)."
  856                           .format(apiName))
  857             if progLanguage == "Python":
  858                 # copy Python3 API files to the same destination
  859                 for apiName in glob.glob(os.path.join(eric6SourceDir, "APIs",
  860                                                       "Python3", "*.api")):
  861                     try:
  862                         shutilCopy(apiName, apidir)
  863                     except EnvironmentError:
  864                         print("Could not install '{0}' (no permission)."
  865                               .format(apiName))
  866                 for apiName in glob.glob(os.path.join(eric6SourceDir, "APIs",
  867                                                       "Python3", "*.bas")):
  868                     if os.path.exists(os.path.join(
  869                         apidir, os.path.basename(
  870                             apiName.replace(".bas", ".api")))):
  871                         try:
  872                             shutilCopy(apiName, apidir)
  873                         except EnvironmentError:
  874                             print("Could not install '{0}' (no permission)."
  875                                   .format(apiName))
  876                 
  877                 # copy MicroPython API files to the same destination
  878                 for apiName in glob.glob(os.path.join(eric6SourceDir, "APIs",
  879                                                       "MicroPython", "*.api")):
  880                     try:
  881                         shutilCopy(apiName, apidir)
  882                     except EnvironmentError:
  883                         print("Could not install '{0}' (no permission)."
  884                               .format(apiName))
  885                 for apiName in glob.glob(os.path.join(eric6SourceDir, "APIs",
  886                                                       "MicroPython", "*.bas")):
  887                     if os.path.exists(os.path.join(
  888                         apidir, os.path.basename(
  889                             apiName.replace(".bas", ".api")))):
  890                         try:
  891                             shutilCopy(apiName, apidir)
  892                         except EnvironmentError:
  893                             print("Could not install '{0}' (no permission)."
  894                                   .format(apiName))
  895     
  896     # Create menu entry for Linux systems
  897     if sys.platform.startswith("linux"):
  898         createLinuxSpecifics()
  899     
  900     # Create Desktop and Start Menu entries for Windows systems
  901     elif sys.platform.startswith(("win", "cygwin")):
  902         createWindowsLinks()
  903     
  904     # Create a Mac application bundle
  905     elif sys.platform == "darwin":
  906         createMacAppBundle(cfg['ericDir'])
  907     
  908     return 0
  909 
  910 
  911 def createLinuxSpecifics():
  912     """
  913     Install Linux specific files.
  914     """
  915     global distDir, sourceDir
  916     
  917     if distDir:
  918         dst = os.path.normpath(os.path.join(distDir, "usr/share/pixmaps"))
  919         if not os.path.exists(dst):
  920             os.makedirs(dst)
  921         shutilCopy(
  922             os.path.join(eric6SourceDir, "pixmaps", "eric_icon.png"),
  923             os.path.join(dst, "eric.png"))
  924         shutilCopy(
  925             os.path.join(eric6SourceDir, "pixmaps", "ericWeb48_icon.png"),
  926             os.path.join(dst, "ericWeb.png"))
  927         dst = os.path.normpath(
  928             os.path.join(distDir, "usr/share/applications"))
  929         if not os.path.exists(dst):
  930             os.makedirs(dst)
  931         copyDesktopFile(os.path.join(sourceDir, "linux", "eric6.desktop.in"),
  932                         os.path.join(dst, "eric6.desktop"))
  933         copyDesktopFile(
  934             os.path.join(sourceDir, "linux", "eric6_browser.desktop.in"),
  935             os.path.join(dst, "eric6_browser.desktop"))
  936         dst = os.path.normpath(
  937             os.path.join(distDir, "usr/share/metainfo"))
  938         if not os.path.exists(dst):
  939             os.makedirs(dst)
  940         copyAppStreamFile(
  941             os.path.join(sourceDir, "linux", "eric6.appdata.xml.in"),
  942             os.path.join(dst, "eric6.appdata.xml"))
  943     elif os.getuid() == 0:
  944         shutilCopy(
  945             os.path.join(eric6SourceDir, "pixmaps", "eric_icon.png"),
  946             "/usr/share/pixmaps/eric.png")
  947         copyDesktopFile(
  948             os.path.join(sourceDir, "linux", "eric6.desktop.in"),
  949             "/usr/share/applications/eric6.desktop")
  950         if os.path.exists("/usr/share/metainfo"):
  951             copyAppStreamFile(
  952                 os.path.join(sourceDir, "linux", "eric6.appdata.xml.in"),
  953                 "/usr/share/metainfo/eric6.appdata.xml")
  954         elif os.path.exists("/usr/share/appdata"):
  955             copyAppStreamFile(
  956                 os.path.join(sourceDir, "linux", "eric6.appdata.xml.in"),
  957                 "/usr/share/appdata/eric6.appdata.xml")
  958         shutilCopy(
  959             os.path.join(eric6SourceDir, "pixmaps", "ericWeb48_icon.png"),
  960             "/usr/share/pixmaps/ericWeb.png")
  961         copyDesktopFile(
  962             os.path.join(sourceDir, "linux", "eric6_browser.desktop.in"),
  963             "/usr/share/applications/eric6_browser.desktop")
  964     elif os.getuid() >= 1000:
  965         # it is assumed, that user ids start at 1000
  966         localPath = os.path.join(os.path.expanduser("~"),
  967                                  ".local", "share")
  968         # create directories first
  969         for directory in [os.path.join(localPath, name)
  970                           for name in ("pixmaps", "applications",
  971                                        "metainfo", "appdata")]:
  972             if not os.path.isdir(directory):
  973                 os.makedirs(directory)
  974         # now copy the files
  975         shutilCopy(
  976             os.path.join(eric6SourceDir, "pixmaps", "eric_icon.png"),
  977             os.path.join(localPath, "pixmaps", "eric.png"))
  978         copyDesktopFile(
  979             os.path.join(sourceDir, "linux", "eric6.desktop.in"),
  980             os.path.join(localPath, "applications", "eric6.desktop"))
  981         copyAppStreamFile(
  982             os.path.join(sourceDir, "linux", "eric6.appdata.xml.in"),
  983             os.path.join(localPath, "metainfo", "eric6.appdata.xml"))
  984         copyAppStreamFile(
  985             os.path.join(sourceDir, "linux", "eric6.appdata.xml.in"),
  986             os.path.join(localPath, "appdata", "eric6.appdata.xml"))
  987         shutilCopy(
  988             os.path.join(eric6SourceDir, "pixmaps", "ericWeb48_icon.png"),
  989             os.path.join(localPath, "pixmaps", "ericWeb.png"))
  990         copyDesktopFile(
  991             os.path.join(sourceDir, "linux", "eric6_browser.desktop.in"),
  992             os.path.join(localPath, "applications", "eric6_browser.desktop"))
  993 
  994 
  995 def createWindowsLinks():
  996     """
  997     Create Desktop and Start Menu links.
  998     """
  999     try:
 1000         # check, if pywin32 is available
 1001         from win32com.client import Dispatch    # __IGNORE_WARNING__
 1002     except ImportError:
 1003         installed = pipInstall(
 1004             "pywin32",
 1005             "\nThe Python package 'pywin32' could not be imported."
 1006         )
 1007         if installed:
 1008             # create the links via an external script to get around some
 1009             # startup magic done by pywin32.pth
 1010             args = [
 1011                 sys.executable,
 1012                 os.path.join(os.path.dirname(__file__),
 1013                              "create_windows_links.py"),
 1014             ]
 1015             subprocess.call(args)               # secok
 1016         else:
 1017             print(
 1018                 "\nThe Python package 'pywin32' is not installed. Desktop and"
 1019                 " Start Menu entries will not be created."
 1020             )
 1021         return
 1022     
 1023     regPath = (
 1024         "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer" +
 1025         "\\User Shell Folders"
 1026     )
 1027     
 1028     # 1. create desktop shortcuts
 1029     regName = "Desktop"
 1030     desktopEntry = getWinregEntry(regName, regPath)
 1031     if desktopEntry:
 1032         desktopFolder = os.path.normpath(os.path.expandvars(desktopEntry))
 1033         for linkName, targetPath, iconPath in windowsDesktopEntries():
 1034             linkPath = os.path.join(desktopFolder, linkName)
 1035             createWindowsShortcut(linkPath, targetPath, iconPath)
 1036     
 1037     # 2. create start menu entry and shortcuts
 1038     regName = "Programs"
 1039     programsEntry = getWinregEntry(regName, regPath)
 1040     if programsEntry:
 1041         programsFolder = os.path.normpath(os.path.expandvars(programsEntry))
 1042         eric6EntryPath = os.path.join(programsFolder, windowsProgramsEntry())
 1043         if not os.path.exists(eric6EntryPath):
 1044             try:
 1045                 os.makedirs(eric6EntryPath)
 1046             except EnvironmentError:
 1047                 # maybe restrictions prohibited link creation
 1048                 return
 1049         
 1050         for linkName, targetPath, iconPath in windowsDesktopEntries():
 1051             linkPath = os.path.join(eric6EntryPath, linkName)
 1052             createWindowsShortcut(linkPath, targetPath, iconPath)
 1053 
 1054 
 1055 def createMacAppBundle(pydir):
 1056     """
 1057     Create a Mac application bundle.
 1058 
 1059     @param pydir the name of the directory where the Python script will
 1060         eventually be installed
 1061     @type str
 1062     """
 1063     global cfg, macAppBundleName, macPythonExe, macAppBundlePath
 1064     
 1065     directories = {
 1066         "contents": "{0}/{1}/Contents/".format(
 1067             macAppBundlePath, macAppBundleName),
 1068         "exe": "{0}/{1}/Contents/MacOS".format(
 1069             macAppBundlePath, macAppBundleName),
 1070         "icns": "{0}/{1}/Contents/Resources".format(
 1071             macAppBundlePath, macAppBundleName)
 1072     }
 1073     for directory in directories.values():
 1074         if not os.path.exists(directory):
 1075             os.makedirs(directory)
 1076     
 1077     if macPythonExe == defaultMacPythonExe and macPythonExe:
 1078         starter = os.path.join(directories["exe"], "eric")
 1079         os.symlink(macPythonExe, starter)
 1080     else:
 1081         starter = "python{0}".format(sys.version_info.major)
 1082     
 1083     wname = os.path.join(directories["exe"], "eric6")
 1084     
 1085     # determine entry for DYLD_FRAMEWORK_PATH
 1086     dyldLine = ""
 1087     try:
 1088         from PyQt5.QtCore import QLibraryInfo
 1089         qtLibraryDir = QLibraryInfo.location(QLibraryInfo.LibrariesPath)
 1090     except ImportError:
 1091         qtLibraryDir = ""
 1092     if qtLibraryDir:
 1093         dyldLine = "DYLD_FRAMEWORK_PATH={0}\n".format(qtLibraryDir)
 1094     
 1095     # determine entry for PATH
 1096     pathLine = ""
 1097     path = os.getenv("PATH", "")
 1098     if path:
 1099         pybin = os.path.join(sys.exec_prefix, "bin")
 1100         pathlist = path.split(os.pathsep)
 1101         pathlist_n = [pybin]
 1102         for path_ in pathlist:
 1103             if path_ and path_ not in pathlist_n:
 1104                 pathlist_n.append(path_)
 1105         pathLine = "PATH={0}\n".format(os.pathsep.join(pathlist_n))
 1106     
 1107     # create the wrapper script
 1108     wrapper = ('''#!/bin/sh\n'''
 1109                '''\n'''
 1110                '''{0}'''
 1111                '''{1}'''
 1112                '''exec "{2}" "{3}/{4}.py" "$@"\n'''
 1113                .format(pathLine, dyldLine, starter, pydir, "eric6"))
 1114     copyToFile(wname, wrapper)
 1115     os.chmod(wname, 0o755)                  # secok
 1116     
 1117     shutilCopy(os.path.join(eric6SourceDir, "pixmaps", "eric_2.icns"),
 1118                os.path.join(directories["icns"], "eric.icns"))
 1119     
 1120     if os.path.exists(os.path.join("eric", "eric6", "UI", "Info.py")):
 1121         # Installing from archive
 1122         from eric.eric6.UI.Info import Version, CopyrightShort
 1123     elif os.path.exists(os.path.join("eric6", "UI", "Info.py")):
 1124         # Installing from source tree
 1125         from eric6.UI.Info import Version, CopyrightShort
 1126     else:
 1127         Version = "Unknown"
 1128         CopyrightShort = "(c) 2002 - 2020 Detlev Offenbach"
 1129     
 1130     copyToFile(
 1131         os.path.join(directories["contents"], "Info.plist"),
 1132         '''<?xml version="1.0" encoding="UTF-8"?>\n'''
 1133         '''<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"\n'''
 1134         '''          "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'''
 1135         '''<plist version="1.0">\n'''
 1136         '''<dict>\n'''
 1137         '''    <key>CFBundleExecutable</key>\n'''
 1138         '''    <string>eric6</string>\n'''
 1139         '''    <key>CFBundleIconFile</key>\n'''
 1140         '''    <string>eric.icns</string>\n'''
 1141         '''    <key>CFBundleInfoDictionaryVersion</key>\n'''
 1142         '''    <string>{1}</string>\n'''
 1143         '''    <key>CFBundleName</key>\n'''
 1144         '''    <string>{0}</string>\n'''
 1145         '''    <key>CFBundleDisplayName</key>\n'''
 1146         '''    <string>{0}</string>\n'''
 1147         '''    <key>CFBundlePackageType</key>\n'''
 1148         '''    <string>APPL</string>\n'''
 1149         '''    <key>CFBundleSignature</key>\n'''
 1150         '''    <string>ERIC-IDE</string>\n'''
 1151         '''    <key>CFBundleVersion</key>\n'''
 1152         '''    <string>{1}</string>\n'''
 1153         '''    <key>CFBundleGetInfoString</key>\n'''
 1154         '''    <string>{1}, {2}</string>\n'''
 1155         '''    <key>CFBundleIdentifier</key>\n'''
 1156         '''    <string>org.python-projects.eric-ide</string>\n'''
 1157         '''    <key>NSRequiresAquaSystemAppearance</key>\n'''
 1158         '''    <string>false</string>\n'''
 1159         '''</dict>\n'''
 1160         '''</plist>\n'''.format(
 1161             macAppBundleName.replace(".app", ""),
 1162             Version.split(None, 1)[0],
 1163             CopyrightShort))
 1164 
 1165 
 1166 def createInstallConfig():
 1167     """
 1168     Create the installation config dictionary.
 1169     """
 1170     global modDir, platBinDir, cfg, apisDir, installApis
 1171         
 1172     ericdir = os.path.join(modDir, "eric6")
 1173     cfg = {
 1174         'ericDir': ericdir,
 1175         'ericPixDir': os.path.join(ericdir, "pixmaps"),
 1176         'ericIconDir': os.path.join(ericdir, "icons"),
 1177         'ericDTDDir': os.path.join(ericdir, "DTDs"),
 1178         'ericCSSDir': os.path.join(ericdir, "CSSs"),
 1179         'ericStylesDir': os.path.join(ericdir, "Styles"),
 1180         'ericDocDir': os.path.join(ericdir, "Documentation"),
 1181         'ericExamplesDir': os.path.join(ericdir, "Examples"),
 1182         'ericTranslationsDir': os.path.join(ericdir, "i18n"),
 1183         'ericTemplatesDir': os.path.join(ericdir, "DesignerTemplates"),
 1184         'ericCodeTemplatesDir': os.path.join(ericdir, 'CodeTemplates'),
 1185         'ericOthersDir': ericdir,
 1186         'bindir': platBinDir,
 1187         'mdir': modDir,
 1188     }
 1189     if installApis:
 1190         if apisDir:
 1191             cfg['apidir'] = apisDir
 1192         else:
 1193             cfg['apidir'] = os.path.join(ericdir, "api")
 1194     else:
 1195         cfg['apidir'] = ""
 1196 configLength = 15
 1197     
 1198 
 1199 def createConfig():
 1200     """
 1201     Create a config file with the respective config entries.
 1202     """
 1203     global cfg, macAppBundlePath, configName
 1204     
 1205     apis = []
 1206     if installApis:
 1207         for progLanguage in progLanguages:
 1208             for apiName in sorted(
 1209                 glob.glob(os.path.join(eric6SourceDir, "APIs", progLanguage,
 1210                                        "*.api"))):
 1211                 apis.append(os.path.basename(apiName))
 1212             if progLanguage == "Python":
 1213                 # treat Python3 API files the same as Python API files
 1214                 for apiName in sorted(
 1215                     glob.glob(os.path.join(eric6SourceDir, "APIs", "Python3",
 1216                                            "*.api"))):
 1217                     apis.append(os.path.basename(apiName))
 1218                 
 1219                 # treat MicroPython API files the same as Python API files
 1220                 for apiName in sorted(
 1221                     glob.glob(os.path.join(eric6SourceDir, "APIs",
 1222                                            "MicroPython", "*.api"))):
 1223                     apis.append(os.path.basename(apiName))
 1224     
 1225     config = (
 1226         """# -*- coding: utf-8 -*-\n"""
 1227         """#\n"""
 1228         """# This module contains the configuration of the individual eric6"""
 1229         """ installation\n"""
 1230         """#\n"""
 1231         """\n"""
 1232         """_pkg_config = {{\n"""
 1233         """    'ericDir': r'{0}',\n"""
 1234         """    'ericPixDir': r'{1}',\n"""
 1235         """    'ericIconDir': r'{2}',\n"""
 1236         """    'ericDTDDir': r'{3}',\n"""
 1237         """    'ericCSSDir': r'{4}',\n"""
 1238         """    'ericStylesDir': r'{5}',\n"""
 1239         """    'ericDocDir': r'{6}',\n"""
 1240         """    'ericExamplesDir': r'{7}',\n"""
 1241         """    'ericTranslationsDir': r'{8}',\n"""
 1242         """    'ericTemplatesDir': r'{9}',\n"""
 1243         """    'ericCodeTemplatesDir': r'{10}',\n"""
 1244         """    'ericOthersDir': r'{11}',\n"""
 1245         """    'bindir': r'{12}',\n"""
 1246         """    'mdir': r'{13}',\n"""
 1247         """    'apidir': r'{14}',\n"""
 1248         """    'apis': {15},\n"""
 1249         """    'macAppBundlePath': r'{16}',\n"""
 1250         """    'macAppBundleName': r'{17}',\n"""
 1251         """}}\n"""
 1252         """\n"""
 1253         """def getConfig(name):\n"""
 1254         """    '''\n"""
 1255         """    Module function to get a configuration value.\n"""
 1256         """\n"""
 1257         """    @param name name of the configuration value"""
 1258         """    @type str\n"""
 1259         """    @exception AttributeError raised to indicate an invalid"""
 1260         """ config entry\n"""
 1261         """    '''\n"""
 1262         """    try:\n"""
 1263         """        return _pkg_config[name]\n"""
 1264         """    except KeyError:\n"""
 1265         """        pass\n"""
 1266         """\n"""
 1267         """    raise AttributeError(\n"""
 1268         """        '"{{0}}" is not a valid configuration value'"""
 1269         """.format(name))\n"""
 1270     ).format(
 1271         cfg['ericDir'], cfg['ericPixDir'], cfg['ericIconDir'],
 1272         cfg['ericDTDDir'], cfg['ericCSSDir'],
 1273         cfg['ericStylesDir'], cfg['ericDocDir'],
 1274         cfg['ericExamplesDir'], cfg['ericTranslationsDir'],
 1275         cfg['ericTemplatesDir'],
 1276         cfg['ericCodeTemplatesDir'], cfg['ericOthersDir'],
 1277         cfg['bindir'], cfg['mdir'],
 1278         cfg['apidir'], sorted(apis),
 1279         macAppBundlePath, macAppBundleName,
 1280     )
 1281     copyToFile(configName, config)
 1282 
 1283 
 1284 def pipInstall(packageName, message):
 1285     """
 1286     Install the given package via pip.
 1287     
 1288     @param packageName name of the package to be installed
 1289     @type str
 1290     @param message message to be shown to the user
 1291     @type str
 1292     @return flag indicating a successful installation
 1293     @rtype bool
 1294     """
 1295     global yes2All
 1296     
 1297     ok = False
 1298     if yes2All:
 1299         answer = "y"
 1300     else:
 1301         print("{0}\n\nShall '{1}' be installed using pip? (Y/n)"
 1302               .format(message, packageName), end=" ")
 1303         answer = input()                            # secok
 1304     if answer in ("", "Y", "y"):
 1305         exitCode = subprocess.call(                 # secok
 1306             [sys.executable, "-m", "pip", "install", packageName])
 1307         ok = (exitCode == 0)
 1308     
 1309     return ok
 1310 
 1311 
 1312 def isPipOutdated():
 1313     """
 1314     Check, if pip is outdated.
 1315     
 1316     @return flag indicating an outdated pip
 1317     @rtype bool
 1318     """
 1319     try:
 1320         pipOut = subprocess.check_output([          # secok
 1321             sys.executable, "-m", "pip", "list", "--outdated",
 1322             "--format=json"
 1323         ])
 1324         pipOut = pipOut.decode()
 1325     except (OSError, subprocess.CalledProcessError):
 1326         pipOut = "[]"       # default empty list
 1327     try:
 1328         jsonList = json.loads(pipOut)
 1329     except Exception:
 1330         jsonList = []
 1331     for package in jsonList:
 1332         if isinstance(package, dict) and package["name"] == "pip":
 1333             print("'pip' is outdated (installed {0}, available {1})".format(
 1334                 package["version"], package["latest_version"]
 1335             ))
 1336             return True
 1337     
 1338     return False
 1339 
 1340 
 1341 def updatePip():
 1342     """
 1343     Update the installed pip package.
 1344     """
 1345     global yes2All
 1346     
 1347     if yes2All:
 1348         answer = "y"
 1349     else:
 1350         print("Shall 'pip' be updated (recommended)? (Y/n)", end=" ")
 1351         answer = input()            # secok
 1352     if answer in ("", "Y", "y"):
 1353         subprocess.call(            # secok
 1354             [sys.executable, "-m", "pip", "install", "--upgrade", "pip"])
 1355 
 1356 
 1357 def doDependancyChecks():
 1358     """
 1359     Perform some dependency checks.
 1360     """
 1361     print('Checking dependencies')
 1362     
 1363     # update pip first even if we don't need to install anything
 1364     if isPipOutdated():
 1365         updatePip()
 1366         print("\n")
 1367     
 1368     # perform dependency checks
 1369     print("Python Version: {0:d}.{1:d}.{2:d}".format(*sys.version_info[:3]))
 1370     if sys.version_info < (3, 5, 0):
 1371         print('Sorry, you must have Python 3.5.0 or higher.')
 1372         exit(5)
 1373     
 1374     try:
 1375         import xml.etree            # __IGNORE_WARNING__
 1376     except ImportError:
 1377         print('Your Python installation is missing the XML module.')
 1378         print('Please install it and try again.')
 1379         exit(5)
 1380     
 1381     try:
 1382         from PyQt5.QtCore import qVersion
 1383     except ImportError as msg:
 1384         installed = pipInstall(
 1385             "PyQt5",
 1386             "PyQt5 could not be detected.\nError: {0}".format(msg)
 1387         )
 1388         if installed:
 1389             # try to import it again
 1390             try:
 1391                 from PyQt5.QtCore import qVersion
 1392             except ImportError as msg:
 1393                 print('Sorry, please install PyQt5.')
 1394                 print('Error: {0}'.format(msg))
 1395                 exit(1)
 1396         else:
 1397             print('Sorry, please install PyQt5.')
 1398             print('Error: {0}'.format(msg))
 1399             exit(1)
 1400     print("Found PyQt5")
 1401     
 1402     try:
 1403         pyuic = "pyuic5"
 1404         from PyQt5 import uic      # __IGNORE_WARNING__
 1405     except ImportError as msg:
 1406         print("Sorry, {0} is not installed.".format(pyuic))
 1407         print('Error: {0}'.format(msg))
 1408         exit(1)
 1409     print("Found {0}".format(pyuic))
 1410     
 1411     try:
 1412         from PyQt5 import QtWebEngineWidgets    # __IGNORE_WARNING__
 1413     except ImportError as msg:
 1414         from PyQt5.QtCore import PYQT_VERSION
 1415         if PYQT_VERSION >= 0x050c00:
 1416             # PyQt 5.12 separated QtWebEngine into a separate wheel
 1417             installed = pipInstall(
 1418                 "PyQtWebEngine",
 1419                 "PyQtWebEngine could not be detected.\nError: {0}"
 1420                 .format(msg)
 1421             )
 1422     
 1423     try:
 1424         from PyQt5 import QtChart    # __IGNORE_WARNING__
 1425     except ImportError as msg:
 1426         installed = pipInstall(
 1427             "PyQtChart",
 1428             "PyQtChart could not be detected.\nError: {0}"
 1429             .format(msg)
 1430         )
 1431     
 1432     try:
 1433         from PyQt5 import Qsci      # __IGNORE_WARNING__
 1434     except ImportError as msg:
 1435         installed = pipInstall(
 1436             "QScintilla",
 1437             "QScintilla could not be detected.\nError: {0}".format(msg)
 1438         )
 1439         if installed:
 1440             # try to import it again
 1441             try:
 1442                 from PyQt5 import Qsci      # __IGNORE_WARNING__
 1443                 message = None
 1444             except ImportError as msg:
 1445                 message = str(msg)
 1446         else:
 1447             message = "QScintilla could not be installed."
 1448         if message:
 1449             print("Sorry, please install QScintilla2 and")
 1450             print("its PyQt5 wrapper.")
 1451             print('Error: {0}'.format(message))
 1452             exit(1)
 1453     print("Found QScintilla2")
 1454     
 1455     impModulesList = [
 1456         "PyQt5.QtGui", "PyQt5.QtNetwork", "PyQt5.QtPrintSupport",
 1457         "PyQt5.QtSql", "PyQt5.QtSvg", "PyQt5.QtWidgets",
 1458     ]
 1459     altModulesList = [
 1460         # Tuple with alternatives, flag indicating it's ok to not be
 1461         # available (e.g. for 32-Bit Windows)
 1462         (("PyQt5.QtWebEngineWidgets", ), sys.maxsize <= 2**32),
 1463     ]
 1464     # check mandatory modules
 1465     modulesOK = True
 1466     for impModule in impModulesList:
 1467         name = impModule.split(".")[1]
 1468         try:
 1469             __import__(impModule)
 1470             print("Found", name)
 1471         except ImportError as msg:
 1472             print('Sorry, please install {0}.'.format(name))
 1473             print('Error: {0}'.format(msg))
 1474             modulesOK = False
 1475     if not modulesOK:
 1476         exit(1)
 1477     # check mandatory modules with alternatives
 1478     if altModulesList:
 1479         altModulesOK = True
 1480         for altModules, forcedOk in altModulesList:
 1481             modulesOK = False
 1482             for altModule in altModules:
 1483                 name = altModule.split(".")[1]
 1484                 try:
 1485                     __import__(altModule)
 1486                     print("Found", name)
 1487                     modulesOK = True
 1488                     break
 1489                 except ImportError:
 1490                     pass
 1491             if not modulesOK and not forcedOk:
 1492                 altModulesOK = False
 1493                 print('Sorry, please install {0}.'
 1494                       .format(" or ".join(altModules)))
 1495         if not altModulesOK:
 1496             exit(1)
 1497     
 1498     # determine the platform dependent black list
 1499     if sys.platform.startswith(("win", "cygwin")):
 1500         PlatformBlackLists = PlatformsBlackLists["windows"]
 1501     elif sys.platform.startswith("linux"):
 1502         PlatformBlackLists = PlatformsBlackLists["linux"]
 1503     else:
 1504         PlatformBlackLists = PlatformsBlackLists["mac"]
 1505     
 1506     # check version of Qt
 1507     qtMajor = int(qVersion().split('.')[0])
 1508     qtMinor = int(qVersion().split('.')[1])
 1509     print("Qt Version: {0}".format(qVersion().strip()))
 1510     if qtMajor == 5 and qtMinor < 9:
 1511         print('Sorry, you must have Qt version 5.9.0 or better.')
 1512         exit(2)
 1513     
 1514     # check version of sip
 1515     try:
 1516         try:
 1517             from PyQt5 import sip
 1518         except ImportError:
 1519             import sip
 1520         sipVersion = sip.SIP_VERSION_STR
 1521         print("sip Version:", sipVersion.strip())
 1522         # always assume, that snapshots or dev versions are new enough
 1523         if "snapshot" not in sipVersion and "dev" not in sipVersion:
 1524             while sipVersion.count('.') < 2:
 1525                 sipVersion += '.0'
 1526             (major, minor, pat) = sipVersion.split('.')
 1527             major = int(major)
 1528             minor = int(minor)
 1529             pat = int(pat)
 1530             if (
 1531                 major < 4 or
 1532                 (major == 4 and minor < 14) or
 1533                 (major == 4 and minor == 14 and pat < 2)
 1534             ):
 1535                 print('Sorry, you must have sip 4.14.2 or higher or'
 1536                       ' a recent snapshot release.')
 1537                 exit(3)
 1538             # check for blacklisted versions
 1539             for vers in BlackLists["sip"] + PlatformBlackLists["sip"]:
 1540                 if vers == sipVersion:
 1541                     print(
 1542                         'Sorry, sip version {0} is not compatible with eric6.'
 1543                         .format(vers))
 1544                     print('Please install another version.')
 1545                     exit(3)
 1546     except (ImportError, AttributeError):
 1547         pass
 1548     
 1549     # check version of PyQt
 1550     from PyQt5.QtCore import PYQT_VERSION_STR
 1551     pyqtVersion = PYQT_VERSION_STR
 1552     print("PyQt Version:", pyqtVersion.strip())
 1553     # always assume, that snapshots or dev versions are new enough
 1554     if "snapshot" not in pyqtVersion and "dev" not in pyqtVersion:
 1555         while pyqtVersion.count('.') < 2:
 1556             pyqtVersion += '.0'
 1557         (major, minor, pat) = pyqtVersion.split('.')
 1558         major = int(major)
 1559         minor = int(minor)
 1560         pat = int(pat)
 1561         if major == 5 and minor < 9:
 1562             print('Sorry, you must have PyQt 5.9.0 or better or'
 1563                   ' a recent snapshot release.')
 1564             exit(4)
 1565         # check for blacklisted versions
 1566         for vers in BlackLists["PyQt5"] + PlatformBlackLists["PyQt5"]:
 1567             if vers == pyqtVersion:
 1568                 print('Sorry, PyQt version {0} is not compatible with eric6.'
 1569                       .format(vers))
 1570                 print('Please install another version.')
 1571                 exit(4)
 1572     
 1573     # check version of QScintilla
 1574     from PyQt5.Qsci import QSCINTILLA_VERSION_STR
 1575     scintillaVersion = QSCINTILLA_VERSION_STR
 1576     print("QScintilla Version:", QSCINTILLA_VERSION_STR.strip())
 1577     # always assume, that snapshots or dev versions are new enough
 1578     if "snapshot" not in scintillaVersion and "dev" not in scintillaVersion:
 1579         while scintillaVersion.count('.') < 2:
 1580             scintillaVersion += '.0'
 1581         (major, minor, pat) = scintillaVersion.split('.')
 1582         major = int(major)
 1583         minor = int(minor)
 1584         pat = int(pat)
 1585         if major < 2 or (major == 2 and minor < 9):
 1586             print('Sorry, you must have QScintilla 2.9.0 or higher or'
 1587                   ' a recent snapshot release.')
 1588             exit(5)
 1589         # check for blacklisted versions
 1590         for vers in (
 1591             BlackLists["QScintilla2"] +
 1592             PlatformBlackLists["QScintilla2"]
 1593         ):
 1594             if vers == scintillaVersion:
 1595                 print(
 1596                     'Sorry, QScintilla2 version {0} is not compatible with'
 1597                     ' eric6.'.format(vers))
 1598                 print('Please install another version.')
 1599                 exit(5)
 1600     
 1601     # print version info for additional modules
 1602     try:
 1603         print("PyQtChart:", QtChart.PYQT_CHART_VERSION_STR)
 1604     except (NameError, AttributeError):
 1605         pass
 1606     try:
 1607         from PyQt5 import QtWebEngine
 1608         print("PyQtWebEngine.", QtWebEngine.PYQT_WEBENGINE_VERSION_STR)
 1609     except (ImportError, AttributeError):
 1610         pass
 1611     
 1612     print("All dependencies ok.")
 1613     print()
 1614 
 1615 
 1616 def __pyName(py_dir, py_file):
 1617     """
 1618     Local function to create the Python source file name for the compiled
 1619     .ui file.
 1620     
 1621     @param py_dir suggested name of the directory (string)
 1622     @param py_file suggested name for the compile source file (string)
 1623     @return tuple of directory name (string) and source file name (string)
 1624     """
 1625     return py_dir, "Ui_{0}".format(py_file)
 1626 
 1627 
 1628 def compileUiFiles():
 1629     """
 1630     Compile the .ui files to Python sources.
 1631     """
 1632     from PyQt5.uic import compileUiDir
 1633     compileUiDir(eric6SourceDir, True, __pyName)
 1634 
 1635 
 1636 def prepareInfoFile(fileName):
 1637     """
 1638     Function to prepare an Info.py file when installing from source.
 1639     
 1640     @param fileName name of the Python file containing the info (string)
 1641     """
 1642     if not fileName:
 1643         return
 1644     
 1645     try:
 1646         os.rename(fileName, fileName + ".orig")
 1647     except EnvironmentError:
 1648         pass
 1649     try:
 1650         hgOut = subprocess.check_output(["hg", "identify", "-i"])   # secok
 1651         hgOut = hgOut.decode()
 1652     except (OSError, subprocess.CalledProcessError):
 1653         hgOut = ""
 1654     if hgOut:
 1655         hgOut = hgOut.strip()
 1656         if hgOut.endswith("+"):
 1657             hgOut = hgOut[:-1]
 1658         f = open(fileName + ".orig", "r", encoding="utf-8")
 1659         text = f.read()
 1660         f.close()
 1661         text = (
 1662             text.replace("@@REVISION@@", hgOut)
 1663             .replace("@@VERSION@@", "rev_" + hgOut)
 1664         )
 1665         copyToFile(fileName, text)
 1666     else:
 1667         shutil.copy(fileName + ".orig", fileName)
 1668 
 1669 
 1670 def getWinregEntry(name, path):
 1671     """
 1672     Function to get an entry from the Windows Registry.
 1673     
 1674     @param name variable name
 1675     @type str
 1676     @param path registry path of the variable
 1677     @type str
 1678     @return value of requested registry variable
 1679     @rtype any
 1680     """
 1681     try:
 1682         import winreg
 1683     except ImportError:
 1684         return None
 1685     
 1686     try:
 1687         registryKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0,
 1688                                      winreg.KEY_READ)
 1689         value, _ = winreg.QueryValueEx(registryKey, name)
 1690         winreg.CloseKey(registryKey)
 1691         return value
 1692     except WindowsError:
 1693         return None
 1694 
 1695 
 1696 def createWindowsShortcut(linkPath, targetPath, iconPath):
 1697     """
 1698     Create Windows shortcut.
 1699     
 1700     @param linkPath path of the shortcut file
 1701     @type str
 1702     @param targetPath path the shortcut shall point to
 1703     @type str
 1704     @param iconPath path of the icon file
 1705     @type str
 1706     """
 1707     from win32com.client import Dispatch
 1708     from pywintypes import com_error
 1709     
 1710     try:
 1711         shell = Dispatch('WScript.Shell')
 1712         shortcut = shell.CreateShortCut(linkPath)
 1713         shortcut.Targetpath = targetPath
 1714         shortcut.WorkingDirectory = os.path.dirname(targetPath)
 1715         shortcut.IconLocation = iconPath
 1716         shortcut.save()
 1717     except com_error:
 1718         # maybe restrictions prohibited link creation
 1719         pass
 1720 
 1721 
 1722 def windowsDesktopNames():
 1723     """
 1724     Function to generate the link names for the Windows Desktop.
 1725     
 1726     @return list of desktop link names
 1727     @rtype list of str
 1728     """
 1729     return [e[0] for e in windowsDesktopEntries()]
 1730 
 1731 
 1732 def windowsDesktopEntries():
 1733     """
 1734     Function to generate data for the Windows Desktop links.
 1735     
 1736     @return list of tuples containing the desktop link name,
 1737         the link target and the icon target
 1738     @rtype list of tuples of (str, str, str)
 1739     """
 1740     global cfg
 1741     
 1742     majorVersion, minorVersion = sys.version_info[:2]
 1743     entriesTemplates = [
 1744         ("eric6 (Python {0}.{1}).lnk",
 1745          os.path.join(cfg["bindir"], "eric6.cmd"),
 1746          os.path.join(cfg["ericPixDir"], "eric6.ico")),
 1747         ("eric6 Browser (Python {0}.{1}).lnk",
 1748          os.path.join(cfg["bindir"], "eric6_browse.cmd"),
 1749          os.path.join(cfg["ericPixDir"], "ericWeb48.ico")),
 1750     ]
 1751     
 1752     return [
 1753         (e[0].format(majorVersion, minorVersion), e[1], e[2])
 1754         for e in entriesTemplates
 1755     ]
 1756 
 1757 
 1758 def windowsProgramsEntry():
 1759     """
 1760     Function to generate the name of the Start Menu top entry.
 1761     
 1762     @return name of the Start Menu top entry
 1763     @rtype str
 1764     """
 1765     majorVersion, minorVersion = sys.version_info[:2]
 1766     return "eric6 (Python {0}.{1})".format(majorVersion, minorVersion)
 1767 
 1768 
 1769 def main(argv):
 1770     """
 1771     The main function of the script.
 1772 
 1773     @param argv list of command line arguments
 1774     @type list of str
 1775     """
 1776     import getopt
 1777 
 1778     # Parse the command line.
 1779     global progName, modDir, doCleanup, doCompile, distDir, cfg, apisDir
 1780     global sourceDir, eric6SourceDir, configName
 1781     global macAppBundlePath, macAppBundleName, macPythonExe
 1782     global installApis, doCleanDesktopLinks, yes2All
 1783     
 1784     if sys.version_info < (3, 5, 0) or sys.version_info > (3, 99, 99):
 1785         print('Sorry, eric6 requires at least Python 3.5 for running.')
 1786         exit(5)
 1787     
 1788     progName = os.path.basename(argv[0])
 1789     
 1790     if os.path.dirname(argv[0]):
 1791         os.chdir(os.path.dirname(argv[0]))
 1792     
 1793     initGlobals()
 1794 
 1795     try:
 1796         if sys.platform.startswith(("win", "cygwin")):
 1797             optlist, args = getopt.getopt(
 1798                 argv[1:], "chxza:b:d:f:",
 1799                 ["help", "no-apis", "yes"])
 1800         elif sys.platform == "darwin":
 1801             optlist, args = getopt.getopt(
 1802                 argv[1:], "chxza:b:d:f:i:m:n:p:",
 1803                 ["help", "no-apis", "yes"])
 1804         else:
 1805             optlist, args = getopt.getopt(
 1806                 argv[1:], "chxza:b:d:f:i:",
 1807                 ["help", "no-apis", "yes"])
 1808     except getopt.GetoptError as err:
 1809         print(err)
 1810         usage()
 1811 
 1812     global platBinDir
 1813     
 1814     depChecks = True
 1815 
 1816     for opt, arg in optlist:
 1817         if opt in ["-h", "--help"]:
 1818             usage(0)
 1819         elif opt == "-a":
 1820             apisDir = arg
 1821         elif opt == "-b":
 1822             platBinDir = arg
 1823         elif opt == "-d":
 1824             modDir = arg
 1825         elif opt == "-i":
 1826             distDir = os.path.normpath(arg)
 1827         elif opt == "-x":
 1828             depChecks = False
 1829         elif opt == "-c":
 1830             doCleanup = False
 1831         elif opt == "-z":
 1832             doCompile = False
 1833         elif opt == "-f":
 1834             try:
 1835                 exec(compile(open(arg).read(), arg, 'exec'), globals())
 1836                 # secok
 1837                 if len(cfg) != configLength:
 1838                     print("The configuration dictionary in '{0}' is incorrect."
 1839                           " Aborting".format(arg))
 1840                     exit(6)
 1841             except Exception:
 1842                 cfg = {}
 1843         elif opt == "-m":
 1844             macAppBundleName = arg
 1845         elif opt == "-n":
 1846             macAppBundlePath = arg
 1847         elif opt == "-p":
 1848             macPythonExe = arg
 1849         elif opt == "--no-apis":
 1850             installApis = False
 1851         elif opt == "--clean-desktop":
 1852             doCleanDesktopLinks = True
 1853         elif opt == "--yes":
 1854             yes2All = True
 1855     
 1856     infoName = ""
 1857     installFromSource = not os.path.isdir(sourceDir)
 1858     
 1859     # check dependencies
 1860     if depChecks:
 1861         doDependancyChecks()
 1862     
 1863     # cleanup source if installing from source
 1864     if installFromSource:
 1865         print("Cleaning up source ...")
 1866         sourceDir = os.path.abspath("..")
 1867         eric6SourceDir = os.path.join(sourceDir, "eric6")
 1868         cleanupSource(eric6SourceDir)
 1869         print()
 1870     
 1871     if installFromSource:
 1872         sourceDir = os.path.abspath("..")
 1873         eric6SourceDir = os.path.join(sourceDir, "eric6")
 1874         configName = os.path.join(eric6SourceDir, "eric6config.py")
 1875         if os.path.exists(os.path.join(sourceDir, ".hg")):
 1876             # we are installing from source with repo
 1877             infoName = os.path.join(eric6SourceDir, "UI", "Info.py")
 1878             prepareInfoFile(infoName)
 1879     
 1880     if len(cfg) == 0:
 1881         createInstallConfig()
 1882     
 1883     # get rid of development config file, if it exists
 1884     try:
 1885         if installFromSource:
 1886             os.rename(configName, configName + ".orig")
 1887             configNameC = configName + 'c'
 1888             if os.path.exists(configNameC):
 1889                 os.remove(configNameC)
 1890         os.remove(configName)
 1891     except EnvironmentError:
 1892         pass
 1893     
 1894     # cleanup old installation
 1895     print("Cleaning up old installation ...")
 1896     try:
 1897         if doCleanup:
 1898             if distDir:
 1899                 shutil.rmtree(distDir, True)
 1900             else:
 1901                 cleanUp()
 1902     except (IOError, OSError) as msg:
 1903         sys.stderr.write('Error: {0}\nTry install as root.\n'.format(msg))
 1904         exit(7)
 1905 
 1906     # Create a config file and delete the default one
 1907     print("\nCreating configuration file ...")
 1908     createConfig()
 1909 
 1910     # Compile .ui files
 1911     print("\nCompiling user interface files ...")
 1912     # step 1: remove old Ui_*.py files
 1913     for root, _, files in os.walk(sourceDir):
 1914         for file in [f for f in files if fnmatch.fnmatch(f, 'Ui_*.py')]:
 1915             os.remove(os.path.join(root, file))
 1916     # step 2: compile the forms
 1917     compileUiFiles()
 1918     
 1919     if doCompile:
 1920         print("\nCompiling source files ...")
 1921         skipRe = re.compile(r"DebugClients[\\/]Python[\\/]")
 1922         sys.stdout = io.StringIO()
 1923         if distDir:
 1924             compileall.compile_dir(
 1925                 eric6SourceDir,
 1926                 ddir=os.path.join(distDir, modDir, cfg['ericDir']),
 1927                 rx=skipRe,
 1928                 quiet=True)
 1929             py_compile.compile(
 1930                 configName,
 1931                 dfile=os.path.join(distDir, modDir, "eric6config.py"))
 1932         else:
 1933             compileall.compile_dir(
 1934                 eric6SourceDir,
 1935                 ddir=os.path.join(modDir, cfg['ericDir']),
 1936                 rx=skipRe,
 1937                 quiet=True)
 1938             py_compile.compile(configName,
 1939                                dfile=os.path.join(modDir, "eric6config.py"))
 1940         sys.stdout = sys.__stdout__
 1941     print("\nInstalling eric6 ...")
 1942     res = installEric()
 1943     
 1944     # do some cleanup
 1945     try:
 1946         if installFromSource:
 1947             os.remove(configName)
 1948             configNameC = configName + 'c'
 1949             if os.path.exists(configNameC):
 1950                 os.remove(configNameC)
 1951             os.rename(configName + ".orig", configName)
 1952     except EnvironmentError:
 1953         pass
 1954     try:
 1955         if installFromSource and infoName:
 1956             os.remove(infoName)
 1957             infoNameC = infoName + 'c'
 1958             if os.path.exists(infoNameC):
 1959                 os.remove(infoNameC)
 1960             os.rename(infoName + ".orig", infoName)
 1961     except EnvironmentError:
 1962         pass
 1963     
 1964     print("\nInstallation complete.")
 1965     print()
 1966     
 1967     exit(res)
 1968     
 1969     
 1970 if __name__ == "__main__":
 1971     try:
 1972         main(sys.argv)
 1973     except SystemExit:
 1974         raise
 1975     except Exception:
 1976         print("""An internal error occured.  Please report all the output"""
 1977               """ of the program,\nincluding the following traceback, to"""
 1978               """ eric-bugs@eric-ide.python-projects.org.\n""")
 1979         raise
 1980 
 1981 #
 1982 # eflag: noqa = M801