fastled 1.2.33__py3-none-any.whl → 1.4.50__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.
- fastled/__init__.py +51 -192
- fastled/__main__.py +14 -0
- fastled/__version__.py +6 -0
- fastled/app.py +124 -27
- fastled/args.py +124 -0
- fastled/assets/localhost-key.pem +28 -0
- fastled/assets/localhost.pem +27 -0
- fastled/cli.py +10 -2
- fastled/cli_test.py +21 -0
- fastled/cli_test_interactive.py +21 -0
- fastled/client_server.py +334 -55
- fastled/compile_server.py +12 -1
- fastled/compile_server_impl.py +115 -42
- fastled/docker_manager.py +392 -69
- fastled/emoji_util.py +27 -0
- fastled/filewatcher.py +100 -8
- fastled/find_good_connection.py +105 -0
- fastled/header_dump.py +63 -0
- fastled/install/__init__.py +1 -0
- fastled/install/examples_manager.py +62 -0
- fastled/install/extension_manager.py +113 -0
- fastled/install/main.py +156 -0
- fastled/install/project_detection.py +167 -0
- fastled/install/test_install.py +373 -0
- fastled/install/vscode_config.py +344 -0
- fastled/interruptible_http.py +148 -0
- fastled/keyboard.py +1 -0
- fastled/keyz.py +84 -0
- fastled/live_client.py +26 -1
- fastled/open_browser.py +133 -89
- fastled/parse_args.py +219 -15
- fastled/playwright/chrome_extension_downloader.py +207 -0
- fastled/playwright/playwright_browser.py +773 -0
- fastled/playwright/resize_tracking.py +127 -0
- fastled/print_filter.py +52 -0
- fastled/project_init.py +20 -13
- fastled/select_sketch_directory.py +142 -17
- fastled/server_flask.py +487 -0
- fastled/server_start.py +21 -0
- fastled/settings.py +53 -4
- fastled/site/build.py +2 -10
- fastled/site/examples.py +10 -0
- fastled/sketch.py +129 -7
- fastled/string_diff.py +218 -9
- fastled/test/examples.py +7 -5
- fastled/types.py +22 -2
- fastled/util.py +78 -0
- fastled/version.py +41 -0
- fastled/web_compile.py +401 -218
- fastled/zip_files.py +76 -0
- {fastled-1.2.33.dist-info → fastled-1.4.50.dist-info}/METADATA +533 -382
- fastled-1.4.50.dist-info/RECORD +60 -0
- {fastled-1.2.33.dist-info → fastled-1.4.50.dist-info}/WHEEL +1 -1
- fastled/open_browser2.py +0 -111
- fastled-1.2.33.dist-info/RECORD +0 -33
- {fastled-1.2.33.dist-info → fastled-1.4.50.dist-info}/entry_points.txt +0 -0
- {fastled-1.2.33.dist-info → fastled-1.4.50.dist-info/licenses}/LICENSE +0 -0
- {fastled-1.2.33.dist-info → fastled-1.4.50.dist-info}/top_level.txt +0 -0
fastled/compile_server_impl.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import subprocess
|
|
2
2
|
import sys
|
|
3
3
|
import time
|
|
4
|
+
import traceback
|
|
4
5
|
import warnings
|
|
5
6
|
from datetime import datetime, timezone
|
|
6
7
|
from pathlib import Path
|
|
@@ -12,16 +13,23 @@ from fastled.docker_manager import (
|
|
|
12
13
|
Container,
|
|
13
14
|
DockerManager,
|
|
14
15
|
RunningContainer,
|
|
16
|
+
Volume,
|
|
15
17
|
)
|
|
18
|
+
from fastled.emoji_util import EMO
|
|
16
19
|
from fastled.settings import DEFAULT_CONTAINER_NAME, IMAGE_NAME, SERVER_PORT
|
|
17
20
|
from fastled.sketch import looks_like_fastled_repo
|
|
18
21
|
from fastled.types import BuildMode, CompileResult, CompileServerError
|
|
22
|
+
from fastled.util import port_is_free, print_banner
|
|
19
23
|
|
|
20
24
|
SERVER_OPTIONS = [
|
|
21
25
|
"--allow-shutdown", # Allow the server to be shut down without a force kill.
|
|
22
26
|
"--no-auto-update", # Don't auto live updates from the git repo.
|
|
23
27
|
]
|
|
24
28
|
|
|
29
|
+
LOCAL_DOCKER_ENV = {
|
|
30
|
+
"ONLY_QUICK_BUILDS": "0" # When running docker always allow release and debug.
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
|
|
26
34
|
def _try_get_fastled_src(path: Path) -> Path | None:
|
|
27
35
|
fastled_src_dir: Path | None = None
|
|
@@ -43,6 +51,8 @@ class CompileServerImpl:
|
|
|
43
51
|
auto_start: bool = True,
|
|
44
52
|
container_name: str | None = None,
|
|
45
53
|
remove_previous: bool = False,
|
|
54
|
+
no_platformio: bool = False,
|
|
55
|
+
allow_libcompile: bool = True,
|
|
46
56
|
) -> None:
|
|
47
57
|
container_name = container_name or DEFAULT_CONTAINER_NAME
|
|
48
58
|
if interactive and not mapped_dir:
|
|
@@ -61,6 +71,18 @@ class CompileServerImpl:
|
|
|
61
71
|
self.running_container: RunningContainer | None = None
|
|
62
72
|
self.auto_updates = auto_updates
|
|
63
73
|
self.remove_previous = remove_previous
|
|
74
|
+
self.no_platformio = no_platformio
|
|
75
|
+
|
|
76
|
+
# Guard: libfastled compilation requires volume source mapping
|
|
77
|
+
# If we don't have fastled_src_dir (not in FastLED repo), disable libcompile
|
|
78
|
+
if allow_libcompile and self.fastled_src_dir is None:
|
|
79
|
+
print(
|
|
80
|
+
f"{EMO('⚠️', 'WARNING:')} libfastled compilation disabled: volume source mapping not available"
|
|
81
|
+
)
|
|
82
|
+
print(" (not running in FastLED repository)")
|
|
83
|
+
allow_libcompile = False
|
|
84
|
+
|
|
85
|
+
self.allow_libcompile = allow_libcompile
|
|
64
86
|
self._port = 0 # 0 until compile server is started
|
|
65
87
|
if auto_start:
|
|
66
88
|
self.start()
|
|
@@ -98,7 +120,12 @@ class CompileServerImpl:
|
|
|
98
120
|
if not self.ping():
|
|
99
121
|
raise RuntimeError("Server is not running")
|
|
100
122
|
out: CompileResult = web_compile(
|
|
101
|
-
directory,
|
|
123
|
+
directory,
|
|
124
|
+
host=self.url(),
|
|
125
|
+
build_mode=build_mode,
|
|
126
|
+
profile=profile,
|
|
127
|
+
no_platformio=self.no_platformio,
|
|
128
|
+
allow_libcompile=self.allow_libcompile,
|
|
102
129
|
)
|
|
103
130
|
return out
|
|
104
131
|
|
|
@@ -110,14 +137,24 @@ class CompileServerImpl:
|
|
|
110
137
|
project_init(example=example, outputdir=outputdir)
|
|
111
138
|
|
|
112
139
|
@property
|
|
113
|
-
def running(self) -> bool:
|
|
140
|
+
def running(self) -> tuple[bool, Exception | None]:
|
|
114
141
|
if not self._port:
|
|
115
|
-
return False
|
|
142
|
+
return False, Exception("Docker hasn't been initialzed with a port yet")
|
|
116
143
|
if not DockerManager.is_docker_installed():
|
|
117
|
-
return False
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
144
|
+
return False, Exception("Docker is not installed")
|
|
145
|
+
docker_running, err = self.docker.is_running()
|
|
146
|
+
if not docker_running:
|
|
147
|
+
IS_MAC = sys.platform == "darwin"
|
|
148
|
+
if IS_MAC:
|
|
149
|
+
if "FileNotFoundError" in str(err):
|
|
150
|
+
traceback.print_exc()
|
|
151
|
+
print("\n\nNone fatal debug print for MacOS\n")
|
|
152
|
+
return False, err
|
|
153
|
+
ok: bool = self.docker.is_container_running(self.container_name)
|
|
154
|
+
if ok:
|
|
155
|
+
return True, None
|
|
156
|
+
else:
|
|
157
|
+
return False, Exception("Docker is not running")
|
|
121
158
|
|
|
122
159
|
def using_fastled_src_dir_volume(self) -> bool:
|
|
123
160
|
out = self.fastled_src_dir is not None
|
|
@@ -170,7 +207,10 @@ class CompileServerImpl:
|
|
|
170
207
|
print("Compiling server starting")
|
|
171
208
|
|
|
172
209
|
# Ensure Docker is running
|
|
173
|
-
|
|
210
|
+
running: bool
|
|
211
|
+
# err: Exception | None
|
|
212
|
+
running, _ = self.docker.is_running()
|
|
213
|
+
if not running:
|
|
174
214
|
if not self.docker.start():
|
|
175
215
|
print("Docker could not be started. Exiting.")
|
|
176
216
|
raise RuntimeError("Docker could not be started. Exiting.")
|
|
@@ -185,10 +225,11 @@ class CompileServerImpl:
|
|
|
185
225
|
upgrade = True
|
|
186
226
|
else:
|
|
187
227
|
upgrade = self.auto_updates
|
|
188
|
-
self.docker.validate_or_download_image(
|
|
189
|
-
image_name=IMAGE_NAME, tag="
|
|
228
|
+
updated = self.docker.validate_or_download_image(
|
|
229
|
+
image_name=IMAGE_NAME, tag="latest", upgrade=upgrade
|
|
190
230
|
)
|
|
191
231
|
DISK_CACHE.put("last-update", now_str)
|
|
232
|
+
INTERNAL_DOCKER_PORT = 80
|
|
192
233
|
|
|
193
234
|
print("Docker image now validated")
|
|
194
235
|
port = SERVER_PORT
|
|
@@ -196,71 +237,90 @@ class CompileServerImpl:
|
|
|
196
237
|
server_command = ["/bin/bash"]
|
|
197
238
|
else:
|
|
198
239
|
server_command = ["python", "/js/run.py", "server"] + SERVER_OPTIONS
|
|
199
|
-
|
|
200
|
-
|
|
240
|
+
if self.no_platformio:
|
|
241
|
+
server_command.append("--no-platformio")
|
|
242
|
+
if self.interactive:
|
|
243
|
+
print("Disabling port forwarding in interactive mode")
|
|
244
|
+
ports = {}
|
|
245
|
+
else:
|
|
246
|
+
ports = {INTERNAL_DOCKER_PORT: port}
|
|
247
|
+
volumes = []
|
|
201
248
|
if self.fastled_src_dir:
|
|
202
|
-
|
|
203
|
-
|
|
249
|
+
msg = f"FastLED REPO updates enabled!!\n\nMounting FastLED source directory\n{self.fastled_src_dir} into container\n/host/fastled/src"
|
|
250
|
+
print_banner(msg)
|
|
251
|
+
volumes.append(
|
|
252
|
+
Volume(
|
|
253
|
+
host_path=str(self.fastled_src_dir),
|
|
254
|
+
container_path="/host/fastled/src",
|
|
255
|
+
mode="ro",
|
|
256
|
+
)
|
|
204
257
|
)
|
|
205
|
-
volumes = {
|
|
206
|
-
str(self.fastled_src_dir): {"bind": "/host/fastled/src", "mode": "ro"}
|
|
207
|
-
}
|
|
208
258
|
if self.interactive:
|
|
209
259
|
# add the mapped directory to the container
|
|
210
260
|
print(f"Mounting {self.mapped_dir} into container /mapped")
|
|
211
|
-
# volumes = {str(self.mapped_dir): {"bind": "/mapped", "mode": "rw"}}
|
|
212
|
-
# add it
|
|
213
261
|
assert self.mapped_dir is not None
|
|
214
262
|
dir_name = self.mapped_dir.name
|
|
215
263
|
if not volumes:
|
|
216
|
-
volumes =
|
|
217
|
-
volumes
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
264
|
+
volumes = []
|
|
265
|
+
volumes.append(
|
|
266
|
+
Volume(
|
|
267
|
+
host_path=str(self.mapped_dir),
|
|
268
|
+
container_path=f"/mapped/{dir_name}",
|
|
269
|
+
mode="rw",
|
|
270
|
+
)
|
|
271
|
+
)
|
|
221
272
|
if self.fastled_src_dir is not None:
|
|
222
|
-
# add volume for src/platforms/wasm/compiler/CMakelists.txt
|
|
223
273
|
# to allow for interactive compilation
|
|
224
|
-
interactive_sources =
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
for
|
|
229
|
-
src_path = Path(
|
|
274
|
+
# interactive_sources = list(INTERACTIVE_SOURCES)
|
|
275
|
+
interactive_sources: list[tuple[Path, str]] = []
|
|
276
|
+
src_host: Path
|
|
277
|
+
dst_container: str
|
|
278
|
+
for src_host, dst_container in interactive_sources:
|
|
279
|
+
src_path = Path(src_host).absolute()
|
|
230
280
|
if src_path.exists():
|
|
231
|
-
print(f"Mounting {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
281
|
+
print(f"Mounting {src_host} into container")
|
|
282
|
+
volumes.append(
|
|
283
|
+
Volume(
|
|
284
|
+
host_path=str(src_path),
|
|
285
|
+
container_path=dst_container,
|
|
286
|
+
mode="rw",
|
|
287
|
+
)
|
|
288
|
+
)
|
|
237
289
|
else:
|
|
238
|
-
print(f"Could not find {
|
|
290
|
+
print(f"Could not find {src_path}")
|
|
239
291
|
|
|
240
292
|
cmd_str = subprocess.list2cmdline(server_command)
|
|
241
293
|
if not self.interactive:
|
|
242
294
|
container: Container = self.docker.run_container_detached(
|
|
243
295
|
image_name=IMAGE_NAME,
|
|
244
|
-
tag="
|
|
296
|
+
tag="latest",
|
|
245
297
|
container_name=self.container_name,
|
|
246
298
|
command=cmd_str,
|
|
247
299
|
ports=ports,
|
|
248
300
|
volumes=volumes,
|
|
249
|
-
remove_previous=self.interactive or self.remove_previous,
|
|
301
|
+
remove_previous=self.interactive or self.remove_previous or updated,
|
|
302
|
+
environment=LOCAL_DOCKER_ENV,
|
|
250
303
|
)
|
|
251
304
|
self.running_container = self.docker.attach_and_run(container)
|
|
252
305
|
assert self.running_container is not None, "Container should be running"
|
|
253
306
|
print("Compile server starting")
|
|
254
307
|
return port
|
|
255
308
|
else:
|
|
256
|
-
|
|
309
|
+
client_port_mapped = INTERNAL_DOCKER_PORT in ports
|
|
310
|
+
free_port = port_is_free(INTERNAL_DOCKER_PORT)
|
|
311
|
+
if client_port_mapped and free_port:
|
|
312
|
+
warnings.warn(
|
|
313
|
+
f"Can't expose port {INTERNAL_DOCKER_PORT}, disabling port forwarding in interactive mode"
|
|
314
|
+
)
|
|
315
|
+
ports = {}
|
|
257
316
|
self.docker.run_container_interactive(
|
|
258
317
|
image_name=IMAGE_NAME,
|
|
259
|
-
tag="
|
|
318
|
+
tag="latest",
|
|
260
319
|
container_name=self.container_name,
|
|
261
320
|
command=cmd_str,
|
|
262
321
|
ports=ports,
|
|
263
322
|
volumes=volumes,
|
|
323
|
+
environment=LOCAL_DOCKER_ENV,
|
|
264
324
|
)
|
|
265
325
|
|
|
266
326
|
print("Exiting interactive mode")
|
|
@@ -270,9 +330,22 @@ class CompileServerImpl:
|
|
|
270
330
|
return self.docker.is_container_running(self.container_name)
|
|
271
331
|
|
|
272
332
|
def stop(self) -> None:
|
|
333
|
+
if self.docker.is_suspended:
|
|
334
|
+
return
|
|
273
335
|
if self.running_container:
|
|
274
336
|
self.running_container.detach()
|
|
275
337
|
self.running_container = None
|
|
276
338
|
self.docker.suspend_container(self.container_name)
|
|
277
339
|
self._port = 0
|
|
278
340
|
print("Compile server stopped")
|
|
341
|
+
|
|
342
|
+
def get_emsdk_headers(self, filepath: Path) -> None:
|
|
343
|
+
"""Get EMSDK headers ZIP data from the server and save to filepath."""
|
|
344
|
+
from fastled.util import download_emsdk_headers
|
|
345
|
+
|
|
346
|
+
if not self._port:
|
|
347
|
+
raise RuntimeError("Server has not been started yet")
|
|
348
|
+
if not self.ping():
|
|
349
|
+
raise RuntimeError("Server is not running")
|
|
350
|
+
|
|
351
|
+
download_emsdk_headers(self.url(), filepath)
|