|
12 | 12 | import sys
|
13 | 13 | import tarfile
|
14 | 14 | import tempfile
|
| 15 | +import sqlite3 |
15 | 16 |
|
16 | 17 | from time import time
|
17 | 18 |
|
| 19 | +# Acquire a lock on the build directory to make sure that |
| 20 | +# we don't cause a race condition while building |
| 21 | +# Lock is created in `build_dir/lock.db` |
| 22 | +def acquire_lock(build_dir): |
| 23 | + path = os.path.join(build_dir, "lock.db") |
| 24 | + try: |
| 25 | + con = sqlite3.Connection(path, timeout=0) |
| 26 | + curs = con.cursor() |
| 27 | + curs.execute("BEGIN EXCLUSIVE") |
| 28 | + # The lock is released when the cursor is dropped |
| 29 | + return curs |
| 30 | + # If the database is busy then lock has already been acquired |
| 31 | + # so we wait for the lock. |
| 32 | + # We retry every quarter second so that execution is passed back to python |
| 33 | + # so that it can handle signals |
| 34 | + except sqlite3.OperationalError: |
| 35 | + del con |
| 36 | + del curs |
| 37 | + print("Waiting for lock on build directory") |
| 38 | + con = sqlite3.Connection(path, timeout=0.25) |
| 39 | + curs = con.cursor() |
| 40 | + while True: |
| 41 | + try: |
| 42 | + curs.execute("BEGIN EXCLUSIVE") |
| 43 | + except sqlite3.OperationalError: |
| 44 | + pass |
| 45 | + return curs |
| 46 | + |
18 | 47 | def support_xz():
|
19 | 48 | try:
|
20 | 49 | with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
@@ -1225,6 +1254,12 @@ def bootstrap(help_triggered):
|
1225 | 1254 | build.set_dist_environment(data["dist_server"])
|
1226 | 1255 |
|
1227 | 1256 | build.build = args.build or build.build_triple()
|
| 1257 | + |
| 1258 | + # Acquire the lock before doing any build actions |
| 1259 | + # The lock is released when `lock` is dropped |
| 1260 | + if not os.path.exists(build.build_dir): |
| 1261 | + os.makedirs(build.build_dir) |
| 1262 | + lock = acquire_lock(build.build_dir) |
1228 | 1263 | build.update_submodules()
|
1229 | 1264 |
|
1230 | 1265 | # Fetch/build the bootstrap
|
|
0 commit comments