|
@@ -393,8 +393,7 @@ class RefsContainer(object):
|
|
|
def watch(self):
|
|
|
"""Watch for changes to the refs in this container.
|
|
|
|
|
|
- Returns a context manager that yields tuples with (refname, old_sha,
|
|
|
- new_sha)
|
|
|
+ Returns a context manager that yields tuples with (refname, new_sha)
|
|
|
"""
|
|
|
raise NotImplementedError(self.watch)
|
|
|
|
|
@@ -443,9 +442,9 @@ class DictRefsContainer(RefsContainer):
|
|
|
def get_packed_refs(self):
|
|
|
return {}
|
|
|
|
|
|
- def _notify(self, ref, oldsha, newsha):
|
|
|
+ def _notify(self, ref, newsha):
|
|
|
for watcher in self._watchers:
|
|
|
- watcher._notify((ref, oldsha, newsha))
|
|
|
+ watcher._notify((ref, newsha))
|
|
|
|
|
|
def watch(self):
|
|
|
return _DictRefsWatcher(self)
|
|
@@ -455,7 +454,7 @@ class DictRefsContainer(RefsContainer):
|
|
|
old = self.follow(name)[-1]
|
|
|
new = SYMREF + other
|
|
|
self._refs[name] = new
|
|
|
- self._notify(name, old, new)
|
|
|
+ self._notify(name, new)
|
|
|
self._log(name, old, new, committer=committer, timestamp=timestamp,
|
|
|
timezone=timezone, message=message)
|
|
|
|
|
@@ -468,7 +467,7 @@ class DictRefsContainer(RefsContainer):
|
|
|
self._check_refname(realname)
|
|
|
old = self._refs.get(realname)
|
|
|
self._refs[realname] = new_ref
|
|
|
- self._notify(realname, old, new_ref)
|
|
|
+ self._notify(realname, new_ref)
|
|
|
self._log(realname, old, new_ref, committer=committer,
|
|
|
timestamp=timestamp, timezone=timezone, message=message)
|
|
|
return True
|
|
@@ -478,7 +477,7 @@ class DictRefsContainer(RefsContainer):
|
|
|
if name in self._refs:
|
|
|
return False
|
|
|
self._refs[name] = ref
|
|
|
- self._notify(name, None, ref)
|
|
|
+ self._notify(name, ref)
|
|
|
self._log(name, None, ref, committer=committer, timestamp=timestamp,
|
|
|
timezone=timezone, message=message)
|
|
|
return True
|
|
@@ -492,7 +491,7 @@ class DictRefsContainer(RefsContainer):
|
|
|
except KeyError:
|
|
|
pass
|
|
|
else:
|
|
|
- self._notify(name, old, None)
|
|
|
+ self._notify(name, None)
|
|
|
self._log(name, old, None, committer=committer,
|
|
|
timestamp=timestamp, timezone=timezone, message=message)
|
|
|
return True
|
|
@@ -546,6 +545,47 @@ 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."""
|
|
|
|
|
@@ -892,6 +932,10 @@ 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."""
|