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 os
import threading
from collections import defaultdict
from dataclasses import dataclass
from datetime import datetime
@ -360,7 +361,27 @@ class InputOutput:
):
self.rule()
rel_fnames = list(rel_fnames)
# 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)
show = ""
if rel_fnames:
rel_read_only_fnames = [
@ -437,6 +458,13 @@ class InputOutput:
print()
self.user_input(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):
if not self.input_history_file:

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
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.
Returns a set of changed file paths whenever changes are detected.
Args:
directory: Root directory to watch
stop_event: Threading event to signal when to stop watching
gitignores: List of paths to .gitignore files (optional)
ignore_func: Optional function that takes a path (relative to watched directory)
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)
# 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
changed_files = {str(Path(change[1])) for change in changes}
yield changed_files