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,716 @@
|
|
|
1
|
+
"""Pure helpers for ``kivyforge init`` (spec 05).
|
|
2
|
+
|
|
3
|
+
Kept side-effect-free (no filesystem, no venv probing) so they can be unit
|
|
4
|
+
tested directly. ``init.py`` orchestrates these with the real environment.
|
|
5
|
+
|
|
6
|
+
Init uses *text surgery* — it only ever adds/replaces
|
|
7
|
+
``[tool.kivy*]`` sections and leaves ``[project]`` and every other namespace
|
|
8
|
+
byte-for-byte intact. We deliberately do not round-trip the whole file through
|
|
9
|
+
a TOML writer (which would drop comments and reorder keys).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import re
|
|
15
|
+
|
|
16
|
+
from packaging.requirements import InvalidRequirement, Requirement
|
|
17
|
+
|
|
18
|
+
from ..config.model import (
|
|
19
|
+
AndroidSigningConfig,
|
|
20
|
+
MacosSigningConfig,
|
|
21
|
+
SigningConfig,
|
|
22
|
+
WindowsSigningConfig,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Default Python.xcframework version init seeds (spec 01).
|
|
26
|
+
DEFAULT_PYTHON_VERSION = "3.15.0b4"
|
|
27
|
+
DEFAULT_DEPLOYMENT_TARGET = "13.0"
|
|
28
|
+
# Default python-build-standalone version seeded for macOS/Linux (desktop
|
|
29
|
+
# targets pin a released runtime, not a beta xcframework).
|
|
30
|
+
DEFAULT_DESKTOP_PYTHON_VERSION = "3.13.14"
|
|
31
|
+
# Default python.org Android embeddable-package version init seeds (android/01;
|
|
32
|
+
# the load-model prototype validated 3.14.6 — android-loadmodel-findings.md).
|
|
33
|
+
DEFAULT_ANDROID_PYTHON_VERSION = "3.14.6"
|
|
34
|
+
|
|
35
|
+
# Exclude block emitted when kivy is a direct dependency. Each entry is
|
|
36
|
+
# documented with the Kivy feature that requires it so users know which lines
|
|
37
|
+
# are safe to remove for their specific app.
|
|
38
|
+
_KIVY_EXCLUDE_LINES = [
|
|
39
|
+
"# Kivy's wheel declares deps that are not needed at runtime for most apps.",
|
|
40
|
+
"# Remove an entry only if your app actually uses that feature.",
|
|
41
|
+
"exclude = [",
|
|
42
|
+
" # kivy-garden: the extension registry / download CLI. Rarely needed at",
|
|
43
|
+
" # runtime (app stores generally prohibit dynamic package installation).",
|
|
44
|
+
" # Individual garden widgets (e.g. kivy-garden.mapview) are separate",
|
|
45
|
+
" # packages — add them to [project].dependencies instead.",
|
|
46
|
+
' "kivy-garden",',
|
|
47
|
+
" # requests and its transitive deps (below) are used by",
|
|
48
|
+
" # kivy.network.urlrequest.UrlRequest *and* by kivy-garden.",
|
|
49
|
+
" # Remove these lines only if your app uses UrlRequest for HTTP calls.",
|
|
50
|
+
' "requests",',
|
|
51
|
+
' "certifi",',
|
|
52
|
+
' "charset-normalizer",',
|
|
53
|
+
' "idna",',
|
|
54
|
+
' "urllib3",',
|
|
55
|
+
" # docutils: required by the RSTDocument widget (kivy.uix.rst).",
|
|
56
|
+
" # Remove this line if your app uses RSTDocument.",
|
|
57
|
+
' "docutils",',
|
|
58
|
+
" # pygments: required by the CodeInput widget (kivy.uix.codeinput).",
|
|
59
|
+
" # Remove this line if your app uses CodeInput.",
|
|
60
|
+
' "pygments",',
|
|
61
|
+
" # NOTE: filetype is imported unconditionally by kivy/core/image/__init__.py",
|
|
62
|
+
" # and cannot be excluded regardless of which widgets you use.",
|
|
63
|
+
"]",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
_TABLE_HEADER = re.compile(r"^\s*\[\[?\s*(?P<key>[^\]]+?)\s*\]\]?\s*(#.*)?$")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def normalize_package_name(raw: str) -> str:
|
|
70
|
+
"""Normalize a directory name into a valid Python package name.
|
|
71
|
+
|
|
72
|
+
Lowercase; hyphens/spaces/dots → underscores; drop other invalid chars;
|
|
73
|
+
ensure it does not start with a digit.
|
|
74
|
+
"""
|
|
75
|
+
name = raw.strip().lower()
|
|
76
|
+
name = re.sub(r"[-\s.]+", "_", name)
|
|
77
|
+
name = re.sub(r"[^a-z0-9_]", "", name)
|
|
78
|
+
name = re.sub(r"_+", "_", name).strip("_")
|
|
79
|
+
if not name:
|
|
80
|
+
name = "app"
|
|
81
|
+
if name[0].isdigit():
|
|
82
|
+
name = f"app_{name}"
|
|
83
|
+
return name
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _canon(name: str) -> str:
|
|
87
|
+
return re.sub(r"[-_.]+", "-", name).lower()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def bundle_id_segment(app_slug: str) -> str:
|
|
91
|
+
"""Convert a Python ``app_slug`` into a valid bundle-identifier segment.
|
|
92
|
+
|
|
93
|
+
Bundle identifiers are UTIs: only alphanumeric, hyphen, and period are
|
|
94
|
+
allowed. ``app_slug`` is a Python package name (underscores are valid
|
|
95
|
+
there) so underscores are mapped to hyphens here.
|
|
96
|
+
"""
|
|
97
|
+
seg = app_slug.replace("_", "-")
|
|
98
|
+
seg = re.sub(r"[^A-Za-z0-9-]", "", seg)
|
|
99
|
+
return seg.strip("-") or "app"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def has_kivy_dep(dependencies: list[str]) -> bool:
|
|
103
|
+
"""Return True if any entry in *dependencies* is the ``kivy`` package."""
|
|
104
|
+
for dep in dependencies:
|
|
105
|
+
try:
|
|
106
|
+
name = Requirement(dep).name
|
|
107
|
+
except InvalidRequirement:
|
|
108
|
+
name = dep.split(";", 1)[0].split("[", 1)[0].strip()
|
|
109
|
+
if _canon(name) == "kivy":
|
|
110
|
+
return True
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def render_kivy_tables(
|
|
115
|
+
app_slug: str,
|
|
116
|
+
signing: SigningConfig | None = None,
|
|
117
|
+
*,
|
|
118
|
+
python_version: str | None = None,
|
|
119
|
+
has_kivy: bool = False,
|
|
120
|
+
simulator_archs: list[str] | tuple[str, ...] | None = None,
|
|
121
|
+
icon_source: str | None = None,
|
|
122
|
+
splash_source: str | None = None,
|
|
123
|
+
splash_background: str | None = None,
|
|
124
|
+
include_shared: bool = True,
|
|
125
|
+
) -> str:
|
|
126
|
+
"""Render the ``[tool.kivy]`` + ``[tool.kivy.ios]`` block.
|
|
127
|
+
|
|
128
|
+
When ``signing`` is provided (the ``--force`` preserve path) its concrete
|
|
129
|
+
values are emitted; otherwise a commented template invites the user to fill
|
|
130
|
+
in ``team_id``. ``python_version`` overrides the default xcframework pin.
|
|
131
|
+
When ``has_kivy`` is True a documented ``exclude`` block is included so
|
|
132
|
+
users know which transitive Kivy deps are safe to drop for their app.
|
|
133
|
+
|
|
134
|
+
``simulator_archs`` / ``icon_source`` / ``splash_source`` /
|
|
135
|
+
``splash_background`` are the user's existing values on the ``--force``
|
|
136
|
+
preserve path: when set, they are emitted as active TOML; when ``None`` (the
|
|
137
|
+
initial-add path, or a value the user never set) a commented TODO stub is
|
|
138
|
+
emitted instead so the build-time default stays in effect.
|
|
139
|
+
|
|
140
|
+
``include_shared`` controls whether the cross-platform ``[tool.kivy]``
|
|
141
|
+
table is emitted. Set it to ``False`` when the project already declares
|
|
142
|
+
``[tool.kivy]`` (e.g. adding iOS alongside an existing macOS/Linux overlay)
|
|
143
|
+
so init never emits a second, TOML-invalidating ``[tool.kivy]`` table.
|
|
144
|
+
"""
|
|
145
|
+
display = app_slug.replace("_", " ").title()
|
|
146
|
+
if simulator_archs is not None:
|
|
147
|
+
archs_toml = ", ".join(f'"{a}"' for a in simulator_archs)
|
|
148
|
+
sim_line = f"simulator_archs = [{archs_toml}]"
|
|
149
|
+
else:
|
|
150
|
+
sim_line = '# simulator_archs = ["arm64"] # the only supported slice (default)'
|
|
151
|
+
lines: list[str] = []
|
|
152
|
+
if include_shared:
|
|
153
|
+
lines += [
|
|
154
|
+
"[tool.kivy]",
|
|
155
|
+
f'display_name = "{display}"',
|
|
156
|
+
'app_dir = "src"',
|
|
157
|
+
'entry_point = "main"',
|
|
158
|
+
'orientation = ["portrait"]',
|
|
159
|
+
"",
|
|
160
|
+
]
|
|
161
|
+
lines += [
|
|
162
|
+
"[tool.kivy.ios]",
|
|
163
|
+
"schema_version = 1",
|
|
164
|
+
f'bundle_id = "org.example.{bundle_id_segment(app_slug)}" '
|
|
165
|
+
"# TODO: change to your reverse-DNS bundle identifier",
|
|
166
|
+
"build = 1",
|
|
167
|
+
f'deployment_target = "{DEFAULT_DEPLOYMENT_TARGET}"',
|
|
168
|
+
sim_line,
|
|
169
|
+
]
|
|
170
|
+
if has_kivy:
|
|
171
|
+
lines += [""] + _KIVY_EXCLUDE_LINES
|
|
172
|
+
if icon_source is not None:
|
|
173
|
+
icon_lines = [f'source = "{icon_source}"']
|
|
174
|
+
else:
|
|
175
|
+
icon_lines = [
|
|
176
|
+
'# source = "assets/icon.png" '
|
|
177
|
+
"# TODO: 1024x1024 PNG app icon — required for App Store submission"
|
|
178
|
+
]
|
|
179
|
+
if splash_source is not None:
|
|
180
|
+
splash_lines = [f'source = "{splash_source}"']
|
|
181
|
+
else:
|
|
182
|
+
splash_lines = ['# source = "assets/splash.png" # TODO: optional launch image']
|
|
183
|
+
if splash_background is not None:
|
|
184
|
+
splash_lines.append(f'background = "{splash_background}"')
|
|
185
|
+
else:
|
|
186
|
+
splash_lines.append(
|
|
187
|
+
'# background = "#000000" '
|
|
188
|
+
"# TODO: optional launch-screen background color"
|
|
189
|
+
)
|
|
190
|
+
lines += [
|
|
191
|
+
"",
|
|
192
|
+
"[tool.kivy.ios.python]",
|
|
193
|
+
f'version = "{python_version or DEFAULT_PYTHON_VERSION}"',
|
|
194
|
+
"",
|
|
195
|
+
"[tool.kivy.ios.icons]",
|
|
196
|
+
*icon_lines,
|
|
197
|
+
"",
|
|
198
|
+
"[tool.kivy.ios.splash]",
|
|
199
|
+
*splash_lines,
|
|
200
|
+
"",
|
|
201
|
+
"[tool.kivy.ios.signing]",
|
|
202
|
+
]
|
|
203
|
+
if signing is not None:
|
|
204
|
+
lines += [
|
|
205
|
+
f'team_id = "{signing.team_id}"',
|
|
206
|
+
f'identity = "{signing.identity}"',
|
|
207
|
+
f'provisioning_profile = "{signing.provisioning_profile}"',
|
|
208
|
+
f"auto_signing = {str(signing.auto_signing).lower()}",
|
|
209
|
+
f"upload_symbols = {str(signing.upload_symbols).lower()}",
|
|
210
|
+
]
|
|
211
|
+
else:
|
|
212
|
+
lines += [
|
|
213
|
+
'# team_id = "ABCDE12345" '
|
|
214
|
+
"# TODO: set your Apple Developer Team ID for device/release builds",
|
|
215
|
+
"auto_signing = true",
|
|
216
|
+
]
|
|
217
|
+
lines += _SWIFT_PACKAGES_STUB
|
|
218
|
+
return "\n".join(lines) + "\n"
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# Commented native-dependency stub. Left inert so a vanilla app needs no Swift
|
|
222
|
+
# toolchain; uncomment to pull in an SPM package (resolved + embedded by Xcode).
|
|
223
|
+
_SWIFT_PACKAGES_STUB = [
|
|
224
|
+
"",
|
|
225
|
+
"# Optional: native Swift Package Manager dependencies (spec 07). Xcode resolves,",
|
|
226
|
+
"# builds, and embeds these; `kivyforge lock` pins each to a commit.",
|
|
227
|
+
"# [tool.kivy.ios.native.swift_packages]",
|
|
228
|
+
'# Sentry = { url = "https://github.com/getsentry/sentry-cocoa", '
|
|
229
|
+
'requirement = { from = "8.49.0" }, products = ["Sentry"] }',
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def has_kivyforge_table(text: str) -> bool:
|
|
234
|
+
"""True if the text already declares a [tool.kivy.ios] table."""
|
|
235
|
+
return has_platform_overlay(text, "ios")
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def has_shared_table(text: str) -> bool:
|
|
239
|
+
"""True if the text already declares the bare, cross-platform [tool.kivy] table."""
|
|
240
|
+
return "tool.kivy" in _section_keys(text)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def has_platform_overlay(text: str, platform: str) -> bool:
|
|
244
|
+
"""True if the text already declares [tool.kivy.<platform>] (or a sub-table)."""
|
|
245
|
+
prefix = f"tool.kivy.{platform}"
|
|
246
|
+
keys = _section_keys(text)
|
|
247
|
+
return prefix in keys or any(k.startswith(f"{prefix}.") for k in keys)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _section_keys(text: str) -> set[str]:
|
|
251
|
+
keys: set[str] = set()
|
|
252
|
+
for line in text.splitlines():
|
|
253
|
+
m = _TABLE_HEADER.match(line)
|
|
254
|
+
if m:
|
|
255
|
+
keys.add(m.group("key").strip())
|
|
256
|
+
return keys
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def strip_kivy_tables(text: str) -> str:
|
|
260
|
+
"""Remove every ``[tool.kivy]`` / ``[tool.kivy.*]`` section from the text.
|
|
261
|
+
|
|
262
|
+
Used by ``--force`` before re-appending freshly rendered tables. Non-kivy
|
|
263
|
+
sections (including ``[project]`` and other tool namespaces) are preserved
|
|
264
|
+
verbatim.
|
|
265
|
+
"""
|
|
266
|
+
lines = text.splitlines(keepends=True)
|
|
267
|
+
out: list[str] = []
|
|
268
|
+
dropping = False
|
|
269
|
+
for line in lines:
|
|
270
|
+
m = _TABLE_HEADER.match(line.rstrip("\n"))
|
|
271
|
+
if m:
|
|
272
|
+
key = m.group("key").strip()
|
|
273
|
+
dropping = key == "tool.kivy" or key.startswith("tool.kivy.")
|
|
274
|
+
if dropping:
|
|
275
|
+
continue
|
|
276
|
+
if dropping:
|
|
277
|
+
continue
|
|
278
|
+
out.append(line)
|
|
279
|
+
result = "".join(out).rstrip("\n")
|
|
280
|
+
return result + "\n" if result else ""
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def strip_platform_tables(text: str, platform: str) -> str:
|
|
284
|
+
"""Remove only ``[tool.kivy.<platform>]`` and its sub-tables.
|
|
285
|
+
|
|
286
|
+
Unlike :func:`strip_kivy_tables` (which drops the shared ``[tool.kivy]``
|
|
287
|
+
table too, safe only when there is exactly one platform), this preserves
|
|
288
|
+
``[tool.kivy]`` and every *other* platform's overlay — required so
|
|
289
|
+
regenerating one platform's overlay (``init --force -p macos``) in a
|
|
290
|
+
multi-platform ``pyproject.toml`` never touches iOS/Linux's tables.
|
|
291
|
+
"""
|
|
292
|
+
prefix = f"tool.kivy.{platform}"
|
|
293
|
+
lines = text.splitlines(keepends=True)
|
|
294
|
+
out: list[str] = []
|
|
295
|
+
dropping = False
|
|
296
|
+
for line in lines:
|
|
297
|
+
m = _TABLE_HEADER.match(line.rstrip("\n"))
|
|
298
|
+
if m:
|
|
299
|
+
key = m.group("key").strip()
|
|
300
|
+
dropping = key == prefix or key.startswith(prefix + ".")
|
|
301
|
+
if dropping:
|
|
302
|
+
continue
|
|
303
|
+
if dropping:
|
|
304
|
+
continue
|
|
305
|
+
out.append(line)
|
|
306
|
+
result = "".join(out).rstrip("\n")
|
|
307
|
+
return result + "\n" if result else ""
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def append_kivy_tables(
|
|
311
|
+
text: str,
|
|
312
|
+
app_slug: str,
|
|
313
|
+
signing: SigningConfig | None = None,
|
|
314
|
+
*,
|
|
315
|
+
python_version: str | None = None,
|
|
316
|
+
has_kivy: bool = False,
|
|
317
|
+
simulator_archs: list[str] | tuple[str, ...] | None = None,
|
|
318
|
+
icon_source: str | None = None,
|
|
319
|
+
splash_source: str | None = None,
|
|
320
|
+
splash_background: str | None = None,
|
|
321
|
+
include_shared: bool = True,
|
|
322
|
+
) -> str:
|
|
323
|
+
"""Append freshly rendered kivy tables to existing pyproject text."""
|
|
324
|
+
block = render_kivy_tables(
|
|
325
|
+
app_slug,
|
|
326
|
+
signing,
|
|
327
|
+
python_version=python_version,
|
|
328
|
+
has_kivy=has_kivy,
|
|
329
|
+
simulator_archs=simulator_archs,
|
|
330
|
+
icon_source=icon_source,
|
|
331
|
+
splash_source=splash_source,
|
|
332
|
+
splash_background=splash_background,
|
|
333
|
+
include_shared=include_shared,
|
|
334
|
+
)
|
|
335
|
+
return append_block(text, block)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def append_block(text: str, block: str) -> str:
|
|
339
|
+
"""Append a rendered ``[tool.kivy*]`` block to existing pyproject text."""
|
|
340
|
+
base = text.rstrip("\n")
|
|
341
|
+
if not base:
|
|
342
|
+
return block
|
|
343
|
+
return f"{base}\n\n{block}"
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
# --------------------------------------------------------------------------- #
|
|
347
|
+
# macOS / Linux overlays — same text-surgery approach as iOS above.
|
|
348
|
+
# --------------------------------------------------------------------------- #
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def render_macos_tables(
|
|
352
|
+
app_slug: str,
|
|
353
|
+
signing: MacosSigningConfig | None = None,
|
|
354
|
+
*,
|
|
355
|
+
python_version: str | None = None,
|
|
356
|
+
has_kivy: bool = False,
|
|
357
|
+
archs: list[str] | tuple[str, ...] | None = None,
|
|
358
|
+
icon_source: str | None = None,
|
|
359
|
+
include_shared: bool = True,
|
|
360
|
+
) -> str:
|
|
361
|
+
"""Render the ``[tool.kivy]`` (optional) + ``[tool.kivy.macos]`` block."""
|
|
362
|
+
display = app_slug.replace("_", " ").title()
|
|
363
|
+
if archs is not None:
|
|
364
|
+
archs_toml = ", ".join(f'"{a}"' for a in archs)
|
|
365
|
+
archs_line = f"archs = [{archs_toml}]"
|
|
366
|
+
else:
|
|
367
|
+
archs_line = 'archs = ["arm64"] # the only supported macOS arch'
|
|
368
|
+
lines: list[str] = []
|
|
369
|
+
if include_shared:
|
|
370
|
+
lines += [
|
|
371
|
+
"[tool.kivy]",
|
|
372
|
+
f'display_name = "{display}"',
|
|
373
|
+
'app_dir = "src"',
|
|
374
|
+
'entry_point = "main"',
|
|
375
|
+
'orientation = ["portrait"]',
|
|
376
|
+
"",
|
|
377
|
+
]
|
|
378
|
+
lines += [
|
|
379
|
+
"[tool.kivy.macos]",
|
|
380
|
+
"schema_version = 1",
|
|
381
|
+
f'bundle_id = "org.example.{bundle_id_segment(app_slug)}" '
|
|
382
|
+
"# TODO: change to your reverse-DNS bundle identifier",
|
|
383
|
+
"build = 1",
|
|
384
|
+
archs_line,
|
|
385
|
+
]
|
|
386
|
+
if has_kivy:
|
|
387
|
+
lines += [""] + _KIVY_EXCLUDE_LINES
|
|
388
|
+
if icon_source is not None:
|
|
389
|
+
icon_lines = [f'source = "{icon_source}"']
|
|
390
|
+
else:
|
|
391
|
+
icon_lines = [
|
|
392
|
+
'# source = "assets/icon.png" '
|
|
393
|
+
"# TODO: 1024x1024 PNG app icon (rendered to .icns)"
|
|
394
|
+
]
|
|
395
|
+
lines += [
|
|
396
|
+
"",
|
|
397
|
+
"[tool.kivy.macos.python]",
|
|
398
|
+
f'version = "{python_version or DEFAULT_DESKTOP_PYTHON_VERSION}"',
|
|
399
|
+
"",
|
|
400
|
+
"[tool.kivy.macos.icons]",
|
|
401
|
+
*icon_lines,
|
|
402
|
+
"",
|
|
403
|
+
"[tool.kivy.macos.signing]",
|
|
404
|
+
]
|
|
405
|
+
if signing is not None and signing.identity:
|
|
406
|
+
lines.append(f'identity = "{signing.identity}"')
|
|
407
|
+
if signing.team_id:
|
|
408
|
+
lines.append(f'team_id = "{signing.team_id}"')
|
|
409
|
+
if signing.notary_profile:
|
|
410
|
+
lines.append(f'notary_profile = "{signing.notary_profile}"')
|
|
411
|
+
else:
|
|
412
|
+
lines += [
|
|
413
|
+
'# identity = "Developer ID Application: Your Name (TEAMID1234)" '
|
|
414
|
+
"# TODO: set for Gatekeeper-trusted distribution (ad-hoc signing is "
|
|
415
|
+
"the default without it)",
|
|
416
|
+
'# notary_profile = "kivyforge-notary" '
|
|
417
|
+
"# TODO: `xcrun notarytool store-credentials` profile name",
|
|
418
|
+
]
|
|
419
|
+
lines += _MACOS_NATIVE_BINARIES_STUB
|
|
420
|
+
return "\n".join(lines) + "\n"
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
# Commented native-binary stub. Left inert so a vanilla app needs no extra
|
|
424
|
+
# artifacts; uncomment to stage a non-wheel dylib/helper (SHA-256-pinned by
|
|
425
|
+
# `kivyforge lock`, staged into Contents/Resources/bin, and covered by the
|
|
426
|
+
# signing sweep).
|
|
427
|
+
_MACOS_NATIVE_BINARIES_STUB = [
|
|
428
|
+
"",
|
|
429
|
+
"# Optional: non-wheel native binaries (macos-spec). Each is pinned by",
|
|
430
|
+
"# `kivyforge lock` and staged into the app's bin directory (on PATH at",
|
|
431
|
+
"# runtime; load dylibs by absolute path via Path(sys.prefix).parent / 'bin').",
|
|
432
|
+
"# [tool.kivy.macos.native.binaries]",
|
|
433
|
+
'# ffmpeg = { version = "7.1", source = "https://example.com/ffmpeg-macos-universal2.zip" }',
|
|
434
|
+
'# libgreet = { version = "0.1.0", source = "binaries/macos/libgreet.dylib" }',
|
|
435
|
+
]
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def render_linux_tables(
|
|
439
|
+
app_slug: str,
|
|
440
|
+
*,
|
|
441
|
+
python_version: str | None = None,
|
|
442
|
+
has_kivy: bool = False,
|
|
443
|
+
archs: list[str] | tuple[str, ...] | None = None,
|
|
444
|
+
icon_source: str | None = None,
|
|
445
|
+
categories: list[str] | tuple[str, ...] | None = None,
|
|
446
|
+
include_shared: bool = True,
|
|
447
|
+
) -> str:
|
|
448
|
+
"""Render the ``[tool.kivy]`` (optional) + ``[tool.kivy.linux]`` block."""
|
|
449
|
+
display = app_slug.replace("_", " ").title()
|
|
450
|
+
if archs is not None:
|
|
451
|
+
archs_toml = ", ".join(f'"{a}"' for a in archs)
|
|
452
|
+
archs_line = f"archs = [{archs_toml}]"
|
|
453
|
+
else:
|
|
454
|
+
archs_line = 'archs = ["x86_64"]'
|
|
455
|
+
lines: list[str] = []
|
|
456
|
+
if include_shared:
|
|
457
|
+
lines += [
|
|
458
|
+
"[tool.kivy]",
|
|
459
|
+
f'display_name = "{display}"',
|
|
460
|
+
'app_dir = "src"',
|
|
461
|
+
'entry_point = "main"',
|
|
462
|
+
'orientation = ["portrait"]',
|
|
463
|
+
"",
|
|
464
|
+
]
|
|
465
|
+
lines += [
|
|
466
|
+
"[tool.kivy.linux]",
|
|
467
|
+
"schema_version = 1",
|
|
468
|
+
f'app_id = "org.example.{bundle_id_segment(app_slug)}" '
|
|
469
|
+
"# TODO: change to your reverse-DNS app id",
|
|
470
|
+
archs_line,
|
|
471
|
+
]
|
|
472
|
+
if has_kivy:
|
|
473
|
+
lines += [""] + _KIVY_EXCLUDE_LINES
|
|
474
|
+
if icon_source is not None:
|
|
475
|
+
icon_lines = [f'source = "{icon_source}"']
|
|
476
|
+
else:
|
|
477
|
+
icon_lines = [
|
|
478
|
+
'# source = "assets/icon.png" '
|
|
479
|
+
"# TODO: 1024x1024 PNG app icon (resized into the hicolor set)"
|
|
480
|
+
]
|
|
481
|
+
if categories is not None:
|
|
482
|
+
cats_toml = ", ".join(f'"{c}"' for c in categories)
|
|
483
|
+
cats_line = f"categories = [{cats_toml}]"
|
|
484
|
+
else:
|
|
485
|
+
cats_line = 'categories = ["Utility"]'
|
|
486
|
+
lines += [
|
|
487
|
+
"",
|
|
488
|
+
"[tool.kivy.linux.python]",
|
|
489
|
+
f'version = "{python_version or DEFAULT_DESKTOP_PYTHON_VERSION}"',
|
|
490
|
+
"",
|
|
491
|
+
"[tool.kivy.linux.icons]",
|
|
492
|
+
*icon_lines,
|
|
493
|
+
"",
|
|
494
|
+
"[tool.kivy.linux.desktop]",
|
|
495
|
+
cats_line,
|
|
496
|
+
]
|
|
497
|
+
lines += _LINUX_NATIVE_BINARIES_STUB
|
|
498
|
+
return "\n".join(lines) + "\n"
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
# Commented native-binary stub. Left inert so a vanilla app needs no extra
|
|
502
|
+
# artifacts; uncomment to stage a non-wheel .so/helper (SHA-256-pinned by
|
|
503
|
+
# `kivyforge lock`, staged into usr/bin). At runtime helpers resolve by name on
|
|
504
|
+
# PATH; libraries load by soname (ctypes.CDLL("libgreet.so")) via the appended
|
|
505
|
+
# LD_LIBRARY_PATH. Both .zip and .tar.gz/.tgz archive sources are extracted.
|
|
506
|
+
_LINUX_NATIVE_BINARIES_STUB = [
|
|
507
|
+
"",
|
|
508
|
+
"# Optional: non-wheel native binaries (linux-spec). Each is pinned by",
|
|
509
|
+
"# `kivyforge lock` and staged into the AppDir's usr/bin (helpers on PATH by",
|
|
510
|
+
"# name; libraries load by soname, e.g. ctypes.CDLL('libgreet.so')).",
|
|
511
|
+
"# [tool.kivy.linux.native.binaries]",
|
|
512
|
+
'# ffmpeg = { version = "7.1", source = "https://example.com/ffmpeg-linux-x86_64.tar.gz" }',
|
|
513
|
+
'# libgreet = { version = "0.1.0", source = "binaries/linux/libgreet.so" }',
|
|
514
|
+
]
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
def _windows_app_id(app_slug: str) -> str:
|
|
518
|
+
"""A Pascal-cased, period-delimited AppUserModelID stub (the good-style form)."""
|
|
519
|
+
pascal = app_slug.replace("_", " ").title().replace(" ", "") or "MyApp"
|
|
520
|
+
return f"Example.{pascal}"
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
def render_windows_tables(
|
|
524
|
+
app_slug: str,
|
|
525
|
+
signing: WindowsSigningConfig | None = None,
|
|
526
|
+
*,
|
|
527
|
+
python_version: str | None = None,
|
|
528
|
+
has_kivy: bool = False,
|
|
529
|
+
archs: list[str] | tuple[str, ...] | None = None,
|
|
530
|
+
icon_source: str | None = None,
|
|
531
|
+
include_shared: bool = True,
|
|
532
|
+
) -> str:
|
|
533
|
+
"""Render the ``[tool.kivy]`` (optional) + ``[tool.kivy.windows]`` block."""
|
|
534
|
+
display = app_slug.replace("_", " ").title()
|
|
535
|
+
if archs is not None:
|
|
536
|
+
archs_toml = ", ".join(f'"{a}"' for a in archs)
|
|
537
|
+
archs_line = f"archs = [{archs_toml}]"
|
|
538
|
+
else:
|
|
539
|
+
archs_line = 'archs = ["amd64"]'
|
|
540
|
+
lines: list[str] = []
|
|
541
|
+
if include_shared:
|
|
542
|
+
lines += [
|
|
543
|
+
"[tool.kivy]",
|
|
544
|
+
f'display_name = "{display}"',
|
|
545
|
+
'app_dir = "src"',
|
|
546
|
+
'entry_point = "main"',
|
|
547
|
+
'orientation = ["portrait"]',
|
|
548
|
+
"",
|
|
549
|
+
]
|
|
550
|
+
lines += [
|
|
551
|
+
"[tool.kivy.windows]",
|
|
552
|
+
"schema_version = 1",
|
|
553
|
+
f'app_id = "{_windows_app_id(app_slug)}" '
|
|
554
|
+
"# TODO: your AppUserModelID (no spaces, <=128 chars)",
|
|
555
|
+
archs_line,
|
|
556
|
+
]
|
|
557
|
+
if has_kivy:
|
|
558
|
+
lines += [""] + _KIVY_EXCLUDE_LINES
|
|
559
|
+
if icon_source is not None:
|
|
560
|
+
icon_lines = [f'source = "{icon_source}"']
|
|
561
|
+
else:
|
|
562
|
+
icon_lines = [
|
|
563
|
+
'# source = "assets/icon.png" '
|
|
564
|
+
"# TODO: 1024x1024 PNG app icon (rendered to a multi-size .ico)"
|
|
565
|
+
]
|
|
566
|
+
lines += [
|
|
567
|
+
"",
|
|
568
|
+
"[tool.kivy.windows.python]",
|
|
569
|
+
f'version = "{python_version or DEFAULT_DESKTOP_PYTHON_VERSION}"',
|
|
570
|
+
"",
|
|
571
|
+
"[tool.kivy.windows.icons]",
|
|
572
|
+
*icon_lines,
|
|
573
|
+
"",
|
|
574
|
+
"[tool.kivy.windows.signing]",
|
|
575
|
+
]
|
|
576
|
+
if signing is not None and signing.thumbprint:
|
|
577
|
+
lines.append(f'thumbprint = "{signing.thumbprint}"')
|
|
578
|
+
if signing.timestamp_url:
|
|
579
|
+
lines.append(f'timestamp_url = "{signing.timestamp_url}"')
|
|
580
|
+
if signing.store_scope:
|
|
581
|
+
lines.append(f'store_scope = "{signing.store_scope}"')
|
|
582
|
+
else:
|
|
583
|
+
lines += [
|
|
584
|
+
'# thumbprint = "AB12CD34...EF" '
|
|
585
|
+
"# TODO: code-signing cert thumbprint (artifact is unsigned without it)",
|
|
586
|
+
'# timestamp_url = "http://timestamp.digicert.com"',
|
|
587
|
+
'# store_scope = "current_user" # or "machine" (adds signtool /sm)',
|
|
588
|
+
]
|
|
589
|
+
lines += _WINDOWS_NATIVE_BINARIES_STUB
|
|
590
|
+
return "\n".join(lines) + "\n"
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def render_android_tables(
|
|
594
|
+
app_slug: str,
|
|
595
|
+
signing: AndroidSigningConfig | None = None,
|
|
596
|
+
*,
|
|
597
|
+
python_version: str | None = None,
|
|
598
|
+
has_kivy: bool = False,
|
|
599
|
+
package: str | None = None,
|
|
600
|
+
abis: list[str] | tuple[str, ...] | None = None,
|
|
601
|
+
kivy_generation: int | None = None,
|
|
602
|
+
icon_source: str | None = None,
|
|
603
|
+
splash_source: str | None = None,
|
|
604
|
+
splash_background: str | None = None,
|
|
605
|
+
include_shared: bool = True,
|
|
606
|
+
) -> str:
|
|
607
|
+
"""Render the ``[tool.kivy]`` (optional) + ``[tool.kivy.android]`` block.
|
|
608
|
+
|
|
609
|
+
Seeds per android/06 §init: ``package = "org.example.<slug>"`` with a
|
|
610
|
+
change-me comment, ``min_sdk = 24``, the latest known target/compile SDK,
|
|
611
|
+
both 64-bit ABIs, ``INTERNET`` as an ordinary editable permission, and
|
|
612
|
+
commented TODO stubs for icons/splash/signing/find_links. On ``--force``
|
|
613
|
+
the caller passes the preserved values (package, abis, kivy_generation,
|
|
614
|
+
python, icon/splash sources, signing).
|
|
615
|
+
"""
|
|
616
|
+
display = app_slug.replace("_", " ").title()
|
|
617
|
+
if abis is not None:
|
|
618
|
+
abis_toml = ", ".join(f'"{a}"' for a in abis)
|
|
619
|
+
abis_line = f"abis = [{abis_toml}]"
|
|
620
|
+
else:
|
|
621
|
+
abis_line = 'abis = ["arm64_v8a", "x86_64"]'
|
|
622
|
+
package_line = (
|
|
623
|
+
f'package = "{package}"'
|
|
624
|
+
if package
|
|
625
|
+
else f'package = "org.example.{app_slug}" '
|
|
626
|
+
"# TODO: your applicationId (reverse-DNS)"
|
|
627
|
+
)
|
|
628
|
+
lines: list[str] = []
|
|
629
|
+
if include_shared:
|
|
630
|
+
lines += [
|
|
631
|
+
"[tool.kivy]",
|
|
632
|
+
f'display_name = "{display}"',
|
|
633
|
+
'app_dir = "src"',
|
|
634
|
+
'entry_point = "main"',
|
|
635
|
+
'orientation = ["portrait"]',
|
|
636
|
+
"",
|
|
637
|
+
]
|
|
638
|
+
lines += [
|
|
639
|
+
"[tool.kivy.android]",
|
|
640
|
+
"schema_version = 1",
|
|
641
|
+
package_line,
|
|
642
|
+
'version_code = 1 # or "auto" to derive from [project].version (android/01)',
|
|
643
|
+
"min_sdk = 24",
|
|
644
|
+
"target_sdk = 35",
|
|
645
|
+
f"kivy_generation = {kivy_generation if kivy_generation is not None else 2} "
|
|
646
|
+
"# 2 = Kivy 2.3.1 (SDL2); 3 = Kivy 3.0 (SDL3)",
|
|
647
|
+
abis_line,
|
|
648
|
+
'# find_links = ["wheels"] '
|
|
649
|
+
"# TODO: a local wheelhouse, for wheels you cross-build yourself",
|
|
650
|
+
"# extra_index_urls = "
|
|
651
|
+
'["https://elliotgarbus.github.io/kivy-mobile-wheels/simple/"] '
|
|
652
|
+
"# TODO: the first-party kivy/pyjnius android wheels, until they are on PyPI",
|
|
653
|
+
]
|
|
654
|
+
if has_kivy:
|
|
655
|
+
lines += [""] + _KIVY_EXCLUDE_LINES
|
|
656
|
+
lines += [
|
|
657
|
+
"",
|
|
658
|
+
"[tool.kivy.android.python]",
|
|
659
|
+
f'version = "{python_version or DEFAULT_ANDROID_PYTHON_VERSION}"',
|
|
660
|
+
"",
|
|
661
|
+
"[tool.kivy.android.permissions]",
|
|
662
|
+
'uses = ["INTERNET"] # ordinary editable entry; delete it if unwanted',
|
|
663
|
+
"",
|
|
664
|
+
"[tool.kivy.android.icons]",
|
|
665
|
+
]
|
|
666
|
+
if icon_source is not None:
|
|
667
|
+
lines.append(f'source = "{icon_source}"')
|
|
668
|
+
else:
|
|
669
|
+
lines.append(
|
|
670
|
+
'# source = "assets/icon.png" '
|
|
671
|
+
"# TODO: 1024x1024 PNG (adaptive-icon foreground)"
|
|
672
|
+
)
|
|
673
|
+
lines += ["", "[tool.kivy.android.splash]"]
|
|
674
|
+
if splash_source is not None:
|
|
675
|
+
lines.append(f'source = "{splash_source}"')
|
|
676
|
+
if splash_background is not None:
|
|
677
|
+
lines.append(f'background = "{splash_background}"')
|
|
678
|
+
else:
|
|
679
|
+
lines += [
|
|
680
|
+
'# source = "assets/splash.png" '
|
|
681
|
+
"# TODO: centered splash icon (PNG or AnimatedVectorDrawable XML)",
|
|
682
|
+
'# background = "#000000"',
|
|
683
|
+
]
|
|
684
|
+
lines += ["", "[tool.kivy.android.signing]"]
|
|
685
|
+
if signing is not None and signing.keystore:
|
|
686
|
+
lines.append(f'keystore = "{signing.keystore}"')
|
|
687
|
+
lines.append(f'key_alias = "{signing.key_alias}"')
|
|
688
|
+
if signing.store_password_env != "KIVYFORGE_KEYSTORE_PASSWORD":
|
|
689
|
+
lines.append(f'store_password_env = "{signing.store_password_env}"')
|
|
690
|
+
if signing.key_password_env != "KIVYFORGE_KEY_PASSWORD":
|
|
691
|
+
lines.append(f'key_password_env = "{signing.key_password_env}"')
|
|
692
|
+
else:
|
|
693
|
+
lines += [
|
|
694
|
+
'# keystore = "release.keystore" '
|
|
695
|
+
"# TODO: release keystore (debug builds need none)",
|
|
696
|
+
'# key_alias = "upload"',
|
|
697
|
+
"# passwords come from KIVYFORGE_KEYSTORE_PASSWORD / "
|
|
698
|
+
"KIVYFORGE_KEY_PASSWORD",
|
|
699
|
+
]
|
|
700
|
+
return "\n".join(lines) + "\n"
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
# Commented native-binary stub. Left inert so a vanilla app needs no extra
|
|
704
|
+
# artifacts; uncomment to stage a non-wheel .dll/helper .exe (SHA-256-pinned by
|
|
705
|
+
# `kivyforge lock`, staged into the bundle's bin\ directory). At runtime helpers
|
|
706
|
+
# resolve by name on PATH; DLLs load by name (ctypes.WinDLL("sdk.dll")) via the
|
|
707
|
+
# add_dll_directory-registered bin\. Both .zip and .tar.gz/.tgz sources extract.
|
|
708
|
+
_WINDOWS_NATIVE_BINARIES_STUB = [
|
|
709
|
+
"",
|
|
710
|
+
"# Optional: non-wheel native binaries (windows-spec). Each is pinned by",
|
|
711
|
+
"# `kivyforge lock` and staged into the bundle's bin\\ (helpers on PATH by",
|
|
712
|
+
"# name; DLLs load by name, e.g. ctypes.WinDLL('sdk.dll')).",
|
|
713
|
+
"# [tool.kivy.windows.native.binaries]",
|
|
714
|
+
'# ffmpeg = { version = "7.1", source = "https://example.com/ffmpeg-windows-amd64.zip" }',
|
|
715
|
+
'# sdk = { version = "0.1.0", source = "binaries/windows/sdk.dll" }',
|
|
716
|
+
]
|