| Index: scons-2.0.1/engine/SCons/dblite.py
|
| ===================================================================
|
| --- scons-2.0.1/engine/SCons/dblite.py (revision 0)
|
| +++ scons-2.0.1/engine/SCons/dblite.py (revision 0)
|
| @@ -0,0 +1,251 @@
|
| +# dblite.py module contributed by Ralf W. Grosse-Kunstleve.
|
| +# Extended for Unicode by Steven Knight.
|
| +
|
| +import SCons.compat
|
| +
|
| +import builtins
|
| +import os
|
| +# compat layer imports "cPickle" for us if it's available.
|
| +import pickle
|
| +import shutil
|
| +import time
|
| +
|
| +keep_all_files = 00000
|
| +ignore_corrupt_dbfiles = 0
|
| +
|
| +def corruption_warning(filename):
|
| + print "Warning: Discarding corrupt database:", filename
|
| +
|
| +try: unicode
|
| +except NameError:
|
| + def is_string(s):
|
| + return isinstance(s, str)
|
| +else:
|
| + def is_string(s):
|
| + return type(s) in (str, unicode)
|
| +
|
| +try:
|
| + unicode('a')
|
| +except NameError:
|
| + def unicode(s): return s
|
| +
|
| +dblite_suffix = '.dblite'
|
| +tmp_suffix = '.tmp'
|
| +
|
| +class dblite(object):
|
| +
|
| + # Squirrel away references to the functions in various modules
|
| + # that we'll use when our __del__() method calls our sync() method
|
| + # during shutdown. We might get destroyed when Python is in the midst
|
| + # of tearing down the different modules we import in an essentially
|
| + # arbitrary order, and some of the various modules's global attributes
|
| + # may already be wiped out from under us.
|
| + #
|
| + # See the discussion at:
|
| + # http://mail.python.org/pipermail/python-bugs-list/2003-March/016877.html
|
| +
|
| + _open = builtins.open
|
| + _pickle_dump = staticmethod(pickle.dump)
|
| + _os_chmod = os.chmod
|
| + try:
|
| + _os_chown = os.chown
|
| + except AttributeError:
|
| + _os_chown = None
|
| + _os_rename = os.rename
|
| + _os_unlink = os.unlink
|
| + _shutil_copyfile = shutil.copyfile
|
| + _time_time = time.time
|
| +
|
| + def __init__(self, file_base_name, flag, mode):
|
| + assert flag in (None, "r", "w", "c", "n")
|
| + if (flag is None): flag = "r"
|
| + base, ext = os.path.splitext(file_base_name)
|
| + if ext == dblite_suffix:
|
| + # There's already a suffix on the file name, don't add one.
|
| + self._file_name = file_base_name
|
| + self._tmp_name = base + tmp_suffix
|
| + else:
|
| + self._file_name = file_base_name + dblite_suffix
|
| + self._tmp_name = file_base_name + tmp_suffix
|
| + self._flag = flag
|
| + self._mode = mode
|
| + self._dict = {}
|
| + self._needs_sync = 00000
|
| + if self._os_chown is not None and (os.geteuid()==0 or os.getuid()==0):
|
| + # running as root; chown back to current owner/group when done
|
| + try:
|
| + statinfo = os.stat(self._file_name)
|
| + self._chown_to = statinfo.st_uid
|
| + self._chgrp_to = statinfo.st_gid
|
| + except OSError, e:
|
| + # db file doesn't exist yet.
|
| + # Check os.environ for SUDO_UID, use if set
|
| + self._chown_to = int(os.environ.get('SUDO_UID', -1))
|
| + self._chgrp_to = int(os.environ.get('SUDO_GID', -1))
|
| + else:
|
| + self._chown_to = -1 # don't chown
|
| + self._chgrp_to = -1 # don't chgrp
|
| + if (self._flag == "n"):
|
| + self._open(self._file_name, "wb", self._mode)
|
| + else:
|
| + try:
|
| + f = self._open(self._file_name, "rb")
|
| + except IOError, e:
|
| + if (self._flag != "c"):
|
| + raise e
|
| + self._open(self._file_name, "wb", self._mode)
|
| + else:
|
| + p = f.read()
|
| + if (len(p) > 0):
|
| + try:
|
| + self._dict = pickle.loads(p)
|
| + except (pickle.UnpicklingError, EOFError):
|
| + if (ignore_corrupt_dbfiles == 0): raise
|
| + if (ignore_corrupt_dbfiles == 1):
|
| + corruption_warning(self._file_name)
|
| +
|
| + def __del__(self):
|
| + if (self._needs_sync):
|
| + self.sync()
|
| +
|
| + def sync(self):
|
| + self._check_writable()
|
| + f = self._open(self._tmp_name, "wb", self._mode)
|
| + self._pickle_dump(self._dict, f, 1)
|
| + f.close()
|
| + # Windows doesn't allow renaming if the file exists, so unlink
|
| + # it first, chmod'ing it to make sure we can do so. On UNIX, we
|
| + # may not be able to chmod the file if it's owned by someone else
|
| + # (e.g. from a previous run as root). We should still be able to
|
| + # unlink() the file if the directory's writable, though, so ignore
|
| + # any OSError exception thrown by the chmod() call.
|
| + try: self._os_chmod(self._file_name, 0777)
|
| + except OSError: pass
|
| + self._os_unlink(self._file_name)
|
| + self._os_rename(self._tmp_name, self._file_name)
|
| + if self._os_chown is not None and self._chown_to > 0: # don't chown to root or -1
|
| + try:
|
| + self._os_chown(self._file_name, self._chown_to, self._chgrp_to)
|
| + except OSError:
|
| + pass
|
| + self._needs_sync = 00000
|
| + if (keep_all_files):
|
| + self._shutil_copyfile(
|
| + self._file_name,
|
| + self._file_name + "_" + str(int(self._time_time())))
|
| +
|
| + def _check_writable(self):
|
| + if (self._flag == "r"):
|
| + raise IOError("Read-only database: %s" % self._file_name)
|
| +
|
| + def __getitem__(self, key):
|
| + return self._dict[key]
|
| +
|
| + def __setitem__(self, key, value):
|
| + self._check_writable()
|
| + if (not is_string(key)):
|
| + raise TypeError("key `%s' must be a string but is %s" % (key, type(key)))
|
| + if (not is_string(value)):
|
| + raise TypeError("value `%s' must be a string but is %s" % (value, type(value)))
|
| + self._dict[key] = value
|
| + self._needs_sync = 0001
|
| +
|
| + def keys(self):
|
| + return list(self._dict.keys())
|
| +
|
| + def has_key(self, key):
|
| + return key in self._dict
|
| +
|
| + def __contains__(self, key):
|
| + return key in self._dict
|
| +
|
| + def iterkeys(self):
|
| + # Wrapping name in () prevents fixer from "fixing" this
|
| + return (self._dict.iterkeys)()
|
| +
|
| + __iter__ = iterkeys
|
| +
|
| + def __len__(self):
|
| + return len(self._dict)
|
| +
|
| +def open(file, flag=None, mode=0666):
|
| + return dblite(file, flag, mode)
|
| +
|
| +def _exercise():
|
| + db = open("tmp", "n")
|
| + assert len(db) == 0
|
| + db["foo"] = "bar"
|
| + assert db["foo"] == "bar"
|
| + db[unicode("ufoo")] = unicode("ubar")
|
| + assert db[unicode("ufoo")] == unicode("ubar")
|
| + db.sync()
|
| + db = open("tmp", "c")
|
| + assert len(db) == 2, len(db)
|
| + assert db["foo"] == "bar"
|
| + db["bar"] = "foo"
|
| + assert db["bar"] == "foo"
|
| + db[unicode("ubar")] = unicode("ufoo")
|
| + assert db[unicode("ubar")] == unicode("ufoo")
|
| + db.sync()
|
| + db = open("tmp", "r")
|
| + assert len(db) == 4, len(db)
|
| + assert db["foo"] == "bar"
|
| + assert db["bar"] == "foo"
|
| + assert db[unicode("ufoo")] == unicode("ubar")
|
| + assert db[unicode("ubar")] == unicode("ufoo")
|
| + try:
|
| + db.sync()
|
| + except IOError, e:
|
| + assert str(e) == "Read-only database: tmp.dblite"
|
| + else:
|
| + raise RuntimeError("IOError expected.")
|
| + db = open("tmp", "w")
|
| + assert len(db) == 4
|
| + db["ping"] = "pong"
|
| + db.sync()
|
| + try:
|
| + db[(1,2)] = "tuple"
|
| + except TypeError, e:
|
| + assert str(e) == "key `(1, 2)' must be a string but is <type 'tuple'>", str(e)
|
| + else:
|
| + raise RuntimeError("TypeError exception expected")
|
| + try:
|
| + db["list"] = [1,2]
|
| + except TypeError, e:
|
| + assert str(e) == "value `[1, 2]' must be a string but is <type 'list'>", str(e)
|
| + else:
|
| + raise RuntimeError("TypeError exception expected")
|
| + db = open("tmp", "r")
|
| + assert len(db) == 5
|
| + db = open("tmp", "n")
|
| + assert len(db) == 0
|
| + dblite._open("tmp.dblite", "w")
|
| + db = open("tmp", "r")
|
| + dblite._open("tmp.dblite", "w").write("x")
|
| + try:
|
| + db = open("tmp", "r")
|
| + except pickle.UnpicklingError:
|
| + pass
|
| + else:
|
| + raise RuntimeError("pickle exception expected.")
|
| + global ignore_corrupt_dbfiles
|
| + ignore_corrupt_dbfiles = 2
|
| + db = open("tmp", "r")
|
| + assert len(db) == 0
|
| + os.unlink("tmp.dblite")
|
| + try:
|
| + db = open("tmp", "w")
|
| + except IOError, e:
|
| + assert str(e) == "[Errno 2] No such file or directory: 'tmp.dblite'", str(e)
|
| + else:
|
| + raise RuntimeError("IOError expected.")
|
| + print "OK"
|
| +
|
| +if (__name__ == "__main__"):
|
| + _exercise()
|
| +
|
| +# Local Variables:
|
| +# tab-width:4
|
| +# indent-tabs-mode:nil
|
| +# End:
|
| +# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
|
| Property changes on: scons-2.0.1/engine/SCons/dblite.py
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|