scripts/install.py

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

eric ide

mercurial