kivyforge 3.0.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kivyforge/__init__.py +9 -0
- kivyforge/artifacts/__init__.py +41 -0
- kivyforge/artifacts/cache.py +81 -0
- kivyforge/artifacts/collect.py +354 -0
- kivyforge/artifacts/download.py +125 -0
- kivyforge/artifacts/frameworks.py +240 -0
- kivyforge/artifacts/native_stage_util.py +346 -0
- kivyforge/artifacts/runtime.py +65 -0
- kivyforge/artifacts/verify.py +45 -0
- kivyforge/artifacts/wheels.py +89 -0
- kivyforge/bundle/__init__.py +1 -0
- kivyforge/bundle/pycompile.py +161 -0
- kivyforge/cli/__init__.py +52 -0
- kivyforge/cli/_common.py +62 -0
- kivyforge/cli/_platform.py +84 -0
- kivyforge/cli/build.py +111 -0
- kivyforge/cli/clean.py +135 -0
- kivyforge/cli/doctor.py +52 -0
- kivyforge/cli/init.py +612 -0
- kivyforge/cli/init_writer.py +716 -0
- kivyforge/cli/lock.py +261 -0
- kivyforge/cli/open_cmd.py +15 -0
- kivyforge/cli/package.py +134 -0
- kivyforge/cli/run.py +162 -0
- kivyforge/cli/status.py +20 -0
- kivyforge/cli/upgrade.py +314 -0
- kivyforge/config/__init__.py +46 -0
- kivyforge/config/errors.py +43 -0
- kivyforge/config/icons.py +60 -0
- kivyforge/config/loader.py +3079 -0
- kivyforge/config/model.py +817 -0
- kivyforge/doctor/__init__.py +19 -0
- kivyforge/doctor/checks_common.py +95 -0
- kivyforge/doctor/probe.py +357 -0
- kivyforge/doctor/result.py +41 -0
- kivyforge/lock/__init__.py +42 -0
- kivyforge/lock/_pip_shim.py +63 -0
- kivyforge/lock/find_links.py +182 -0
- kivyforge/lock/model.py +69 -0
- kivyforge/lock/pep751.py +111 -0
- kivyforge/lock/reader.py +30 -0
- kivyforge/lock/resolver.py +124 -0
- kivyforge/lock/wheelruntime/__init__.py +70 -0
- kivyforge/lock/wheelruntime/builder.py +280 -0
- kivyforge/lock/wheelruntime/model.py +94 -0
- kivyforge/lock/wheelruntime/native_binaries.py +127 -0
- kivyforge/lock/wheelruntime/pbs_github.py +133 -0
- kivyforge/lock/wheelruntime/profile.py +104 -0
- kivyforge/lock/wheelruntime/resolver.py +248 -0
- kivyforge/lock/wheelruntime/runtime.py +161 -0
- kivyforge/lock/wheelruntime/serialize.py +245 -0
- kivyforge/platforms/__init__.py +114 -0
- kivyforge/platforms/android/__init__.py +140 -0
- kivyforge/platforms/android/adb.py +215 -0
- kivyforge/platforms/android/bootstrap/__init__.py +7 -0
- kivyforge/platforms/android/bootstrap/contract.py +166 -0
- kivyforge/platforms/android/bootstrap/render.py +244 -0
- kivyforge/platforms/android/bootstrap/templates/androidtest/KivyforgeContractTest.java +76 -0
- kivyforge/platforms/android/bootstrap/templates/bootstrap_py/_kivy_bootstrap.py +50 -0
- kivyforge/platforms/android/bootstrap/templates/bootstrap_py/_kivyforge_bootstrap.py +54 -0
- kivyforge/platforms/android/bootstrap/templates/bootstrap_py/_kivyforge_selftest.py +97 -0
- kivyforge/platforms/android/bootstrap/templates/cpp/CMakeLists.txt +20 -0
- kivyforge/platforms/android/bootstrap/templates/cpp/main.c +150 -0
- kivyforge/platforms/android/bootstrap/templates/java/org/jnius/NativeInvocationHandler.java +48 -0
- kivyforge/platforms/android/bootstrap/templates/java/org/kivy/android/PythonActivity.java +75 -0
- kivyforge/platforms/android/bootstrap/templates/java/org/kivy/android/PythonBundle.java +132 -0
- kivyforge/platforms/android/bootstrap/templates/java/org/kivy/android/PythonService.java +189 -0
- kivyforge/platforms/android/bootstrap/templates/java/org/renpy/android/Hardware.java +276 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/LICENSE-SDL.txt +18 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/SDL_REVISION.txt +3 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/HIDDevice.java +22 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/HIDDeviceBLESteamController.java +650 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/HIDDeviceManager.java +698 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/HIDDeviceUSB.java +309 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDL.java +90 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDLActivity.java +2120 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDLAudioManager.java +514 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDLControllerManager.java +856 -0
- kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDLSurface.java +405 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/LICENSE-SDL.txt +18 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/SDL_REVISION.txt +3 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/HIDDevice.java +21 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/HIDDeviceBLESteamController.java +829 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/HIDDeviceManager.java +698 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/HIDDeviceUSB.java +354 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDL.java +90 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLActivity.java +2240 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLAudioManager.java +126 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLControllerManager.java +1010 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLDummyEdit.java +66 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLInputConnection.java +136 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLSensorManager.java +73 -0
- kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLSurface.java +464 -0
- kivyforge/platforms/android/cli.py +1023 -0
- kivyforge/platforms/android/doctor.py +899 -0
- kivyforge/platforms/android/elf.py +148 -0
- kivyforge/platforms/android/generate/__init__.py +1 -0
- kivyforge/platforms/android/generate/manifest.py +261 -0
- kivyforge/platforms/android/generate/project.py +462 -0
- kivyforge/platforms/android/generate/services.py +187 -0
- kivyforge/platforms/android/gradle_wrapper/NOTICE +3 -0
- kivyforge/platforms/android/gradle_wrapper/SHA256SUMS +1 -0
- kivyforge/platforms/android/gradle_wrapper/gradle-wrapper.jar +0 -0
- kivyforge/platforms/android/gradle_wrapper/gradlew +164 -0
- kivyforge/platforms/android/gradle_wrapper/gradlew.bat +90 -0
- kivyforge/platforms/android/gradlew.py +60 -0
- kivyforge/platforms/android/icons.py +237 -0
- kivyforge/platforms/android/lock/__init__.py +1 -0
- kivyforge/platforms/android/lock/archives.py +109 -0
- kivyforge/platforms/android/lock/builder.py +387 -0
- kivyforge/platforms/android/lock/markers.py +71 -0
- kivyforge/platforms/android/lock/maven.py +252 -0
- kivyforge/platforms/android/lock/model.py +113 -0
- kivyforge/platforms/android/lock/python_meta.py +199 -0
- kivyforge/platforms/android/lock/reader.py +206 -0
- kivyforge/platforms/android/lock/resolver.py +276 -0
- kivyforge/platforms/android/lock/writer.py +121 -0
- kivyforge/platforms/android/policy.py +214 -0
- kivyforge/platforms/android/signing.py +145 -0
- kivyforge/platforms/android/smoke.py +43 -0
- kivyforge/platforms/android/splash.py +293 -0
- kivyforge/platforms/android/stage/__init__.py +1 -0
- kivyforge/platforms/android/stage/bundle.py +295 -0
- kivyforge/platforms/android/stage/jnilibs.py +186 -0
- kivyforge/platforms/android/stage/runtime.py +61 -0
- kivyforge/platforms/android/stage/wheels.py +106 -0
- kivyforge/platforms/android/toolchain.py +29 -0
- kivyforge/platforms/base.py +157 -0
- kivyforge/platforms/ios/__init__.py +129 -0
- kivyforge/platforms/ios/assets.py +193 -0
- kivyforge/platforms/ios/buildsettings.py +128 -0
- kivyforge/platforms/ios/cli.py +543 -0
- kivyforge/platforms/ios/doctor.py +410 -0
- kivyforge/platforms/ios/entitlements.py +34 -0
- kivyforge/platforms/ios/generator.py +318 -0
- kivyforge/platforms/ios/lock/__init__.py +71 -0
- kivyforge/platforms/ios/lock/builder.py +393 -0
- kivyforge/platforms/ios/lock/markers.py +69 -0
- kivyforge/platforms/ios/lock/model.py +95 -0
- kivyforge/platforms/ios/lock/python_meta.py +187 -0
- kivyforge/platforms/ios/lock/reader.py +191 -0
- kivyforge/platforms/ios/lock/resolver.py +304 -0
- kivyforge/platforms/ios/lock/spm.py +217 -0
- kivyforge/platforms/ios/lock/writer.py +114 -0
- kivyforge/platforms/ios/lock/xcframework.py +188 -0
- kivyforge/platforms/ios/materialize.py +59 -0
- kivyforge/platforms/ios/plist.py +91 -0
- kivyforge/platforms/ios/privacy.py +39 -0
- kivyforge/platforms/ios/skeleton.py +165 -0
- kivyforge/platforms/ios/sources.py +63 -0
- kivyforge/platforms/ios/staging.py +225 -0
- kivyforge/platforms/ios/swift_packages.py +324 -0
- kivyforge/platforms/ios/templates/kivyforge_bootstrap.h +34 -0
- kivyforge/platforms/ios/templates/kivyforge_bootstrap.m +146 -0
- kivyforge/platforms/ios/templates/main.m +15 -0
- kivyforge/platforms/ios/templates/main_config.h.in +12 -0
- kivyforge/platforms/ios/xcframeworks.py +194 -0
- kivyforge/platforms/ios/xcode/__init__.py +76 -0
- kivyforge/platforms/ios/xcode/commands.py +296 -0
- kivyforge/platforms/ios/xcode/runner.py +316 -0
- kivyforge/platforms/linux/__init__.py +120 -0
- kivyforge/platforms/linux/appimage.py +169 -0
- kivyforge/platforms/linux/bundle.py +235 -0
- kivyforge/platforms/linux/cli.py +232 -0
- kivyforge/platforms/linux/desktop.py +71 -0
- kivyforge/platforms/linux/doctor.py +438 -0
- kivyforge/platforms/linux/elftools.py +95 -0
- kivyforge/platforms/linux/icons.py +129 -0
- kivyforge/platforms/linux/launcher.py +107 -0
- kivyforge/platforms/linux/lock/__init__.py +126 -0
- kivyforge/platforms/linux/lock/profile.py +254 -0
- kivyforge/platforms/linux/lock/runtime.py +75 -0
- kivyforge/platforms/linux/native_stage.py +47 -0
- kivyforge/platforms/linux/runtime_stage.py +107 -0
- kivyforge/platforms/linux/wheels_stage.py +103 -0
- kivyforge/platforms/macos/__init__.py +121 -0
- kivyforge/platforms/macos/bundle.py +255 -0
- kivyforge/platforms/macos/cli.py +269 -0
- kivyforge/platforms/macos/doctor.py +480 -0
- kivyforge/platforms/macos/icns.py +75 -0
- kivyforge/platforms/macos/launcher.py +118 -0
- kivyforge/platforms/macos/lock/__init__.py +112 -0
- kivyforge/platforms/macos/lock/profile.py +119 -0
- kivyforge/platforms/macos/lock/runtime.py +58 -0
- kivyforge/platforms/macos/machotools.py +138 -0
- kivyforge/platforms/macos/native_stage.py +47 -0
- kivyforge/platforms/macos/notarize.py +143 -0
- kivyforge/platforms/macos/plist.py +37 -0
- kivyforge/platforms/macos/runtime_stage.py +110 -0
- kivyforge/platforms/macos/signing.py +78 -0
- kivyforge/platforms/macos/wheels_stage.py +108 -0
- kivyforge/platforms/windows/__init__.py +133 -0
- kivyforge/platforms/windows/assets.py +76 -0
- kivyforge/platforms/windows/bundle.py +298 -0
- kivyforge/platforms/windows/cli.py +314 -0
- kivyforge/platforms/windows/doctor.py +563 -0
- kivyforge/platforms/windows/fsswap.py +87 -0
- kivyforge/platforms/windows/icons.py +64 -0
- kivyforge/platforms/windows/launcher/__init__.py +193 -0
- kivyforge/platforms/windows/launcher/build_launcher.py +507 -0
- kivyforge/platforms/windows/launcher/launcher.c +379 -0
- kivyforge/platforms/windows/lock/__init__.py +112 -0
- kivyforge/platforms/windows/lock/profile.py +101 -0
- kivyforge/platforms/windows/lock/runtime.py +64 -0
- kivyforge/platforms/windows/naming.py +52 -0
- kivyforge/platforms/windows/native_stage.py +66 -0
- kivyforge/platforms/windows/petools.py +98 -0
- kivyforge/platforms/windows/rcedit.py +116 -0
- kivyforge/platforms/windows/runtime_stage.py +221 -0
- kivyforge/platforms/windows/signing.py +168 -0
- kivyforge/platforms/windows/vendor/LICENSE.rcedit +29 -0
- kivyforge/platforms/windows/vendor/NOTICE +17 -0
- kivyforge/platforms/windows/vendor/SHA256SUMS +4 -0
- kivyforge/platforms/windows/vendor/TOOLSET.txt +4 -0
- kivyforge/platforms/windows/vendor/__init__.py +12 -0
- kivyforge/platforms/windows/vendor/fetch_rcedit.py +97 -0
- kivyforge/platforms/windows/vendor/launcher-amd64.exe +0 -0
- kivyforge/platforms/windows/vendor/rcedit-x64.exe +0 -0
- kivyforge/platforms/windows/wheels_stage.py +139 -0
- kivyforge-3.0.0.dev0.dist-info/METADATA +609 -0
- kivyforge-3.0.0.dev0.dist-info/RECORD +225 -0
- kivyforge-3.0.0.dev0.dist-info/WHEEL +5 -0
- kivyforge-3.0.0.dev0.dist-info/entry_points.txt +3 -0
- kivyforge-3.0.0.dev0.dist-info/licenses/LICENSE +21 -0
- kivyforge-3.0.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Generate the app-level ``PrivacyInfo.xcprivacy`` (spec 06).
|
|
2
|
+
|
|
3
|
+
Either copies the user's ``[tool.kivy.ios.privacy_manifest].source`` or writes a
|
|
4
|
+
minimal valid stub. This is the *app-level* manifest only; per-xcframework
|
|
5
|
+
privacy manifests are the framework author's responsibility (spec 06).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import plistlib
|
|
11
|
+
import shutil
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from kivyforge.config.model import Config
|
|
15
|
+
|
|
16
|
+
# Minimal valid privacy manifest: declares no tracking and no collected data.
|
|
17
|
+
STUB_MANIFEST: dict = {
|
|
18
|
+
"NSPrivacyTracking": False,
|
|
19
|
+
"NSPrivacyTrackingDomains": [],
|
|
20
|
+
"NSPrivacyCollectedDataTypes": [],
|
|
21
|
+
"NSPrivacyAccessedAPITypes": [],
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def write_privacy_manifest(
|
|
26
|
+
config: Config, dest: str | Path, *, project_root: Path | None = None
|
|
27
|
+
) -> Path:
|
|
28
|
+
dest = Path(dest)
|
|
29
|
+
source = config.ios.privacy_manifest_source if config.ios else None
|
|
30
|
+
if source:
|
|
31
|
+
root = project_root or Path.cwd()
|
|
32
|
+
src_path = (root / source).resolve()
|
|
33
|
+
if not src_path.is_file():
|
|
34
|
+
raise FileNotFoundError(f"privacy_manifest source not found: {source}")
|
|
35
|
+
shutil.copyfile(src_path, dest)
|
|
36
|
+
return dest
|
|
37
|
+
with open(dest, "wb") as f:
|
|
38
|
+
plistlib.dump(STUB_MANIFEST, f, sort_keys=True)
|
|
39
|
+
return dest
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Minimal valid ``project.pbxproj`` skeleton for bootstrapping (spec 06).
|
|
2
|
+
|
|
3
|
+
The ``pbxproj`` library mutates an existing project; it has no from-scratch
|
|
4
|
+
constructor. ``kivyforge build`` therefore parses this internal skeleton once
|
|
5
|
+
(substituting the app name + bundle id) and drives all subsequent wiring —
|
|
6
|
+
phases, files, build settings — through the library's API. This is *not*
|
|
7
|
+
user-facing cookiecutter templating: the skeleton is an implementation detail
|
|
8
|
+
and every meaningful object is added/synced programmatically afterwards.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
# Stable 24-hex object IDs for the skeleton. pbxproj generates fresh IDs for
|
|
14
|
+
# everything added later; these only need to be internally consistent.
|
|
15
|
+
_SKELETON = """// !$*UTF8*$!
|
|
16
|
+
{
|
|
17
|
+
\tarchiveVersion = 1;
|
|
18
|
+
\tclasses = {
|
|
19
|
+
\t};
|
|
20
|
+
\tobjectVersion = 56;
|
|
21
|
+
\tobjects = {
|
|
22
|
+
|
|
23
|
+
\t\t1A0000000000000000000001 /* Sources */ = {
|
|
24
|
+
\t\t\tisa = PBXSourcesBuildPhase;
|
|
25
|
+
\t\t\tbuildActionMask = 2147483647;
|
|
26
|
+
\t\t\tfiles = (
|
|
27
|
+
\t\t\t);
|
|
28
|
+
\t\t\trunOnlyForDeploymentPostprocessing = 0;
|
|
29
|
+
\t\t};
|
|
30
|
+
\t\t1A0000000000000000000002 /* Frameworks */ = {
|
|
31
|
+
\t\t\tisa = PBXFrameworksBuildPhase;
|
|
32
|
+
\t\t\tbuildActionMask = 2147483647;
|
|
33
|
+
\t\t\tfiles = (
|
|
34
|
+
\t\t\t);
|
|
35
|
+
\t\t\trunOnlyForDeploymentPostprocessing = 0;
|
|
36
|
+
\t\t};
|
|
37
|
+
\t\t1A0000000000000000000003 /* Resources */ = {
|
|
38
|
+
\t\t\tisa = PBXResourcesBuildPhase;
|
|
39
|
+
\t\t\tbuildActionMask = 2147483647;
|
|
40
|
+
\t\t\tfiles = (
|
|
41
|
+
\t\t\t);
|
|
42
|
+
\t\t\trunOnlyForDeploymentPostprocessing = 0;
|
|
43
|
+
\t\t};
|
|
44
|
+
|
|
45
|
+
\t\t1A0000000000000000000010 /* {APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "{APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
46
|
+
|
|
47
|
+
\t\t1A0000000000000000000020 = {
|
|
48
|
+
\t\t\tisa = PBXGroup;
|
|
49
|
+
\t\t\tchildren = (
|
|
50
|
+
\t\t\t\t1A0000000000000000000021 /* Products */,
|
|
51
|
+
\t\t\t);
|
|
52
|
+
\t\t\tsourceTree = "<group>";
|
|
53
|
+
\t\t};
|
|
54
|
+
\t\t1A0000000000000000000021 /* Products */ = {
|
|
55
|
+
\t\t\tisa = PBXGroup;
|
|
56
|
+
\t\t\tchildren = (
|
|
57
|
+
\t\t\t\t1A0000000000000000000010 /* {APP_NAME}.app */,
|
|
58
|
+
\t\t\t);
|
|
59
|
+
\t\t\tname = Products;
|
|
60
|
+
\t\t\tsourceTree = "<group>";
|
|
61
|
+
\t\t};
|
|
62
|
+
|
|
63
|
+
\t\t1A0000000000000000000030 /* {APP_NAME} */ = {
|
|
64
|
+
\t\t\tisa = PBXNativeTarget;
|
|
65
|
+
\t\t\tbuildConfigurationList = 1A0000000000000000000040 /* Build configuration list for PBXNativeTarget */;
|
|
66
|
+
\t\t\tbuildPhases = (
|
|
67
|
+
\t\t\t\t1A0000000000000000000001 /* Sources */,
|
|
68
|
+
\t\t\t\t1A0000000000000000000003 /* Resources */,
|
|
69
|
+
\t\t\t\t1A0000000000000000000002 /* Frameworks */,
|
|
70
|
+
\t\t\t);
|
|
71
|
+
\t\t\tbuildRules = (
|
|
72
|
+
\t\t\t);
|
|
73
|
+
\t\t\tdependencies = (
|
|
74
|
+
\t\t\t);
|
|
75
|
+
\t\t\tname = "{APP_NAME}";
|
|
76
|
+
\t\t\tproductName = "{APP_NAME}";
|
|
77
|
+
\t\t\tproductReference = 1A0000000000000000000010 /* {APP_NAME}.app */;
|
|
78
|
+
\t\t\tproductType = "com.apple.product-type.application";
|
|
79
|
+
\t\t};
|
|
80
|
+
|
|
81
|
+
\t\t1A0000000000000000000050 /* Project object */ = {
|
|
82
|
+
\t\t\tisa = PBXProject;
|
|
83
|
+
\t\t\tattributes = {
|
|
84
|
+
\t\t\t\tLastUpgradeCheck = 2600;
|
|
85
|
+
\t\t\t\tTargetAttributes = {
|
|
86
|
+
\t\t\t\t};
|
|
87
|
+
\t\t\t};
|
|
88
|
+
\t\t\tbuildConfigurationList = 1A0000000000000000000060 /* Build configuration list for PBXProject */;
|
|
89
|
+
\t\t\tcompatibilityVersion = "Xcode 14.0";
|
|
90
|
+
\t\t\tdevelopmentRegion = en;
|
|
91
|
+
\t\t\thasScannedForEncodings = 0;
|
|
92
|
+
\t\t\tknownRegions = (
|
|
93
|
+
\t\t\t\ten,
|
|
94
|
+
\t\t\t\tBase,
|
|
95
|
+
\t\t\t);
|
|
96
|
+
\t\t\tmainGroup = 1A0000000000000000000020;
|
|
97
|
+
\t\t\tproductRefGroup = 1A0000000000000000000021 /* Products */;
|
|
98
|
+
\t\t\tprojectDirPath = "";
|
|
99
|
+
\t\t\tprojectRoot = "";
|
|
100
|
+
\t\t\ttargets = (
|
|
101
|
+
\t\t\t\t1A0000000000000000000030 /* {APP_NAME} */,
|
|
102
|
+
\t\t\t);
|
|
103
|
+
\t\t};
|
|
104
|
+
|
|
105
|
+
\t\t1A0000000000000000000041 /* Debug */ = {
|
|
106
|
+
\t\t\tisa = XCBuildConfiguration;
|
|
107
|
+
\t\t\tbuildSettings = {
|
|
108
|
+
\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = "{BUNDLE_ID}";
|
|
109
|
+
\t\t\t\tPRODUCT_NAME = "$(TARGET_NAME)";
|
|
110
|
+
\t\t\t};
|
|
111
|
+
\t\t\tname = Debug;
|
|
112
|
+
\t\t};
|
|
113
|
+
\t\t1A0000000000000000000042 /* Release */ = {
|
|
114
|
+
\t\t\tisa = XCBuildConfiguration;
|
|
115
|
+
\t\t\tbuildSettings = {
|
|
116
|
+
\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = "{BUNDLE_ID}";
|
|
117
|
+
\t\t\t\tPRODUCT_NAME = "$(TARGET_NAME)";
|
|
118
|
+
\t\t\t};
|
|
119
|
+
\t\t\tname = Release;
|
|
120
|
+
\t\t};
|
|
121
|
+
\t\t1A0000000000000000000040 /* Build configuration list for PBXNativeTarget */ = {
|
|
122
|
+
\t\t\tisa = XCConfigurationList;
|
|
123
|
+
\t\t\tbuildConfigurations = (
|
|
124
|
+
\t\t\t\t1A0000000000000000000041 /* Debug */,
|
|
125
|
+
\t\t\t\t1A0000000000000000000042 /* Release */,
|
|
126
|
+
\t\t\t);
|
|
127
|
+
\t\t\tdefaultConfigurationIsVisible = 0;
|
|
128
|
+
\t\t\tdefaultConfigurationName = Release;
|
|
129
|
+
\t\t};
|
|
130
|
+
|
|
131
|
+
\t\t1A0000000000000000000061 /* Debug */ = {
|
|
132
|
+
\t\t\tisa = XCBuildConfiguration;
|
|
133
|
+
\t\t\tbuildSettings = {
|
|
134
|
+
\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;
|
|
135
|
+
\t\t\t\tSDKROOT = iphoneos;
|
|
136
|
+
\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
137
|
+
\t\t\t};
|
|
138
|
+
\t\t\tname = Debug;
|
|
139
|
+
\t\t};
|
|
140
|
+
\t\t1A0000000000000000000062 /* Release */ = {
|
|
141
|
+
\t\t\tisa = XCBuildConfiguration;
|
|
142
|
+
\t\t\tbuildSettings = {
|
|
143
|
+
\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;
|
|
144
|
+
\t\t\t\tSDKROOT = iphoneos;
|
|
145
|
+
\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
146
|
+
\t\t\t};
|
|
147
|
+
\t\t\tname = Release;
|
|
148
|
+
\t\t};
|
|
149
|
+
\t\t1A0000000000000000000060 /* Build configuration list for PBXProject */ = {
|
|
150
|
+
\t\t\tisa = XCConfigurationList;
|
|
151
|
+
\t\t\tbuildConfigurations = (
|
|
152
|
+
\t\t\t\t1A0000000000000000000061 /* Debug */,
|
|
153
|
+
\t\t\t\t1A0000000000000000000062 /* Release */,
|
|
154
|
+
\t\t\t);
|
|
155
|
+
\t\t\tdefaultConfigurationIsVisible = 0;
|
|
156
|
+
\t\t\tdefaultConfigurationName = Release;
|
|
157
|
+
\t\t};
|
|
158
|
+
\t};
|
|
159
|
+
\trootObject = 1A0000000000000000000050 /* Project object */;
|
|
160
|
+
}
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def skeleton_pbxproj(app_name: str, bundle_id: str) -> str:
|
|
165
|
+
return _SKELETON.replace("{APP_NAME}", app_name).replace("{BUNDLE_ID}", bundle_id)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Render the fixed source files and the per-project ``main_config.h`` (spec 06).
|
|
2
|
+
|
|
3
|
+
Generated source layout in <app>-ios/:
|
|
4
|
+
main.m — trivial entry point; calls kivyforge_main()
|
|
5
|
+
kivyforge_bootstrap.h — bootstrap public header
|
|
6
|
+
kivyforge_bootstrap.m — dual-mode bootstrap (SDL3 for Kivy, UIKit for pure-Python)
|
|
7
|
+
main_config.h — per-project defines (entry point, py version)
|
|
8
|
+
|
|
9
|
+
Mobile window/display geometry (DPI, scale, safe area, keyboard height) is no
|
|
10
|
+
longer vendored here — it ships in Kivy core as ``kivy.mobile`` (kivy/kivy#9331).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from kivyforge.config.model import Config
|
|
18
|
+
|
|
19
|
+
_TEMPLATES = Path(__file__).parent / "templates"
|
|
20
|
+
|
|
21
|
+
# Files that are copied verbatim from templates/ into the generated project.
|
|
22
|
+
_BOOTSTRAP_FILES = ("kivyforge_bootstrap.h", "kivyforge_bootstrap.m")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main_m_source() -> str:
|
|
26
|
+
return (_TEMPLATES / "main.m").read_text(encoding="utf-8")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def render_main_config_h(config: Config, *, python_version: str | None = None) -> str:
|
|
30
|
+
"""Fill the main_config.h template with APP_DIR / ENTRY_POINT / py version.
|
|
31
|
+
|
|
32
|
+
``app/`` is the symlink name inside ``<app>-ios/`` (always ``app``), so
|
|
33
|
+
APP_DIR is the bundle-relative folder name, not the user's ``app_dir`` path.
|
|
34
|
+
"""
|
|
35
|
+
version = (
|
|
36
|
+
python_version
|
|
37
|
+
or (config.ios.python_version if config.ios else None)
|
|
38
|
+
or "3.15.0"
|
|
39
|
+
)
|
|
40
|
+
major_minor = ".".join(version.split(".")[:2])
|
|
41
|
+
template = (_TEMPLATES / "main_config.h.in").read_text(encoding="utf-8")
|
|
42
|
+
return (
|
|
43
|
+
template.replace("@APP_DIR@", "app")
|
|
44
|
+
.replace("@ENTRY_POINT@", config.kivy.entry_point)
|
|
45
|
+
.replace("@PYTHON_MAJOR_MINOR@", major_minor)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def write_sources(
|
|
50
|
+
config: Config, project_dir: str | Path, *, python_version: str | None = None
|
|
51
|
+
) -> tuple[Path, Path]:
|
|
52
|
+
project_dir = Path(project_dir)
|
|
53
|
+
main_m = project_dir / "main.m"
|
|
54
|
+
main_h = project_dir / "main_config.h"
|
|
55
|
+
main_m.write_text(main_m_source(), encoding="utf-8")
|
|
56
|
+
main_h.write_text(
|
|
57
|
+
render_main_config_h(config, python_version=python_version), encoding="utf-8"
|
|
58
|
+
)
|
|
59
|
+
for fname in _BOOTSTRAP_FILES:
|
|
60
|
+
(project_dir / fname).write_text(
|
|
61
|
+
(_TEMPLATES / fname).read_text(encoding="utf-8"), encoding="utf-8"
|
|
62
|
+
)
|
|
63
|
+
return main_m, main_h
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Create and maintain the ``<app>-ios/`` staging tree (spec 06)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from kivyforge.bundle.pycompile import PycompileError, byte_compile, select_compiler
|
|
12
|
+
from kivyforge.config.model import Config
|
|
13
|
+
|
|
14
|
+
_APP_COPY_IGNORE = shutil.ignore_patterns("__pycache__", "*.pyc")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class StagingError(Exception):
|
|
18
|
+
"""Staging tree cannot be created (e.g. ``app_dir`` does not exist)."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class StagingLayout:
|
|
23
|
+
root: Path # <app>-ios/
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def xcodeproj(self) -> Path:
|
|
27
|
+
return self.root / f"{self.root.name[:-4]}.xcodeproj"
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def python_xcframework(self) -> Path:
|
|
31
|
+
return self.root / "Python.xcframework"
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def frameworks(self) -> Path:
|
|
35
|
+
return self.root / "Frameworks"
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def app(self) -> Path:
|
|
39
|
+
return self.root / "app"
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def pip_deps_simulator(self) -> Path:
|
|
43
|
+
return self.root / "pip-deps-simulator"
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def pip_deps_device(self) -> Path:
|
|
47
|
+
return self.root / "pip-deps-device"
|
|
48
|
+
|
|
49
|
+
def pip_deps_for_slice(self, target: str) -> Path:
|
|
50
|
+
"""Return the slice-specific pip-deps directory for *target*."""
|
|
51
|
+
return (
|
|
52
|
+
self.pip_deps_simulator if target == "simulator" else self.pip_deps_device
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def resources(self) -> Path:
|
|
57
|
+
return self.root / "Resources"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def staging_dir_name(config: Config) -> str:
|
|
61
|
+
return f"{config.app_slug}-ios"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def create_staging(
|
|
65
|
+
config: Config,
|
|
66
|
+
project_root: str | Path,
|
|
67
|
+
*,
|
|
68
|
+
release: bool = False,
|
|
69
|
+
python_version: str | None = None,
|
|
70
|
+
echo: Callable[[str], None] = lambda msg: None,
|
|
71
|
+
) -> StagingLayout:
|
|
72
|
+
"""Create the ``<app>-ios/`` tree and the ``app/`` source.
|
|
73
|
+
|
|
74
|
+
Dev builds (``release=False``, the default) get a symlink to ``app_dir``
|
|
75
|
+
(spec 06 "symlink, not copy") for fast edit-rebuild iteration — the
|
|
76
|
+
symlink is created once and refreshed only if it points somewhere other
|
|
77
|
+
than the current ``app_dir``. Release builds (``kivyforge package``) get a
|
|
78
|
+
real, disposable copy instead, so ``[tool.kivy.ios.python.build_settings]``
|
|
79
|
+
byte-compilation/stripping can run against it without ever touching the
|
|
80
|
+
user's actual source tree — *release* requires *python_version* (the
|
|
81
|
+
pinned ``Python.xcframework`` version) for that.
|
|
82
|
+
"""
|
|
83
|
+
if release and python_version is None:
|
|
84
|
+
raise ValueError("create_staging(release=True) requires python_version")
|
|
85
|
+
|
|
86
|
+
project_root = Path(project_root)
|
|
87
|
+
root = project_root / staging_dir_name(config)
|
|
88
|
+
layout = StagingLayout(root=root)
|
|
89
|
+
|
|
90
|
+
for d in (
|
|
91
|
+
root,
|
|
92
|
+
layout.frameworks,
|
|
93
|
+
layout.pip_deps_device,
|
|
94
|
+
layout.pip_deps_simulator,
|
|
95
|
+
layout.resources,
|
|
96
|
+
):
|
|
97
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
|
|
99
|
+
if release:
|
|
100
|
+
_materialize_app_copy(layout, project_root, config, python_version, echo)
|
|
101
|
+
else:
|
|
102
|
+
_refresh_app_symlink(layout, project_root, config.kivy.app_dir)
|
|
103
|
+
return layout
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _refresh_app_symlink(
|
|
107
|
+
layout: StagingLayout, project_root: Path, app_dir: str
|
|
108
|
+
) -> None:
|
|
109
|
+
source = project_root / app_dir
|
|
110
|
+
if not source.is_dir():
|
|
111
|
+
raise StagingError(
|
|
112
|
+
f"app_dir '{app_dir}' is not an existing directory "
|
|
113
|
+
f"(looked for {source}). Create it or fix [tool.kivy].app_dir in "
|
|
114
|
+
f"pyproject.toml — it must point at your app's Python source."
|
|
115
|
+
)
|
|
116
|
+
# The symlink target is relative to <app>-ios/ (e.g. ../src).
|
|
117
|
+
target = os.path.relpath(source.resolve(), layout.root)
|
|
118
|
+
link = layout.app
|
|
119
|
+
if link.is_symlink():
|
|
120
|
+
if os.readlink(link) == target:
|
|
121
|
+
return
|
|
122
|
+
link.unlink()
|
|
123
|
+
elif link.is_dir():
|
|
124
|
+
# A real directory here is a previous release build's materialized
|
|
125
|
+
# copy (create_staging(release=True)), not foreign user data — always
|
|
126
|
+
# kivyforge-owned output at this exact path. Reclaim it for the
|
|
127
|
+
# symlink so switching back to build/run after a package works.
|
|
128
|
+
shutil.rmtree(link)
|
|
129
|
+
elif link.exists():
|
|
130
|
+
raise FileExistsError(
|
|
131
|
+
f"{link} exists and is not a symlink; remove it and re-run build."
|
|
132
|
+
)
|
|
133
|
+
link.symlink_to(target)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _materialize_app_copy(
|
|
137
|
+
layout: StagingLayout,
|
|
138
|
+
project_root: Path,
|
|
139
|
+
config: Config,
|
|
140
|
+
python_version: str,
|
|
141
|
+
echo: Callable[[str], None],
|
|
142
|
+
) -> None:
|
|
143
|
+
source = project_root / config.kivy.app_dir
|
|
144
|
+
if not source.is_dir():
|
|
145
|
+
raise StagingError(
|
|
146
|
+
f"app_dir '{config.kivy.app_dir}' is not an existing directory "
|
|
147
|
+
f"(looked for {source}). Create it or fix [tool.kivy].app_dir in "
|
|
148
|
+
f"pyproject.toml — it must point at your app's Python source."
|
|
149
|
+
)
|
|
150
|
+
link = layout.app
|
|
151
|
+
# Always start clean: byte-compiling mutates the copy destructively
|
|
152
|
+
# (deletes .py once a .pyc exists), so a stale copy must never be reused
|
|
153
|
+
# across builds, and a leftover symlink from an earlier dev build must
|
|
154
|
+
# never be mistaken for the release copy.
|
|
155
|
+
if link.is_symlink():
|
|
156
|
+
link.unlink()
|
|
157
|
+
elif link.is_dir():
|
|
158
|
+
shutil.rmtree(link)
|
|
159
|
+
elif link.exists():
|
|
160
|
+
raise FileExistsError(
|
|
161
|
+
f"{link} exists and is neither a symlink nor a directory; remove "
|
|
162
|
+
"it and re-run build."
|
|
163
|
+
)
|
|
164
|
+
shutil.copytree(source, link, ignore=_APP_COPY_IGNORE)
|
|
165
|
+
_compile_app_copy(link, config, python_version, echo)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _setting_applies(value: bool | str, *, release: bool) -> bool:
|
|
169
|
+
"""A ``build_settings`` tri-state resolved for the build being produced."""
|
|
170
|
+
if isinstance(value, bool):
|
|
171
|
+
return value
|
|
172
|
+
return release # DESKTOP_RELEASE_ONLY
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _compile_app_copy(
|
|
176
|
+
app: Path,
|
|
177
|
+
config: Config,
|
|
178
|
+
python_version: str,
|
|
179
|
+
echo: Callable[[str], None],
|
|
180
|
+
) -> None:
|
|
181
|
+
"""Byte-compile/strip the materialized app copy, per ``build_settings``.
|
|
182
|
+
|
|
183
|
+
Only ever called for the release copy (``release=True`` is implicit here
|
|
184
|
+
— this function is unreachable from the dev symlink path), so the
|
|
185
|
+
tri-state resolves against ``release=True`` unconditionally. Mirrors
|
|
186
|
+
``artifacts/collect.py::_compile_pip_deps``: the Python.xcframework ships
|
|
187
|
+
no standalone interpreter to shell out to, so the compiler ladder always
|
|
188
|
+
falls to "this process's interpreter, if its CPython minor matches", or
|
|
189
|
+
degrades.
|
|
190
|
+
"""
|
|
191
|
+
settings = config.ios_required.python_build_settings
|
|
192
|
+
if not _setting_applies(settings.byte_compile, release=True):
|
|
193
|
+
return
|
|
194
|
+
compiler = select_compiler(
|
|
195
|
+
staged_interpreter=Path(), native=False, python_version=python_version
|
|
196
|
+
)
|
|
197
|
+
if compiler is None:
|
|
198
|
+
message = (
|
|
199
|
+
f"this project ships CPython {python_version}, and no CPython of "
|
|
200
|
+
"that minor could be found to byte-compile with (a .pyc is only "
|
|
201
|
+
"loadable by the exact CPython minor that wrote it)"
|
|
202
|
+
)
|
|
203
|
+
if settings.byte_compile is True:
|
|
204
|
+
raise StagingError(
|
|
205
|
+
"[tool.kivy.ios.python.build_settings].byte_compile = true but "
|
|
206
|
+
f"{message}.\n"
|
|
207
|
+
" Install a matching CPython, or set byte_compile = false."
|
|
208
|
+
)
|
|
209
|
+
echo(f"[stage] not byte-compiling app sources: {message}.")
|
|
210
|
+
return
|
|
211
|
+
strip_source = _setting_applies(settings.strip_source, release=True)
|
|
212
|
+
with_what = " ".join(compiler) if compiler else "this interpreter"
|
|
213
|
+
echo(
|
|
214
|
+
f"[stage] byte-compiling app sources with {with_what}"
|
|
215
|
+
+ (" (.pyc only)" if strip_source else "")
|
|
216
|
+
)
|
|
217
|
+
try:
|
|
218
|
+
byte_compile(
|
|
219
|
+
[app], compiler=compiler, strip_source=strip_source, stripdir=app.parent
|
|
220
|
+
)
|
|
221
|
+
except PycompileError as exc:
|
|
222
|
+
raise StagingError(
|
|
223
|
+
f"{exc}\n Fix it, or set "
|
|
224
|
+
"[tool.kivy.ios.python.build_settings].byte_compile = false."
|
|
225
|
+
) from exc
|