Make writing a .sconsign more robust by writing to a temporary file first and renamin...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 9 Feb 2002 22:26:59 +0000 (22:26 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 9 Feb 2002 22:26:59 +0000 (22:26 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@249 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Sig/__init__.py
test/sconsign.py [moved from test/nonwritable-sconsign.py with 53% similarity]

index 7ac99798503e05144eb2c7d68099712734fd3347..d533be97eeb10f7b2ef731b2b8853d84b4235d01 100644 (file)
@@ -36,6 +36,9 @@ RELEASE 0.05 -
   - Look up implicit (scanned) dependencies relative to the directory
     of file being scanned.
 
+  - Make writing .sconsign files more robust by first trying to write
+    to a temp file that we rename.
+
   From Anthony Roach:
 
   - Make the scons script return an error code on failures.
index 52d8b33fb1a4c3784cc44d291edc8bf83787e3d9..d1e546f07d0ed75fbaa6da880aeb1971bd88a1f1 100644 (file)
@@ -29,6 +29,7 @@ The Signature package for the scons software construction utility.
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+import os
 import os.path
 import string
 import SCons.Node
@@ -114,17 +115,38 @@ class SConsignFile:
     def write(self):
         """
         Write the .sconsign file to disk.
+
+        Try to write to a temporary file first, and rename it if we
+        succeed.  If we can't write to the temporary file, it's
+        probably because the directory isn't writable (and if so,
+        how did we build anything in this directory, anyway?), so
+        try to write directly to the .sconsign file as a backup.
+        If we can't rename, try to copy the temporary contents back
+        to the .sconsign file.  Either way, always try to remove
+        the temporary file at the end.
         """
         if self.dirty:
+            temp = os.path.join(self.dir.path, '.scons%d' % os.getpid())
             try:
+                file = open(temp, 'wt')
+                fname = temp
+            except:
                 file = open(self.sconsign, 'wt')
+                fname = self.sconsign
+            keys = self.entries.keys()
+            keys.sort()
+            for name in keys:
+                file.write("%s: %s\n" % (name, self.entries[name]))
+            file.close
+            if fname != self.sconsign:
+                try:
+                    os.rename(fname, self.sconsign)
+                except:
+                    open(self.sconsign, 'wb').write(open(fname, 'rb').read())
+            try:
+                os.unlink(temp)
             except:
                 pass
-            else:
-                keys = self.entries.keys()
-                keys.sort()
-                for name in keys:
-                    file.write("%s: %s\n" % (name, self.entries[name]))
 
 
 class Calculator:
similarity index 53%
rename from test/nonwritable-sconsign.py
rename to test/sconsign.py
index 6955438064839266fd39e7e0caf046bcfd9c458e..ac6bf2fee86bb7f18dcdae28c671c14963a92963 100644 (file)
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #
 
-__revision__ = "test/nonwritable-sconsign.py __REVISION__ __DATE__ __DEVELOPER__"
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-import TestSCons
 import os
+import TestSCons
 
 test = TestSCons.TestSCons()
 
+test.subdir('sub1', 'sub2')
+
 test.write('SConstruct', """
-env = Environment()
-env.Program(target = 'foo1', source = 'f1.c')
-""")
+def build1(target, source, env):
+    open(str(target), 'wb').write(open(str(source[0]), 'rb').read())
+    return None
 
-test.write('f1.c', r"""
-int
-main(int argc, char *argv[])
-{
-       argv[argc++] = "--";
-       printf("f1.c\n");
-       exit (0);
-}
+def build2(target, source, env):
+    import os
+    import os.path
+    open(str(target), 'wb').write(open(str(source[0]), 'rb').read())
+    dir, file = os.path.split(target)
+    os.chmod(dir, 0555)
+    return None
+
+B1 = Builder(name = "B1", action = build1)
+B2 = Builder(name = "B2", action = build2)
+env = Environment(BUILDERS = [B1, B2])
+env.B1(target = 'sub1/foo.out', source = 'foo.in')
+env.B2(target = 'sub2/foo.out', source = 'foo.in')
 """)
 
-test.write('.sconsign', "")
+test.write('foo.in', "foo.in\n")
+
+sub1__sconsign = test.workpath('sub1', '.sconsign')
+sub2__sconsign = test.workpath('sub2', '.sconsign')
 
-# For *NIX, systems, make .sconsign not writable.
+test.write(sub1__sconsign, "")
+test.write(sub2__sconsign, "")
+
+# For *NIX systems, make .sconsign not writable.
 # For Win32 systems, open it to lock it.
-os.chmod(test.workpath('.sconsign'), 0444)
-f = open(test.workpath('.sconsign'), 'r')
+os.chmod(sub1__sconsign, 0444)
+f = open(sub1__sconsign, 'r')
+
+test.run(arguments = '.')
 
-test.run(arguments = ".")
-test.run(program = test.workpath('foo1'), stdout = "f1.c\n")
+test.fail_test(test.read(sub1__sconsign) == "")
+test.fail_test(test.read(sub2__sconsign) == "")
 
-os.chmod(test.workpath('.sconsign'), 0666)
+os.chmod(sub1__sconsign, 0666)
 f.close()
 
 test.pass_test()