feat: add clean shutdown for file watcher thread

This commit is contained in:
Paul Gauthier (aider) 2024-10-25 12:43:31 -07:00
parent 3db3150a7e
commit b985a8d47a
2 changed files with 32 additions and 3 deletions

View file

@ -1,5 +1,6 @@
import base64 import base64
import os import os
import threading
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
@ -360,6 +361,26 @@ class InputOutput:
): ):
self.rule() self.rule()
# Add a variable to store changed files and create stop event
self.changed_files = None
stop_event = threading.Event()
# Define the watcher thread function
def watch_files():
try:
for changed in watch_source_files(root, stop_event=stop_event):
if changed:
self.changed_files = list(changed)[0] # Take the first changed file
self.interrupt_input()
break
except Exception as e:
self.tool_error(f"File watcher error: {e}")
# Start the watcher thread
watcher = threading.Thread(target=watch_files, daemon=True)
watcher.start()
try:
rel_fnames = list(rel_fnames) rel_fnames = list(rel_fnames)
show = "" show = ""
if rel_fnames: if rel_fnames:
@ -438,6 +459,13 @@ class InputOutput:
self.user_input(inp) self.user_input(inp)
return inp return inp
finally:
# Clean up the watcher thread
stop_event.set()
watcher.join(timeout=1.0) # Wait up to 1 second for thread to finish
if watcher.is_alive():
self.tool_warning("Warning: File watcher thread did not shut down cleanly")
def add_to_input_history(self, inp): def add_to_input_history(self, inp):
if not self.input_history_file: if not self.input_history_file:
return return

View file

@ -58,13 +58,14 @@ def load_gitignores(gitignore_paths: list[Path]) -> Optional[PathSpec]:
return PathSpec.from_lines(GitWildMatchPattern, patterns) if patterns else None return PathSpec.from_lines(GitWildMatchPattern, patterns) if patterns else None
def watch_source_files(directory: str, gitignores: list[str] = None, ignore_func=None) -> Set[str]: def watch_source_files(directory: str, stop_event=None, gitignores: list[str] = None, ignore_func=None) -> Set[str]:
""" """
Watch for changes to source files in the given directory and its subdirectories. Watch for changes to source files in the given directory and its subdirectories.
Returns a set of changed file paths whenever changes are detected. Returns a set of changed file paths whenever changes are detected.
Args: Args:
directory: Root directory to watch directory: Root directory to watch
stop_event: Threading event to signal when to stop watching
gitignores: List of paths to .gitignore files (optional) gitignores: List of paths to .gitignore files (optional)
ignore_func: Optional function that takes a path (relative to watched directory) ignore_func: Optional function that takes a path (relative to watched directory)
and returns True if it should be ignored and returns True if it should be ignored
@ -92,7 +93,7 @@ def watch_source_files(directory: str, gitignores: list[str] = None, ignore_func
return is_source_file(path_obj) return is_source_file(path_obj)
# Watch the directory for changes # Watch the directory for changes
for changes in watch(root, watch_filter=filter_func): for changes in watch(root, watch_filter=filter_func, stop_event=stop_event):
# Convert the changes to a set of unique file paths # Convert the changes to a set of unique file paths
changed_files = {str(Path(change[1])) for change in changes} changed_files = {str(Path(change[1])) for change in changes}
yield changed_files yield changed_files