@@ -262,8 +262,127 @@ function Build {
262
262
ExitWithExitCode 0
263
263
}
264
264
265
+ function Stop-ArtifactLockers {
266
+ # Terminates dotnet processes that are holding locks on artifacts shared libraries
267
+ #
268
+ # This function finds dotnet processes spawned from <repo>/.dotnet/dotnet that have file handles
269
+ # open to shared library files in the artifacts directory and terminates them to prevent build conflicts.
270
+ #
271
+ # Parameters:
272
+ # $1 - RepoRoot: The root directory of the repository (required)
273
+
274
+ local repo_root=" ${1:- $(pwd)} "
275
+ local artifacts_path=" $repo_root /artifacts"
276
+
277
+ # Exit early if artifacts directory doesn't exist
278
+ if [[ ! -d " $artifacts_path " ]]; then
279
+ return 0
280
+ fi
281
+
282
+ # Find dotnet processes spawned from this repository's .dotnet directory
283
+ local repo_dotnet_path=" $repo_root /.dotnet/dotnet"
284
+ local dotnet_pids=()
285
+
286
+ # Get all dotnet processes and filter by exact path
287
+ if command -v pgrep > /dev/null 2>&1 ; then
288
+ # Use pgrep if available (more efficient)
289
+ while IFS= read -r line; do
290
+ local pid
291
+ local path
292
+ pid=$( echo " $line " | cut -d' ' -f1)
293
+ path=$( echo " $line " | cut -d' ' -f2-)
294
+ if [[ " $path " == " $repo_dotnet_path " ]]; then
295
+ dotnet_pids+=(" $pid " )
296
+ fi
297
+ done < <( pgrep -f dotnet -l 2> /dev/null | grep -E " ^[0-9]+ .*dotnet$" || true)
298
+ else
299
+ # Fallback to ps if pgrep is not available
300
+ while IFS= read -r line; do
301
+ local pid
302
+ local cmd
303
+ pid=$( echo " $line " | awk ' {print $2}' )
304
+ cmd=$( echo " $line " | awk ' {for(i=11;i<=NF;i++) printf "%s ", $i; print ""}' | sed ' s/ $//' )
305
+ if [[ " $cmd " == " $repo_dotnet_path " ]]; then
306
+ dotnet_pids+=(" $pid " )
307
+ fi
308
+ done < <( ps aux | grep dotnet | grep -v grep || true)
309
+ fi
310
+
311
+ if [[ ${# dotnet_pids[@]} -eq 0 ]]; then
312
+ return 0
313
+ fi
314
+
315
+ # Check each dotnet process for command lines pointing to artifacts DLLs
316
+ local pids_to_kill=()
317
+ for pid in " ${dotnet_pids[@]} " ; do
318
+ # Skip if process no longer exists
319
+ if ! kill -0 " $pid " 2> /dev/null; then
320
+ continue
321
+ fi
322
+
323
+ local has_artifact_dll=false
324
+
325
+ # Get the command line for this process
326
+ local cmdline=" "
327
+ if [[ -r " /proc/$pid /cmdline" ]]; then
328
+ # Linux: read from /proc/pid/cmdline
329
+ cmdline=$( tr ' \0' ' ' < " /proc/$pid /cmdline" 2> /dev/null || true)
330
+ elif command -v ps > /dev/null 2>&1 ; then
331
+ # macOS/other: use ps to get command line
332
+ cmdline=$( ps -p " $pid " -o command= 2> /dev/null || true)
333
+ fi
334
+
335
+ # Check if command line contains any DLL path under artifacts
336
+ if [[ -n " $cmdline " && " $cmdline " == * " $artifacts_path " * .dll* ]]; then
337
+ has_artifact_dll=true
338
+ fi
339
+
340
+ if [[ " $has_artifact_dll " == true ]]; then
341
+ echo " Terminating dotnet process $pid with artifacts DLL in command line"
342
+ pids_to_kill+=(" $pid " )
343
+ fi
344
+ done
345
+
346
+ # Kill all identified processes in parallel
347
+ if [[ ${# pids_to_kill[@]} -gt 0 ]]; then
348
+ # Send SIGTERM to all processes
349
+ for pid in " ${pids_to_kill[@]} " ; do
350
+ kill " $pid " 2> /dev/null || true
351
+ done
352
+
353
+ # Wait up to 5 seconds for all processes to exit
354
+ local count=0
355
+ local still_running=()
356
+ while [[ $count -lt 50 ]]; do
357
+ still_running=()
358
+ for pid in " ${pids_to_kill[@]} " ; do
359
+ if kill -0 " $pid " 2> /dev/null; then
360
+ still_running+=(" $pid " )
361
+ fi
362
+ done
363
+
364
+ if [[ ${# still_running[@]} -eq 0 ]]; then
365
+ break
366
+ fi
367
+
368
+ sleep 0.1
369
+ (( count++ ))
370
+ done
371
+
372
+ # Force kill any processes still running after 5 seconds
373
+ for pid in " ${still_running[@]} " ; do
374
+ if kill -0 " $pid " 2> /dev/null; then
375
+ echo " Force killing dotnet process $pid "
376
+ kill -9 " $pid " 2> /dev/null || true
377
+ fi
378
+ done
379
+ fi
380
+ }
381
+
265
382
if [[ " $clean " == true ]]; then
266
383
if [ -d " $artifacts_dir " ]; then
384
+ # Kill any lingering dotnet processes that might be holding onto artifacts
385
+ Stop-ArtifactLockers " $repo_root "
267
386
rm -rf $artifacts_dir
268
387
echo " Artifacts directory deleted."
269
388
fi
@@ -274,4 +393,7 @@ if [[ "$restore" == true ]]; then
274
393
InitializeNativeTools
275
394
fi
276
395
396
+ # Kill any lingering dotnet processes that might be holding onto artifacts
397
+ Stop-ArtifactLockers " $repo_root "
398
+
277
399
Build
0 commit comments