1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/ItemSupport.py Sun Jan 20 01:13:24 2013 +0100
1.3 @@ -0,0 +1,168 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - ItemSupport library
1.7 +
1.8 + @copyright: 2013 by Paul Boddie <paul@boddie.org.uk>
1.9 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.10 +"""
1.11 +
1.12 +from MoinMoin.util import lock
1.13 +import os
1.14 +
1.15 +# Content storage support.
1.16 +
1.17 +class ItemDirectoryStore:
1.18 +
1.19 + "A directory-based item store."
1.20 +
1.21 + def __init__(self, path, lock_dir):
1.22 +
1.23 + "Initialise an item store for the given 'path' and 'lock_dir'."
1.24 +
1.25 + self.path = path
1.26 + self.next_path = os.path.join(self.path, "next")
1.27 + self.lock_dir = lock_dir
1.28 + self.writelock = lock.WriteLock(lock_dir)
1.29 + self.readlock = lock.ReadLock(lock_dir)
1.30 +
1.31 + def get_next(self):
1.32 +
1.33 + "Return the next item number."
1.34 +
1.35 + next = self.read_next()
1.36 + if next is None:
1.37 + next = self.deduce_next()
1.38 + self.write_next(next)
1.39 + return next
1.40 +
1.41 + def deduce_next(self):
1.42 +
1.43 + "Deduce the next item number from the existing item files."
1.44 +
1.45 + return max([int(filename) for filename in os.listdir(self.path) if filename.isdigit()] or [-1]) + 1
1.46 +
1.47 + def read_next(self):
1.48 +
1.49 + "Read the next item number from a special file."
1.50 +
1.51 + if not os.path.exists(self.next_path):
1.52 + return None
1.53 +
1.54 + f = open(self.next_path)
1.55 + try:
1.56 + try:
1.57 + return int(f.read())
1.58 + except ValueError:
1.59 + return None
1.60 + finally:
1.61 + f.close()
1.62 +
1.63 + def write_next(self, next):
1.64 +
1.65 + "Write the 'next' item number to a special file."
1.66 +
1.67 + f = open(self.next_path, "w")
1.68 + try:
1.69 + f.write(str(next))
1.70 + finally:
1.71 + f.close()
1.72 +
1.73 + def write_item(self, item, next):
1.74 +
1.75 + "Write the given 'item' to a file with the given 'next' item number."
1.76 +
1.77 + f = open(self.get_item_path(next), "w")
1.78 + try:
1.79 + f.write(item)
1.80 + finally:
1.81 + f.close()
1.82 +
1.83 + def read_item(self, number):
1.84 +
1.85 + "Read the item with the given item 'number'."
1.86 +
1.87 + f = open(self.get_item_path(number))
1.88 + try:
1.89 + return f.read()
1.90 + finally:
1.91 + f.close()
1.92 +
1.93 + def get_item_path(self, number):
1.94 +
1.95 + "Get the path for the given item 'number'."
1.96 +
1.97 + path = os.path.abspath(os.path.join(self.path, str(number)))
1.98 + basepath = os.path.join(self.path, "")
1.99 +
1.100 + if os.path.commonprefix([path, basepath]) != basepath:
1.101 + raise OSError, path
1.102 +
1.103 + return path
1.104 +
1.105 + # High-level methods.
1.106 +
1.107 + def append(self, item):
1.108 +
1.109 + "Append the given 'item' to the store."
1.110 +
1.111 + self.writelock.acquire()
1.112 + try:
1.113 + next = self.get_next()
1.114 + self.write_item(item, next)
1.115 + self.write_next(next + 1)
1.116 + finally:
1.117 + self.writelock.release()
1.118 +
1.119 + def __len__(self):
1.120 +
1.121 + """
1.122 + Return the number of the next item (which should also be the number of
1.123 + items).
1.124 + """
1.125 +
1.126 + self.writelock.acquire()
1.127 + try:
1.128 + return self.get_next()
1.129 + finally:
1.130 + self.writelock.release()
1.131 +
1.132 + def __iter__(self):
1.133 +
1.134 + "Return an iterator over the items in the store."
1.135 +
1.136 + return ItemIterator(self)
1.137 +
1.138 + def __getitem__(self, number):
1.139 +
1.140 + "Return the item with the given 'number'."
1.141 +
1.142 + self.readlock.acquire()
1.143 + try:
1.144 + try:
1.145 + return self.read_item(number)
1.146 + except (IOError, OSError):
1.147 + raise IndexError, number
1.148 + finally:
1.149 + self.readlock.release()
1.150 +
1.151 +class ItemIterator:
1.152 +
1.153 + "An iterator over items in a store."
1.154 +
1.155 + def __init__(self, store):
1.156 + self.store = store
1.157 + self._next = -1
1.158 +
1.159 + def next(self):
1.160 + final = len(self.store)
1.161 +
1.162 + while self._next < final:
1.163 + self._next += 1
1.164 + try:
1.165 + return self.store[self._next]
1.166 + except IndexError:
1.167 + pass
1.168 +
1.169 + raise StopIteration
1.170 +
1.171 +# vim: tabstop=4 expandtab shiftwidth=4