فهرست منبع

Merge pull request #490 from Unrud/hook

Move hook into storage.Collection
Guillaume Ayoub 9 سال پیش
والد
کامیت
ac61b18237
2فایلهای تغییر یافته به همراه26 افزوده شده و 31 حذف شده
  1. 11 27
      radicale/__init__.py
  2. 15 4
      radicale/storage.py

+ 11 - 27
radicale/__init__.py

@@ -33,11 +33,9 @@ import itertools
 import os
 import posixpath
 import pprint
-import shlex
 import socket
 import socketserver
 import ssl
-import subprocess
 import threading
 import urllib
 import wsgiref.simple_server
@@ -313,12 +311,12 @@ class Application:
         if user and is_authenticated:
             principal_path = "/%s/" % user
             if self.authorized(user, principal_path, "w"):
-                with self._lock_collection("r", user):
+                with self.Collection.acquire_lock("r", user):
                     principal = next(
                         self.Collection.discover(principal_path, depth="1"),
                         None)
                 if not principal:
-                    with self._lock_collection("w", user):
+                    with self.Collection.acquire_lock("w", user):
                         self.Collection.create_collection(principal_path)
 
         # Verify content length
@@ -391,20 +389,6 @@ class Application:
             allowed |= self.authorized(user, parent_path, permission)
         return allowed
 
-    @contextmanager
-    def _lock_collection(self, lock_mode, user):
-        """Lock the collection with ``permission`` and execute hook."""
-        with self.Collection.acquire_lock(lock_mode) as value:
-            yield value
-            hook = self.configuration.get("storage", "hook")
-            if lock_mode == "w" and hook:
-                self.logger.debug("Running hook")
-                folder = os.path.expanduser(self.configuration.get(
-                    "storage", "filesystem_folder"))
-                subprocess.check_call(
-                    hook % {"user": shlex.quote(user or "Anonymous")},
-                    shell=True, cwd=folder)
-
     def _read_content(self, environ):
         content_length = int(environ.get("CONTENT_LENGTH") or 0)
         if content_length > 0:
@@ -419,7 +403,7 @@ class Application:
         """Manage DELETE request."""
         if not self._access(user, path, "w"):
             return NOT_ALLOWED
-        with self._lock_collection("w", user):
+        with self.Collection.acquire_lock("w", user):
             item = next(self.Collection.discover(path), None)
             if not self._access(user, path, "w", item):
                 return NOT_ALLOWED
@@ -444,7 +428,7 @@ class Application:
             return client.OK, headers, answer
         if not self._access(user, path, "r"):
             return NOT_ALLOWED
-        with self._lock_collection("r", user):
+        with self.Collection.acquire_lock("r", user):
             item = next(self.Collection.discover(path), None)
             if not self._access(user, path, "r", item):
                 return NOT_ALLOWED
@@ -473,7 +457,7 @@ class Application:
         if not self.authorized(user, path, "w"):
             return NOT_ALLOWED
         content = self._read_content(environ)
-        with self._lock_collection("w", user):
+        with self.Collection.acquire_lock("w", user):
             item = next(self.Collection.discover(path), None)
             if item:
                 return client.CONFLICT, {}, None
@@ -489,7 +473,7 @@ class Application:
         if not self.authorized(user, path, "w"):
             return NOT_ALLOWED
         content = self._read_content(environ)
-        with self._lock_collection("w", user):
+        with self.Collection.acquire_lock("w", user):
             item = next(self.Collection.discover(path), None)
             if item:
                 return client.CONFLICT, {}, None
@@ -509,7 +493,7 @@ class Application:
         if not self._access(user, to_path, "w"):
             return NOT_ALLOWED
 
-        with self._lock_collection("w", user):
+        with self.Collection.acquire_lock("w", user):
             item = next(self.Collection.discover(path), None)
             if not self._access(user, path, "w", item):
                 return NOT_ALLOWED
@@ -547,7 +531,7 @@ class Application:
         if not self._access(user, path, "r"):
             return NOT_ALLOWED
         content = self._read_content(environ)
-        with self._lock_collection("r", user):
+        with self.Collection.acquire_lock("r", user):
             items = self.Collection.discover(
                 path, environ.get("HTTP_DEPTH", "0"))
             # take root item for rights checking
@@ -572,7 +556,7 @@ class Application:
         if not self.authorized(user, path, "w"):
             return NOT_ALLOWED
         content = self._read_content(environ)
-        with self._lock_collection("w", user):
+        with self.Collection.acquire_lock("w", user):
             item = next(self.Collection.discover(path), None)
             if not isinstance(item, self.Collection):
                 return client.CONFLICT, {}, None
@@ -585,7 +569,7 @@ class Application:
         if not self._access(user, path, "w"):
             return NOT_ALLOWED
         content = self._read_content(environ)
-        with self._lock_collection("w", user):
+        with self.Collection.acquire_lock("w", user):
             parent_path = storage.sanitize_path(
                 "/%s/" % posixpath.dirname(path.strip("/")))
             item = next(self.Collection.discover(path), None)
@@ -640,7 +624,7 @@ class Application:
         if not self._access(user, path, "w"):
             return NOT_ALLOWED
         content = self._read_content(environ)
-        with self._lock_collection("r", user):
+        with self.Collection.acquire_lock("r", user):
             item = next(self.Collection.discover(path), None)
             if not self._access(user, path, "w", item):
                 return NOT_ALLOWED

+ 15 - 4
radicale/storage.py

@@ -29,7 +29,9 @@ import errno
 import json
 import os
 import posixpath
+import shlex
 import stat
+import subprocess
 import threading
 import time
 from contextlib import contextmanager
@@ -371,12 +373,14 @@ class BaseCollection:
 
     @classmethod
     @contextmanager
-    def acquire_lock(cls, mode):
+    def acquire_lock(cls, mode, user=None):
         """Set a context manager to lock the whole storage.
 
         ``mode`` must either be "r" for shared access or "w" for exclusive
         access.
 
+        ``user`` is the name of the logged in user or empty.
+
         """
         raise NotImplementedError
 
@@ -743,13 +747,15 @@ class Collection(BaseCollection):
 
     @classmethod
     @contextmanager
-    def acquire_lock(cls, mode):
+    def acquire_lock(cls, mode, user=None):
         def condition():
             if mode == "r":
                 return not cls._writer
             else:
                 return not cls._writer and cls._readers == 0
 
+        folder = os.path.expanduser(cls.configuration.get(
+            "storage", "filesystem_folder"))
         # Use a primitive lock which only works within one process as a
         # precondition for inter-process file-based locking
         with cls._lock:
@@ -770,8 +776,6 @@ class Collection(BaseCollection):
             else:
                 cls._writer = True
             if not cls._lock_file:
-                folder = os.path.expanduser(
-                    cls.configuration.get("storage", "filesystem_folder"))
                 cls._makedirs_synced(folder)
                 lock_path = os.path.join(folder, ".Radicale.lock")
                 cls._lock_file = open(lock_path, "w+")
@@ -797,6 +801,13 @@ class Collection(BaseCollection):
                 cls._lock_file_locked = True
         try:
             yield
+            # execute hook
+            hook = cls.configuration.get("storage", "hook")
+            if mode == "w" and hook:
+                cls.logger.debug("Running hook")
+                subprocess.check_call(
+                    hook % {"user": shlex.quote(user or "Anonymous")},
+                    shell=True, cwd=folder)
         finally:
             with cls._lock:
                 if mode == "r":