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