fastled 1.2.75__tar.gz → 1.2.77__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.75 → fastled-1.2.77}/PKG-INFO +1 -1
- {fastled-1.2.75 → fastled-1.2.77}/compiler/compile.py +24 -4
- {fastled-1.2.75 → fastled-1.2.77}/pyproject.toml +2 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/__init__.py +3 -6
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/app.py +28 -10
- fastled-1.2.77/src/fastled/cli_test_interactive.py +21 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/compile_server_impl.py +39 -1
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/docker_manager.py +2 -2
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/parse_args.py +27 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/print_filter.py +43 -15
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/settings.py +4 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/types.py +7 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/web_compile.py +38 -2
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled.egg-info/PKG-INFO +1 -1
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled.egg-info/SOURCES.txt +1 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_bad_ino.py +9 -1
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_print_filter.py +6 -4
- {fastled-1.2.75 → fastled-1.2.77}/.aiderignore +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.dockerignore +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/build_multi_docker_image.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/build_webpage.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/lint.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/publish_release.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/template_build_docker_image.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/test_build_exe.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/test_macos.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/test_ubuntu.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.github/workflows/test_win.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.gitignore +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.pylintrc +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.vscode/launch.json +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.vscode/settings.json +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/.vscode/tasks.json +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/Dockerfile +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/LICENSE +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/MANIFEST.in +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/README.md +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/RELEASE.md +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/TODO.md +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/build_exe.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/build_site.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/clean +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/CMakeLists.txt +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/__init__.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/arduino-pre-process.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/build.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/build_archive.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/build_fast.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/code_sync.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/compile_lock.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/entrypoint.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/extra/100dots.html +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/extra/demo_threejs.html +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/extra/micdemo.html +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/extra/mp3upload.html +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/extra/webgl_postprocessing_unreal_bloom.html +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/final_prewarm.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/init_runtime.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/install-arduino-cli.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/libcompile/CMakeLists.txt +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/paths.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/pre-process.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/prewarm.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/process-ino.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/process_extended.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/pyproject.toml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/run.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/server.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/sketch_hasher.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/compiler/wasm_compiler_flags.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/docker-compose.yml +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/install +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/install_linux.sh +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/lint +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/requirements.testing.txt +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/setup.cfg +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/setup.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/assets/example.txt +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/assets/localhost-key.pem +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/assets/localhost.pem +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/cli.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/cli_test.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/client_server.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/compile_server.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/filewatcher.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/interactive_srcs.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/keyboard.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/keyz.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/live_client.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/open_browser.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/paths.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/project_init.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/select_sketch_directory.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/server_fastapi.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/server_fastapi_cli.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/server_flask.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/server_start.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/site/build.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/site/examples.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/sketch.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/spinner.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/string_diff.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/test/can_run_local_docker_tests.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/test/examples.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled/util.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled.egg-info/dependency_links.txt +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled.egg-info/entry_points.txt +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled.egg-info/requires.txt +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/src/fastled.egg-info/top_level.txt +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/test +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/integration/test_build_examples.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/integration/test_examples.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/html/index.html +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_api.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_cli.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_compile_server.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_docker_linux_on_windows.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_embedded_data.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_filechanger.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_http_server.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_ino/bad/bad.ino +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_ino/embedded/wasm.ino +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_ino/wasm/wasm.ino +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_project_init.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_server_and_client_seperatly.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_string_diff.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/tests/unit/test_webcompile.py +0 -0
- {fastled-1.2.75 → fastled-1.2.77}/upload_package.sh +0 -0
@@ -116,6 +116,23 @@ def _banner(msg: str) -> str:
|
|
116
116
|
return banner
|
117
117
|
|
118
118
|
|
119
|
+
def _chunked_print(text: str, lines_per_print: int = 10) -> None:
|
120
|
+
"""Prints the text in chunks of the specified size."""
|
121
|
+
lines = text.splitlines()
|
122
|
+
buffer: list[str] = []
|
123
|
+
|
124
|
+
def flush() -> None:
|
125
|
+
if buffer:
|
126
|
+
print("\n".join(buffer))
|
127
|
+
buffer.clear()
|
128
|
+
|
129
|
+
for line in lines:
|
130
|
+
buffer.append(line)
|
131
|
+
if len(buffer) >= lines_per_print:
|
132
|
+
flush()
|
133
|
+
flush()
|
134
|
+
|
135
|
+
|
119
136
|
def compile(
|
120
137
|
compiler_root: Path, build_mode: BuildMode, auto_clean: bool, no_platformio: bool
|
121
138
|
) -> int:
|
@@ -140,7 +157,11 @@ def compile(
|
|
140
157
|
cmd_list.append("-v")
|
141
158
|
|
142
159
|
def _open_process(cmd_list: list[str] = cmd_list) -> subprocess.Popen:
|
143
|
-
print(
|
160
|
+
print(
|
161
|
+
_banner(
|
162
|
+
"Build started with command:\n " + subprocess.list2cmdline(cmd_list)
|
163
|
+
)
|
164
|
+
)
|
144
165
|
out = subprocess.Popen(
|
145
166
|
cmd_list,
|
146
167
|
cwd=compiler_root,
|
@@ -159,12 +180,11 @@ def compile(
|
|
159
180
|
assert process.stdout is not None
|
160
181
|
line: str
|
161
182
|
for line in process.stdout:
|
162
|
-
|
163
|
-
timestamped_line = _timestamp_output(processed_line)
|
183
|
+
timestamped_line = _timestamp_output(line)
|
164
184
|
output_lines.append(timestamped_line)
|
165
185
|
process.wait()
|
166
186
|
relative_output = _make_timestamps_relative("\n".join(output_lines))
|
167
|
-
|
187
|
+
_chunked_print(relative_output)
|
168
188
|
if process.returncode == 0:
|
169
189
|
print(_banner(f"Compilation successful on attempt {attempt}"))
|
170
190
|
return 0
|
@@ -15,11 +15,13 @@ dependencies = [
|
|
15
15
|
"httpx>=0.28.1",
|
16
16
|
"watchdog>=6.0.0",
|
17
17
|
"download>=0.3.5",
|
18
|
+
########## Begin Docker Manager Dependencies
|
18
19
|
"filelock>=3.16.1",
|
19
20
|
"disklru>=2.0.1",
|
20
21
|
"appdirs>=1.4.4",
|
21
22
|
"rapidfuzz>=3.10.1",
|
22
23
|
"progress>=1.6",
|
24
|
+
########## End Docker Manager Dependencies
|
23
25
|
"fastapi>=0.115.12",
|
24
26
|
"uvicorn>=0.34.2",
|
25
27
|
"pywebview>=5.4",
|
@@ -7,17 +7,14 @@ from typing import Generator
|
|
7
7
|
|
8
8
|
from .compile_server import CompileServer
|
9
9
|
from .live_client import LiveClient
|
10
|
+
from .settings import DOCKER_FILE, IMAGE_NAME
|
10
11
|
from .site.build import build
|
11
12
|
from .types import BuildMode, CompileResult, CompileServerError
|
12
13
|
|
13
14
|
# IMPORTANT! There's a bug in github which will REJECT any version update
|
14
15
|
# that has any other change in the repo. Please bump the version as the
|
15
16
|
# ONLY change in a commit, or else the pypi update and the release will fail.
|
16
|
-
__version__ = "1.2.
|
17
|
-
|
18
|
-
DOCKER_FILE = (
|
19
|
-
"https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/Dockerfile"
|
20
|
-
)
|
17
|
+
__version__ = "1.2.77"
|
21
18
|
|
22
19
|
|
23
20
|
class Api:
|
@@ -154,7 +151,6 @@ class Docker:
|
|
154
151
|
@staticmethod
|
155
152
|
def purge() -> None:
|
156
153
|
from fastled.docker_manager import DockerManager
|
157
|
-
from fastled.settings import IMAGE_NAME
|
158
154
|
|
159
155
|
docker_mgr = DockerManager()
|
160
156
|
docker_mgr.purge(image_name=IMAGE_NAME)
|
@@ -217,4 +213,5 @@ __all__ = [
|
|
217
213
|
"CompileResult",
|
218
214
|
"CompileServerError",
|
219
215
|
"BuildMode",
|
216
|
+
"DOCKER_FILE",
|
220
217
|
]
|
@@ -68,19 +68,37 @@ def main() -> int:
|
|
68
68
|
print("Building is disabled")
|
69
69
|
build = False
|
70
70
|
|
71
|
-
if
|
72
|
-
raise NotImplementedError("Building is not yet supported.")
|
71
|
+
if interactive:
|
72
|
+
# raise NotImplementedError("Building is not yet supported.")
|
73
73
|
file_watcher_set(False)
|
74
|
-
project_root = Path(".").absolute()
|
75
|
-
print(f"Building Docker image at {project_root}")
|
76
|
-
from fastled import Api
|
77
|
-
|
78
|
-
server = Docker.spawn_server_from_fastled_repo(
|
79
|
-
|
74
|
+
# project_root = Path(".").absolute()
|
75
|
+
# print(f"Building Docker image at {project_root}")
|
76
|
+
from fastled import Api
|
77
|
+
|
78
|
+
# server = Docker.spawn_server_from_fastled_repo(
|
79
|
+
# project_root=project_root,
|
80
|
+
# interactive=interactive,
|
81
|
+
# sketch_folder=directory,
|
82
|
+
# )
|
83
|
+
# assert isinstance(server, CompileServer)
|
84
|
+
server: CompileServer = CompileServer(
|
80
85
|
interactive=interactive,
|
81
|
-
|
86
|
+
auto_updates=False,
|
87
|
+
mapped_dir=directory,
|
88
|
+
auto_start=False,
|
89
|
+
remove_previous=False,
|
82
90
|
)
|
83
|
-
|
91
|
+
|
92
|
+
server.start(wait_for_startup=False)
|
93
|
+
|
94
|
+
try:
|
95
|
+
while server.process_running():
|
96
|
+
# wait for ctrl-c
|
97
|
+
time.sleep(0.1)
|
98
|
+
except KeyboardInterrupt:
|
99
|
+
print("\nExiting from server...")
|
100
|
+
server.stop()
|
101
|
+
return 0
|
84
102
|
|
85
103
|
try:
|
86
104
|
if interactive:
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import sys
|
2
|
+
|
3
|
+
from fastled.app import main as app_main
|
4
|
+
|
5
|
+
if __name__ == "__main__":
|
6
|
+
# Note that the entry point for the exe is in cli.py
|
7
|
+
try:
|
8
|
+
import os
|
9
|
+
|
10
|
+
os.chdir("../fastled")
|
11
|
+
# sys.argv.append("--server")
|
12
|
+
# sys.argv.append("--local")
|
13
|
+
sys.argv.append("examples/FxWave2d")
|
14
|
+
sys.argv.append("-i")
|
15
|
+
sys.exit(app_main())
|
16
|
+
except KeyboardInterrupt:
|
17
|
+
print("\nExiting from main...")
|
18
|
+
sys.exit(1)
|
19
|
+
except Exception as e:
|
20
|
+
print(f"Error: {e}")
|
21
|
+
sys.exit(1)
|
@@ -37,6 +37,32 @@ def _try_get_fastled_src(path: Path) -> Path | None:
|
|
37
37
|
return None
|
38
38
|
|
39
39
|
|
40
|
+
def _port_is_free(port: int) -> bool:
|
41
|
+
"""Check if a port is free."""
|
42
|
+
import socket
|
43
|
+
|
44
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
45
|
+
try:
|
46
|
+
sock.bind(("localhost", port)) and sock.bind(("0.0.0.0", port))
|
47
|
+
return True
|
48
|
+
except OSError:
|
49
|
+
return False
|
50
|
+
|
51
|
+
|
52
|
+
def _find_free_port() -> int:
|
53
|
+
"""Find a free port on the system."""
|
54
|
+
|
55
|
+
start_port = 49152
|
56
|
+
tries = 10
|
57
|
+
|
58
|
+
for port in range(start_port, start_port + tries):
|
59
|
+
if _port_is_free(port):
|
60
|
+
return port
|
61
|
+
raise RuntimeError(
|
62
|
+
f"No free port found in the range {start_port}-{start_port + tries - 1}"
|
63
|
+
)
|
64
|
+
|
65
|
+
|
40
66
|
class CompileServerImpl:
|
41
67
|
def __init__(
|
42
68
|
self,
|
@@ -202,6 +228,7 @@ class CompileServerImpl:
|
|
202
228
|
image_name=IMAGE_NAME, tag="latest", upgrade=upgrade
|
203
229
|
)
|
204
230
|
DISK_CACHE.put("last-update", now_str)
|
231
|
+
CLIENT_PORT = 80 # TODO: Don't use port 80.
|
205
232
|
|
206
233
|
print("Docker image now validated")
|
207
234
|
port = SERVER_PORT
|
@@ -209,7 +236,11 @@ class CompileServerImpl:
|
|
209
236
|
server_command = ["/bin/bash"]
|
210
237
|
else:
|
211
238
|
server_command = ["python", "/js/run.py", "server"] + SERVER_OPTIONS
|
212
|
-
|
239
|
+
if self.interactive:
|
240
|
+
print("Disabling port forwarding in interactive mode")
|
241
|
+
ports = {}
|
242
|
+
else:
|
243
|
+
ports = {CLIENT_PORT: port}
|
213
244
|
volumes = []
|
214
245
|
if self.fastled_src_dir:
|
215
246
|
print(
|
@@ -269,6 +300,13 @@ class CompileServerImpl:
|
|
269
300
|
print("Compile server starting")
|
270
301
|
return port
|
271
302
|
else:
|
303
|
+
client_port_mapped = CLIENT_PORT in ports
|
304
|
+
port_is_free = _port_is_free(CLIENT_PORT)
|
305
|
+
if client_port_mapped and port_is_free:
|
306
|
+
warnings.warn(
|
307
|
+
f"Can't expose port {CLIENT_PORT}, disabling port forwarding in interactive mode"
|
308
|
+
)
|
309
|
+
ports = {}
|
272
310
|
self.docker.run_container_interactive(
|
273
311
|
image_name=IMAGE_NAME,
|
274
312
|
tag="latest",
|
@@ -25,7 +25,7 @@ from docker.models.containers import Container
|
|
25
25
|
from docker.models.images import Image
|
26
26
|
from filelock import FileLock
|
27
27
|
|
28
|
-
from fastled.print_filter import PrintFilter
|
28
|
+
from fastled.print_filter import PrintFilter, PrintFilterFastled
|
29
29
|
from fastled.spinner import Spinner
|
30
30
|
|
31
31
|
CONFIG_DIR = Path(user_data_dir("fastled", "fastled"))
|
@@ -103,7 +103,7 @@ class Volume:
|
|
103
103
|
# Override the default PrintFilter to use a custom one.
|
104
104
|
def make_default_print_filter() -> PrintFilter:
|
105
105
|
"""Create a default PrintFilter instance."""
|
106
|
-
return
|
106
|
+
return PrintFilterFastled()
|
107
107
|
|
108
108
|
|
109
109
|
class RunningContainer:
|
@@ -24,10 +24,37 @@ def _find_fastled_repo(start: Path) -> Path | None:
|
|
24
24
|
return None
|
25
25
|
|
26
26
|
|
27
|
+
_DEFAULT_HELP_TEXT = """
|
28
|
+
FastLED WASM Compiler - Useful options:
|
29
|
+
<directory> Directory containing the FastLED sketch to compile
|
30
|
+
--init [example] Initialize one of the top tier WASM examples
|
31
|
+
--web [url] Use web compiler
|
32
|
+
--server Run the compiler server
|
33
|
+
--debug Build with debug symbols for dev-tools debugging
|
34
|
+
--quick Build in quick mode (default)
|
35
|
+
--release Build in optimized release mode
|
36
|
+
--profile Enable profiling the C++ build system
|
37
|
+
--update Update the docker image for the wasm compiler
|
38
|
+
--purge Remove all FastLED containers and images
|
39
|
+
--version Show version information
|
40
|
+
--help Show detailed help
|
41
|
+
Examples:
|
42
|
+
fastled (will auto detect the sketch directory and prompt you)
|
43
|
+
fastled my_sketch
|
44
|
+
fastled my_sketch --web (compiles using the web compiler only)
|
45
|
+
fastled --init Blink (initializes a new sketch directory with the Blink example)
|
46
|
+
fastled --server (runs the compiler server in the current directory)
|
47
|
+
"""
|
48
|
+
|
49
|
+
|
27
50
|
def parse_args() -> Args:
|
28
51
|
"""Parse command-line arguments."""
|
29
52
|
from fastled import __version__
|
30
53
|
|
54
|
+
# Check if no arguments were provided
|
55
|
+
if len(sys.argv) == 1:
|
56
|
+
print(_DEFAULT_HELP_TEXT)
|
57
|
+
|
31
58
|
parser = argparse.ArgumentParser(description=f"FastLED WASM Compiler {__version__}")
|
32
59
|
parser.add_argument("--version", action="version", version=f"{__version__}")
|
33
60
|
parser.add_argument(
|
@@ -1,4 +1,26 @@
|
|
1
1
|
import re
|
2
|
+
from abc import ABC, abstractmethod
|
3
|
+
|
4
|
+
|
5
|
+
class PrintFilter(ABC):
|
6
|
+
"""Abstract base class for filtering text output."""
|
7
|
+
|
8
|
+
def __init__(self, echo: bool = True) -> None:
|
9
|
+
self.echo = echo
|
10
|
+
|
11
|
+
@abstractmethod
|
12
|
+
def filter(self, text: str) -> str:
|
13
|
+
"""Filter the text according to implementation-specific rules."""
|
14
|
+
pass
|
15
|
+
|
16
|
+
def print(self, text: str | bytes) -> str:
|
17
|
+
"""Prints the text to the console after filtering."""
|
18
|
+
if isinstance(text, bytes):
|
19
|
+
text = text.decode("utf-8")
|
20
|
+
text = self.filter(text)
|
21
|
+
if self.echo:
|
22
|
+
print(text, end="")
|
23
|
+
return text
|
2
24
|
|
3
25
|
|
4
26
|
def _handle_ino_cpp(line: str) -> str:
|
@@ -17,31 +39,37 @@ def _handle_ino_cpp(line: str) -> str:
|
|
17
39
|
return line
|
18
40
|
|
19
41
|
|
20
|
-
|
21
|
-
""
|
42
|
+
def _handle_fastled_src(line: str) -> str:
|
43
|
+
return line.replace("fastled/src", "src")
|
44
|
+
|
45
|
+
|
46
|
+
class PrintFilterDefault(PrintFilter):
|
47
|
+
"""Provides default filtering for FastLED output."""
|
48
|
+
|
49
|
+
def filter(self, text: str) -> str:
|
50
|
+
return text
|
51
|
+
|
52
|
+
|
53
|
+
class PrintFilterFastled(PrintFilter):
|
54
|
+
"""Provides filtering for FastLED output so that source files match up with local names."""
|
22
55
|
|
23
56
|
def __init__(self, echo: bool = True) -> None:
|
24
|
-
|
57
|
+
super().__init__(echo)
|
25
58
|
self.build_started = False
|
26
|
-
pass
|
27
59
|
|
28
|
-
def
|
60
|
+
def filter(self, text: str) -> str:
|
29
61
|
lines = text.splitlines()
|
30
62
|
out: list[str] = []
|
31
63
|
for line in lines:
|
64
|
+
## DEBUG DO NOT SUBMIT
|
65
|
+
# print(line)
|
32
66
|
if "# WASM is building" in line:
|
33
67
|
self.build_started = True
|
34
|
-
|
68
|
+
line = _handle_fastled_src(
|
69
|
+
line
|
70
|
+
) # Always convert fastled/src to src for file matchups.
|
71
|
+
if self.build_started or " error: " in line:
|
35
72
|
line = _handle_ino_cpp(line)
|
36
73
|
out.append(line)
|
37
74
|
text = "\n".join(out)
|
38
75
|
return text
|
39
|
-
|
40
|
-
def print(self, text: str | bytes) -> str:
|
41
|
-
"""Prints the text to the console."""
|
42
|
-
if isinstance(text, bytes):
|
43
|
-
text = text.decode("utf-8")
|
44
|
-
text = self._filter_all(text)
|
45
|
-
if self.echo:
|
46
|
-
print(text, end="")
|
47
|
-
return text
|
@@ -4,6 +4,8 @@ from enum import Enum
|
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import Any
|
6
6
|
|
7
|
+
from fastled.print_filter import PrintFilterFastled
|
8
|
+
|
7
9
|
|
8
10
|
@dataclass
|
9
11
|
class Args:
|
@@ -102,6 +104,11 @@ class CompileResult:
|
|
102
104
|
def to_dict(self) -> dict[str, Any]:
|
103
105
|
return self.__dict__.copy()
|
104
106
|
|
107
|
+
def __post_init__(self):
|
108
|
+
# Filter the stdout.
|
109
|
+
pf = PrintFilterFastled(echo=False)
|
110
|
+
self.stdout = pf.print(self.stdout)
|
111
|
+
|
105
112
|
|
106
113
|
class CompileServerError(Exception):
|
107
114
|
"""Error class for failing to instantiate CompileServer."""
|
@@ -4,6 +4,7 @@ import json
|
|
4
4
|
import os
|
5
5
|
import shutil
|
6
6
|
import tempfile
|
7
|
+
import time
|
7
8
|
import zipfile
|
8
9
|
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
|
9
10
|
from dataclasses import dataclass
|
@@ -154,6 +155,37 @@ def find_good_connection(
|
|
154
155
|
return None
|
155
156
|
|
156
157
|
|
158
|
+
def _banner(msg: str) -> str:
|
159
|
+
"""
|
160
|
+
Create a banner for the given message.
|
161
|
+
Example:
|
162
|
+
msg = "Hello, World!"
|
163
|
+
print -> "#################"
|
164
|
+
"# Hello, World! #"
|
165
|
+
"#################"
|
166
|
+
"""
|
167
|
+
lines = msg.split("\n")
|
168
|
+
# Find the width of the widest line
|
169
|
+
max_width = max(len(line) for line in lines)
|
170
|
+
width = max_width + 4 # Add 4 for "# " and " #"
|
171
|
+
|
172
|
+
# Create the top border
|
173
|
+
banner = "\n" + "#" * width + "\n"
|
174
|
+
|
175
|
+
# Add each line with proper padding
|
176
|
+
for line in lines:
|
177
|
+
padding = max_width - len(line)
|
178
|
+
banner += f"# {line}{' ' * padding} #\n"
|
179
|
+
|
180
|
+
# Add the bottom border
|
181
|
+
banner += "#" * width + "\n"
|
182
|
+
return banner
|
183
|
+
|
184
|
+
|
185
|
+
def _print_banner(msg: str) -> None:
|
186
|
+
print(_banner(msg))
|
187
|
+
|
188
|
+
|
157
189
|
def web_compile(
|
158
190
|
directory: Path | str,
|
159
191
|
host: str | None = None,
|
@@ -161,11 +193,12 @@ def web_compile(
|
|
161
193
|
build_mode: BuildMode | None = None,
|
162
194
|
profile: bool = False,
|
163
195
|
) -> CompileResult:
|
196
|
+
start_time = time.time()
|
164
197
|
if isinstance(directory, str):
|
165
198
|
directory = Path(directory)
|
166
199
|
host = _sanitize_host(host or DEFAULT_HOST)
|
167
200
|
build_mode = build_mode or BuildMode.QUICK
|
168
|
-
|
201
|
+
_print_banner(f"Compiling on {host}")
|
169
202
|
auth_token = auth_token or _AUTH_TOKEN
|
170
203
|
if not directory.exists():
|
171
204
|
raise FileNotFoundError(f"Directory not found: {directory}")
|
@@ -186,7 +219,7 @@ def web_compile(
|
|
186
219
|
|
187
220
|
connection_result = find_good_connection(urls)
|
188
221
|
if connection_result is None:
|
189
|
-
|
222
|
+
_print_banner("Connection failed to all endpoints")
|
190
223
|
return CompileResult(
|
191
224
|
success=False,
|
192
225
|
stdout="Connection failed",
|
@@ -270,6 +303,9 @@ def web_compile(
|
|
270
303
|
relative_path = file_path.relative_to(extract_path)
|
271
304
|
out_zip.write(file_path, relative_path)
|
272
305
|
|
306
|
+
diff_time = time.time() - start_time
|
307
|
+
msg = f"Compilation success, took {diff_time:.2f} seconds"
|
308
|
+
_print_banner(msg)
|
273
309
|
return CompileResult(
|
274
310
|
success=True,
|
275
311
|
stdout=stdout,
|
@@ -35,7 +35,15 @@ class WebCompileTester(unittest.TestCase):
|
|
35
35
|
print("stdout:")
|
36
36
|
print(result.stdout)
|
37
37
|
self.fail("Expected error not found in stdout")
|
38
|
-
|
38
|
+
if "bad/bad.ino:" not in result.stdout: # No .cpp extension.
|
39
|
+
print(
|
40
|
+
"bad.ino.cpp was not transformed to bad.ino without the cpp extension"
|
41
|
+
)
|
42
|
+
print("stdout:")
|
43
|
+
print(result.stdout)
|
44
|
+
self.fail(
|
45
|
+
"bad.ino.cpp was not transformed to bad.ino without the cpp extension"
|
46
|
+
)
|
39
47
|
|
40
48
|
print(f"Zip size: {len(result.zip_bytes)} bytes")
|
41
49
|
|
@@ -4,18 +4,20 @@ Unit test file.
|
|
4
4
|
|
5
5
|
import unittest
|
6
6
|
|
7
|
-
from fastled.print_filter import
|
7
|
+
from fastled.print_filter import PrintFilterFastled
|
8
8
|
|
9
9
|
|
10
10
|
class PrintFitlerTester(unittest.TestCase):
|
11
11
|
"""Main tester class."""
|
12
12
|
|
13
|
-
def
|
13
|
+
def test_print_filter(self) -> None:
|
14
14
|
"""Tests that a project can be filtered"""
|
15
15
|
# Test the PrintFilter class
|
16
|
-
pf =
|
16
|
+
pf = PrintFilterFastled(echo=False)
|
17
17
|
pf.print("# WASM is building") # This should trigger the filter.
|
18
|
-
result = pf.print(
|
18
|
+
result = pf.print(
|
19
|
+
"5.36 src/XYPath.ino.cpp:4:1: error: unknown type name 'kdsjfsdkfjsd'"
|
20
|
+
) # This should now be transformed.
|
19
21
|
self.assertNotIn(".ino.cpp", result, "Expected .ino.cpp to be filtered out")
|
20
22
|
self.assertIn(
|
21
23
|
"examples/XYPath/XYPath.ino", result, "Expected path to be transformed"
|
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
|