fastled 1.3.0__tar.gz → 1.3.3__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.3.0 → fastled-1.3.3}/PKG-INFO +2 -2
- {fastled-1.3.0 → fastled-1.3.3}/compiler/pyproject.toml +1 -1
- {fastled-1.3.0 → fastled-1.3.3}/pyproject.toml +1 -1
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/__init__.py +2 -5
- fastled-1.3.3/src/fastled/__version__.py +6 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/compile_server.py +1 -5
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/compile_server_impl.py +1 -24
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/docker_manager.py +19 -1
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/print_filter.py +58 -1
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/server_flask.py +34 -13
- fastled-1.3.3/src/fastled/version.py +41 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/PKG-INFO +2 -2
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/SOURCES.txt +3 -1
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/requires.txt +1 -1
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_experimental_cpp_filter.py +74 -28
- fastled-1.3.0/tests/unit/test_fetch_source_files.py → fastled-1.3.3/tests/unit/test_fetch_debug_source_files.py +35 -19
- {fastled-1.3.0 → fastled-1.3.3}/.aiderignore +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.dockerignore +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/build_multi_docker_image.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/build_webpage.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/lint.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/publish_release.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/template_build_docker_image.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/test_build_exe.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/test_macos.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/test_ubuntu.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/test_win.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.gitignore +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.pylintrc +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.vscode/launch.json +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.vscode/settings.json +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/.vscode/tasks.json +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/Dockerfile +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/LICENSE +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/MANIFEST.in +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/README.md +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/RELEASE.md +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/TODO.md +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/build_exe.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/build_local_docker.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/build_site.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/clean +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/CMakeLists.txt +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/arduino-pre-process.sh +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/debug.sh +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/entrypoint.sh +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/final_prewarm.sh +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/init_runtime.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/install-arduino-cli.sh +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/libcompile/CMakeLists.txt +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/prewarm.sh +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/process-ino.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/compiler/run.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/demo/100dots.html +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/demo/demo_threejs.html +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/demo/micdemo.html +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/demo/mp3upload.html +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/demo/webgl_postprocessing_unreal_bloom.html +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/docker-compose.yml +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/install +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/install_linux.sh +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/lint +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/requirements.testing.txt +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/setup.cfg +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/setup.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/app.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/assets/example.txt +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/assets/localhost-key.pem +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/assets/localhost.pem +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/cli.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/cli_test.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/cli_test_interactive.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/client_server.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/filewatcher.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/keyboard.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/keyz.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/live_client.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/open_browser.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/parse_args.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/paths.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/project_init.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/select_sketch_directory.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/server_start.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/settings.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/site/build.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/site/examples.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/sketch.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/spinner.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/string_diff.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/test/can_run_local_docker_tests.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/test/examples.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/types.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/util.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled/web_compile.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/dependency_links.txt +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/entry_points.txt +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/top_level.txt +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/test +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/integration/test_build_examples.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/integration/test_examples.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/html/index.html +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_api.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_bad_ino.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_cli.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_compile_server.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_docker_linux_on_windows.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_embedded_data.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_filechanger.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_http_server.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/bad/bad.ino +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/embedded/wasm.ino +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/wasm/wasm.ino +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_print_filter.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_project_init.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_server_and_client_seperatly.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_string_diff.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_version.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_version_matches.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_webcompile.py +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/upload_package.sh +0 -0
- {fastled-1.3.0 → fastled-1.3.3}/vscode-plugin/readme +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fastled
|
3
|
-
Version: 1.3.
|
3
|
+
Version: 1.3.3
|
4
4
|
Summary: FastLED Wasm Compiler
|
5
5
|
Home-page: https://github.com/zackees/fastled-wasm
|
6
6
|
Maintainer: Zachary Vorhies
|
@@ -20,7 +20,7 @@ Requires-Dist: progress>=1.6
|
|
20
20
|
Requires-Dist: watchfiles>=1.0.5
|
21
21
|
Requires-Dist: Flask>=3.0.0
|
22
22
|
Requires-Dist: livereload
|
23
|
-
Requires-Dist: fastled-wasm-server>=1.0.
|
23
|
+
Requires-Dist: fastled-wasm-server>=1.0.25
|
24
24
|
Dynamic: home-page
|
25
25
|
Dynamic: license-file
|
26
26
|
Dynamic: maintainer
|
@@ -15,7 +15,7 @@ dependencies = [
|
|
15
15
|
"disklru==2.0.0",
|
16
16
|
"psutil==6.1.1",
|
17
17
|
"wormhole-tx",
|
18
|
-
"fastled-wasm-server>=1.0.
|
18
|
+
"fastled-wasm-server>=1.0.25", # Also versions fastled-wasm-compiler dependency.
|
19
19
|
]
|
20
20
|
|
21
21
|
[tool.setuptools]
|
@@ -24,7 +24,7 @@ dependencies = [
|
|
24
24
|
"Flask>=3.0.0",
|
25
25
|
"livereload",
|
26
26
|
###### WASM SERVER ######
|
27
|
-
"fastled-wasm-server>=1.0.
|
27
|
+
"fastled-wasm-server>=1.0.25", # Enforced by unit test to match project <--> docker.
|
28
28
|
]
|
29
29
|
|
30
30
|
dynamic = ["version"]
|
@@ -5,17 +5,13 @@ from multiprocessing import Process
|
|
5
5
|
from pathlib import Path
|
6
6
|
from typing import Generator
|
7
7
|
|
8
|
+
from .__version__ import __version__
|
8
9
|
from .compile_server import CompileServer
|
9
10
|
from .live_client import LiveClient
|
10
11
|
from .settings import DOCKER_FILE, IMAGE_NAME
|
11
12
|
from .site.build import build
|
12
13
|
from .types import BuildMode, CompileResult, CompileServerError, FileResponse
|
13
14
|
|
14
|
-
# IMPORTANT! There's a bug in github which will REJECT any version update
|
15
|
-
# that has any other change in the repo. Please bump the version as the
|
16
|
-
# ONLY change in a commit, or else the pypi update and the release will fail.
|
17
|
-
__version__ = "1.3.0"
|
18
|
-
|
19
15
|
|
20
16
|
class Api:
|
21
17
|
@staticmethod
|
@@ -224,4 +220,5 @@ __all__ = [
|
|
224
220
|
"BuildMode",
|
225
221
|
"FileResponse",
|
226
222
|
"DOCKER_FILE",
|
223
|
+
"__version__",
|
227
224
|
]
|
@@ -0,0 +1,6 @@
|
|
1
|
+
# IMPORTANT! There's a bug in github which will REJECT any version update
|
2
|
+
# that has any other change in the repo. Please bump the version as the
|
3
|
+
# ONLY change in a commit, or else the pypi update and the release will fail.
|
4
|
+
__version__ = "1.3.3"
|
5
|
+
|
6
|
+
__version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from pathlib import Path
|
2
2
|
|
3
|
-
from fastled.types import BuildMode, CompileResult,
|
3
|
+
from fastled.types import BuildMode, CompileResult, Platform
|
4
4
|
|
5
5
|
|
6
6
|
class CompileServer:
|
@@ -53,10 +53,6 @@ class CompileServer:
|
|
53
53
|
|
54
54
|
project_init(example=example, outputdir=outputdir)
|
55
55
|
|
56
|
-
def fetch_source_file(self, filepath: str) -> FileResponse | Exception:
|
57
|
-
"""Get the source file from the server."""
|
58
|
-
return self.impl.fetch_source_file(filepath)
|
59
|
-
|
60
56
|
@property
|
61
57
|
def name(self) -> str:
|
62
58
|
return self.impl.container_name
|
@@ -17,7 +17,7 @@ from fastled.docker_manager import (
|
|
17
17
|
)
|
18
18
|
from fastled.settings import DEFAULT_CONTAINER_NAME, IMAGE_NAME, SERVER_PORT
|
19
19
|
from fastled.sketch import looks_like_fastled_repo
|
20
|
-
from fastled.types import BuildMode, CompileResult, CompileServerError
|
20
|
+
from fastled.types import BuildMode, CompileResult, CompileServerError
|
21
21
|
from fastled.util import port_is_free
|
22
22
|
|
23
23
|
SERVER_OPTIONS = [
|
@@ -183,29 +183,6 @@ class CompileServerImpl:
|
|
183
183
|
return False
|
184
184
|
return False
|
185
185
|
|
186
|
-
def fetch_source_file(self, filepath: str) -> FileResponse | Exception:
|
187
|
-
"""Get the source file from the server."""
|
188
|
-
if not self._port:
|
189
|
-
raise RuntimeError("Server has not been started yet")
|
190
|
-
try:
|
191
|
-
httpx_client = httpx.Client()
|
192
|
-
url = f"http://localhost:{self._port}/sourcefiles/{filepath}"
|
193
|
-
response = httpx_client.get(url, follow_redirects=True)
|
194
|
-
if response.status_code == 200:
|
195
|
-
content = response.text
|
196
|
-
mimetype: str = response.headers.get("Content-Type", "text/plain")
|
197
|
-
return FileResponse(
|
198
|
-
content=content,
|
199
|
-
mimetype=mimetype,
|
200
|
-
filename=filepath,
|
201
|
-
)
|
202
|
-
else:
|
203
|
-
return CompileServerError(
|
204
|
-
f"Error fetching file {filepath}: {response.status_code}"
|
205
|
-
)
|
206
|
-
except httpx.RequestError as e:
|
207
|
-
return CompileServerError(f"Error fetching file {filepath}: {e}")
|
208
|
-
|
209
186
|
def _start(self) -> int:
|
210
187
|
print("Compiling server starting")
|
211
188
|
|
@@ -366,7 +366,7 @@ class DockerManager:
|
|
366
366
|
Returns:
|
367
367
|
A tuple of (has_newer_version, message)
|
368
368
|
has_newer_version: True if a newer version is available, False otherwise
|
369
|
-
message: A message describing the result
|
369
|
+
message: A message describing the result, including the date of the newer version if available
|
370
370
|
"""
|
371
371
|
try:
|
372
372
|
# Get the local image
|
@@ -388,6 +388,24 @@ class DockerManager:
|
|
388
388
|
if remote_image_hash_from_local_image == remote_image_hash:
|
389
389
|
return False, f"Local image {image_name}:{tag} is up to date."
|
390
390
|
else:
|
391
|
+
# Get the creation date of the remote image if possible
|
392
|
+
try:
|
393
|
+
# Try to get detailed image info including creation date
|
394
|
+
remote_image_details = self.client.api.inspect_image(
|
395
|
+
f"{image_name}:{tag}"
|
396
|
+
)
|
397
|
+
if "Created" in remote_image_details:
|
398
|
+
created_date = remote_image_details["Created"].split("T")[
|
399
|
+
0
|
400
|
+
] # Extract just the date part
|
401
|
+
return (
|
402
|
+
True,
|
403
|
+
f"Newer version of {image_name}:{tag} is available (published on {created_date}).",
|
404
|
+
)
|
405
|
+
except Exception:
|
406
|
+
pass
|
407
|
+
|
408
|
+
# Fallback if we couldn't get the date
|
391
409
|
return True, f"Newer version of {image_name}:{tag} is available."
|
392
410
|
|
393
411
|
except ImageNotFound:
|
@@ -94,8 +94,65 @@ class BuildArtifact:
|
|
94
94
|
compile_or_link: CompileOrLink
|
95
95
|
hash: int
|
96
96
|
|
97
|
+
def flags_pretty(self) -> str:
|
98
|
+
"""
|
99
|
+
Returns the flags in a pretty format.
|
100
|
+
This is used for printing the flags to the console.
|
101
|
+
"""
|
102
|
+
flags = self.build_flags
|
103
|
+
flags = flags.replace(" -I", "\n-I")
|
104
|
+
flags = flags.replace(" -D", "\n-D")
|
105
|
+
flags = flags.replace(" -l", "\n-l")
|
106
|
+
flags = flags.replace(" -L", "\n-L")
|
107
|
+
flags = flags.replace(" -o", "\n-o")
|
108
|
+
flags = flags.replace(" -W", "\n-W")
|
109
|
+
flags = flags.replace(" -f", "\n-f")
|
110
|
+
flags = flags.replace(" -g", "\n-g")
|
111
|
+
|
112
|
+
# break into lines and sort
|
113
|
+
lines = flags.splitlines()
|
114
|
+
first_line = lines[0]
|
115
|
+
lines.pop(0) # remove first line
|
116
|
+
lines = sorted(lines)
|
117
|
+
# remove duplicates
|
118
|
+
lines = list(dict.fromkeys(lines))
|
119
|
+
# remove empty lines
|
120
|
+
lines = [line for line in lines if line.strip() != ""]
|
121
|
+
# remove leading and trailing whitespace
|
122
|
+
lines = [line.strip() for line in lines]
|
123
|
+
lines = sorted(lines)
|
124
|
+
lines = [first_line] + lines # add first line back to the beginning
|
125
|
+
# stringify
|
126
|
+
flags = "\n".join(lines)
|
127
|
+
return flags
|
128
|
+
|
97
129
|
def __str__(self) -> str:
|
98
|
-
return f"{self.
|
130
|
+
return f"{self.brief()} {self.build_flags} {self.compile_or_link} {self.hash}"
|
131
|
+
|
132
|
+
def brief(self) -> str:
|
133
|
+
return f"{self.timestamp:.2f} {self.output_artifact}"
|
134
|
+
|
135
|
+
def begin_flags(self) -> str:
|
136
|
+
"""
|
137
|
+
Returns the flags that are used to begin a build.
|
138
|
+
This is the flags that are used for the first compile or link.
|
139
|
+
"""
|
140
|
+
|
141
|
+
out: str = (
|
142
|
+
"\n################ NEW COMPILE/LINK FLAG GROUP #####################\n\n"
|
143
|
+
)
|
144
|
+
out += f"{self.flags_pretty()}\n"
|
145
|
+
return out
|
146
|
+
|
147
|
+
def end_flags(self) -> str:
|
148
|
+
"""
|
149
|
+
Returns the flags that are used to end a build.
|
150
|
+
This is the flags that are used for the last compile or link.
|
151
|
+
"""
|
152
|
+
out: str = (
|
153
|
+
"\n################ END COMPILE/LINK FLAG GROUP #####################\n"
|
154
|
+
)
|
155
|
+
return out
|
99
156
|
|
100
157
|
@staticmethod
|
101
158
|
def parse(input_str: str) -> "BuildArtifact | None":
|
@@ -26,6 +26,16 @@ else:
|
|
26
26
|
logger.disabled = True
|
27
27
|
|
28
28
|
|
29
|
+
def _is_dwarf_source(path: str) -> bool:
|
30
|
+
"""Check if the path is a dwarf source file."""
|
31
|
+
# Check if the path starts with "fastledsource/" or "sketchsource/"
|
32
|
+
return (
|
33
|
+
path.startswith("fastledsource/")
|
34
|
+
or path.startswith("sketchsource/")
|
35
|
+
or path.startswith("dwarfsource")
|
36
|
+
)
|
37
|
+
|
38
|
+
|
29
39
|
def _run_flask_server(
|
30
40
|
fastled_js: Path,
|
31
41
|
port: int,
|
@@ -125,22 +135,20 @@ def _run_flask_server(
|
|
125
135
|
logger.error(f"Error forwarding request: {e}", exc_info=True)
|
126
136
|
return Response(f"Error: {str(e)}", status=500)
|
127
137
|
|
128
|
-
def
|
129
|
-
"""Handle requests to
|
130
|
-
|
138
|
+
def handle_fastledsource(path: str) -> Response:
|
139
|
+
"""Handle requests to
|
140
|
+
/fastledsource/js/fastledsource/git/fastled/src/
|
141
|
+
or
|
142
|
+
/sketchsource/js/src/Blink.ino
|
143
|
+
|
144
|
+
The names are a bit mangled due to the way C++ prefixing works near the root directory.
|
145
|
+
"""
|
131
146
|
from flask import request
|
132
147
|
|
133
148
|
start_time = time.time()
|
134
149
|
logger.info(f"Processing request: {request.method} {request.url}")
|
135
|
-
|
136
|
-
if "../" in path:
|
137
|
-
# Prevent directory traversal attacks
|
138
|
-
error_msg = "Directory traversal attack detected"
|
139
|
-
logger.error(error_msg)
|
140
|
-
return Response(error_msg, status=400)
|
141
|
-
|
142
150
|
# Forward the request to the compile server
|
143
|
-
target_url = f"http://localhost:{compile_server_port}/{path}"
|
151
|
+
target_url = f"http://localhost:{compile_server_port}/dwarfsource/{path}"
|
144
152
|
logger.info(f"Requesting: {target_url}")
|
145
153
|
logger.info(f"Processing dwarfsource request for {path}")
|
146
154
|
|
@@ -309,14 +317,27 @@ def _run_flask_server(
|
|
309
317
|
return Response(f"File not found: {path}", status=404)
|
310
318
|
return Response(f"Error serving file: {str(e)}", status=500)
|
311
319
|
|
320
|
+
@app.route("/fastapi")
|
321
|
+
def server_backend_redirect():
|
322
|
+
"""Redirect to the compile server"""
|
323
|
+
logger.info("Redirecting to compile server")
|
324
|
+
target_url = f"http://localhost:{compile_server_port}/docs"
|
325
|
+
logger.info(f"Redirecting to: {target_url}")
|
326
|
+
return Response(
|
327
|
+
f"Redirecting to compile server: <a href='{target_url}'>{target_url}</a>",
|
328
|
+
status=302,
|
329
|
+
headers={"Location": target_url},
|
330
|
+
)
|
331
|
+
|
312
332
|
@app.route("/<path:path>")
|
313
333
|
def serve_files(path: str):
|
314
334
|
logger.info(f"Received request for path: {path}")
|
315
335
|
|
316
336
|
try:
|
317
|
-
|
337
|
+
is_debug_src_code_request = _is_dwarf_source(path)
|
338
|
+
if is_debug_src_code_request:
|
318
339
|
logger.info(f"Handling as drawfsource: {path}")
|
319
|
-
return
|
340
|
+
return handle_fastledsource(path)
|
320
341
|
elif path.startswith("sourcefiles/"):
|
321
342
|
logger.info(f"Handling as sourcefiles: {path}")
|
322
343
|
return handle_sourcefile(path)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from concurrent.futures import Future, ThreadPoolExecutor
|
2
|
+
|
3
|
+
import httpx
|
4
|
+
|
5
|
+
from fastled.__version__ import __version_url_latest__
|
6
|
+
|
7
|
+
|
8
|
+
def _fetch_version() -> str | Exception:
|
9
|
+
"""
|
10
|
+
Helper function to fetch the latest version from the GitHub repository.
|
11
|
+
"""
|
12
|
+
try:
|
13
|
+
response = httpx.get(__version_url_latest__)
|
14
|
+
response.raise_for_status()
|
15
|
+
# Extract the version string from the response text
|
16
|
+
version_line = response.text.split("__version__ = ")[1].split('"')[1]
|
17
|
+
return version_line
|
18
|
+
except Exception as e:
|
19
|
+
return e
|
20
|
+
|
21
|
+
|
22
|
+
def get_latest_version() -> Future[str | Exception]:
|
23
|
+
"""
|
24
|
+
Fetch the latest version from the GitHub repository.
|
25
|
+
Returns a future that will resolve with the version string or an exception.
|
26
|
+
"""
|
27
|
+
executor = ThreadPoolExecutor()
|
28
|
+
return executor.submit(_fetch_version)
|
29
|
+
|
30
|
+
|
31
|
+
def unit_test() -> None:
|
32
|
+
future = get_latest_version()
|
33
|
+
latest_version = future.result() # Wait for the future to complete
|
34
|
+
if isinstance(latest_version, Exception):
|
35
|
+
print(f"Error fetching latest version: {latest_version}")
|
36
|
+
else:
|
37
|
+
print(f"Latest version: {latest_version}")
|
38
|
+
|
39
|
+
|
40
|
+
if __name__ == "__main__":
|
41
|
+
unit_test()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fastled
|
3
|
-
Version: 1.3.
|
3
|
+
Version: 1.3.3
|
4
4
|
Summary: FastLED Wasm Compiler
|
5
5
|
Home-page: https://github.com/zackees/fastled-wasm
|
6
6
|
Maintainer: Zachary Vorhies
|
@@ -20,7 +20,7 @@ Requires-Dist: progress>=1.6
|
|
20
20
|
Requires-Dist: watchfiles>=1.0.5
|
21
21
|
Requires-Dist: Flask>=3.0.0
|
22
22
|
Requires-Dist: livereload
|
23
|
-
Requires-Dist: fastled-wasm-server>=1.0.
|
23
|
+
Requires-Dist: fastled-wasm-server>=1.0.25
|
24
24
|
Dynamic: home-page
|
25
25
|
Dynamic: license-file
|
26
26
|
Dynamic: maintainer
|
@@ -51,6 +51,7 @@ demo/micdemo.html
|
|
51
51
|
demo/mp3upload.html
|
52
52
|
demo/webgl_postprocessing_unreal_bloom.html
|
53
53
|
src/fastled/__init__.py
|
54
|
+
src/fastled/__version__.py
|
54
55
|
src/fastled/app.py
|
55
56
|
src/fastled/cli.py
|
56
57
|
src/fastled/cli_test.py
|
@@ -77,6 +78,7 @@ src/fastled/spinner.py
|
|
77
78
|
src/fastled/string_diff.py
|
78
79
|
src/fastled/types.py
|
79
80
|
src/fastled/util.py
|
81
|
+
src/fastled/version.py
|
80
82
|
src/fastled/web_compile.py
|
81
83
|
src/fastled.egg-info/PKG-INFO
|
82
84
|
src/fastled.egg-info/SOURCES.txt
|
@@ -100,7 +102,7 @@ tests/unit/test_compile_server.py
|
|
100
102
|
tests/unit/test_docker_linux_on_windows.py
|
101
103
|
tests/unit/test_embedded_data.py
|
102
104
|
tests/unit/test_experimental_cpp_filter.py
|
103
|
-
tests/unit/
|
105
|
+
tests/unit/test_fetch_debug_source_files.py
|
104
106
|
tests/unit/test_filechanger.py
|
105
107
|
tests/unit/test_http_server.py
|
106
108
|
tests/unit/test_print_filter.py
|
@@ -124,43 +124,89 @@ src/third_party/cq_kernel/kiss_fft.c
|
|
124
124
|
"""
|
125
125
|
|
126
126
|
|
127
|
-
class
|
128
|
-
|
127
|
+
class Filter:
|
128
|
+
def __init__(self):
|
129
|
+
self._prev_broken_line: str | None = None
|
130
|
+
self._last_build_artifact: BuildArtifact | None = None
|
131
|
+
|
132
|
+
def filter(self, line: str) -> str | None:
|
133
|
+
if not line:
|
134
|
+
return None
|
135
|
+
maybe_prev_broken_line: str | None = self._prev_broken_line
|
136
|
+
self._prev_broken_line = None
|
137
|
+
# if the line starts with a digit, it's a build artifact
|
138
|
+
ba: BuildArtifact | None = BuildArtifact.parse(line)
|
139
|
+
|
140
|
+
if ba is not None: # Successfully parsed a build artifact.
|
141
|
+
# if we have a build artifact, we need to check if it's the same as the last one
|
142
|
+
if (
|
143
|
+
self._last_build_artifact is not None
|
144
|
+
and ba.hash == self._last_build_artifact.hash
|
145
|
+
):
|
146
|
+
# No change in build settings.
|
147
|
+
out = ba.brief()
|
148
|
+
self._last_build_artifact = ba
|
149
|
+
return out
|
150
|
+
if self._last_build_artifact is None:
|
151
|
+
self._last_build_artifact = ba
|
152
|
+
return ba.begin_flags() + "\n" + ba.brief()
|
153
|
+
# we have a new build artifact, so we need to print out the build settings
|
154
|
+
# and the line
|
155
|
+
out = self._last_build_artifact.end_flags() + "\n\n\n"
|
156
|
+
out += ba.begin_flags()
|
157
|
+
out += "\n" + ba.brief()
|
158
|
+
self._last_build_artifact = ba
|
159
|
+
return out
|
160
|
+
|
161
|
+
# We couldn't parse this line so store it in stead.
|
162
|
+
if maybe_prev_broken_line is None:
|
163
|
+
self._prev_broken_line = line
|
164
|
+
return None
|
165
|
+
# we have a previous line, so we can try to merge them because this typically happens
|
166
|
+
# for line breaks.
|
167
|
+
new_line = maybe_prev_broken_line + line
|
168
|
+
ba = BuildArtifact.parse(new_line)
|
169
|
+
if ba is None:
|
170
|
+
return None
|
171
|
+
# we have a build artifact, so we can use it.
|
172
|
+
|
173
|
+
if self._last_build_artifact and (ba.hash == self._last_build_artifact.hash):
|
174
|
+
# No change in build settings.
|
175
|
+
out = ba.brief()
|
176
|
+
return out
|
177
|
+
out = ""
|
178
|
+
# different build settings so we need to print out the new build settings and then the line
|
179
|
+
if self._last_build_artifact is not None:
|
180
|
+
out += "\n" + self._last_build_artifact.end_flags() + "\n\n"
|
181
|
+
out += ba.begin_flags()
|
182
|
+
out += ba.brief() + "\n"
|
183
|
+
self._last_build_artifact = ba
|
184
|
+
return out
|
129
185
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
186
|
+
def end(self) -> str:
|
187
|
+
"""Returns the end of the build artifact."""
|
188
|
+
if self._last_build_artifact is None:
|
189
|
+
return ""
|
190
|
+
# we have a build artifact, so we can use it.
|
191
|
+
out = self._last_build_artifact.end_flags()
|
192
|
+
self._last_build_artifact = None
|
193
|
+
return out
|
134
194
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
# print(f"###Filtered: result was {out}")
|
139
|
-
# print("Done")
|
195
|
+
|
196
|
+
class ExperimentalPrintFitlerCppTester(unittest.TestCase):
|
197
|
+
"""Main tester class."""
|
140
198
|
|
141
199
|
def test_build_artifact_parsing(self) -> None:
|
142
200
|
"""Tests that a project can be filtered"""
|
143
201
|
# Test the PrintFilter class
|
144
202
|
lines = _BUILD_CONFIG_SAMPLE.splitlines()
|
145
203
|
lines = [line.strip() for line in lines if line.strip()]
|
146
|
-
|
204
|
+
filter: Filter = Filter()
|
147
205
|
for line in lines:
|
148
|
-
|
149
|
-
if
|
150
|
-
print(
|
151
|
-
|
152
|
-
|
153
|
-
if last_hash is None or ba.hash != last_hash:
|
154
|
-
# print out the build flags
|
155
|
-
print("Found new build flags:")
|
156
|
-
print(ba.build_flags)
|
157
|
-
# now set the hash to the new value
|
158
|
-
last_hash = ba.hash
|
159
|
-
|
160
|
-
# print the time and build output
|
161
|
-
print(f"{ba.timestamp} {ba.output_artifact}")
|
162
|
-
|
163
|
-
print("Done")
|
206
|
+
str_or_none = filter.filter(line)
|
207
|
+
if str_or_none is not None:
|
208
|
+
print(str_or_none)
|
209
|
+
print(filter.end())
|
164
210
|
|
165
211
|
|
166
212
|
if __name__ == "__main__":
|
@@ -15,13 +15,12 @@ HERE = Path(__file__).parent
|
|
15
15
|
TEST_INO_WASM = HERE / "test_ino" / "wasm"
|
16
16
|
|
17
17
|
# New refactor has broken this test. Good news, we got the sketch to output debug symbols!!!!!!
|
18
|
-
_ENABLED =
|
18
|
+
_ENABLED = True
|
19
19
|
|
20
20
|
_DWARF_SRC_EXAMPLE1 = "http://localhost:{http_port}/fastledsource/js/src/fastledsource/git/fastled/src/FastLED.h"
|
21
21
|
_DWARF_SRC_EXAMPLE2 = (
|
22
22
|
"http://localhost:{http_port}/sketchsource/js/sketchsource/headers/FastLED.h"
|
23
23
|
)
|
24
|
-
# _DWARF_SRC_EXAMPLES = "http://localhost:{http_port}/drawfsource/js/src/direct.h"
|
25
24
|
|
26
25
|
_DWARF_SRC_EXAMPLES = [
|
27
26
|
_DWARF_SRC_EXAMPLE1,
|
@@ -54,21 +53,6 @@ def wait_for_server(url: str, timeout: int = 10) -> bool:
|
|
54
53
|
class FetchSourceFileTester(unittest.TestCase):
|
55
54
|
"""Main tester class."""
|
56
55
|
|
57
|
-
@unittest.skipUnless(
|
58
|
-
_enabled(),
|
59
|
-
"Skipping test because either this is on non-Linux system on github or embedded data is disabled",
|
60
|
-
)
|
61
|
-
def test_backend_server_for_src_file_fetch(self) -> None:
|
62
|
-
"""Tests that embedded data is round tripped correctly."""
|
63
|
-
# Todo: make this only run on a local build. Otherwise there are sync issues
|
64
|
-
# with the docker version of this app and will generate false positives until
|
65
|
-
# the docker version is updated - Frustrating.
|
66
|
-
with Api.server() as server:
|
67
|
-
resp = server.fetch_source_file("FastLED.h")
|
68
|
-
if isinstance(resp, Exception):
|
69
|
-
raise resp
|
70
|
-
print("Done")
|
71
|
-
|
72
56
|
@unittest.skipUnless(
|
73
57
|
_enabled(),
|
74
58
|
"Skipping test because either this is on non-Linux system on github or embedded data is disabled",
|
@@ -83,11 +67,18 @@ class FetchSourceFileTester(unittest.TestCase):
|
|
83
67
|
http_port=http_port,
|
84
68
|
)
|
85
69
|
with client:
|
86
|
-
# TODO Make faster.
|
87
70
|
wait_for_server(f"http://localhost:{http_port}", timeout=100)
|
71
|
+
backend_host = client.url()
|
72
|
+
|
73
|
+
# This url should proxy back to the server at /dwarfsource/fastledsource/git/fastled/src/FastLED.h
|
74
|
+
url = (
|
75
|
+
f"http://localhost:{http_port}/fastledsource/git/fastled/src/FastLED.h"
|
76
|
+
)
|
88
77
|
|
89
78
|
resp = httpx.get(
|
90
|
-
|
79
|
+
# This type of request will come from the server during debug mode to
|
80
|
+
# enable debugging.
|
81
|
+
url,
|
91
82
|
timeout=100,
|
92
83
|
)
|
93
84
|
if resp.status_code != 200:
|
@@ -96,6 +87,20 @@ class FetchSourceFileTester(unittest.TestCase):
|
|
96
87
|
if content_length == 0:
|
97
88
|
raise Exception("Content-Length is 0")
|
98
89
|
|
90
|
+
backend_url = (
|
91
|
+
backend_host
|
92
|
+
+ "/dwarfsource"
|
93
|
+
+ "/fastledsource/git/fastled/src/FastLED.h"
|
94
|
+
)
|
95
|
+
resp = httpx.get(
|
96
|
+
backend_url,
|
97
|
+
timeout=100,
|
98
|
+
)
|
99
|
+
if resp.status_code != 200:
|
100
|
+
raise Exception(
|
101
|
+
f"Failed to fetch source file from the backend server: {resp.status_code}"
|
102
|
+
)
|
103
|
+
|
99
104
|
for ds in _DWARF_SRC_EXAMPLES:
|
100
105
|
# now get something similar at static/js/fastled/src/platforms/wasm/js.cpp
|
101
106
|
url = ds.format(http_port=http_port)
|
@@ -104,6 +109,17 @@ class FetchSourceFileTester(unittest.TestCase):
|
|
104
109
|
timeout=100,
|
105
110
|
)
|
106
111
|
self.assertTrue(resp.status_code == 200, resp.status_code)
|
112
|
+
content_length = int(resp.headers["Content-Length"])
|
113
|
+
self.assertTrue(content_length > 0, "Content-Length is 0")
|
114
|
+
backend_url = backend_host + "/dwarfsource/" + url.split("/")[-1]
|
115
|
+
resp = httpx.get(
|
116
|
+
backend_url,
|
117
|
+
timeout=100,
|
118
|
+
)
|
119
|
+
if resp.status_code != 200:
|
120
|
+
raise Exception(
|
121
|
+
f"Failed to fetch source file from the backend server: {resp.status_code}"
|
122
|
+
)
|
107
123
|
|
108
124
|
print("Done")
|
109
125
|
|
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
|