[utils] Make JSON file writes atomic (Fixes #3549)

This commit is contained in:
Philipp Hagemeister 2014-08-21 13:01:13 +02:00
parent 3b95347bb6
commit 181c8655c7

View file

@ -24,6 +24,7 @@ import socket
import struct import struct
import subprocess import subprocess
import sys import sys
import tempfile
import traceback import traceback
import xml.etree.ElementTree import xml.etree.ElementTree
import zlib import zlib
@ -228,16 +229,34 @@ else:
assert type(s) == type(u'') assert type(s) == type(u'')
print(s) print(s)
def write_json_file(obj, fn):
""" Encode obj as JSON and write it to fn, atomically """
# In Python 2.x, json.dump expects a bytestream. # In Python 2.x, json.dump expects a bytestream.
# In Python 3.x, it writes to a character stream # In Python 3.x, it writes to a character stream
if sys.version_info < (3, 0): if sys.version_info < (3, 0):
def write_json_file(obj, fn): mode = 'wb'
with open(fn, 'wb') as f: encoding = None
json.dump(obj, f)
else: else:
def write_json_file(obj, fn): mode = 'w'
with open(fn, 'w', encoding='utf-8') as f: encoding = 'utf-8'
json.dump(obj, f) tf = tempfile.NamedTemporaryFile(
suffix='.tmp', prefix=os.path.basename(fn) + '.',
dir=os.path.dirname(fn),
delete=False)
try:
with tf:
json.dump(obj, tf)
os.rename(tf.name, fn)
except:
try:
os.remove(tf.name)
except OSError:
pass
raise
if sys.version_info >= (2, 7): if sys.version_info >= (2, 7):
def find_xpath_attr(node, xpath, key, val): def find_xpath_attr(node, xpath, key, val):