aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShyamnath Premnadh <[email protected]>2024-12-06 09:48:34 +0100
committerShyamnath Premnadh <[email protected]>2025-01-02 16:44:42 +0100
commitab8b330123cb557f66306b237f4c3aa8c0004f39 (patch)
tree9acae54ed4529e3c7b206c12befc071d178472a8
parenta067880f70c09f84bfeb24b4944c9e013c0fb93f (diff)
Android Deployment: Auto download Android NDK
- In order to prevent code duplication, a symlink to tools/cross_compile_android/android_utilities.py is created under sources/pyside-tools/deploy_lib/android. When running the script sources/pyside-tools/android_deploy.py, this works without any issues. When packaging the tools, the symlink is resolved into the actual file and the actual file is packaged into the wheels. - Remove global variable to __init__.py and remove the ones that are not used - Add tqdm to requirements.txt - Adapt tests - Additionally, include several new test cases to cover error scenarios more comprehensively Pick-to: 6.8 Task-number: PYSIDE-1612 Change-Id: I74728be30a2b8214b9a379b0b906fdacbb105833 Reviewed-by: Cristian Maureira-Fredes <[email protected]> Reviewed-by: Friedemann Kleint <[email protected]>
-rw-r--r--sources/pyside-tools/CMakeLists.txt15
-rw-r--r--sources/pyside-tools/deploy_lib/android/__init__.py3
-rw-r--r--sources/pyside-tools/deploy_lib/android/android_config.py23
l---------sources/pyside-tools/deploy_lib/android/android_utilities.py1
-rw-r--r--sources/pyside-tools/requirements-android.txt1
-rw-r--r--sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py50
6 files changed, 77 insertions, 16 deletions
diff --git a/sources/pyside-tools/CMakeLists.txt b/sources/pyside-tools/CMakeLists.txt
index 7808eeee1..124ecc780 100644
--- a/sources/pyside-tools/CMakeLists.txt
+++ b/sources/pyside-tools/CMakeLists.txt
@@ -66,6 +66,7 @@ else()
# pyside6-rcc, pyside6-uic, pyside6-designer, shiboken and pyside6-lupdate entrypoints
foreach(file ${files})
if(EXISTS ${file})
+ message(STATUS "Installing tool: ${file}")
install(FILES "${file}"
DESTINATION bin
PERMISSIONS
@@ -83,6 +84,18 @@ else()
FILE_PERMISSIONS
OWNER_EXECUTE OWNER_WRITE OWNER_READ
GROUP_EXECUTE GROUP_READ
- WORLD_EXECUTE WORLD_READ)
+ WORLD_EXECUTE WORLD_READ
+ PATTERN "android_utilities.py" EXCLUDE) # excluding the symlink
endforeach()
+
+ # dealing with android_utilities.py
+ set(ANDROID_UTILITIES_REALPATH
+ "${CMAKE_CURRENT_SOURCE_DIR}/../../tools/cross_compile_android/android_utilities.py")
+ message(STATUS "Installing ${ANDROID_UTILITIES_REALPATH}")
+ install(FILES "${ANDROID_UTILITIES_REALPATH}"
+ DESTINATION bin/deploy_lib/android
+ PERMISSIONS
+ OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ GROUP_EXECUTE GROUP_READ
+ WORLD_EXECUTE WORLD_READ)
endif()
diff --git a/sources/pyside-tools/deploy_lib/android/__init__.py b/sources/pyside-tools/deploy_lib/android/__init__.py
index 80ba6dee3..27d4d7b60 100644
--- a/sources/pyside-tools/deploy_lib/android/__init__.py
+++ b/sources/pyside-tools/deploy_lib/android/__init__.py
@@ -1,6 +1,7 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
from __future__ import annotations
+from pathlib import Path
# maps instruction set to Android platform names
platform_map = {"aarch64": "arm64-v8a",
@@ -11,6 +12,8 @@ platform_map = {"aarch64": "arm64-v8a",
"armeabi-v7a": "armeabi-v7a",
"x86": "x86"}
+ANDROID_DEPLOY_CACHE = Path.home() / ".pyside6_android_deploy"
+
from .android_helper import (create_recipe, extract_and_copy_jar, get_wheel_android_arch,
AndroidData, get_llvm_readobj, find_lib_dependencies,
find_qtlibs_in_wheel)
diff --git a/sources/pyside-tools/deploy_lib/android/android_config.py b/sources/pyside-tools/deploy_lib/android/android_config.py
index 503fa6085..6b9386b8a 100644
--- a/sources/pyside-tools/deploy_lib/android/android_config.py
+++ b/sources/pyside-tools/deploy_lib/android/android_config.py
@@ -12,12 +12,11 @@ from pathlib import Path
from pkginfo import Wheel
from . import (extract_and_copy_jar, get_wheel_android_arch, find_lib_dependencies,
- get_llvm_readobj, find_qtlibs_in_wheel, platform_map, create_recipe)
+ get_llvm_readobj, find_qtlibs_in_wheel, platform_map, create_recipe,
+ ANDROID_DEPLOY_CACHE)
from .. import (Config, get_all_pyside_modules, MAJOR_VERSION)
-
-ANDROID_NDK_VERSION = "26b"
-ANDROID_NDK_VERSION_NUMBER_SUFFIX = "10909125"
-ANDROID_DEPLOY_CACHE = Path.home() / ".pyside6_android_deploy"
+from .android_utilities import (ANDROID_NDK_VERSION, ANDROID_NDK_VERSION_NUMBER_SUFFIX,
+ download_android_ndk)
class AndroidConfig(Config):
@@ -52,7 +51,7 @@ class AndroidConfig(Config):
if android_data.ndk_path:
# from cli
self.ndk_path = android_data.ndk_path
- else:
+ elif not existing_config_file:
# from config
ndk_path_temp = self.get_value("buildozer", "ndk_path")
if ndk_path_temp:
@@ -67,12 +66,14 @@ class AndroidConfig(Config):
)
if ndk_path_temp.exists():
self.ndk_path = ndk_path_temp
+ else:
+ # download NDK
+ if not ANDROID_DEPLOY_CACHE.exists():
+ ANDROID_DEPLOY_CACHE.mkdir()
+ logging.info(f"Cache created at {str(ANDROID_DEPLOY_CACHE.resolve())}")
- if self.ndk_path:
- print(f"Using Android NDK: {str(self.ndk_path)}")
- else:
- raise FileNotFoundError("[DEPLOY] Unable to find Android NDK. Please pass the NDK "
- "path either from the CLI or from pysidedeploy.spec")
+ logging.info("[DEPLOY] Downloading Android NDK")
+ self.ndk_path = download_android_ndk(ANDROID_DEPLOY_CACHE)
self.sdk_path = None
if android_data.sdk_path:
diff --git a/sources/pyside-tools/deploy_lib/android/android_utilities.py b/sources/pyside-tools/deploy_lib/android/android_utilities.py
new file mode 120000
index 000000000..d8a91b3e7
--- /dev/null
+++ b/sources/pyside-tools/deploy_lib/android/android_utilities.py
@@ -0,0 +1 @@
+../../../../tools/cross_compile_android/android_utilities.py \ No newline at end of file
diff --git a/sources/pyside-tools/requirements-android.txt b/sources/pyside-tools/requirements-android.txt
index 1169fd663..9ed5d8427 100644
--- a/sources/pyside-tools/requirements-android.txt
+++ b/sources/pyside-tools/requirements-android.txt
@@ -1,2 +1,3 @@
jinja2
pkginfo
+tqdm
diff --git a/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py b/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
index a0187deee..120c54af3 100644
--- a/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
+++ b/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
@@ -169,11 +169,26 @@ class TestPySide6AndroidDeployWidgets(DeployTestBase):
self.buildozer_config.unlink()
def test_errors(self, mock_extract_jar):
- # test if error raises for non existing NDK
- with self.assertRaises(FileNotFoundError) as context:
+ # test when no shiboken wheel is passed
+ with self.assertRaises(RuntimeError) as context:
+ self.android_deploy.main(name="android_app", pyside_wheel=self.pyside_wheel,
+ ndk_path=self.ndk_path, force=True)
+ self.assertTrue("Unable to find shiboken6 Android wheel" in str(context.exception))
+
+ # test when no PySide wheel is passed
+ with self.assertRaises(RuntimeError) as context:
self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
- pyside_wheel=self.pyside_wheel, force=True)
- self.assertTrue("Unable to find Android NDK" in str(context.exception))
+ ndk_path=self.ndk_path, force=True)
+ self.assertTrue("Unable to find PySide6 Android wheel" in str(context.exception))
+
+ # test if wheel name is correct
+ pyside_wheel_temp = Path("/tmp/"
+ "PySide6-6.8.0.1+commercial-6.8.0.1-cp311-cp311-android_fake.whl")
+ with self.assertRaises(RuntimeError) as context:
+ self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
+ pyside_wheel=pyside_wheel_temp, ndk_path=self.ndk_path,
+ force=True)
+ self.assertTrue("PySide wheel corrupted" in str(context.exception))
# test when cwd() is not project_dir
os.chdir(self.current_dir)
@@ -182,6 +197,33 @@ class TestPySide6AndroidDeployWidgets(DeployTestBase):
pyside_wheel=self.pyside_wheel, init=True, force=True)
self.assertTrue("For Android deployment to work" in str(context.exception))
+ @patch("deploy_lib.android.buildozer.BuildozerConfig._BuildozerConfig__find_jars")
+ @patch("deploy_lib.android.android_config.AndroidConfig.recipes_exist")
+ @patch("deploy_lib.android.android_config.AndroidConfig._find_dependent_qt_modules")
+ @patch("deploy_lib.android.android_config.find_qtlibs_in_wheel")
+ @patch("deploy_lib.android.android_config.download_android_ndk")
+ def test_no_ndk_passed(self, mock_ndk, mock_qtlibs, mock_extraqtmodules, mock_recipes_exist,
+ mock_find_jars, mock_extract_jar):
+ jar_dir = "tmp/jar/PySide6/jar"
+ mock_extract_jar.return_value = Path(jar_dir)
+ mock_qtlibs.return_value = self.pyside_wheel / "PySide6/Qt/lib"
+ mock_extraqtmodules.return_value = []
+ mock_recipes_exist.return_value = True
+ jars, init_classes = ["/tmp/jar/PySide6/jar/Qt6Android.jar",
+ "/tmp/jar/PySide6/jar/Qt6AndroidBindings.jar"], []
+ mock_find_jars.return_value = jars, init_classes
+ mock_ndk.return_value = Path("/tmp/android_ndk")
+
+ self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
+ pyside_wheel=self.pyside_wheel,
+ init=True, force=True,
+ keep_deployment_files=True)
+
+ # test config file contents
+ config_obj = self.deploy_lib.BaseConfig(config_file=self.config_file)
+ self.assertEqual(config_obj.get_value("buildozer", "sdk_path"), '')
+ self.assertEqual(config_obj.get_value("buildozer", "ndk_path"), "/tmp/android_ndk")
+
@patch("deploy_lib.config.run_qmlimportscanner")
@patch("deploy_lib.android.android_config.extract_and_copy_jar")