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
2.1 --- a/MoinSupport.py Sat Jan 19 23:12:05 2013 +0100
2.2 +++ b/MoinSupport.py Sun Jan 20 01:13:24 2013 +0100
2.3 @@ -9,6 +9,7 @@
2.4 """
2.5
2.6 from DateSupport import *
2.7 +from ItemSupport import ItemDirectoryStore
2.8 from MoinMoin.Page import Page
2.9 from MoinMoin.util import lock
2.10 from MoinMoin import config, search, wikiutil
2.11 @@ -872,7 +873,7 @@
2.12
2.13 # Content storage support.
2.14
2.15 -class ItemStore:
2.16 +class ItemStore(ItemDirectoryStore):
2.17
2.18 "A page-specific item store."
2.19
2.20 @@ -880,78 +881,8 @@
2.21
2.22 "Initialise an item store for the given 'page'."
2.23
2.24 + ItemDirectoryStore.__init__(self, page.getPagePath(item_dir_name), page.getPagePath(lock_dir_name))
2.25 self.page = page
2.26 - self.path = page.getPagePath(item_dir_name)
2.27 - self.next_path = os.path.join(self.path, "next")
2.28 - lock_dir = page.getPagePath(lock_dir_name)
2.29 - self.lock = lock.WriteLock(lock_dir)
2.30 -
2.31 - def get_next(self):
2.32 -
2.33 - "Return the next item number."
2.34 -
2.35 - next = self.read_next()
2.36 - if not next:
2.37 - next = self.deduce_next()
2.38 - self.write_next(next)
2.39 - return next
2.40 -
2.41 - def deduce_next(self):
2.42 -
2.43 - "Deduce the next item number from the existing item files."
2.44 -
2.45 - return max([int(filename) for filename in os.listdir(self.path) if filename.isdigit()] or [0]) + 1
2.46 -
2.47 - def read_next(self):
2.48 -
2.49 - "Read the next item number from a special file."
2.50 -
2.51 - if not os.path.exists(self.next_path):
2.52 - return 0
2.53 -
2.54 - f = open(self.next_path)
2.55 - try:
2.56 - try:
2.57 - return int(f.read())
2.58 - except ValueError:
2.59 - return 0
2.60 - finally:
2.61 - f.close()
2.62 -
2.63 - def write_next(self, next):
2.64 -
2.65 - "Write the 'next' item number to a special file."
2.66 -
2.67 - f = open(self.next_path, "w")
2.68 - try:
2.69 - f.write(str(next))
2.70 - finally:
2.71 - f.close()
2.72 -
2.73 - def write_item(self, item, next):
2.74 -
2.75 - "Write the given 'item' to a file with the given 'next' item number."
2.76 -
2.77 - f = open(os.path.join(self.path, str(next)), "w")
2.78 - try:
2.79 - f.write(item)
2.80 - finally:
2.81 - f.close()
2.82 -
2.83 - def append(self, item):
2.84 -
2.85 - "Append the given 'item' to the store."
2.86 -
2.87 - if not self.can_write():
2.88 - return
2.89 -
2.90 - self.lock.acquire()
2.91 - try:
2.92 - next = self.get_next()
2.93 - self.write_item(item, next)
2.94 - self.write_next(next + 1)
2.95 - finally:
2.96 - self.lock.release()
2.97
2.98 def can_write(self):
2.99
2.100 @@ -963,4 +894,15 @@
2.101 user = self.page.request.user
2.102 return user and user.may.write(self.page.page_name)
2.103
2.104 + # High-level methods.
2.105 +
2.106 + def append(self, item):
2.107 +
2.108 + "Append the given 'item' to the store."
2.109 +
2.110 + if not self.can_write():
2.111 + return
2.112 +
2.113 + ItemDirectoryStore.append(self, item)
2.114 +
2.115 # vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/setup.py Sat Jan 19 23:12:05 2013 +0100
3.2 +++ b/setup.py Sun Jan 20 01:13:24 2013 +0100
3.3 @@ -10,6 +10,6 @@
3.4 url = "http://hgweb.boddie.org.uk/MoinSupport",
3.5 version = "0.2",
3.6 py_modules = ["ContentTypeSupport", "DateSupport", "GeneralSupport",
3.7 - "LocationSupport", "MoinDateSupport", "MoinRemoteSupport",
3.8 - "MoinSupport", "ViewSupport"]
3.9 + "ItemSupport", "LocationSupport", "MoinDateSupport",
3.10 + "MoinRemoteSupport", "MoinSupport", "ViewSupport"]
3.11 )