Fix updater interface: pass desktop_arch_path in args

This also adds a lot of type hints. I refrained from changing a lot
of 'str' variables to Path variables, but eventually I think they
will need to become Paths
This commit is contained in:
Dave Dalcino
2022-07-27 22:13:03 -07:00
parent 861a3d6b61
commit 94ff9f44f7
2 changed files with 30 additions and 17 deletions

View File

@@ -20,9 +20,9 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import logging import logging
import os import os
import pathlib
import subprocess import subprocess
from logging import getLogger from logging import getLogger
from pathlib import Path
from typing import Optional from typing import Optional
import patch import patch
@@ -41,13 +41,13 @@ def unpatched_path(os_name: str, final_component: str) -> str:
class Updater: class Updater:
def __init__(self, prefix: pathlib.Path, logger): def __init__(self, prefix: Path, logger):
self.logger = logger self.logger = logger
self.prefix = prefix self.prefix = prefix
self.qmake_path = None self.qmake_path = None
self.qconfigs = {} self.qconfigs = {}
def _patch_binfile(self, file: pathlib.Path, key: bytes, newpath: bytes): def _patch_binfile(self, file: Path, key: bytes, newpath: bytes):
"""Patch binary file with key/value""" """Patch binary file with key/value"""
st = file.stat() st = file.stat()
data = file.read_bytes() data = file.read_bytes()
@@ -62,7 +62,7 @@ class Updater:
file.write_bytes(data) file.write_bytes(data)
os.chmod(str(file), st.st_mode) os.chmod(str(file), st.st_mode)
def _append_string(self, file: pathlib.Path, val: str): def _append_string(self, file: Path, val: str):
"""Append string to file""" """Append string to file"""
st = file.stat() st = file.stat()
data = file.read_text("UTF-8") data = file.read_text("UTF-8")
@@ -70,7 +70,7 @@ class Updater:
file.write_text(data, "UTF-8") file.write_text(data, "UTF-8")
os.chmod(str(file), st.st_mode) os.chmod(str(file), st.st_mode)
def _patch_textfile(self, file: pathlib.Path, old: str, new: str): def _patch_textfile(self, file: Path, old: str, new: str):
st = file.stat() st = file.stat()
data = file.read_text("UTF-8") data = file.read_text("UTF-8")
data = data.replace(old, new) data = data.replace(old, new)
@@ -167,10 +167,9 @@ class Updater:
newpath=bytes(str(self.prefix), "UTF-8"), newpath=bytes(str(self.prefix), "UTF-8"),
) )
def patch_qmake_script(self, base_dir, qt_version: str, os_name): def patch_qmake_script(self, base_dir, qt_version: str, os_name: str, desktop_arch_dir: str):
arch_dir = default_desktop_arch_dir(os_name, qt_version)
sep = "\\" if os_name == "windows" else "/" sep = "\\" if os_name == "windows" else "/"
patched = sep.join([base_dir, qt_version, arch_dir, "bin"]) patched = sep.join([base_dir, qt_version, desktop_arch_dir, "bin"])
unpatched = unpatched_path(os_name, "bin") unpatched = unpatched_path(os_name, "bin")
qmake_path = self.prefix / "bin" / ("qmake.bat" if os_name == "windows" else "qmake") qmake_path = self.prefix / "bin" / ("qmake.bat" if os_name == "windows" else "qmake")
self.logger.info(f"Patching {qmake_path}") self.logger.info(f"Patching {qmake_path}")
@@ -211,7 +210,7 @@ class Updater:
f.write("cd /D {}\n".format(os.path.join(base_dir, qt_version, arch_dir))) f.write("cd /D {}\n".format(os.path.join(base_dir, qt_version, arch_dir)))
f.write("echo Remember to call vcvarsall.bat to complete environment setup!\n") f.write("echo Remember to call vcvarsall.bat to complete environment setup!\n")
def set_license(self, base_dir, qt_version, arch_dir): def set_license(self, base_dir: str, qt_version: str, arch_dir: str):
"""Update qtconfig.pri as OpenSource""" """Update qtconfig.pri as OpenSource"""
with open(os.path.join(base_dir, qt_version, arch_dir, "mkspecs", "qconfig.pri"), "r+") as f: with open(os.path.join(base_dir, qt_version, arch_dir, "mkspecs", "qconfig.pri"), "r+") as f:
lines = f.readlines() lines = f.readlines()
@@ -224,21 +223,27 @@ class Updater:
line = "QT_LICHECK =\n" line = "QT_LICHECK =\n"
f.write(line) f.write(line)
def patch_target_qt_conf(self, base_dir, qt_version, arch_dir, os_name): def patch_target_qt_conf(self, base_dir: str, qt_version: str, arch_dir: str, os_name: str, desktop_arch_dir: str):
target_qt_conf = self.prefix / "bin" / "target_qt.conf" target_qt_conf = self.prefix / "bin" / "target_qt.conf"
old_targetprefix = f'Prefix={unpatched_path(os_name, "target")}' old_targetprefix = f'Prefix={unpatched_path(os_name, "target")}'
new_hostprefix = f"HostPrefix=../../{default_desktop_arch_dir(os_name, qt_version)}" new_hostprefix = f"HostPrefix=../../{desktop_arch_dir}"
new_targetprefix = "Prefix={}".format(str(pathlib.Path(base_dir).joinpath(qt_version, arch_dir, "target"))) new_targetprefix = "Prefix={}".format(str(Path(base_dir).joinpath(qt_version, arch_dir, "target")))
new_hostdata = "HostData=../{}".format(arch_dir) new_hostdata = "HostData=../{}".format(arch_dir)
self._patch_textfile(target_qt_conf, old_targetprefix, new_targetprefix) self._patch_textfile(target_qt_conf, old_targetprefix, new_targetprefix)
self._patch_textfile(target_qt_conf, "HostPrefix=../../", new_hostprefix) self._patch_textfile(target_qt_conf, "HostPrefix=../../", new_hostprefix)
self._patch_textfile(target_qt_conf, "HostData=target", new_hostdata) self._patch_textfile(target_qt_conf, "HostData=target", new_hostdata)
@classmethod @classmethod
def update(cls, target: TargetConfig, base_dir: str): def update(cls, target: TargetConfig, base_path: Path, installed_desktop_arch_dir: Optional[str]):
""" """
Make Qt configuration files, qt.conf and qtconfig.pri. Make Qt configuration files, qt.conf and qtconfig.pri.
And update pkgconfig and patch Qt5Core and qmake And update pkgconfig and patch Qt5Core and qmake
:param installed_desktop_arch_dir: This is the path to a desktop Qt installation, like `Qt/6.3.0/mingw_win64`.
This may or may not contain an actual desktop Qt installation.
If it does not, the Updater will patch files in a mobile Qt installation
that point to this directory, and this installation will be non-functional
until the user installs a desktop Qt in this directory.
""" """
logger = getLogger("aqt.updater") logger = getLogger("aqt.updater")
arch = target.arch arch = target.arch
@@ -246,8 +251,9 @@ class Updater:
os_name = target.os_name os_name = target.os_name
version_dir = dir_for_version(version) version_dir = dir_for_version(version)
arch_dir = QtRepoProperty.get_arch_dir_name(os_name, arch, version) arch_dir = QtRepoProperty.get_arch_dir_name(os_name, arch, version)
base_dir = str(base_path)
try: try:
prefix = pathlib.Path(base_dir) / version_dir / arch_dir prefix = base_path / version_dir / arch_dir
updater = Updater(prefix, logger) updater = Updater(prefix, logger)
updater.set_license(base_dir, version_dir, arch_dir) updater.set_license(base_dir, version_dir, arch_dir)
if target.arch not in [ if target.arch not in [
@@ -274,8 +280,14 @@ class Updater:
elif version in SimpleSpec(">=5.0,<6.0"): elif version in SimpleSpec(">=5.0,<6.0"):
updater.patch_qmake() updater.patch_qmake()
else: # qt6 non-desktop else: # qt6 non-desktop
updater.patch_qmake_script(base_dir, version_dir, target.os_name) desktop_arch_dir = (
updater.patch_target_qt_conf(base_dir, version_dir, arch_dir, target.os_name) installed_desktop_arch_dir
if installed_desktop_arch_dir is not None
else default_desktop_arch_dir(os_name, version)
)
updater.patch_qmake_script(base_dir, version_dir, target.os_name, desktop_arch_dir)
updater.patch_target_qt_conf(base_dir, version_dir, arch_dir, target.os_name, desktop_arch_dir)
except IOError as e: except IOError as e:
raise UpdaterError(f"Updater caused an IO error: {e}") from e raise UpdaterError(f"Updater caused an IO error: {e}") from e

View File

@@ -1,4 +1,5 @@
import re import re
from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
import pytest import pytest
@@ -58,7 +59,7 @@ def test_updater_update_license_io_error(monkeypatch, target_config: TargetConfi
with pytest.raises(UpdaterError) as err: with pytest.raises(UpdaterError) as err:
with TemporaryDirectory() as empty_dir: with TemporaryDirectory() as empty_dir:
# Try to update a Qt installation that does not exist # Try to update a Qt installation that does not exist
Updater.update(target_config, base_dir=empty_dir) Updater.update(target_config, base_path=Path(empty_dir), installed_desktop_arch_dir=None)
assert err.type == UpdaterError assert err.type == UpdaterError
err_msg = format(err.value) err_msg = format(err.value)
assert expected_err_pattern.match(err_msg) assert expected_err_pattern.match(err_msg)