# HG changeset patch # User Paul Boddie # Date 1358640804 -3600 # Node ID 5187550c11de735a5f735662c831d2bb02f84a48 # Parent 471bd53b5bb27c58672f9180250c854b1543c1a7 Added a module for item storage along with support for reading items from stores. diff -r 471bd53b5bb2 -r 5187550c11de ItemSupport.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ItemSupport.py Sun Jan 20 01:13:24 2013 +0100 @@ -0,0 +1,168 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - ItemSupport library + + @copyright: 2013 by Paul Boddie + @license: GNU GPL (v2 or later), see COPYING.txt for details. +""" + +from MoinMoin.util import lock +import os + +# Content storage support. + +class ItemDirectoryStore: + + "A directory-based item store." + + def __init__(self, path, lock_dir): + + "Initialise an item store for the given 'path' and 'lock_dir'." + + self.path = path + self.next_path = os.path.join(self.path, "next") + self.lock_dir = lock_dir + self.writelock = lock.WriteLock(lock_dir) + self.readlock = lock.ReadLock(lock_dir) + + def get_next(self): + + "Return the next item number." + + next = self.read_next() + if next is None: + next = self.deduce_next() + self.write_next(next) + return next + + def deduce_next(self): + + "Deduce the next item number from the existing item files." + + return max([int(filename) for filename in os.listdir(self.path) if filename.isdigit()] or [-1]) + 1 + + def read_next(self): + + "Read the next item number from a special file." + + if not os.path.exists(self.next_path): + return None + + f = open(self.next_path) + try: + try: + return int(f.read()) + except ValueError: + return None + finally: + f.close() + + def write_next(self, next): + + "Write the 'next' item number to a special file." + + f = open(self.next_path, "w") + try: + f.write(str(next)) + finally: + f.close() + + def write_item(self, item, next): + + "Write the given 'item' to a file with the given 'next' item number." + + f = open(self.get_item_path(next), "w") + try: + f.write(item) + finally: + f.close() + + def read_item(self, number): + + "Read the item with the given item 'number'." + + f = open(self.get_item_path(number)) + try: + return f.read() + finally: + f.close() + + def get_item_path(self, number): + + "Get the path for the given item 'number'." + + path = os.path.abspath(os.path.join(self.path, str(number))) + basepath = os.path.join(self.path, "") + + if os.path.commonprefix([path, basepath]) != basepath: + raise OSError, path + + return path + + # High-level methods. + + def append(self, item): + + "Append the given 'item' to the store." + + self.writelock.acquire() + try: + next = self.get_next() + self.write_item(item, next) + self.write_next(next + 1) + finally: + self.writelock.release() + + def __len__(self): + + """ + Return the number of the next item (which should also be the number of + items). + """ + + self.writelock.acquire() + try: + return self.get_next() + finally: + self.writelock.release() + + def __iter__(self): + + "Return an iterator over the items in the store." + + return ItemIterator(self) + + def __getitem__(self, number): + + "Return the item with the given 'number'." + + self.readlock.acquire() + try: + try: + return self.read_item(number) + except (IOError, OSError): + raise IndexError, number + finally: + self.readlock.release() + +class ItemIterator: + + "An iterator over items in a store." + + def __init__(self, store): + self.store = store + self._next = -1 + + def next(self): + final = len(self.store) + + while self._next < final: + self._next += 1 + try: + return self.store[self._next] + except IndexError: + pass + + raise StopIteration + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 471bd53b5bb2 -r 5187550c11de MoinSupport.py --- a/MoinSupport.py Sat Jan 19 23:12:05 2013 +0100 +++ b/MoinSupport.py Sun Jan 20 01:13:24 2013 +0100 @@ -9,6 +9,7 @@ """ from DateSupport import * +from ItemSupport import ItemDirectoryStore from MoinMoin.Page import Page from MoinMoin.util import lock from MoinMoin import config, search, wikiutil @@ -872,7 +873,7 @@ # Content storage support. -class ItemStore: +class ItemStore(ItemDirectoryStore): "A page-specific item store." @@ -880,78 +881,8 @@ "Initialise an item store for the given 'page'." + ItemDirectoryStore.__init__(self, page.getPagePath(item_dir_name), page.getPagePath(lock_dir_name)) self.page = page - self.path = page.getPagePath(item_dir_name) - self.next_path = os.path.join(self.path, "next") - lock_dir = page.getPagePath(lock_dir_name) - self.lock = lock.WriteLock(lock_dir) - - def get_next(self): - - "Return the next item number." - - next = self.read_next() - if not next: - next = self.deduce_next() - self.write_next(next) - return next - - def deduce_next(self): - - "Deduce the next item number from the existing item files." - - return max([int(filename) for filename in os.listdir(self.path) if filename.isdigit()] or [0]) + 1 - - def read_next(self): - - "Read the next item number from a special file." - - if not os.path.exists(self.next_path): - return 0 - - f = open(self.next_path) - try: - try: - return int(f.read()) - except ValueError: - return 0 - finally: - f.close() - - def write_next(self, next): - - "Write the 'next' item number to a special file." - - f = open(self.next_path, "w") - try: - f.write(str(next)) - finally: - f.close() - - def write_item(self, item, next): - - "Write the given 'item' to a file with the given 'next' item number." - - f = open(os.path.join(self.path, str(next)), "w") - try: - f.write(item) - finally: - f.close() - - def append(self, item): - - "Append the given 'item' to the store." - - if not self.can_write(): - return - - self.lock.acquire() - try: - next = self.get_next() - self.write_item(item, next) - self.write_next(next + 1) - finally: - self.lock.release() def can_write(self): @@ -963,4 +894,15 @@ user = self.page.request.user return user and user.may.write(self.page.page_name) + # High-level methods. + + def append(self, item): + + "Append the given 'item' to the store." + + if not self.can_write(): + return + + ItemDirectoryStore.append(self, item) + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 471bd53b5bb2 -r 5187550c11de setup.py --- a/setup.py Sat Jan 19 23:12:05 2013 +0100 +++ b/setup.py Sun Jan 20 01:13:24 2013 +0100 @@ -10,6 +10,6 @@ url = "http://hgweb.boddie.org.uk/MoinSupport", version = "0.2", py_modules = ["ContentTypeSupport", "DateSupport", "GeneralSupport", - "LocationSupport", "MoinDateSupport", "MoinRemoteSupport", - "MoinSupport", "ViewSupport"] + "ItemSupport", "LocationSupport", "MoinDateSupport", + "MoinRemoteSupport", "MoinSupport", "ViewSupport"] )