changeset 199:e15b7165ced5

Fix for #36: avoid corrupting the catalog on update when there's an error in the writing process.
author cmlenz
date Tue, 03 Jul 2007 13:12:36 +0000
parents 982d7e704fdc
children 2f0161df6a38
files babel/messages/frontend.py
diffstat 1 files changed, 54 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/babel/messages/frontend.py
+++ b/babel/messages/frontend.py
@@ -22,8 +22,10 @@
 from optparse import OptionParser
 import os
 import re
+import shutil
 from StringIO import StringIO
 import sys
+import tempfile
 
 from babel import __version__ as VERSION
 from babel import Locale, localedata
@@ -511,13 +513,33 @@
             finally:
                 infile.close()
 
-            rest = catalog.update(template)
+            catalog.update(template)
 
-            outfile = open(filename, 'w')
+            tmpname = os.path.join(os.path.dirname(filename),
+                                   tempfile.gettempprefix() + 
+                                   os.path.basename(filename))
+            tmpfile = open(tmpname, 'w')
             try:
-                write_po(outfile, catalog, ignore_obsolete=self.ignore_obsolete)
-            finally:
-                outfile.close()
+                try:
+                    write_po(tmpfile, catalog,
+                             ignore_obsolete=self.ignore_obsolete)
+                finally:
+                    tmpfile.close()
+            except:
+                os.remove(tmpname)
+                raise
+
+            try:
+                os.rename(tmpname, filename)
+            except OSError:
+                # We're probably on Windows, which doesn't support atomic
+                # renames, at least not through Python
+                # If the error is in fact due to a permissions problem, that
+                # same error is going to be raised from one of the following
+                # operations
+                os.remove(filename)
+                shutil.copy(tmpname, filename)
+                os.remove(tmpname)
 
 
 class CommandLineInterface(object):
@@ -915,14 +937,35 @@
             finally:
                 infile.close()
 
-            rest = catalog.update(template)
+            catalog.update(template)
 
-            outfile = open(filename, 'w')
+            catalog.update(template)
+
+            tmpname = os.path.join(os.path.dirname(filename),
+                                   tempfile.gettempprefix() + 
+                                   os.path.basename(filename))
+            tmpfile = open(tmpname, 'w')
             try:
-                write_po(outfile, catalog,
-                         ignore_obsolete=options.ignore_obsolete)
-            finally:
-                outfile.close()
+                try:
+                    write_po(tmpfile, catalog,
+                             ignore_obsolete=options.ignore_obsolete)
+                finally:
+                    tmpfile.close()
+            except:
+                os.remove(tmpname)
+                raise
+
+            try:
+                os.rename(tmpname, filename)
+            except OSError:
+                # We're probably on Windows, which doesn't support atomic
+                # renames, at least not through Python
+                # If the error is in fact due to a permissions problem, that
+                # same error is going to be raised from one of the following
+                # operations
+                os.remove(filename)
+                shutil.copy(tmpname, filename)
+                os.remove(tmpname)
 
 
 def main():
Copyright (C) 2012-2017 Edgewall Software