Bug 1574761 - Avoid race condition creating old-configure. r?build
authorMike Hommey <mh+mozilla@glandium.org>
Sun, 18 Aug 2019 10:28:16 +0000 (19:28 +0900)
committerMike Hommey <glandium@debian.org>
Wed, 8 Jan 2020 21:40:28 +0000 (21:40 +0000)
This is not something that happens under normal circumstances, but it
can happen when you go fancy and run multiple configures in parallel
with different objdirs, and old-configure doesn't exist in the first
place ; then one configure may overwrite old-configure while another is
starting to execute it, resulting in the latter nor executing
old-configure completely.

Differential Revision: https://phabricator.services.mozilla.com/D42428

Gbp-Pq: Topic fixes
Gbp-Pq: Name Bug-1574761-Avoid-race-condition-creating-old-config.patch

build/moz.configure/old.configure

index 7286b23ce86af91133e132111333a7e1154211fd..e8d4be4c2cd391cf38b5f619eff22614f6e625c2 100644 (file)
@@ -88,6 +88,10 @@ def prepare_mozconfig(mozconfig):
 @imports(_from='os.path', _import='getmtime')
 @imports(_from='os.path', _import='exists')
 @imports(_from='mozbuild.shellutil', _import='quote')
+@imports(_from='tempfile', _import='NamedTemporaryFile')
+@imports(_from='os', _import='remove')
+@imports(_from='os', _import='rename')
+@imports(_from='__builtin__', _import='OSError')
 def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell,
                       old_configure_assignments, build_project):
     # os.path.abspath in the sandbox will ensure forward slashes on Windows,
@@ -129,9 +133,20 @@ def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell,
         # This could be done with a m4 macro, but it's way easier this way
         script = script.replace('>./config.log', '>>${CONFIG_LOG=./config.log}')
 
-        with open(old_configure, 'wb') as fh:
+        with NamedTemporaryFile(mode='wb', prefix=os.path.basename(old_configure),
+                                dir=os.path.dirname(old_configure), delete=False) as fh:
             fh.write(script)
 
+        try:
+            rename(fh.name, old_configure)
+        except OSError:
+            try:
+                # Likely the file already existed (on Windows). Retry after removing it.
+                remove(old_configure)
+                rename(fh.name, old_configure)
+            except OSError:
+                die('Failed creating old-configure')
+
     cmd = [shell, old_configure]
     with encoded_open('old-configure.vars', 'w') as out:
         log.debug('Injecting the following to old-configure:')