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,379 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* kivyforge Windows onedir launcher (bootloader).
|
|
3
|
+
*
|
|
4
|
+
* A prebuilt, windowed-subsystem native launcher. One binary serves every app:
|
|
5
|
+
* everything app-specific lives in the generated bootstrap module, and the only
|
|
6
|
+
* per-app change to the binary is its icon/version *resources* (patched with
|
|
7
|
+
* rcedit at package time). See docs/design/platforms/windows/bootloader-windows.md.
|
|
8
|
+
*
|
|
9
|
+
* Behavior (spawn-and-wait, NOT exec):
|
|
10
|
+
* 1. Self-locate via GetModuleFileNameW (loop on ERROR_INSUFFICIENT_BUFFER;
|
|
11
|
+
* never a fixed MAX_PATH); derive the bundle layout from the launcher's own
|
|
12
|
+
* directory (never trust the CWD).
|
|
13
|
+
* 2. Set a Unicode child environment: PYTHONHOME=<bundle>\python,
|
|
14
|
+
* PYTHONPATH=<bundle>\app, PYTHONNOUSERSITE=1.
|
|
15
|
+
* 3. Build the child command line
|
|
16
|
+
* (<bundle>\python\python.exe <bundle>\_kivyforge_bootstrap.py <argv...>)
|
|
17
|
+
* with the correct CommandLineToArgvW-inverse quoting algorithm.
|
|
18
|
+
* 4. Console handoff: AttachConsole(ATTACH_PARENT_PROCESS). If a parent console
|
|
19
|
+
* exists (the `kivyforge run` path), inherit its std handles so the child's
|
|
20
|
+
* output/tracebacks reach the terminal. Otherwise (Explorer double-click),
|
|
21
|
+
* spawn with CREATE_NO_WINDOW so no console flashes.
|
|
22
|
+
* 5. CreateProcessW with CREATE_SUSPENDED, assign to a kill-on-close Job
|
|
23
|
+
* object, THEN ResumeThread (so no grandchild escapes the job). The job is
|
|
24
|
+
* best-effort: on the rare host where it cannot be armed/assigned the app
|
|
25
|
+
* still launches, just without the kill-on-close guarantee.
|
|
26
|
+
* 6. WaitForSingleObject -> GetExitCodeProcess -> exit with the child's code.
|
|
27
|
+
* Close every handle on every path.
|
|
28
|
+
*
|
|
29
|
+
* Linked /SUBSYSTEM:WINDOWS (windowed only; console apps are out of scope).
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
#ifndef UNICODE
|
|
33
|
+
#define UNICODE
|
|
34
|
+
#endif
|
|
35
|
+
#ifndef _UNICODE
|
|
36
|
+
#define _UNICODE
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
#include <windows.h>
|
|
40
|
+
#include <shellapi.h>
|
|
41
|
+
#include <stddef.h>
|
|
42
|
+
|
|
43
|
+
/* Fixed convention names (see bootloader-windows.md / windows-spec). */
|
|
44
|
+
static const wchar_t *PYTHON_REL = L"\\python\\python.exe";
|
|
45
|
+
static const wchar_t *BOOTSTRAP_REL = L"\\_kivyforge_bootstrap.py";
|
|
46
|
+
static const wchar_t *PYTHONHOME_REL = L"\\python";
|
|
47
|
+
static const wchar_t *PYTHONPATH_REL = L"\\app";
|
|
48
|
+
|
|
49
|
+
/* Exit code for a launcher-internal failure (distinct from any app exit code).
|
|
50
|
+
* 71 == EX_OSERR, matching the macOS/Linux launchers. */
|
|
51
|
+
#define LAUNCHER_EX_OSERR 71
|
|
52
|
+
|
|
53
|
+
/* ----------------------------------------------------------------------------
|
|
54
|
+
* Small heap helpers. On OOM we fail hard with the OS-error exit code; there is
|
|
55
|
+
* no meaningful recovery for a launcher.
|
|
56
|
+
* ------------------------------------------------------------------------- */
|
|
57
|
+
static void *xalloc(size_t bytes) {
|
|
58
|
+
void *p = HeapAlloc(GetProcessHeap(), 0, bytes);
|
|
59
|
+
return p;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static void xfree(void *p) {
|
|
63
|
+
if (p != NULL) {
|
|
64
|
+
HeapFree(GetProcessHeap(), 0, p);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* ----------------------------------------------------------------------------
|
|
69
|
+
* Self-location: GetModuleFileNameW into a growable buffer. Returns a
|
|
70
|
+
* heap-allocated wide string (caller frees) or NULL on failure.
|
|
71
|
+
* ------------------------------------------------------------------------- */
|
|
72
|
+
static wchar_t *module_path(void) {
|
|
73
|
+
DWORD cap = MAX_PATH;
|
|
74
|
+
for (;;) {
|
|
75
|
+
wchar_t *buf = (wchar_t *)xalloc(cap * sizeof(wchar_t));
|
|
76
|
+
if (buf == NULL) {
|
|
77
|
+
return NULL;
|
|
78
|
+
}
|
|
79
|
+
DWORD n = GetModuleFileNameW(NULL, buf, cap);
|
|
80
|
+
if (n == 0) {
|
|
81
|
+
xfree(buf);
|
|
82
|
+
return NULL;
|
|
83
|
+
}
|
|
84
|
+
if (n < cap && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
85
|
+
/* n < cap means the name fit (and is NUL-terminated). */
|
|
86
|
+
return buf;
|
|
87
|
+
}
|
|
88
|
+
xfree(buf);
|
|
89
|
+
if (cap > (1 << 20)) {
|
|
90
|
+
/* Runaway guard: no sane path is a million wchars. */
|
|
91
|
+
return NULL;
|
|
92
|
+
}
|
|
93
|
+
cap *= 2;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Return the length of *path up to (not including) the final backslash — i.e.
|
|
98
|
+
* the directory portion. If there is no backslash, returns 0. */
|
|
99
|
+
static size_t dir_len(const wchar_t *path) {
|
|
100
|
+
size_t last = 0;
|
|
101
|
+
for (size_t i = 0; path[i] != L'\0'; i++) {
|
|
102
|
+
if (path[i] == L'\\') {
|
|
103
|
+
last = i;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return last;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Concatenate dir[0..dir_count) + suffix into a fresh heap string. */
|
|
110
|
+
static wchar_t *join(const wchar_t *dir, size_t dir_count, const wchar_t *suffix) {
|
|
111
|
+
size_t slen = 0;
|
|
112
|
+
while (suffix[slen] != L'\0') {
|
|
113
|
+
slen++;
|
|
114
|
+
}
|
|
115
|
+
wchar_t *out = (wchar_t *)xalloc((dir_count + slen + 1) * sizeof(wchar_t));
|
|
116
|
+
if (out == NULL) {
|
|
117
|
+
return NULL;
|
|
118
|
+
}
|
|
119
|
+
for (size_t i = 0; i < dir_count; i++) {
|
|
120
|
+
out[i] = dir[i];
|
|
121
|
+
}
|
|
122
|
+
for (size_t i = 0; i < slen; i++) {
|
|
123
|
+
out[dir_count + i] = suffix[i];
|
|
124
|
+
}
|
|
125
|
+
out[dir_count + slen] = L'\0';
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* ----------------------------------------------------------------------------
|
|
130
|
+
* Argv quoting — the exact inverse of CommandLineToArgvW (Daniel Colascione's
|
|
131
|
+
* documented algorithm). Naive double-quoting corrupts paths ending in `\` and
|
|
132
|
+
* any argument containing a `"`. Appends the quoted form of *arg to the buffer.
|
|
133
|
+
* ------------------------------------------------------------------------- */
|
|
134
|
+
|
|
135
|
+
typedef struct {
|
|
136
|
+
wchar_t *data;
|
|
137
|
+
size_t len;
|
|
138
|
+
size_t cap;
|
|
139
|
+
int oom;
|
|
140
|
+
} WBuf;
|
|
141
|
+
|
|
142
|
+
static void wbuf_init(WBuf *b) {
|
|
143
|
+
b->cap = 256;
|
|
144
|
+
b->len = 0;
|
|
145
|
+
b->oom = 0;
|
|
146
|
+
b->data = (wchar_t *)xalloc(b->cap * sizeof(wchar_t));
|
|
147
|
+
if (b->data == NULL) {
|
|
148
|
+
b->oom = 1;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static void wbuf_push(WBuf *b, wchar_t c) {
|
|
153
|
+
if (b->oom) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (b->len + 1 >= b->cap) {
|
|
157
|
+
size_t ncap = b->cap * 2;
|
|
158
|
+
wchar_t *nd = (wchar_t *)xalloc(ncap * sizeof(wchar_t));
|
|
159
|
+
if (nd == NULL) {
|
|
160
|
+
b->oom = 1;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
for (size_t i = 0; i < b->len; i++) {
|
|
164
|
+
nd[i] = b->data[i];
|
|
165
|
+
}
|
|
166
|
+
xfree(b->data);
|
|
167
|
+
b->data = nd;
|
|
168
|
+
b->cap = ncap;
|
|
169
|
+
}
|
|
170
|
+
b->data[b->len++] = c;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static void wbuf_push_str(WBuf *b, const wchar_t *s) {
|
|
174
|
+
for (size_t i = 0; s[i] != L'\0'; i++) {
|
|
175
|
+
wbuf_push(b, s[i]);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Append *arg, quoted iff necessary, to *b (per CommandLineToArgvW rules). */
|
|
180
|
+
static void append_quoted(WBuf *b, const wchar_t *arg) {
|
|
181
|
+
int needs_quotes = (arg[0] == L'\0');
|
|
182
|
+
for (size_t i = 0; arg[i] != L'\0'; i++) {
|
|
183
|
+
if (arg[i] == L' ' || arg[i] == L'\t' || arg[i] == L'"') {
|
|
184
|
+
needs_quotes = 1;
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (!needs_quotes) {
|
|
189
|
+
wbuf_push_str(b, arg);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
wbuf_push(b, L'"');
|
|
193
|
+
for (size_t i = 0;; i++) {
|
|
194
|
+
size_t backslashes = 0;
|
|
195
|
+
while (arg[i] == L'\\') {
|
|
196
|
+
i++;
|
|
197
|
+
backslashes++;
|
|
198
|
+
}
|
|
199
|
+
if (arg[i] == L'\0') {
|
|
200
|
+
/* Escape all backslashes, but let the terminating quote be added
|
|
201
|
+
* after; the backslashes must not eat that quote. */
|
|
202
|
+
for (size_t k = 0; k < backslashes * 2; k++) {
|
|
203
|
+
wbuf_push(b, L'\\');
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
} else if (arg[i] == L'"') {
|
|
207
|
+
/* Escape all backslashes and the following quote. */
|
|
208
|
+
for (size_t k = 0; k < backslashes * 2 + 1; k++) {
|
|
209
|
+
wbuf_push(b, L'\\');
|
|
210
|
+
}
|
|
211
|
+
wbuf_push(b, arg[i]);
|
|
212
|
+
} else {
|
|
213
|
+
/* Backslashes are not special here. */
|
|
214
|
+
for (size_t k = 0; k < backslashes; k++) {
|
|
215
|
+
wbuf_push(b, L'\\');
|
|
216
|
+
}
|
|
217
|
+
wbuf_push(b, arg[i]);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
wbuf_push(b, L'"');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* ----------------------------------------------------------------------------
|
|
224
|
+
* Entry point. /SUBSYSTEM:WINDOWS with the Unicode CRT startup calls wWinMain.
|
|
225
|
+
* We ignore its args and pull the real command line via GetCommandLineW so we
|
|
226
|
+
* get wide-char argv regardless.
|
|
227
|
+
* ------------------------------------------------------------------------- */
|
|
228
|
+
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
229
|
+
LPWSTR lpCmdLine, int nCmdShow) {
|
|
230
|
+
(void)hInstance;
|
|
231
|
+
(void)hPrevInstance;
|
|
232
|
+
(void)lpCmdLine;
|
|
233
|
+
(void)nCmdShow;
|
|
234
|
+
|
|
235
|
+
wchar_t *exe = module_path();
|
|
236
|
+
if (exe == NULL) {
|
|
237
|
+
return LAUNCHER_EX_OSERR;
|
|
238
|
+
}
|
|
239
|
+
size_t bundle_len = dir_len(exe); /* index of the last backslash */
|
|
240
|
+
|
|
241
|
+
wchar_t *python = join(exe, bundle_len, PYTHON_REL);
|
|
242
|
+
wchar_t *bootstrap = join(exe, bundle_len, BOOTSTRAP_REL);
|
|
243
|
+
wchar_t *pyhome = join(exe, bundle_len, PYTHONHOME_REL);
|
|
244
|
+
wchar_t *pypath = join(exe, bundle_len, PYTHONPATH_REL);
|
|
245
|
+
if (python == NULL || bootstrap == NULL || pyhome == NULL || pypath == NULL) {
|
|
246
|
+
return LAUNCHER_EX_OSERR;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* Child environment: inherit ours, then override the Python isolation vars.
|
|
250
|
+
* SetEnvironmentVariableW mutates this process's block, which the child
|
|
251
|
+
* inherits (we pass a NULL environment to CreateProcessW). */
|
|
252
|
+
SetEnvironmentVariableW(L"PYTHONHOME", pyhome);
|
|
253
|
+
SetEnvironmentVariableW(L"PYTHONPATH", pypath);
|
|
254
|
+
SetEnvironmentVariableW(L"PYTHONNOUSERSITE", L"1");
|
|
255
|
+
|
|
256
|
+
/* Reconstruct the child command line: python.exe, the bootstrap, then every
|
|
257
|
+
* forwarded argument (argv[1..]) quoted correctly. */
|
|
258
|
+
int argc = 0;
|
|
259
|
+
LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
|
260
|
+
if (argv == NULL) {
|
|
261
|
+
return LAUNCHER_EX_OSERR;
|
|
262
|
+
}
|
|
263
|
+
WBuf cmd;
|
|
264
|
+
wbuf_init(&cmd);
|
|
265
|
+
append_quoted(&cmd, python);
|
|
266
|
+
wbuf_push(&cmd, L' ');
|
|
267
|
+
append_quoted(&cmd, bootstrap);
|
|
268
|
+
for (int i = 1; i < argc; i++) {
|
|
269
|
+
wbuf_push(&cmd, L' ');
|
|
270
|
+
append_quoted(&cmd, argv[i]);
|
|
271
|
+
}
|
|
272
|
+
wbuf_push(&cmd, L'\0');
|
|
273
|
+
LocalFree(argv);
|
|
274
|
+
if (cmd.oom) {
|
|
275
|
+
return LAUNCHER_EX_OSERR;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* Console handoff. A windowed-subsystem process does not reliably inherit a
|
|
279
|
+
* parent console's std handles; make the handoff explicit. */
|
|
280
|
+
BOOL attached = AttachConsole(ATTACH_PARENT_PROCESS);
|
|
281
|
+
DWORD creation_flags = CREATE_SUSPENDED;
|
|
282
|
+
STARTUPINFOW si;
|
|
283
|
+
ZeroMemory(&si, sizeof(si));
|
|
284
|
+
si.cb = sizeof(si);
|
|
285
|
+
BOOL inherit_handles = FALSE;
|
|
286
|
+
if (attached) {
|
|
287
|
+
/* Pass the attached terminal's std handles to the console-subsystem
|
|
288
|
+
* child so prints/tracebacks land where the developer is looking. */
|
|
289
|
+
HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
|
|
290
|
+
HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
291
|
+
HANDLE herr = GetStdHandle(STD_ERROR_HANDLE);
|
|
292
|
+
si.dwFlags |= STARTF_USESTDHANDLES;
|
|
293
|
+
si.hStdInput = hin;
|
|
294
|
+
si.hStdOutput = hout;
|
|
295
|
+
si.hStdError = herr;
|
|
296
|
+
SetHandleInformation(hin, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
|
297
|
+
SetHandleInformation(hout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
|
298
|
+
SetHandleInformation(herr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
|
299
|
+
inherit_handles = TRUE;
|
|
300
|
+
} else {
|
|
301
|
+
/* No parent console (Explorer double-click): suppress the console flash
|
|
302
|
+
* that a console-subsystem python.exe would otherwise create.
|
|
303
|
+
*
|
|
304
|
+
* Why CREATE_NO_WINDOW on python.exe rather than launching pythonw.exe:
|
|
305
|
+
* a single code path serves both entry points. On the `kivyforge run`
|
|
306
|
+
* path we WANT the console-subsystem python.exe so its stdout/stderr and
|
|
307
|
+
* tracebacks attach to the parent terminal (above). Using pythonw.exe for
|
|
308
|
+
* double-click would mean detecting the mode and choosing a different
|
|
309
|
+
* child, and pythonw.exe forfeits that attach-for-diagnostics story. One
|
|
310
|
+
* child + CREATE_NO_WINDOW gives silent double-click AND visible `run`. */
|
|
311
|
+
creation_flags |= CREATE_NO_WINDOW;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* A Job object with kill-on-close makes the whole child process tree die
|
|
315
|
+
* with the launcher (Ctrl-C, task kill, crash) — no orphaned python. This
|
|
316
|
+
* is best-effort: if the job cannot be established (rare on Win8+ where
|
|
317
|
+
* nested jobs are the default), we drop it and still launch rather than
|
|
318
|
+
* refuse to start the app. Failing calls are checked, never ignored. */
|
|
319
|
+
HANDLE job = CreateJobObjectW(NULL, NULL);
|
|
320
|
+
if (job != NULL) {
|
|
321
|
+
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
|
|
322
|
+
ZeroMemory(&jeli, sizeof(jeli));
|
|
323
|
+
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
|
324
|
+
if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &jeli,
|
|
325
|
+
sizeof(jeli))) {
|
|
326
|
+
/* A job we cannot arm for kill-on-close is worse than none: close it
|
|
327
|
+
* so we do not rely on a half-configured job below. */
|
|
328
|
+
CloseHandle(job);
|
|
329
|
+
job = NULL;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
PROCESS_INFORMATION pi;
|
|
334
|
+
ZeroMemory(&pi, sizeof(pi));
|
|
335
|
+
BOOL ok = CreateProcessW(python, /* application: the bundled python */
|
|
336
|
+
cmd.data, /* full command line */
|
|
337
|
+
NULL, NULL, /* default security */
|
|
338
|
+
inherit_handles,
|
|
339
|
+
creation_flags,
|
|
340
|
+
NULL, /* inherit our (mutated) environment */
|
|
341
|
+
NULL, /* inherit CWD; bootstrap sets its own */
|
|
342
|
+
&si, &pi);
|
|
343
|
+
if (!ok) {
|
|
344
|
+
if (job != NULL) {
|
|
345
|
+
CloseHandle(job);
|
|
346
|
+
}
|
|
347
|
+
return LAUNCHER_EX_OSERR;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* Assign to the job while still suspended (closes the grandchild-escape
|
|
351
|
+
* race), THEN resume the main thread. If assignment fails we cannot promise
|
|
352
|
+
* kill-on-close, so drop the job rather than pretend the guarantee holds. */
|
|
353
|
+
if (job != NULL && !AssignProcessToJobObject(job, pi.hProcess)) {
|
|
354
|
+
CloseHandle(job);
|
|
355
|
+
job = NULL;
|
|
356
|
+
}
|
|
357
|
+
if (ResumeThread(pi.hThread) == (DWORD)-1) {
|
|
358
|
+
/* The child is stuck suspended; never WaitForSingleObject forever on it.
|
|
359
|
+
* Tear it down deterministically and report an OS error. */
|
|
360
|
+
TerminateProcess(pi.hProcess, LAUNCHER_EX_OSERR);
|
|
361
|
+
CloseHandle(pi.hThread);
|
|
362
|
+
CloseHandle(pi.hProcess);
|
|
363
|
+
if (job != NULL) {
|
|
364
|
+
CloseHandle(job);
|
|
365
|
+
}
|
|
366
|
+
return LAUNCHER_EX_OSERR;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
370
|
+
DWORD code = LAUNCHER_EX_OSERR;
|
|
371
|
+
GetExitCodeProcess(pi.hProcess, &code);
|
|
372
|
+
|
|
373
|
+
CloseHandle(pi.hThread);
|
|
374
|
+
CloseHandle(pi.hProcess);
|
|
375
|
+
if (job != NULL) {
|
|
376
|
+
CloseHandle(job);
|
|
377
|
+
}
|
|
378
|
+
return (int)code;
|
|
379
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Windows lock stack (``pylock.windows.toml``).
|
|
2
|
+
|
|
3
|
+
A thin Windows *profile* (:class:`WindowsProfile`) over the generic
|
|
4
|
+
wheel+runtime lock engine (``kivyforge.lock.wheelruntime``). This module is the
|
|
5
|
+
stable Windows public surface: it binds the profile into the core and re-exports
|
|
6
|
+
the engine's types under Windows-friendly names so callers (the CLI, tests)
|
|
7
|
+
never reach into the generic package directly.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from kivyforge.config.model import Config
|
|
17
|
+
from kivyforge.lock.wheelruntime import (
|
|
18
|
+
PythonRuntime as WindowsPythonRuntime,
|
|
19
|
+
)
|
|
20
|
+
from kivyforge.lock.wheelruntime import (
|
|
21
|
+
ResolvedPackage,
|
|
22
|
+
ResolvedWheel,
|
|
23
|
+
RuntimeArtifact,
|
|
24
|
+
RuntimeProvider,
|
|
25
|
+
RuntimeProviderError,
|
|
26
|
+
Variant,
|
|
27
|
+
WheelResolver,
|
|
28
|
+
WheelResolverError,
|
|
29
|
+
WheelRuntimeBuildError,
|
|
30
|
+
WheelRuntimeLock,
|
|
31
|
+
build_wheel_runtime_lock,
|
|
32
|
+
diff_summary,
|
|
33
|
+
get_wheel_resolver,
|
|
34
|
+
semantic_equal,
|
|
35
|
+
)
|
|
36
|
+
from kivyforge.lock.wheelruntime import serialize as _ser
|
|
37
|
+
|
|
38
|
+
from .profile import WindowsProfile, wheel_arch, windows_platform_tag
|
|
39
|
+
from .runtime import PythonBuildStandaloneProvider
|
|
40
|
+
|
|
41
|
+
# Windows-friendly aliases for the generic engine types.
|
|
42
|
+
WindowsLockfile = WheelRuntimeLock
|
|
43
|
+
WindowsBuildError = WheelRuntimeBuildError
|
|
44
|
+
WindowsResolverError = WheelResolverError
|
|
45
|
+
|
|
46
|
+
_PROFILE = WindowsProfile()
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"PythonBuildStandaloneProvider",
|
|
50
|
+
"ResolvedPackage",
|
|
51
|
+
"ResolvedWheel",
|
|
52
|
+
"RuntimeArtifact",
|
|
53
|
+
"RuntimeProvider",
|
|
54
|
+
"RuntimeProviderError",
|
|
55
|
+
"Variant",
|
|
56
|
+
"WheelResolver",
|
|
57
|
+
"WindowsBuildError",
|
|
58
|
+
"WindowsLockfile",
|
|
59
|
+
"WindowsProfile",
|
|
60
|
+
"WindowsPythonRuntime",
|
|
61
|
+
"WindowsResolverError",
|
|
62
|
+
"build_windows_lockfile",
|
|
63
|
+
"diff_summary",
|
|
64
|
+
"dumps",
|
|
65
|
+
"get_windows_resolver",
|
|
66
|
+
"load",
|
|
67
|
+
"loads",
|
|
68
|
+
"semantic_equal",
|
|
69
|
+
"wheel_arch",
|
|
70
|
+
"windows_platform_tag",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def build_windows_lockfile(
|
|
75
|
+
config: Config,
|
|
76
|
+
pyproject_text: str,
|
|
77
|
+
*,
|
|
78
|
+
project_root: Path | None = None,
|
|
79
|
+
resolver: WheelResolver | None = None,
|
|
80
|
+
runtime_provider: RuntimeProvider | None = None,
|
|
81
|
+
offline: bool = False,
|
|
82
|
+
now: datetime | None = None,
|
|
83
|
+
on_warning: Callable[[str], None] | None = None,
|
|
84
|
+
) -> WindowsLockfile:
|
|
85
|
+
return build_wheel_runtime_lock(
|
|
86
|
+
_PROFILE,
|
|
87
|
+
config,
|
|
88
|
+
pyproject_text,
|
|
89
|
+
project_root=project_root,
|
|
90
|
+
resolver=resolver,
|
|
91
|
+
runtime_provider=runtime_provider,
|
|
92
|
+
native_binaries=config.windows.binaries if config.windows else (),
|
|
93
|
+
offline=offline,
|
|
94
|
+
now=now,
|
|
95
|
+
on_warning=on_warning,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def dumps(lock: WindowsLockfile) -> str:
|
|
100
|
+
return _ser.dumps(lock)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def loads(text: str) -> WindowsLockfile:
|
|
104
|
+
return _ser.loads(text, platform="windows")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def load(path: str | Path) -> WindowsLockfile:
|
|
108
|
+
return _ser.load(path, platform="windows")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_windows_resolver(backend: str = "pip", **kwargs) -> WheelResolver:
|
|
112
|
+
return get_wheel_resolver(backend, **kwargs)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Windows lock profile — the platform-specific inputs to the wheel+runtime core.
|
|
2
|
+
|
|
3
|
+
The simplest of the desktop family: Windows has a single stable wheel platform
|
|
4
|
+
tag per arch (``win_amd64`` this phase — ``win32``/``win_arm64`` are out of
|
|
5
|
+
scope), so there is no tag ladder (Linux) and no fat-wheel arch (macOS
|
|
6
|
+
``universal2``). ``kivy_deps.*`` are ordinary wheels — Kivy's ``win_amd64`` wheel
|
|
7
|
+
declares them as conditional dependencies, so they flow through the shared
|
|
8
|
+
resolver with URL + SHA-256 pins with no special-casing. The bundled runtime
|
|
9
|
+
comes from python-build-standalone (``x86_64-pc-windows-msvc``). Everything else
|
|
10
|
+
— resolve/serialize/build orchestration — is the shared core.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from kivyforge.config.errors import ConfigError
|
|
16
|
+
from kivyforge.config.model import Config
|
|
17
|
+
from kivyforge.lock.wheelruntime.profile import PlatformLockProfile
|
|
18
|
+
from kivyforge.lock.wheelruntime.resolver import Variant
|
|
19
|
+
from kivyforge.lock.wheelruntime.runtime import RuntimeProvider
|
|
20
|
+
|
|
21
|
+
from .runtime import PythonBuildStandaloneProvider
|
|
22
|
+
|
|
23
|
+
# arm64: add "arm64" here and "arm64": "win_arm64" to _ARCH_TO_TAG; _TAG_TO_ARCH
|
|
24
|
+
# derives automatically, and coverage_error's "win_amd64" text should generalize
|
|
25
|
+
# to the per-arch tag. Gated on upstream win_arm64 wheels — see arm64-windows.md §2.
|
|
26
|
+
VALID_WHEEL_ARCHS = frozenset({"amd64"})
|
|
27
|
+
|
|
28
|
+
# kivyforge arch name -> the wheel platform tag pip requests / a wheel carries.
|
|
29
|
+
_ARCH_TO_TAG = {"amd64": "win_amd64"}
|
|
30
|
+
_TAG_TO_ARCH = {tag: arch for arch, tag in _ARCH_TO_TAG.items()}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def windows_platform_tag(arch: str) -> str:
|
|
34
|
+
"""The pip ``--platform`` tag for a Windows arch (``amd64`` -> ``win_amd64``)."""
|
|
35
|
+
return _ARCH_TO_TAG[arch]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def wheel_arch(platform_tag: str) -> str | None:
|
|
39
|
+
"""The architecture a Windows wheel platform tag targets, or ``None``.
|
|
40
|
+
|
|
41
|
+
``win_amd64`` -> ``amd64``. ``win32`` (x86) and ``win_arm64`` are recognized
|
|
42
|
+
as Windows tags but are unsupported this phase, so they resolve to their arch
|
|
43
|
+
name only if that arch is a valid target (they are not), i.e. ``None`` here.
|
|
44
|
+
A non-Windows tag (``any`` is handled by the shared core) also returns
|
|
45
|
+
``None``.
|
|
46
|
+
"""
|
|
47
|
+
return _TAG_TO_ARCH.get(platform_tag)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class WindowsProfile(PlatformLockProfile):
|
|
51
|
+
platform = "windows"
|
|
52
|
+
|
|
53
|
+
def overlay(self, config: Config):
|
|
54
|
+
return config.windows
|
|
55
|
+
|
|
56
|
+
def missing_overlay_error(self) -> str:
|
|
57
|
+
return "pyproject.toml has no [tool.kivy.windows] table; nothing to lock."
|
|
58
|
+
|
|
59
|
+
def python_version(self, config: Config) -> str:
|
|
60
|
+
# [tool.kivy.windows.python].version is required (the loader raises a
|
|
61
|
+
# ConfigError when it is missing), so it is always set here. Never
|
|
62
|
+
# silently substitute a hidden default — that would pin an unexpected
|
|
63
|
+
# (and possibly unreleased) Python instead of surfacing the misconfig.
|
|
64
|
+
version = config.windows_required.python_version
|
|
65
|
+
if not version:
|
|
66
|
+
raise ConfigError(
|
|
67
|
+
"missing required [tool.kivy.windows.python].version",
|
|
68
|
+
key_path="tool.kivy.windows.python.version",
|
|
69
|
+
)
|
|
70
|
+
return version
|
|
71
|
+
|
|
72
|
+
def variants(self, config: Config) -> tuple[Variant, ...]:
|
|
73
|
+
return tuple(
|
|
74
|
+
Variant(arch=arch, platform_tag=windows_platform_tag(arch))
|
|
75
|
+
for arch in config.windows_required.archs
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def wheel_covers(self, platform_tag: str, archs: tuple[str, ...]) -> set[str]:
|
|
79
|
+
arch = wheel_arch(platform_tag)
|
|
80
|
+
if arch in archs:
|
|
81
|
+
return {arch}
|
|
82
|
+
return set()
|
|
83
|
+
|
|
84
|
+
def runtime_provider(self, config: Config) -> RuntimeProvider:
|
|
85
|
+
return PythonBuildStandaloneProvider()
|
|
86
|
+
|
|
87
|
+
def coverage_error(self, name: str, missing: list[str]) -> str:
|
|
88
|
+
return (
|
|
89
|
+
f"{name} has no win_amd64 wheel for arch(es): {', '.join(missing)}.\n"
|
|
90
|
+
f" A compiled package must publish a win_amd64 wheel to be locked "
|
|
91
|
+
f"reproducibly.\n"
|
|
92
|
+
f" Supply the wheel via extra_index_urls/find_links, or drop the "
|
|
93
|
+
f"dependency on Windows."
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def wheel_scope_hint(self) -> str:
|
|
97
|
+
return (
|
|
98
|
+
"Vendored wheels must live under the project directory, a sibling "
|
|
99
|
+
"directory, or the enclosing repository (e.g. a wheels/ directory "
|
|
100
|
+
"beside pyproject.toml)."
|
|
101
|
+
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Windows runtime provider — python-build-standalone with the msvc triple.
|
|
2
|
+
|
|
3
|
+
A one-line specialization of the generic :class:`PbsProvider`: it fixes the
|
|
4
|
+
arch→target-triple map to Windows's ``x86_64-pc-windows-msvc`` build, and
|
|
5
|
+
otherwise inherits the shared PBS resolution + injectable metadata fetcher. The
|
|
6
|
+
Windows ``install_only`` archive normalizes under the same top-level ``python/``
|
|
7
|
+
tree as the darwin/linux ones (a normal relocatable prefix — ``python.exe`` at
|
|
8
|
+
the root, ``Lib/site-packages`` beneath it), which is load-bearing: staging must
|
|
9
|
+
**not** flatten, prune, or ``._pth``-isolate it (windows-spec).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from kivyforge.lock.wheelruntime.runtime import (
|
|
15
|
+
MetadataFetcher,
|
|
16
|
+
PbsProvider,
|
|
17
|
+
ReleaseAsset,
|
|
18
|
+
RuntimeProvider,
|
|
19
|
+
RuntimeProviderError,
|
|
20
|
+
pbs_asset_glob,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"PythonBuildStandaloneProvider",
|
|
25
|
+
"ReleaseAsset",
|
|
26
|
+
"RuntimeProvider",
|
|
27
|
+
"RuntimeProviderError",
|
|
28
|
+
"WINDOWS_TRIPLES",
|
|
29
|
+
"get_runtime_provider",
|
|
30
|
+
"pbs_asset_name",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
# kivyforge arch name -> PBS/LLVM Windows target triple.
|
|
34
|
+
# arm64: add "arm64": "aarch64-pc-windows-msvc" (confirm PBS ships that
|
|
35
|
+
# install_only archive for the pinned CPython). The generic PbsProvider handles
|
|
36
|
+
# the rest — no other change here. See arm64-windows.md §3.
|
|
37
|
+
WINDOWS_TRIPLES = {
|
|
38
|
+
"amd64": "x86_64-pc-windows-msvc",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Windows-facing alias for the generic PBS asset glob helper.
|
|
42
|
+
pbs_asset_name = pbs_asset_glob
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class PythonBuildStandaloneProvider(PbsProvider):
|
|
46
|
+
"""PBS provider fixed to the Windows msvc triple."""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
metadata_fetcher: MetadataFetcher | None = None,
|
|
51
|
+
*,
|
|
52
|
+
floor: str | None = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
super().__init__(WINDOWS_TRIPLES, metadata_fetcher, floor=floor)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_runtime_provider(
|
|
58
|
+
name: str = "python-build-standalone", **kwargs
|
|
59
|
+
) -> RuntimeProvider:
|
|
60
|
+
if name in ("python-build-standalone", "pbs", "python_build_standalone"):
|
|
61
|
+
return PythonBuildStandaloneProvider(**kwargs)
|
|
62
|
+
raise RuntimeProviderError(
|
|
63
|
+
f"unknown runtime provider {name!r} (expected python-build-standalone)"
|
|
64
|
+
)
|