summaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2019-04-28 20:51:46 (GMT)
committerGitHub <noreply@github.com>2019-04-28 20:51:46 (GMT)
commitc3b0bb3b4d15a33c93413cb3cfaea3469f56c31b (patch)
treeed8ee5a8637731e38010ff2517e93849a276165d /src/engine
parent35e6bbe16a859b42efca4592b435695a530f0717 (diff)
parentd745eb81c18d448837740d9543570ddd110243d6 (diff)
downloadSCons-c3b0bb3b4d15a33c93413cb3cfaea3469f56c31b.zip
SCons-c3b0bb3b4d15a33c93413cb3cfaea3469f56c31b.tar.gz
SCons-c3b0bb3b4d15a33c93413cb3cfaea3469f56c31b.tar.bz2
Merge pull request #3353 from mwichmann/cacheDir
[WIP] Avoid cachedir races
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/SCons/CacheDir.py88
1 files changed, 75 insertions, 13 deletions
diff --git a/src/engine/SCons/CacheDir.py b/src/engine/SCons/CacheDir.py
index dabda8e..0a378c2 100644
--- a/src/engine/SCons/CacheDir.py
+++ b/src/engine/SCons/CacheDir.py
@@ -35,6 +35,7 @@ import sys
import SCons.Action
import SCons.Warnings
+from SCons.Util import PY3
cache_enabled = True
cache_debug = False
@@ -139,34 +140,95 @@ warned = dict()
class CacheDir(object):
def __init__(self, path):
+ """
+ Initialize a CacheDir object.
+
+ The cache configuration is stored in the object. It
+ is read from the config file in the supplied path if
+ one exists, if not the config file is created and
+ the default config is written, as well as saved in the object.
+ """
self.path = path
self.current_cache_debug = None
self.debugFP = None
self.config = dict()
if path is None:
return
- # See if there's a config file in the cache directory. If there is,
- # use it. If there isn't, and the directory exists and isn't empty,
- # produce a warning. If the directory doesn't exist or is empty,
- # write a config file.
+
+ if PY3:
+ self._readconfig3(path)
+ else:
+ self._readconfig2(path)
+
+
+ def _readconfig3(self, path):
+ """
+ Python3 version of reading the cache config.
+
+ If directory or config file do not exist, create. Take advantage
+ of Py3 capability in os.makedirs() and in file open(): just try
+ the operation and handle failure appropriately.
+
+ Omit the check for old cache format, assume that's old enough
+ there will be none of those left to worry about.
+
+ :param path: path to the cache directory
+ """
+ config_file = os.path.join(path, 'config')
+ try:
+ os.makedirs(path, exist_ok=True)
+ except FileExistsError:
+ pass
+ except OSError:
+ msg = "Failed to create cache directory " + path
+ raise SCons.Errors.EnvironmentError(msg)
+
+ try:
+ with open(config_file, 'x') as config:
+ self.config['prefix_len'] = 2
+ try:
+ json.dump(self.config, config)
+ except Exception:
+ msg = "Failed to write cache configuration for " + path
+ raise SCons.Errors.EnvironmentError(msg)
+ except FileExistsError:
+ try:
+ with open(config_file) as config:
+ self.config = json.load(config)
+ except ValueError:
+ msg = "Failed to read cache configuration for " + path
+ raise SCons.Errors.EnvironmentError(msg)
+
+
+ def _readconfig2(self, path):
+ """
+ Python2 version of reading cache config.
+
+ See if there is a config file in the cache directory. If there is,
+ use it. If there isn't, and the directory exists and isn't empty,
+ produce a warning. If the directory does not exist or is empty,
+ write a config file.
+
+ :param path: path to the cache directory
+ """
config_file = os.path.join(path, 'config')
if not os.path.exists(config_file):
- # A note: There is a race hazard here, if two processes start and
+ # A note: There is a race hazard here if two processes start and
# attempt to create the cache directory at the same time. However,
- # python doesn't really give you the option to do exclusive file
- # creation (it doesn't even give you the option to error on opening
- # an existing file for writing...). The ordering of events here
- # as an attempt to alleviate this, on the basis that it's a pretty
- # unlikely occurence (it'd require two builds with a brand new cache
+ # Python 2.x does not give you the option to do exclusive file
+ # creation (not even the option to error on opening an existing
+ # file for writing...). The ordering of events here is an attempt
+ # to alleviate this, on the basis that it's a pretty unlikely
+ # occurrence (would require two builds with a brand new cache
# directory)
- if os.path.isdir(path) and len(os.listdir(path)) != 0:
+ if os.path.isdir(path) and any(f != "config" for f in os.listdir(path)):
self.config['prefix_len'] = 1
# When building the project I was testing this on, the warning
# was output over 20 times. That seems excessive
global warned
if self.path not in warned:
msg = "Please upgrade your cache by running " +\
- " scons-configure-cache.py " + self.path
+ "scons-configure-cache.py " + self.path
SCons.Warnings.warn(SCons.Warnings.CacheVersionWarning, msg)
warned[self.path] = True
else:
@@ -184,7 +246,7 @@ class CacheDir(object):
try:
with open(config_file, 'w') as config:
json.dump(self.config, config)
- except:
+ except Exception:
msg = "Failed to write cache configuration for " + path
raise SCons.Errors.SConsEnvironmentError(msg)
else: