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,318 @@
|
|
|
1
|
+
"""Programmatic ``<app>.xcodeproj`` generation via ``pbxproj`` (spec 06).
|
|
2
|
+
|
|
3
|
+
Bootstraps from the internal skeleton on first run, then performs the spec's
|
|
4
|
+
idempotent "every build" sync: managed build settings (per-config), the Build
|
|
5
|
+
Python run script (ordered between Copy Bundle Resources and Frameworks),
|
|
6
|
+
``main.m`` in Sources, Python.xcframework + Frameworks/* embed & sign, the app/
|
|
7
|
+
folder reference, and signing/user settings.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, cast
|
|
14
|
+
|
|
15
|
+
from pbxproj import XcodeProject
|
|
16
|
+
from pbxproj.pbxextensions.ProjectFiles import FileOptions, ProjectFiles, TreeType
|
|
17
|
+
|
|
18
|
+
from kivyforge.config.model import Config
|
|
19
|
+
|
|
20
|
+
from .buildsettings import (
|
|
21
|
+
BUILD_PYTHON_SCRIPT,
|
|
22
|
+
managed_settings,
|
|
23
|
+
signing_settings,
|
|
24
|
+
user_build_settings,
|
|
25
|
+
)
|
|
26
|
+
from .lock.model import LockedSwiftPackage, LockedXcframework
|
|
27
|
+
from .skeleton import skeleton_pbxproj
|
|
28
|
+
from .staging import StagingError, StagingLayout
|
|
29
|
+
from .swift_packages import sync_swift_packages, write_package_resolved
|
|
30
|
+
from .xcframeworks import sync_native_frameworks
|
|
31
|
+
|
|
32
|
+
CONFIGURATIONS = ("Debug", "Release")
|
|
33
|
+
|
|
34
|
+
# Xcode shows "Update to recommended settings" when the project's
|
|
35
|
+
# LastUpgradeCheck is below the running Xcode's version. `kivyforge build`
|
|
36
|
+
# detects the installed Xcode and passes its encoded version down (see
|
|
37
|
+
# kivyforge/cli/build.py); this constant is only the fallback used when Xcode
|
|
38
|
+
# can't be queried. Keep it at/above the minimum supported Xcode.
|
|
39
|
+
RECOMMENDED_LAST_UPGRADE_CHECK = "2650"
|
|
40
|
+
|
|
41
|
+
# pbxproj does not ship .storyboard; register for LaunchScreen.storyboard sync.
|
|
42
|
+
ProjectFiles._FILE_TYPES.setdefault(
|
|
43
|
+
".storyboard", ("file.storyboard", "PBXResourcesBuildPhase")
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class XcodeProjectGenerator:
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
config: Config,
|
|
51
|
+
layout: StagingLayout,
|
|
52
|
+
*,
|
|
53
|
+
last_upgrade_check: str | None = None,
|
|
54
|
+
swift_packages: tuple[LockedSwiftPackage, ...] = (),
|
|
55
|
+
xcframeworks: tuple[LockedXcframework, ...] = (),
|
|
56
|
+
) -> None:
|
|
57
|
+
self.config = config
|
|
58
|
+
self.layout = layout
|
|
59
|
+
self.app_name = config.app_slug
|
|
60
|
+
self.last_upgrade_check = last_upgrade_check or RECOMMENDED_LAST_UPGRADE_CHECK
|
|
61
|
+
self.swift_packages = swift_packages
|
|
62
|
+
self.xcframeworks = xcframeworks
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def pbxproj_path(self) -> Path:
|
|
66
|
+
return self.layout.xcodeproj / "project.pbxproj"
|
|
67
|
+
|
|
68
|
+
def generate(self) -> Path:
|
|
69
|
+
project = self._load_or_bootstrap()
|
|
70
|
+
self._sync_project_attributes(project)
|
|
71
|
+
self._apply_build_settings(project)
|
|
72
|
+
self._sync_run_script(project)
|
|
73
|
+
self._sync_sources(project)
|
|
74
|
+
self._sync_bundle_folders(project)
|
|
75
|
+
self._sync_pip_deps_browse_reference(project)
|
|
76
|
+
self._sync_resources(project)
|
|
77
|
+
self._sync_embedded_frameworks(project)
|
|
78
|
+
self._sync_swift_packages(project)
|
|
79
|
+
project.save()
|
|
80
|
+
self._write_package_resolved()
|
|
81
|
+
return self.pbxproj_path
|
|
82
|
+
|
|
83
|
+
# -- swift packages (spec 07) ------------------------------------------ #
|
|
84
|
+
def _sync_swift_packages(self, project: XcodeProject) -> None:
|
|
85
|
+
sync_swift_packages(
|
|
86
|
+
project,
|
|
87
|
+
self.app_name,
|
|
88
|
+
self.swift_packages,
|
|
89
|
+
staging_root=self.layout.root,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def _write_package_resolved(self) -> None:
|
|
93
|
+
resolved = (
|
|
94
|
+
self.layout.xcodeproj
|
|
95
|
+
/ "project.xcworkspace"
|
|
96
|
+
/ "xcshareddata"
|
|
97
|
+
/ "swiftpm"
|
|
98
|
+
/ "Package.resolved"
|
|
99
|
+
)
|
|
100
|
+
write_package_resolved(resolved, self.swift_packages)
|
|
101
|
+
|
|
102
|
+
# -- bootstrap ---------------------------------------------------------- #
|
|
103
|
+
def _load_or_bootstrap(self) -> XcodeProject:
|
|
104
|
+
if self.pbxproj_path.is_file():
|
|
105
|
+
return XcodeProject.load(str(self.pbxproj_path))
|
|
106
|
+
self.layout.xcodeproj.mkdir(parents=True, exist_ok=True)
|
|
107
|
+
assert self.config.ios is not None
|
|
108
|
+
self.pbxproj_path.write_text(
|
|
109
|
+
skeleton_pbxproj(self.app_name, self.config.ios.bundle_id),
|
|
110
|
+
encoding="utf-8",
|
|
111
|
+
)
|
|
112
|
+
return XcodeProject.load(str(self.pbxproj_path))
|
|
113
|
+
|
|
114
|
+
# -- project attributes ------------------------------------------------- #
|
|
115
|
+
def _sync_project_attributes(self, project: XcodeProject) -> None:
|
|
116
|
+
"""Keep LastUpgradeCheck current so Xcode doesn't prompt to "Update to
|
|
117
|
+
recommended settings" (self-heals projects bootstrapped by older runs).
|
|
118
|
+
"""
|
|
119
|
+
for proj in cast(Any, project).objects.get_objects_in_section("PBXProject"):
|
|
120
|
+
attributes = proj["attributes"]
|
|
121
|
+
attributes["LastUpgradeCheck"] = self.last_upgrade_check
|
|
122
|
+
|
|
123
|
+
# -- build settings ----------------------------------------------------- #
|
|
124
|
+
def _apply_build_settings(self, project: XcodeProject) -> None:
|
|
125
|
+
signing = signing_settings(self.config)
|
|
126
|
+
user = user_build_settings(self.config)
|
|
127
|
+
for configuration in CONFIGURATIONS:
|
|
128
|
+
project.set_flags(
|
|
129
|
+
"ALWAYS_SEARCH_USER_PATHS",
|
|
130
|
+
"NO",
|
|
131
|
+
configuration_name=configuration,
|
|
132
|
+
)
|
|
133
|
+
settings = managed_settings(
|
|
134
|
+
self.config, configuration=configuration, layout=self.layout
|
|
135
|
+
)
|
|
136
|
+
# user settings layered under managed (reserved keys already rejected)
|
|
137
|
+
merged = {**user, **settings, **signing}
|
|
138
|
+
for key, value in merged.items():
|
|
139
|
+
project.set_flags(
|
|
140
|
+
key,
|
|
141
|
+
value,
|
|
142
|
+
target_name=self.app_name,
|
|
143
|
+
configuration_name=configuration,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# -- run script --------------------------------------------------------- #
|
|
147
|
+
def _sync_run_script(self, project: XcodeProject) -> None:
|
|
148
|
+
# Idempotent: drop any prior copy, re-add, then order it between Copy
|
|
149
|
+
# Bundle Resources and the Frameworks (Link) phase.
|
|
150
|
+
project.remove_run_script(BUILD_PYTHON_SCRIPT)
|
|
151
|
+
project.add_run_script(BUILD_PYTHON_SCRIPT, target_name=self.app_name)
|
|
152
|
+
self._configure_run_script(project)
|
|
153
|
+
self._order_run_script(project)
|
|
154
|
+
|
|
155
|
+
def _configure_run_script(self, project: XcodeProject) -> None:
|
|
156
|
+
# Spec 06: run every build (install_python walks app/ + pip-deps/).
|
|
157
|
+
target = project.get_target_by_name(self.app_name)
|
|
158
|
+
if target is None:
|
|
159
|
+
raise RuntimeError(f"target {self.app_name!r} not found in Xcode project")
|
|
160
|
+
for phase_id in target.buildPhases:
|
|
161
|
+
phase = project.get_object(phase_id)
|
|
162
|
+
if (
|
|
163
|
+
getattr(phase, "isa", None) == "PBXShellScriptBuildPhase"
|
|
164
|
+
and getattr(phase, "shellScript", None) == BUILD_PYTHON_SCRIPT
|
|
165
|
+
):
|
|
166
|
+
phase["alwaysOutOfDate"] = 1
|
|
167
|
+
break
|
|
168
|
+
|
|
169
|
+
def _order_run_script(self, project: XcodeProject) -> None:
|
|
170
|
+
target = project.get_target_by_name(self.app_name)
|
|
171
|
+
if target is None:
|
|
172
|
+
raise RuntimeError(f"target {self.app_name!r} not found in Xcode project")
|
|
173
|
+
phases = list(target.buildPhases)
|
|
174
|
+
kinds = {pid: project.get_object(pid).isa for pid in phases}
|
|
175
|
+
script = next(
|
|
176
|
+
(p for p in phases if kinds[p] == "PBXShellScriptBuildPhase"), None
|
|
177
|
+
)
|
|
178
|
+
frameworks = next(
|
|
179
|
+
(p for p in phases if kinds[p] == "PBXFrameworksBuildPhase"), None
|
|
180
|
+
)
|
|
181
|
+
if script is None or frameworks is None:
|
|
182
|
+
return
|
|
183
|
+
phases.remove(script)
|
|
184
|
+
idx = phases.index(frameworks)
|
|
185
|
+
phases.insert(idx, script)
|
|
186
|
+
target.buildPhases = phases
|
|
187
|
+
|
|
188
|
+
# -- sources ------------------------------------------------------------ #
|
|
189
|
+
def _sync_sources(self, project: XcodeProject) -> None:
|
|
190
|
+
sources_group = project.get_or_create_group("Sources")
|
|
191
|
+
for source_file in ("main.m", "kivyforge_bootstrap.m"):
|
|
192
|
+
fpath = self.layout.root / source_file
|
|
193
|
+
if fpath.is_file() and not project.get_files_by_name(source_file):
|
|
194
|
+
project.add_file(
|
|
195
|
+
source_file,
|
|
196
|
+
parent=sources_group,
|
|
197
|
+
target_name=self.app_name,
|
|
198
|
+
tree="SOURCE_ROOT",
|
|
199
|
+
file_options=FileOptions(embed_framework=False),
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# -- bundle resources --------------------------------------------------- #
|
|
203
|
+
def _sync_bundle_folders(self, project: XcodeProject) -> None:
|
|
204
|
+
"""Add ``app/`` as a folder reference (spec 06).
|
|
205
|
+
|
|
206
|
+
``app/`` is mandatory — it is the symlink to the user's ``app_dir`` and
|
|
207
|
+
carries the app's Python source into the bundle. If it does not resolve
|
|
208
|
+
to an existing directory, fail loudly rather than silently shipping an
|
|
209
|
+
app with no code.
|
|
210
|
+
|
|
211
|
+
``pip-deps/`` is intentionally *not* a Copy Bundle Resources folder
|
|
212
|
+
reference. It is platform-sliced (``pip-deps-simulator`` /
|
|
213
|
+
``pip-deps-device``) and the Build Python run script rsyncs the correct
|
|
214
|
+
slice into the bundle on every build; a folder reference here would
|
|
215
|
+
stage one fixed slice — the wrong one for half of all builds — ahead of
|
|
216
|
+
that rsync.
|
|
217
|
+
"""
|
|
218
|
+
if not self.layout.app.exists():
|
|
219
|
+
raise StagingError(
|
|
220
|
+
f"app source directory is missing: {self.layout.app} does not "
|
|
221
|
+
f"resolve to an existing directory (app_dir = "
|
|
222
|
+
f"{self.config.kivy.app_dir!r}). Fix [tool.kivy].app_dir in "
|
|
223
|
+
f"pyproject.toml."
|
|
224
|
+
)
|
|
225
|
+
if not project.get_files_by_name("app"):
|
|
226
|
+
project.add_file(
|
|
227
|
+
"app",
|
|
228
|
+
target_name=self.app_name,
|
|
229
|
+
tree="SOURCE_ROOT",
|
|
230
|
+
file_options=FileOptions(embed_framework=False),
|
|
231
|
+
)
|
|
232
|
+
# pbxproj type detection uses CWD; force folder refs for bundle copy.
|
|
233
|
+
for ref in project.get_files_by_name("app"):
|
|
234
|
+
ref.set_last_known_file_type("folder")
|
|
235
|
+
|
|
236
|
+
def _sync_pip_deps_browse_reference(self, project: XcodeProject) -> None:
|
|
237
|
+
"""Show the pip-deps packages in the navigator without building them.
|
|
238
|
+
|
|
239
|
+
pip-deps is staged into the bundle by the Build Python run script, not
|
|
240
|
+
Copy Bundle Resources, so it would otherwise be invisible in Xcode's
|
|
241
|
+
project navigator. Add the simulator slice as a folder reference for
|
|
242
|
+
browsing only: ``create_build_files=False`` keeps it out of every build
|
|
243
|
+
phase, so it has no effect on the build (the package set is identical
|
|
244
|
+
across slices). Its on-disk path is ``pip-deps-simulator``; only its
|
|
245
|
+
display name is ``pip-deps``.
|
|
246
|
+
"""
|
|
247
|
+
if not self.layout.pip_deps_simulator.is_dir():
|
|
248
|
+
return
|
|
249
|
+
if project.get_files_by_path("pip-deps-simulator", tree=TreeType.SOURCE_ROOT):
|
|
250
|
+
return # already present (idempotent)
|
|
251
|
+
project.add_file(
|
|
252
|
+
"pip-deps-simulator",
|
|
253
|
+
tree=TreeType.SOURCE_ROOT,
|
|
254
|
+
force=True,
|
|
255
|
+
file_options=FileOptions(create_build_files=False, embed_framework=False),
|
|
256
|
+
)
|
|
257
|
+
for ref in project.get_files_by_path(
|
|
258
|
+
"pip-deps-simulator", tree=TreeType.SOURCE_ROOT
|
|
259
|
+
):
|
|
260
|
+
ref.set_last_known_file_type("folder")
|
|
261
|
+
ref["name"] = "pip-deps"
|
|
262
|
+
|
|
263
|
+
def _sync_resources(self, project: XcodeProject) -> None:
|
|
264
|
+
opts = FileOptions(embed_framework=False)
|
|
265
|
+
# PrivacyInfo.xcprivacy must ship in the bundle (Apple required-reason
|
|
266
|
+
# APIs); pbxproj already maps .xcprivacy -> Copy Bundle Resources.
|
|
267
|
+
privacy = self.layout.root / "PrivacyInfo.xcprivacy"
|
|
268
|
+
if privacy.is_file() and not project.get_files_by_name("PrivacyInfo.xcprivacy"):
|
|
269
|
+
project.add_file(
|
|
270
|
+
"PrivacyInfo.xcprivacy",
|
|
271
|
+
target_name=self.app_name,
|
|
272
|
+
tree="SOURCE_ROOT",
|
|
273
|
+
file_options=opts,
|
|
274
|
+
)
|
|
275
|
+
catalog = self.layout.resources / "Assets.xcassets"
|
|
276
|
+
if catalog.is_dir() and not project.get_files_by_name("Assets.xcassets"):
|
|
277
|
+
project.add_file(
|
|
278
|
+
"Resources/Assets.xcassets",
|
|
279
|
+
target_name=self.app_name,
|
|
280
|
+
tree="SOURCE_ROOT",
|
|
281
|
+
file_options=opts,
|
|
282
|
+
)
|
|
283
|
+
launch = self.layout.root / "LaunchScreen.storyboard"
|
|
284
|
+
if launch.is_file() and not project.get_files_by_name(
|
|
285
|
+
"LaunchScreen.storyboard"
|
|
286
|
+
):
|
|
287
|
+
project.add_file(
|
|
288
|
+
"LaunchScreen.storyboard",
|
|
289
|
+
target_name=self.app_name,
|
|
290
|
+
tree="SOURCE_ROOT",
|
|
291
|
+
file_options=opts,
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# -- frameworks (embed & sign) ----------------------------------------- #
|
|
295
|
+
def _sync_embedded_frameworks(self, project: XcodeProject) -> None:
|
|
296
|
+
embed = FileOptions(embed_framework=True, code_sign_on_copy=True)
|
|
297
|
+
frameworks_group = project.get_or_create_group("Frameworks", "Frameworks")
|
|
298
|
+
# Python.xcframework: Embed & Sign (Link + Embed) per python.org docs.
|
|
299
|
+
if self.layout.python_xcframework.exists() and not project.get_files_by_name(
|
|
300
|
+
"Python.xcframework"
|
|
301
|
+
):
|
|
302
|
+
project.add_file(
|
|
303
|
+
"Python.xcframework",
|
|
304
|
+
target_name=self.app_name,
|
|
305
|
+
tree="SOURCE_ROOT",
|
|
306
|
+
file_options=embed,
|
|
307
|
+
)
|
|
308
|
+
# Frameworks/*.xcframework — link/embed per the locked native entries
|
|
309
|
+
# (wheel-embedded SDL3/ANGLE default to Embed & Sign); stale refs for
|
|
310
|
+
# frameworks no longer on disk are pruned.
|
|
311
|
+
link_embed = {xc.name: (xc.link, xc.embed) for xc in self.xcframeworks}
|
|
312
|
+
sync_native_frameworks(
|
|
313
|
+
project,
|
|
314
|
+
self.app_name,
|
|
315
|
+
frameworks_dir=self.layout.frameworks,
|
|
316
|
+
frameworks_group=frameworks_group,
|
|
317
|
+
link_embed=link_embed,
|
|
318
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""iOS lock stack (``pylock.ios.toml``, spec 02).
|
|
2
|
+
|
|
3
|
+
The iOS public lock surface: resolve dependencies + native artifacts into a
|
|
4
|
+
``Lockfile``, serialize/parse ``pylock.ios.toml``, and compare locks. The
|
|
5
|
+
platform-neutral pieces (the ``[[packages]]`` model, PEP 751 helpers, the
|
|
6
|
+
drift check, and the neutral pip helpers) live in ``kivyforge.lock``.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from kivyforge.lock.model import LockedPackage, LockedWheel
|
|
12
|
+
|
|
13
|
+
from .builder import BuildError, build_lockfile, diff_summary, semantic_equal
|
|
14
|
+
from .model import (
|
|
15
|
+
LockedSwiftPackage,
|
|
16
|
+
LockedXcframework,
|
|
17
|
+
Lockfile,
|
|
18
|
+
PythonXcframework,
|
|
19
|
+
)
|
|
20
|
+
from .reader import LockError, compute_pyproject_sha256, is_in_sync, load, loads
|
|
21
|
+
from .resolver import (
|
|
22
|
+
PipResolver,
|
|
23
|
+
ResolvedPackage,
|
|
24
|
+
ResolvedWheel,
|
|
25
|
+
Resolver,
|
|
26
|
+
ResolverError,
|
|
27
|
+
get_resolver,
|
|
28
|
+
slice_tags,
|
|
29
|
+
)
|
|
30
|
+
from .spm import (
|
|
31
|
+
ResolvedSwiftPackage,
|
|
32
|
+
SpmResolver,
|
|
33
|
+
SpmResolverError,
|
|
34
|
+
XcodeSpmResolver,
|
|
35
|
+
get_spm_resolver,
|
|
36
|
+
)
|
|
37
|
+
from .writer import dumps
|
|
38
|
+
from .xcframework import XcframeworkResolverError, resolve_xcframeworks
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"BuildError",
|
|
42
|
+
"build_lockfile",
|
|
43
|
+
"diff_summary",
|
|
44
|
+
"semantic_equal",
|
|
45
|
+
"Lockfile",
|
|
46
|
+
"LockedPackage",
|
|
47
|
+
"LockedSwiftPackage",
|
|
48
|
+
"LockedWheel",
|
|
49
|
+
"LockedXcframework",
|
|
50
|
+
"PythonXcframework",
|
|
51
|
+
"LockError",
|
|
52
|
+
"compute_pyproject_sha256",
|
|
53
|
+
"is_in_sync",
|
|
54
|
+
"load",
|
|
55
|
+
"loads",
|
|
56
|
+
"dumps",
|
|
57
|
+
"PipResolver",
|
|
58
|
+
"Resolver",
|
|
59
|
+
"ResolvedPackage",
|
|
60
|
+
"ResolvedWheel",
|
|
61
|
+
"ResolverError",
|
|
62
|
+
"get_resolver",
|
|
63
|
+
"slice_tags",
|
|
64
|
+
"ResolvedSwiftPackage",
|
|
65
|
+
"SpmResolver",
|
|
66
|
+
"SpmResolverError",
|
|
67
|
+
"XcodeSpmResolver",
|
|
68
|
+
"get_spm_resolver",
|
|
69
|
+
"XcframeworkResolverError",
|
|
70
|
+
"resolve_xcframeworks",
|
|
71
|
+
]
|