diff --git a/aqt/commercial.py b/aqt/commercial.py index faba179..4ba7265 100644 --- a/aqt/commercial.py +++ b/aqt/commercial.py @@ -35,6 +35,7 @@ from aqt.helper import ( get_os_name, get_qt_account_path, get_qt_installer_name, + prepare_installer, safely_run, safely_run_save_output, ) @@ -340,7 +341,8 @@ class CommercialInstaller: self.logger.info(f"Downloading Qt installer to {installer_path}") timeout = (Settings.connection_timeout, Settings.response_timeout) - download_installer(self.base_url, self._installer_filename, self.os_name, installer_path, timeout) + download_installer(self.base_url, self._installer_filename, installer_path, timeout) + installer_path = prepare_installer(installer_path, self.os_name) try: if self.override: diff --git a/aqt/helper.py b/aqt/helper.py index 67e575d..8ba512f 100644 --- a/aqt/helper.py +++ b/aqt/helper.py @@ -27,6 +27,7 @@ import secrets import shutil import subprocess import sys +import uuid from configparser import ConfigParser from logging import Handler, getLogger from logging.handlers import QueueListener @@ -669,15 +670,37 @@ def extract_auth(args: List[str]) -> Tuple[str | None, str | None, List[str] | N return username, password, args -def download_installer( - base_url: str, installer_filename: str, os_name: str, target_path: Path, timeout: Tuple[float, float] -) -> None: +def download_installer(base_url: str, installer_filename: str, target_path: Path, timeout: Tuple[float, float]) -> None: base_path = f"official_releases/online_installers/{installer_filename}" url = f"{base_url}/{base_path}" try: hash = get_hash(base_path, Settings.hash_algorithm, timeout) downloadBinaryFile(url, target_path, Settings.hash_algorithm, hash, timeout=timeout) - if os_name != "windows": - os.chmod(target_path, 0o500) except Exception as e: raise RuntimeError(f"Failed to download installer: {e}") + + +def prepare_installer(installer_path: Path, os_name: str) -> Path: + """ + Prepares the installer for execution. This may involve setting the correct permissions or + extracting the installer if it's packaged. Returns the path to the installer executable. + """ + if os_name == "linux": + os.chmod(installer_path, 0o500) + return installer_path + elif os_name == "mac": + volume_path = Path(f"/Volumes/{str(uuid.uuid4())}") + subprocess.run( + ["hdiutil", "attach", str(installer_path), "-mountpoint", str(volume_path)], + stdout=subprocess.DEVNULL, + check=True, + ) + try: + src_app_name = next(volume_path.glob("*.app")).name + dst_app_path = installer_path.with_suffix(".app") + shutil.copytree(volume_path / src_app_name, dst_app_path) + finally: + subprocess.run(["hdiutil", "detach", str(volume_path), "-force"], stdout=subprocess.DEVNULL, check=True) + return dst_app_path / "Contents" / "MacOS" / Path(src_app_name).stem + else: + return installer_path diff --git a/aqt/installer.py b/aqt/installer.py index ee0bb36..2d54cfa 100644 --- a/aqt/installer.py +++ b/aqt/installer.py @@ -65,6 +65,7 @@ from aqt.helper import ( get_hash, get_os_name, get_qt_installer_name, + prepare_installer, retry_on_bad_connection, retry_on_errors, safely_run_save_output, @@ -905,7 +906,8 @@ class Cli: # Download installer self.logger.info(f"Downloading Qt installer to {installer_path}") timeout = (Settings.connection_timeout, Settings.response_timeout) - download_installer(Settings.baseurl, installer_filename, get_os_name(), installer_path, timeout) + download_installer(Settings.baseurl, installer_filename, installer_path, timeout) + installer_path = prepare_installer(installer_path, get_os_name()) # Build command cmd = [str(installer_path), "--accept-licenses", "--accept-obligations", "--confirm-command"] diff --git a/tests/test_commercial.py b/tests/test_commercial.py index 89d0f99..9ddb882 100644 --- a/tests/test_commercial.py +++ b/tests/test_commercial.py @@ -221,13 +221,7 @@ def test_commercial_installer_download_sha256(tmp_path, monkeypatch, commercial_ target_path = tmp_path / "qt-installer" timeout = (Settings.connection_timeout, Settings.response_timeout) - download_installer( - commercial_installer.base_url, - commercial_installer._installer_filename, - commercial_installer.os_name, - target_path, - timeout, - ) + download_installer(commercial_installer.base_url, commercial_installer._installer_filename,target_path, timeout) assert target_path.exists()