From 9cc9facbea886ea224ffcba9a89d3dd36162d70d Mon Sep 17 00:00:00 2001 From: Nadav Har'El Date: Mon, 15 Jul 2019 15:21:29 +0300 Subject: [PATCH] configure.py: atomically overwrite build.ninja MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit configure.py currently takes some time to write build.ninja. If the user interrupts (e.g., control-C) configure.py, it can leave behind a partial or even empty build.ninja file. This is most frustrating when the user didn't explicitly run "configure.py", but rather just ran "ninja" and ninja decided to run configure.py, and after interrupting it the user cannot run "ninja" again because build.ninja is gone. Another result of losing build.ninja is that the user now needs to remember which parameters to run "configure.py", because the old ones stored in build.ninja were lost. The solution in this patch is simple: We write the new build.ninja contents into a temporary file, not directly into build.ninja. Then, only when the entire file has been succesfully written, do we rename the temporary file to its intended name - build.ninja. Fixes #4706 Signed-off-by: Nadav Har'El Reviewed-by: Botond Dénes Message-Id: <20190715122129.16033-1-nyh@scylladb.com> --- configure.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configure.py b/configure.py index cd5997554c..89cee8e6fc 100755 --- a/configure.py +++ b/configure.py @@ -1161,7 +1161,13 @@ if args.antlr3_exec: else: antlr3_exec = "antlr3" -with open(buildfile, 'w') as f: +# configure.py may run automatically from an already-existing build.ninja. +# If the user interrupts configure.py in the middle, we need build.ninja +# to remain in a valid state. So we write our output to a temporary +# file, and only when done we rename it atomically to build.ninja. +buildfile_tmp = buildfile + ".tmp" + +with open(buildfile_tmp, 'w') as f: f.write(textwrap.dedent('''\ configure_args = {configure_args} builddir = {outdir} @@ -1410,3 +1416,5 @@ with open(buildfile, 'w') as f: command = ./SCYLLA-VERSION-GEN build build/SCYLLA-RELEASE-FILE build/SCYLLA-VERSION-FILE: scylla_version_gen ''').format(modes_list=' '.join(build_modes), **globals())) + +os.rename(buildfile_tmp, buildfile)