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): |
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", |
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): |
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: |