fastled 1.0.8__py2.py3-none-any.whl → 1.0.11__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/app.py CHANGED
@@ -1,376 +1,409 @@
1
- """
2
- Uses the latest wasm compiler image to compile the FastLED sketch.
3
- """
4
-
5
- import argparse
6
- import os
7
- import platform
8
- import shutil
9
- import subprocess
10
- import sys
11
- import tempfile
12
- import time
13
- from dataclasses import dataclass
14
- from pathlib import Path
15
-
16
- from fastled import __version__
17
- from fastled.build_mode import BuildMode, get_build_mode
18
- from fastled.compile_server import CompileServer, looks_like_fastled_repo
19
- from fastled.docker_manager import DockerManager
20
- from fastled.filewatcher import FileChangedNotifier
21
- from fastled.open_browser import open_browser_thread
22
- from fastled.sketch import looks_like_sketch_directory
23
- from fastled.web_compile import web_compile
24
-
25
- machine = platform.machine().lower()
26
- IS_ARM: bool = "arm" in machine or "aarch64" in machine
27
- PLATFORM_TAG: str = "-arm64" if IS_ARM else ""
28
- CONTAINER_NAME = f"fastled-wasm-compiler{PLATFORM_TAG}"
29
- DEFAULT_URL = "https://fastled.onrender.com"
30
-
31
-
32
- @dataclass
33
- class CompiledResult:
34
- """Dataclass to hold the result of the compilation."""
35
-
36
- success: bool
37
- fastled_js: str
38
- hash_value: str | None
39
-
40
-
41
- DOCKER = DockerManager(container_name=CONTAINER_NAME)
42
-
43
-
44
- def parse_args() -> argparse.Namespace:
45
- """Parse command-line arguments."""
46
- parser = argparse.ArgumentParser(description=f"FastLED WASM Compiler {__version__}")
47
- parser.add_argument(
48
- "--version", action="version", version=f"%(prog)s {__version__}"
49
- )
50
- parser.add_argument(
51
- "directory",
52
- type=str,
53
- nargs="?",
54
- default=None,
55
- help="Directory containing the FastLED sketch to compile",
56
- )
57
- parser.add_argument(
58
- "--just-compile",
59
- action="store_true",
60
- help="Just compile, skip opening the browser and watching for changes.",
61
- )
62
- parser.add_argument(
63
- "--web",
64
- "-w",
65
- type=str,
66
- nargs="?",
67
- # const does not seem to be working as expected
68
- const=DEFAULT_URL, # Default value when --web is specified without value
69
- help="Use web compiler. Optional URL can be provided (default: https://fastled.onrender.com)",
70
- )
71
- parser.add_argument(
72
- "-i",
73
- "--interactive",
74
- action="store_true",
75
- help="Run in interactive mode (Not available with --web)",
76
- )
77
- parser.add_argument(
78
- "--profile",
79
- action="store_true",
80
- help="Enable profiling for web compilation",
81
- )
82
- build_mode = parser.add_mutually_exclusive_group()
83
- build_mode.add_argument("--debug", action="store_true", help="Build in debug mode")
84
- build_mode.add_argument(
85
- "--quick",
86
- action="store_true",
87
- default=True,
88
- help="Build in quick mode (default)",
89
- )
90
- build_mode.add_argument(
91
- "--release", action="store_true", help="Build in release mode"
92
- )
93
- build_mode.add_argument(
94
- "--server",
95
- action="store_true",
96
- help="Run the server in the current directory, volume mapping fastled if we are in the repo",
97
- )
98
-
99
- build_mode.add_argument(
100
- "--force-compile",
101
- action="store_true",
102
- help="Skips the test to see if the current directory is a valid FastLED sketch directory",
103
- )
104
-
105
- args = parser.parse_args()
106
- if args.server and args.web:
107
- parser.error("--server and --web are mutually exclusive")
108
- if args.directory is None and not args.server:
109
- # does current directory look like a sketch?
110
- maybe_sketch_dir = Path(os.getcwd())
111
- if looks_like_sketch_directory(maybe_sketch_dir):
112
- args.directory = str(maybe_sketch_dir)
113
- else:
114
- print(
115
- "\nYou either need to specify a sketch directory or run in --server mode."
116
- )
117
- sys.exit(1)
118
- return args
119
-
120
-
121
- def run_web_compiler(
122
- directory: Path,
123
- host: str,
124
- build_mode: BuildMode,
125
- profile: bool,
126
- last_hash_value: str | None,
127
- ) -> CompiledResult:
128
- input_dir = Path(directory)
129
- output_dir = input_dir / "fastled_js"
130
- start = time.time()
131
- web_result = web_compile(
132
- directory=input_dir, host=host, build_mode=build_mode, profile=profile
133
- )
134
- diff = time.time() - start
135
- if not web_result.success:
136
- print("\nWeb compilation failed:")
137
- print(f"Time taken: {diff:.2f} seconds")
138
- print(web_result.stdout)
139
- return CompiledResult(success=False, fastled_js="", hash_value=None)
140
-
141
- def print_results() -> None:
142
- hash_value = (
143
- web_result.hash_value
144
- if web_result.hash_value is not None
145
- else "NO HASH VALUE"
146
- )
147
- print(
148
- f"\nWeb compilation successful\n Time: {diff:.2f}\n output: {output_dir}\n hash: {hash_value}\n zip size: {len(web_result.zip_bytes)} bytes"
149
- )
150
-
151
- # now check to see if the hash value is the same as the last hash value
152
- if last_hash_value is not None and last_hash_value == web_result.hash_value:
153
- print("\nSkipping redeploy: No significant changes found.")
154
- print_results()
155
- return CompiledResult(
156
- success=True, fastled_js=str(output_dir), hash_value=web_result.hash_value
157
- )
158
-
159
- # Extract zip contents to fastled_js directory
160
- output_dir.mkdir(exist_ok=True)
161
- with tempfile.TemporaryDirectory() as temp_dir:
162
- temp_path = Path(temp_dir)
163
- temp_zip = temp_path / "result.zip"
164
- temp_zip.write_bytes(web_result.zip_bytes)
165
-
166
- # Clear existing contents
167
- shutil.rmtree(output_dir, ignore_errors=True)
168
- output_dir.mkdir(exist_ok=True)
169
-
170
- # Extract zip contents
171
- shutil.unpack_archive(temp_zip, output_dir, "zip")
172
-
173
- print(web_result.stdout)
174
- print_results()
175
- return CompiledResult(
176
- success=True, fastled_js=str(output_dir), hash_value=web_result.hash_value
177
- )
178
-
179
-
180
- def _try_start_server_or_get_url(args: argparse.Namespace) -> str | CompileServer:
181
- if args.web:
182
- if isinstance(args.web, str):
183
- return args.web
184
- if isinstance(args.web, bool):
185
- return DEFAULT_URL
186
- return args.web
187
- else:
188
- try:
189
- compile_server = CompileServer()
190
- print("Waiting for the local compiler to start...")
191
- if not compile_server.wait_for_startup():
192
- print("Failed to start local compiler.")
193
- raise RuntimeError("Failed to start local compiler.")
194
- return compile_server
195
- except KeyboardInterrupt:
196
- raise
197
- except RuntimeError:
198
- print("Failed to start local compile server, using web compiler instead.")
199
- return DEFAULT_URL
200
-
201
-
202
- def run_client(args: argparse.Namespace) -> int:
203
- compile_server: CompileServer | None = None
204
- open_web_browser = not args.just_compile
205
- profile = args.profile
206
- if not args.force_compile and not looks_like_sketch_directory(Path(args.directory)):
207
- print(
208
- "Error: Not a valid FastLED sketch directory, if you are sure it is, use --force-compile"
209
- )
210
- return 1
211
-
212
- # If not explicitly using web compiler, check Docker installation
213
- if not args.web and not DOCKER.is_docker_installed():
214
- print(
215
- "\nDocker is not installed on this system - switching to web compiler instead."
216
- )
217
- args.web = True
218
-
219
- url: str
220
- try:
221
- try:
222
- url_or_server: str | CompileServer = _try_start_server_or_get_url(args)
223
- if isinstance(url_or_server, str):
224
- print(f"Found URL: {url_or_server}")
225
- url = url_or_server
226
- else:
227
- compile_server = url_or_server
228
- print(f"Server started at {compile_server.url()}")
229
- url = compile_server.url()
230
- except KeyboardInterrupt:
231
- print("\nExiting from first try...")
232
- if compile_server:
233
- compile_server.stop()
234
- return 1
235
- except Exception as e:
236
- print(f"Error: {e}")
237
- return 1
238
- build_mode: BuildMode = get_build_mode(args)
239
-
240
- def compile_function(
241
- url: str = url,
242
- build_mode: BuildMode = build_mode,
243
- profile: bool = profile,
244
- last_hash_value: str | None = None,
245
- ) -> CompiledResult:
246
- return run_web_compiler(
247
- args.directory,
248
- host=url,
249
- build_mode=build_mode,
250
- profile=profile,
251
- last_hash_value=last_hash_value,
252
- )
253
-
254
- result: CompiledResult = compile_function(last_hash_value=None)
255
- last_compiled_result: CompiledResult = result
256
-
257
- if not result.success:
258
- print("\nCompilation failed.")
259
- return 1
260
-
261
- browser_proc: subprocess.Popen | None = None
262
- if open_web_browser:
263
- browser_proc = open_browser_thread(Path(args.directory) / "fastled_js")
264
- else:
265
- print(
266
- "\nCompilation successful. Run without --just-compile to open in browser and watch for changes."
267
- )
268
- if compile_server:
269
- print("Shutting down compile server...")
270
- compile_server.stop()
271
- return 0
272
-
273
- if args.just_compile:
274
- if compile_server:
275
- compile_server.stop()
276
- if browser_proc:
277
- browser_proc.kill()
278
- return 0 if result.success else 1
279
- except KeyboardInterrupt:
280
- print("\nExiting from main")
281
- if compile_server:
282
- compile_server.stop()
283
- return 1
284
-
285
- # Watch mode
286
- print("\nWatching for changes. Press Ctrl+C to stop...")
287
- watcher = FileChangedNotifier(args.directory, excluded_patterns=["fastled_js"])
288
- watcher.start()
289
-
290
- try:
291
- while True:
292
- try:
293
- changed_files = watcher.get_all_changes()
294
- except KeyboardInterrupt:
295
- print("\nExiting from watcher...")
296
- raise
297
- except Exception as e:
298
- print(f"Error getting changes: {e}")
299
- changed_files = []
300
- if changed_files:
301
- print(f"\nChanges detected in {changed_files}")
302
- last_hash_value = last_compiled_result.hash_value
303
- result = compile_function(last_hash_value=last_hash_value)
304
- if not result.success:
305
- print("\nRecompilation failed.")
306
- else:
307
- print("\nRecompilation successful.")
308
- time.sleep(0.3)
309
- except KeyboardInterrupt:
310
- watcher.stop()
311
- print("\nStopping watch mode...")
312
- return 0
313
- except Exception as e:
314
- watcher.stop()
315
- print(f"Error: {e}")
316
- return 1
317
- finally:
318
- watcher.stop()
319
- if compile_server:
320
- compile_server.stop()
321
- if browser_proc:
322
- browser_proc.kill()
323
-
324
-
325
- def run_server(args: argparse.Namespace) -> int:
326
- interactive = args.interactive
327
- compile_server = CompileServer(interactive=interactive)
328
- if not interactive:
329
- print(f"Server started at {compile_server.url()}")
330
- compile_server.wait_for_startup()
331
- try:
332
- while True:
333
- if not compile_server.proceess_running():
334
- print("Server process is not running. Exiting...")
335
- return 1
336
- time.sleep(1)
337
- except KeyboardInterrupt:
338
- print("\nExiting from server...")
339
- return 1
340
- finally:
341
- compile_server.stop()
342
- return 0
343
-
344
-
345
- def main() -> int:
346
- args = parse_args()
347
- target_dir = Path(args.directory)
348
- cwd_is_target_dir = target_dir == Path(os.getcwd())
349
- force_server = cwd_is_target_dir and looks_like_fastled_repo(target_dir)
350
- auto_server = (args.server or args.interactive or cwd_is_target_dir) and (
351
- not args.web and not args.just_compile
352
- )
353
- if auto_server or force_server:
354
- print("Running in server only mode.")
355
- return run_server(args)
356
- else:
357
- print("Running in client/server mode.")
358
- return run_client(args)
359
-
360
-
361
- if __name__ == "__main__":
362
- try:
363
- project_root = Path(__file__).resolve().parent.parent.parent
364
- print(f"Project root: {project_root}")
365
- os.chdir(project_root)
366
- os.chdir("../fastled")
367
- sys.argv.append("examples/wasm")
368
- sys.argv.append("--server")
369
- sys.argv.append("--interactive")
370
- sys.exit(main())
371
- except KeyboardInterrupt:
372
- print("\nExiting from main...")
373
- sys.exit(1)
374
- except Exception as e:
375
- print(f"Error: {e}")
376
- sys.exit(1)
1
+ """
2
+ Uses the latest wasm compiler image to compile the FastLED sketch.
3
+ """
4
+
5
+ import argparse
6
+ import os
7
+ import platform
8
+ import shutil
9
+ import subprocess
10
+ import sys
11
+ import tempfile
12
+ import time
13
+ from dataclasses import dataclass
14
+ from pathlib import Path
15
+
16
+ from fastled import __version__
17
+ from fastled.build_mode import BuildMode, get_build_mode
18
+ from fastled.compile_server import CompileServer
19
+ from fastled.docker_manager import DockerManager
20
+ from fastled.filewatcher import FileWatcherProcess
21
+ from fastled.keyboard import SpaceBarWatcher
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
25
+
26
+ machine = platform.machine().lower()
27
+ IS_ARM: bool = "arm" in machine or "aarch64" in machine
28
+ PLATFORM_TAG: str = "-arm64" if IS_ARM else ""
29
+ CONTAINER_NAME = f"fastled-wasm-compiler{PLATFORM_TAG}"
30
+ DEFAULT_URL = "https://fastled.onrender.com"
31
+
32
+
33
+ @dataclass
34
+ class CompiledResult:
35
+ """Dataclass to hold the result of the compilation."""
36
+
37
+ success: bool
38
+ fastled_js: str
39
+ hash_value: str | None
40
+
41
+
42
+ DOCKER = DockerManager(container_name=CONTAINER_NAME)
43
+
44
+
45
+ def parse_args() -> argparse.Namespace:
46
+ """Parse command-line arguments."""
47
+ parser = argparse.ArgumentParser(description=f"FastLED WASM Compiler {__version__}")
48
+ parser.add_argument(
49
+ "--version", action="version", version=f"%(prog)s {__version__}"
50
+ )
51
+ parser.add_argument(
52
+ "directory",
53
+ type=str,
54
+ nargs="?",
55
+ default=None,
56
+ help="Directory containing the FastLED sketch to compile",
57
+ )
58
+ parser.add_argument(
59
+ "--just-compile",
60
+ action="store_true",
61
+ help="Just compile, skip opening the browser and watching for changes.",
62
+ )
63
+ parser.add_argument(
64
+ "--web",
65
+ "-w",
66
+ type=str,
67
+ nargs="?",
68
+ # const does not seem to be working as expected
69
+ const=DEFAULT_URL, # Default value when --web is specified without value
70
+ help="Use web compiler. Optional URL can be provided (default: https://fastled.onrender.com)",
71
+ )
72
+ parser.add_argument(
73
+ "-i",
74
+ "--interactive",
75
+ action="store_true",
76
+ help="Run in interactive mode (Not available with --web)",
77
+ )
78
+ parser.add_argument(
79
+ "--profile",
80
+ action="store_true",
81
+ help="Enable profiling for web compilation",
82
+ )
83
+ build_mode = parser.add_mutually_exclusive_group()
84
+ build_mode.add_argument("--debug", action="store_true", help="Build in debug mode")
85
+ build_mode.add_argument(
86
+ "--quick",
87
+ action="store_true",
88
+ default=True,
89
+ help="Build in quick mode (default)",
90
+ )
91
+ build_mode.add_argument(
92
+ "--release", action="store_true", help="Build in release mode"
93
+ )
94
+ build_mode.add_argument(
95
+ "--localhost",
96
+ action="store_true",
97
+ help="Use localhost for web compilation from an instance of fastled --server",
98
+ )
99
+ build_mode.add_argument(
100
+ "--server",
101
+ action="store_true",
102
+ help="Run the server in the current directory, volume mapping fastled if we are in the repo",
103
+ )
104
+
105
+ build_mode.add_argument(
106
+ "--force-compile",
107
+ action="store_true",
108
+ help="Skips the test to see if the current directory is a valid FastLED sketch directory",
109
+ )
110
+
111
+ args = parser.parse_args()
112
+ if args.localhost:
113
+ args.web = "localhost"
114
+ if args.web is not None:
115
+ args.web = args.web if args.web == "" else args.web
116
+ if args.server and args.web:
117
+ parser.error("--server and --web are mutually exclusive")
118
+ if args.directory is None and not args.server:
119
+ # does current directory look like a sketch?
120
+ maybe_sketch_dir = Path(os.getcwd())
121
+ if looks_like_sketch_directory(maybe_sketch_dir):
122
+ args.directory = str(maybe_sketch_dir)
123
+ else:
124
+ print(
125
+ "\nYou either need to specify a sketch directory or run in --server mode."
126
+ )
127
+ sys.exit(1)
128
+ return args
129
+
130
+
131
+ def run_web_compiler(
132
+ directory: Path,
133
+ host: str,
134
+ build_mode: BuildMode,
135
+ profile: bool,
136
+ last_hash_value: str | None,
137
+ ) -> CompiledResult:
138
+ input_dir = Path(directory)
139
+ output_dir = input_dir / "fastled_js"
140
+ start = time.time()
141
+ web_result = web_compile(
142
+ directory=input_dir, host=host, build_mode=build_mode, profile=profile
143
+ )
144
+ diff = time.time() - start
145
+ if not web_result.success:
146
+ print("\nWeb compilation failed:")
147
+ print(f"Time taken: {diff:.2f} seconds")
148
+ print(web_result.stdout)
149
+ return CompiledResult(success=False, fastled_js="", hash_value=None)
150
+
151
+ def print_results() -> None:
152
+ hash_value = (
153
+ web_result.hash_value
154
+ if web_result.hash_value is not None
155
+ else "NO HASH VALUE"
156
+ )
157
+ print(
158
+ f"\nWeb compilation successful\n Time: {diff:.2f}\n output: {output_dir}\n hash: {hash_value}\n zip size: {len(web_result.zip_bytes)} bytes"
159
+ )
160
+
161
+ # now check to see if the hash value is the same as the last hash value
162
+ if last_hash_value is not None and last_hash_value == web_result.hash_value:
163
+ print("\nSkipping redeploy: No significant changes found.")
164
+ print_results()
165
+ return CompiledResult(
166
+ success=True, fastled_js=str(output_dir), hash_value=web_result.hash_value
167
+ )
168
+
169
+ # Extract zip contents to fastled_js directory
170
+ output_dir.mkdir(exist_ok=True)
171
+ with tempfile.TemporaryDirectory() as temp_dir:
172
+ temp_path = Path(temp_dir)
173
+ temp_zip = temp_path / "result.zip"
174
+ temp_zip.write_bytes(web_result.zip_bytes)
175
+
176
+ # Clear existing contents
177
+ shutil.rmtree(output_dir, ignore_errors=True)
178
+ output_dir.mkdir(exist_ok=True)
179
+
180
+ # Extract zip contents
181
+ shutil.unpack_archive(temp_zip, output_dir, "zip")
182
+
183
+ print(web_result.stdout)
184
+ print_results()
185
+ return CompiledResult(
186
+ success=True, fastled_js=str(output_dir), hash_value=web_result.hash_value
187
+ )
188
+
189
+
190
+ def _try_start_server_or_get_url(args: argparse.Namespace) -> str | CompileServer:
191
+ if args.web:
192
+ if isinstance(args.web, str):
193
+ return args.web
194
+ if isinstance(args.web, bool):
195
+ return DEFAULT_URL
196
+ return args.web
197
+ else:
198
+ try:
199
+ compile_server = CompileServer()
200
+ print("Waiting for the local compiler to start...")
201
+ if not compile_server.wait_for_startup():
202
+ print("Failed to start local compiler.")
203
+ raise RuntimeError("Failed to start local compiler.")
204
+ return compile_server
205
+ except KeyboardInterrupt:
206
+ raise
207
+ except RuntimeError:
208
+ print("Failed to start local compile server, using web compiler instead.")
209
+ return DEFAULT_URL
210
+
211
+
212
+ def run_client(args: argparse.Namespace) -> int:
213
+ compile_server: CompileServer | None = None
214
+ open_web_browser = not args.just_compile
215
+ profile = args.profile
216
+ if not args.force_compile and not looks_like_sketch_directory(Path(args.directory)):
217
+ print(
218
+ "Error: Not a valid FastLED sketch directory, if you are sure it is, use --force-compile"
219
+ )
220
+ return 1
221
+
222
+ # If not explicitly using web compiler, check Docker installation
223
+ if not args.web and not DOCKER.is_docker_installed():
224
+ print(
225
+ "\nDocker is not installed on this system - switching to web compiler instead."
226
+ )
227
+ args.web = True
228
+
229
+ url: str
230
+ try:
231
+ try:
232
+ url_or_server: str | CompileServer = _try_start_server_or_get_url(args)
233
+ if isinstance(url_or_server, str):
234
+ print(f"Found URL: {url_or_server}")
235
+ url = url_or_server
236
+ else:
237
+ compile_server = url_or_server
238
+ print(f"Server started at {compile_server.url()}")
239
+ url = compile_server.url()
240
+ except KeyboardInterrupt:
241
+ print("\nExiting from first try...")
242
+ if compile_server:
243
+ compile_server.stop()
244
+ return 1
245
+ except Exception as e:
246
+ print(f"Error: {e}")
247
+ return 1
248
+ build_mode: BuildMode = get_build_mode(args)
249
+
250
+ def compile_function(
251
+ url: str = url,
252
+ build_mode: BuildMode = build_mode,
253
+ profile: bool = profile,
254
+ last_hash_value: str | None = None,
255
+ ) -> CompiledResult:
256
+ return run_web_compiler(
257
+ args.directory,
258
+ host=url,
259
+ build_mode=build_mode,
260
+ profile=profile,
261
+ last_hash_value=last_hash_value,
262
+ )
263
+
264
+ result: CompiledResult = compile_function(last_hash_value=None)
265
+ last_compiled_result: CompiledResult = result
266
+
267
+ if not result.success:
268
+ print("\nCompilation failed.")
269
+ return 1
270
+
271
+ browser_proc: subprocess.Popen | None = None
272
+ if open_web_browser:
273
+ browser_proc = open_browser_thread(Path(args.directory) / "fastled_js")
274
+ else:
275
+ print(
276
+ "\nCompilation successful. Run without --just-compile to open in browser and watch for changes."
277
+ )
278
+ if compile_server:
279
+ print("Shutting down compile server...")
280
+ compile_server.stop()
281
+ return 0
282
+
283
+ if args.just_compile:
284
+ if compile_server:
285
+ compile_server.stop()
286
+ if browser_proc:
287
+ browser_proc.kill()
288
+ return 0 if result.success else 1
289
+ except KeyboardInterrupt:
290
+ print("\nExiting from main")
291
+ if compile_server:
292
+ compile_server.stop()
293
+ return 1
294
+
295
+ print("\nWatching for changes. Press Ctrl+C to stop...")
296
+ sketch_filewatcher = FileWatcherProcess(
297
+ args.directory, excluded_patterns=["fastled_js"]
298
+ )
299
+
300
+ source_code_watcher: FileWatcherProcess | None = None
301
+ if compile_server and compile_server.using_fastled_src_dir_volume():
302
+ assert compile_server.fastled_src_dir is not None
303
+ source_code_watcher = FileWatcherProcess(
304
+ compile_server.fastled_src_dir, excluded_patterns=[]
305
+ )
306
+
307
+ def trigger_rebuild_if_sketch_changed(
308
+ last_compiled_result: CompiledResult,
309
+ ) -> CompiledResult:
310
+ changed_files = sketch_filewatcher.get_all_changes()
311
+ if changed_files:
312
+ print(f"\nChanges detected in {changed_files}")
313
+ last_hash_value = last_compiled_result.hash_value
314
+ out = compile_function(last_hash_value=last_hash_value)
315
+ if not out.success:
316
+ print("\nRecompilation failed.")
317
+ else:
318
+ print("\nRecompilation successful.")
319
+ return out
320
+ return last_compiled_result
321
+
322
+ try:
323
+ while True:
324
+ last_compiled_result = trigger_rebuild_if_sketch_changed(
325
+ last_compiled_result
326
+ )
327
+ if compile_server and not compile_server.proceess_running():
328
+ print("Server process is not running. Exiting...")
329
+ return 1
330
+ if source_code_watcher is not None:
331
+ changed_files = source_code_watcher.get_all_changes()
332
+ if changed_files:
333
+ print(f"\nChanges detected in FastLED source code: {changed_files}")
334
+ print("Press space bar to trigger compile.")
335
+
336
+ space_key_watcher = SpaceBarWatcher()
337
+ try:
338
+ while True:
339
+ if space_key_watcher.space_bar_pressed():
340
+ print("Space bar pressed, triggering recompile...")
341
+ last_compiled_result = compile_function(
342
+ last_hash_value=None
343
+ )
344
+ print("Finished recompile.")
345
+ break
346
+ elif len(sketch_filewatcher.get_all_changes()) > 0:
347
+ last_compiled_result = compile_function(
348
+ last_hash_value=None
349
+ )
350
+ break
351
+ time.sleep(0.1)
352
+ finally:
353
+ space_key_watcher.stop()
354
+
355
+ except KeyboardInterrupt:
356
+ print("\nStopping watch mode...")
357
+ return 0
358
+ except Exception as e:
359
+ print(f"Error: {e}")
360
+ return 1
361
+ finally:
362
+ sketch_filewatcher.stop()
363
+ if compile_server:
364
+ compile_server.stop()
365
+ if browser_proc:
366
+ browser_proc.kill()
367
+
368
+
369
+ def run_server(args: argparse.Namespace) -> int:
370
+ interactive = args.interactive
371
+ compile_server = CompileServer(interactive=interactive)
372
+ if not interactive:
373
+ print(f"Server started at {compile_server.url()}")
374
+ compile_server.wait_for_startup()
375
+ try:
376
+ while True:
377
+ if not compile_server.proceess_running():
378
+ print("Server process is not running. Exiting...")
379
+ return 1
380
+ time.sleep(1)
381
+ except KeyboardInterrupt:
382
+ print("\nExiting from server...")
383
+ return 1
384
+ finally:
385
+ compile_server.stop()
386
+ return 0
387
+
388
+
389
+ def main() -> int:
390
+ args = parse_args()
391
+ if args.server:
392
+ print("Running in server only mode.")
393
+ return run_server(args)
394
+ else:
395
+ print("Running in client/server mode.")
396
+ return run_client(args)
397
+
398
+
399
+ if __name__ == "__main__":
400
+ try:
401
+ os.chdir("../fastled")
402
+ sys.argv.append("examples/SdCard")
403
+ sys.exit(main())
404
+ except KeyboardInterrupt:
405
+ print("\nExiting from main...")
406
+ sys.exit(1)
407
+ except Exception as e:
408
+ print(f"Error: {e}")
409
+ sys.exit(1)