fastled 1.1.32__py2.py3-none-any.whl → 1.1.34__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 +1 -1
- fastled/compile_server.py +2 -2
- fastled/docker_manager.py +665 -590
- fastled/filewatcher.py +202 -202
- fastled/open_browser.py +59 -59
- fastled/parse_args.py +12 -5
- fastled/spinner.py +34 -34
- {fastled-1.1.32.dist-info → fastled-1.1.34.dist-info}/METADATA +3 -1
- {fastled-1.1.32.dist-info → fastled-1.1.34.dist-info}/RECORD +13 -13
- {fastled-1.1.32.dist-info → fastled-1.1.34.dist-info}/LICENSE +0 -0
- {fastled-1.1.32.dist-info → fastled-1.1.34.dist-info}/WHEEL +0 -0
- {fastled-1.1.32.dist-info → fastled-1.1.34.dist-info}/entry_points.txt +0 -0
- {fastled-1.1.32.dist-info → fastled-1.1.34.dist-info}/top_level.txt +0 -0
fastled/filewatcher.py
CHANGED
@@ -1,202 +1,202 @@
|
|
1
|
-
"""File system watcher implementation using watchdog
|
2
|
-
"""
|
3
|
-
|
4
|
-
import hashlib
|
5
|
-
import os
|
6
|
-
import queue
|
7
|
-
import threading
|
8
|
-
import time
|
9
|
-
from contextlib import redirect_stdout
|
10
|
-
from multiprocessing import Process, Queue
|
11
|
-
from pathlib import Path
|
12
|
-
from queue import Empty
|
13
|
-
from typing import Dict, Set
|
14
|
-
|
15
|
-
from watchdog.events import FileSystemEvent, FileSystemEventHandler
|
16
|
-
from watchdog.observers import Observer
|
17
|
-
from watchdog.observers.api import BaseObserver
|
18
|
-
|
19
|
-
|
20
|
-
class MyEventHandler(FileSystemEventHandler):
|
21
|
-
def __init__(
|
22
|
-
self,
|
23
|
-
change_queue: queue.Queue,
|
24
|
-
excluded_patterns: Set[str],
|
25
|
-
file_hashes: Dict[str, str],
|
26
|
-
) -> None:
|
27
|
-
super().__init__()
|
28
|
-
self.change_queue = change_queue
|
29
|
-
self.excluded_patterns = excluded_patterns
|
30
|
-
self.file_hashes = file_hashes
|
31
|
-
|
32
|
-
def _get_file_hash(self, filepath: str) -> str:
|
33
|
-
try:
|
34
|
-
with open(filepath, "rb") as f:
|
35
|
-
return hashlib.md5(f.read()).hexdigest()
|
36
|
-
except Exception: # pylint: disable=broad-except
|
37
|
-
return ""
|
38
|
-
|
39
|
-
def on_modified(self, event: FileSystemEvent) -> None:
|
40
|
-
if not event.is_directory:
|
41
|
-
# Convert src_path to str if it's bytes
|
42
|
-
src_path = (
|
43
|
-
event.src_path.decode()
|
44
|
-
if isinstance(event.src_path, bytes)
|
45
|
-
else event.src_path
|
46
|
-
)
|
47
|
-
path = Path(src_path)
|
48
|
-
# Check if any part of the path matches excluded patterns
|
49
|
-
if not any(part in self.excluded_patterns for part in path.parts):
|
50
|
-
new_hash = self._get_file_hash(src_path)
|
51
|
-
if new_hash and new_hash != self.file_hashes.get(src_path):
|
52
|
-
self.file_hashes[src_path] = new_hash
|
53
|
-
self.change_queue.put(src_path)
|
54
|
-
|
55
|
-
|
56
|
-
class FileChangedNotifier(threading.Thread):
|
57
|
-
"""Watches a directory for file changes and queues notifications"""
|
58
|
-
|
59
|
-
def __init__(
|
60
|
-
self,
|
61
|
-
path: str,
|
62
|
-
debounce_seconds: float = 1.0,
|
63
|
-
excluded_patterns: list[str] | None = None,
|
64
|
-
) -> None:
|
65
|
-
"""Initialize the notifier with a path to watch
|
66
|
-
|
67
|
-
Args:
|
68
|
-
path: Directory path to watch for changes
|
69
|
-
debounce_seconds: Minimum time between notifications for the same file
|
70
|
-
excluded_patterns: List of directory/file patterns to exclude from watching
|
71
|
-
"""
|
72
|
-
super().__init__(daemon=True)
|
73
|
-
self.path = path
|
74
|
-
self.observer: BaseObserver | None = None
|
75
|
-
self.event_handler: MyEventHandler | None = None
|
76
|
-
|
77
|
-
# Combine default and user-provided patterns
|
78
|
-
self.excluded_patterns = (
|
79
|
-
set(excluded_patterns) if excluded_patterns is not None else set()
|
80
|
-
)
|
81
|
-
self.stopped = False
|
82
|
-
self.change_queue: queue.Queue = queue.Queue()
|
83
|
-
self.last_notification: Dict[str, float] = {}
|
84
|
-
self.file_hashes: Dict[str, str] = {}
|
85
|
-
self.debounce_seconds = debounce_seconds
|
86
|
-
|
87
|
-
def stop(self) -> None:
|
88
|
-
"""Stop watching for changes"""
|
89
|
-
print("watcher stop")
|
90
|
-
self.stopped = True
|
91
|
-
if self.observer:
|
92
|
-
self.observer.stop()
|
93
|
-
self.observer.join()
|
94
|
-
self.observer = None
|
95
|
-
self.event_handler = None
|
96
|
-
|
97
|
-
def run(self) -> None:
|
98
|
-
"""Thread main loop - starts watching for changes"""
|
99
|
-
self.event_handler = MyEventHandler(
|
100
|
-
self.change_queue, self.excluded_patterns, self.file_hashes
|
101
|
-
)
|
102
|
-
self.observer = Observer()
|
103
|
-
self.observer.schedule(self.event_handler, self.path, recursive=True)
|
104
|
-
self.observer.start()
|
105
|
-
|
106
|
-
try:
|
107
|
-
while not self.stopped:
|
108
|
-
time.sleep(0.1)
|
109
|
-
except KeyboardInterrupt:
|
110
|
-
print("File watcher stopped by user.")
|
111
|
-
finally:
|
112
|
-
self.stop()
|
113
|
-
|
114
|
-
def get_next_change(self, timeout: float = 0.001) -> str | None:
|
115
|
-
"""Get the next file change event from the queue
|
116
|
-
|
117
|
-
Args:
|
118
|
-
timeout: How long to wait for next change in seconds
|
119
|
-
|
120
|
-
Returns:
|
121
|
-
Changed filepath or None if no change within timeout
|
122
|
-
"""
|
123
|
-
try:
|
124
|
-
filepath = self.change_queue.get(timeout=timeout)
|
125
|
-
current_time = time.time()
|
126
|
-
|
127
|
-
# Check if we've seen this file recently
|
128
|
-
last_time = self.last_notification.get(filepath, 0)
|
129
|
-
if current_time - last_time < self.debounce_seconds:
|
130
|
-
return None
|
131
|
-
|
132
|
-
self.last_notification[filepath] = current_time
|
133
|
-
return filepath
|
134
|
-
except KeyboardInterrupt:
|
135
|
-
raise
|
136
|
-
except queue.Empty:
|
137
|
-
return None
|
138
|
-
|
139
|
-
def get_all_changes(self, timeout: float = 0.001) -> list[str]:
|
140
|
-
"""Get all file change events from the queue
|
141
|
-
|
142
|
-
Args:
|
143
|
-
timeout: How long to wait for next change in seconds
|
144
|
-
|
145
|
-
Returns:
|
146
|
-
List of changed filepaths
|
147
|
-
"""
|
148
|
-
changed_files = []
|
149
|
-
while True:
|
150
|
-
changed_file = self.get_next_change(timeout=timeout)
|
151
|
-
if changed_file is None:
|
152
|
-
break
|
153
|
-
changed_files.append(changed_file)
|
154
|
-
# clear all the changes from the queue
|
155
|
-
self.change_queue.queue.clear()
|
156
|
-
return changed_files
|
157
|
-
|
158
|
-
|
159
|
-
def _process_wrapper(root: Path, excluded_patterns: list[str], queue: Queue):
|
160
|
-
with open(os.devnull, "w") as fnull: # Redirect to /dev/null
|
161
|
-
with redirect_stdout(fnull):
|
162
|
-
watcher = FileChangedNotifier(
|
163
|
-
str(root), excluded_patterns=excluded_patterns
|
164
|
-
)
|
165
|
-
watcher.start()
|
166
|
-
while True:
|
167
|
-
try:
|
168
|
-
changed_files = watcher.get_all_changes()
|
169
|
-
for file in changed_files:
|
170
|
-
queue.put(file)
|
171
|
-
except KeyboardInterrupt:
|
172
|
-
break
|
173
|
-
watcher.stop()
|
174
|
-
|
175
|
-
|
176
|
-
class FileWatcherProcess:
|
177
|
-
def __init__(self, root: Path, excluded_patterns: list[str]) -> None:
|
178
|
-
self.queue: Queue = Queue()
|
179
|
-
self.process = Process(
|
180
|
-
target=_process_wrapper,
|
181
|
-
args=(root, excluded_patterns, self.queue),
|
182
|
-
daemon=True,
|
183
|
-
)
|
184
|
-
self.process.start()
|
185
|
-
|
186
|
-
def stop(self):
|
187
|
-
self.process.terminate()
|
188
|
-
self.process.join()
|
189
|
-
self.queue.close()
|
190
|
-
self.queue.join_thread()
|
191
|
-
|
192
|
-
def get_all_changes(self, timeout: float | None = None) -> list[str]:
|
193
|
-
changed_files = []
|
194
|
-
block = timeout is not None
|
195
|
-
|
196
|
-
while True:
|
197
|
-
try:
|
198
|
-
changed_file = self.queue.get(block=block, timeout=timeout)
|
199
|
-
changed_files.append(changed_file)
|
200
|
-
except Empty:
|
201
|
-
break
|
202
|
-
return changed_files
|
1
|
+
"""File system watcher implementation using watchdog
|
2
|
+
"""
|
3
|
+
|
4
|
+
import hashlib
|
5
|
+
import os
|
6
|
+
import queue
|
7
|
+
import threading
|
8
|
+
import time
|
9
|
+
from contextlib import redirect_stdout
|
10
|
+
from multiprocessing import Process, Queue
|
11
|
+
from pathlib import Path
|
12
|
+
from queue import Empty
|
13
|
+
from typing import Dict, Set
|
14
|
+
|
15
|
+
from watchdog.events import FileSystemEvent, FileSystemEventHandler
|
16
|
+
from watchdog.observers import Observer
|
17
|
+
from watchdog.observers.api import BaseObserver
|
18
|
+
|
19
|
+
|
20
|
+
class MyEventHandler(FileSystemEventHandler):
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
change_queue: queue.Queue,
|
24
|
+
excluded_patterns: Set[str],
|
25
|
+
file_hashes: Dict[str, str],
|
26
|
+
) -> None:
|
27
|
+
super().__init__()
|
28
|
+
self.change_queue = change_queue
|
29
|
+
self.excluded_patterns = excluded_patterns
|
30
|
+
self.file_hashes = file_hashes
|
31
|
+
|
32
|
+
def _get_file_hash(self, filepath: str) -> str:
|
33
|
+
try:
|
34
|
+
with open(filepath, "rb") as f:
|
35
|
+
return hashlib.md5(f.read()).hexdigest()
|
36
|
+
except Exception: # pylint: disable=broad-except
|
37
|
+
return ""
|
38
|
+
|
39
|
+
def on_modified(self, event: FileSystemEvent) -> None:
|
40
|
+
if not event.is_directory:
|
41
|
+
# Convert src_path to str if it's bytes
|
42
|
+
src_path = (
|
43
|
+
event.src_path.decode()
|
44
|
+
if isinstance(event.src_path, bytes)
|
45
|
+
else event.src_path
|
46
|
+
)
|
47
|
+
path = Path(src_path)
|
48
|
+
# Check if any part of the path matches excluded patterns
|
49
|
+
if not any(part in self.excluded_patterns for part in path.parts):
|
50
|
+
new_hash = self._get_file_hash(src_path)
|
51
|
+
if new_hash and new_hash != self.file_hashes.get(src_path):
|
52
|
+
self.file_hashes[src_path] = new_hash
|
53
|
+
self.change_queue.put(src_path)
|
54
|
+
|
55
|
+
|
56
|
+
class FileChangedNotifier(threading.Thread):
|
57
|
+
"""Watches a directory for file changes and queues notifications"""
|
58
|
+
|
59
|
+
def __init__(
|
60
|
+
self,
|
61
|
+
path: str,
|
62
|
+
debounce_seconds: float = 1.0,
|
63
|
+
excluded_patterns: list[str] | None = None,
|
64
|
+
) -> None:
|
65
|
+
"""Initialize the notifier with a path to watch
|
66
|
+
|
67
|
+
Args:
|
68
|
+
path: Directory path to watch for changes
|
69
|
+
debounce_seconds: Minimum time between notifications for the same file
|
70
|
+
excluded_patterns: List of directory/file patterns to exclude from watching
|
71
|
+
"""
|
72
|
+
super().__init__(daemon=True)
|
73
|
+
self.path = path
|
74
|
+
self.observer: BaseObserver | None = None
|
75
|
+
self.event_handler: MyEventHandler | None = None
|
76
|
+
|
77
|
+
# Combine default and user-provided patterns
|
78
|
+
self.excluded_patterns = (
|
79
|
+
set(excluded_patterns) if excluded_patterns is not None else set()
|
80
|
+
)
|
81
|
+
self.stopped = False
|
82
|
+
self.change_queue: queue.Queue = queue.Queue()
|
83
|
+
self.last_notification: Dict[str, float] = {}
|
84
|
+
self.file_hashes: Dict[str, str] = {}
|
85
|
+
self.debounce_seconds = debounce_seconds
|
86
|
+
|
87
|
+
def stop(self) -> None:
|
88
|
+
"""Stop watching for changes"""
|
89
|
+
print("watcher stop")
|
90
|
+
self.stopped = True
|
91
|
+
if self.observer:
|
92
|
+
self.observer.stop()
|
93
|
+
self.observer.join()
|
94
|
+
self.observer = None
|
95
|
+
self.event_handler = None
|
96
|
+
|
97
|
+
def run(self) -> None:
|
98
|
+
"""Thread main loop - starts watching for changes"""
|
99
|
+
self.event_handler = MyEventHandler(
|
100
|
+
self.change_queue, self.excluded_patterns, self.file_hashes
|
101
|
+
)
|
102
|
+
self.observer = Observer()
|
103
|
+
self.observer.schedule(self.event_handler, self.path, recursive=True)
|
104
|
+
self.observer.start()
|
105
|
+
|
106
|
+
try:
|
107
|
+
while not self.stopped:
|
108
|
+
time.sleep(0.1)
|
109
|
+
except KeyboardInterrupt:
|
110
|
+
print("File watcher stopped by user.")
|
111
|
+
finally:
|
112
|
+
self.stop()
|
113
|
+
|
114
|
+
def get_next_change(self, timeout: float = 0.001) -> str | None:
|
115
|
+
"""Get the next file change event from the queue
|
116
|
+
|
117
|
+
Args:
|
118
|
+
timeout: How long to wait for next change in seconds
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
Changed filepath or None if no change within timeout
|
122
|
+
"""
|
123
|
+
try:
|
124
|
+
filepath = self.change_queue.get(timeout=timeout)
|
125
|
+
current_time = time.time()
|
126
|
+
|
127
|
+
# Check if we've seen this file recently
|
128
|
+
last_time = self.last_notification.get(filepath, 0)
|
129
|
+
if current_time - last_time < self.debounce_seconds:
|
130
|
+
return None
|
131
|
+
|
132
|
+
self.last_notification[filepath] = current_time
|
133
|
+
return filepath
|
134
|
+
except KeyboardInterrupt:
|
135
|
+
raise
|
136
|
+
except queue.Empty:
|
137
|
+
return None
|
138
|
+
|
139
|
+
def get_all_changes(self, timeout: float = 0.001) -> list[str]:
|
140
|
+
"""Get all file change events from the queue
|
141
|
+
|
142
|
+
Args:
|
143
|
+
timeout: How long to wait for next change in seconds
|
144
|
+
|
145
|
+
Returns:
|
146
|
+
List of changed filepaths
|
147
|
+
"""
|
148
|
+
changed_files = []
|
149
|
+
while True:
|
150
|
+
changed_file = self.get_next_change(timeout=timeout)
|
151
|
+
if changed_file is None:
|
152
|
+
break
|
153
|
+
changed_files.append(changed_file)
|
154
|
+
# clear all the changes from the queue
|
155
|
+
self.change_queue.queue.clear()
|
156
|
+
return changed_files
|
157
|
+
|
158
|
+
|
159
|
+
def _process_wrapper(root: Path, excluded_patterns: list[str], queue: Queue):
|
160
|
+
with open(os.devnull, "w") as fnull: # Redirect to /dev/null
|
161
|
+
with redirect_stdout(fnull):
|
162
|
+
watcher = FileChangedNotifier(
|
163
|
+
str(root), excluded_patterns=excluded_patterns
|
164
|
+
)
|
165
|
+
watcher.start()
|
166
|
+
while True:
|
167
|
+
try:
|
168
|
+
changed_files = watcher.get_all_changes()
|
169
|
+
for file in changed_files:
|
170
|
+
queue.put(file)
|
171
|
+
except KeyboardInterrupt:
|
172
|
+
break
|
173
|
+
watcher.stop()
|
174
|
+
|
175
|
+
|
176
|
+
class FileWatcherProcess:
|
177
|
+
def __init__(self, root: Path, excluded_patterns: list[str]) -> None:
|
178
|
+
self.queue: Queue = Queue()
|
179
|
+
self.process = Process(
|
180
|
+
target=_process_wrapper,
|
181
|
+
args=(root, excluded_patterns, self.queue),
|
182
|
+
daemon=True,
|
183
|
+
)
|
184
|
+
self.process.start()
|
185
|
+
|
186
|
+
def stop(self):
|
187
|
+
self.process.terminate()
|
188
|
+
self.process.join()
|
189
|
+
self.queue.close()
|
190
|
+
self.queue.join_thread()
|
191
|
+
|
192
|
+
def get_all_changes(self, timeout: float | None = None) -> list[str]:
|
193
|
+
changed_files = []
|
194
|
+
block = timeout is not None
|
195
|
+
|
196
|
+
while True:
|
197
|
+
try:
|
198
|
+
changed_file = self.queue.get(block=block, timeout=timeout)
|
199
|
+
changed_files.append(changed_file)
|
200
|
+
except Empty:
|
201
|
+
break
|
202
|
+
return changed_files
|
fastled/open_browser.py
CHANGED
@@ -1,59 +1,59 @@
|
|
1
|
-
import os
|
2
|
-
import socket
|
3
|
-
import sys
|
4
|
-
from multiprocessing import Process
|
5
|
-
from pathlib import Path
|
6
|
-
|
7
|
-
from livereload import Server
|
8
|
-
|
9
|
-
DEFAULT_PORT = 8081
|
10
|
-
|
11
|
-
|
12
|
-
def _open_browser_python(fastled_js: Path, port: int) -> Server:
|
13
|
-
"""Start livereload server in the fastled_js directory using API"""
|
14
|
-
print(f"\nStarting livereload server in {fastled_js} on port {port}")
|
15
|
-
|
16
|
-
# server = Server()
|
17
|
-
# server.watch(str(fastled_js / "index.html"), delay=0.1)
|
18
|
-
# server.setHeader("Cache-Control", "no-cache")
|
19
|
-
# server.serve(root=str(fastled_js), port=port, open_url_delay=0.5)
|
20
|
-
# return server
|
21
|
-
os.system(f"cd {fastled_js} && live-server")
|
22
|
-
|
23
|
-
|
24
|
-
def _find_open_port(start_port: int) -> int:
|
25
|
-
"""Find an open port starting from start_port."""
|
26
|
-
port = start_port
|
27
|
-
while True:
|
28
|
-
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
29
|
-
if sock.connect_ex(("localhost", port)) != 0:
|
30
|
-
return port
|
31
|
-
port += 1
|
32
|
-
|
33
|
-
|
34
|
-
def _run_server(fastled_js: Path, port: int) -> None:
|
35
|
-
"""Function to run in separate process that starts the livereload server"""
|
36
|
-
sys.stderr = open(os.devnull, "w") # Suppress stderr output
|
37
|
-
_open_browser_python(fastled_js, port)
|
38
|
-
try:
|
39
|
-
# Keep the process running
|
40
|
-
while True:
|
41
|
-
pass
|
42
|
-
except KeyboardInterrupt:
|
43
|
-
print("\nShutting down livereload server...")
|
44
|
-
|
45
|
-
|
46
|
-
def open_browser_process(fastled_js: Path, port: int | None = None) -> Process:
|
47
|
-
"""Start livereload server in the fastled_js directory and return the process"""
|
48
|
-
if port is None:
|
49
|
-
port = DEFAULT_PORT
|
50
|
-
|
51
|
-
port = _find_open_port(port)
|
52
|
-
|
53
|
-
process = Process(
|
54
|
-
target=_run_server,
|
55
|
-
args=(fastled_js, port),
|
56
|
-
daemon=True,
|
57
|
-
)
|
58
|
-
process.start()
|
59
|
-
return process
|
1
|
+
import os
|
2
|
+
import socket
|
3
|
+
import sys
|
4
|
+
from multiprocessing import Process
|
5
|
+
from pathlib import Path
|
6
|
+
|
7
|
+
from livereload import Server
|
8
|
+
|
9
|
+
DEFAULT_PORT = 8081
|
10
|
+
|
11
|
+
|
12
|
+
def _open_browser_python(fastled_js: Path, port: int) -> Server:
|
13
|
+
"""Start livereload server in the fastled_js directory using API"""
|
14
|
+
print(f"\nStarting livereload server in {fastled_js} on port {port}")
|
15
|
+
|
16
|
+
# server = Server()
|
17
|
+
# server.watch(str(fastled_js / "index.html"), delay=0.1)
|
18
|
+
# server.setHeader("Cache-Control", "no-cache")
|
19
|
+
# server.serve(root=str(fastled_js), port=port, open_url_delay=0.5)
|
20
|
+
# return server
|
21
|
+
os.system(f"cd {fastled_js} && live-server")
|
22
|
+
|
23
|
+
|
24
|
+
def _find_open_port(start_port: int) -> int:
|
25
|
+
"""Find an open port starting from start_port."""
|
26
|
+
port = start_port
|
27
|
+
while True:
|
28
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
29
|
+
if sock.connect_ex(("localhost", port)) != 0:
|
30
|
+
return port
|
31
|
+
port += 1
|
32
|
+
|
33
|
+
|
34
|
+
def _run_server(fastled_js: Path, port: int) -> None:
|
35
|
+
"""Function to run in separate process that starts the livereload server"""
|
36
|
+
sys.stderr = open(os.devnull, "w") # Suppress stderr output
|
37
|
+
_open_browser_python(fastled_js, port)
|
38
|
+
try:
|
39
|
+
# Keep the process running
|
40
|
+
while True:
|
41
|
+
pass
|
42
|
+
except KeyboardInterrupt:
|
43
|
+
print("\nShutting down livereload server...")
|
44
|
+
|
45
|
+
|
46
|
+
def open_browser_process(fastled_js: Path, port: int | None = None) -> Process:
|
47
|
+
"""Start livereload server in the fastled_js directory and return the process"""
|
48
|
+
if port is None:
|
49
|
+
port = DEFAULT_PORT
|
50
|
+
|
51
|
+
port = _find_open_port(port)
|
52
|
+
|
53
|
+
process = Process(
|
54
|
+
target=_run_server,
|
55
|
+
args=(fastled_js, port),
|
56
|
+
daemon=True,
|
57
|
+
)
|
58
|
+
process.start()
|
59
|
+
return process
|
fastled/parse_args.py
CHANGED
@@ -122,13 +122,20 @@ def parse_args() -> argparse.Namespace:
|
|
122
122
|
and not args.web
|
123
123
|
and not args.server
|
124
124
|
):
|
125
|
-
# print(f"Using web compiler at {DEFAULT_URL}")
|
126
|
-
args.web = DEFAULT_URL
|
127
125
|
if DockerManager.is_docker_installed():
|
128
|
-
|
129
|
-
|
126
|
+
if not DockerManager.ensure_linux_containers_for_windows():
|
127
|
+
print(
|
128
|
+
f"Windows must be in linux containers mode, but is in Windows container mode, Using web compiler at {DEFAULT_URL}."
|
129
|
+
)
|
130
|
+
args.web = DEFAULT_URL
|
131
|
+
else:
|
132
|
+
print(
|
133
|
+
"Docker is installed. Defaulting to --local mode, use --web to override and use the web compiler instead."
|
134
|
+
)
|
135
|
+
args.localhost = True
|
130
136
|
else:
|
131
|
-
print("Docker is not installed. Using web compiler.")
|
137
|
+
print(f"Docker is not installed. Using web compiler at {DEFAULT_URL}.")
|
138
|
+
args.web = DEFAULT_URL
|
132
139
|
if cwd_is_fastled and not args.web and not args.server:
|
133
140
|
print("Forcing --local mode because we are in the FastLED repo")
|
134
141
|
args.localhost = True
|
fastled/spinner.py
CHANGED
@@ -1,34 +1,34 @@
|
|
1
|
-
import _thread
|
2
|
-
import threading
|
3
|
-
import time
|
4
|
-
import warnings
|
5
|
-
|
6
|
-
from progress.spinner import Spinner as SpinnerImpl
|
7
|
-
|
8
|
-
|
9
|
-
class Spinner:
|
10
|
-
def __init__(self, message: str = ""):
|
11
|
-
self.spinner = SpinnerImpl(message)
|
12
|
-
self.event = threading.Event()
|
13
|
-
self.thread = threading.Thread(target=self._spin, daemon=True)
|
14
|
-
self.thread.start()
|
15
|
-
|
16
|
-
def _spin(self) -> None:
|
17
|
-
try:
|
18
|
-
while not self.event.is_set():
|
19
|
-
self.spinner.next()
|
20
|
-
time.sleep(0.1)
|
21
|
-
except KeyboardInterrupt:
|
22
|
-
_thread.interrupt_main()
|
23
|
-
except Exception as e:
|
24
|
-
warnings.warn(f"Spinner thread failed: {e}")
|
25
|
-
|
26
|
-
def stop(self) -> None:
|
27
|
-
self.event.set()
|
28
|
-
self.thread.join()
|
29
|
-
|
30
|
-
def __enter__(self):
|
31
|
-
return self
|
32
|
-
|
33
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
34
|
-
self.stop()
|
1
|
+
import _thread
|
2
|
+
import threading
|
3
|
+
import time
|
4
|
+
import warnings
|
5
|
+
|
6
|
+
from progress.spinner import Spinner as SpinnerImpl
|
7
|
+
|
8
|
+
|
9
|
+
class Spinner:
|
10
|
+
def __init__(self, message: str = ""):
|
11
|
+
self.spinner = SpinnerImpl(message)
|
12
|
+
self.event = threading.Event()
|
13
|
+
self.thread = threading.Thread(target=self._spin, daemon=True)
|
14
|
+
self.thread.start()
|
15
|
+
|
16
|
+
def _spin(self) -> None:
|
17
|
+
try:
|
18
|
+
while not self.event.is_set():
|
19
|
+
self.spinner.next()
|
20
|
+
time.sleep(0.1)
|
21
|
+
except KeyboardInterrupt:
|
22
|
+
_thread.interrupt_main()
|
23
|
+
except Exception as e:
|
24
|
+
warnings.warn(f"Spinner thread failed: {e}")
|
25
|
+
|
26
|
+
def stop(self) -> None:
|
27
|
+
self.event.set()
|
28
|
+
self.thread.join()
|
29
|
+
|
30
|
+
def __enter__(self):
|
31
|
+
return self
|
32
|
+
|
33
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
34
|
+
self.stop()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fastled
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.34
|
4
4
|
Summary: FastLED Wasm Compiler
|
5
5
|
Home-page: https://github.com/zackees/fastled-wasm
|
6
6
|
Maintainer: Zachary Vorhies
|
@@ -163,6 +163,8 @@ A: A big chunk of space is being used by unnecessary javascript `emscripten` is
|
|
163
163
|
|
164
164
|
# Revisions
|
165
165
|
|
166
|
+
* 1.1.34 - On windows check to make sure we are in linux container mode, if not try to switch and if that fails then use `--web` compiler.
|
167
|
+
* 1.1.33 - Auto updating frequency has been reduced from one hour to one day. To update immediatly use `--update`.
|
166
168
|
* 1.1.32 - `--init` now asks for which example you want, then tells you where the example was downloaded to. No longer auto-compiles.
|
167
169
|
* 1.1.31 - `--local` is auto-enabled if docker is installed, use `--web` to force web compiler. Updating is much more pretty.
|
168
170
|
* 1.1.30 - Added `--init` to initialize a demo project.
|