changeset 3442:fe130d233204

Allow Xapian to run under Windows (thanks to Don Reid)
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sun, 30 Mar 2008 04:24:38 +0200
parents 8230be5f24d7
children 4ee64d58e801
files MoinMoin/search/builtin.py MoinMoin/support/xapwrap/index.py
diffstat 2 files changed, 127 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/search/builtin.py	Thu Mar 27 14:20:01 2008 +0100
+++ b/MoinMoin/search/builtin.py	Sun Mar 30 04:24:38 2008 +0200
@@ -11,6 +11,9 @@
 """
 
 import time, os, errno, codecs
+import sys
+if sys.platform == 'win32':
+    import win32file, win32con, pywintypes
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
@@ -204,7 +207,34 @@
 
     def touch(self):
         """ Touch the index """
-        os.utime(self.dir, None)
+        if sys.platform == 'win32':
+            access=win32file.GENERIC_WRITE
+            share=win32file.FILE_SHARE_DELETE | \
+                  win32file.FILE_SHARE_READ | \
+                  win32file.FILE_SHARE_WRITE
+            create=win32file.OPEN_EXISTING
+            mtime = time.gmtime()
+            try:
+                handle=win32file.CreateFile(self.dir,
+                                            access,
+                                            share,
+                                            None,
+                                            create,
+                                            win32file.FILE_ATTRIBUTE_NORMAL |
+                                            win32con.FILE_FLAG_BACKUP_SEMANTICS,
+                                            None)
+            except pywintypes.error:
+                raise error, 'open("%s") for touch failed' % self.dir
+            try:
+                newTime = pywintypes.Time(mtime)
+                win32file.SetFileTime(handle,
+                                      newTime,
+                                      newTime,
+                                      newTime)
+            finally:
+                 win32file.CloseHandle(handle)
+        else:
+            os.utime(self.dir, None)
 
     def _search(self, query):
         """ Actually perfom the search (read-lock acquired)
--- a/MoinMoin/support/xapwrap/index.py	Thu Mar 27 14:20:01 2008 +0100
+++ b/MoinMoin/support/xapwrap/index.py	Sun Mar 30 04:24:38 2008 +0200
@@ -126,74 +126,108 @@
 try:
     from atop.tpython import FilesystemLock
 except ImportError:
-    from os import symlink, readlink, remove as rmlink
-    import errno
-
-    class FilesystemLock:
-        """A mutex.
-
-        This relies on the filesystem property that creating
-        a symlink is an atomic operation and that it will
-        fail if the symlink already exists.  Deleting the
-        symlink will release the lock.
+    try:
+        from os import symlink, readlink, remove as rmlink
+    except ImportError:
+        import win32event
 
-        @ivar name: The name of the file associated with this lock.
-        @ivar clean: Indicates whether this lock was released cleanly by its
-        last owner.  Only meaningful after C{lock} has been called and returns
-        True.
-        """
-
-        clean = None
-        locked = False
+        class FilesystemLock:
+            """A mutex
 
-        def __init__(self, name):
-            self.name = name
-
-        def lock(self):
-            """Acquire this lock.
+            A real mutex this time. See the non-win32 version for details.
+            """
 
-            @rtype: C{bool}
-            @return: True if the lock is acquired, false otherwise.
+            locked = False
+            clean = True
 
-            @raise: Any exception os.symlink() may raise, other than
-            EEXIST.
+            def __init__(self, name):
+                #Mutex name cannot contain backslash
+                name = name.replace('\\', '/')
+                self.name = name
+                self._mutex = win32event.CreateMutex(None, False, name)
+                if not self._mutex:
+                    raise RuntimeError("Failed to create a named mutex")
+
+            def lock(self):
+                res = win32event.WaitForSingleObject(self._mutex, 0)
+                self.locked = (res != win32event.WAIT_TIMEOUT)
+                return self.locked
+
+            def unlock(self):
+                #C API ReleaseMutex version is supposed to return something to
+                #tell whether the lock was correctly released or not. The binding
+                #does not.
+                win32event.ReleaseMutex(self._mutex)
+                self.locked = False
+
+    else:
+        import errno
+
+        class FilesystemLock:
+            """A mutex.
+
+            This relies on the filesystem property that creating
+            a symlink is an atomic operation and that it will
+            fail if the symlink already exists.  Deleting the
+            symlink will release the lock.
+
+            @ivar name: The name of the file associated with this lock.
+            @ivar clean: Indicates whether this lock was released cleanly by its
+            last owner.  Only meaningful after C{lock} has been called and returns
+            True.
             """
-            try:
+
+            clean = None
+            locked = False
+
+            def __init__(self, name):
+                self.name = name
+
+            def lock(self):
+                """Acquire this lock.
+
+                @rtype: C{bool}
+                @return: True if the lock is acquired, false otherwise.
+
+                @raise: Any exception os.symlink() may raise, other than
+                EEXIST.
+                """
+                try:
+                    pid = readlink(self.name)
+                except (OSError, IOError), e:
+                    if e.errno != errno.ENOENT:
+                        raise
+                    self.clean = True
+                else:
+                    if not hasattr(os, 'kill'):
+                        return False
+                    try:
+                        os.kill(int(pid), 0)
+                    except (OSError, IOError), e:
+                        if e.errno != errno.ESRCH:
+                            raise
+                        rmlink(self.name)
+                        self.clean = False
+                    else:
+                        return False
+
+                symlink(str(os.getpid()), self.name)
+                self.locked = True
+                return True
+
+            def unlock(self):
+                """Release this lock.
+
+                This deletes the directory with the given name.
+
+                @raise: Any exception os.readlink() may raise, or
+                ValueError if the lock is not owned by this process.
+                """
                 pid = readlink(self.name)
-            except (OSError, IOError), e:
-                if e.errno != errno.ENOENT:
-                    raise
-                self.clean = True
-            else:
-                if not hasattr(os, 'kill'):
-                    return False
-                try:
-                    os.kill(int(pid), 0)
-                except (OSError, IOError), e:
-                    if e.errno != errno.ESRCH:
-                        raise
-                    rmlink(self.name)
-                    self.clean = False
-                else:
-                    return False
-
-            symlink(str(os.getpid()), self.name)
-            self.locked = True
-            return True
-
-        def unlock(self):
-            """Release this lock.
-
-            This deletes the directory with the given name.
-
-            @raise: Any exception os.readlink() may raise, or
-            ValueError if the lock is not owned by this process.
-            """
-            pid = readlink(self.name)
-            if int(pid) != os.getpid():
-                raise ValueError("Lock %r not owned by this process" % (self.name,))
-            rmlink(self.name)
-            self.locked = False
+                if int(pid) != os.getpid():
+                    raise ValueError("Lock %r not owned by this process" % (self.name,))
+                rmlink(self.name)
+                self.locked = False
 
 try:
     from twisted.python.log import msg as log