1
2
3
4 import SCons.compat
5
6 import os
7
8 import pickle
9 import shutil
10 import time
11
12 keep_all_files = 00000
13 ignore_corrupt_dbfiles = 0
14
16 print "Warning: Discarding corrupt database:", filename
17
18 try: unicode
19 except NameError:
21 return isinstance(s, str)
22 else:
24 return type(s) in (str, unicode)
25
26 try:
27 unicode('a')
28 except NameError:
30
31 dblite_suffix = '.dblite'
32 tmp_suffix = '.tmp'
33
35
36
37
38
39
40
41
42
43
44
45
46 _open = open
47 _pickle_dump = staticmethod(pickle.dump)
48 _os_chmod = os.chmod
49 try:
50 _os_chown = os.chown
51 except AttributeError:
52 _os_chown = None
53 _os_rename = os.rename
54 _os_unlink = os.unlink
55 _shutil_copyfile = shutil.copyfile
56 _time_time = time.time
57
58 - def __init__(self, file_base_name, flag, mode):
59 assert flag in (None, "r", "w", "c", "n")
60 if (flag is None): flag = "r"
61 base, ext = os.path.splitext(file_base_name)
62 if ext == dblite_suffix:
63
64 self._file_name = file_base_name
65 self._tmp_name = base + tmp_suffix
66 else:
67 self._file_name = file_base_name + dblite_suffix
68 self._tmp_name = file_base_name + tmp_suffix
69 self._flag = flag
70 self._mode = mode
71 self._dict = {}
72 self._needs_sync = 00000
73 if self._os_chown is not None and (os.geteuid()==0 or os.getuid()==0):
74
75 try:
76 statinfo = os.stat(self._file_name)
77 self._chown_to = statinfo.st_uid
78 self._chgrp_to = statinfo.st_gid
79 except OSError, e:
80
81
82 self._chown_to = int(os.environ.get('SUDO_UID', -1))
83 self._chgrp_to = int(os.environ.get('SUDO_GID', -1))
84 else:
85 self._chown_to = -1
86 self._chgrp_to = -1
87 if (self._flag == "n"):
88 self._open(self._file_name, "wb", self._mode)
89 else:
90 try:
91 f = self._open(self._file_name, "rb")
92 except IOError, e:
93 if (self._flag != "c"):
94 raise e
95 self._open(self._file_name, "wb", self._mode)
96 else:
97 p = f.read()
98 if (len(p) > 0):
99 try:
100 self._dict = pickle.loads(p)
101 except (pickle.UnpicklingError, EOFError, KeyError):
102
103
104
105 if (ignore_corrupt_dbfiles == 0): raise
106 if (ignore_corrupt_dbfiles == 1):
107 corruption_warning(self._file_name)
108
110 if (self._needs_sync):
111 self.sync()
112
115
117 self._check_writable()
118 f = self._open(self._tmp_name, "wb", self._mode)
119 self._pickle_dump(self._dict, f, 1)
120 f.close()
121
122
123
124
125
126
127 try: self._os_chmod(self._file_name, 0777)
128 except OSError: pass
129 self._os_unlink(self._file_name)
130 self._os_rename(self._tmp_name, self._file_name)
131 if self._os_chown is not None and self._chown_to > 0:
132 try:
133 self._os_chown(self._file_name, self._chown_to, self._chgrp_to)
134 except OSError:
135 pass
136 self._needs_sync = 00000
137 if (keep_all_files):
138 self._shutil_copyfile(
139 self._file_name,
140 self._file_name + "_" + str(int(self._time_time())))
141
143 if (self._flag == "r"):
144 raise IOError("Read-only database: %s" % self._file_name)
145
147 return self._dict[key]
148
150 self._check_writable()
151 if (not is_string(key)):
152 raise TypeError("key `%s' must be a string but is %s" % (key, type(key)))
153 if (not is_string(value)):
154 raise TypeError("value `%s' must be a string but is %s" % (value, type(value)))
155 self._dict[key] = value
156 self._needs_sync = 0001
157
159 return list(self._dict.keys())
160
162 return key in self._dict
163
165 return key in self._dict
166
170
171 __iter__ = iterkeys
172
174 return len(self._dict)
175
176 -def open(file, flag=None, mode=0666):
177 return dblite(file, flag, mode)
178
180 db = open("tmp", "n")
181 assert len(db) == 0
182 db["foo"] = "bar"
183 assert db["foo"] == "bar"
184 db[unicode("ufoo")] = unicode("ubar")
185 assert db[unicode("ufoo")] == unicode("ubar")
186 db.sync()
187 db = open("tmp", "c")
188 assert len(db) == 2, len(db)
189 assert db["foo"] == "bar"
190 db["bar"] = "foo"
191 assert db["bar"] == "foo"
192 db[unicode("ubar")] = unicode("ufoo")
193 assert db[unicode("ubar")] == unicode("ufoo")
194 db.sync()
195 db = open("tmp", "r")
196 assert len(db) == 4, len(db)
197 assert db["foo"] == "bar"
198 assert db["bar"] == "foo"
199 assert db[unicode("ufoo")] == unicode("ubar")
200 assert db[unicode("ubar")] == unicode("ufoo")
201 try:
202 db.sync()
203 except IOError, e:
204 assert str(e) == "Read-only database: tmp.dblite"
205 else:
206 raise RuntimeError("IOError expected.")
207 db = open("tmp", "w")
208 assert len(db) == 4
209 db["ping"] = "pong"
210 db.sync()
211 try:
212 db[(1,2)] = "tuple"
213 except TypeError, e:
214 assert str(e) == "key `(1, 2)' must be a string but is <type 'tuple'>", str(e)
215 else:
216 raise RuntimeError("TypeError exception expected")
217 try:
218 db["list"] = [1,2]
219 except TypeError, e:
220 assert str(e) == "value `[1, 2]' must be a string but is <type 'list'>", str(e)
221 else:
222 raise RuntimeError("TypeError exception expected")
223 db = open("tmp", "r")
224 assert len(db) == 5
225 db = open("tmp", "n")
226 assert len(db) == 0
227 dblite._open("tmp.dblite", "w")
228 db = open("tmp", "r")
229 dblite._open("tmp.dblite", "w").write("x")
230 try:
231 db = open("tmp", "r")
232 except pickle.UnpicklingError:
233 pass
234 else:
235 raise RuntimeError("pickle exception expected.")
236 global ignore_corrupt_dbfiles
237 ignore_corrupt_dbfiles = 2
238 db = open("tmp", "r")
239 assert len(db) == 0
240 os.unlink("tmp.dblite")
241 try:
242 db = open("tmp", "w")
243 except IOError, e:
244 assert str(e) == "[Errno 2] No such file or directory: 'tmp.dblite'", str(e)
245 else:
246 raise RuntimeError("IOError expected.")
247 print "OK"
248
249 if (__name__ == "__main__"):
250 _exercise()
251
252
253
254
255
256
257