fastled 1.1.7__py2.py3-none-any.whl → 1.1.16__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
fastled/__init__.py CHANGED
@@ -0,0 +1,3 @@
1
+ """FastLED Wasm Compiler package."""
2
+
3
+ __version__ = "1.1.16"
fastled/app.py CHANGED
@@ -1,7 +1,5 @@
1
1
  """
2
2
  Uses the latest wasm compiler image to compile the FastLED sketch.
3
-
4
-
5
3
  """
6
4
 
7
5
  import argparse
@@ -15,13 +13,20 @@ import time
15
13
  from dataclasses import dataclass
16
14
  from pathlib import Path
17
15
 
16
+ from fastled import __version__
18
17
  from fastled.build_mode import BuildMode, get_build_mode
19
- from fastled.compile_server import CompileServer, looks_like_fastled_repo
18
+ from fastled.compile_server import CompileServer
20
19
  from fastled.docker_manager import DockerManager
21
- from fastled.filewatcher import FileChangedNotifier
20
+ from fastled.filewatcher import FileWatcherProcess
21
+ from fastled.keyboard import SpaceBarWatcher
22
22
  from fastled.open_browser import open_browser_thread
23
- from fastled.sketch import looks_like_sketch_directory
24
- from fastled.web_compile import web_compile
23
+ from fastled.sketch import looks_like_fastled_repo, looks_like_sketch_directory
24
+ from fastled.web_compile import (
25
+ SERVER_PORT,
26
+ ConnectionResult,
27
+ find_good_connection,
28
+ web_compile,
29
+ )
25
30
 
26
31
  machine = platform.machine().lower()
27
32
  IS_ARM: bool = "arm" in machine or "aarch64" in machine
@@ -39,12 +44,12 @@ class CompiledResult:
39
44
  hash_value: str | None
40
45
 
41
46
 
42
- DOCKER = DockerManager(container_name=CONTAINER_NAME)
43
-
44
-
45
47
  def parse_args() -> argparse.Namespace:
46
48
  """Parse command-line arguments."""
47
- parser = argparse.ArgumentParser(description="FastLED WASM Compiler")
49
+ parser = argparse.ArgumentParser(description=f"FastLED WASM Compiler {__version__}")
50
+ parser.add_argument(
51
+ "--version", action="version", version=f"%(prog)s {__version__}"
52
+ )
48
53
  parser.add_argument(
49
54
  "directory",
50
55
  type=str,
@@ -88,6 +93,12 @@ def parse_args() -> argparse.Namespace:
88
93
  build_mode.add_argument(
89
94
  "--release", action="store_true", help="Build in release mode"
90
95
  )
96
+ build_mode.add_argument(
97
+ "--localhost",
98
+ "--local",
99
+ action="store_true",
100
+ help="Use localhost for web compilation from an instance of fastled --server, creating it if necessary",
101
+ )
91
102
  build_mode.add_argument(
92
103
  "--server",
93
104
  action="store_true",
@@ -100,9 +111,20 @@ def parse_args() -> argparse.Namespace:
100
111
  help="Skips the test to see if the current directory is a valid FastLED sketch directory",
101
112
  )
102
113
 
114
+ cwd_is_fastled = looks_like_fastled_repo(Path(os.getcwd()))
115
+
103
116
  args = parser.parse_args()
104
- if args.server and args.web:
105
- parser.error("--server and --web are mutually exclusive")
117
+ if not cwd_is_fastled and not args.localhost and not args.web and not args.server:
118
+ print(f"Using web compiler at {DEFAULT_URL}")
119
+ args.web = DEFAULT_URL
120
+ if cwd_is_fastled and not args.web:
121
+ print("Forcing --local mode because we are in the FastLED repo")
122
+ args.localhost = True
123
+ if args.localhost:
124
+ args.web = "localhost"
125
+ if args.interactive and not args.server:
126
+ print("--interactive forces --server mode")
127
+ args.server = True
106
128
  if args.directory is None and not args.server:
107
129
  # does current directory look like a sketch?
108
130
  maybe_sketch_dir = Path(os.getcwd())
@@ -113,6 +135,7 @@ def parse_args() -> argparse.Namespace:
113
135
  "\nYou either need to specify a sketch directory or run in --server mode."
114
136
  )
115
137
  sys.exit(1)
138
+
116
139
  return args
117
140
 
118
141
 
@@ -176,7 +199,24 @@ def run_web_compiler(
176
199
 
177
200
 
178
201
  def _try_start_server_or_get_url(args: argparse.Namespace) -> str | CompileServer:
179
- if args.web:
202
+ is_local_host = "localhost" in args.web or "127.0.0.1" in args.web or args.localhost
203
+
204
+ # test to see if there is already a local host server
205
+ local_host_needs_server = False
206
+ if is_local_host:
207
+ addr = "localhost" if args.localhost else args.web
208
+ urls = [addr]
209
+ if ":" not in addr:
210
+ urls.append(f"{addr}:{SERVER_PORT}")
211
+
212
+ result: ConnectionResult | None = find_good_connection(urls)
213
+ if result is not None:
214
+ print(f"Found local server at {result.host}")
215
+ return result.host
216
+ else:
217
+ local_host_needs_server = True
218
+
219
+ if not local_host_needs_server and args.web:
180
220
  if isinstance(args.web, str):
181
221
  return args.web
182
222
  if isinstance(args.web, bool):
@@ -184,6 +224,7 @@ def _try_start_server_or_get_url(args: argparse.Namespace) -> str | CompileServe
184
224
  return args.web
185
225
  else:
186
226
  try:
227
+ print("No local server found, starting one...")
187
228
  compile_server = CompileServer()
188
229
  print("Waiting for the local compiler to start...")
189
230
  if not compile_server.wait_for_startup():
@@ -199,7 +240,7 @@ def _try_start_server_or_get_url(args: argparse.Namespace) -> str | CompileServe
199
240
 
200
241
  def run_client(args: argparse.Namespace) -> int:
201
242
  compile_server: CompileServer | None = None
202
- open_web_browser = not args.just_compile
243
+ open_web_browser = not args.just_compile and not args.interactive
203
244
  profile = args.profile
204
245
  if not args.force_compile and not looks_like_sketch_directory(Path(args.directory)):
205
246
  print(
@@ -208,7 +249,7 @@ def run_client(args: argparse.Namespace) -> int:
208
249
  return 1
209
250
 
210
251
  # If not explicitly using web compiler, check Docker installation
211
- if not args.web and not DOCKER.is_docker_installed():
252
+ if not args.web and not DockerManager.is_docker_installed():
212
253
  print(
213
254
  "\nDocker is not installed on this system - switching to web compiler instead."
214
255
  )
@@ -260,9 +301,7 @@ def run_client(args: argparse.Namespace) -> int:
260
301
  if open_web_browser:
261
302
  browser_proc = open_browser_thread(Path(args.directory) / "fastled_js")
262
303
  else:
263
- print(
264
- "\nCompilation successful. Run without --just-compile to open in browser and watch for changes."
265
- )
304
+ print("\nCompilation successful.")
266
305
  if compile_server:
267
306
  print("Shutting down compile server...")
268
307
  compile_server.stop()
@@ -280,40 +319,76 @@ def run_client(args: argparse.Namespace) -> int:
280
319
  compile_server.stop()
281
320
  return 1
282
321
 
283
- # Watch mode
284
322
  print("\nWatching for changes. Press Ctrl+C to stop...")
285
- watcher = FileChangedNotifier(args.directory, excluded_patterns=["fastled_js"])
286
- watcher.start()
323
+ sketch_filewatcher = FileWatcherProcess(
324
+ args.directory, excluded_patterns=["fastled_js"]
325
+ )
326
+
327
+ source_code_watcher: FileWatcherProcess | None = None
328
+ if compile_server and compile_server.using_fastled_src_dir_volume():
329
+ assert compile_server.fastled_src_dir is not None
330
+ source_code_watcher = FileWatcherProcess(
331
+ compile_server.fastled_src_dir, excluded_patterns=[]
332
+ )
333
+
334
+ def trigger_rebuild_if_sketch_changed(
335
+ last_compiled_result: CompiledResult,
336
+ ) -> CompiledResult:
337
+ changed_files = sketch_filewatcher.get_all_changes()
338
+ if changed_files:
339
+ print(f"\nChanges detected in {changed_files}")
340
+ last_hash_value = last_compiled_result.hash_value
341
+ out = compile_function(last_hash_value=last_hash_value)
342
+ if not out.success:
343
+ print("\nRecompilation failed.")
344
+ else:
345
+ print("\nRecompilation successful.")
346
+ return out
347
+ return last_compiled_result
287
348
 
288
349
  try:
289
350
  while True:
290
- try:
291
- changed_files = watcher.get_all_changes()
292
- except KeyboardInterrupt:
293
- print("\nExiting from watcher...")
294
- raise
295
- except Exception as e:
296
- print(f"Error getting changes: {e}")
297
- changed_files = []
298
- if changed_files:
299
- print(f"\nChanges detected in {changed_files}")
300
- last_hash_value = last_compiled_result.hash_value
301
- result = compile_function(last_hash_value=last_hash_value)
302
- if not result.success:
303
- print("\nRecompilation failed.")
304
- else:
305
- print("\nRecompilation successful.")
306
- time.sleep(0.3)
351
+ last_compiled_result = trigger_rebuild_if_sketch_changed(
352
+ last_compiled_result
353
+ )
354
+ if compile_server and not compile_server.proceess_running():
355
+ print("Server process is not running. Exiting...")
356
+ return 1
357
+ if source_code_watcher is not None:
358
+ changed_files = source_code_watcher.get_all_changes()
359
+ # de-duplicate changes
360
+ changed_files = sorted(list(set(changed_files)))
361
+ if changed_files:
362
+ print(f"\nChanges detected in FastLED source code: {changed_files}")
363
+ print("Press space bar to trigger compile.")
364
+
365
+ space_key_watcher = SpaceBarWatcher()
366
+ try:
367
+ while True:
368
+ if space_key_watcher.space_bar_pressed():
369
+ print("Space bar pressed, triggering recompile...")
370
+ last_compiled_result = compile_function(
371
+ last_hash_value=None
372
+ )
373
+ print("Finished recompile.")
374
+ break
375
+ elif len(sketch_filewatcher.get_all_changes()) > 0:
376
+ last_compiled_result = compile_function(
377
+ last_hash_value=None
378
+ )
379
+ break
380
+ time.sleep(0.1)
381
+ finally:
382
+ space_key_watcher.stop()
383
+
307
384
  except KeyboardInterrupt:
308
- watcher.stop()
309
385
  print("\nStopping watch mode...")
310
386
  return 0
311
387
  except Exception as e:
312
- watcher.stop()
313
388
  print(f"Error: {e}")
314
389
  return 1
315
390
  finally:
316
- watcher.stop()
391
+ sketch_filewatcher.stop()
317
392
  if compile_server:
318
393
  compile_server.stop()
319
394
  if browser_proc:
@@ -342,13 +417,7 @@ def run_server(args: argparse.Namespace) -> int:
342
417
 
343
418
  def main() -> int:
344
419
  args = parse_args()
345
- target_dir = Path(args.directory)
346
- cwd_is_target_dir = target_dir == Path(os.getcwd())
347
- force_server = cwd_is_target_dir and looks_like_fastled_repo(target_dir)
348
- auto_server = (args.server or args.interactive or cwd_is_target_dir) and (
349
- not args.web and not args.just_compile
350
- )
351
- if auto_server or force_server:
420
+ if args.server:
352
421
  print("Running in server only mode.")
353
422
  return run_server(args)
354
423
  else:
@@ -358,13 +427,8 @@ def main() -> int:
358
427
 
359
428
  if __name__ == "__main__":
360
429
  try:
361
- project_root = Path(__file__).resolve().parent.parent.parent
362
- print(f"Project root: {project_root}")
363
- os.chdir(project_root)
364
430
  os.chdir("../fastled")
365
- sys.argv.append("examples/wasm")
366
431
  sys.argv.append("--server")
367
- sys.argv.append("--interactive")
368
432
  sys.exit(main())
369
433
  except KeyboardInterrupt:
370
434
  print("\nExiting from main...")