From: Christopher Lenz Date: Tue, 3 Jul 2007 13:12:36 +0000 (+0000) Subject: Fix for #36: avoid corrupting the catalog on update when there's an error in the... X-Git-Tag: 1.0~452 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7eabc9c6e99adf016208582648a072f193b892e7;p=thirdparty%2Fbabel.git Fix for #36: avoid corrupting the catalog on update when there's an error in the writing process. --- diff --git a/babel/messages/frontend.py b/babel/messages/frontend.py index a8333157..f58bf071 100755 --- a/babel/messages/frontend.py +++ b/babel/messages/frontend.py @@ -22,8 +22,10 @@ from distutils.errors import DistutilsOptionError, DistutilsSetupError 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 @@ class update_catalog(Command): 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 @@ class CommandLineInterface(object): finally: infile.close() - rest = catalog.update(template) + 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=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():