1 #!/usr/bin/env python 2 3 """ 4 Directory repositories for WebStack. 5 6 Copyright (C) 2005 Paul Boddie <paul@boddie.org.uk> 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Lesser General Public 10 License as published by the Free Software Foundation; either 11 version 2.1 of the License, or (at your option) any later version. 12 13 This library is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Lesser General Public License for more details. 17 18 You should have received a copy of the GNU Lesser General Public 19 License along with this library; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 21 """ 22 23 import os 24 25 class DirectoryRepository: 26 27 "A directory repository providing session-like access to files." 28 29 def __init__(self, path, fsencoding=None, delay=1): 30 31 """ 32 Initialise the repository using the given 'path' to indicate the 33 location of the repository. If no such location exists in the filesystem 34 an attempt will be made to create the directory. 35 36 The optional 'fsencoding' parameter can be used to assert a particular 37 character encoding used by the filesystem to represent filenames. By 38 default, the default encoding is detected (or Unicode objects are used 39 if appropriate). 40 41 The optional 'delay' argument specifies the time in seconds between each 42 poll of an opened repository file when that file is found to be locked 43 for editing. 44 """ 45 46 if not os.path.exists(path): 47 os.mkdir(path) 48 self.path = path 49 self.fsencoding = fsencoding 50 self.delay = delay 51 52 # Guess the filesystem encoding. 53 54 if fsencoding is None: 55 if os.path.supports_unicode_filenames: 56 self.fsencoding = None 57 else: 58 import locale 59 self.fsencoding = locale.getdefaultlocale()[1] 60 61 # Or override any guesses. 62 63 else: 64 self.fsencoding = fsencoding 65 66 def _convert_name(self, name): 67 if self.fsencoding: 68 return name.encode(self.fsencoding) 69 else: 70 return name 71 72 def _convert_fsname(self, name): 73 if self.fsencoding: 74 return unicode(name, self.fsencoding) 75 else: 76 return name 77 78 def keys(self): 79 # NOTE: Special names converted using a simple rule. 80 l = [] 81 for name in os.listdir(self.path): 82 if name.endswith(".edit"): 83 l.append(name[:-5]) 84 else: 85 l.append(name) 86 return map(self._convert_fsname, l) 87 88 def full_path(self, key): 89 return os.path.join(self.path, self._convert_name(key)) 90 91 def has_key(self, key): 92 return key in self.keys() 93 94 # NOTE: Methods very similar to Helpers.Session.Wrapper. 95 96 def items(self): 97 results = [] 98 for key in self.keys(): 99 results.append((key, self[key])) 100 return results 101 102 def values(self): 103 results = [] 104 for key in self.keys(): 105 results.append(self[key]) 106 return results 107 108 def _wait_for_file(self, key): 109 filename = self.full_path(key) 110 if os.path.exists(filename) or os.path.exists(filename + ".edit"): 111 while 1: 112 try: 113 os.rename(filename, filename + ".edit") 114 except OSError: 115 time.sleep(self.delay) 116 else: 117 break 118 return filename, 1 119 else: 120 return filename, 0 121 122 def __delitem__(self, key): 123 filename = self.full_path(key) 124 if os.path.exists(filename) or os.path.exists(filename + ".edit"): 125 while 1: 126 try: 127 os.remove(filename) 128 except OSError: 129 time.sleep(self.delay) 130 else: 131 break 132 else: 133 raise KeyError, key 134 135 def __getitem__(self, key): 136 filename, exists = self._wait_for_file(key) 137 if not exists: 138 raise KeyError, key 139 try: 140 f = open(filename + ".edit", "rb") 141 s = "" 142 try: 143 s = f.read() 144 finally: 145 f.close() 146 finally: 147 os.rename(filename + ".edit", filename) 148 149 return s 150 151 def __setitem__(self, key, value): 152 filename, exists = self._wait_for_file(key) 153 try: 154 f = open(filename + ".edit", "wb") 155 try: 156 f.write(value) 157 finally: 158 f.close() 159 finally: 160 os.rename(filename + ".edit", filename) 161 162 # vim: tabstop=4 expandtab shiftwidth=4