scripts/install.py

branch
eric7-maintenance
changeset 10814
ba20efe10336
parent 10733
d96c69a235fc
parent 10801
5859861e7a1f
child 10873
4e8e63df7893
equal deleted inserted replaced
10734:2b015db9761a 10814:ba20efe10336
28 import subprocess # secok 28 import subprocess # secok
29 import sys 29 import sys
30 import sysconfig 30 import sysconfig
31 import time 31 import time
32 32
33 from functools import partial
34
35 # Define the globals. 33 # Define the globals.
36 currDir = os.getcwd() 34 currDir = os.getcwd()
37 modDir = None 35 modDir = None
38 pyModDir = None 36 pyModDir = None
39 platBinDir = None 37 platBinDir = None
45 forceCleanDesktopLinks = False 43 forceCleanDesktopLinks = False
46 doCompile = True 44 doCompile = True
47 yes2All = False 45 yes2All = False
48 withPyqt6Tools = False 46 withPyqt6Tools = False
49 verbose = False 47 verbose = False
48 proxy = None
50 cfg = {} 49 cfg = {}
51 progLanguages = ["MicroPython", "Python3", "QSS"] 50 progLanguages = ["MicroPython", "Python3", "QSS"]
52 sourceDir = "eric" 51 sourceDir = "eric"
53 eric7SourceDir = "" 52 eric7SourceDir = ""
54 configName = "eric7config.py" 53 configName = "eric7config.py"
705 Actually perform the installation steps. 704 Actually perform the installation steps.
706 705
707 @return result code 706 @return result code
708 @rtype int 707 @rtype int
709 """ 708 """
710 global distDir, doCleanup, cfg, progLanguages, sourceDir, configName 709 global distDir, cfg, progLanguages, sourceDir, configName
711 global installApis 710 global installApis
712 711
713 # Create the platform specific wrappers. 712 # Create the platform specific wrappers.
714 scriptsDir = "install_scripts" 713 scriptsDir = "install_scripts"
715 if not os.path.isdir(scriptsDir): 714 if not os.path.isdir(scriptsDir):
1458 without asking the user 1457 without asking the user
1459 @type bool 1458 @type bool
1460 @return flag indicating a successful installation 1459 @return flag indicating a successful installation
1461 @rtype bool 1460 @rtype bool
1462 """ 1461 """
1463 global yes2All 1462 global yes2All, proxy
1464 1463
1465 ok = False 1464 ok = False
1466 if yes2All or force: 1465 if yes2All or force:
1467 answer = "y" 1466 answer = "y"
1468 else: 1467 else:
1472 ), 1471 ),
1473 end=" ", 1472 end=" ",
1474 ) 1473 )
1475 answer = input() # secok 1474 answer = input() # secok
1476 if answer in ("", "Y", "y"): 1475 if answer in ("", "Y", "y"):
1477 exitCode = subprocess.run( # secok 1476 args = [
1478 [ 1477 sys.executable,
1479 sys.executable, 1478 "-m",
1480 "-m", 1479 "pip",
1481 "pip", 1480 "install",
1482 "install", 1481 "--prefer-binary",
1483 "--prefer-binary", 1482 "--upgrade",
1484 "--upgrade", 1483 ]
1485 packageName, 1484 if proxy:
1486 ] 1485 args.append(f"--proxy={proxy}")
1487 ).returncode 1486 args.append(packageName)
1487 exitCode = subprocess.run(args).returncode # secok
1488 ok = exitCode == 0 1488 ok = exitCode == 0
1489 1489
1490 return ok 1490 return ok
1491 1491
1492 1492
1495 Check, if pip is outdated. 1495 Check, if pip is outdated.
1496 1496
1497 @return flag indicating an outdated pip 1497 @return flag indicating an outdated pip
1498 @rtype bool 1498 @rtype bool
1499 """ 1499 """
1500 global proxy
1501
1500 try: 1502 try:
1503 args = [
1504 sys.executable,
1505 "-m",
1506 "pip",
1507 "list",
1508 "--outdated",
1509 "--format=json",
1510 ]
1511 if proxy:
1512 args.append(f"--proxy={proxy}")
1501 pipOut = ( 1513 pipOut = (
1502 subprocess.run( # secok 1514 subprocess.run( # secok
1503 [sys.executable, "-m", "pip", "list", "--outdated", "--format=json"], 1515 args,
1504 check=True, 1516 check=True,
1505 capture_output=True, 1517 capture_output=True,
1506 text=True, 1518 text=True,
1507 ) 1519 )
1508 .stdout.strip() 1520 .stdout.strip()
1529 1541
1530 def updatePip(): 1542 def updatePip():
1531 """ 1543 """
1532 Update the installed pip package. 1544 Update the installed pip package.
1533 """ 1545 """
1534 global yes2All 1546 global yes2All, proxy
1535 1547
1536 if yes2All: 1548 if yes2All:
1537 answer = "y" 1549 answer = "y"
1538 else: 1550 else:
1539 print("Shall 'pip' be updated (recommended)? (Y/n)", end=" ") 1551 print("Shall 'pip' be updated (recommended)? (Y/n)", end=" ")
1540 answer = input() # secok 1552 answer = input() # secok
1541 if answer in ("", "Y", "y"): 1553 if answer in ("", "Y", "y"):
1542 subprocess.run( # secok 1554 args = [
1543 [sys.executable, "-m", "pip", "install", "--upgrade", "pip"] 1555 sys.executable,
1544 ) 1556 "-m",
1557 "pip",
1558 "install",
1559 "--upgrade",
1560 ]
1561 if proxy:
1562 args.append(f"--proxy={proxy}")
1563 args.append("pip")
1564 subprocess.run(args) # secok
1545 1565
1546 1566
1547 def versionToStr(version): 1567 def versionToStr(version):
1548 """ 1568 """
1549 Function to convert a version number into a version string. 1569 Function to convert a version number into a version string.
1802 # check version of Qt 1822 # check version of Qt
1803 # =================== 1823 # ===================
1804 qtMajor = int(qVersion().split(".")[0]) 1824 qtMajor = int(qVersion().split(".")[0])
1805 qtMinor = int(qVersion().split(".")[1]) 1825 qtMinor = int(qVersion().split(".")[1])
1806 print("Qt6: {0}".format(qVersion().strip())) 1826 print("Qt6: {0}".format(qVersion().strip()))
1807 if qtMajor == 6 and qtMinor < 1: 1827 if qtMajor == 6 and qtMinor < 2:
1808 print("Sorry, you must have Qt version 6.1.0 or better.") 1828 print("Sorry, you must have Qt version 6.2.0 or better.")
1809 exit(2) 1829 exit(2)
1810 1830
1811 # check version of sip 1831 # check version of sip
1812 # ==================== 1832 # ====================
1813 with contextlib.suppress(ImportError, AttributeError): 1833 with contextlib.suppress(ImportError, AttributeError):
1905 print() 1925 print()
1906 print("All dependencies ok.") 1926 print("All dependencies ok.")
1907 print() 1927 print()
1908 1928
1909 1929
1910 def __pyName(py_dir, py_file):
1911 """
1912 Local function to create the Python source file name for the compiled
1913 .ui file.
1914
1915 @param py_dir suggested name of the directory
1916 @type str
1917 @param py_file suggested name for the compile source file
1918 @type str
1919 @return tuple of directory name and source file name
1920 @rtype tuple of (str, str)
1921 """
1922 return py_dir, "Ui_{0}".format(py_file)
1923
1924
1925 def __compileOneUi(ui_path, mapFunc=None):
1926 """
1927 Function to compile a single form file to Python code.
1928
1929 @param ui_path path of the Qt form file
1930 @type str
1931 @param mapFunc function to change directory and/or name of the resulting Python file
1932 (defaults to None)
1933 @type func (optional)
1934 """
1935 from PyQt6.uic import compileUi # noqa: I102
1936
1937 py_dir, py_file = os.path.split(ui_path[:-3] + ".py")
1938
1939 # Allow the caller to change the name of the .py file or generate
1940 # it in a different directory.
1941 if mapFunc is not None:
1942 py_dir, py_file = mapFunc(py_dir, py_file)
1943
1944 # Make sure the destination directory exists.
1945 os.makedirs(py_dir, exist_ok=True)
1946
1947 py_path = os.path.join(py_dir, py_file)
1948
1949 with open(py_path, "w", encoding="utf-8") as py_file:
1950 compileUi(ui_path, py_file, execute=False, indent=4)
1951
1952
1953 def compileUiDir(root, recurse=False, mapFunc=None, workers=1):
1954 """
1955 Function to compile all Qt form files of a directory or directory tree
1956 to Python code.
1957
1958 @param root directory to scan for Qt form files (i.e. files ending with '.ui'
1959 @type str
1960 @param recurse flag indicating to recurse into sub-directories (defaults to False)
1961 @type bool (optional)
1962 @param mapFunc function to change directory and/or name of the resulting Python file
1963 (defaults to None)
1964 @type func (optional)
1965 @param workers number of worker processes to be used to compile (defaults to 1)
1966 @type int (optional)
1967 """
1968 if recurse:
1969 ui_files = []
1970 for rootDir, _, files in os.walk(root):
1971 ui_files.extend(
1972 os.path.join(rootDir, ui) for ui in files if ui.endswith(".ui")
1973 )
1974 else:
1975 ui_files = [
1976 os.path.join(root, ui)
1977 for ui in os.listdir(root)
1978 if os.path.isfile(os.path.join(root, ui) and ui.endswith(".ui"))
1979 ]
1980
1981 ProcessPoolExecutor = None
1982 if workers != 1:
1983 try:
1984 from concurrent.futures import ProcessPoolExecutor # noqa: I101, I103
1985 except NotImplementedError:
1986 workers = 1
1987
1988 if workers != 1 and ProcessPoolExecutor is not None:
1989 # If workers == 0, let ProcessPoolExecutor determine worker count.
1990 workers = workers or None
1991 with ProcessPoolExecutor(max_workers=workers) as executor:
1992 executor.map(
1993 partial(__compileOneUi, mapFunc=mapFunc),
1994 ui_files,
1995 )
1996 else:
1997 for ui_file in ui_files:
1998 __compileOneUi(ui_file, mapFunc=mapFunc)
1999
2000
2001 def prepareInfoFile(fileName): 1930 def prepareInfoFile(fileName):
2002 """ 1931 """
2003 Function to prepare an Info.py file when installing from source. 1932 Function to prepare an Info.py file when installing from source.
2004 1933
2005 @param fileName name of the Python file containing the info 1934 @param fileName name of the Python file containing the info
2165 @rtype argparse.ArgumentParser 2094 @rtype argparse.ArgumentParser
2166 """ 2095 """
2167 parser = argparse.ArgumentParser( 2096 parser = argparse.ArgumentParser(
2168 description="Install eric7 from the source code tree.", 2097 description="Install eric7 from the source code tree.",
2169 epilog="The file given to the -f option must be valid Python code defining a" 2098 epilog="The file given to the -f option must be valid Python code defining a"
2170 "dictionary called 'cfg' with the keys 'ericDir', 'ericPixDir', ericIconDir'," 2099 " dictionary called 'cfg' with the keys 'ericDir', 'ericPixDir', ericIconDir',"
2171 " 'ericDTDDir', 'ericCSSDir', 'ericStylesDir', 'ericThemesDir', ericDocDir'," 2100 " 'ericDTDDir', 'ericCSSDir', 'ericStylesDir', 'ericThemesDir', ericDocDir',"
2172 " ericExamplesDir', ericTranslationsDir', 'ericTemplatesDir'," 2101 " ericExamplesDir', ericTranslationsDir', 'ericTemplatesDir',"
2173 " 'ericCodeTemplatesDir', ericOthersDir','bindir', 'mdir' and 'apidir." 2102 " 'ericCodeTemplatesDir', ericOthersDir','bindir', 'mdir' and 'apidir."
2174 "These define the directories for the installation of the various parts of" 2103 " These define the directories for the installation of the various parts of"
2175 " eric.", 2104 " eric.",
2176 ) 2105 )
2177 2106
2178 parser.add_argument( 2107 parser.add_argument(
2179 "-a", 2108 "-a",
2275 parser.add_argument( 2204 parser.add_argument(
2276 "--with-tools", 2205 "--with-tools",
2277 action="store_true", 2206 action="store_true",
2278 help="install the 'qt6-applications' package", 2207 help="install the 'qt6-applications' package",
2279 ) 2208 )
2209 parser.add_argument(
2210 "--proxy",
2211 default=None,
2212 metavar="url",
2213 help="HTTP proxy url will be used with pip (default: no proxy used)",
2214 )
2280 2215
2281 return parser 2216 return parser
2282 2217
2283 2218
2284 def main(argv): 2219 def main(argv):
2289 @type list of str 2224 @type list of str
2290 """ 2225 """
2291 global modDir, doCleanup, doCompile, distDir, cfg, apisDir 2226 global modDir, doCleanup, doCompile, distDir, cfg, apisDir
2292 global sourceDir, eric7SourceDir, configName, platBinDir 2227 global sourceDir, eric7SourceDir, configName, platBinDir
2293 global macAppBundlePath, macAppBundleName, macPythonExe 2228 global macAppBundlePath, macAppBundleName, macPythonExe
2294 global installApis, doCleanDesktopLinks, yes2All 2229 global installApis, doCleanDesktopLinks, yes2All, proxy
2295 global createInstallInfoFile, installCwd 2230 global createInstallInfoFile, installCwd
2296 global withPyqt6Tools 2231 global withPyqt6Tools
2297 global verbose 2232 global verbose
2298 2233
2299 if sys.version_info < (3, 8, 0) or sys.version_info > (3, 99, 99): 2234 if sys.version_info < (3, 8, 0) or sys.version_info > (3, 99, 99):
2316 depChecks = args.x 2251 depChecks = args.x
2317 doCleanup = args.c 2252 doCleanup = args.c
2318 doCompile = args.z 2253 doCompile = args.z
2319 installApis = not args.no_apis 2254 installApis = not args.no_apis
2320 yes2All = args.yes 2255 yes2All = args.yes
2256 proxy = args.proxy
2321 withPyqt6Tools = args.with_tools 2257 withPyqt6Tools = args.with_tools
2322 createInstallInfoFile = not args.no_info 2258 createInstallInfoFile = not args.no_info
2323 verbose = args.verbose 2259 verbose = args.verbose
2324 if sys.platform == "darwin": 2260 if sys.platform == "darwin":
2325 macAppBundleName = args.m 2261 macAppBundleName = args.m
2411 # Create an install info file 2347 # Create an install info file
2412 print("Creating an install info file ...", end="", flush=True) 2348 print("Creating an install info file ...", end="", flush=True)
2413 createInstallInfo() 2349 createInstallInfo()
2414 print(" Done") 2350 print(" Done")
2415 2351
2416 # Compile .ui files
2417 print("Compiling user interface files ...", end="", flush=True)
2418 # step 1: remove old Ui_*.py files
2419 for root, _, files in os.walk(sourceDir):
2420 for file in [f for f in files if fnmatch.fnmatch(f, "Ui_*.py")]:
2421 os.remove(os.path.join(root, file))
2422 # step 2: compile the forms
2423 compileUiDir(eric7SourceDir, recurse=True, mapFunc=__pyName, workers=0)
2424 print(" Done")
2425
2426 if doCompile: 2352 if doCompile:
2427 print("Compiling source files ...", end="", flush=True) 2353 print("Compiling source files ...", end="", flush=True)
2428 skipRe = re.compile(r"DebugClients[\\/]Python[\\/]") 2354 skipRe = re.compile(r"DebugClients[\\/]Python[\\/]")
2429 sys.stdout = io.StringIO() 2355 sys.stdout = io.StringIO()
2430 if distDir: 2356 if distDir:

eric ide

mercurial