summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2005-08-20 23:10:35 (GMT)
committerSteven Knight <knight@baldmt.com>2005-08-20 23:10:35 (GMT)
commitc5f5ba58f1c8b4927ee22e3781a19c334352aa45 (patch)
tree0f8aba7fb052a1dfc6efa91287951f007a752892
parentcfcbeb6ff0607e5a573768eb1dbaef6fe86089a2 (diff)
downloadSCons-c5f5ba58f1c8b4927ee22e3781a19c334352aa45.zip
SCons-c5f5ba58f1c8b4927ee22e3781a19c334352aa45.tar.gz
SCons-c5f5ba58f1c8b4927ee22e3781a19c334352aa45.tar.bz2
Handle IOError exceptions when pushing files to CacheDir (and elsewhere).
-rw-r--r--src/engine/SCons/Node/FS.py18
-rw-r--r--src/engine/SCons/SConsign.py15
-rw-r--r--src/engine/SCons/Scanner/Dir.py2
-rw-r--r--src/engine/SCons/Script/Main.py38
-rw-r--r--src/engine/SCons/Tool/hpc++.py4
-rw-r--r--src/engine/SCons/Tool/hplink.py4
-rw-r--r--src/engine/SCons/Tool/sunlink.py4
-rw-r--r--src/engine/SCons/Util.py36
-rw-r--r--src/engine/SCons/UtilTests.py33
9 files changed, 76 insertions, 78 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index c7905b5..6eb61d9 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -156,7 +156,13 @@ def LinkFunc(target, source, env):
try:
func(src,dest)
break
- except OSError:
+ except (IOError, OSError):
+ # An OSError indicates something happened like a permissions
+ # problem or an attempt to symlink across file-system
+ # boundaries. An IOError indicates something like the file
+ # not existing. In either case, keeping trying additional
+ # functions in the list and only raise an error if the last
+ # one failed.
if func == Link_Funcs[-1]:
# exception of the last link method (copy) are fatal
raise
@@ -240,10 +246,12 @@ def CachePushFunc(target, source, env):
fs.rename(tempfile, cachefile)
st = fs.stat(t.path)
fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
- except OSError:
- # It's possible someone else tried writing the file at the same
- # time we did. Print a warning but don't stop the build, since
- # it doesn't affect the correctness of the build.
+ except (IOError, OSError):
+ # It's possible someone else tried writing the file at the
+ # same time we did, or else that there was some problem like
+ # the CacheDir being on a separate file system that's full.
+ # In any case, inability to push a file to cache doesn't affect
+ # the correctness of the build, so just print a warning.
SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning,
"Unable to copy %s to cache. Cache file is %s"
% (str(target), cachefile))
diff --git a/src/engine/SCons/SConsign.py b/src/engine/SCons/SConsign.py
index d99df4e..67b2aff 100644
--- a/src/engine/SCons/SConsign.py
+++ b/src/engine/SCons/SConsign.py
@@ -297,16 +297,27 @@ class DirFile(Dir):
mode = os.stat(self.sconsign)[0]
os.chmod(self.sconsign, 0666)
os.unlink(self.sconsign)
- except OSError:
+ except (IOError, OSError):
+ # Try to carry on in the face of either OSError
+ # (things like permission issues) or IOError (disk
+ # or network issues). If there's a really dangerous
+ # issue, it should get re-raised by the calls below.
pass
try:
os.rename(fname, self.sconsign)
except OSError:
+ # An OSError failure to rename may indicate something
+ # like the directory has no write permission, but
+ # the .sconsign file itself might still be writable,
+ # so try writing on top of it directly. An IOError
+ # here, or in any of the following calls, would get
+ # raised, indicating something like a potentially
+ # serious disk or network issue.
open(self.sconsign, 'wb').write(open(fname, 'rb').read())
os.chmod(self.sconsign, mode)
try:
os.unlink(temp)
- except OSError:
+ except (IOError, OSError):
pass
ForDirectory = DB
diff --git a/src/engine/SCons/Scanner/Dir.py b/src/engine/SCons/Scanner/Dir.py
index 7c39f26..e722230 100644
--- a/src/engine/SCons/Scanner/Dir.py
+++ b/src/engine/SCons/Scanner/Dir.py
@@ -53,7 +53,7 @@ def scan(node, env, path=()):
"""
try:
flist = node.fs.listdir(node.abspath)
- except OSError:
+ except (IOError, OSError):
return []
dont_scan = lambda k: not skip_entry.has_key(k)
flist = filter(dont_scan, flist)
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index e5a8cb2..67b3308 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -190,6 +190,35 @@ class BuildTask(SCons.Taskmaster.Task):
class CleanTask(SCons.Taskmaster.Task):
"""An SCons clean task."""
+ def dir_index(self, directory):
+ dirname = lambda f, d=directory: os.path.join(d, f)
+ files = map(dirname, os.listdir(directory))
+
+ # os.listdir() isn't guaranteed to return files in any specific order,
+ # but some of the test code expects sorted output.
+ files.sort()
+ return files
+
+ def fs_delete(self, path, remove=1):
+ try:
+ if os.path.exists(path):
+ if os.path.isfile(path):
+ if remove: os.unlink(path)
+ display("Removed " + path)
+ elif os.path.isdir(path) and not os.path.islink(path):
+ # delete everything in the dir
+ for p in self.dir_index(path):
+ if os.path.isfile(p):
+ if remove: os.unlink(p)
+ display("Removed " + p)
+ else:
+ self.fs_delete(p, remove)
+ # then delete dir itself
+ if remove: os.rmdir(path)
+ display("Removed directory " + path)
+ except (IOError, OSError), e:
+ print "scons: Could not remove '%s':" % str(path), e.strerror
+
def show(self):
target = self.targets[0]
if (target.has_builder() or target.side_effect) and not target.isdir():
@@ -197,7 +226,7 @@ class CleanTask(SCons.Taskmaster.Task):
if SCons.Environment.CleanTargets.has_key(target):
files = SCons.Environment.CleanTargets[target]
for f in files:
- SCons.Util.fs_delete(str(f), 0)
+ self.fs_delete(str(f), 0)
def remove(self):
target = self.targets[0]
@@ -206,6 +235,11 @@ class CleanTask(SCons.Taskmaster.Task):
try:
removed = t.remove()
except OSError, e:
+ # An OSError may indicate something like a permissions
+ # issue, an IOError would indicate something like
+ # the file not existing. In either case, print a
+ # message and keep going to try to remove as many
+ # targets aa possible.
print "scons: Could not remove '%s':" % str(t), e.strerror
else:
if removed:
@@ -213,7 +247,7 @@ class CleanTask(SCons.Taskmaster.Task):
if SCons.Environment.CleanTargets.has_key(target):
files = SCons.Environment.CleanTargets[target]
for f in files:
- SCons.Util.fs_delete(str(f))
+ self.fs_delete(str(f))
execute = remove
diff --git a/src/engine/SCons/Tool/hpc++.py b/src/engine/SCons/Tool/hpc++.py
index a1b3e97..3276412 100644
--- a/src/engine/SCons/Tool/hpc++.py
+++ b/src/engine/SCons/Tool/hpc++.py
@@ -46,7 +46,9 @@ acc = None
try:
dirs = os.listdir('/opt')
-except OSError:
+except (IOError, OSError):
+ # Not being able to read the directory because it doesn't exist
+ # (IOError) or isn't readable (OSError) is okay.
dirs = []
for dir in dirs:
diff --git a/src/engine/SCons/Tool/hplink.py b/src/engine/SCons/Tool/hplink.py
index f3d03c9..5921b39 100644
--- a/src/engine/SCons/Tool/hplink.py
+++ b/src/engine/SCons/Tool/hplink.py
@@ -45,7 +45,9 @@ ccLinker = None
try:
dirs = os.listdir('/opt')
-except OSError:
+except (IOError, OSError):
+ # Not being able to read the directory because it doesn't exist
+ # (IOError) or isn't readable (OSError) is okay.
dirs = []
for dir in dirs:
diff --git a/src/engine/SCons/Tool/sunlink.py b/src/engine/SCons/Tool/sunlink.py
index 66dd7c0..665d656 100644
--- a/src/engine/SCons/Tool/sunlink.py
+++ b/src/engine/SCons/Tool/sunlink.py
@@ -45,7 +45,9 @@ ccLinker = None
try:
dirs = os.listdir('/opt')
-except OSError:
+except (IOError, OSError):
+ # Not being able to read the directory because it doesn't exist
+ # (IOError) or isn't readable (OSError) is okay.
dirs = []
for d in dirs:
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 084975a..2859807 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -1380,6 +1380,10 @@ else:
try:
st = os.stat(f)
except OSError:
+ # os.stat() raises OSError, not IOError if the file
+ # doesn't exist, so in this case we let IOError get
+ # raised so as to not mask possibly serious disk or
+ # network issues.
continue
if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
try:
@@ -1478,38 +1482,6 @@ def AppendPath(oldpath, newpath, sep = os.pathsep):
else:
return string.join(paths, sep)
-
-def dir_index(directory):
- files = []
- for f in os.listdir(directory):
- fullname = os.path.join(directory, f)
- files.append(fullname)
-
- # os.listdir() isn't guaranteed to return files in any specific order,
- # but some of the test code expects sorted output.
- files.sort()
- return files
-
-def fs_delete(path, remove=1):
- try:
- if os.path.exists(path):
- if os.path.isfile(path):
- if remove: os.unlink(path)
- display("Removed " + path)
- elif os.path.isdir(path) and not os.path.islink(path):
- # delete everything in the dir
- for p in dir_index(path):
- if os.path.isfile(p):
- if remove: os.unlink(p)
- display("Removed " + p)
- else:
- fs_delete(p, remove)
- # then delete dir itself
- if remove: os.rmdir(path)
- display("Removed directory " + path)
- except OSError, e:
- print "scons: Could not remove '%s':" % str(path), e.strerror
-
if sys.platform == 'cygwin':
def get_native_path(path):
"""Transforms an absolute path into a native path for the system. In
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index ce9fd56..19ec748 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -1388,39 +1388,6 @@ class UtilTestCase(unittest.TestCase):
assert sys.stdout.buffer == "line1\nline3\nline4\n"
sys.stdout = old_stdout
- def test_fs_delete(self):
- test = TestCmd.TestCmd(workdir = '')
- base = test.workpath('')
- xxx = test.workpath('xxx.xxx')
- ZZZ = test.workpath('ZZZ.ZZZ')
- sub1_yyy = test.workpath('sub1', 'yyy.yyy')
-
- test.subdir('sub1')
- test.write(xxx, "\n")
- test.write(ZZZ, "\n")
- test.write(sub1_yyy, "\n")
-
- old_stdout = sys.stdout
- sys.stdout = OutBuffer()
-
- exp = "Removed " + os.path.join(base, ZZZ) + "\n" + \
- "Removed " + os.path.join(base, sub1_yyy) + '\n' + \
- "Removed directory " + os.path.join(base, 'sub1') + '\n' + \
- "Removed " + os.path.join(base, xxx) + '\n' + \
- "Removed directory " + base + '\n'
-
- fs_delete(base, remove=0)
- assert sys.stdout.buffer == exp, sys.stdout.buffer
- assert os.path.exists(sub1_yyy)
-
- sys.stdout.buffer = ""
- fs_delete(base, remove=1)
- assert sys.stdout.buffer == exp
- assert not os.path.exists(base)
-
- test._dirlist = None
- sys.stdout = old_stdout
-
def test_get_native_path(self):
"""Test the get_native_path() function."""
import tempfile