killBuildRunner function

Future<int> killBuildRunner({
  1. String? workingDirectory,
})

Kills any existing build_runner processes before starting a new one.

build_runner uses a lock file (.dart_tool/build/lock) so a second invocation in the same project will hang indefinitely waiting for the lock. This function uses two complementary strategies:

Strategy 1 — lock-file owner (most reliable) Uses lsof -t to find the exact PID(s) holding the lock file and kills them directly. This bypasses command-line truncation issues that can cause pkill -f to miss the process (e.g. when Flutter/puro runs build_runner via a long snapshot path).

Strategy 2 — pkill fallback pkill -f build_runner catches any remaining dart processes whose argv contains "build_runner" in case lsof found nothing (e.g. when the lock file doesn't exist yet but the process is still starting).

Finally, the entire .dart_tool/build directory is deleted so no stale lock can block the new process, even if the killed process held the file handle right up to SIGKILL.

Returns the number of processes that were killed (0 = none were running).

Implementation

Future<int> killBuildRunner({String? workingDirectory}) async {
  int killed = 0;

  if (Platform.isWindows) {
    killed += await _killBuildRunnerWindows();
  } else {
    killed += await _killBuildRunnerPosix(workingDirectory);
  }

  // ── Delete the entire .dart_tool/build directory ─────────────────────────
  // Deleting just the lock file is insufficient — the OS may keep the file
  // descriptor open briefly after SIGKILL. Removing the whole directory
  // guarantees a clean slate. Retry once after a short pause.
  if (workingDirectory != null) {
    await _deleteBuildCache(workingDirectory);
  }

  return killed;
}