Add file lock to serialize bazel_build.py builds.

This serializes not only the Bazel build invocations, but also the
Tulsi script actions to delete symlinks, clear temp files, remove
assumed expired dSYMs, and others to prevent accidentally parallel
behavior.

--
PiperOrigin-RevId: 175993048
MOS_MIGRATED_REVID=175993048
diff --git a/src/TulsiGenerator/Scripts/bazel_build.py b/src/TulsiGenerator/Scripts/bazel_build.py
index 172a781..2e66d92 100755
--- a/src/TulsiGenerator/Scripts/bazel_build.py
+++ b/src/TulsiGenerator/Scripts/bazel_build.py
@@ -21,6 +21,8 @@
 
 import atexit
 import collections
+import errno
+import fcntl
 import io
 import json
 from operator import itemgetter
@@ -75,6 +77,11 @@
                        (bep_file_path, e.strerror))
 
 
+# Function to be called atexit to release the file lock on script termination.
+def _LockFileExitCleanup(lock_file_path):
+  lock_file_path.close()
+
+
 class Timer(object):
   """Simple profiler."""
 
@@ -1823,6 +1830,24 @@
 
 
 if __name__ == '__main__':
+  sys.stdout.write('Queuing Tulsi build...\n')
+  sys.stdout.flush()
+  _locktimer = Timer('Acquiring /tmp/tulsi_bazel_build.lock',
+                     'tulsi_build_lock').Start()
+  # TODO(b/69414272): See if we can improve this for multiple WORKSPACEs.
+  _lockpath = '/tmp/tulsi_bazel_build.lock'
+  _lockfile = open('/tmp/tulsi_bazel_build.lock', 'w')
+  while True:
+    try:
+      fcntl.lockf(_lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
+      atexit.register(_LockFileExitCleanup, _lockfile)
+      break
+    except IOError as err:
+      if err.errno != errno.EAGAIN:
+        raise
+      else:
+        time.sleep(0.1)
+  _locktimer.End()
   _timer = Timer('Everything', 'complete_build').Start()
   _exit_code = BazelBuildBridge().Run(sys.argv)
   _timer.End()