From 95bf95acd65abea73fdb07b510b87ebe63b7cfbc Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Thu, 13 Jul 2023 20:04:15 -0400 Subject: [PATCH 01/11] Improve support for arbitrary machine architectures - Prevent running on 32bit Windows or 32bit Python on 64bit Windows - Support building an AppImage for i386; verify LinuxDeploy for all Commands - Support building Linux System packages on i386 - Support installing JDK for armv7/8 - Let users know when Android SDK must be manually installed - Derive the Linux system target distro architecture from the build environment - Download a 32bit JDK and 32bit standalone Python when host Python is 32bit - Ensure `makepkg` creates a `.pkg.tar.zst` distributable --- changes/1360.feature.rst | 1 + src/briefcase/commands/create.py | 2 + src/briefcase/exceptions.py | 20 ++- src/briefcase/integrations/android_sdk.py | 39 +++-- src/briefcase/integrations/base.py | 2 + src/briefcase/integrations/java.py | 47 +++--- src/briefcase/integrations/linuxdeploy.py | 20 ++- src/briefcase/platforms/linux/__init__.py | 9 +- src/briefcase/platforms/linux/appimage.py | 19 ++- src/briefcase/platforms/linux/system.py | 138 +++++++++++------- src/briefcase/platforms/windows/__init__.py | 24 ++- .../android_sdk/AndroidSDK/test_properties.py | 13 +- .../android_sdk/AndroidSDK/test_verify.py | 43 ++++++ tests/integrations/base/test_ToolCache.py | 14 ++ tests/integrations/java/test_JDK__verify.py | 42 +++++- tests/integrations/linuxdeploy/conftest.py | 2 +- .../test_LinuxDeployBase__patch_elf_binary.py | 8 +- .../test_LinuxDeployBase__upgrade.py | 8 +- .../test_LinuxDeployQtPlugin__properties.py | 38 ++++- .../test_LinuxDeploy__is_elf_file.py | 8 +- .../test_LinuxDeploy__properties.py | 56 ++++++- .../test_LinuxDeploy__verify_plugins.py | 26 ++-- tests/platforms/linux/appimage/test_build.py | 38 ++--- tests/platforms/linux/appimage/test_create.py | 50 ++++++- tests/platforms/linux/appimage/test_mixin.py | 6 +- .../platforms/linux/appimage/test_package.py | 8 +- tests/platforms/linux/appimage/test_run.py | 12 +- .../linux/system/test_mixin__properties.py | 32 ++-- tests/platforms/linux/system/test_package.py | 61 ++++++-- .../linux/system/test_package__deb.py | 8 +- .../linux/system/test_package__pkg.py | 10 +- .../linux/system/test_package__rpm.py | 4 +- .../platforms/linux/test_DockerOpenCommand.py | 11 +- .../test_LinuxMixin__support_package_url.py | 31 +++- tests/platforms/windows/app/test_build.py | 1 + tests/platforms/windows/app/test_create.py | 34 +++++ 36 files changed, 670 insertions(+), 215 deletions(-) create mode 100644 changes/1360.feature.rst diff --git a/changes/1360.feature.rst b/changes/1360.feature.rst new file mode 100644 index 000000000..e328b5e89 --- /dev/null +++ b/changes/1360.feature.rst @@ -0,0 +1 @@ +Support for less common environments, such as Linux on ARM, is improved and error messages for unsupported platforms are more accurate. diff --git a/src/briefcase/commands/create.py b/src/briefcase/commands/create.py index d04e5c660..3a165c7ca 100644 --- a/src/briefcase/commands/create.py +++ b/src/briefcase/commands/create.py @@ -344,6 +344,7 @@ def _download_support_package(self, app: AppConfig): python_version_tag=self.python_version_tag, platform=self.platform, host_arch=self.tools.host_arch, + is_32bit=self.tools.is_32bit_python, ) support_package_url = self.support_package_url(support_revision) @@ -384,6 +385,7 @@ def _download_support_package(self, app: AppConfig): python_version_tag=self.python_version_tag, platform=self.platform, host_arch=self.tools.host_arch, + is_32bit=self.tools.is_32bit_python, ) from e def _write_requirements_file( diff --git a/src/briefcase/exceptions.py b/src/briefcase/exceptions.py index 005f78096..14fcd4034 100644 --- a/src/briefcase/exceptions.py +++ b/src/briefcase/exceptions.py @@ -103,6 +103,18 @@ def __init__(self, tool): super().__init__(msg=f"Unable to locate {tool!r}. Has it been installed?") +class IncompatibleToolError(BriefcaseCommandError): + def __init__(self, tool: str, env_var: str): + self.tool = tool + super().__init__( + msg=f"""\ +Briefcase cannot install {tool} on this machine. + +Install {tool} manually and specify the installation directory in the {env_var} environment variable. + """ + ) + + class NonManagedToolError(BriefcaseCommandError): def __init__(self, tool): self.tool = tool @@ -153,16 +165,16 @@ def __init__(self, app_bundle_path): class MissingSupportPackage(BriefcaseCommandError): - def __init__(self, python_version_tag, platform, host_arch): + def __init__(self, python_version_tag, platform, host_arch, is_32bit): self.python_version_tag = python_version_tag - self.platform = platform + self.platform = f"{'32 bit ' if is_32bit else ''}{platform}" self.host_arch = host_arch super().__init__( f"""\ Unable to download {self.platform} support package for Python {self.python_version_tag} on {self.host_arch}. -This is likely because either Python {self.python_version_tag} and/or {self.host_arch} -is not yet supported on {self.platform}. You will need to: +This is likely because either Python {self.python_version_tag} and/or {self.host_arch} is not yet +supported on {self.platform}. You will need to: * Use an older version of Python; or * Compile your own custom support package. """ diff --git a/src/briefcase/integrations/android_sdk.py b/src/briefcase/integrations/android_sdk.py index 2147ab07a..643625fc8 100644 --- a/src/briefcase/integrations/android_sdk.py +++ b/src/briefcase/integrations/android_sdk.py @@ -15,6 +15,7 @@ from briefcase.console import InputDisabled, select_option from briefcase.exceptions import ( BriefcaseCommandError, + IncompatibleToolError, InvalidDeviceError, MissingToolError, ) @@ -57,15 +58,35 @@ def __init__(self, tools: ToolCache, root_path: Path): @property def cmdline_tools_url(self) -> str: - """The Android SDK Command-Line Tools URL appropriate to the current operating - system.""" - platform_name = self.tools.host_os.lower() - if self.tools.host_os.lower() == "darwin": - platform_name = "mac" - elif self.tools.host_os.lower() == "windows": # pragma: no branch - platform_name = "win" - - return f"https://dl.google.com/android/repository/commandlinetools-{platform_name}-{self.cmdline_tools_version}_latest.zip" # noqa: E501 + """The Android SDK Command-Line Tools URL appropriate for the current machine. + + The SDK largely only supports typical development environments; if a machine is + using an unsupported architecture, `sdkmanager` will error while installing the + emulator as a dependency of the build-tools. However, for some of the platforms + that are unsupported by sdkmanager, users can set up their own SDK install. + """ + try: + platform_name = { + "Darwin": { + "arm64": "mac", + "x86_64": "mac", + }, + "Linux": { + "x86_64": "linux", + }, + "Windows": { + "AMD64": "win", + }, + }[self.tools.host_os][self.tools.host_arch] + except KeyError as e: + raise IncompatibleToolError( + tool=self.full_name, env_var="ANDROID_HOME" + ) from e + + return ( + f"https://dl.google.com/android/repository/commandlinetools-" + f"{platform_name}-{self.cmdline_tools_version}_latest.zip" + ) @property def cmdline_tools_path(self) -> Path: diff --git a/src/briefcase/integrations/base.py b/src/briefcase/integrations/base.py index e054c02a7..472c43749 100644 --- a/src/briefcase/integrations/base.py +++ b/src/briefcase/integrations/base.py @@ -195,6 +195,8 @@ def __init__( self.host_arch = self.platform.machine() self.host_os = self.platform.system() + # Python is 32bit if its pointers can only address with 32 bits or fewer + self.is_32bit_python = self.sys.maxsize <= 2**32 self.app_tools: DefaultDict[AppConfig, ToolCache] = defaultdict( lambda: ToolCache( diff --git a/src/briefcase/integrations/java.py b/src/briefcase/integrations/java.py index 69f5bf8bf..18c87066d 100644 --- a/src/briefcase/integrations/java.py +++ b/src/briefcase/integrations/java.py @@ -5,7 +5,11 @@ import subprocess from pathlib import Path -from briefcase.exceptions import BriefcaseCommandError, MissingToolError +from briefcase.exceptions import ( + BriefcaseCommandError, + IncompatibleToolError, + MissingToolError, +) from briefcase.integrations.base import ManagedTool, ToolCache @@ -26,23 +30,30 @@ def __init__(self, tools: ToolCache, java_home: Path): @property def OpenJDK_download_url(self): - arch = { - "x86_64": "x64", # Linux\macOS x86-64 - "aarch64": "aarch64", # Linux arm64 - "armv6l": "arm", # Linux arm - "arm64": "aarch64", # macOS arm64 - "AMD64": "x64", # Windows x86-64 - }.get(self.tools.host_arch) - - platform = { - "Darwin": "mac", - "Windows": "windows", - "Linux": "linux", - }.get(self.tools.host_os) - - extension = { - "Windows": "zip", - }.get(self.tools.host_os, "tar.gz") + """The OpenJDK download URL appropriate for the current machine.""" + system_arch = self.tools.host_arch + # use a 32bit JDK if using 32bit Python on 64bit hardware + if self.tools.is_32bit_python and self.tools.host_arch == "aarch64": + system_arch = "armv7l" + + try: + platform, arch, extension = { + "Darwin": { + "arm64": ("mac", "aarch64", "tar.gz"), + "x86_64": ("mac", "x64", "tar.gz"), + }, + "Linux": { + "armv7l": ("linux", "arm", "tar.gz"), + "armv8l": ("linux", "arm", "tar.gz"), + "aarch64": ("linux", "aarch64", "tar.gz"), + "x86_64": ("linux", "x64", "tar.gz"), + }, + "Windows": { + "AMD64": ("windows", "x64", "zip"), + }, + }[self.tools.host_os][system_arch] + except KeyError as e: + raise IncompatibleToolError(tool=self.full_name, env_var="JAVA_HOME") from e return ( f"https://github.com/adoptium/temurin{self.JDK_MAJOR_VER}-binaries/" diff --git a/src/briefcase/integrations/linuxdeploy.py b/src/briefcase/integrations/linuxdeploy.py index 9d5d9f5f5..9dbcd7aba 100644 --- a/src/briefcase/integrations/linuxdeploy.py +++ b/src/briefcase/integrations/linuxdeploy.py @@ -11,6 +11,7 @@ BriefcaseCommandError, CorruptToolError, MissingToolError, + UnsupportedHostError, ) from briefcase.integrations.base import ManagedTool, Tool, ToolCache @@ -48,6 +49,21 @@ def download_url(self) -> str: def file_path(self) -> Path: """The folder on the local filesystem that contains the file_name.""" + @classmethod + def arch(cls, host_os: str, host_arch: str) -> str: + # always use the x86-64 arch on macOS since the + # manylinux image will always be x86-64 for macOS + arch = "x86_64" if host_os == "Darwin" else host_arch + try: + return { + "x86_64": "x86_64", + "i686": "i386", + }[arch] + except KeyError as e: + raise UnsupportedHostError( + f"Linux AppImages cannot be built on {host_arch}." + ) from e + def exists(self) -> bool: return (self.file_path / self.file_name).is_file() @@ -208,7 +224,7 @@ class LinuxDeployQtPlugin(LinuxDeployPluginBase, ManagedTool): @property def file_name(self) -> str: - return f"linuxdeploy-plugin-qt-{self.tools.host_arch}.AppImage" + return f"linuxdeploy-plugin-qt-{self.arch(self.tools.host_os, self.tools.host_arch)}.AppImage" @property def download_url(self) -> str: @@ -319,7 +335,7 @@ def file_path(self) -> Path: @property def file_name(self) -> str: - return f"linuxdeploy-{self.tools.host_arch}.AppImage" + return f"linuxdeploy-{self.arch(self.tools.host_os, self.tools.host_arch)}.AppImage" @property def download_url(self) -> str: diff --git a/src/briefcase/platforms/linux/__init__.py b/src/briefcase/platforms/linux/__init__.py index 1a2efadd8..12a1338a4 100644 --- a/src/briefcase/platforms/linux/__init__.py +++ b/src/briefcase/platforms/linux/__init__.py @@ -66,10 +66,17 @@ def support_package_url(self, support_revision): System packages don't use a support package; this is defined by the template, so this method won't be invoked """ + python_download_arch = self.tools.host_arch + # use a 32bit Python if using 32bit Python on 64bit hardware + if self.tools.is_32bit_python and self.tools.host_arch == "aarch64": + python_download_arch = "armv7" + elif self.tools.is_32bit_python and self.tools.host_arch == "x86_64": + python_download_arch = "i686" + version, datestamp = support_revision.split("+") return ( "https://github.com/indygreg/python-build-standalone/releases/download/" - f"{datestamp}/cpython-{support_revision}-{self.tools.host_arch}-unknown-linux-gnu-install_only.tar.gz" + f"{datestamp}/cpython-{support_revision}-{python_download_arch}-unknown-linux-gnu-install_only.tar.gz" ) def vendor_details(self, freedesktop_info): diff --git a/src/briefcase/platforms/linux/appimage.py b/src/briefcase/platforms/linux/appimage.py index 5af145b2e..c160832cd 100644 --- a/src/briefcase/platforms/linux/appimage.py +++ b/src/briefcase/platforms/linux/appimage.py @@ -44,7 +44,8 @@ def project_path(self, app): def binary_name(self, app): safe_name = app.formal_name.replace(" ", "_") - return f"{safe_name}-{app.version}-{self.tools.host_arch}.AppImage" + arch = LinuxDeploy.arch(self.tools.host_os, self.tools.host_arch) + return f"{safe_name}-{app.version}-{arch}.AppImage" def binary_path(self, app): return self.bundle_path(app) / self.binary_name(app) @@ -52,6 +53,11 @@ def binary_path(self, app): def distribution_path(self, app): return self.dist_path / self.binary_name(app) + def verify_tools(self): + """Verify the AppImage LinuxDeploy tool and its plugins exist.""" + super().verify_tools() + LinuxDeploy.verify(tools=self.tools) + def add_options(self, parser): super().add_options(parser) parser.add_argument( @@ -154,7 +160,11 @@ def output_format_template_context(self, app: AppConfig): # Add the manylinux tag to the template context. try: tag = getattr(app, "manylinux_image_tag", "latest") - context["manylinux_image"] = f"{app.manylinux}_{self.tools.host_arch}:{tag}" + manylinux_arch = { + "x86_64": "x86_64", + "i386": "i686", + }[LinuxDeploy.arch(self.tools.host_os, self.tools.host_arch)] + context["manylinux_image"] = f"{app.manylinux}_{manylinux_arch}:{tag}" if app.manylinux in {"manylinux1", "manylinux2010", "manylinux2014"}: context["vendor_base"] = "centos" elif app.manylinux == "manylinux_2_24": @@ -213,11 +223,6 @@ class LinuxAppImageOpenCommand(LinuxAppImageMostlyPassiveMixin, DockerOpenComman class LinuxAppImageBuildCommand(LinuxAppImageMixin, BuildCommand): description = "Build a Linux AppImage." - def verify_tools(self): - """Verify the AppImage linuxdeploy tool and plugins exist.""" - super().verify_tools() - LinuxDeploy.verify(tools=self.tools) - def build_app(self, app: AppConfig, **kwargs): # pragma: no-cover-if-is-windows """Build an application. diff --git a/src/briefcase/platforms/linux/system.py b/src/briefcase/platforms/linux/system.py index 2a7270844..32629a867 100644 --- a/src/briefcase/platforms/linux/system.py +++ b/src/briefcase/platforms/linux/system.py @@ -54,15 +54,6 @@ def parse_options(self, extra): return options - @property - def linux_arch(self): - # Linux uses different architecture identifiers for some platforms - return { - "x86_64": "amd64", - "aarch64": "arm64", - "armv6l": "armhf", - }.get(self.tools.host_arch, self.tools.host_arch) - def build_path(self, app): # Override the default build path to use the vendor name, # rather than "linux" @@ -85,31 +76,6 @@ def rpm_tag(self, app): else: return f"el{app.target_codename}" - def distribution_filename(self, app): - if app.packaging_format == "deb": - return ( - f"{app.app_name}_{app.version}-{getattr(app, 'revision', 1)}" - f"~{app.target_vendor}-{app.target_codename}_{self.linux_arch}.deb" - ) - elif app.packaging_format == "rpm": - return ( - f"{app.app_name}-{app.version}-{getattr(app, 'revision', 1)}" - f".{self.rpm_tag(app)}.{self.tools.host_arch}.rpm" - ) - elif app.packaging_format == "pkg": - return ( - f"{app.app_name}-{app.version}-{getattr(app, 'revision', 1)}" - f"-{self.tools.host_arch}.pkg.tar.zst" - ) - else: - raise BriefcaseCommandError( - "Briefcase doesn't currently know how to build system packages in " - f"{app.packaging_format.upper()} format." - ) - - def distribution_path(self, app): - return self.dist_path / self.distribution_filename(app) - def target_glibc_version(self, app): target_glibc = self.tools.os.confstr("CS_GNU_LIBC_VERSION").split()[1] return target_glibc @@ -235,7 +201,7 @@ def use_docker(self): # what "use docker" means in terms of target_image. return bool(self.target_image) - def app_python_version_tag(self, app): + def app_python_version_tag(self, app: AppConfig): if self.use_docker: # If we're running in Docker, we can't know the Python3 version # before rolling out the template; so we fall back to "3". Later, @@ -247,6 +213,75 @@ def app_python_version_tag(self, app): python_version_tag = super().app_python_version_tag(app) return python_version_tag + def _build_env_abi(self, app: AppConfig): + """Retrieves the ABI the packaging system is targeting in the build env. + + Each packaging system uses different values to identify the exact ABI that + describes the target environment...so just defer to the packaging system. + """ + command = { + "deb": ["dpkg", "--print-architecture"], + "rpm": ["rpm", "--eval", "%_target_cpu"], + "pkg": ["pacman-conf", "Architecture"], + }[app.packaging_format] + try: + return ( + self.tools[app].app_context.check_output(command).split("\n")[0].strip() + ) + except (OSError, subprocess.CalledProcessError) as e: + raise BriefcaseCommandError( + "Failed to determine build environment's ABI for packaging." + ) from e + + def deb_abi(self, app: AppConfig) -> str: + """The default ABI for dpkg packaging for the target environment.""" + try: + return self._deb_abi + except AttributeError: + self._deb_abi = self._build_env_abi(app) + return self._deb_abi + + def rpm_abi(self, app: AppConfig) -> str: + """The default ABI for rpm packaging for the target environment.""" + try: + return self._rpm_abi + except AttributeError: + self._rpm_abi = self._build_env_abi(app) + return self._rpm_abi + + def pkg_abi(self, app: AppConfig) -> str: + """The default ABI for pacman packaging for the target environment.""" + try: + return self._pkg_abi + except AttributeError: + self._pkg_abi = self._build_env_abi(app) + return self._pkg_abi + + def distribution_filename(self, app: AppConfig) -> str: + if app.packaging_format == "deb": + return ( + f"{app.app_name}_{app.version}-{getattr(app, 'revision', 1)}" + f"~{app.target_vendor}-{app.target_codename}_{self.deb_abi(app)}.deb" + ) + elif app.packaging_format == "rpm": + return ( + f"{app.app_name}-{app.version}-{getattr(app, 'revision', 1)}" + f".{self.rpm_tag(app)}.{self.rpm_abi(app)}.rpm" + ) + elif app.packaging_format == "pkg": + return ( + f"{app.app_name}-{app.version}-{getattr(app, 'revision', 1)}" + f"-{self.pkg_abi(app)}.pkg.tar.zst" + ) + else: + raise BriefcaseCommandError( + "Briefcase doesn't currently know how to build system packages in " + f"{app.packaging_format.upper()} format." + ) + + def distribution_path(self, app: AppConfig): + return self.dist_path / self.distribution_filename(app) + def target_glibc_version(self, app): """Determine the glibc version. @@ -289,7 +324,7 @@ def target_glibc_version(self, app): return target_glibc - def platform_freedesktop_info(self, app): + def platform_freedesktop_info(self, app: AppConfig): if self.use_docker: # Preserve the target image on the command line as the app's target app.target_image = self.target_image @@ -308,7 +343,7 @@ def platform_freedesktop_info(self, app): return freedesktop_info - def docker_image_tag(self, app): + def docker_image_tag(self, app: AppConfig): """The Docker image tag for an app.""" return f"briefcase/{app.bundle_identifier.lower()}:{app.target_vendor}-{app.target_codename}" @@ -339,7 +374,7 @@ def clone_options(self, command): super().clone_options(command) self.target_image = command.target_image - def verify_python(self, app): + def verify_python(self, app: AppConfig): """Verify that the version of Python being used to build the app in Docker is compatible with the version being used to run Briefcase. @@ -487,7 +522,7 @@ def verify_system_packages(self, app: AppConfig): ) return - # Run a check for each packages listed in the app's system_requires, + # Run a check for each package listed in the app's system_requires, # plus the baseline system packages that are required. missing = [] for package in base_system_packages + getattr(app, "system_requires", []): @@ -880,15 +915,15 @@ def _package_deb(self, app: AppConfig, **kwargs): f.write( "\n".join( [ - f"Package: { app.app_name }", - f"Version: { app.version }", - f"Architecture: { self.linux_arch }", - f"Maintainer: { app.author } <{ app.author_email }>", - f"Homepage: { app.url }", - f"Description: { app.description }", - f" { debian_multiline_description(app.long_description) }", - f"Depends: { system_runtime_requires }", - f"Section: { getattr(app, 'system_section', 'utils') }", + f"Package: {app.app_name}", + f"Version: {app.version}", + f"Architecture: {self.deb_abi(app)}", + f"Maintainer: {app.author } <{app.author_email}>", + f"Homepage: {app.url}", + f"Description: {app.description}", + f" {debian_multiline_description(app.long_description)}", + f"Depends: {system_runtime_requires}", + f"Section: {getattr(app, 'system_section', 'utils')}", "Priority: optional\n", ] ) @@ -994,7 +1029,7 @@ def _package_rpm(self, app: AppConfig, **kwargs): # pragma: no-cover-if-is-wind ] + [ "", - f"ExclusiveArch: {self.tools.host_arch}", + f"ExclusiveArch: {self.rpm_abi(app)}", "", "%description", app.long_description, @@ -1072,7 +1107,7 @@ def _package_rpm(self, app: AppConfig, **kwargs): # pragma: no-cover-if-is-wind self.tools.shutil.move( rpmbuild_path / "RPMS" - / self.tools.host_arch + / self.rpm_abi(app) / self.distribution_filename(app), self.distribution_path(app), ) @@ -1140,7 +1175,7 @@ def _package_pkg(self, app: AppConfig, **kwargs): # pragma: no-cover-if-is-wind f"pkgver={app.version}", f"pkgrel={getattr(app, 'revision', 1)}", f'pkgdesc="{app.description}"', - f"arch=('{self.tools.host_arch}')", + f"arch=('{self.pkg_abi(app)}')", f'url="{app.url}"', f"license=('{app.license}')", f"depends=({system_runtime_requires})", @@ -1162,6 +1197,7 @@ def _package_pkg(self, app: AppConfig, **kwargs): # pragma: no-cover-if-is-wind [ "makepkg", ], + env={"PKGEXT": ".pkg.tar.zst"}, check=True, cwd=pkgbuild_path, ) diff --git a/src/briefcase/platforms/windows/__init__.py b/src/briefcase/platforms/windows/__init__.py index fbd2c18f0..c205efd5e 100644 --- a/src/briefcase/platforms/windows/__init__.py +++ b/src/briefcase/platforms/windows/__init__.py @@ -8,7 +8,7 @@ from briefcase.commands import CreateCommand, PackageCommand, RunCommand from briefcase.config import AppConfig, parsed_version -from briefcase.exceptions import BriefcaseCommandError +from briefcase.exceptions import BriefcaseCommandError, UnsupportedHostError from briefcase.integrations.windows_sdk import WindowsSDK from briefcase.integrations.wix import WiX @@ -27,6 +27,23 @@ def distribution_path(self, app): suffix = "zip" if app.packaging_format == "zip" else "msi" return self.dist_path / f"{app.formal_name}-{app.version}.{suffix}" + def verify_host(self): + super().verify_host() + # the stub app only supports x86-64 right now + if self.tools.host_arch != "AMD64": + raise UnsupportedHostError( + f"Windows applications cannot be built on an {self.tools.host_arch} machine." + ) + # 64bit Python is required to ensure 64bit wheels are installed/created for the app + if self.tools.is_32bit_python: + raise UnsupportedHostError( + """\ +Windows applications cannot be built using a 32bit version of Python. + +Install a 64bit version of Python and run Briefcase again. +""" + ) + class WindowsCreateCommand(CreateCommand): def support_package_filename(self, support_revision): @@ -34,8 +51,9 @@ def support_package_filename(self, support_revision): def support_package_url(self, support_revision): return ( - f"https://www.python.org/ftp/python/{self.python_version_tag}.{support_revision}/" - + self.support_package_filename(support_revision) + f"https://www.python.org/ftp/python/" + f"{self.python_version_tag}.{support_revision}/" + f"{self.support_package_filename(support_revision)}" ) def output_format_template_context(self, app: AppConfig): diff --git a/tests/integrations/android_sdk/AndroidSDK/test_properties.py b/tests/integrations/android_sdk/AndroidSDK/test_properties.py index 9aae960f4..29f1ad787 100644 --- a/tests/integrations/android_sdk/AndroidSDK/test_properties.py +++ b/tests/integrations/android_sdk/AndroidSDK/test_properties.py @@ -7,17 +7,18 @@ @pytest.mark.parametrize( - "host_os, name", + "host_os, host_arch, name", [ - ("windows", "win"), - ("Windows", "win"), - ("darwin", "mac"), - ("Darwin", "mac"), + ("Darwin", "arm64", "mac"), + ("Darwin", "x86_64", "mac"), + ("Linux", "x86_64", "linux"), + ("Windows", "AMD64", "win"), ], ) -def test_cmdline_tools_url(mock_tools, android_sdk, host_os, name): +def test_cmdline_tools_url(mock_tools, android_sdk, host_os, host_arch, name): """Validate that the SDK URL is computed using `host_os`.""" mock_tools.host_os = host_os + mock_tools.host_arch = host_arch assert android_sdk.cmdline_tools_url == ( f"https://dl.google.com/android/repository/commandlinetools-{name}-8092744_latest.zip" diff --git a/tests/integrations/android_sdk/AndroidSDK/test_verify.py b/tests/integrations/android_sdk/AndroidSDK/test_verify.py index c38718984..03b63e695 100644 --- a/tests/integrations/android_sdk/AndroidSDK/test_verify.py +++ b/tests/integrations/android_sdk/AndroidSDK/test_verify.py @@ -7,6 +7,7 @@ from briefcase.exceptions import ( BriefcaseCommandError, + IncompatibleToolError, MissingToolError, NetworkFailure, UnsupportedHostError, @@ -78,6 +79,48 @@ def test_unsupported_os(mock_tools): AndroidSDK.verify(mock_tools) +def test_unsupported_arch(mock_tools): + """When the architecture is not supported, an error is raised.""" + mock_tools.host_arch = "IA-64" + + with pytest.raises( + IncompatibleToolError, + match="Briefcase cannot install Android SDK on this machine.", + ): + AndroidSDK.verify(mock_tools) + + +@pytest.mark.parametrize( + "host_os, host_arch", + [ + ("Darwin", "arm64"), + ("Darwin", "x86_64"), + ("Linux", "x86_64"), + ("Windows", "AMD64"), + ], +) +def test_supported_os_arch(mock_tools, host_os, host_arch, tmp_path): + """The supported OS/arch combinations do not error.""" + mock_tools.host_os = host_os + mock_tools.host_arch = host_arch + + # Create `sdkmanager` and the license file. + android_sdk_root_path = tmp_path / "tools" / "android_sdk" + tools_bin = android_sdk_root_path / "cmdline-tools" / "latest" / "bin" + tools_bin.mkdir(parents=True, mode=0o755) + if host_os == "Windows": + sdk_manager = tools_bin / "sdkmanager.bat" + sdk_manager.touch() + else: + sdk_manager = tools_bin / "sdkmanager" + sdk_manager.touch(mode=0o755) + + # Pre-accept the license + accept_license(android_sdk_root_path)() + + assert isinstance(AndroidSDK.verify(mock_tools), AndroidSDK) + + def test_succeeds_immediately_in_happy_path(mock_tools, tmp_path): """If verify is invoked on a path containing an Android SDK, it does nothing.""" # If `sdkmanager` exists and has the right permissions, and `android-sdk-license` diff --git a/tests/integrations/base/test_ToolCache.py b/tests/integrations/base/test_ToolCache.py index 0d174bdcb..ac6dddb67 100644 --- a/tests/integrations/base/test_ToolCache.py +++ b/tests/integrations/base/test_ToolCache.py @@ -165,3 +165,17 @@ def test_windows_home_path(home_path, expected_path, tmp_path): home_path=home_path, ) assert tools.home_path == expected_path + + +@pytest.mark.parametrize("maxsize, is_32bit", [(2**32, True), (2**64, False)]) +def test_is_32bit_python(maxsize, is_32bit, monkeypatch, tmp_path): + """Whether Python is 32bits is sensitive to `sys.maxsize`.""" + monkeypatch.setattr(sys, "maxsize", maxsize) + + tools = ToolCache( + logger=Log(), + console=Console(), + base_path=tmp_path, + ) + + assert tools.is_32bit_python is is_32bit diff --git a/tests/integrations/java/test_JDK__verify.py b/tests/integrations/java/test_JDK__verify.py index be74a75e2..6c87851a0 100644 --- a/tests/integrations/java/test_JDK__verify.py +++ b/tests/integrations/java/test_JDK__verify.py @@ -8,6 +8,7 @@ from briefcase.exceptions import ( BriefcaseCommandError, + IncompatibleToolError, MissingToolError, NetworkFailure, UnsupportedHostError, @@ -38,6 +39,17 @@ def test_unsupported_os(mock_tools): JDK.verify(mock_tools) +def test_unsupported_arch(mock_tools): + """When the architecture is not supported, an error is raised.""" + mock_tools.host_arch = "IA-64" + + with pytest.raises( + IncompatibleToolError, + match="Briefcase cannot install Java JDK on this machine.", + ): + JDK.verify(mock_tools) + + def test_macos_tool_java_home(mock_tools, capsys): """On macOS, the /usr/libexec/java_home utility is checked.""" # Mock being on macOS @@ -386,7 +398,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap @pytest.mark.parametrize( - "host_os, host_arch, jdk_url, jhome", + "host_os, host_arch, jdk_url, jhome, is_32bit", [ ( "Darwin", @@ -394,13 +406,15 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "https://github.com/adoptium/temurin17-binaries/releases/download/" "jdk-17.0.7+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.7_7.tar.gz", "java17/Contents/Home", + False, ), ( "Darwin", - "aarch64", + "arm64", "https://github.com/adoptium/temurin17-binaries/releases/download/" "jdk-17.0.7+7/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.7_7.tar.gz", "java17/Contents/Home", + False, ), ( "Linux", @@ -408,6 +422,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "https://github.com/adoptium/temurin17-binaries/releases/download/" "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", "java17", + False, ), ( "Linux", @@ -415,13 +430,31 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "https://github.com/adoptium/temurin17-binaries/releases/download/" "jdk-17.0.7+7/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.7_7.tar.gz", "java17", + False, + ), + ( + "Linux", + "aarch64", + "https://github.com/adoptium/temurin17-binaries/releases/download/" + "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", + "java17", + True, + ), + ( + "Linux", + "armv7l", + "https://github.com/adoptium/temurin17-binaries/releases/download/" + "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", + "java17", + False, ), ( "Linux", - "armv6l", + "armv8l", "https://github.com/adoptium/temurin17-binaries/releases/download/" "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", "java17", + False, ), ( "Windows", @@ -429,6 +462,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "https://github.com/adoptium/temurin17-binaries/releases/download/" "jdk-17.0.7+7/OpenJDK17U-jdk_x64_windows_hotspot_17.0.7_7.zip", "java17", + False, ), ], ) @@ -440,11 +474,13 @@ def test_successful_jdk_download( host_arch, jdk_url, jhome, + is_32bit, ): """If needed, a JDK can be downloaded.""" # Mock host OS and arch mock_tools.host_os = host_os mock_tools.host_arch = host_arch + mock_tools.is_32bit_python = is_32bit # Mock a JAVA_HOME that won't exist # This is only needed to make macOS *not* run /usr/libexec/java_home diff --git a/tests/integrations/linuxdeploy/conftest.py b/tests/integrations/linuxdeploy/conftest.py index d95fbb5dd..be9ee0109 100644 --- a/tests/integrations/linuxdeploy/conftest.py +++ b/tests/integrations/linuxdeploy/conftest.py @@ -12,7 +12,7 @@ @pytest.fixture def mock_tools(tmp_path, mock_tools) -> ToolCache: mock_tools.host_os = "Linux" - mock_tools.host_arch = "wonky" + mock_tools.host_arch = "i686" # Mock default tools mock_tools.subprocess = MagicMock(spec_set=Subprocess) diff --git a/tests/integrations/linuxdeploy/test_LinuxDeployBase__patch_elf_binary.py b/tests/integrations/linuxdeploy/test_LinuxDeployBase__patch_elf_binary.py index 756be873a..5199e77a4 100644 --- a/tests/integrations/linuxdeploy/test_LinuxDeployBase__patch_elf_binary.py +++ b/tests/integrations/linuxdeploy/test_LinuxDeployBase__patch_elf_binary.py @@ -11,7 +11,7 @@ def test_patch_linuxdeploy_elf_header_unpatched(linuxdeploy, tmp_path): """If the linuxdeploy tool/plugin is not patched, patch it.""" - appimage_path = tmp_path / "tools" / "linuxdeploy-wonky.AppImage" + appimage_path = tmp_path / "tools" / "linuxdeploy-i386.AppImage" # Mock an unpatched linuxdeploy AppImage pre_patch_header = create_mock_appimage( @@ -32,7 +32,7 @@ def test_patch_linuxdeploy_elf_header_unpatched(linuxdeploy, tmp_path): def test_patch_linuxdeploy_elf_header_already_patched(linuxdeploy, tmp_path): """If linuxdeploy is already patched, don't patch it.""" - appimage_path = tmp_path / "tools" / "linuxdeploy-wonky.AppImage" + appimage_path = tmp_path / "tools" / "linuxdeploy-i386.AppImage" # Mock a patched linuxdeploy AppImage pre_patch_header = create_mock_appimage( @@ -53,7 +53,7 @@ def test_patch_linuxdeploy_elf_header_already_patched(linuxdeploy, tmp_path): def test_patch_linuxdeploy_elf_header_bad_appimage(linuxdeploy, tmp_path): """If linuxdeploy does not have a valid header, raise an error.""" - appimage_path = tmp_path / "tools" / "linuxdeploy-wonky.AppImage" + appimage_path = tmp_path / "tools" / "linuxdeploy-i386.AppImage" # Mock a bad linuxdeploy AppImage create_mock_appimage(appimage_path=appimage_path, mock_appimage_kind="corrupt") @@ -65,7 +65,7 @@ def test_patch_linuxdeploy_elf_header_bad_appimage(linuxdeploy, tmp_path): def test_patch_linuxdeploy_elf_header_empty_appimage(linuxdeploy, tmp_path): """If file is empty, raise an error.""" - appimage_path = tmp_path / "tools" / "linuxdeploy-wonky.AppImage" + appimage_path = tmp_path / "tools" / "linuxdeploy-i386.AppImage" # Mock a bad linuxdeploy AppImage create_mock_appimage(appimage_path=appimage_path, mock_appimage_kind="empty") diff --git a/tests/integrations/linuxdeploy/test_LinuxDeployBase__upgrade.py b/tests/integrations/linuxdeploy/test_LinuxDeployBase__upgrade.py index 4548b5417..ee406812e 100644 --- a/tests/integrations/linuxdeploy/test_LinuxDeployBase__upgrade.py +++ b/tests/integrations/linuxdeploy/test_LinuxDeployBase__upgrade.py @@ -6,7 +6,7 @@ def test_upgrade_exists(linuxdeploy, mock_tools, tmp_path): """If linuxdeploy already exists, upgrading deletes first.""" - appimage_path = tmp_path / "tools" / "linuxdeploy-wonky.AppImage" + appimage_path = tmp_path / "tools" / "linuxdeploy-i386.AppImage" # Mock the existence of an install appimage_path.touch() @@ -24,7 +24,7 @@ def test_upgrade_exists(linuxdeploy, mock_tools, tmp_path): # A download is invoked mock_tools.download.file.assert_called_with( - url="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-wonky.AppImage", + url="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-i386.AppImage", download_path=tmp_path / "tools", role="linuxdeploy", ) @@ -45,7 +45,7 @@ def test_upgrade_does_not_exist(linuxdeploy, mock_tools): def test_upgrade_linuxdeploy_download_failure(linuxdeploy, mock_tools, tmp_path): """If linuxdeploy doesn't exist, but a download failure occurs, an error is raised.""" - appimage_path = tmp_path / "tools" / "linuxdeploy-wonky.AppImage" + appimage_path = tmp_path / "tools" / "linuxdeploy-i386.AppImage" # Mock the existence of an install appimage_path.touch() @@ -61,7 +61,7 @@ def test_upgrade_linuxdeploy_download_failure(linuxdeploy, mock_tools, tmp_path) # A download was invoked mock_tools.download.file.assert_called_with( - url="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-wonky.AppImage", + url="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-i386.AppImage", download_path=tmp_path / "tools", role="linuxdeploy", ) diff --git a/tests/integrations/linuxdeploy/test_LinuxDeployQtPlugin__properties.py b/tests/integrations/linuxdeploy/test_LinuxDeployQtPlugin__properties.py index 13e2bce16..9b5c0a9fd 100644 --- a/tests/integrations/linuxdeploy/test_LinuxDeployQtPlugin__properties.py +++ b/tests/integrations/linuxdeploy/test_LinuxDeployQtPlugin__properties.py @@ -16,9 +16,25 @@ def test_file_path(mock_tools, linuxdeploy_qt_plugin): ) -def test_file_name(linuxdeploy_qt_plugin): +@pytest.mark.parametrize( + "host_os, host_arch, linuxdeploy_arch", + [ + ("Linux", "x86_64", "x86_64"), + ("Linux", "i686", "i386"), + ("Darwin", "x86_64", "x86_64"), + ("Darwin", "arm64", "x86_64"), + ], +) +def test_file_name(mock_tools, host_os, host_arch, linuxdeploy_arch): """Linuxdeploy Qt plugin filename is architecture dependent.""" - assert linuxdeploy_qt_plugin.file_name == "linuxdeploy-plugin-qt-wonky.AppImage" + mock_tools.host_os = host_os + mock_tools.host_arch = host_arch + + linuxdeploy_qt_plugin = LinuxDeployQtPlugin(mock_tools) + assert ( + linuxdeploy_qt_plugin.file_name + == f"linuxdeploy-plugin-qt-{linuxdeploy_arch}.AppImage" + ) def test_plugin_id(linuxdeploy_qt_plugin): @@ -26,9 +42,23 @@ def test_plugin_id(linuxdeploy_qt_plugin): assert linuxdeploy_qt_plugin.plugin_id == "qt" -def test_download_url(linuxdeploy_qt_plugin): +@pytest.mark.parametrize( + "host_os, host_arch, linuxdeploy_arch", + [ + ("Linux", "x86_64", "x86_64"), + ("Linux", "i686", "i386"), + ("Darwin", "x86_64", "x86_64"), + ("Darwin", "arm64", "x86_64"), + ], +) +def test_download_url(mock_tools, host_os, host_arch, linuxdeploy_arch): """Linuxdeploy Qt plugin download URL is architecture dependent.""" + mock_tools.host_os = host_os + mock_tools.host_arch = host_arch + + linuxdeploy_qt_plugin = LinuxDeployQtPlugin(mock_tools) + assert linuxdeploy_qt_plugin.download_url == ( "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/" - "releases/download/continuous/linuxdeploy-plugin-qt-wonky.AppImage" + f"releases/download/continuous/linuxdeploy-plugin-qt-{linuxdeploy_arch}.AppImage" ) diff --git a/tests/integrations/linuxdeploy/test_LinuxDeploy__is_elf_file.py b/tests/integrations/linuxdeploy/test_LinuxDeploy__is_elf_file.py index 2971f21c1..eb2383823 100644 --- a/tests/integrations/linuxdeploy/test_LinuxDeploy__is_elf_file.py +++ b/tests/integrations/linuxdeploy/test_LinuxDeploy__is_elf_file.py @@ -3,16 +3,14 @@ def test_is_elf_header_positive_detection(linuxdeploy, tmp_path): """File with an ELF Header is identified as an ELF file.""" - create_mock_appimage( - appimage_path=tmp_path / "tools" / "linuxdeploy-wonky.AppImage" - ) + create_mock_appimage(appimage_path=tmp_path / "tools" / "linuxdeploy-i386.AppImage") assert linuxdeploy.is_elf_file() is True def test_is_elf_header_negative_detection(linuxdeploy, tmp_path): """File without an ELF Header is not identified as an ELF file.""" create_mock_appimage( - appimage_path=tmp_path / "tools" / "linuxdeploy-wonky.AppImage", + appimage_path=tmp_path / "tools" / "linuxdeploy-i386.AppImage", mock_appimage_kind="corrupt", ) assert linuxdeploy.is_elf_file() is False @@ -21,7 +19,7 @@ def test_is_elf_header_negative_detection(linuxdeploy, tmp_path): def test_is_elf_header_empty_file(linuxdeploy, tmp_path): """Empty file is not identified as an ELF file without any errors.""" create_mock_appimage( - appimage_path=tmp_path / "tools" / "linuxdeploy-wonky.AppImage", + appimage_path=tmp_path / "tools" / "linuxdeploy-i386.AppImage", mock_appimage_kind="empty", ) assert linuxdeploy.is_elf_file() is False diff --git a/tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py b/tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py index c5d17c8a9..d06b24f58 100644 --- a/tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py +++ b/tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py @@ -1,4 +1,11 @@ -from briefcase.integrations.linuxdeploy import LinuxDeployGtkPlugin, LinuxDeployQtPlugin +import pytest + +from briefcase.exceptions import UnsupportedHostError +from briefcase.integrations.linuxdeploy import ( + LinuxDeploy, + LinuxDeployGtkPlugin, + LinuxDeployQtPlugin, +) def test_managed_install(linuxdeploy): @@ -11,16 +18,55 @@ def test_file_path(linuxdeploy, mock_tools): assert linuxdeploy.file_path == mock_tools.base_path -def test_file_name(linuxdeploy): +@pytest.mark.parametrize( + "host_os, host_arch, linuxdeploy_arch", + [ + ("Linux", "x86_64", "x86_64"), + ("Linux", "i686", "i386"), + ("Darwin", "x86_64", "x86_64"), + ("Darwin", "arm64", "x86_64"), + ], +) +def test_file_name(mock_tools, host_os, host_arch, linuxdeploy_arch): """Linuxdeploy filename is architecture dependent.""" - assert linuxdeploy.file_name == "linuxdeploy-wonky.AppImage" + mock_tools.host_os = host_os + mock_tools.host_arch = host_arch + + linuxdeploy = LinuxDeploy(mock_tools) + + assert linuxdeploy.file_name == f"linuxdeploy-{linuxdeploy_arch}.AppImage" + +def test_file_name_unsupported_arch(mock_tools): + """LinuxDeploy cannot be verified for an unsupported architecture.""" + mock_tools.host_arch = "IA-64" -def test_download_url(linuxdeploy): + with pytest.raises( + UnsupportedHostError, + match="Linux AppImages cannot be built on IA-64.", + ): + _ = LinuxDeploy(mock_tools).file_name + + +@pytest.mark.parametrize( + "host_os, host_arch, linuxdeploy_arch", + [ + ("Linux", "x86_64", "x86_64"), + ("Linux", "i686", "i386"), + ("Darwin", "x86_64", "x86_64"), + ("Darwin", "arm64", "x86_64"), + ], +) +def test_download_url(mock_tools, host_os, host_arch, linuxdeploy_arch): """Linuxdeploy download URL is architecture dependent.""" + mock_tools.host_os = host_os + mock_tools.host_arch = host_arch + + linuxdeploy = LinuxDeploy(mock_tools) + assert linuxdeploy.download_url == ( "https://github.com/linuxdeploy/linuxdeploy/" - "releases/download/continuous/linuxdeploy-wonky.AppImage" + f"releases/download/continuous/linuxdeploy-{linuxdeploy_arch}.AppImage" ) diff --git a/tests/integrations/linuxdeploy/test_LinuxDeploy__verify_plugins.py b/tests/integrations/linuxdeploy/test_LinuxDeploy__verify_plugins.py index db17c3f8c..f3de248d5 100644 --- a/tests/integrations/linuxdeploy/test_LinuxDeploy__verify_plugins.py +++ b/tests/integrations/linuxdeploy/test_LinuxDeploy__verify_plugins.py @@ -57,7 +57,7 @@ def test_qt_plugin(linuxdeploy, mock_tools, tmp_path): / "tools" / "linuxdeploy_plugins" / "qt" - / "linuxdeploy-plugin-qt-wonky.AppImage" + / "linuxdeploy-plugin-qt-i386.AppImage" ) plugins = linuxdeploy.verify_plugins(["qt"], bundle_path=tmp_path / "bundle") @@ -68,7 +68,7 @@ def test_qt_plugin(linuxdeploy, mock_tools, tmp_path): mock_tools.download.file.assert_called_with( url=( "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/" - "releases/download/continuous/linuxdeploy-plugin-qt-wonky.AppImage" + "releases/download/continuous/linuxdeploy-plugin-qt-i386.AppImage" ), download_path=tmp_path / "tools" / "linuxdeploy_plugins" / "qt", role="linuxdeploy Qt plugin", @@ -84,12 +84,12 @@ def test_custom_url_plugin(linuxdeploy, mock_tools, tmp_path): / "tools" / "linuxdeploy_plugins" / "sometool" - / "f3355f8e631ffc1abbb7afd37b36315f7846182ca2276c481fb9a43a7f4d239f" - / "linuxdeploy-plugin-sometool-wonky.AppImage" + / "bbf1b5dc4c3d2069dc5b916f73e9d6f5ad24603576298509367878e393c6f8f5" + / "linuxdeploy-plugin-sometool-i386.AppImage" ) plugins = linuxdeploy.verify_plugins( - ["https://example.com/path/to/linuxdeploy-plugin-sometool-wonky.AppImage"], + ["https://example.com/path/to/linuxdeploy-plugin-sometool-i386.AppImage"], bundle_path=tmp_path / "bundle", ) @@ -97,12 +97,12 @@ def test_custom_url_plugin(linuxdeploy, mock_tools, tmp_path): assert isinstance(plugins["sometool"], LinuxDeployURLPlugin) mock_tools.download.file.assert_called_with( - url="https://example.com/path/to/linuxdeploy-plugin-sometool-wonky.AppImage", + url="https://example.com/path/to/linuxdeploy-plugin-sometool-i386.AppImage", download_path=tmp_path / "tools" / "linuxdeploy_plugins" / "sometool" - / "f3355f8e631ffc1abbb7afd37b36315f7846182ca2276c481fb9a43a7f4d239f", + / "bbf1b5dc4c3d2069dc5b916f73e9d6f5ad24603576298509367878e393c6f8f5", role="user-provided linuxdeploy plugin from URL", ) @@ -115,9 +115,7 @@ def test_custom_local_file_plugin(linuxdeploy, mock_tools, tmp_path): """A Custom local file plugin can be verified.""" # Create a local file - plugin_path = ( - tmp_path / "path" / "to" / "linuxdeploy-plugin-sometool-wonky.AppImage" - ) + plugin_path = tmp_path / "path" / "to" / "linuxdeploy-plugin-sometool-i386.AppImage" create_mock_appimage(plugin_path) plugins = linuxdeploy.verify_plugins( @@ -131,7 +129,7 @@ def test_custom_local_file_plugin(linuxdeploy, mock_tools, tmp_path): # No download happened mock_tools.download.file.assert_not_called() # But a copy happened - assert (tmp_path / "bundle" / "linuxdeploy-plugin-sometool-wonky.AppImage").exists() + assert (tmp_path / "bundle" / "linuxdeploy-plugin-sometool-i386.AppImage").exists() @pytest.mark.parametrize( @@ -214,7 +212,7 @@ def mock_downloads(url, download_path, role): / "tools" / "linuxdeploy_plugins" / "qt" - / "linuxdeploy-plugin-qt-wonky.AppImage" + / "linuxdeploy-plugin-qt-i386.AppImage" )(url, download_path, role) elif "linuxdeploy_plugins/network" in str(download_path): return side_effect_create_mock_tool( @@ -232,7 +230,7 @@ def mock_downloads(url, download_path, role): # Local file tool is a local file. local_plugin_path = ( - tmp_path / "path" / "to" / "linuxdeploy-plugin-sometool-wonky.AppImage" + tmp_path / "path" / "to" / "linuxdeploy-plugin-sometool-i386.AppImage" ) create_mock_appimage(local_plugin_path) @@ -260,7 +258,7 @@ def mock_downloads(url, download_path, role): # Local file plugin is as expected assert isinstance(plugins["sometool"], LinuxDeployLocalFilePlugin) assert plugins["sometool"].env == {"QUALITY": "really nice"} - assert (tmp_path / "bundle" / "linuxdeploy-plugin-sometool-wonky.AppImage").exists() + assert (tmp_path / "bundle" / "linuxdeploy-plugin-sometool-i386.AppImage").exists() # URL plugin is as expected assert isinstance(plugins["network"], LinuxDeployURLPlugin) diff --git a/tests/platforms/linux/appimage/test_build.py b/tests/platforms/linux/appimage/test_build.py index 617cf9f07..3473818d3 100644 --- a/tests/platforms/linux/appimage/test_build.py +++ b/tests/platforms/linux/appimage/test_build.py @@ -56,7 +56,7 @@ def build_command(tmp_path, first_app_config): apps={"first": first_app_config}, ) command.tools.host_os = "Linux" - command.tools.host_arch = "wonky" + command.tools.host_arch = "x86_64" command.use_docker = False command._briefcase_toml[first_app_config] = { "paths": { @@ -138,7 +138,7 @@ def test_verify_tools_download_failure(build_command): # The download was attempted build_command.tools.download.file.assert_called_with( - url="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-wonky.AppImage", + url="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage", download_path=build_command.tools.base_path, role="linuxdeploy", ) @@ -169,7 +169,7 @@ def test_build_appimage(build_command, first_app, tmp_path, sub_stream_kw): build_command._subprocess.Popen.assert_called_with( [ os.fsdecode( - tmp_path / "briefcase" / "tools" / "linuxdeploy-wonky.AppImage" + tmp_path / "briefcase" / "tools" / "linuxdeploy-x86_64.AppImage" ), "--appdir", os.fsdecode(app_dir), @@ -189,7 +189,7 @@ def test_build_appimage(build_command, first_app, tmp_path, sub_stream_kw): "LINUXDEPLOY_OUTPUT_VERSION": "0.0.1", "DISABLE_COPYRIGHT_FILES_DEPLOYMENT": "1", "APPIMAGE_EXTRACT_AND_RUN": "1", - "ARCH": "wonky", + "ARCH": "x86_64", }, cwd=os.fsdecode( tmp_path / "base_path" / "build" / "first-app" / "linux" / "appimage" @@ -204,7 +204,7 @@ def test_build_appimage(build_command, first_app, tmp_path, sub_stream_kw): / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage", + / "First_App-0.0.1-x86_64.AppImage", 0o755, ) @@ -254,7 +254,7 @@ def test_build_appimage_with_plugin(build_command, first_app, tmp_path, sub_stre build_command._subprocess.Popen.assert_called_with( [ os.fsdecode( - tmp_path / "briefcase" / "tools" / "linuxdeploy-wonky.AppImage" + tmp_path / "briefcase" / "tools" / "linuxdeploy-x86_64.AppImage" ), "--appdir", os.fsdecode(app_dir), @@ -279,7 +279,7 @@ def test_build_appimage_with_plugin(build_command, first_app, tmp_path, sub_stre "LINUXDEPLOY_OUTPUT_VERSION": "0.0.1", "DISABLE_COPYRIGHT_FILES_DEPLOYMENT": "1", "APPIMAGE_EXTRACT_AND_RUN": "1", - "ARCH": "wonky", + "ARCH": "x86_64", }, cwd=os.fsdecode( tmp_path / "base_path" / "build" / "first-app" / "linux" / "appimage" @@ -305,7 +305,7 @@ def test_build_appimage_with_plugin(build_command, first_app, tmp_path, sub_stre / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage", + / "First_App-0.0.1-x86_64.AppImage", 0o755, ) @@ -336,7 +336,7 @@ def test_build_failure(build_command, first_app, tmp_path, sub_stream_kw): build_command._subprocess.Popen.assert_called_with( [ os.fsdecode( - tmp_path / "briefcase" / "tools" / "linuxdeploy-wonky.AppImage" + tmp_path / "briefcase" / "tools" / "linuxdeploy-x86_64.AppImage" ), "--appdir", os.fsdecode(app_dir), @@ -356,7 +356,7 @@ def test_build_failure(build_command, first_app, tmp_path, sub_stream_kw): "LINUXDEPLOY_OUTPUT_VERSION": "0.0.1", "DISABLE_COPYRIGHT_FILES_DEPLOYMENT": "1", "APPIMAGE_EXTRACT_AND_RUN": "1", - "ARCH": "wonky", + "ARCH": "x86_64", }, cwd=os.fsdecode( tmp_path / "base_path" / "build" / "first-app" / "linux" / "appimage" @@ -422,11 +422,11 @@ def test_build_appimage_in_docker(build_command, first_app, tmp_path, sub_stream "--env", "APPIMAGE_EXTRACT_AND_RUN=1", "--env", - "ARCH=wonky", + "ARCH=x86_64", "--workdir", "/app", f"briefcase/com.example.first-app:py3.{sys.version_info.minor}", - "/home/brutus/.cache/briefcase/tools/linuxdeploy-wonky.AppImage", + "/home/brutus/.cache/briefcase/tools/linuxdeploy-x86_64.AppImage", "--appdir", "/app/First App.AppDir", "--desktop-file", @@ -450,7 +450,7 @@ def test_build_appimage_in_docker(build_command, first_app, tmp_path, sub_stream / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage", + / "First_App-0.0.1-x86_64.AppImage", 0o755, ) @@ -546,11 +546,11 @@ def test_build_appimage_with_plugins_in_docker( "--env", "APPIMAGE_EXTRACT_AND_RUN=1", "--env", - "ARCH=wonky", + "ARCH=x86_64", "--workdir", "/app", f"briefcase/com.example.first-app:py3.{sys.version_info.minor}", - "/home/brutus/.cache/briefcase/tools/linuxdeploy-wonky.AppImage", + "/home/brutus/.cache/briefcase/tools/linuxdeploy-x86_64.AppImage", "--appdir", "/app/First App.AppDir", "--desktop-file", @@ -589,7 +589,7 @@ def test_build_appimage_with_plugins_in_docker( / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage", + / "First_App-0.0.1-x86_64.AppImage", 0o755, ) @@ -654,7 +654,7 @@ def test_build_appimage_with_support_package_update( build_command._subprocess.Popen.assert_called_with( [ os.fsdecode( - tmp_path / "briefcase" / "tools" / "linuxdeploy-wonky.AppImage" + tmp_path / "briefcase" / "tools" / "linuxdeploy-x86_64.AppImage" ), "--appdir", os.fsdecode(app_dir), @@ -674,7 +674,7 @@ def test_build_appimage_with_support_package_update( "LINUXDEPLOY_OUTPUT_VERSION": "0.0.1", "DISABLE_COPYRIGHT_FILES_DEPLOYMENT": "1", "APPIMAGE_EXTRACT_AND_RUN": "1", - "ARCH": "wonky", + "ARCH": "x86_64", }, cwd=os.fsdecode( tmp_path / "base_path" / "build" / "first-app" / "linux" / "appimage" @@ -689,6 +689,6 @@ def test_build_appimage_with_support_package_update( / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage", + / "First_App-0.0.1-x86_64.AppImage", 0o755, ) diff --git a/tests/platforms/linux/appimage/test_create.py b/tests/platforms/linux/appimage/test_create.py index 94d40b93a..36f13eb75 100644 --- a/tests/platforms/linux/appimage/test_create.py +++ b/tests/platforms/linux/appimage/test_create.py @@ -9,12 +9,14 @@ @pytest.fixture def create_command(first_app_config, tmp_path): - return LinuxAppImageCreateCommand( + command = LinuxAppImageCreateCommand( logger=Log(), console=Console(), base_path=tmp_path / "base_path", data_path=tmp_path / "briefcase", ) + command.tools.host_arch = "x86_64" + return command def test_default_options(create_command): @@ -82,15 +84,16 @@ def test_finalize_nodocker(create_command, first_app_config, capsys): @pytest.mark.parametrize( - "manylinux, tag, host_arch, is_user_mapped, context", + "manylinux, tag, host_os, host_arch, is_user_mapped, context", [ # Fallback. - (None, None, "x86_64", False, {"use_non_root_user": True}), - # x86_64 architecture, all versions + (None, None, "Linux", "x86_64", False, {"use_non_root_user": True}), + # Linux on x86_64 architecture, all versions # Explicit tag ( "manylinux1", "2023-03-05-271004f", + "Linux", "x86_64", True, { @@ -103,6 +106,7 @@ def test_finalize_nodocker(create_command, first_app_config, capsys): ( "manylinux2010", "latest", + "Linux", "x86_64", False, { @@ -115,6 +119,7 @@ def test_finalize_nodocker(create_command, first_app_config, capsys): ( "manylinux2014", None, + "Linux", "x86_64", True, { @@ -126,6 +131,7 @@ def test_finalize_nodocker(create_command, first_app_config, capsys): ( "manylinux_2_24", None, + "Linux", "x86_64", True, { @@ -137,6 +143,7 @@ def test_finalize_nodocker(create_command, first_app_config, capsys): ( "manylinux_2_28", None, + "Linux", "x86_64", False, { @@ -145,14 +152,41 @@ def test_finalize_nodocker(create_command, first_app_config, capsys): "use_non_root_user": True, }, ), - # non x86 architecture + # Linux on i686 hardware + ( + "manylinux_2_28", + None, + "Linux", + "i686", + False, + { + "manylinux_image": "manylinux_2_28_i686:latest", + "vendor_base": "almalinux", + "use_non_root_user": True, + }, + ), + # macOS on x86_64 + ( + "manylinux2014", + None, + "Darwin", + "x86_64", + True, + { + "manylinux_image": "manylinux2014_x86_64:latest", + "vendor_base": "centos", + "use_non_root_user": False, + }, + ), + # macOS on Apple Silicon ( "manylinux2014", None, - "aarch64", + "Darwin", + "arm64", True, { - "manylinux_image": "manylinux2014_aarch64:latest", + "manylinux_image": "manylinux2014_x86_64:latest", "vendor_base": "centos", "use_non_root_user": False, }, @@ -164,6 +198,7 @@ def test_output_format_template_context( first_app_config, manylinux, tag, + host_os, host_arch, is_user_mapped, context, @@ -178,6 +213,7 @@ def test_output_format_template_context( if tag: first_app_config.manylinux_image_tag = tag + create_command.tools.host_os = host_os create_command.tools.host_arch = host_arch assert create_command.output_format_template_context(first_app_config) == context diff --git a/tests/platforms/linux/appimage/test_mixin.py b/tests/platforms/linux/appimage/test_mixin.py index ec491486f..73f23354c 100644 --- a/tests/platforms/linux/appimage/test_mixin.py +++ b/tests/platforms/linux/appimage/test_mixin.py @@ -6,6 +6,7 @@ import briefcase.platforms.linux.appimage from briefcase.console import Console, Log from briefcase.integrations.docker import Docker, DockerAppContext +from briefcase.integrations.linuxdeploy import LinuxDeploy from briefcase.integrations.subprocess import Subprocess from briefcase.platforms.linux.appimage import ( LinuxAppImageBuildCommand, @@ -15,12 +16,15 @@ @pytest.fixture def create_command(tmp_path): - return LinuxAppImageCreateCommand( + command = LinuxAppImageCreateCommand( logger=Log(), console=Console(), base_path=tmp_path / "base_path", data_path=tmp_path / "briefcase", ) + # Mock verified linuxdeploy + command.tools.linuxdeploy = LinuxDeploy(tools=command.tools) + return command def test_binary_path(create_command, first_app_config, tmp_path): diff --git a/tests/platforms/linux/appimage/test_package.py b/tests/platforms/linux/appimage/test_package.py index b46af82df..f837d0c8b 100644 --- a/tests/platforms/linux/appimage/test_package.py +++ b/tests/platforms/linux/appimage/test_package.py @@ -15,7 +15,7 @@ def package_command(tmp_path, first_app_config): data_path=tmp_path / "briefcase", ) # Mock the host architecture to something repeatable - command.tools.host_arch = "wonky" + command.tools.host_arch = "x86_64" # Ensure the dist folder exists (tmp_path / "base_path" / "dist").mkdir(parents=True) @@ -34,7 +34,7 @@ def test_package_app(package_command, first_app_config, tmp_path): / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage", + / "First_App-0.0.1-x86_64.AppImage", "AppImage", ) @@ -42,4 +42,6 @@ def test_package_app(package_command, first_app_config, tmp_path): package_command.package_app(first_app_config) # The binary has been copied to the dist folder - assert (tmp_path / "base_path" / "dist" / "First_App-0.0.1-wonky.AppImage").exists() + assert ( + tmp_path / "base_path" / "dist" / "First_App-0.0.1-x86_64.AppImage" + ).exists() diff --git a/tests/platforms/linux/appimage/test_run.py b/tests/platforms/linux/appimage/test_run.py index 83480be3d..c27375371 100644 --- a/tests/platforms/linux/appimage/test_run.py +++ b/tests/platforms/linux/appimage/test_run.py @@ -21,7 +21,7 @@ def run_command(tmp_path): command.tools.home_path = tmp_path / "home" # Set the host architecture for test purposes. - command.tools.host_arch = "wonky" + command.tools.host_arch = "x86_64" command.tools.subprocess = mock.MagicMock(spec_set=Subprocess) @@ -63,7 +63,7 @@ def test_run_app(run_command, first_app_config, tmp_path): / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage" + / "First_App-0.0.1-x86_64.AppImage" ) ], cwd=tmp_path / "home", @@ -104,7 +104,7 @@ def test_run_app_with_passthrough(run_command, first_app_config, tmp_path): / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage" + / "First_App-0.0.1-x86_64.AppImage" ), "foo", "--bar", @@ -141,7 +141,7 @@ def test_run_app_failed(run_command, first_app_config, tmp_path): / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage" + / "First_App-0.0.1-x86_64.AppImage" ) ], cwd=tmp_path / "home", @@ -173,7 +173,7 @@ def test_run_app_test_mode(run_command, first_app_config, tmp_path): / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage" + / "First_App-0.0.1-x86_64.AppImage" ) ], cwd=tmp_path / "home", @@ -215,7 +215,7 @@ def test_run_app_test_mode_with_args(run_command, first_app_config, tmp_path): / "first-app" / "linux" / "appimage" - / "First_App-0.0.1-wonky.AppImage" + / "First_App-0.0.1-x86_64.AppImage" ), "foo", "--bar", diff --git a/tests/platforms/linux/system/test_mixin__properties.py b/tests/platforms/linux/system/test_mixin__properties.py index 35f40ee78..fae88c340 100644 --- a/tests/platforms/linux/system/test_mixin__properties.py +++ b/tests/platforms/linux/system/test_mixin__properties.py @@ -1,3 +1,5 @@ +from unittest.mock import MagicMock + import pytest from briefcase.console import Console, Log @@ -5,20 +7,6 @@ from briefcase.platforms.linux.system import LinuxSystemBuildCommand -@pytest.mark.parametrize( - "host_arch, linux_arch", - [ - ("x86_64", "amd64"), - ("aarch64", "arm64"), - ("armv6l", "armhf"), - ], -) -def test_linux_arch(create_command, host_arch, linux_arch): - """Host architectures are transformed to Linux-accepted values.""" - create_command.tools.host_arch = host_arch - assert create_command.linux_arch == linux_arch - - @pytest.mark.parametrize( "vendor, codename", [ @@ -93,14 +81,22 @@ def test_binary_path(create_command, first_app_config, tmp_path): @pytest.mark.parametrize( "packaging_format, filename", - [("deb", "first-app_0.0.1-1~somevendor-surprising_amd64.deb")], + [ + ("deb", "first-app_0.0.1-1~somevendor-surprising_wonky.deb"), + ("rpm", "first-app-0.0.1-1.elsurprising.wonky.rpm"), + ("pkg", "first-app-0.0.1-1-wonky.pkg.tar.zst"), + ], ) def test_distribution_path( - create_command, first_app_config, packaging_format, filename, tmp_path + create_command, + first_app_config, + packaging_format, + filename, + tmp_path, ): """The distribution path contains vendor details.""" - # Force the architecture to x86_64 for test purposes. - create_command.tools.host_arch = "x86_64" + # Mock return value for ABI from packaging system + create_command._build_env_abi = MagicMock(return_value="wonky") # Force a dummy vendor:codename for test purposes. first_app_config.target_vendor = "somevendor" diff --git a/tests/platforms/linux/system/test_package.py b/tests/platforms/linux/system/test_package.py index d62b6b117..6c45635c3 100644 --- a/tests/platforms/linux/system/test_package.py +++ b/tests/platforms/linux/system/test_package.py @@ -1,9 +1,11 @@ +import subprocess from unittest import mock import pytest from briefcase.console import Console, Log from briefcase.exceptions import BriefcaseCommandError +from briefcase.integrations.subprocess import Subprocess from briefcase.platforms.linux.system import LinuxSystemPackageCommand @@ -17,9 +19,6 @@ def package_command(monkeypatch, first_app, tmp_path): ) command.tools.home_path = tmp_path / "home" - # Set the host architecture for test purposes. - command.tools.host_arch = "wonky" - # Run outside docker for these tests. command.target_image = None @@ -36,7 +35,7 @@ def package_command(monkeypatch, first_app, tmp_path): def test_formats(package_command): - "The supported packaging formats are as expected." + """The supported packaging formats are as expected.""" assert package_command.packaging_formats == ["deb", "rpm", "pkg", "system"] @@ -67,12 +66,25 @@ def test_formats(package_command): ], ) def test_distribution_path( - package_command, first_app, format, vendor, codename, revision, filename, tmp_path + package_command, + first_app, + format, + vendor, + codename, + revision, + filename, + tmp_path, ): first_app.packaging_format = format first_app.target_vendor = vendor first_app.target_codename = codename + # Mock return value for ABI from packaging system + package_command.tools[first_app].app_context = mock.MagicMock(spec_set=Subprocess) + package_command.tools[first_app].app_context.check_output = mock.MagicMock( + return_value="wonky" + ) + if revision: first_app.revision = revision @@ -81,6 +93,33 @@ def test_distribution_path( == tmp_path / "base_path" / "dist" / filename ) + # Confirm ABI was requested from build env + package_command.tools[first_app].app_context.check_output.assert_called_with( + { + "deb": ["dpkg", "--print-architecture"], + "rpm": ["rpm", "--eval", "%_target_cpu"], + "pkg": ["pacman-conf", "Architecture"], + }[format] + ) + + +@pytest.mark.parametrize("format", ["rpm", "deb", "pkg"]) +def test_build_env_abi_failure(package_command, first_app, format): + """If the subprocess to get the build ABI fails, an error is raised.""" + first_app.packaging_format = format + + # Mock return value for ABI from packaging system + package_command.tools[first_app].app_context = mock.MagicMock(spec_set=Subprocess) + package_command.tools[first_app].app_context.check_output = mock.MagicMock( + side_effect=subprocess.CalledProcessError(returncode=1, cmd="pkg -arch") + ) + + with pytest.raises( + BriefcaseCommandError, + match="Failed to determine build environment's ABI for packaging.", + ): + getattr(package_command, f"{format}_abi")(first_app) + @pytest.mark.parametrize( "base_vendor, input_format, output_format", @@ -93,7 +132,7 @@ def test_distribution_path( ("debian", "deb", "deb"), ("redhat", "rpm", "rpm"), ("arch", "pkg", "pkg"), - # This is technically posssible, but probably ill-advised + # This is technically possible, but probably ill-advised ("debian", "rpm", "rpm"), # Unknown base vendor, but explicit packaging format (None, "deb", "deb"), @@ -102,9 +141,13 @@ def test_distribution_path( ], ) def test_adjust_packaging_format( - package_command, first_app, base_vendor, input_format, output_format + package_command, + first_app, + base_vendor, + input_format, + output_format, ): - "The packaging format can be ajusted based on host system knowledge" + """The packaging format can be adjusted based on host system knowledge.""" first_app.target_vendor_base = base_vendor first_app.packaging_format = input_format @@ -171,7 +214,7 @@ def test_package_pkg_app(package_command, first_app): def test_package_unknown_format(package_command, first_app): - "Unknown/unsupported packaging formats raise an error" + """Unknown/unsupported packaging formats raise an error.""" # Set the packaging format first_app.packaging_format = "unknown" diff --git a/tests/platforms/linux/system/test_package__deb.py b/tests/platforms/linux/system/test_package__deb.py index 6d32d4d52..a12aef3ed 100644 --- a/tests/platforms/linux/system/test_package__deb.py +++ b/tests/platforms/linux/system/test_package__deb.py @@ -27,8 +27,8 @@ def package_command(first_app, tmp_path): ) command.tools.home_path = tmp_path / "home" - # Set the host architecture for test purposes. - command.tools.host_arch = "wonky" + # Mock ABI from packaging system + command._deb_abi = "wonky" # Mock the app context command.tools.app_tools[first_app].app_context = mock.MagicMock() @@ -121,7 +121,7 @@ def test_verify_docker(monkeypatch, package_command, first_app_deb): dpkg_deb.exists.assert_not_called() -@pytest.mark.skipif(sys.platform == "win32", reason="Can't build PKGs on Windows") +@pytest.mark.skipif(sys.platform == "win32", reason="Can't build debs on Windows") def test_deb_package(package_command, first_app_deb, tmp_path): """A deb app can be packaged.""" bundle_path = ( @@ -340,7 +340,7 @@ def test_deb_package_extra_requirements(package_command, first_app_deb, tmp_path def test_deb_package_failure(package_command, first_app_deb, tmp_path): - """If an packaging doesn't succeed, an error is raised.""" + """If a packaging doesn't succeed, an error is raised.""" bundle_path = ( tmp_path / "base_path" / "build" / "first-app" / "somevendor" / "surprising" ) diff --git a/tests/platforms/linux/system/test_package__pkg.py b/tests/platforms/linux/system/test_package__pkg.py index 9954754f8..22a8904be 100644 --- a/tests/platforms/linux/system/test_package__pkg.py +++ b/tests/platforms/linux/system/test_package__pkg.py @@ -25,8 +25,8 @@ def package_command(first_app, tmp_path): ) command.tools.home_path = tmp_path / "home" - # Set the host architecture for test purposes. - command.tools.host_arch = "wonky" + # Mock ABI from packaging system + command._pkg_abi = "wonky" # Mock the app context command.tools.app_tools[first_app].app_context = mock.MagicMock() @@ -220,6 +220,7 @@ def test_pkg_package(package_command, first_app_pkg, tmp_path): ], check=True, cwd=(bundle_path / "pkgbuild"), + env={"PKGEXT": ".pkg.tar.zst"}, ) # The pkg was moved into the final location @@ -317,6 +318,7 @@ def test_pkg_re_package(package_command, first_app_pkg, tmp_path): ], check=True, cwd=(bundle_path / "pkgbuild"), + env={"PKGEXT": ".pkg.tar.zst"}, ) # The pkg was moved into the final location @@ -405,6 +407,7 @@ def test_pkg_package_extra_requirements(package_command, first_app_pkg, tmp_path ], check=True, cwd=(bundle_path / "pkgbuild"), + env={"PKGEXT": ".pkg.tar.zst"}, ) # The pkg was moved into the final location @@ -454,6 +457,7 @@ def test_pkg_package_failure(package_command, first_app_pkg, tmp_path): ], check=True, cwd=(bundle_path / "pkgbuild"), + env={"PKGEXT": ".pkg.tar.zst"}, ) # The pkg wasn't built, so it wasn't moved. @@ -462,7 +466,7 @@ def test_pkg_package_failure(package_command, first_app_pkg, tmp_path): @pytest.mark.skipif(sys.platform == "win32", reason="Can't build PKGs on Windows") def test_no_changelog(package_command, first_app_pkg, tmp_path): - """If an packaging doesn't succeed, an error is raised.""" + """If a packaging doesn't succeed, an error is raised.""" bundle_path = ( tmp_path / "base_path" / "build" / "first-app" / "somevendor" / "surprising" ) diff --git a/tests/platforms/linux/system/test_package__rpm.py b/tests/platforms/linux/system/test_package__rpm.py index 3a580d8a5..cf7f1ea5f 100644 --- a/tests/platforms/linux/system/test_package__rpm.py +++ b/tests/platforms/linux/system/test_package__rpm.py @@ -25,8 +25,8 @@ def package_command(first_app, tmp_path): ) command.tools.home_path = tmp_path / "home" - # Set the host architecture for test purposes. - command.tools.host_arch = "wonky" + # Mock ABI from packaging system + command._rpm_abi = "wonky" # Mock the app context command.tools.app_tools[first_app].app_context = mock.MagicMock() diff --git a/tests/platforms/linux/test_DockerOpenCommand.py b/tests/platforms/linux/test_DockerOpenCommand.py index 1b813ee71..b6ba97b71 100644 --- a/tests/platforms/linux/test_DockerOpenCommand.py +++ b/tests/platforms/linux/test_DockerOpenCommand.py @@ -22,10 +22,19 @@ def open_command(tmp_path): ) command.tools.os = MagicMock(spec_set=os) + # Mock x86_64 for linuxdeploy verification + command.tools.host_arch = "x86_64" + # Store the underlying subprocess instance command._subprocess = MagicMock(spec_set=Subprocess) command.tools.subprocess = command._subprocess + # Mock existence of linuxdeploy in tools + create_file( + command.tools.base_path / "linuxdeploy-x86_64.AppImage", + content="", + ) + return command @@ -121,7 +130,7 @@ def test_open_no_docker_linux(open_command, first_app_config, tmp_path): @pytest.mark.skipif(sys.platform != "darwin", reason="macOS specific test") def test_open_no_docker_macOS(open_command, first_app_config, tmp_path): - """On macOS, Open runs `open` on the project folder if we specify --no- docker.""" + """On macOS, Open runs `open` on the project folder if we specify --no-docker.""" # Create the desktop file that would be in the project folder. create_file( open_command.project_path(first_app_config) diff --git a/tests/platforms/linux/test_LinuxMixin__support_package_url.py b/tests/platforms/linux/test_LinuxMixin__support_package_url.py index 351c29993..93b64b19e 100644 --- a/tests/platforms/linux/test_LinuxMixin__support_package_url.py +++ b/tests/platforms/linux/test_LinuxMixin__support_package_url.py @@ -2,34 +2,63 @@ @pytest.mark.parametrize( - "support_revision, host_arch, url", + "support_revision, host_arch, is_32bit_python, url", [ ( "3.10.9+20230116", "x86_64", + False, "20230116/cpython-3.10.9+20230116-x86_64-unknown-linux-gnu-install_only.tar.gz", ), ( "3.11.1+20230116", "aarch64", + False, "20230116/cpython-3.11.1+20230116-aarch64-unknown-linux-gnu-install_only.tar.gz", ), + ( + "3.11.1+20230116", + "aarch64", + True, + "20230116/cpython-3.11.1+20230116-armv7-unknown-linux-gnu-install_only.tar.gz", + ), + ( + "3.11.1+20230116", + "armv7l", + True, + "20230116/cpython-3.11.1+20230116-armv7l-unknown-linux-gnu-install_only.tar.gz", + ), ( "3.8.16+20221220", "x86_64", + False, "20221220/cpython-3.8.16+20221220-x86_64-unknown-linux-gnu-install_only.tar.gz", ), + ( + "3.8.16+20221220", + "x86_64", + True, + "20221220/cpython-3.8.16+20221220-i686-unknown-linux-gnu-install_only.tar.gz", + ), + ( + "3.8.16+20221220", + "i686", + True, + "20221220/cpython-3.8.16+20221220-i686-unknown-linux-gnu-install_only.tar.gz", + ), ], ) def test_support_package_url( linux_mixin, host_arch, support_revision, + is_32bit_python, url, ): """The support package URL is customized.""" # Set up the host architecture linux_mixin.tools.host_arch = host_arch + linux_mixin.tools.is_32bit_python = is_32bit_python assert linux_mixin.support_package_url(support_revision) == ( "https://github.com/indygreg/python-build-standalone/releases/download/" + url diff --git a/tests/platforms/windows/app/test_build.py b/tests/platforms/windows/app/test_build.py index 2d6ac2531..b096b3b89 100644 --- a/tests/platforms/windows/app/test_build.py +++ b/tests/platforms/windows/app/test_build.py @@ -27,6 +27,7 @@ def build_command(tmp_path): data_path=tmp_path / "briefcase", ) command.tools.host_os = "Windows" + command.tools.host_arch = "AMD64" command.tools.subprocess = mock.MagicMock(spec_set=Subprocess) command.tools.shutil = mock.MagicMock(spec_set=shutil) command.tools.download = mock.MagicMock() diff --git a/tests/platforms/windows/app/test_create.py b/tests/platforms/windows/app/test_create.py index ded0a1544..bb29009e3 100644 --- a/tests/platforms/windows/app/test_create.py +++ b/tests/platforms/windows/app/test_create.py @@ -29,6 +29,40 @@ def test_unsupported_host_os(create_command, host_os): create_command() +@pytest.mark.parametrize("host_arch", ["i686", "ARM64", "wonky"]) +def test_unsupported_arch(create_command, host_arch): + """Windows commands can only run on x86-64.""" + create_command.tools.host_os = "Windows" + create_command.tools.host_arch = host_arch + + with pytest.raises( + UnsupportedHostError, + match=f"Windows applications cannot be built on an {host_arch} machine.", + ): + create_command() + + +def test_supported_arch(create_command): + """Windows command are allowed to run on x86-64.""" + create_command.tools.host_os = "Windows" + create_command.tools.host_arch = "AMD64" + + create_command() + + +def test_unsupported_32bit_python(create_command): + """Windows commands cannot run with 32bit Python.""" + create_command.tools.host_os = "Windows" + create_command.tools.host_arch = "AMD64" + create_command.tools.is_32bit_python = True + + with pytest.raises( + UnsupportedHostError, + match="Windows applications cannot be built using a 32bit version of Python", + ): + create_command() + + @pytest.mark.parametrize( "version, version_triple", [ From a0935885d378af28f390a2c2bba6a7c894c6181e Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Thu, 27 Jul 2023 19:16:18 -0400 Subject: [PATCH 02/11] Bump JDK to `17.0.8+7` and Android Command-line Tools to `9477386` --- src/briefcase/integrations/android_sdk.py | 4 +-- src/briefcase/integrations/java.py | 8 +++--- .../android_sdk/AndroidSDK/test_properties.py | 2 +- .../android_sdk/AndroidSDK/test_verify.py | 12 ++++---- tests/integrations/java/test_JDK__upgrade.py | 12 ++++---- tests/integrations/java/test_JDK__verify.py | 28 +++++++++---------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/briefcase/integrations/android_sdk.py b/src/briefcase/integrations/android_sdk.py index 643625fc8..ff2161c6e 100644 --- a/src/briefcase/integrations/android_sdk.py +++ b/src/briefcase/integrations/android_sdk.py @@ -95,11 +95,11 @@ def cmdline_tools_path(self) -> Path: @property def cmdline_tools_version(self) -> str: # This is the version of the Android SDK Command-line tools that - # are current as of May 2022. These tools can generally self-update, + # are current as of July 2023. These tools can generally self-update, # so using a fixed download URL isn't a problem. # However, if/when this version number is changed, ensure that the # checks done during verification include any required upgrade steps. - return "8092744" + return "9477386" @property def cmdline_tools_version_path(self) -> Path: diff --git a/src/briefcase/integrations/java.py b/src/briefcase/integrations/java.py index 18c87066d..c369cdfcb 100644 --- a/src/briefcase/integrations/java.py +++ b/src/briefcase/integrations/java.py @@ -20,7 +20,7 @@ class JDK(ManagedTool): # As of 12 May 2023, 17.0.7+7 is the current OpenJDK # https://adoptium.net/temurin/releases/ JDK_MAJOR_VER = "17" - JDK_RELEASE = "17.0.7" + JDK_RELEASE = "17.0.8" JDK_BUILD = "7" JDK_INSTALL_DIR_NAME = f"java{JDK_MAJOR_VER}" @@ -75,7 +75,7 @@ def version_from_path(cls, tools: ToolCache, java_path: str | Path) -> str: :param tools: ToolCache of available tools :param java_path: File path to a candidate JDK install - :return: JDK release version; e.g. "17.0.7" + :return: JDK release version; e.g. "17.0.8" """ output = tools.subprocess.check_output( [ @@ -83,7 +83,7 @@ def version_from_path(cls, tools: ToolCache, java_path: str | Path) -> str: "-version", ], ) - # javac's output should look like "javac 17.0.7\n" + # javac's output should look like "javac 17.0.8\n" return output.strip("\n").split(" ")[1] @classmethod @@ -289,7 +289,7 @@ def install(self): jdk_zip_path.unlink() # Zip file no longer needed once unpacked. - # The tarball will unpack into /tools/jdk-17.0.7+7 + # The tarball will unpack into /tools/jdk-17.0.8+7 # (or whatever name matches the current release). # We turn this into /tools/java so we have a consistent name. java_unpack_path = ( diff --git a/tests/integrations/android_sdk/AndroidSDK/test_properties.py b/tests/integrations/android_sdk/AndroidSDK/test_properties.py index 29f1ad787..088209a13 100644 --- a/tests/integrations/android_sdk/AndroidSDK/test_properties.py +++ b/tests/integrations/android_sdk/AndroidSDK/test_properties.py @@ -21,7 +21,7 @@ def test_cmdline_tools_url(mock_tools, android_sdk, host_os, host_arch, name): mock_tools.host_arch = host_arch assert android_sdk.cmdline_tools_url == ( - f"https://dl.google.com/android/repository/commandlinetools-{name}-8092744_latest.zip" + f"https://dl.google.com/android/repository/commandlinetools-{name}-9477386_latest.zip" ) diff --git a/tests/integrations/android_sdk/AndroidSDK/test_verify.py b/tests/integrations/android_sdk/AndroidSDK/test_verify.py index 03b63e695..0c38b93e0 100644 --- a/tests/integrations/android_sdk/AndroidSDK/test_verify.py +++ b/tests/integrations/android_sdk/AndroidSDK/test_verify.py @@ -417,7 +417,7 @@ def test_download_sdk(mock_tools, tmp_path): # Validate that the SDK was downloaded and unpacked url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, @@ -487,7 +487,7 @@ def test_download_sdk_legacy_install(mock_tools, tmp_path): # Validate that the SDK was downloaded and unpacked url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, @@ -546,7 +546,7 @@ def test_download_sdk_if_sdkmanager_not_executable(mock_tools, tmp_path): # Create pre-existing non-executable `sdkmanager`. (cmdline_tools_base_path / "latest" / "bin").mkdir(parents=True) (cmdline_tools_base_path / "latest" / "bin" / "sdkmanager").touch(mode=0o644) - (cmdline_tools_base_path / "8092744").touch() + (cmdline_tools_base_path / "9477386").touch() # The download will produce a cached file cache_file = MagicMock() @@ -564,7 +564,7 @@ def test_download_sdk_if_sdkmanager_not_executable(mock_tools, tmp_path): # Validate that the SDK was downloaded and unpacked url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, @@ -597,7 +597,7 @@ def test_raises_networkfailure_on_connectionerror(mock_tools): # The download was attempted url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, @@ -624,7 +624,7 @@ def test_detects_bad_zipfile(mock_tools, tmp_path): # The download attempt was made. url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, diff --git a/tests/integrations/java/test_JDK__upgrade.py b/tests/integrations/java/test_JDK__upgrade.py index b9c86fbcd..af1e2e190 100644 --- a/tests/integrations/java/test_JDK__upgrade.py +++ b/tests/integrations/java/test_JDK__upgrade.py @@ -65,7 +65,7 @@ def rmtree(path): mock_tools.download.file.return_value = archive # Create a directory to make it look like Java was downloaded and unpacked. - (tmp_path / "tools" / "jdk-17.0.7+7").mkdir(parents=True) + (tmp_path / "tools" / "jdk-17.0.8+7").mkdir(parents=True) # Create an SDK wrapper jdk = JDK(mock_tools, java_home=java_home) @@ -79,7 +79,7 @@ def rmtree(path): # A download was initiated mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) @@ -114,7 +114,7 @@ def rmtree(path): mock_tools.download.file.return_value = archive # Create a directory to make it look like Java was downloaded and unpacked. - (tmp_path / "tools" / "jdk-17.0.7+7").mkdir(parents=True) + (tmp_path / "tools" / "jdk-17.0.8+7").mkdir(parents=True) # Create an SDK wrapper jdk = JDK(mock_tools, java_home=java_home) @@ -128,7 +128,7 @@ def rmtree(path): # A download was initiated mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.8_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) @@ -170,7 +170,7 @@ def rmtree(path): # A download was initiated mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) @@ -212,7 +212,7 @@ def rmtree(path): # A download was initiated mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) diff --git a/tests/integrations/java/test_JDK__verify.py b/tests/integrations/java/test_JDK__verify.py index 6c87851a0..b5ce5e301 100644 --- a/tests/integrations/java/test_JDK__verify.py +++ b/tests/integrations/java/test_JDK__verify.py @@ -58,7 +58,7 @@ def test_macos_tool_java_home(mock_tools, capsys): # Mock 2 calls to check_output. mock_tools.subprocess.check_output.side_effect = [ "/path/to/java", - "javac 17.0.7\n", + "javac 17.0.8\n", ] # Create a JDK wrapper by verification @@ -179,7 +179,7 @@ def test_macos_provided_overrides_tool_java_home(mock_tools, capsys): mock_tools.os.environ = {"JAVA_HOME": "/path/to/java"} # Mock return value from javac. libexec won't be invoked. - mock_tools.subprocess.check_output.return_value = "javac 17.0.7\n" + mock_tools.subprocess.check_output.return_value = "javac 17.0.8\n" # Create a JDK wrapper by verification JDK.verify(mock_tools) @@ -205,7 +205,7 @@ def test_valid_provided_java_home(mock_tools, capsys): mock_tools.os.environ = {"JAVA_HOME": "/path/to/java"} # Mock return value from javac. - mock_tools.subprocess.check_output.return_value = "javac 17.0.7\n" + mock_tools.subprocess.check_output.return_value = "javac 17.0.8\n" # Create a JDK wrapper by verification JDK.verify(mock_tools) @@ -404,7 +404,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Darwin", "x86_64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.8_7.tar.gz", "java17/Contents/Home", False, ), @@ -412,7 +412,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Darwin", "arm64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.8_7.tar.gz", "java17/Contents/Home", False, ), @@ -420,7 +420,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "x86_64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", "java17", False, ), @@ -428,7 +428,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "aarch64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.8_7.tar.gz", "java17", False, ), @@ -436,7 +436,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "aarch64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.8_7.tar.gz", "java17", True, ), @@ -444,7 +444,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "armv7l", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.8_7.tar.gz", "java17", False, ), @@ -452,7 +452,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "armv8l", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.8_7.tar.gz", "java17", False, ), @@ -460,7 +460,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Windows", "AMD64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_windows_hotspot_17.0.7_7.zip", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_windows_hotspot_17.0.8_7.zip", "java17", False, ), @@ -492,7 +492,7 @@ def test_successful_jdk_download( mock_tools.download.file.return_value = archive # Create a directory to make it look like Java was downloaded and unpacked. - (tmp_path / "tools" / "jdk-17.0.7+7").mkdir(parents=True) + (tmp_path / "tools" / "jdk-17.0.8+7").mkdir(parents=True) # Invoke the verify call JDK.verify(mock_tools) @@ -547,7 +547,7 @@ def test_jdk_download_failure(mock_tools, tmp_path): # That download was attempted mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) @@ -575,7 +575,7 @@ def test_invalid_jdk_archive(mock_tools, tmp_path): # The download occurred mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", + "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) From 3dd2018e8900ff819b3adbb6d5dd3b550b6f2f67 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Sun, 30 Jul 2023 20:59:36 -0400 Subject: [PATCH 03/11] Fix tests after merge from main --- tests/platforms/linux/appimage/test_build.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/platforms/linux/appimage/test_build.py b/tests/platforms/linux/appimage/test_build.py index b44edf453..88096f163 100644 --- a/tests/platforms/linux/appimage/test_build.py +++ b/tests/platforms/linux/appimage/test_build.py @@ -175,7 +175,7 @@ def test_build_appimage(build_command, first_app, debug_mode, tmp_path, sub_stre "LINUXDEPLOY_OUTPUT_VERSION": "0.0.1", "DISABLE_COPYRIGHT_FILES_DEPLOYMENT": "1", "APPIMAGE_EXTRACT_AND_RUN": "1", - "ARCH": "wonky", + "ARCH": "x86_64", } if debug_mode: expected_env["DEBUG"] = "1" @@ -436,7 +436,7 @@ def test_build_appimage_in_docker(build_command, first_app, tmp_path, sub_stream "--workdir", "/app", f"briefcase/com.example.first-app:py3.{sys.version_info.minor}", - "/briefcase/tools/linuxdeploy-wonky.AppImage", + "/briefcase/tools/linuxdeploy-x86_64.AppImage", "--appdir", "/app/First App.AppDir", "--desktop-file", @@ -561,7 +561,7 @@ def test_build_appimage_with_plugins_in_docker( "--workdir", "/app", f"briefcase/com.example.first-app:py3.{sys.version_info.minor}", - "/briefcase/tools/linuxdeploy-wonky.AppImage", + "/briefcase/tools/linuxdeploy-x86_64.AppImage", "--appdir", "/app/First App.AppDir", "--desktop-file", From 1e6184ce34a73dcc6002b047d2d0ee3a584a0da8 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Mon, 31 Jul 2023 18:49:08 -0400 Subject: [PATCH 04/11] Capture bitness and platform separately for `MissingSupportPackage` --- src/briefcase/exceptions.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/briefcase/exceptions.py b/src/briefcase/exceptions.py index 14fcd4034..bb12101b5 100644 --- a/src/briefcase/exceptions.py +++ b/src/briefcase/exceptions.py @@ -167,14 +167,16 @@ def __init__(self, app_bundle_path): class MissingSupportPackage(BriefcaseCommandError): def __init__(self, python_version_tag, platform, host_arch, is_32bit): self.python_version_tag = python_version_tag - self.platform = f"{'32 bit ' if is_32bit else ''}{platform}" + self.platform = platform self.host_arch = host_arch + self.is_32bit = is_32bit + platform_name = f"{'32 bit ' if is_32bit else ''}{platform}" super().__init__( f"""\ -Unable to download {self.platform} support package for Python {self.python_version_tag} on {self.host_arch}. +Unable to download {platform_name} support package for Python {self.python_version_tag} on {self.host_arch}. This is likely because either Python {self.python_version_tag} and/or {self.host_arch} is not yet -supported on {self.platform}. You will need to: +supported on {platform_name}. You will need to: * Use an older version of Python; or * Compile your own custom support package. """ From 2ef9191433dcb33aa09fda01282b8dee477e0d65 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Mon, 31 Jul 2023 19:00:56 -0400 Subject: [PATCH 05/11] Disable building AppImages on Apple Silicon - On Apple Silicon, Docker Desktop runs x86-64 containers in an emulation mode in an arm64 Linux VM; however, due to present issues in the implementation of QEMU used, AppImages cannot successfully run. Since linuxdeploy itself is an AppImage, it cannot run and AppImages cannot be created. --- src/briefcase/integrations/linuxdeploy.py | 12 +++++------- src/briefcase/platforms/linux/appimage.py | 4 ++-- .../test_LinuxDeployQtPlugin__properties.py | 2 -- .../linuxdeploy/test_LinuxDeploy__properties.py | 2 -- tests/platforms/linux/appimage/test_create.py | 13 ------------- 5 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/briefcase/integrations/linuxdeploy.py b/src/briefcase/integrations/linuxdeploy.py index 9dbcd7aba..b00e07082 100644 --- a/src/briefcase/integrations/linuxdeploy.py +++ b/src/briefcase/integrations/linuxdeploy.py @@ -50,15 +50,13 @@ def file_path(self) -> Path: """The folder on the local filesystem that contains the file_name.""" @classmethod - def arch(cls, host_os: str, host_arch: str) -> str: - # always use the x86-64 arch on macOS since the - # manylinux image will always be x86-64 for macOS - arch = "x86_64" if host_os == "Darwin" else host_arch + def arch(cls, host_arch: str) -> str: + """The architecture defined (and supported) by linuxdeploy for AppImages.""" try: return { "x86_64": "x86_64", "i686": "i386", - }[arch] + }[host_arch] except KeyError as e: raise UnsupportedHostError( f"Linux AppImages cannot be built on {host_arch}." @@ -224,7 +222,7 @@ class LinuxDeployQtPlugin(LinuxDeployPluginBase, ManagedTool): @property def file_name(self) -> str: - return f"linuxdeploy-plugin-qt-{self.arch(self.tools.host_os, self.tools.host_arch)}.AppImage" + return f"linuxdeploy-plugin-qt-{self.arch(self.tools.host_arch)}.AppImage" @property def download_url(self) -> str: @@ -335,7 +333,7 @@ def file_path(self) -> Path: @property def file_name(self) -> str: - return f"linuxdeploy-{self.arch(self.tools.host_os, self.tools.host_arch)}.AppImage" + return f"linuxdeploy-{self.arch(self.tools.host_arch)}.AppImage" @property def download_url(self) -> str: diff --git a/src/briefcase/platforms/linux/appimage.py b/src/briefcase/platforms/linux/appimage.py index a87c305ca..55f47acbb 100644 --- a/src/briefcase/platforms/linux/appimage.py +++ b/src/briefcase/platforms/linux/appimage.py @@ -44,7 +44,7 @@ def project_path(self, app): def binary_name(self, app): safe_name = app.formal_name.replace(" ", "_") - arch = LinuxDeploy.arch(self.tools.host_os, self.tools.host_arch) + arch = LinuxDeploy.arch(self.tools.host_arch) return f"{safe_name}-{app.version}-{arch}.AppImage" def binary_path(self, app): @@ -163,7 +163,7 @@ def output_format_template_context(self, app: AppConfig): manylinux_arch = { "x86_64": "x86_64", "i386": "i686", - }[LinuxDeploy.arch(self.tools.host_os, self.tools.host_arch)] + }[LinuxDeploy.arch(self.tools.host_arch)] context["manylinux_image"] = f"{app.manylinux}_{manylinux_arch}:{tag}" if app.manylinux in {"manylinux1", "manylinux2010", "manylinux2014"}: context["vendor_base"] = "centos" diff --git a/tests/integrations/linuxdeploy/test_LinuxDeployQtPlugin__properties.py b/tests/integrations/linuxdeploy/test_LinuxDeployQtPlugin__properties.py index 9b5c0a9fd..4f523e70f 100644 --- a/tests/integrations/linuxdeploy/test_LinuxDeployQtPlugin__properties.py +++ b/tests/integrations/linuxdeploy/test_LinuxDeployQtPlugin__properties.py @@ -22,7 +22,6 @@ def test_file_path(mock_tools, linuxdeploy_qt_plugin): ("Linux", "x86_64", "x86_64"), ("Linux", "i686", "i386"), ("Darwin", "x86_64", "x86_64"), - ("Darwin", "arm64", "x86_64"), ], ) def test_file_name(mock_tools, host_os, host_arch, linuxdeploy_arch): @@ -48,7 +47,6 @@ def test_plugin_id(linuxdeploy_qt_plugin): ("Linux", "x86_64", "x86_64"), ("Linux", "i686", "i386"), ("Darwin", "x86_64", "x86_64"), - ("Darwin", "arm64", "x86_64"), ], ) def test_download_url(mock_tools, host_os, host_arch, linuxdeploy_arch): diff --git a/tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py b/tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py index d06b24f58..bfbe57bc7 100644 --- a/tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py +++ b/tests/integrations/linuxdeploy/test_LinuxDeploy__properties.py @@ -24,7 +24,6 @@ def test_file_path(linuxdeploy, mock_tools): ("Linux", "x86_64", "x86_64"), ("Linux", "i686", "i386"), ("Darwin", "x86_64", "x86_64"), - ("Darwin", "arm64", "x86_64"), ], ) def test_file_name(mock_tools, host_os, host_arch, linuxdeploy_arch): @@ -54,7 +53,6 @@ def test_file_name_unsupported_arch(mock_tools): ("Linux", "x86_64", "x86_64"), ("Linux", "i686", "i386"), ("Darwin", "x86_64", "x86_64"), - ("Darwin", "arm64", "x86_64"), ], ) def test_download_url(mock_tools, host_os, host_arch, linuxdeploy_arch): diff --git a/tests/platforms/linux/appimage/test_create.py b/tests/platforms/linux/appimage/test_create.py index 36f13eb75..d008b9e64 100644 --- a/tests/platforms/linux/appimage/test_create.py +++ b/tests/platforms/linux/appimage/test_create.py @@ -178,19 +178,6 @@ def test_finalize_nodocker(create_command, first_app_config, capsys): "use_non_root_user": False, }, ), - # macOS on Apple Silicon - ( - "manylinux2014", - None, - "Darwin", - "arm64", - True, - { - "manylinux_image": "manylinux2014_x86_64:latest", - "vendor_base": "centos", - "use_non_root_user": False, - }, - ), ], ) def test_output_format_template_context( From a7abd969e08a689ee62270456619ca628ce581f9 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Tue, 1 Aug 2023 10:38:07 -0400 Subject: [PATCH 06/11] Revert cmdline-tools upgrade to implement separately --- src/briefcase/integrations/android_sdk.py | 4 ++-- .../android_sdk/AndroidSDK/test_properties.py | 2 +- .../android_sdk/AndroidSDK/test_verify.py | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/briefcase/integrations/android_sdk.py b/src/briefcase/integrations/android_sdk.py index 51a323207..97b4f9056 100644 --- a/src/briefcase/integrations/android_sdk.py +++ b/src/briefcase/integrations/android_sdk.py @@ -95,11 +95,11 @@ def cmdline_tools_path(self) -> Path: @property def cmdline_tools_version(self) -> str: # This is the version of the Android SDK Command-line tools that - # are current as of July 2023. These tools can generally self-update, + # are current as of May 2022. These tools can generally self-update, # so using a fixed download URL isn't a problem. # However, if/when this version number is changed, ensure that the # checks done during verification include any required upgrade steps. - return "9477386" + return "8092744" @property def cmdline_tools_version_path(self) -> Path: diff --git a/tests/integrations/android_sdk/AndroidSDK/test_properties.py b/tests/integrations/android_sdk/AndroidSDK/test_properties.py index 088209a13..29f1ad787 100644 --- a/tests/integrations/android_sdk/AndroidSDK/test_properties.py +++ b/tests/integrations/android_sdk/AndroidSDK/test_properties.py @@ -21,7 +21,7 @@ def test_cmdline_tools_url(mock_tools, android_sdk, host_os, host_arch, name): mock_tools.host_arch = host_arch assert android_sdk.cmdline_tools_url == ( - f"https://dl.google.com/android/repository/commandlinetools-{name}-9477386_latest.zip" + f"https://dl.google.com/android/repository/commandlinetools-{name}-8092744_latest.zip" ) diff --git a/tests/integrations/android_sdk/AndroidSDK/test_verify.py b/tests/integrations/android_sdk/AndroidSDK/test_verify.py index a37fe579b..dc673dcb2 100644 --- a/tests/integrations/android_sdk/AndroidSDK/test_verify.py +++ b/tests/integrations/android_sdk/AndroidSDK/test_verify.py @@ -425,7 +425,7 @@ def test_download_sdk(mock_tools, tmp_path): # Validate that the SDK was downloaded and unpacked url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, @@ -495,7 +495,7 @@ def test_download_sdk_legacy_install(mock_tools, tmp_path): # Validate that the SDK was downloaded and unpacked url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, @@ -554,7 +554,7 @@ def test_download_sdk_if_sdkmanager_not_executable(mock_tools, tmp_path): # Create pre-existing non-executable `sdkmanager`. (cmdline_tools_base_path / "latest" / "bin").mkdir(parents=True) (cmdline_tools_base_path / "latest" / "bin" / "sdkmanager").touch(mode=0o644) - (cmdline_tools_base_path / "9477386").touch() + (cmdline_tools_base_path / "8092744").touch() # The download will produce a cached file cache_file = MagicMock() @@ -572,7 +572,7 @@ def test_download_sdk_if_sdkmanager_not_executable(mock_tools, tmp_path): # Validate that the SDK was downloaded and unpacked url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, @@ -605,7 +605,7 @@ def test_raises_networkfailure_on_connectionerror(mock_tools): # The download was attempted url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, @@ -632,7 +632,7 @@ def test_detects_bad_zipfile(mock_tools, tmp_path): # The download attempt was made. url = ( "https://dl.google.com/android/repository/" - f"commandlinetools-{mock_tools._test_download_tag}-9477386_latest.zip" + f"commandlinetools-{mock_tools._test_download_tag}-8092744_latest.zip" ) mock_tools.download.file.assert_called_once_with( url=url, From e147b56dace5b787ed07d82371ff3c4ed6196d82 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Tue, 1 Aug 2023 14:02:21 -0400 Subject: [PATCH 07/11] Revert JDK upgrade to implement separately --- src/briefcase/integrations/java.py | 8 +++--- tests/integrations/java/test_JDK__upgrade.py | 12 ++++----- tests/integrations/java/test_JDK__verify.py | 28 ++++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/briefcase/integrations/java.py b/src/briefcase/integrations/java.py index 5792058c7..d8eb6234b 100644 --- a/src/briefcase/integrations/java.py +++ b/src/briefcase/integrations/java.py @@ -20,7 +20,7 @@ class JDK(ManagedTool): # As of 12 May 2023, 17.0.7+7 is the current OpenJDK # https://adoptium.net/temurin/releases/ JDK_MAJOR_VER = "17" - JDK_RELEASE = "17.0.8" + JDK_RELEASE = "17.0.7" JDK_BUILD = "7" JDK_INSTALL_DIR_NAME = f"java{JDK_MAJOR_VER}" @@ -75,7 +75,7 @@ def version_from_path(cls, tools: ToolCache, java_path: str | Path) -> str: :param tools: ToolCache of available tools :param java_path: File path to a candidate JDK install - :return: JDK release version; e.g. "17.0.8" + :return: JDK release version; e.g. "17.0.7" """ output = tools.subprocess.check_output( [ @@ -83,7 +83,7 @@ def version_from_path(cls, tools: ToolCache, java_path: str | Path) -> str: "-version", ], ) - # javac's output should look like "javac 17.0.8\n" + # javac's output should look like "javac 17.0.7\n" return output.strip("\n").split(" ")[1] @classmethod @@ -303,7 +303,7 @@ def install(self): jdk_zip_path.unlink() # Zip file no longer needed once unpacked. - # The tarball will unpack into /tools/jdk-17.0.8+7 + # The tarball will unpack into /tools/jdk-17.0.7+7 # (or whatever name matches the current release). # We turn this into /tools/java so we have a consistent name. java_unpack_path = ( diff --git a/tests/integrations/java/test_JDK__upgrade.py b/tests/integrations/java/test_JDK__upgrade.py index af1e2e190..b9c86fbcd 100644 --- a/tests/integrations/java/test_JDK__upgrade.py +++ b/tests/integrations/java/test_JDK__upgrade.py @@ -65,7 +65,7 @@ def rmtree(path): mock_tools.download.file.return_value = archive # Create a directory to make it look like Java was downloaded and unpacked. - (tmp_path / "tools" / "jdk-17.0.8+7").mkdir(parents=True) + (tmp_path / "tools" / "jdk-17.0.7+7").mkdir(parents=True) # Create an SDK wrapper jdk = JDK(mock_tools, java_home=java_home) @@ -79,7 +79,7 @@ def rmtree(path): # A download was initiated mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) @@ -114,7 +114,7 @@ def rmtree(path): mock_tools.download.file.return_value = archive # Create a directory to make it look like Java was downloaded and unpacked. - (tmp_path / "tools" / "jdk-17.0.8+7").mkdir(parents=True) + (tmp_path / "tools" / "jdk-17.0.7+7").mkdir(parents=True) # Create an SDK wrapper jdk = JDK(mock_tools, java_home=java_home) @@ -128,7 +128,7 @@ def rmtree(path): # A download was initiated mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.7_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) @@ -170,7 +170,7 @@ def rmtree(path): # A download was initiated mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) @@ -212,7 +212,7 @@ def rmtree(path): # A download was initiated mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) diff --git a/tests/integrations/java/test_JDK__verify.py b/tests/integrations/java/test_JDK__verify.py index b5ce5e301..6c87851a0 100644 --- a/tests/integrations/java/test_JDK__verify.py +++ b/tests/integrations/java/test_JDK__verify.py @@ -58,7 +58,7 @@ def test_macos_tool_java_home(mock_tools, capsys): # Mock 2 calls to check_output. mock_tools.subprocess.check_output.side_effect = [ "/path/to/java", - "javac 17.0.8\n", + "javac 17.0.7\n", ] # Create a JDK wrapper by verification @@ -179,7 +179,7 @@ def test_macos_provided_overrides_tool_java_home(mock_tools, capsys): mock_tools.os.environ = {"JAVA_HOME": "/path/to/java"} # Mock return value from javac. libexec won't be invoked. - mock_tools.subprocess.check_output.return_value = "javac 17.0.8\n" + mock_tools.subprocess.check_output.return_value = "javac 17.0.7\n" # Create a JDK wrapper by verification JDK.verify(mock_tools) @@ -205,7 +205,7 @@ def test_valid_provided_java_home(mock_tools, capsys): mock_tools.os.environ = {"JAVA_HOME": "/path/to/java"} # Mock return value from javac. - mock_tools.subprocess.check_output.return_value = "javac 17.0.8\n" + mock_tools.subprocess.check_output.return_value = "javac 17.0.7\n" # Create a JDK wrapper by verification JDK.verify(mock_tools) @@ -404,7 +404,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Darwin", "x86_64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_mac_hotspot_17.0.7_7.tar.gz", "java17/Contents/Home", False, ), @@ -412,7 +412,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Darwin", "arm64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.7_7.tar.gz", "java17/Contents/Home", False, ), @@ -420,7 +420,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "x86_64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", "java17", False, ), @@ -428,7 +428,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "aarch64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.7_7.tar.gz", "java17", False, ), @@ -436,7 +436,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "aarch64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", "java17", True, ), @@ -444,7 +444,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "armv7l", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", "java17", False, ), @@ -452,7 +452,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Linux", "armv8l", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_arm_linux_hotspot_17.0.7_7.tar.gz", "java17", False, ), @@ -460,7 +460,7 @@ def test_unparseable_javac_version(mock_tools, host_os, java_home, tmp_path, cap "Windows", "AMD64", "https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_windows_hotspot_17.0.8_7.zip", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_windows_hotspot_17.0.7_7.zip", "java17", False, ), @@ -492,7 +492,7 @@ def test_successful_jdk_download( mock_tools.download.file.return_value = archive # Create a directory to make it look like Java was downloaded and unpacked. - (tmp_path / "tools" / "jdk-17.0.8+7").mkdir(parents=True) + (tmp_path / "tools" / "jdk-17.0.7+7").mkdir(parents=True) # Invoke the verify call JDK.verify(mock_tools) @@ -547,7 +547,7 @@ def test_jdk_download_failure(mock_tools, tmp_path): # That download was attempted mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) @@ -575,7 +575,7 @@ def test_invalid_jdk_archive(mock_tools, tmp_path): # The download occurred mock_tools.download.file.assert_called_with( url="https://github.com/adoptium/temurin17-binaries/releases/download/" - "jdk-17.0.8+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.8_7.tar.gz", + "jdk-17.0.7+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.7_7.tar.gz", download_path=tmp_path / "tools", role="Java 17 JDK", ) From 77cf5df285e47b9454413fb0f60b5c4ddda32380 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Tue, 22 Aug 2023 12:34:51 -0400 Subject: [PATCH 08/11] Host platform support documentation --- docs/conf.py | 10 +++++ docs/reference/platforms/android.rst | 11 +++++ docs/reference/platforms/iOS.rst | 10 +++++ docs/reference/platforms/index.rst | 43 ++++++++++++++++++- docs/reference/platforms/linux/appimage.rst | 10 +++++ docs/reference/platforms/linux/flatpak.rst | 10 +++++ docs/reference/platforms/linux/system.rst | 10 +++++ docs/reference/platforms/macOS/app.rst | 10 +++++ docs/reference/platforms/macOS/xcode.rst | 10 +++++ docs/reference/platforms/web.rst | 10 +++++ docs/reference/platforms/windows/app.rst | 10 +++++ .../platforms/windows/visualstudio.rst | 10 +++++ 12 files changed, 153 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 8272744c7..8fcf5310e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -97,6 +97,16 @@ intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} +# API status indicators. +rst_prolog = """ +.. role:: full +.. role:: yes +.. role:: ymmv +.. |f| replace:: :full:`●` +.. |y| replace:: :yes:`○` +.. |v| replace:: :ymmv:`▲` +""" + # -- Options for link checking ------------------------------------------------- linkcheck_anchors_ignore = [ diff --git a/docs/reference/platforms/android.rst b/docs/reference/platforms/android.rst index d08ed8c80..e4c60b8f7 100644 --- a/docs/reference/platforms/android.rst +++ b/docs/reference/platforms/android.rst @@ -2,6 +2,17 @@ Android ======= ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| |f| | |y| | | |f| | | |v| | |f| | |v| | |v| | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + + When generating an Android project, Briefcase produces a Gradle project. Gradle requires an install of the Android SDK and a Java 17 JDK. diff --git a/docs/reference/platforms/iOS.rst b/docs/reference/platforms/iOS.rst index 009c060b5..461c5e6dd 100644 --- a/docs/reference/platforms/iOS.rst +++ b/docs/reference/platforms/iOS.rst @@ -2,6 +2,16 @@ iOS === ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| |f| | |y| | | | | | | | | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + When generating an iOS project, Briefcase produces an Xcode project. Icon format diff --git a/docs/reference/platforms/index.rst b/docs/reference/platforms/index.rst index 929d02e49..a5403475f 100644 --- a/docs/reference/platforms/index.rst +++ b/docs/reference/platforms/index.rst @@ -3,7 +3,7 @@ Platform support ================ .. toctree:: - :maxdepth: 2 + :hidden: macOS/index windows/index @@ -11,3 +11,44 @@ Platform support iOS android web + ++------------------------+------------------+--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Target App Format | Host System | ++ +--------+-------+---------+--------+---+-----+--------+-----+-------+ +| | macOS | Windows | Linux | ++ +--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========================+==================+========+=======+=====+========+=======+=====+========+=====+=======+ +| :doc:`./android` | Gradle | |f| | |y| | | |f| | | |v| | |f| | |v| | |v| | ++------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| :doc:`./iOS` | Xcode | |f| | |y| | | | | | | | | ++------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| :doc:`./linux/index` | AppImage | |f| | | | | | |v| | |f| | | | ++ +------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | Flatpak | | | | | | |v| | |f| | |v| | |v| | ++ +------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | System | |y| | |y| | | | | |v| | |f| | |v| | |v| | ++------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| :doc:`./macOS/index` | .app | |f| | |y| | | | | | | | | ++ +------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | Xcode | |f| | |y| | | | | | | | | ++------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| :doc:`./windows/index` | App | | | | |f| | | | | | | ++ +------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | Visual Studio | | | | |f| | | | | | | ++------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| :doc:`./web` | Static | |f| | |y| | |v| | |f| | |v| | |v| | |f| | |v| | |v| | ++------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ + +.. _platform-support-key: + +Key +--- + ++-----+-------------------------------------+ +| |f| | Supported and tested in CI | ++-----+-------------------------------------+ +| |y| | Supported and tested by maintainers | ++-----+-------------------------------------+ +| |v| | Supported but not regularly tested | ++-----+-------------------------------------+ diff --git a/docs/reference/platforms/linux/appimage.rst b/docs/reference/platforms/linux/appimage.rst index 0c949af2c..52a72a7f0 100644 --- a/docs/reference/platforms/linux/appimage.rst +++ b/docs/reference/platforms/linux/appimage.rst @@ -2,6 +2,16 @@ AppImage ======== ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| |f| | | | | | |v| | |f| | | | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + `AppImage `__ provides a way for developers to provide "native" binaries for Linux users. It allow packaging applications for any common Linux based operating system, including Ubuntu, Debian, Fedora, and more. diff --git a/docs/reference/platforms/linux/flatpak.rst b/docs/reference/platforms/linux/flatpak.rst index ee025f1fb..2eaed8486 100644 --- a/docs/reference/platforms/linux/flatpak.rst +++ b/docs/reference/platforms/linux/flatpak.rst @@ -2,6 +2,16 @@ Flatpak ======= ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| | | | | | |v| | |f| | |v| | |v| | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + `Flatpak `__ provides a way for developers to distribute apps to Linux users in a format that is independent of the specific distribution used by the end-user. It allow packaging applications for use on any common diff --git a/docs/reference/platforms/linux/system.rst b/docs/reference/platforms/linux/system.rst index 28def6910..8cf1e1b52 100644 --- a/docs/reference/platforms/linux/system.rst +++ b/docs/reference/platforms/linux/system.rst @@ -2,6 +2,16 @@ Native System Packages ====================== ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| |y| | |y| | | | | |v| | |f| | |v| | |v| | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + All modern Linux distributions have a native format for distributing packages that are integrated into their overall operating system: diff --git a/docs/reference/platforms/macOS/app.rst b/docs/reference/platforms/macOS/app.rst index e547187ab..c3ed247a9 100644 --- a/docs/reference/platforms/macOS/app.rst +++ b/docs/reference/platforms/macOS/app.rst @@ -2,6 +2,16 @@ .app bundle =========== ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| |f| | |y| | | | | | | | | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + A macOS ``.app`` bundle is a collection of directory with a specific layout, and with some key metadata. If this structure and metadata exists, macOS treats the folder as an executable file, giving it an icon. diff --git a/docs/reference/platforms/macOS/xcode.rst b/docs/reference/platforms/macOS/xcode.rst index 2820184e9..9cc869c90 100644 --- a/docs/reference/platforms/macOS/xcode.rst +++ b/docs/reference/platforms/macOS/xcode.rst @@ -2,6 +2,16 @@ Xcode project ============= ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| |f| | |y| | | | | | | | | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + Briefcase supports creating a full Xcode project for a macOS app. This project can then be used to build an actual app bundle, with the ``briefcase build`` command or directly from Xcode. diff --git a/docs/reference/platforms/web.rst b/docs/reference/platforms/web.rst index 48f58c616..66ef0d816 100644 --- a/docs/reference/platforms/web.rst +++ b/docs/reference/platforms/web.rst @@ -2,6 +2,16 @@ Web === ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| |f| | |y| | |v| | |f| | |v| | |v| | |f| | |v| | |v| | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + When generating a web project, Briefcase produces a static folder of HTML, CSS and JavaScript resources that can be deployed as a web site. The static web site is packaged as a ``.zip`` file for distribution. diff --git a/docs/reference/platforms/windows/app.rst b/docs/reference/platforms/windows/app.rst index c9696e2ad..4324a5325 100644 --- a/docs/reference/platforms/windows/app.rst +++ b/docs/reference/platforms/windows/app.rst @@ -2,6 +2,16 @@ Windows App =========== ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| | | | |f| | | | | | | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + A Windows app is a stub binary, allow with a collection of folders that contain the Python code for the app and the Python runtime libraries. diff --git a/docs/reference/platforms/windows/visualstudio.rst b/docs/reference/platforms/windows/visualstudio.rst index ae1d46092..5dbe8f0a2 100644 --- a/docs/reference/platforms/windows/visualstudio.rst +++ b/docs/reference/platforms/windows/visualstudio.rst @@ -2,6 +2,16 @@ Visual Studio project ===================== ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Host Platform Support (:ref:`platform-support-key`) | ++--------+-------+---------+--------+---+-----+--------+-----+-------+ +| macOS | Windows | Linux | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | ++========+=======+=====+========+=======+=====+========+=====+=======+ +| | | | |f| | | | | | | ++--------+-------+-----+--------+-------+-----+--------+-----+-------+ + Briefcase supports creating a full Visual Studio project for a Windows App. This project can then be used to build the stub app binary with the ``briefcase build`` command, or directly from Visual Studio. From 5f184d3f6a122652d249ee153c964d43bb0c402b Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Tue, 29 Aug 2023 17:34:16 -0400 Subject: [PATCH 09/11] Bump `tox` to `4.11.0` to mitigate docs build error --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 8755eec7f..066fa7cc7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -94,7 +94,7 @@ dev = pytest == 7.4.0 pytest-xdist == 3.3.1 setuptools_scm[toml] == 7.1.0 - tox == 4.9.0 + tox == 4.11.0 docs = furo == 2023.8.19 pyenchant == 3.2.2 From f636e6e55de389edf7cbed36d231f5a68e4e11fe Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 30 Aug 2023 09:32:27 +0800 Subject: [PATCH 10/11] Tweaks to markup of support tables. --- docs/conf.py | 2 +- docs/reference/platforms/android.rst | 2 +- docs/reference/platforms/iOS.rst | 2 +- docs/reference/platforms/index.rst | 77 ++++++++++++------- docs/reference/platforms/linux/appimage.rst | 2 +- docs/reference/platforms/linux/flatpak.rst | 2 +- docs/reference/platforms/linux/system.rst | 29 +++---- docs/reference/platforms/macOS/app.rst | 2 +- docs/reference/platforms/macOS/xcode.rst | 8 +- docs/reference/platforms/web.rst | 2 +- docs/reference/platforms/windows/app.rst | 2 +- .../platforms/windows/visualstudio.rst | 2 +- 12 files changed, 72 insertions(+), 60 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 8fcf5310e..0ef307aff 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -104,7 +104,7 @@ .. role:: ymmv .. |f| replace:: :full:`●` .. |y| replace:: :yes:`○` -.. |v| replace:: :ymmv:`▲` +.. |v| replace:: :ymmv:`△` """ # -- Options for link checking ------------------------------------------------- diff --git a/docs/reference/platforms/android.rst b/docs/reference/platforms/android.rst index e4c60b8f7..cea9a020d 100644 --- a/docs/reference/platforms/android.rst +++ b/docs/reference/platforms/android.rst @@ -7,7 +7,7 @@ Android +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | |f| | |y| | | |f| | | |v| | |f| | |v| | |v| | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/iOS.rst b/docs/reference/platforms/iOS.rst index 461c5e6dd..2008d7ae8 100644 --- a/docs/reference/platforms/iOS.rst +++ b/docs/reference/platforms/iOS.rst @@ -7,7 +7,7 @@ iOS +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | |f| | |y| | | | | | | | | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/index.rst b/docs/reference/platforms/index.rst index a5403475f..d62508fdf 100644 --- a/docs/reference/platforms/index.rst +++ b/docs/reference/platforms/index.rst @@ -12,34 +12,6 @@ Platform support android web -+------------------------+------------------+--------+-------+---------+--------+---+-----+--------+-----+-------+ -| Target App Format | Host System | -+ +--------+-------+---------+--------+---+-----+--------+-----+-------+ -| | macOS | Windows | Linux | -+ +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| | x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | -+========================+==================+========+=======+=====+========+=======+=====+========+=====+=======+ -| :doc:`./android` | Gradle | |f| | |y| | | |f| | | |v| | |f| | |v| | |v| | -+------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| :doc:`./iOS` | Xcode | |f| | |y| | | | | | | | | -+------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| :doc:`./linux/index` | AppImage | |f| | | | | | |v| | |f| | | | -+ +------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| | Flatpak | | | | | | |v| | |f| | |v| | |v| | -+ +------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| | System | |y| | |y| | | | | |v| | |f| | |v| | |v| | -+------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| :doc:`./macOS/index` | .app | |f| | |y| | | | | | | | | -+ +------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| | Xcode | |f| | |y| | | | | | | | | -+------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| :doc:`./windows/index` | App | | | | |f| | | | | | | -+ +------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| | Visual Studio | | | | |f| | | | | | | -+------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| :doc:`./web` | Static | |f| | |y| | |v| | |f| | |v| | |v| | |f| | |v| | |v| | -+------------------------+------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ - .. _platform-support-key: Key @@ -50,5 +22,52 @@ Key +-----+-------------------------------------+ | |y| | Supported and tested by maintainers | +-----+-------------------------------------+ -| |v| | Supported but not regularly tested | +| |v| | Supported but not tested regularly | +-----+-------------------------------------+ + + +.. |Gradle| replace:: **Gradle** +.. _Gradle: ./android.html + +.. |iOS| replace:: **Xcode** +.. _iOS: ./iOS.html + +.. |System| replace:: **Native System Packages** +.. _System: ./linux/system.html + +.. |macOSApp| replace:: **.app bundle** +.. _macOSApp: ./macOS/app.html + +.. |windowsApp| replace:: **Windows app** +.. _windowsApp: ./windows/app.html + +.. |Web| replace:: **Static** +.. _Web: ./web.html + ++---------+--------------------------------------+--------+-------+---------+--------+---+-----+--------+-----+-------+ +| Target App Format | Host System | ++ +--------+-------+---------+--------+---+-----+--------+-----+-------+ +| | macOS | Windows | Linux | ++ +--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | ++=========+======================================+========+=======+=====+========+=======+=====+========+=====+=======+ +| Android | |Gradle|_ | |f| | |y| | | |f| | | |v| | |f| | |v| | |v| | ++---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| iOS | |iOS|_ | |f| | |y| | | | | | | | | ++---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| Linux | :doc:`./linux/appimage` | |f| | | | | | |v| | |f| | | | ++ +--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | :doc:`./linux/flatpak` | | | | | | |v| | |f| | |v| | |v| | ++ +--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | |System|_ | |y| | |y| | | | | |v| | |f| | |v| | |v| | ++---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| macOS | |macOSApp|_ | |f| | |y| | | | | | | | | ++ +--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | :doc:`Xcode project <./macOS/xcode>` | |f| | |y| | | | | | | | | ++---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| Windows | |windowsApp|_ | | | | |f| | | | | | | ++ +--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| | :doc:`./windows/visualstudio` | | | | |f| | | | | | | ++---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| Web | |web|_ | |f| | |y| | |v| | |f| | |v| | |v| | |f| | |v| | |v| | ++---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/linux/appimage.rst b/docs/reference/platforms/linux/appimage.rst index 52a72a7f0..0bf5d5e40 100644 --- a/docs/reference/platforms/linux/appimage.rst +++ b/docs/reference/platforms/linux/appimage.rst @@ -7,7 +7,7 @@ AppImage +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | |f| | | | | | |v| | |f| | | | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/linux/flatpak.rst b/docs/reference/platforms/linux/flatpak.rst index 2eaed8486..e4058cf17 100644 --- a/docs/reference/platforms/linux/flatpak.rst +++ b/docs/reference/platforms/linux/flatpak.rst @@ -7,7 +7,7 @@ Flatpak +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | | | | | | |v| | |f| | |v| | |v| | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/linux/system.rst b/docs/reference/platforms/linux/system.rst index 8cf1e1b52..b372524b6 100644 --- a/docs/reference/platforms/linux/system.rst +++ b/docs/reference/platforms/linux/system.rst @@ -7,7 +7,7 @@ Native System Packages +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | |y| | |y| | | | | |v| | |f| | |v| | |v| | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ @@ -22,17 +22,10 @@ that are integrated into their overall operating system: The Briefcase ``system`` backend provides a way to build your app in these system package formats. -.. note:: Not all Linux distributions are currently supported! +.. admonition:: Not all Linux distributions are supported! - At present, Briefcase only has full support for Debian-based distributions. - It should be possible to build and run an application on other Linux - distributions; however, it won't be possible to package the app for - distribution on those platforms. We intend to add support for other - packaging formats - patches are welcome. - - In addition, Briefcase cannot reliably identify *every* Linux vendor. If - your Linux distribution isn't being identified (or isn't being identified - correctly), please `open a ticket + Briefcase cannot reliably identify *every* Linux vendor. If your Linux distribution + isn't being identified (or isn't being identified correctly), please `open a ticket `__ with the contents of your ``/etc/os-release`` file. @@ -118,13 +111,13 @@ supported by the vendor, and system Python is Python 3.8 or later. The following Linux vendors are known to work as Docker targets: - * Debian (e.g., ``debian:bullseye`` or ``debian:11``) - * Ubuntu (e.g., ``ubuntu:jammy`` or ``ubuntu:22.04``) - * Fedora (e.g, ``fedora:37``) - * AlmaLinux (e.g., ``almalinux:9``) - * Red Hat Enterprise Linux (e.g., ``redhat/ubi9:9``) - * Arch Linux (e.g., ``archlinux:latest``) - * Manjaro Linux (e.g., ``manjarolinux/base:latest``) +* Debian (e.g., ``debian:bullseye`` or ``debian:11``) +* Ubuntu (e.g., ``ubuntu:jammy`` or ``ubuntu:22.04``) +* Fedora (e.g, ``fedora:37``) +* AlmaLinux (e.g., ``almalinux:9``) +* Red Hat Enterprise Linux (e.g., ``redhat/ubi9:9``) +* Arch Linux (e.g., ``archlinux:latest``) +* Manjaro Linux (e.g., ``manjarolinux/base:latest``) Application configuration ========================= diff --git a/docs/reference/platforms/macOS/app.rst b/docs/reference/platforms/macOS/app.rst index c3ed247a9..6d866ece7 100644 --- a/docs/reference/platforms/macOS/app.rst +++ b/docs/reference/platforms/macOS/app.rst @@ -7,7 +7,7 @@ +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | |f| | |y| | | | | | | | | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/macOS/xcode.rst b/docs/reference/platforms/macOS/xcode.rst index 9cc869c90..77c4e27b5 100644 --- a/docs/reference/platforms/macOS/xcode.rst +++ b/docs/reference/platforms/macOS/xcode.rst @@ -1,13 +1,13 @@ -============= -Xcode project -============= +=================== +macOS Xcode project +=================== +--------+-------+---------+--------+---+-----+--------+-----+-------+ | Host Platform Support (:ref:`platform-support-key`) | +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | |f| | |y| | | | | | | | | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/web.rst b/docs/reference/platforms/web.rst index 66ef0d816..653304186 100644 --- a/docs/reference/platforms/web.rst +++ b/docs/reference/platforms/web.rst @@ -7,7 +7,7 @@ Web +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | |f| | |y| | |v| | |f| | |v| | |v| | |f| | |v| | |v| | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/windows/app.rst b/docs/reference/platforms/windows/app.rst index 4324a5325..d1aee4d86 100644 --- a/docs/reference/platforms/windows/app.rst +++ b/docs/reference/platforms/windows/app.rst @@ -7,7 +7,7 @@ Windows App +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | | | | |f| | | | | | | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ diff --git a/docs/reference/platforms/windows/visualstudio.rst b/docs/reference/platforms/windows/visualstudio.rst index 5dbe8f0a2..912d51c82 100644 --- a/docs/reference/platforms/windows/visualstudio.rst +++ b/docs/reference/platforms/windows/visualstudio.rst @@ -7,7 +7,7 @@ Visual Studio project +--------+-------+---------+--------+---+-----+--------+-----+-------+ | macOS | Windows | Linux | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| x86-64 | arm64 | x86 | x86-64 | arm64 | x86 | x86-64 | arm | arm64 | +| x86‑64 | arm64 | x86 | x86‑64 | arm64 | x86 | x86‑64 | arm | arm64 | +========+=======+=====+========+=======+=====+========+=====+=======+ | | | | |f| | | | | | | +--------+-------+-----+--------+-------+-----+--------+-----+-------+ From 5aedb7cf03c4f2a165abdc0aa555679ba0765946 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 30 Aug 2023 09:54:27 +0800 Subject: [PATCH 11/11] Make link checker happy. --- docs/conf.py | 11 +++++++++++ docs/reference/platforms/index.rst | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 0ef307aff..9b7d029c5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -320,6 +320,17 @@ # Location of word list. spelling_word_list_filename = "spelling_wordlist" +# -- Options for link check ------------------------------------------- + +linkcheck_ignore = [ + r"./android.html", + r"./iOS.html", + r"./linux/system.html", + r"./macOS/app.html", + r"./web.html", + r"./windows/app.html", +] + # -- Options for Todos ------------------------------------------- # If this is True, todo and todolist produce output, else they produce nothing. The default is False. diff --git a/docs/reference/platforms/index.rst b/docs/reference/platforms/index.rst index d62508fdf..b1a2c4723 100644 --- a/docs/reference/platforms/index.rst +++ b/docs/reference/platforms/index.rst @@ -65,9 +65,9 @@ Key + +--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ | | :doc:`Xcode project <./macOS/xcode>` | |f| | |y| | | | | | | | | +---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ +| Web | |web|_ | |f| | |y| | |v| | |f| | |v| | |v| | |f| | |v| | |v| | ++---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ | Windows | |windowsApp|_ | | | | |f| | | | | | | + +--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ | | :doc:`./windows/visualstudio` | | | | |f| | | | | | | +---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+ -| Web | |web|_ | |f| | |y| | |v| | |f| | |v| | |v| | |f| | |v| | |v| | -+---------+--------------------------------------+--------+-------+-----+--------+-------+-----+--------+-----+-------+