diff --git a/spyder/plugins/projects/utils/watcher.py b/spyder/plugins/projects/utils/watcher.py index b11ed519b16..f23a2a563cf 100644 --- a/spyder/plugins/projects/utils/watcher.py +++ b/spyder/plugins/projects/utils/watcher.py @@ -7,19 +7,17 @@ """Watcher to detect filesystem changes in the project's directory.""" # Standard lib imports +import os import logging # Third-party imports from qtpy.QtCore import QObject, Signal -from qtpy.QtWidgets import QMessageBox from superqt.utils import qthrottled import watchdog -from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler, PatternMatchingEventHandler +from watchdog.observers.polling import PollingObserverVFS # Local imports -from spyder.config.base import _ -from spyder.py3compat import to_text_string from spyder.config.utils import get_edit_extensions @@ -142,42 +140,26 @@ def connect_signals(self, project): self.sig_file_modified.connect(project.file_modified) def start(self, workspace_folder): - # Needed to handle an error caused by the inotify limit reached. - # See spyder-ide/spyder#10478 + # We use a polling observer because: + # * It doesn't introduce long freezes on Linux when switching git + # branches that have many changes between them. That's because the + # OS-based observer (i.e. inotify) generates way too many events. + # * The OS-based observer on Windows has many shortcomings (see + # openmsi/openmsistream#56). + # * There doesn't seem to be issues on Mac, but it's simpler to use a + # single observer for all OSes. + self.observer = PollingObserverVFS(stat=os.stat, listdir=os.scandir) + + self.observer.schedule( + self.event_handler, workspace_folder, recursive=True + ) + try: - self.observer = Observer() - self.observer.schedule( - self.event_handler, workspace_folder, recursive=True) - try: - self.observer.start() - except OSError: - # This error happens frequently on Linux - logger.debug("Watcher could not be started.") - except OSError as e: - self.observer = None - if u'inotify' in to_text_string(e): - QMessageBox.warning( - self.parent(), - "Spyder", - _("File system changes for this project can't be tracked " - "because it contains too many files. To fix this you " - "need to increase the inotify limit in your system, " - "with the following command:" - "

" - "" - "sudo sysctl -n -w fs.inotify.max_user_watches=524288" - "" - "

For a permanent solution you need to add to" - "/etc/sysctl.conf" - "the following line:

" - "" - "fs.inotify.max_user_watches=524288" - "" - "

" - "After doing that, you need to close and start Spyder " - "again so those changes can take effect.")) - else: - raise e + self.observer.start() + except Exception: + logger.debug( + f"Observer could not be started for: {workspace_folder}." + ) def stop(self): if self.observer is not None: