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
kivyforge/cli/upgrade.py
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"""``kivyforge upgrade`` — re-download pinned runtime/native artifacts per the
|
|
2
|
+
resolved platform's lock (spec 05).
|
|
3
|
+
|
|
4
|
+
Platform-aware: resolves the target the same way as ``lock``/``build``/``run``
|
|
5
|
+
(``-p`` / ``KIVYFORGE_PLATFORM`` / host default, gated on the lock already
|
|
6
|
+
being configured). iOS refreshes ``Python.xcframework`` + xcframework
|
|
7
|
+
artifacts; macOS/Linux refresh the pinned python-build-standalone runtime
|
|
8
|
+
archive(s) — their locks have no xcframework-equivalent entries. Dependency
|
|
9
|
+
wheels are deliberately never touched here on any platform (that is
|
|
10
|
+
``build``'s/``lock``'s job); ``upgrade`` only re-fetches bytes already pinned
|
|
11
|
+
by the existing lock, it never changes what is pinned.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import click
|
|
19
|
+
|
|
20
|
+
from ..artifacts.download import DownloadError, fetch_artifact
|
|
21
|
+
from ..artifacts.verify import HashMismatch
|
|
22
|
+
from ..lock import LockError
|
|
23
|
+
from ..platforms.ios.lock import load as load_ios_lock
|
|
24
|
+
from ._common import ToolchainError, lockfile_path_for
|
|
25
|
+
from ._platform import platform_option, resolve_target
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.command()
|
|
29
|
+
@platform_option
|
|
30
|
+
@click.option(
|
|
31
|
+
"--python",
|
|
32
|
+
"python_only",
|
|
33
|
+
is_flag=True,
|
|
34
|
+
help="Only refresh the bundled Python runtime (iOS: Python.xcframework; "
|
|
35
|
+
"macOS/Linux: the runtime archive(s) — a no-op flag there, it's already "
|
|
36
|
+
"the only refreshable artifact).",
|
|
37
|
+
)
|
|
38
|
+
@click.option(
|
|
39
|
+
"--xcframeworks",
|
|
40
|
+
"xcframeworks_only",
|
|
41
|
+
is_flag=True,
|
|
42
|
+
help="Only refresh native xcframework artifacts (iOS only).",
|
|
43
|
+
)
|
|
44
|
+
@click.option(
|
|
45
|
+
"--libs",
|
|
46
|
+
"libs_only",
|
|
47
|
+
is_flag=True,
|
|
48
|
+
help="Only refresh the locked .aar/.jar artifacts (Android only) — the "
|
|
49
|
+
"Android counterpart of --xcframeworks.",
|
|
50
|
+
)
|
|
51
|
+
@click.option(
|
|
52
|
+
"--name",
|
|
53
|
+
default=None,
|
|
54
|
+
help="Only refresh a specific artifact by name (iOS: an xcframework name "
|
|
55
|
+
"or 'Python.xcframework'; Android: an .aar/.jar name or an ABI; "
|
|
56
|
+
"macOS/Linux: a locked arch, e.g. 'arm64').",
|
|
57
|
+
)
|
|
58
|
+
def upgrade(
|
|
59
|
+
cli_platform: str | None,
|
|
60
|
+
python_only: bool,
|
|
61
|
+
xcframeworks_only: bool,
|
|
62
|
+
libs_only: bool,
|
|
63
|
+
name: str | None,
|
|
64
|
+
) -> None:
|
|
65
|
+
"""Re-fetch pinned runtime/native artifacts for the resolved platform's lock."""
|
|
66
|
+
backend, project_root = resolve_target(cli_platform, verb="upgrade")
|
|
67
|
+
|
|
68
|
+
if libs_only and backend.name != "android":
|
|
69
|
+
raise ToolchainError(
|
|
70
|
+
f"--libs is Android-only; {backend.name} locks have no .aar/.jar "
|
|
71
|
+
+ (
|
|
72
|
+
"artifacts. Use --xcframeworks for the iOS equivalent."
|
|
73
|
+
if backend.name == "ios"
|
|
74
|
+
else "artifacts."
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
if python_only and libs_only:
|
|
78
|
+
raise ToolchainError(
|
|
79
|
+
"--python and --libs select disjoint halves of the lock; pass one, "
|
|
80
|
+
"or neither to refresh everything."
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if backend.name == "ios":
|
|
84
|
+
_upgrade_ios(project_root, python_only, xcframeworks_only, name)
|
|
85
|
+
elif backend.name == "android":
|
|
86
|
+
if xcframeworks_only:
|
|
87
|
+
raise ToolchainError(
|
|
88
|
+
"--xcframeworks is iOS-only; Android uses --libs for .aar/.jar."
|
|
89
|
+
)
|
|
90
|
+
_upgrade_android(project_root, python_only, libs_only, name)
|
|
91
|
+
elif backend.name in ("macos", "linux", "windows"):
|
|
92
|
+
if xcframeworks_only:
|
|
93
|
+
raise ToolchainError(
|
|
94
|
+
f"--xcframeworks is iOS-only; {backend.name} locks have no "
|
|
95
|
+
"xcframework artifacts. Use --python (or no flag) to refresh "
|
|
96
|
+
"the bundled runtime."
|
|
97
|
+
)
|
|
98
|
+
_upgrade_wheelruntime(backend.name, project_root, name)
|
|
99
|
+
else:
|
|
100
|
+
raise ToolchainError(
|
|
101
|
+
f"`kivyforge upgrade` does not support platform {backend.name!r} yet."
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _upgrade_android(
|
|
106
|
+
project_root: Path, python_only: bool, libs_only: bool, name: str | None
|
|
107
|
+
) -> None:
|
|
108
|
+
"""Re-fetch the pinned python.org runtime + .aar/.jar per the existing lock.
|
|
109
|
+
|
|
110
|
+
Does not reinstall wheels, regenerate the project, or invoke Gradle
|
|
111
|
+
(android/06 §upgrade): to take newer versions, edit pyproject.toml and
|
|
112
|
+
re-lock.
|
|
113
|
+
"""
|
|
114
|
+
from ..platforms.android.lock import reader as android_reader
|
|
115
|
+
|
|
116
|
+
lock_path = project_root / "pylock.android.toml"
|
|
117
|
+
if not lock_path.is_file():
|
|
118
|
+
raise ToolchainError(
|
|
119
|
+
"pylock.android.toml not found. Run `kivyforge lock -p android` first."
|
|
120
|
+
)
|
|
121
|
+
try:
|
|
122
|
+
lock = android_reader.load(lock_path)
|
|
123
|
+
except LockError as exc:
|
|
124
|
+
raise ToolchainError(str(exc)) from exc
|
|
125
|
+
|
|
126
|
+
do_python = not libs_only
|
|
127
|
+
do_libs = not python_only
|
|
128
|
+
refreshed = skipped = 0
|
|
129
|
+
for runtime in lock.python_android if do_python else ():
|
|
130
|
+
if name and name not in (runtime.abi, "python"):
|
|
131
|
+
continue
|
|
132
|
+
if runtime.path:
|
|
133
|
+
skipped += 1
|
|
134
|
+
continue
|
|
135
|
+
click.echo(
|
|
136
|
+
f"Refreshing python.org runtime {runtime.version} ({runtime.abi}) ..."
|
|
137
|
+
)
|
|
138
|
+
fetch_artifact(
|
|
139
|
+
name=f"python-android-{runtime.abi}",
|
|
140
|
+
sha256=runtime.sha256,
|
|
141
|
+
filename=(runtime.url or "").rsplit("/", 1)[-1],
|
|
142
|
+
url=runtime.url,
|
|
143
|
+
project_root=project_root,
|
|
144
|
+
no_cache=True,
|
|
145
|
+
)
|
|
146
|
+
refreshed += 1
|
|
147
|
+
if do_libs:
|
|
148
|
+
for lib in lock.android_libs:
|
|
149
|
+
if name and name != lib.name:
|
|
150
|
+
continue
|
|
151
|
+
if lib.path:
|
|
152
|
+
skipped += 1
|
|
153
|
+
continue
|
|
154
|
+
click.echo(f"Refreshing {lib.kind} {lib.name} {lib.version} ...")
|
|
155
|
+
fetch_artifact(
|
|
156
|
+
name=lib.name,
|
|
157
|
+
sha256=lib.sha256,
|
|
158
|
+
filename=(lib.url or "").rsplit("/", 1)[-1],
|
|
159
|
+
url=lib.url,
|
|
160
|
+
project_root=project_root,
|
|
161
|
+
no_cache=True,
|
|
162
|
+
)
|
|
163
|
+
refreshed += 1
|
|
164
|
+
if name and refreshed == 0 and skipped == 0:
|
|
165
|
+
known = sorted(
|
|
166
|
+
{r.abi for r in lock.python_android}
|
|
167
|
+
| {lib.name for lib in lock.android_libs}
|
|
168
|
+
)
|
|
169
|
+
raise ToolchainError(
|
|
170
|
+
f"no artifact named {name!r} found in {lock_path.name}. "
|
|
171
|
+
f"Known name(s): {', '.join(known) or 'none'} (or 'python' for "
|
|
172
|
+
"every runtime)."
|
|
173
|
+
)
|
|
174
|
+
click.echo(
|
|
175
|
+
f"Refreshed {refreshed} artifact(s)"
|
|
176
|
+
+ (f"; {skipped} vendored (path) entry(ies) skipped." if skipped else ".")
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# --------------------------------------------------------------------------- #
|
|
181
|
+
# iOS — Python.xcframework + [[xcframeworks]]
|
|
182
|
+
# --------------------------------------------------------------------------- #
|
|
183
|
+
def _upgrade_ios(
|
|
184
|
+
project_root: Path,
|
|
185
|
+
python_only: bool,
|
|
186
|
+
xcframeworks_only: bool,
|
|
187
|
+
name: str | None,
|
|
188
|
+
) -> None:
|
|
189
|
+
lock = _load_ios_lock(project_root)
|
|
190
|
+
|
|
191
|
+
# No selector flag => refresh everything.
|
|
192
|
+
do_python = python_only or not (python_only or xcframeworks_only or name)
|
|
193
|
+
do_xc = xcframeworks_only or not (python_only or xcframeworks_only or name)
|
|
194
|
+
if name:
|
|
195
|
+
do_python = name == "Python.xcframework"
|
|
196
|
+
do_xc = True
|
|
197
|
+
|
|
198
|
+
refreshed = 0
|
|
199
|
+
skipped_vendored = 0
|
|
200
|
+
try:
|
|
201
|
+
if do_python and (not name or name == "Python.xcframework"):
|
|
202
|
+
px = lock.python_xcframework
|
|
203
|
+
click.echo(f"Refreshing Python.xcframework {px.version} ...")
|
|
204
|
+
fetch_artifact(
|
|
205
|
+
name="Python.xcframework",
|
|
206
|
+
sha256=px.sha256,
|
|
207
|
+
filename=px.url.rsplit("/", 1)[-1],
|
|
208
|
+
url=px.url,
|
|
209
|
+
no_cache=True,
|
|
210
|
+
)
|
|
211
|
+
refreshed += 1
|
|
212
|
+
|
|
213
|
+
if do_xc:
|
|
214
|
+
for xc in lock.xcframeworks:
|
|
215
|
+
if name and xc.name != name:
|
|
216
|
+
continue
|
|
217
|
+
if xc.path:
|
|
218
|
+
skipped_vendored += 1
|
|
219
|
+
continue
|
|
220
|
+
url = xc.url
|
|
221
|
+
if url is None:
|
|
222
|
+
continue
|
|
223
|
+
click.echo(f"Refreshing {xc.name} {xc.version} ...")
|
|
224
|
+
fetch_artifact(
|
|
225
|
+
name=xc.name,
|
|
226
|
+
sha256=xc.sha256,
|
|
227
|
+
filename=url.rsplit("/", 1)[-1],
|
|
228
|
+
url=url,
|
|
229
|
+
project_root=project_root,
|
|
230
|
+
no_cache=True,
|
|
231
|
+
)
|
|
232
|
+
refreshed += 1
|
|
233
|
+
except HashMismatch as exc:
|
|
234
|
+
raise ToolchainError(str(exc)) from exc
|
|
235
|
+
except DownloadError as exc:
|
|
236
|
+
raise ToolchainError(str(exc)) from exc
|
|
237
|
+
|
|
238
|
+
if name and refreshed == 0 and skipped_vendored == 0:
|
|
239
|
+
raise ToolchainError(
|
|
240
|
+
f"no artifact named {name!r} found in {lockfile_path_for('ios').name}."
|
|
241
|
+
)
|
|
242
|
+
msg = f"Refreshed {refreshed} artifact(s)."
|
|
243
|
+
if skipped_vendored:
|
|
244
|
+
msg += f" Skipped {skipped_vendored} vendored (path-based) entry/entries."
|
|
245
|
+
click.echo(msg)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _load_ios_lock(project_root: Path):
|
|
249
|
+
path = lockfile_path_for("ios", project_root)
|
|
250
|
+
if not path.is_file():
|
|
251
|
+
raise ToolchainError(f"no {path.name} found. Run `kivyforge lock` first.")
|
|
252
|
+
try:
|
|
253
|
+
return load_ios_lock(path)
|
|
254
|
+
except LockError as exc:
|
|
255
|
+
raise ToolchainError(str(exc)) from exc
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# --------------------------------------------------------------------------- #
|
|
259
|
+
# macOS / Linux — bundled python-build-standalone runtime archive(s)
|
|
260
|
+
# --------------------------------------------------------------------------- #
|
|
261
|
+
def _upgrade_wheelruntime(
|
|
262
|
+
platform_name: str, project_root: Path, name: str | None
|
|
263
|
+
) -> None:
|
|
264
|
+
lock = _load_wheelruntime_lock(platform_name, project_root)
|
|
265
|
+
runtime = lock.python_runtime
|
|
266
|
+
artifacts = runtime.artifacts
|
|
267
|
+
if name:
|
|
268
|
+
artifacts = [art for art in artifacts if art.arch == name]
|
|
269
|
+
|
|
270
|
+
refreshed = 0
|
|
271
|
+
try:
|
|
272
|
+
for art in artifacts:
|
|
273
|
+
click.echo(
|
|
274
|
+
f"Refreshing the {platform_name} Python runtime "
|
|
275
|
+
f"({art.arch}) {runtime.version} ..."
|
|
276
|
+
)
|
|
277
|
+
fetch_artifact(
|
|
278
|
+
name=f"python-runtime-{art.arch}",
|
|
279
|
+
sha256=art.sha256,
|
|
280
|
+
filename=art.url.rsplit("/", 1)[-1],
|
|
281
|
+
url=art.url,
|
|
282
|
+
project_root=project_root,
|
|
283
|
+
no_cache=True,
|
|
284
|
+
)
|
|
285
|
+
refreshed += 1
|
|
286
|
+
except HashMismatch as exc:
|
|
287
|
+
raise ToolchainError(str(exc)) from exc
|
|
288
|
+
except DownloadError as exc:
|
|
289
|
+
raise ToolchainError(str(exc)) from exc
|
|
290
|
+
|
|
291
|
+
if name and refreshed == 0:
|
|
292
|
+
locked = ", ".join(sorted(art.arch for art in runtime.artifacts))
|
|
293
|
+
path = lockfile_path_for(platform_name, project_root)
|
|
294
|
+
raise ToolchainError(
|
|
295
|
+
f"no runtime artifact for arch {name!r} in {path.name}. "
|
|
296
|
+
f"Locked arch(s): {locked}."
|
|
297
|
+
)
|
|
298
|
+
click.echo(f"Refreshed {refreshed} artifact(s).")
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _load_wheelruntime_lock(platform_name: str, project_root: Path):
|
|
302
|
+
path = lockfile_path_for(platform_name, project_root)
|
|
303
|
+
if not path.is_file():
|
|
304
|
+
raise ToolchainError(f"no {path.name} found. Run `kivyforge lock` first.")
|
|
305
|
+
if platform_name == "macos":
|
|
306
|
+
from ..platforms.macos.lock import load as loader
|
|
307
|
+
elif platform_name == "windows":
|
|
308
|
+
from ..platforms.windows.lock import load as loader
|
|
309
|
+
else:
|
|
310
|
+
from ..platforms.linux.lock import load as loader
|
|
311
|
+
try:
|
|
312
|
+
return loader(path)
|
|
313
|
+
except LockError as exc:
|
|
314
|
+
raise ToolchainError(str(exc)) from exc
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""kivyforge project configuration (pyproject.toml) model and loader (spec 01)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .errors import ConfigError
|
|
6
|
+
from .loader import load_config, load_config_from_text
|
|
7
|
+
from .model import (
|
|
8
|
+
Author,
|
|
9
|
+
Config,
|
|
10
|
+
DesktopConfig,
|
|
11
|
+
IconConfig,
|
|
12
|
+
IosConfig,
|
|
13
|
+
KivyMeta,
|
|
14
|
+
LinuxConfig,
|
|
15
|
+
MacosConfig,
|
|
16
|
+
NativeBinaryDep,
|
|
17
|
+
ProjectMeta,
|
|
18
|
+
SigningConfig,
|
|
19
|
+
SplashConfig,
|
|
20
|
+
SwiftPackageDep,
|
|
21
|
+
WindowsConfig,
|
|
22
|
+
WindowsSigningConfig,
|
|
23
|
+
XcframeworkDep,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"ConfigError",
|
|
28
|
+
"load_config",
|
|
29
|
+
"load_config_from_text",
|
|
30
|
+
"Author",
|
|
31
|
+
"Config",
|
|
32
|
+
"DesktopConfig",
|
|
33
|
+
"IconConfig",
|
|
34
|
+
"IosConfig",
|
|
35
|
+
"KivyMeta",
|
|
36
|
+
"LinuxConfig",
|
|
37
|
+
"MacosConfig",
|
|
38
|
+
"NativeBinaryDep",
|
|
39
|
+
"ProjectMeta",
|
|
40
|
+
"SigningConfig",
|
|
41
|
+
"SplashConfig",
|
|
42
|
+
"SwiftPackageDep",
|
|
43
|
+
"WindowsConfig",
|
|
44
|
+
"WindowsSigningConfig",
|
|
45
|
+
"XcframeworkDep",
|
|
46
|
+
]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Configuration validation errors.
|
|
2
|
+
|
|
3
|
+
Kept free of any CLI/click dependency so the config layer is importable and
|
|
4
|
+
testable in isolation. The CLI converts ``ConfigError`` into a clean
|
|
5
|
+
user-facing message.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ConfigError(Exception):
|
|
12
|
+
"""A semantic or structural problem in ``pyproject.toml``.
|
|
13
|
+
|
|
14
|
+
Carries an optional ``key_path`` (dotted TOML location, e.g.
|
|
15
|
+
``tool.kivy.ios.bundle_id``) and a best-effort ``line`` number so the CLI
|
|
16
|
+
can point the user at the offending spot with a remediation ``hint``.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
message: str,
|
|
22
|
+
*,
|
|
23
|
+
key_path: str | None = None,
|
|
24
|
+
line: int | None = None,
|
|
25
|
+
hint: str | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
self.message = message
|
|
28
|
+
self.key_path = key_path
|
|
29
|
+
self.line = line
|
|
30
|
+
self.hint = hint
|
|
31
|
+
super().__init__(message)
|
|
32
|
+
|
|
33
|
+
def format(self) -> str:
|
|
34
|
+
parts = []
|
|
35
|
+
location = ""
|
|
36
|
+
if self.line is not None:
|
|
37
|
+
location = f" (line {self.line})"
|
|
38
|
+
elif self.key_path is not None:
|
|
39
|
+
location = f" ([{self.key_path}])"
|
|
40
|
+
parts.append(f"{self.message}{location}")
|
|
41
|
+
if self.hint:
|
|
42
|
+
parts.append(f" hint: {self.hint}")
|
|
43
|
+
return "\n".join(parts)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Validate a configured ``[tool.kivy.<platform>.icons].source`` (spec 01).
|
|
2
|
+
|
|
3
|
+
Shared across the iOS, macOS, and Linux backends: the icon source must be an
|
|
4
|
+
existing 1024x1024 PNG. This module only validates the source file; each
|
|
5
|
+
platform decides what to do with it (iOS uses the single-size ``AppIcon``
|
|
6
|
+
catalog entry as-is, macOS/Linux resize into their icon sets).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import struct
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
APP_ICON_SIZE = 1024
|
|
15
|
+
_PNG_SIG = b"\x89PNG\r\n\x1a\n"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class IconSourceError(Exception):
|
|
19
|
+
"""A configured ``[tool.kivy.<platform>.icons].source`` failed validation."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def png_dimensions(path: Path) -> tuple[int, int]:
|
|
23
|
+
"""Read width and height from a PNG IHDR chunk."""
|
|
24
|
+
with path.open("rb") as fh:
|
|
25
|
+
header = fh.read(24)
|
|
26
|
+
if len(header) < 24 or header[:8] != _PNG_SIG:
|
|
27
|
+
raise IconSourceError(f"{path}: not a PNG file (expected 1024x1024 PNG)")
|
|
28
|
+
return struct.unpack(">II", header[16:24])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def validate_icon_source(path: Path) -> None:
|
|
32
|
+
"""Fail fast when the icon path is missing, not PNG, or not 1024x1024."""
|
|
33
|
+
if not path.is_file():
|
|
34
|
+
raise IconSourceError(
|
|
35
|
+
f"app icon not found: {path}\n"
|
|
36
|
+
" [tool.kivy.<platform>.icons].source must point to an existing "
|
|
37
|
+
f"{APP_ICON_SIZE}x{APP_ICON_SIZE} PNG."
|
|
38
|
+
)
|
|
39
|
+
try:
|
|
40
|
+
width, height = png_dimensions(path)
|
|
41
|
+
except IconSourceError:
|
|
42
|
+
raise
|
|
43
|
+
except OSError as exc:
|
|
44
|
+
raise IconSourceError(f"cannot read app icon {path}: {exc}") from exc
|
|
45
|
+
if (width, height) != (APP_ICON_SIZE, APP_ICON_SIZE):
|
|
46
|
+
raise IconSourceError(
|
|
47
|
+
f"app icon {path} is {width}x{height}; "
|
|
48
|
+
f"expected {APP_ICON_SIZE}x{APP_ICON_SIZE} PNG.\n"
|
|
49
|
+
f" Resize the source image to {APP_ICON_SIZE}x{APP_ICON_SIZE} "
|
|
50
|
+
"before building."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def icon_source_problem(path: Path) -> str | None:
|
|
55
|
+
"""Return an error message, or None when the icon source is valid."""
|
|
56
|
+
try:
|
|
57
|
+
validate_icon_source(path)
|
|
58
|
+
except IconSourceError as exc:
|
|
59
|
+
return str(exc)
|
|
60
|
+
return None
|