Commit abdea474 authored by Jérome Perrin's avatar Jérome Perrin

Save installed database in an atomic way

This reduces the risk of leaving a corrupted .installed.cfg
parent 5058b42c
...@@ -839,11 +839,16 @@ class Buildout(UserDict.DictMixin): ...@@ -839,11 +839,16 @@ class Buildout(UserDict.DictMixin):
def _update_installed(self, **buildout_options): def _update_installed(self, **buildout_options):
installed = self['buildout']['installed'] installed = self['buildout']['installed']
f = open(installed, 'a') # read old installed database
f.write('\n[buildout]\n') with open(installed, 'r') as f:
installed_data = f.read()
installed_data = '%s\n[buildout]\n' % installed_data
f = StringIO()
f.write(installed_data)
for option, value in buildout_options.items(): for option, value in buildout_options.items():
_save_option(option, value, f) _save_option(option, value, f)
f.close() self._save_installed_database(f.getvalue())
def _uninstall_part(self, part, installed_part_options): def _uninstall_part(self, part, installed_part_options):
# uninstall part # uninstall part
...@@ -1007,17 +1012,36 @@ class Buildout(UserDict.DictMixin): ...@@ -1007,17 +1012,36 @@ class Buildout(UserDict.DictMixin):
for d in installed] for d in installed]
return ' '.join(installed) return ' '.join(installed)
def _save_installed_database(self, text):
# Saved installed database in an atomic fashion
installed = self['buildout']['installed']
temp_installed = '%s.tmp' % installed
try:
with open(temp_installed, 'w') as f:
f.write(text)
f.flush()
os.fsync(f.fileno())
os.rename(temp_installed, installed)
finally:
try:
os.remove(temp_installed)
except OSError:
pass
directory_fd = os.open(os.path.dirname(installed), os.O_DIRECTORY)
os.fsync(directory_fd)
os.close(directory_fd)
def _save_installed_options(self, installed_options): def _save_installed_options(self, installed_options):
installed = self['buildout']['installed'] installed = self['buildout']['installed']
if not installed: if not installed:
return return
f = open(installed, 'w') f = StringIO()
_save_options('buildout', installed_options['buildout'], f) _save_options('buildout', installed_options['buildout'], f)
for part in installed_options['buildout']['parts'].split(): for part in installed_options['buildout']['parts'].split():
print >>f print >>f
_save_options(part, installed_options[part], f) _save_options(part, installed_options[part], f)
f.close()
self._save_installed_database(f.getvalue())
def _error(self, message, *args): def _error(self, message, *args):
raise zc.buildout.UserError(message % args) raise zc.buildout.UserError(message % args)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment