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,206 @@
|
|
|
1
|
+
"""Parse ``pylock.android.toml`` back into an ``AndroidLockfile`` (android/02).
|
|
2
|
+
|
|
3
|
+
The neutral drift helpers (``LockError``, ``compute_pyproject_sha256``,
|
|
4
|
+
``is_in_sync``) live in ``kivyforge.lock.reader``; this module adds the Android
|
|
5
|
+
``pylock.android.toml`` parsing on top. The reader fails *cleanly* on corrupt,
|
|
6
|
+
hand-edited, or future-schema files — never a raw ``KeyError``.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import tomllib
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from kivyforge.lock.pep751 import parse_package as _parse_package
|
|
15
|
+
from kivyforge.lock.reader import (
|
|
16
|
+
LockError,
|
|
17
|
+
compute_pyproject_sha256,
|
|
18
|
+
is_in_sync,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
from .model import (
|
|
22
|
+
LOCK_VERSION,
|
|
23
|
+
TOOL_SCHEMA_VERSION,
|
|
24
|
+
AndroidLockfile,
|
|
25
|
+
GradleArtifact,
|
|
26
|
+
GradlePins,
|
|
27
|
+
GradleResolvedModule,
|
|
28
|
+
LockedAndroidLib,
|
|
29
|
+
LockedIncludeFile,
|
|
30
|
+
PythonAndroidRuntime,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"LockError",
|
|
35
|
+
"compute_pyproject_sha256",
|
|
36
|
+
"is_in_sync",
|
|
37
|
+
"load",
|
|
38
|
+
"loads",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
SUPPORTED_LOCK_VERSION_MAJOR = int(LOCK_VERSION.split(".", 1)[0])
|
|
42
|
+
SUPPORTED_TOOL_SCHEMA_VERSION = TOOL_SCHEMA_VERSION
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def loads(text: str) -> AndroidLockfile:
|
|
46
|
+
try:
|
|
47
|
+
raw = tomllib.loads(text)
|
|
48
|
+
except tomllib.TOMLDecodeError as exc:
|
|
49
|
+
raise LockError(f"pylock.android.toml is not valid TOML: {exc}") from exc
|
|
50
|
+
if not isinstance(raw, dict):
|
|
51
|
+
raise LockError("pylock.android.toml must be a TOML table.")
|
|
52
|
+
try:
|
|
53
|
+
return _from_raw(raw)
|
|
54
|
+
except LockError:
|
|
55
|
+
raise
|
|
56
|
+
except (KeyError, TypeError, AttributeError, ValueError) as exc:
|
|
57
|
+
raise LockError(f"pylock.android.toml is malformed: {exc!r}") from exc
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def load(path: str | Path) -> AndroidLockfile:
|
|
61
|
+
return loads(Path(path).read_text(encoding="utf-8"))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _from_raw(raw: dict) -> AndroidLockfile:
|
|
65
|
+
lock_version = _check_lock_version(raw)
|
|
66
|
+
|
|
67
|
+
tool_raw = raw.get("tool", {})
|
|
68
|
+
if not isinstance(tool_raw, dict):
|
|
69
|
+
raise LockError("pylock.android.toml [tool] must be a table.")
|
|
70
|
+
tool = tool_raw.get("kivyforge", {})
|
|
71
|
+
if not isinstance(tool, dict) or not tool:
|
|
72
|
+
raise LockError("pylock.android.toml is missing the [tool.kivyforge] table.")
|
|
73
|
+
|
|
74
|
+
schema_version = _check_tool_schema_version(tool)
|
|
75
|
+
|
|
76
|
+
runtimes = tuple(_parse_runtime(r) for r in _as_list(tool, "python_android"))
|
|
77
|
+
if not runtimes:
|
|
78
|
+
raise LockError(
|
|
79
|
+
"pylock.android.toml has no [[tool.kivyforge.python_android]] "
|
|
80
|
+
"entries; re-run `kivyforge lock -p android`."
|
|
81
|
+
)
|
|
82
|
+
packages = tuple(_parse_package(p) for p in _as_list(raw, "packages"))
|
|
83
|
+
android_libs = tuple(_parse_lib(x) for x in _as_list(tool, "android_libs"))
|
|
84
|
+
gradle = _parse_gradle(tool.get("gradle"))
|
|
85
|
+
include_files = tuple(
|
|
86
|
+
_parse_include_file(f) for f in _as_list(tool, "include_files")
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
kivy_generation = tool.get("kivy_generation", 2)
|
|
90
|
+
if kivy_generation not in (2, 3):
|
|
91
|
+
raise LockError(
|
|
92
|
+
f"pylock.android.toml [tool.kivyforge].kivy_generation "
|
|
93
|
+
f"{kivy_generation!r} invalid."
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return AndroidLockfile(
|
|
97
|
+
requires_python=raw.get("requires-python", ">=3.14"),
|
|
98
|
+
packages=packages,
|
|
99
|
+
python_android=runtimes,
|
|
100
|
+
kivyforge_version=tool.get("kivyforge_version", ""),
|
|
101
|
+
generated_at=tool.get("generated_at", ""),
|
|
102
|
+
pyproject_sha256=tool.get("pyproject_sha256", ""),
|
|
103
|
+
tool_kivy_android_schema_version=tool.get(
|
|
104
|
+
"tool_kivy_android_schema_version", 1
|
|
105
|
+
),
|
|
106
|
+
kivy_generation=kivy_generation,
|
|
107
|
+
android_libs=android_libs,
|
|
108
|
+
gradle=gradle,
|
|
109
|
+
include_files=include_files,
|
|
110
|
+
schema_version=schema_version,
|
|
111
|
+
lock_version=lock_version,
|
|
112
|
+
created_by=raw.get("created-by", "kivyforge"),
|
|
113
|
+
extras=tuple(raw.get("extras", [])),
|
|
114
|
+
dependency_groups=tuple(raw.get("dependency-groups", [])),
|
|
115
|
+
default_groups=tuple(raw.get("default-groups", [])),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _parse_runtime(entry: dict) -> PythonAndroidRuntime:
|
|
120
|
+
return PythonAndroidRuntime(
|
|
121
|
+
version=entry["version"],
|
|
122
|
+
abi=entry["abi"],
|
|
123
|
+
url=entry.get("url"),
|
|
124
|
+
path=entry.get("path"),
|
|
125
|
+
sha256=entry["sha256"],
|
|
126
|
+
min_api=int(entry.get("min_api", 24)),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _parse_lib(entry: dict) -> LockedAndroidLib:
|
|
131
|
+
return LockedAndroidLib(
|
|
132
|
+
name=entry["name"],
|
|
133
|
+
kind=entry["kind"],
|
|
134
|
+
version=entry["version"],
|
|
135
|
+
url=entry.get("url"),
|
|
136
|
+
path=entry.get("path"),
|
|
137
|
+
sha256=entry["sha256"],
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _parse_gradle(table: object) -> GradlePins:
|
|
142
|
+
if table is None:
|
|
143
|
+
return GradlePins()
|
|
144
|
+
if not isinstance(table, dict):
|
|
145
|
+
raise LockError("pylock.android.toml [tool.kivyforge.gradle] must be a table.")
|
|
146
|
+
resolved = tuple(
|
|
147
|
+
GradleResolvedModule(
|
|
148
|
+
coordinate=m["coordinate"],
|
|
149
|
+
artifacts=tuple(
|
|
150
|
+
GradleArtifact(name=a["name"], sha256=a["sha256"])
|
|
151
|
+
for a in m.get("artifacts", [])
|
|
152
|
+
),
|
|
153
|
+
)
|
|
154
|
+
for m in table.get("resolved", [])
|
|
155
|
+
)
|
|
156
|
+
return GradlePins(
|
|
157
|
+
dependencies=tuple(table.get("dependencies", [])),
|
|
158
|
+
repositories=tuple(table.get("repositories", [])),
|
|
159
|
+
resolved=resolved,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _parse_include_file(entry: dict) -> LockedIncludeFile:
|
|
164
|
+
return LockedIncludeFile(
|
|
165
|
+
source=entry["source"], dest=entry["dest"], sha256=entry["sha256"]
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _check_lock_version(raw: dict) -> str:
|
|
170
|
+
lock_version = raw.get("lock-version", LOCK_VERSION)
|
|
171
|
+
if not isinstance(lock_version, str):
|
|
172
|
+
raise LockError("pylock.android.toml lock-version must be a string.")
|
|
173
|
+
major = lock_version.split(".", 1)[0]
|
|
174
|
+
if not major.isdigit():
|
|
175
|
+
raise LockError(
|
|
176
|
+
f"pylock.android.toml lock-version {lock_version!r} is not a valid version."
|
|
177
|
+
)
|
|
178
|
+
if int(major) > SUPPORTED_LOCK_VERSION_MAJOR:
|
|
179
|
+
raise LockError(
|
|
180
|
+
f"pylock.android.toml lock-version {lock_version} is newer than "
|
|
181
|
+
f"this kivyforge understands (<= {SUPPORTED_LOCK_VERSION_MAJOR}.x); "
|
|
182
|
+
"upgrade kivyforge."
|
|
183
|
+
)
|
|
184
|
+
return lock_version
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _check_tool_schema_version(tool: dict) -> int:
|
|
188
|
+
schema_version = tool.get("schema_version", TOOL_SCHEMA_VERSION)
|
|
189
|
+
if not isinstance(schema_version, int) or isinstance(schema_version, bool):
|
|
190
|
+
raise LockError(
|
|
191
|
+
"pylock.android.toml [tool.kivyforge].schema_version must be an integer."
|
|
192
|
+
)
|
|
193
|
+
if schema_version > SUPPORTED_TOOL_SCHEMA_VERSION:
|
|
194
|
+
raise LockError(
|
|
195
|
+
f"pylock.android.toml [tool.kivyforge].schema_version "
|
|
196
|
+
f"{schema_version} is newer than this kivyforge understands "
|
|
197
|
+
f"(<= {SUPPORTED_TOOL_SCHEMA_VERSION}); upgrade kivyforge."
|
|
198
|
+
)
|
|
199
|
+
return schema_version
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _as_list(table: dict, key: str) -> list:
|
|
203
|
+
value = table.get(key, [])
|
|
204
|
+
if not isinstance(value, list):
|
|
205
|
+
raise LockError(f"pylock.android.toml {key!r} must be an array of tables.")
|
|
206
|
+
return value
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"""Android dependency resolver (android/02 §"Resolution semantics").
|
|
2
|
+
|
|
3
|
+
Turns ``[project].dependencies`` into fully-pinned per-ABI Android wheels,
|
|
4
|
+
**host-independent**: every compiled package is pinned for every ABI in
|
|
5
|
+
``[tool.kivy.android].abis``, regardless of the host running ``lock``.
|
|
6
|
+
|
|
7
|
+
Host-independence covers *marker evaluation*, not just wheel tags. pip's
|
|
8
|
+
``--platform``/``--abi`` select acceptable tags but leave ``sys_platform`` and
|
|
9
|
+
friends pointing at the machine running pip, which made the same lock succeed
|
|
10
|
+
on Linux and fail on Windows. Resolution therefore runs through
|
|
11
|
+
``_pip_shim.py``, which retargets ``packaging``'s marker environment at Android
|
|
12
|
+
(see ``markers.py``) before handing off to pip.
|
|
13
|
+
|
|
14
|
+
Mirrors the iOS resolver (same pip ``--report`` backend, same fail-fast
|
|
15
|
+
semantics): a package missing any targeted ABI slice is rejected, and a
|
|
16
|
+
version skew across ABIs (one ABI's wheel published before another's) is
|
|
17
|
+
rejected rather than merged. The wheel-tag API level is a floor — pip's
|
|
18
|
+
PEP 738 tag expansion accepts an ``android_21_*`` wheel at ``min_sdk = 24``
|
|
19
|
+
(android/01 §find_links), so kivyforge never re-implements that rule.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import subprocess
|
|
27
|
+
import sys
|
|
28
|
+
import tempfile
|
|
29
|
+
from dataclasses import dataclass, field
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from typing import Protocol
|
|
32
|
+
|
|
33
|
+
from kivyforge.lock import _pip_shim
|
|
34
|
+
from kivyforge.lock._pip_shim import MARKER_ENV_VAR
|
|
35
|
+
from kivyforge.lock.model import canonical_name
|
|
36
|
+
from kivyforge.lock.resolver import (
|
|
37
|
+
MIN_PIP_VERSION,
|
|
38
|
+
abi_tags,
|
|
39
|
+
dep_names_for_environment,
|
|
40
|
+
pip_python_version,
|
|
41
|
+
pip_version,
|
|
42
|
+
version_str,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
from .markers import android_marker_environment
|
|
46
|
+
|
|
47
|
+
# Run by path, not ``-m``: the shim imports nothing from kivyforge, so it also
|
|
48
|
+
# works when resolving with an interpreter that only has pip installed.
|
|
49
|
+
_SHIM = Path(_pip_shim.__file__)
|
|
50
|
+
|
|
51
|
+
# Android wheels: android_<apilevel>_<abi> (PEP 738). pip >= 25.1 understands
|
|
52
|
+
# them (including cross-download); enforce the same floor everywhere.
|
|
53
|
+
MIN_ANDROID_PIP_VERSION = (25, 1)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ResolverError(Exception):
|
|
57
|
+
"""A resolution failure (missing ABI, no matching wheel, backend error)."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass(frozen=True)
|
|
61
|
+
class ResolvedWheel:
|
|
62
|
+
filename: str
|
|
63
|
+
url: str
|
|
64
|
+
sha256: str
|
|
65
|
+
upload_time: str | None = None
|
|
66
|
+
size: int | None = None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class ResolvedPackage:
|
|
71
|
+
name: str
|
|
72
|
+
version: str
|
|
73
|
+
wheels: list[ResolvedWheel] = field(default_factory=list)
|
|
74
|
+
requires_python: str | None = None
|
|
75
|
+
dependencies: list[str] = field(default_factory=list)
|
|
76
|
+
source_index: str | None = None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def abi_platform_tag(min_sdk: int, abi: str) -> str:
|
|
80
|
+
"""The pip ``--platform`` tag for one targeted ABI (android/06 step 4)."""
|
|
81
|
+
return f"android_{min_sdk}_{abi}"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class Resolver(Protocol):
|
|
85
|
+
def resolve(
|
|
86
|
+
self,
|
|
87
|
+
requirements: list[str],
|
|
88
|
+
*,
|
|
89
|
+
python_version: str,
|
|
90
|
+
min_sdk: int,
|
|
91
|
+
abis: tuple[str, ...],
|
|
92
|
+
extra_index_urls: list[str],
|
|
93
|
+
find_links: list[str] | None = None,
|
|
94
|
+
offline: bool = False,
|
|
95
|
+
) -> list[ResolvedPackage]:
|
|
96
|
+
"""Resolve requirements to per-ABI Android wheels (all ABIs pinned)."""
|
|
97
|
+
...
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class PipResolver:
|
|
101
|
+
"""Default backend: stock pip cross-resolution via ``pip install --report``.
|
|
102
|
+
|
|
103
|
+
One dry-run report per targeted ABI; results merge into one
|
|
104
|
+
``ResolvedPackage`` per distribution (pure-Python wheels dedupe by
|
|
105
|
+
filename across ABIs).
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
def __init__(self, python_executable: str | None = None) -> None:
|
|
109
|
+
self._python = python_executable or sys.executable
|
|
110
|
+
|
|
111
|
+
def resolve(
|
|
112
|
+
self,
|
|
113
|
+
requirements: list[str],
|
|
114
|
+
*,
|
|
115
|
+
python_version: str,
|
|
116
|
+
min_sdk: int,
|
|
117
|
+
abis: tuple[str, ...],
|
|
118
|
+
extra_index_urls: list[str],
|
|
119
|
+
find_links: list[str] | None = None,
|
|
120
|
+
offline: bool = False,
|
|
121
|
+
) -> list[ResolvedPackage]:
|
|
122
|
+
if not requirements:
|
|
123
|
+
return []
|
|
124
|
+
self._require_modern_pip()
|
|
125
|
+
cp_abis = abi_tags(python_version)
|
|
126
|
+
merged: dict[str, ResolvedPackage] = {}
|
|
127
|
+
seen_filenames: dict[str, set[str]] = {}
|
|
128
|
+
|
|
129
|
+
for abi in abis:
|
|
130
|
+
# Markers are evaluated for the *target*, per ABI: platform_machine
|
|
131
|
+
# differs between arm64_v8a and x86_64, and packages do gate on it.
|
|
132
|
+
environment = android_marker_environment(
|
|
133
|
+
python_version=python_version, abi=abi
|
|
134
|
+
)
|
|
135
|
+
report = self._run_report(
|
|
136
|
+
requirements,
|
|
137
|
+
python_version=python_version,
|
|
138
|
+
platform_tag=abi_platform_tag(min_sdk, abi),
|
|
139
|
+
abis=cp_abis,
|
|
140
|
+
extra_index_urls=extra_index_urls,
|
|
141
|
+
find_links=find_links or [],
|
|
142
|
+
offline=offline,
|
|
143
|
+
marker_environment=environment,
|
|
144
|
+
)
|
|
145
|
+
for item in report.get("install", []):
|
|
146
|
+
self._absorb(item, merged, seen_filenames, environment)
|
|
147
|
+
|
|
148
|
+
return list(merged.values())
|
|
149
|
+
|
|
150
|
+
def _require_modern_pip(self) -> None:
|
|
151
|
+
version = pip_version(self._python)
|
|
152
|
+
floor = max(MIN_PIP_VERSION, MIN_ANDROID_PIP_VERSION)
|
|
153
|
+
if version is not None and version < floor:
|
|
154
|
+
raise ResolverError(
|
|
155
|
+
f"kivyforge needs pip >= {version_str(floor)} to resolve "
|
|
156
|
+
f"Android wheels, but {self._python} has pip "
|
|
157
|
+
f"{version_str(version)}.\n"
|
|
158
|
+
" pip < 25.1 predates PEP 738 android platform tags, so "
|
|
159
|
+
"compatible wheels (e.g. android_24_*) are reported as missing.\n"
|
|
160
|
+
f" Upgrade it: {self._python} -m pip install --upgrade pip"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def _absorb(self, item, merged, seen_filenames, environment) -> None:
|
|
164
|
+
meta = item.get("metadata", {})
|
|
165
|
+
name = meta.get("name")
|
|
166
|
+
version = meta.get("version")
|
|
167
|
+
download = item.get("download_info", {})
|
|
168
|
+
url = download.get("url", "")
|
|
169
|
+
if not url.endswith(".whl"):
|
|
170
|
+
# sdist/vcs/directory are refused (android/02): wheels only — the
|
|
171
|
+
# backend has no on-host cross-compile step.
|
|
172
|
+
raise ResolverError(
|
|
173
|
+
f"{name} {version} resolved to a non-wheel source ({url}); "
|
|
174
|
+
"kivyforge installs only Android wheels (no from-source "
|
|
175
|
+
"pipeline — build an android_* wheel out-of-band, android/03)."
|
|
176
|
+
)
|
|
177
|
+
archive = download.get("archive_info", {})
|
|
178
|
+
hashes = archive.get("hashes", {})
|
|
179
|
+
sha256 = hashes.get("sha256", "")
|
|
180
|
+
filename = url.rsplit("/", 1)[-1]
|
|
181
|
+
key = canonical_name(name)
|
|
182
|
+
pkg = merged.get(key)
|
|
183
|
+
if pkg is None:
|
|
184
|
+
pkg = ResolvedPackage(
|
|
185
|
+
name=name,
|
|
186
|
+
version=version,
|
|
187
|
+
requires_python=meta.get("requires_python"),
|
|
188
|
+
dependencies=dep_names_for_environment(
|
|
189
|
+
meta.get("requires_dist", []), environment
|
|
190
|
+
),
|
|
191
|
+
)
|
|
192
|
+
merged[key] = pkg
|
|
193
|
+
seen_filenames[key] = set()
|
|
194
|
+
elif version != pkg.version:
|
|
195
|
+
# Each ABI is a separate pip resolution; if upstream published the
|
|
196
|
+
# ABIs at different times they can disagree on version. Merging
|
|
197
|
+
# would produce a lock that installs mismatched binaries per ABI.
|
|
198
|
+
raise ResolverError(
|
|
199
|
+
f"{name} resolved to inconsistent versions across Android ABIs: "
|
|
200
|
+
f"{pkg.version!r} and {version!r}. Re-lock once upstream "
|
|
201
|
+
"publishes the lagging ABI (android/02 fail-fast)."
|
|
202
|
+
)
|
|
203
|
+
if filename not in seen_filenames[key]:
|
|
204
|
+
seen_filenames[key].add(filename)
|
|
205
|
+
pkg.wheels.append(ResolvedWheel(filename=filename, url=url, sha256=sha256))
|
|
206
|
+
|
|
207
|
+
def _run_report(
|
|
208
|
+
self,
|
|
209
|
+
requirements: list[str],
|
|
210
|
+
*,
|
|
211
|
+
python_version: str,
|
|
212
|
+
platform_tag: str,
|
|
213
|
+
abis: tuple[str, ...],
|
|
214
|
+
extra_index_urls: list[str],
|
|
215
|
+
find_links: list[str],
|
|
216
|
+
offline: bool,
|
|
217
|
+
marker_environment: dict[str, str],
|
|
218
|
+
) -> dict:
|
|
219
|
+
with tempfile.TemporaryDirectory(prefix="kivy-lock-") as tmp:
|
|
220
|
+
report_path = Path(tmp) / "report.json"
|
|
221
|
+
# Not "-m pip": the shim retargets marker evaluation at the Android
|
|
222
|
+
# environment first, then runs pip unchanged (see _pip_shim.py).
|
|
223
|
+
cmd = [
|
|
224
|
+
self._python,
|
|
225
|
+
str(_SHIM),
|
|
226
|
+
"install",
|
|
227
|
+
"--dry-run",
|
|
228
|
+
"--ignore-installed",
|
|
229
|
+
"--only-binary=:all:",
|
|
230
|
+
"--python-version",
|
|
231
|
+
pip_python_version(python_version),
|
|
232
|
+
"--implementation",
|
|
233
|
+
"cp",
|
|
234
|
+
"--platform",
|
|
235
|
+
platform_tag,
|
|
236
|
+
"--target",
|
|
237
|
+
str(Path(tmp) / "target"),
|
|
238
|
+
"--report",
|
|
239
|
+
str(report_path),
|
|
240
|
+
]
|
|
241
|
+
for abi in abis:
|
|
242
|
+
cmd += ["--abi", abi]
|
|
243
|
+
for index in extra_index_urls:
|
|
244
|
+
cmd += ["--extra-index-url", index]
|
|
245
|
+
for link in find_links:
|
|
246
|
+
cmd += ["--find-links", link]
|
|
247
|
+
if offline:
|
|
248
|
+
cmd += ["--no-index"]
|
|
249
|
+
cmd += list(requirements)
|
|
250
|
+
|
|
251
|
+
env = dict(os.environ)
|
|
252
|
+
env[MARKER_ENV_VAR] = json.dumps(marker_environment)
|
|
253
|
+
proc = subprocess.run(cmd, capture_output=True, text=True, env=env)
|
|
254
|
+
if proc.returncode != 0:
|
|
255
|
+
raise ResolverError(
|
|
256
|
+
f"pip could not resolve the Android ABI {platform_tag!r}.\n"
|
|
257
|
+
f" This usually means a dependency has no android_* wheel "
|
|
258
|
+
f"for that ABI (vendor one via find_links, android/03).\n"
|
|
259
|
+
f" pip said:\n{_indent(proc.stderr or proc.stdout)}"
|
|
260
|
+
)
|
|
261
|
+
try:
|
|
262
|
+
# pip writes the report as UTF-8; never trust the locale codec
|
|
263
|
+
# (cp1252 on Windows chokes on non-ASCII package metadata).
|
|
264
|
+
return json.loads(report_path.read_text(encoding="utf-8"))
|
|
265
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
266
|
+
raise ResolverError(f"could not read pip report: {exc}") from exc
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def get_resolver(backend: str = "pip", **kwargs) -> Resolver:
|
|
270
|
+
if backend == "pip":
|
|
271
|
+
return PipResolver(**kwargs)
|
|
272
|
+
raise ResolverError(f"unknown resolver backend {backend!r} (expected pip)")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _indent(text: str) -> str:
|
|
276
|
+
return "\n".join(f" {line}" for line in (text or "").splitlines())
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Serialize an ``AndroidLockfile`` to ``pylock.android.toml`` text (android/02).
|
|
2
|
+
|
|
3
|
+
Hand-rolled emitter like the iOS writer: exact PEP 751 layout via the shared
|
|
4
|
+
``kivyforge.lock.pep751`` helpers, deterministic ordering everywhere (packages
|
|
5
|
+
by name/version, wheels by filename, runtimes by ABI, libs by name, resolved
|
|
6
|
+
Maven modules by coordinate) so re-lock diffs show only real changes.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from kivyforge.lock.pep751 import arr as _arr
|
|
12
|
+
from kivyforge.lock.pep751 import emit_package as _emit_package
|
|
13
|
+
from kivyforge.lock.pep751 import s as _s
|
|
14
|
+
|
|
15
|
+
from .model import (
|
|
16
|
+
AndroidLockfile,
|
|
17
|
+
GradleResolvedModule,
|
|
18
|
+
LockedAndroidLib,
|
|
19
|
+
PythonAndroidRuntime,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def dumps(lock: AndroidLockfile) -> str:
|
|
24
|
+
lines: list[str] = []
|
|
25
|
+
|
|
26
|
+
# --- PEP 751 top-level scalars ---
|
|
27
|
+
lines.append(f"lock-version = {_s(lock.lock_version)}")
|
|
28
|
+
lines.append(f"created-by = {_s(lock.created_by)}")
|
|
29
|
+
lines.append(f"requires-python = {_s(lock.requires_python)}")
|
|
30
|
+
lines.append(f"extras = {_arr(lock.extras)}")
|
|
31
|
+
lines.append(f"dependency-groups = {_arr(lock.dependency_groups)}")
|
|
32
|
+
lines.append(f"default-groups = {_arr(lock.default_groups)}")
|
|
33
|
+
lines.append("")
|
|
34
|
+
|
|
35
|
+
# --- [[packages]] (deterministic order) ---
|
|
36
|
+
for pkg in sorted(lock.packages, key=lambda p: p.sort_key):
|
|
37
|
+
_emit_package(lines, pkg)
|
|
38
|
+
|
|
39
|
+
# --- [tool.kivyforge] extension ---
|
|
40
|
+
lines.append("[tool.kivyforge]")
|
|
41
|
+
lines.append(f"schema_version = {lock.schema_version}")
|
|
42
|
+
lines.append(f"kivyforge_version = {_s(lock.kivyforge_version)}")
|
|
43
|
+
lines.append(f"generated_at = {_s(lock.generated_at)}")
|
|
44
|
+
lines.append(f"pyproject_sha256 = {_s(lock.pyproject_sha256)}")
|
|
45
|
+
lines.append(
|
|
46
|
+
f"tool_kivy_android_schema_version = {lock.tool_kivy_android_schema_version}"
|
|
47
|
+
)
|
|
48
|
+
lines.append(f"kivy_generation = {lock.kivy_generation}")
|
|
49
|
+
|
|
50
|
+
# --- [[tool.kivyforge.python_android]] (one per ABI, sorted) ---
|
|
51
|
+
for runtime in sorted(lock.python_android, key=lambda r: r.abi):
|
|
52
|
+
lines.append("")
|
|
53
|
+
_emit_runtime(lines, runtime)
|
|
54
|
+
|
|
55
|
+
# --- [[tool.kivyforge.android_libs]] ---
|
|
56
|
+
for lib in sorted(lock.android_libs, key=lambda x: (x.name.lower(), x.version)):
|
|
57
|
+
lines.append("")
|
|
58
|
+
_emit_android_lib(lines, lib)
|
|
59
|
+
|
|
60
|
+
# --- [tool.kivyforge.gradle] (only when Maven deps are declared) ---
|
|
61
|
+
if lock.gradle.declared:
|
|
62
|
+
lines.append("")
|
|
63
|
+
lines.append("[tool.kivyforge.gradle]")
|
|
64
|
+
lines.append(f"dependencies = {_arr(lock.gradle.dependencies)}")
|
|
65
|
+
lines.append(f"repositories = {_arr(lock.gradle.repositories)}")
|
|
66
|
+
for module in sorted(lock.gradle.resolved, key=lambda m: m.coordinate):
|
|
67
|
+
lines.append("")
|
|
68
|
+
_emit_resolved_module(lines, module)
|
|
69
|
+
|
|
70
|
+
# --- [[tool.kivyforge.include_files]] ---
|
|
71
|
+
for pin in sorted(lock.include_files, key=lambda p: (p.dest, p.source)):
|
|
72
|
+
lines.append("")
|
|
73
|
+
lines.append("[[tool.kivyforge.include_files]]")
|
|
74
|
+
lines.append(f"source = {_s(pin.source)}")
|
|
75
|
+
lines.append(f"dest = {_s(pin.dest)}")
|
|
76
|
+
lines.append(f"sha256 = {_s(pin.sha256)}")
|
|
77
|
+
|
|
78
|
+
return "\n".join(lines) + "\n"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _emit_runtime(lines: list[str], runtime: PythonAndroidRuntime) -> None:
|
|
82
|
+
lines.append("[[tool.kivyforge.python_android]]")
|
|
83
|
+
lines.append(f"version = {_s(runtime.version)}")
|
|
84
|
+
lines.append(f"abi = {_s(runtime.abi)}")
|
|
85
|
+
if runtime.url:
|
|
86
|
+
lines.append(f"url = {_s(runtime.url)}")
|
|
87
|
+
else:
|
|
88
|
+
path = runtime.path
|
|
89
|
+
assert path is not None
|
|
90
|
+
lines.append(f"path = {_s(path)}")
|
|
91
|
+
lines.append(f"sha256 = {_s(runtime.sha256)}")
|
|
92
|
+
lines.append(f"min_api = {runtime.min_api}")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _emit_android_lib(lines: list[str], lib: LockedAndroidLib) -> None:
|
|
96
|
+
lines.append("[[tool.kivyforge.android_libs]]")
|
|
97
|
+
lines.append(f"name = {_s(lib.name)}")
|
|
98
|
+
lines.append(f"kind = {_s(lib.kind)}")
|
|
99
|
+
lines.append(f"version = {_s(lib.version)}")
|
|
100
|
+
if lib.url:
|
|
101
|
+
lines.append(f"url = {_s(lib.url)}")
|
|
102
|
+
else:
|
|
103
|
+
path = lib.path
|
|
104
|
+
assert path is not None
|
|
105
|
+
lines.append(f"path = {_s(path)}")
|
|
106
|
+
lines.append(f"sha256 = {_s(lib.sha256)}")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _emit_resolved_module(lines: list[str], module: GradleResolvedModule) -> None:
|
|
110
|
+
lines.append("[[tool.kivyforge.gradle.resolved]]")
|
|
111
|
+
lines.append(f"coordinate = {_s(module.coordinate)}")
|
|
112
|
+
artifacts = sorted(module.artifacts, key=lambda a: a.name)
|
|
113
|
+
if not artifacts:
|
|
114
|
+
lines.append("artifacts = []")
|
|
115
|
+
return
|
|
116
|
+
lines.append("artifacts = [")
|
|
117
|
+
for artifact in artifacts:
|
|
118
|
+
lines.append(
|
|
119
|
+
f" {{ name = {_s(artifact.name)}, sha256 = {_s(artifact.sha256)} }},"
|
|
120
|
+
)
|
|
121
|
+
lines.append("]")
|