From ffbc4a40573fad1ccd6685d896af930208a769c1 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Thu, 10 Sep 2020 12:56:27 -0600 Subject: dblite tweaks use os.replace instead of the dance around os.rename which behaves differently on Windows. use True/False for flags for clarity. Fix some PEP8 warnings. Signed-off-by: Mats Wichmann --- SCons/SConsign.py | 12 ++++--- SCons/Utilities/sconsign.py | 4 +-- SCons/dblite.py | 77 +++++++++++++++++---------------------------- 3 files changed, 37 insertions(+), 56 deletions(-) diff --git a/SCons/SConsign.py b/SCons/SConsign.py index 8e3ebf4..95b8096 100644 --- a/SCons/SConsign.py +++ b/SCons/SConsign.py @@ -35,10 +35,12 @@ from SCons.compat import PICKLE_PROTOCOL def corrupt_dblite_warning(filename): - SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, - "Ignoring corrupt .sconsign file: %s"%filename) + SCons.Warnings.warn( + SCons.Warnings.CorruptSConsignWarning, + "Ignoring corrupt .sconsign file: %s" % filename, + ) -SCons.dblite.ignore_corrupt_dbfiles = 1 +SCons.dblite.IGNORE_CORRUPT_DBFILES = True SCons.dblite.corruption_warning = corrupt_dblite_warning # XXX Get rid of the global array so this becomes re-entrant. @@ -141,7 +143,7 @@ class SConsignEntry: def __getstate__(self): state = getattr(self, '__dict__', {}).copy() for obj in type(self).mro(): - for name in getattr(obj,'__slots__',()): + for name in getattr(obj, '__slots__', ()): if hasattr(self, name): state[name] = getattr(self, name) @@ -154,7 +156,7 @@ class SConsignEntry: def __setstate__(self, state): for key, value in state.items(): - if key not in ('_version_id','__weakref__'): + if key not in ('_version_id', '__weakref__'): setattr(self, key, value) diff --git a/SCons/Utilities/sconsign.py b/SCons/Utilities/sconsign.py index 3288779..e595b2d 100644 --- a/SCons/Utilities/sconsign.py +++ b/SCons/Utilities/sconsign.py @@ -431,7 +431,7 @@ def main(): # Ensure that we don't ignore corrupt DB files, # this was handled by calling my_import('SCons.dblite') # again in earlier versions... - SCons.dblite.ignore_corrupt_dbfiles = 0 + SCons.dblite.IGNORE_CORRUPT_DBFILES = False except ImportError: sys.stderr.write("sconsign: illegal file format `%s'\n" % a) print(helpstr) @@ -474,7 +474,7 @@ def main(): # Ensure that we don't ignore corrupt DB files, # this was handled by calling my_import('SCons.dblite') # again in earlier versions... - SCons.dblite.ignore_corrupt_dbfiles = 0 + SCons.dblite.IGNORE_CORRUPT_DBFILES = False Do_SConsignDB(Map_Module.get(dbm_name, dbm_name), dbm)(a) else: Do_SConsignDir(a) diff --git a/SCons/dblite.py b/SCons/dblite.py index c6943e3..f744c9a 100644 --- a/SCons/dblite.py +++ b/SCons/dblite.py @@ -33,20 +33,20 @@ import time from SCons.compat import PICKLE_PROTOCOL -keep_all_files = 00000 -ignore_corrupt_dbfiles = 0 +KEEP_ALL_FILES = False +IGNORE_CORRUPT_DBFILES = False def corruption_warning(filename): - print("Warning: Discarding corrupt database:", filename) - + """Local warning for corrupt db. -dblite_suffix = '.dblite' + Used for self-tests. SCons overwrites this with a + different warning function in SConsign.py. + """ + print("Warning: Discarding corrupt database:", filename) -# TODO: Does commenting this out break switching from py2/3? -# if bytes is not str: -# dblite_suffix += '.p3' -tmp_suffix = '.tmp' +DBLITE_SUFFIX = '.dblite' +TMP_SUFFIX = '.tmp' class dblite: @@ -66,15 +66,13 @@ class dblite: _open = open _pickle_dump = staticmethod(pickle.dump) _pickle_protocol = PICKLE_PROTOCOL - _os_chmod = os.chmod try: _os_chown = os.chown except AttributeError: _os_chown = None - _os_rename = os.rename - _os_unlink = os.unlink + _os_replace = os.replace _shutil_copyfile = shutil.copyfile _time_time = time.time @@ -84,18 +82,18 @@ class dblite: flag = "r" base, ext = os.path.splitext(file_base_name) - if ext == dblite_suffix: + 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 + self._tmp_name = base + TMP_SUFFIX else: - self._file_name = file_base_name + dblite_suffix - self._tmp_name = file_base_name + tmp_suffix + 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 + self._needs_sync = False 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 @@ -103,7 +101,7 @@ class dblite: statinfo = os.stat(self._file_name) self._chown_to = statinfo.st_uid self._chgrp_to = statinfo.st_gid - except OSError as e: + except OSError: # 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)) @@ -128,15 +126,12 @@ class dblite: f.close() if len(p) > 0: try: - if bytes is not str: - self._dict = pickle.loads(p, encoding='bytes') - else: - self._dict = pickle.loads(p) + self._dict = pickle.loads(p, encoding='bytes') except (pickle.UnpicklingError, EOFError, KeyError): # Note how we catch KeyErrors too here, which might happen # when we don't have cPickle available (default pickle # throws it). - if ignore_corrupt_dbfiles: + if IGNORE_CORRUPT_DBFILES: corruption_warning(self._file_name) else: raise @@ -150,29 +145,16 @@ class dblite: def sync(self): self._check_writable() - f = self._open(self._tmp_name, "wb", self._mode) - self._pickle_dump(self._dict, f, self._pickle_protocol) - 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, 0o777) - except OSError: - pass - self._os_unlink(self._file_name) - self._os_rename(self._tmp_name, self._file_name) + with self._open(self._tmp_name, "wb", self._mode) as f: + self._pickle_dump(self._dict, f, self._pickle_protocol) + self._os_replace(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._needs_sync = False + if KEEP_ALL_FILES: self._shutil_copyfile( self._file_name, self._file_name + "_" + str(int(self._time_time()))) @@ -194,7 +176,7 @@ class dblite: raise TypeError("value `%s' must be a bytes but is %s" % (value, type(value))) self._dict[key] = value - self._needs_sync = 0o001 + self._needs_sync = True def keys(self): return list(self._dict.keys()) @@ -205,11 +187,8 @@ class dblite: 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 __iter__(self): + return iter(self._dict) def __len__(self): return len(self._dict) @@ -278,8 +257,8 @@ def _exercise(): else: raise RuntimeError("pickle exception expected.") - global ignore_corrupt_dbfiles - ignore_corrupt_dbfiles = 2 + global IGNORE_CORRUPT_DBFILES + IGNORE_CORRUPT_DBFILES = True db = open("tmp", "r") assert len(db) == 0, len(db) os.unlink("tmp.dblite") -- cgit v0.12