Commit Diff


commit - 68fee245f414f76c48996c61da8527a7a984e101
commit + cef367d5a30420d93301507cf0956eaa30f02e9f
blob - b607e7858e6564a7ff30aafc75bc95bedd204a66
blob + d0f5aac913a25f276b42468a9f032aba5cd125bb
--- NEWS
+++ NEWS
@@ -1,5 +1,8 @@
 0.20.42	UNRELEASED
 
+ * Drop ``RefsContainer.watch`` that was always flaky.
+   (Jelmer Vernooij, #886)
+
 0.20.41	2022-05-24
 
  * Fix wheel uploading, properly. (Ruslan Kuprieiev)
blob - 4420cec17956cbf21104a77d322d3732dbb0cc5e
blob + 1a1fc547e1d0a4f8c074ca2bbc52ff21d66589a7
--- dulwich/refs.py
+++ dulwich/refs.py
@@ -429,37 +429,8 @@ class RefsContainer(object):
             else:
                 ret[src] = dst
         return ret
-
-    def watch(self):
-        """Watch for changes to the refs in this container.
-
-        Returns a context manager that yields tuples with (refname, new_sha)
-        """
-        raise NotImplementedError(self.watch)
-
-
-class _DictRefsWatcher(object):
-    def __init__(self, refs):
-        self._refs = refs
-
-    def __enter__(self):
-        from queue import Queue
-
-        self.queue = Queue()
-        self._refs._watchers.add(self)
-        return self
-
-    def __next__(self):
-        return self.queue.get()
 
-    def _notify(self, entry):
-        self.queue.put_nowait(entry)
 
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self._refs._watchers.remove(self)
-        return False
-
-
 class DictRefsContainer(RefsContainer):
     """RefsContainer backed by a simple dict.
 
@@ -486,9 +457,6 @@ class DictRefsContainer(RefsContainer):
         for watcher in self._watchers:
             watcher._notify((ref, newsha))
 
-    def watch(self):
-        return _DictRefsWatcher(self)
-
     def set_symbolic_ref(
         self,
         name,
@@ -642,50 +610,6 @@ class InfoRefsContainer(RefsContainer):
             return self._refs[name]
 
 
-class _InotifyRefsWatcher(object):
-    def __init__(self, path):
-        import pyinotify
-        from queue import Queue
-
-        self.path = os.fsdecode(path)
-        self.manager = pyinotify.WatchManager()
-        self.manager.add_watch(
-            self.path,
-            pyinotify.IN_DELETE | pyinotify.IN_CLOSE_WRITE | pyinotify.IN_MOVED_TO,
-            rec=True,
-            auto_add=True,
-        )
-
-        self.notifier = pyinotify.ThreadedNotifier(
-            self.manager, default_proc_fun=self._notify
-        )
-        self.queue = Queue()
-
-    def _notify(self, event):
-        if event.dir:
-            return
-        if event.pathname.endswith(".lock"):
-            return
-        ref = os.fsencode(os.path.relpath(event.pathname, self.path))
-        if event.maskname == "IN_DELETE":
-            self.queue.put_nowait((ref, None))
-        elif event.maskname in ("IN_CLOSE_WRITE", "IN_MOVED_TO"):
-            with open(event.pathname, "rb") as f:
-                sha = f.readline().rstrip(b"\n\r")
-                self.queue.put_nowait((ref, sha))
-
-    def __next__(self):
-        return self.queue.get()
-
-    def __enter__(self):
-        self.notifier.start()
-        return self
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self.notifier.stop()
-        return False
-
-
 class DiskRefsContainer(RefsContainer):
     """Refs container that reads refs from disk."""
 
@@ -1085,12 +1009,7 @@ class DiskRefsContainer(RefsContainer):
 
         return True
 
-    def watch(self):
-        import pyinotify  # noqa: F401
 
-        return _InotifyRefsWatcher(self.path)
-
-
 def _split_ref_line(line):
     """Split a single ref line into a tuple of SHA1 and name."""
     fields = line.rstrip(b"\n\r").split(b" ")
blob - cd0a116915e93278f65b6b86369233742c93b37e
blob + 47e38a2eb776e39b8b38ad685df9bd3adcc4cc3c
--- dulwich/tests/test_refs.py
+++ dulwich/tests/test_refs.py
@@ -355,40 +355,7 @@ class RefsContainerTests(object):
         )
         self.assertNotIn(b"refs/remotes/origin/other", self._refs)
 
-    def test_watch(self):
-        self.skipTest("watch sometimes hangs")
-        try:
-            watcher = self._refs.watch()
-        except (NotImplementedError, ImportError):
-            self.skipTest("watching not supported")
-        with watcher:
-            self._refs[
-                b"refs/remotes/origin/other"
-            ] = b"48d01bd4b77fed026b154d16493e5deab78f02ec"
-            change = next(watcher)
-            self.assertEqual(
-                (
-                    b"refs/remotes/origin/other",
-                    b"48d01bd4b77fed026b154d16493e5deab78f02ec",
-                ),
-                change,
-            )
-            self._refs[
-                b"refs/remotes/origin/other"
-            ] = b"48d01bd4b77fed026b154d16493e5deab78f02ed"
-            change = next(watcher)
-            self.assertEqual(
-                (
-                    b"refs/remotes/origin/other",
-                    b"48d01bd4b77fed026b154d16493e5deab78f02ed",
-                ),
-                change,
-            )
-            del self._refs[b"refs/remotes/origin/other"]
-            change = next(watcher)
-            self.assertEqual((b"refs/remotes/origin/other", None), change)
 
-
 class DictRefsContainerTests(RefsContainerTests, TestCase):
     def setUp(self):
         TestCase.setUp(self)
blob - 4f2e21a721c32c19ba5d4c4d3753af038c2c17f7
blob + b85a69e625e0293c3cfaa15788a0e83961c3d395
--- setup.py
+++ setup.py
@@ -78,7 +78,6 @@ if has_setuptools:
         'fastimport': ['fastimport'],
         'https': ['urllib3[secure]>=1.24.1'],
         'pgp': ['gpg'],
-        'watch': ['pyinotify'],
         'paramiko': ['paramiko'],
         }
     setup_kwargs['install_requires'] = ['urllib3>=1.24.1', 'certifi']