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.
Files changed (124) hide show
  1. {fastled-1.3.0 → fastled-1.3.3}/PKG-INFO +2 -2
  2. {fastled-1.3.0 → fastled-1.3.3}/compiler/pyproject.toml +1 -1
  3. {fastled-1.3.0 → fastled-1.3.3}/pyproject.toml +1 -1
  4. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/__init__.py +2 -5
  5. fastled-1.3.3/src/fastled/__version__.py +6 -0
  6. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/compile_server.py +1 -5
  7. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/compile_server_impl.py +1 -24
  8. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/docker_manager.py +19 -1
  9. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/print_filter.py +58 -1
  10. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/server_flask.py +34 -13
  11. fastled-1.3.3/src/fastled/version.py +41 -0
  12. {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/PKG-INFO +2 -2
  13. {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/SOURCES.txt +3 -1
  14. {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/requires.txt +1 -1
  15. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_experimental_cpp_filter.py +74 -28
  16. 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
  17. {fastled-1.3.0 → fastled-1.3.3}/.aiderignore +0 -0
  18. {fastled-1.3.0 → fastled-1.3.3}/.dockerignore +0 -0
  19. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/build_multi_docker_image.yml +0 -0
  20. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/build_webpage.yml +0 -0
  21. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/lint.yml +0 -0
  22. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/publish_release.yml +0 -0
  23. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/template_build_docker_image.yml +0 -0
  24. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/test_build_exe.yml +0 -0
  25. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/test_macos.yml +0 -0
  26. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/test_ubuntu.yml +0 -0
  27. {fastled-1.3.0 → fastled-1.3.3}/.github/workflows/test_win.yml +0 -0
  28. {fastled-1.3.0 → fastled-1.3.3}/.gitignore +0 -0
  29. {fastled-1.3.0 → fastled-1.3.3}/.pylintrc +0 -0
  30. {fastled-1.3.0 → fastled-1.3.3}/.vscode/launch.json +0 -0
  31. {fastled-1.3.0 → fastled-1.3.3}/.vscode/settings.json +0 -0
  32. {fastled-1.3.0 → fastled-1.3.3}/.vscode/tasks.json +0 -0
  33. {fastled-1.3.0 → fastled-1.3.3}/Dockerfile +0 -0
  34. {fastled-1.3.0 → fastled-1.3.3}/LICENSE +0 -0
  35. {fastled-1.3.0 → fastled-1.3.3}/MANIFEST.in +0 -0
  36. {fastled-1.3.0 → fastled-1.3.3}/README.md +0 -0
  37. {fastled-1.3.0 → fastled-1.3.3}/RELEASE.md +0 -0
  38. {fastled-1.3.0 → fastled-1.3.3}/TODO.md +0 -0
  39. {fastled-1.3.0 → fastled-1.3.3}/build_exe.py +0 -0
  40. {fastled-1.3.0 → fastled-1.3.3}/build_local_docker.py +0 -0
  41. {fastled-1.3.0 → fastled-1.3.3}/build_site.py +0 -0
  42. {fastled-1.3.0 → fastled-1.3.3}/clean +0 -0
  43. {fastled-1.3.0 → fastled-1.3.3}/compiler/CMakeLists.txt +0 -0
  44. {fastled-1.3.0 → fastled-1.3.3}/compiler/arduino-pre-process.sh +0 -0
  45. {fastled-1.3.0 → fastled-1.3.3}/compiler/debug.sh +0 -0
  46. {fastled-1.3.0 → fastled-1.3.3}/compiler/entrypoint.sh +0 -0
  47. {fastled-1.3.0 → fastled-1.3.3}/compiler/final_prewarm.sh +0 -0
  48. {fastled-1.3.0 → fastled-1.3.3}/compiler/init_runtime.py +0 -0
  49. {fastled-1.3.0 → fastled-1.3.3}/compiler/install-arduino-cli.sh +0 -0
  50. {fastled-1.3.0 → fastled-1.3.3}/compiler/libcompile/CMakeLists.txt +0 -0
  51. {fastled-1.3.0 → fastled-1.3.3}/compiler/prewarm.sh +0 -0
  52. {fastled-1.3.0 → fastled-1.3.3}/compiler/process-ino.py +0 -0
  53. {fastled-1.3.0 → fastled-1.3.3}/compiler/run.py +0 -0
  54. {fastled-1.3.0 → fastled-1.3.3}/demo/100dots.html +0 -0
  55. {fastled-1.3.0 → fastled-1.3.3}/demo/demo_threejs.html +0 -0
  56. {fastled-1.3.0 → fastled-1.3.3}/demo/micdemo.html +0 -0
  57. {fastled-1.3.0 → fastled-1.3.3}/demo/mp3upload.html +0 -0
  58. {fastled-1.3.0 → fastled-1.3.3}/demo/webgl_postprocessing_unreal_bloom.html +0 -0
  59. {fastled-1.3.0 → fastled-1.3.3}/docker-compose.yml +0 -0
  60. {fastled-1.3.0 → fastled-1.3.3}/install +0 -0
  61. {fastled-1.3.0 → fastled-1.3.3}/install_linux.sh +0 -0
  62. {fastled-1.3.0 → fastled-1.3.3}/lint +0 -0
  63. {fastled-1.3.0 → fastled-1.3.3}/requirements.testing.txt +0 -0
  64. {fastled-1.3.0 → fastled-1.3.3}/setup.cfg +0 -0
  65. {fastled-1.3.0 → fastled-1.3.3}/setup.py +0 -0
  66. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/app.py +0 -0
  67. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/assets/example.txt +0 -0
  68. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/assets/localhost-key.pem +0 -0
  69. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/assets/localhost.pem +0 -0
  70. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/cli.py +0 -0
  71. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/cli_test.py +0 -0
  72. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/cli_test_interactive.py +0 -0
  73. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/client_server.py +0 -0
  74. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/filewatcher.py +0 -0
  75. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/keyboard.py +0 -0
  76. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/keyz.py +0 -0
  77. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/live_client.py +0 -0
  78. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/open_browser.py +0 -0
  79. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/parse_args.py +0 -0
  80. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/paths.py +0 -0
  81. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/project_init.py +0 -0
  82. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/select_sketch_directory.py +0 -0
  83. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/server_start.py +0 -0
  84. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/settings.py +0 -0
  85. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/site/build.py +0 -0
  86. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/site/examples.py +0 -0
  87. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/sketch.py +0 -0
  88. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/spinner.py +0 -0
  89. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/string_diff.py +0 -0
  90. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/test/can_run_local_docker_tests.py +0 -0
  91. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/test/examples.py +0 -0
  92. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/types.py +0 -0
  93. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/util.py +0 -0
  94. {fastled-1.3.0 → fastled-1.3.3}/src/fastled/web_compile.py +0 -0
  95. {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/dependency_links.txt +0 -0
  96. {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/entry_points.txt +0 -0
  97. {fastled-1.3.0 → fastled-1.3.3}/src/fastled.egg-info/top_level.txt +0 -0
  98. {fastled-1.3.0 → fastled-1.3.3}/test +0 -0
  99. {fastled-1.3.0 → fastled-1.3.3}/tests/integration/test_build_examples.py +0 -0
  100. {fastled-1.3.0 → fastled-1.3.3}/tests/integration/test_examples.py +0 -0
  101. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/html/index.html +0 -0
  102. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_api.py +0 -0
  103. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_bad_ino.py +0 -0
  104. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_cli.py +0 -0
  105. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_compile_server.py +0 -0
  106. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_docker_linux_on_windows.py +0 -0
  107. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_embedded_data.py +0 -0
  108. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_filechanger.py +0 -0
  109. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_http_server.py +0 -0
  110. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/bad/bad.ino +0 -0
  111. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
  112. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
  113. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
  114. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/embedded/wasm.ino +0 -0
  115. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_ino/wasm/wasm.ino +0 -0
  116. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_print_filter.py +0 -0
  117. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_project_init.py +0 -0
  118. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_server_and_client_seperatly.py +0 -0
  119. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_string_diff.py +0 -0
  120. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_version.py +0 -0
  121. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_version_matches.py +0 -0
  122. {fastled-1.3.0 → fastled-1.3.3}/tests/unit/test_webcompile.py +0 -0
  123. {fastled-1.3.0 → fastled-1.3.3}/upload_package.sh +0 -0
  124. {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.0
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.22
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.22", # Also versions fastled-wasm-compiler dependency.
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.22", # Enforced by unit test to match project <--> docker.
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, FileResponse, Platform
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, FileResponse
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.timestamp} {self.output_artifact} {self.build_flags} {self.compile_or_link} {self.hash}"
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 handle_dwarfsource(path: str) -> Response:
129
- """Handle requests to /drawfsource/js/fastled/src/
130
- or /drawfsource/js/drawfsource/emsdk/*"""
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
- if path.startswith("drawfsource/"):
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 handle_dwarfsource(path)
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.0
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.22
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/test_fetch_source_files.py
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
@@ -8,4 +8,4 @@ progress>=1.6
8
8
  watchfiles>=1.0.5
9
9
  Flask>=3.0.0
10
10
  livereload
11
- fastled-wasm-server>=1.0.22
11
+ fastled-wasm-server>=1.0.25
@@ -124,43 +124,89 @@ src/third_party/cq_kernel/kiss_fft.c
124
124
  """
125
125
 
126
126
 
127
- class ExperimentalPrintFitlerCppTester(unittest.TestCase):
128
- """Main tester class."""
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
- # def test_print_filter_no_build(self) -> None:
131
- # """Tests that a project can be filtered"""
132
- # # Test the PrintFilter class
133
- # cbc = ChunkedBuildConfigGrouper()
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
- # print(f"\n###Filtering:\n\n{_BUILD_CONFIG_SAMPLE}")
136
- # out = cbc.filter(_BUILD_CONFIG_SAMPLE)
137
- # #print(out)
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
- last_hash: int | None = None
204
+ filter: Filter = Filter()
147
205
  for line in lines:
148
- ba = BuildArtifact.parse(line)
149
- if ba is None:
150
- print("!!")
151
- continue
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 = False
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
- f"http://localhost:{http_port}/sourcefiles/FastLED.h",
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