1. SCons
  2. Core
  3. SCons

Commits

Steven Knight  committed 24ad868

Handle IOError exceptions when pushing files to CacheDir (and elsewhere).

  • Participants
  • Parent commits 0015348
  • Branches default

Comments (0)

Files changed (9)

File src/engine/SCons/Node/FS.py

View file
  • Ignore whitespace
         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
         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))

File src/engine/SCons/SConsign.py

View file
  • Ignore whitespace
                     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

File src/engine/SCons/Scanner/Dir.py

View file
  • Ignore whitespace
     """
     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)

File src/engine/SCons/Script/Main.py

View file
  • Ignore whitespace
 
 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():
         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]
                 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:
         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
 

File src/engine/SCons/Tool/hpc++.py

View file
  • Ignore whitespace
 
 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:

File src/engine/SCons/Tool/hplink.py

View file
  • Ignore whitespace
 
 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:

File src/engine/SCons/Tool/sunlink.py

View file
  • Ignore whitespace
 
 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:

File src/engine/SCons/Util.py

View file
  • Ignore whitespace
                 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:
     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

File src/engine/SCons/UtilTests.py

View file
  • Ignore whitespace
         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