fastled 1.2.68__tar.gz → 1.2.73__tar.gz
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-1.2.68 → fastled-1.2.73}/PKG-INFO +1 -1
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/__init__.py +1 -1
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/app.py +5 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/compile_server_impl.py +26 -16
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/docker_manager.py +112 -15
- fastled-1.2.73/src/fastled/keyz.py +84 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/open_browser.py +3 -13
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/parse_args.py +2 -1
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/string_diff.py +22 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/util.py +9 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled.egg-info/PKG-INFO +1 -1
- fastled-1.2.68/src/fastled/keyz.py +0 -31
- {fastled-1.2.68 → fastled-1.2.73}/.aiderignore +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.dockerignore +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/build_multi_docker_image.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/build_webpage.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/lint.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/publish_release.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/template_build_docker_image.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/test_build_exe.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/test_macos.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/test_ubuntu.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.github/workflows/test_win.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.gitignore +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.pylintrc +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.vscode/launch.json +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.vscode/settings.json +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/.vscode/tasks.json +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/Dockerfile +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/LICENSE +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/MANIFEST.in +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/README.md +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/RELEASE.md +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/TODO.md +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/build_exe.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/build_site.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/clean +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/CMakeLists.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/__init__.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/arduino-pre-process.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/build.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/build_archive.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/build_fast.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/code_sync.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/compile.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/compile_lock.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/entrypoint.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/extra/100dots.html +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/extra/demo_threejs.html +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/extra/micdemo.html +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/extra/mp3upload.html +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/extra/webgl_postprocessing_unreal_bloom.html +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/final_prewarm.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/init_runtime.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/install-arduino-cli.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/libcompile/CMakeLists.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/paths.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/pre-process.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/prewarm.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/process-ino.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/process_extended.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/pyproject.toml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/run.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/server.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/sketch_hasher.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/compiler/wasm_compiler_flags.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/docker-compose.yml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/install +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/install_linux.sh +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/lint +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/pyproject.toml +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/requirements.testing.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/setup.cfg +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/setup.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/assets/example.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/assets/localhost-key.pem +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/assets/localhost.pem +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/cli.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/cli_test.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/client_server.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/compile_server.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/filewatcher.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/interactive_srcs.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/keyboard.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/live_client.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/paths.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/project_init.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/select_sketch_directory.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/server_fastapi.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/server_fastapi_cli.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/server_flask.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/server_start.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/settings.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/site/build.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/site/examples.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/sketch.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/spinner.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/test/can_run_local_docker_tests.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/test/examples.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/types.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled/web_compile.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled.egg-info/SOURCES.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled.egg-info/dependency_links.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled.egg-info/entry_points.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled.egg-info/requires.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/src/fastled.egg-info/top_level.txt +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/test +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/integration/test_build_examples.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/integration/test_examples.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/html/index.html +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_api.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_bad_ino.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_cli.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_compile_server.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_docker_linux_on_windows.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_embedded_data.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_filechanger.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_http_server.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_ino/bad/bad.ino +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_ino/embedded/wasm.ino +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_ino/wasm/wasm.ino +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_project_init.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_server_and_client_seperatly.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_string_diff.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/tests/unit/test_webcompile.py +0 -0
- {fastled-1.2.68 → fastled-1.2.73}/upload_package.sh +0 -0
@@ -13,7 +13,7 @@ from .types import BuildMode, CompileResult, CompileServerError
|
|
13
13
|
# IMPORTANT! There's a bug in github which will REJECT any version update
|
14
14
|
# that has any other change in the repo. Please bump the version as the
|
15
15
|
# ONLY change in a commit, or else the pypi update and the release will fail.
|
16
|
-
__version__ = "1.2.
|
16
|
+
__version__ = "1.2.73"
|
17
17
|
|
18
18
|
DOCKER_FILE = (
|
19
19
|
"https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/Dockerfile"
|
@@ -43,6 +43,8 @@ def run_server(args: Args) -> int:
|
|
43
43
|
|
44
44
|
|
45
45
|
def main() -> int:
|
46
|
+
from fastled import __version__
|
47
|
+
|
46
48
|
args = parse_args()
|
47
49
|
interactive: bool = args.interactive
|
48
50
|
has_server = args.server
|
@@ -52,6 +54,9 @@ def main() -> int:
|
|
52
54
|
# directory: Path | None = Path(args.directory).absolute() if args.directory else None
|
53
55
|
directory: Path | None = Path(args.directory) if args.directory else None
|
54
56
|
|
57
|
+
# now it is safe to print out the version
|
58
|
+
print(f"FastLED version: {__version__}")
|
59
|
+
|
55
60
|
if update:
|
56
61
|
# Force auto_update to ensure update check happens
|
57
62
|
compile_server = CompileServer(interactive=False, auto_updates=True)
|
@@ -13,6 +13,7 @@ from fastled.docker_manager import (
|
|
13
13
|
Container,
|
14
14
|
DockerManager,
|
15
15
|
RunningContainer,
|
16
|
+
Volume,
|
16
17
|
)
|
17
18
|
from fastled.interactive_srcs import INTERACTIVE_SOURCES
|
18
19
|
from fastled.settings import DEFAULT_CONTAINER_NAME, IMAGE_NAME, SERVER_PORT
|
@@ -209,27 +210,32 @@ class CompileServerImpl:
|
|
209
210
|
else:
|
210
211
|
server_command = ["python", "/js/run.py", "server"] + SERVER_OPTIONS
|
211
212
|
ports = {80: port}
|
212
|
-
volumes =
|
213
|
+
volumes = []
|
213
214
|
if self.fastled_src_dir:
|
214
215
|
print(
|
215
216
|
f"Mounting FastLED source directory {self.fastled_src_dir} into container /host/fastled/src"
|
216
217
|
)
|
217
|
-
volumes
|
218
|
-
|
219
|
-
|
218
|
+
volumes.append(
|
219
|
+
Volume(
|
220
|
+
host_path=str(self.fastled_src_dir),
|
221
|
+
container_path="/host/fastled/src",
|
222
|
+
mode="ro",
|
223
|
+
)
|
224
|
+
)
|
220
225
|
if self.interactive:
|
221
226
|
# add the mapped directory to the container
|
222
227
|
print(f"Mounting {self.mapped_dir} into container /mapped")
|
223
|
-
# volumes = {str(self.mapped_dir): {"bind": "/mapped", "mode": "rw"}}
|
224
|
-
# add it
|
225
228
|
assert self.mapped_dir is not None
|
226
229
|
dir_name = self.mapped_dir.name
|
227
230
|
if not volumes:
|
228
|
-
volumes =
|
229
|
-
volumes
|
230
|
-
|
231
|
-
|
232
|
-
|
231
|
+
volumes = []
|
232
|
+
volumes.append(
|
233
|
+
Volume(
|
234
|
+
host_path=str(self.mapped_dir),
|
235
|
+
container_path=f"/mapped/{dir_name}",
|
236
|
+
mode="rw",
|
237
|
+
)
|
238
|
+
)
|
233
239
|
if self.fastled_src_dir is not None:
|
234
240
|
# to allow for interactive compilation
|
235
241
|
interactive_sources = list(INTERACTIVE_SOURCES)
|
@@ -237,11 +243,13 @@ class CompileServerImpl:
|
|
237
243
|
src_path = Path(src).absolute()
|
238
244
|
if src_path.exists():
|
239
245
|
print(f"Mounting {src} into container")
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
246
|
+
volumes.append(
|
247
|
+
Volume(
|
248
|
+
host_path=str(src_path),
|
249
|
+
container_path=f"/js/fastled/{src}",
|
250
|
+
mode="rw",
|
251
|
+
)
|
252
|
+
)
|
245
253
|
else:
|
246
254
|
print(f"Could not find {src}")
|
247
255
|
|
@@ -277,6 +285,8 @@ class CompileServerImpl:
|
|
277
285
|
return self.docker.is_container_running(self.container_name)
|
278
286
|
|
279
287
|
def stop(self) -> None:
|
288
|
+
if self.docker.is_suspended:
|
289
|
+
return
|
280
290
|
if self.running_container:
|
281
291
|
self.running_container.detach()
|
282
292
|
self.running_container = None
|
@@ -3,6 +3,7 @@ New abstraction for Docker management with improved Ctrl+C handling.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import _thread
|
6
|
+
import json
|
6
7
|
import os
|
7
8
|
import platform
|
8
9
|
import subprocess
|
@@ -11,6 +12,7 @@ import threading
|
|
11
12
|
import time
|
12
13
|
import traceback
|
13
14
|
import warnings
|
15
|
+
from dataclasses import dataclass
|
14
16
|
from datetime import datetime, timezone
|
15
17
|
from pathlib import Path
|
16
18
|
|
@@ -63,6 +65,40 @@ def get_lock(image_name: str) -> FileLock:
|
|
63
65
|
return out
|
64
66
|
|
65
67
|
|
68
|
+
@dataclass
|
69
|
+
class Volume:
|
70
|
+
"""
|
71
|
+
Represents a Docker volume mapping between host and container.
|
72
|
+
|
73
|
+
Attributes:
|
74
|
+
host_path: Path on the host system (e.g., "C:\\Users\\username\\project")
|
75
|
+
container_path: Path inside the container (e.g., "/app/data")
|
76
|
+
mode: Access mode, "rw" for read-write or "ro" for read-only
|
77
|
+
"""
|
78
|
+
|
79
|
+
host_path: str
|
80
|
+
container_path: str
|
81
|
+
mode: str = "rw"
|
82
|
+
|
83
|
+
def to_dict(self) -> dict[str, dict[str, str]]:
|
84
|
+
"""Convert the Volume object to the format expected by Docker API."""
|
85
|
+
return {self.host_path: {"bind": self.container_path, "mode": self.mode}}
|
86
|
+
|
87
|
+
@classmethod
|
88
|
+
def from_dict(cls, volume_dict: dict[str, dict[str, str]]) -> list["Volume"]:
|
89
|
+
"""Create Volume objects from a Docker volume dictionary."""
|
90
|
+
volumes = []
|
91
|
+
for host_path, config in volume_dict.items():
|
92
|
+
volumes.append(
|
93
|
+
cls(
|
94
|
+
host_path=host_path,
|
95
|
+
container_path=config["bind"],
|
96
|
+
mode=config.get("mode", "rw"),
|
97
|
+
)
|
98
|
+
)
|
99
|
+
return volumes
|
100
|
+
|
101
|
+
|
66
102
|
class RunningContainer:
|
67
103
|
def __init__(self, container, first_run=False):
|
68
104
|
self.container = container
|
@@ -104,10 +140,46 @@ class RunningContainer:
|
|
104
140
|
self.detach()
|
105
141
|
|
106
142
|
|
143
|
+
def _hack_to_fix_mac(volumes: list[Volume] | None) -> list[Volume] | None:
|
144
|
+
"""Fixes the volume mounts on MacOS by removing the mode."""
|
145
|
+
if volumes is None:
|
146
|
+
return None
|
147
|
+
if sys.platform != "darwin":
|
148
|
+
# Only macos needs hacking.
|
149
|
+
return volumes
|
150
|
+
|
151
|
+
volumes = volumes.copy()
|
152
|
+
# Work around a Docker bug on MacOS where the expected network socket to the
|
153
|
+
# the host is not mounted correctly. This was actually fixed in recent versions
|
154
|
+
# of docker client but there is a large chunk of Docker clients out there with
|
155
|
+
# this bug in it.
|
156
|
+
#
|
157
|
+
# This hack is done by mounting the socket directly to the container.
|
158
|
+
# This socket talks to the docker daemon on the host.
|
159
|
+
#
|
160
|
+
# Found here.
|
161
|
+
# https://github.com/docker/docker-py/issues/3069#issuecomment-1316778735
|
162
|
+
# if it exists already then return the input
|
163
|
+
for volume in volumes:
|
164
|
+
if volume.host_path == "/var/run/docker.sock":
|
165
|
+
return volumes
|
166
|
+
# ok it doesn't exist, so add it
|
167
|
+
volumes.append(
|
168
|
+
Volume(
|
169
|
+
host_path="/var/run/docker.sock",
|
170
|
+
container_path="/var/run/docker.sock",
|
171
|
+
mode="rw",
|
172
|
+
)
|
173
|
+
)
|
174
|
+
return volumes
|
175
|
+
|
176
|
+
|
107
177
|
class DockerManager:
|
108
178
|
def __init__(self) -> None:
|
109
179
|
from docker.errors import DockerException
|
110
180
|
|
181
|
+
self.is_suspended: bool = False
|
182
|
+
|
111
183
|
try:
|
112
184
|
self._client: DockerClient | None = None
|
113
185
|
self.first_run = False
|
@@ -314,8 +386,6 @@ class DockerManager:
|
|
314
386
|
|
315
387
|
# Quick check for latest version
|
316
388
|
with Spinner(f"Pulling newer version of {image_name}:{tag}..."):
|
317
|
-
# This needs to be swapped out using the the command line interface AI!
|
318
|
-
# _ = self.client.images.pull(image_name, tag=tag)
|
319
389
|
cmd_list = ["docker", "pull", f"{image_name}:{tag}"]
|
320
390
|
cmd_str = subprocess.list2cmdline(cmd_list)
|
321
391
|
print(f"Running command: {cmd_str}")
|
@@ -355,8 +425,8 @@ class DockerManager:
|
|
355
425
|
self,
|
356
426
|
container: Container,
|
357
427
|
command: str | None,
|
358
|
-
|
359
|
-
ports: dict | None,
|
428
|
+
volumes_dict: dict[str, dict[str, str]] | None,
|
429
|
+
ports: dict[int, int] | None,
|
360
430
|
) -> bool:
|
361
431
|
"""Compare if existing container has matching configuration"""
|
362
432
|
try:
|
@@ -386,7 +456,7 @@ class DockerManager:
|
|
386
456
|
return False
|
387
457
|
|
388
458
|
# Check volumes if specified
|
389
|
-
if
|
459
|
+
if volumes_dict:
|
390
460
|
container_mounts = (
|
391
461
|
{
|
392
462
|
m["Source"]: {"bind": m["Destination"], "mode": m["Mode"]}
|
@@ -396,7 +466,7 @@ class DockerManager:
|
|
396
466
|
else {}
|
397
467
|
)
|
398
468
|
|
399
|
-
for host_dir, mount in
|
469
|
+
for host_dir, mount in volumes_dict.items():
|
400
470
|
if host_dir not in container_mounts:
|
401
471
|
print(f"Volume {host_dir} not found in container mounts.")
|
402
472
|
return False
|
@@ -446,7 +516,7 @@ class DockerManager:
|
|
446
516
|
tag: str,
|
447
517
|
container_name: str,
|
448
518
|
command: str | None = None,
|
449
|
-
volumes:
|
519
|
+
volumes: list[Volume] | None = None,
|
450
520
|
ports: dict[int, int] | None = None,
|
451
521
|
remove_previous: bool = False,
|
452
522
|
) -> Container:
|
@@ -455,11 +525,23 @@ class DockerManager:
|
|
455
525
|
If it exists with different config, remove and recreate it.
|
456
526
|
|
457
527
|
Args:
|
458
|
-
volumes:
|
459
|
-
Example: {'/host/path': {'bind': '/container/path', 'mode': 'rw'}}
|
528
|
+
volumes: List of Volume objects for container volume mappings
|
460
529
|
ports: Dict mapping host ports to container ports
|
461
530
|
Example: {8080: 80} maps host port 8080 to container port 80
|
462
531
|
"""
|
532
|
+
volumes = _hack_to_fix_mac(volumes)
|
533
|
+
# Convert volumes to the format expected by Docker API
|
534
|
+
volumes_dict = None
|
535
|
+
if volumes is not None:
|
536
|
+
volumes_dict = {}
|
537
|
+
for volume in volumes:
|
538
|
+
volumes_dict.update(volume.to_dict())
|
539
|
+
|
540
|
+
# Serialize the volumes to a json string
|
541
|
+
if volumes_dict:
|
542
|
+
volumes_str = json.dumps(volumes_dict)
|
543
|
+
print(f"Volumes: {volumes_str}")
|
544
|
+
print("Done")
|
463
545
|
image_name = f"{image_name}:{tag}"
|
464
546
|
try:
|
465
547
|
container: Container = self.client.containers.get(container_name)
|
@@ -469,7 +551,9 @@ class DockerManager:
|
|
469
551
|
container.remove(force=True)
|
470
552
|
raise NotFound("Container removed due to remove_previous")
|
471
553
|
# Check if configuration matches
|
472
|
-
elif not self._container_configs_match(
|
554
|
+
elif not self._container_configs_match(
|
555
|
+
container, command, volumes_dict, ports
|
556
|
+
):
|
473
557
|
print(
|
474
558
|
f"Container {container_name} exists but with different configuration. Removing and recreating..."
|
475
559
|
)
|
@@ -517,7 +601,7 @@ class DockerManager:
|
|
517
601
|
name=container_name,
|
518
602
|
detach=True,
|
519
603
|
tty=True,
|
520
|
-
volumes=
|
604
|
+
volumes=volumes_dict,
|
521
605
|
ports=ports, # type: ignore
|
522
606
|
remove=True,
|
523
607
|
)
|
@@ -529,9 +613,16 @@ class DockerManager:
|
|
529
613
|
tag: str,
|
530
614
|
container_name: str,
|
531
615
|
command: str | None = None,
|
532
|
-
volumes:
|
616
|
+
volumes: list[Volume] | None = None,
|
533
617
|
ports: dict[int, int] | None = None,
|
534
618
|
) -> None:
|
619
|
+
# Convert volumes to the format expected by Docker API
|
620
|
+
volumes = _hack_to_fix_mac(volumes)
|
621
|
+
volumes_dict = None
|
622
|
+
if volumes is not None:
|
623
|
+
volumes_dict = {}
|
624
|
+
for volume in volumes:
|
625
|
+
volumes_dict.update(volume.to_dict())
|
535
626
|
# Remove existing container
|
536
627
|
try:
|
537
628
|
container: Container = self.client.containers.get(container_name)
|
@@ -548,9 +639,13 @@ class DockerManager:
|
|
548
639
|
"--name",
|
549
640
|
container_name,
|
550
641
|
]
|
551
|
-
if
|
552
|
-
for host_dir, mount in
|
553
|
-
|
642
|
+
if volumes_dict:
|
643
|
+
for host_dir, mount in volumes_dict.items():
|
644
|
+
docker_volume_arg = [
|
645
|
+
"-v",
|
646
|
+
f"{host_dir}:{mount['bind']}:{mount['mode']}",
|
647
|
+
]
|
648
|
+
docker_command.extend(docker_volume_arg)
|
554
649
|
if ports:
|
555
650
|
for host_port, container_port in ports.items():
|
556
651
|
docker_command.extend(["-p", f"{host_port}:{container_port}"])
|
@@ -591,6 +686,8 @@ class DockerManager:
|
|
591
686
|
"""
|
592
687
|
Suspend (pause) the container.
|
593
688
|
"""
|
689
|
+
if self.is_suspended:
|
690
|
+
return
|
594
691
|
if isinstance(container, str):
|
595
692
|
container_name = container
|
596
693
|
# container = self.get_container(container)
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# This was an experiment for https://localhost
|
2
|
+
# Important for audio sampling from sites like Youtube or an app like Audacity.
|
3
|
+
# However, pkg_resources does not work in the exe version of this app.
|
4
|
+
# For this to work pyinstaller needs special handling (probably a spec-file)
|
5
|
+
# in order to properly package up external resources.
|
6
|
+
|
7
|
+
|
8
|
+
from dataclasses import dataclass
|
9
|
+
|
10
|
+
_ENABLE_SSL_CONFIG = False
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass
|
14
|
+
class SslConfig:
|
15
|
+
cert: str
|
16
|
+
key: str
|
17
|
+
|
18
|
+
|
19
|
+
def get_ssl_config() -> SslConfig | None:
|
20
|
+
"""Get the keys for the server"""
|
21
|
+
if not _ENABLE_SSL_CONFIG:
|
22
|
+
return None
|
23
|
+
return SslConfig(
|
24
|
+
cert=_CERT,
|
25
|
+
key=_PRIVATE_KEY,
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
_PRIVATE_KEY = """-----BEGIN PRIVATE KEY-----
|
30
|
+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDlxbWcpUXPpjqs
|
31
|
+
DJPgFF1FsXPZqq0JPJqssHh4ZLfN0h4yJmj+kRcHS+pkgXnG46g6bUcL/AK5Ba08
|
32
|
+
vwnUUGkPH0v4ShKiAGYwvOcbWaqTmvvJuIoaDBXh2jSCeOTagNoaHLYEugARkkEu
|
33
|
+
0/FEW5P/79wU5vJ5G+SyZ8rBCVdxlU57pL1hKWBU7K+BLWsCiZ308NMpzHF5APZ6
|
34
|
+
YxVjhFosJPr4TjN6yXr+whrsAjSTHamD5690MbXWyyPG0jwPQyjBot/cNtt8GrsN
|
35
|
+
gcjA1E+8VKFvxO8RvZanMZLb0CGEpt7u3oaJ/jprHEsw+/UhnG6Qhksm8C/DN9kP
|
36
|
+
hselewffAgMBAAECggEARjQ6YTo+Mkvf8WGGbRjLxteJRiBX7lKOD+V7aY2ce06P
|
37
|
+
21LREbbTCm+vljXZN2OnqvJomsjNLCsH21+jaTOIZg5x79LyDn2Au7N8CWdELwVT
|
38
|
+
mTbBO2Ql63P4R0UY54onGYNcOeV6z+OX9u7a8L/qYHCxFdHalBZpsfj0gjaQeStJ
|
39
|
+
JSnvGjo6tKkwC/nUmX01qEVQgUO1+39WYqCaIWjijZNXt6XiKclEuu1AkL0u6Mpt
|
40
|
+
CzvzEDrEA66D0Lvl3Tek9B4O16Oie5anNnNMHigwU9yVc6dI8vDCRSEiz7laPTFK
|
41
|
+
xzOCQmqPGClKXkX3U+OvZp/Ss9U26Wpu0AbRKTvzAQKBgQDsMR9NjMpOmUaWkAwl
|
42
|
+
1wlUxsZ9YkRuTy7R3RfIdYWj6Lcoc4/iN0qILFM7xidkHhYTFqnsnP1SQkV6lEHV
|
43
|
+
OalYxZu9F2l1rHPc8G5YWh/KOg1rAEI47MVT4iwhA2fw6JLti/rm25AeSTMjSTqu
|
44
|
+
ht3146036opcIF3v86oGUrSXDwKBgQD5CsNcwLeUDGXozjq62T8/mTYwd2Tw3aiY
|
45
|
+
KaGp+exAW321vYm5SKsMitBMGU2tGFlv5eptSI48h7SCpgnszaexw7yj30KuvqjG
|
46
|
+
bBqq/MsKuXHyn2sG0A7MJ6zfk+4l46B45blDJZ+x7xL0dyS4UCU3zUeesgSGo4zK
|
47
|
+
ZOspPIQCMQKBgQCk35VuWP1P6IbxyxPvxi/pUeh01gfWyMdyD9fuQrtLM8PHJQQn
|
48
|
+
cVlBvU9MxoHwzV+za3qqhNwAc+p0KtHZuiqQoUCZuqIPVpZ6gAtG+YJ/dA6xxrhz
|
49
|
+
bDRC3frYALyp2m/WCoTWaiYsPgTIePHRqqt+XbQo+DwlGyL3wSvKxijx2QKBgCb0
|
50
|
+
OwioEE70/X/DukX9szn0chh0pHJUiYl7gZD/yadraCdkRUWZC0BD+j7c+lxn4Z1y
|
51
|
+
HhAH+E+Zfm+tHwJOTLuufTQ4uMpygh2/TRCPyAaeaSdlLi17n8TpM84o6mg8yZ3/
|
52
|
+
eNH68Za4aYOZm0HFL30h++DjwXd534zM6keh8pgRAoGBAKUrsjDGjuSo8l1fi4Cq
|
53
|
+
INu/rQop2h/db02zyJP5q7NKhE1nqogeLwwn+2M/LtHQ1nIzZR+rvrLNgt6oWY31
|
54
|
+
sPsv8JUfVT8GmdhU9KKmizK6eUu3rWdj2+rJARmuEaPmHcD5O6oJaGU0qadqQP34
|
55
|
+
H+enwWmpyZXAIbEu/q63DFhV
|
56
|
+
-----END PRIVATE KEY-----"""
|
57
|
+
|
58
|
+
_CERT = """-----BEGIN _CERTIFICATE-----
|
59
|
+
MIIEfTCCAuWgAwIBAgIRAPb7jkLrCuqToG+s3AQYeuUwDQYJKoZIhvcNAQELBQAw
|
60
|
+
gakxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTE/MD0GA1UECww2REVT
|
61
|
+
S1RPUC1JMzcxOERPXFphY2ggVm9yaGllc0BERVNLVE9QLUkzNzE4RE8gKG5pdGVy
|
62
|
+
aXMpMUYwRAYDVQQDDD1ta2NlcnQgREVTS1RPUC1JMzcxOERPXFphY2ggVm9yaGll
|
63
|
+
c0BERVNLVE9QLUkzNzE4RE8gKG5pdGVyaXMpMB4XDTI1MDQyODAwMzk1MFoXDTI3
|
64
|
+
MDcyODAwMzk1MFowajEnMCUGA1UEChMebWtjZXJ0IGRldmVsb3BtZW50IGNlcnRp
|
65
|
+
ZmljYXRlMT8wPQYDVQQLDDZERVNLVE9QLUkzNzE4RE9cWmFjaCBWb3JoaWVzQERF
|
66
|
+
U0tUT1AtSTM3MThETyAobml0ZXJpcykwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
67
|
+
ggEKAoIBAQDlxbWcpUXPpjqsDJPgFF1FsXPZqq0JPJqssHh4ZLfN0h4yJmj+kRcH
|
68
|
+
S+pkgXnG46g6bUcL/AK5Ba08vwnUUGkPH0v4ShKiAGYwvOcbWaqTmvvJuIoaDBXh
|
69
|
+
2jSCeOTagNoaHLYEugARkkEu0/FEW5P/79wU5vJ5G+SyZ8rBCVdxlU57pL1hKWBU
|
70
|
+
7K+BLWsCiZ308NMpzHF5APZ6YxVjhFosJPr4TjN6yXr+whrsAjSTHamD5690MbXW
|
71
|
+
yyPG0jwPQyjBot/cNtt8GrsNgcjA1E+8VKFvxO8RvZanMZLb0CGEpt7u3oaJ/jpr
|
72
|
+
HEsw+/UhnG6Qhksm8C/DN9kPhselewffAgMBAAGjXjBcMA4GA1UdDwEB/wQEAwIF
|
73
|
+
oDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBSPBydvhr9wI+FsoW/H
|
74
|
+
WK3DbS8IUDAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggGB
|
75
|
+
AJVrF1yczZaxt+A2AhdeFbJQUR6NzGBTc20YeWF1YzLV5sV3QVumwZLP2M9ggRgd
|
76
|
+
xWV0xfwUHobFQk6RIPTADcLKctiurql0cgF4DPnpWVvto9RM00U3AkQcMj3xtKBV
|
77
|
+
wUqo83TcbqgL+euudFZ09gGTs9u9AENaZPcMh+rW8DDO92t+EwMI/IfopxVOJGUB
|
78
|
+
RSM3yTwV93BMYBuddt8mclzLzPK/1WONfsHU2xEascaHR1tYMOmJN9Vq4o0fzWxo
|
79
|
+
a2vI6K0aJqZV/ztdXq3akwLc6/e9hyptHWa0i/022xVCyNWIlnuEhT7ENMPxh6rX
|
80
|
+
ZCQCZVnhcSWAyFjggLJql3aSID5fPF8rmN7wWsB/I5pl9qwMR1/THMPrm5aWn1Xj
|
81
|
+
xW6PxkSGm73kd57DH7tqm5HTd8eYCbnsFofI9rC7xI6HCfwchKp+YHvIEu/LJ56E
|
82
|
+
FLnCZW/orYkHCzWntzxv1bddrw1BwaNR8Q+mu3imRP8fuyXb2UkFkINVVyOOWHuW
|
83
|
+
Kw==
|
84
|
+
-----END _CERTIFICATE-----"""
|
@@ -8,7 +8,6 @@ from fastled.keyz import get_ssl_config
|
|
8
8
|
|
9
9
|
DEFAULT_PORT = 8089 # different than live version.
|
10
10
|
PYTHON_EXE = sys.executable
|
11
|
-
SSL_CONFIG = get_ssl_config()
|
12
11
|
|
13
12
|
|
14
13
|
# print(f"SSL Config: {SSL_CONFIG.certfile}, {SSL_CONFIG.keyfile}")
|
@@ -21,6 +20,7 @@ def _open_http_server_subprocess(
|
|
21
20
|
print("\n################################################################")
|
22
21
|
print(f"# Opening browser to {fastled_js} on port {port}")
|
23
22
|
print("################################################################\n")
|
23
|
+
ssl = get_ssl_config()
|
24
24
|
try:
|
25
25
|
# Fallback to our Python server
|
26
26
|
cmd = [
|
@@ -32,18 +32,8 @@ def _open_http_server_subprocess(
|
|
32
32
|
str(port),
|
33
33
|
]
|
34
34
|
# Pass SSL flags if available
|
35
|
-
if
|
36
|
-
|
37
|
-
[
|
38
|
-
"--cert",
|
39
|
-
str(SSL_CONFIG.certfile),
|
40
|
-
"--key",
|
41
|
-
str(SSL_CONFIG.keyfile),
|
42
|
-
]
|
43
|
-
)
|
44
|
-
print(
|
45
|
-
f"Running server on port {port} with certs: {SSL_CONFIG.certfile}, {SSL_CONFIG.keyfile}"
|
46
|
-
)
|
35
|
+
if ssl:
|
36
|
+
raise NotImplementedError("SSL is not implemented yet")
|
47
37
|
print(f"Running server on port {port}.")
|
48
38
|
print(f"Command: {subprocess.list2cmdline(cmd)}")
|
49
39
|
# Suppress output
|
@@ -3,7 +3,6 @@ import os
|
|
3
3
|
import sys
|
4
4
|
from pathlib import Path
|
5
5
|
|
6
|
-
from fastled import __version__
|
7
6
|
from fastled.project_init import project_init
|
8
7
|
from fastled.select_sketch_directory import select_sketch_directory
|
9
8
|
from fastled.settings import DEFAULT_URL, IMAGE_NAME
|
@@ -27,6 +26,8 @@ def _find_fastled_repo(start: Path) -> Path | None:
|
|
27
26
|
|
28
27
|
def parse_args() -> Args:
|
29
28
|
"""Parse command-line arguments."""
|
29
|
+
from fastled import __version__
|
30
|
+
|
30
31
|
parser = argparse.ArgumentParser(description=f"FastLED WASM Compiler {__version__}")
|
31
32
|
parser.add_argument("--version", action="version", version=f"{__version__}")
|
32
33
|
parser.add_argument(
|
@@ -3,6 +3,24 @@ from pathlib import Path
|
|
3
3
|
from rapidfuzz import fuzz
|
4
4
|
|
5
5
|
|
6
|
+
def _filter_out_obvious_bad_choices(
|
7
|
+
input_str: str, string_list: list[str]
|
8
|
+
) -> list[str]:
|
9
|
+
"""
|
10
|
+
Filter out strings that are too different from the input string.
|
11
|
+
This is a heuristic and may not be perfect.
|
12
|
+
"""
|
13
|
+
input_chars = set(input_str)
|
14
|
+
filtered_list = []
|
15
|
+
for s in string_list:
|
16
|
+
# Check if at least half of the input characters are in the string
|
17
|
+
s_chars = set(s)
|
18
|
+
common_chars = input_chars.intersection(s_chars)
|
19
|
+
if len(common_chars) >= len(input_chars) / 2:
|
20
|
+
filtered_list.append(s)
|
21
|
+
return filtered_list
|
22
|
+
|
23
|
+
|
6
24
|
# Returns the min distance strings. If there is a tie, it returns
|
7
25
|
# all the strings that have the same min distance.
|
8
26
|
# Returns a tuple of index and string.
|
@@ -24,6 +42,10 @@ def string_diff(
|
|
24
42
|
string_list = [s.lower() for s in string_list]
|
25
43
|
input_string = input_string.lower()
|
26
44
|
|
45
|
+
# Apply set membership filtering for queries with 3+ characters
|
46
|
+
if len(input_string) >= 3:
|
47
|
+
string_list = _filter_out_obvious_bad_choices(input_string, string_list)
|
48
|
+
|
27
49
|
is_substring = False
|
28
50
|
for s in string_list:
|
29
51
|
if input_string in s:
|
@@ -8,3 +8,12 @@ def hash_file(file_path: Path) -> str:
|
|
8
8
|
for chunk in iter(lambda: f.read(4096), b""):
|
9
9
|
hasher.update(chunk)
|
10
10
|
return hasher.hexdigest()
|
11
|
+
|
12
|
+
|
13
|
+
def banner_string(msg: str) -> str:
|
14
|
+
"""
|
15
|
+
Return `msg` surrounded by a border of # characters, including
|
16
|
+
leading and trailing newlines.
|
17
|
+
"""
|
18
|
+
border = "#" * (len(msg) + 4)
|
19
|
+
return f"\n{border}\n# {msg}\n{border}\n"
|
@@ -1,31 +0,0 @@
|
|
1
|
-
import importlib.resources as pkg_resources
|
2
|
-
from dataclasses import dataclass
|
3
|
-
from pathlib import Path
|
4
|
-
|
5
|
-
|
6
|
-
@dataclass
|
7
|
-
class SslConfig:
|
8
|
-
certfile: Path
|
9
|
-
keyfile: Path
|
10
|
-
|
11
|
-
|
12
|
-
def get_asset_path(filename: str) -> Path | None:
|
13
|
-
"""Locate a file from the fastled.assets package resources."""
|
14
|
-
try:
|
15
|
-
resource = pkg_resources.files("fastled.assets").joinpath(filename)
|
16
|
-
# Convert to Path for file-system access
|
17
|
-
path = Path(str(resource))
|
18
|
-
return path if path.exists() else None
|
19
|
-
except (ModuleNotFoundError, AttributeError):
|
20
|
-
return None
|
21
|
-
|
22
|
-
|
23
|
-
def get_ssl_config() -> SslConfig | None:
|
24
|
-
"""Get the keys for the server"""
|
25
|
-
# certfile = get_asset_path("localhost-key.pem")
|
26
|
-
# keyfile = get_asset_path("localhost.pem")
|
27
|
-
# if certfile is None or keyfile is None:
|
28
|
-
# raise ValueError("Could not find keys for server")
|
29
|
-
# # return certfile, keyfile
|
30
|
-
# return SslConfig(certfile=certfile, keyfile=keyfile)
|
31
|
-
return None
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|