{"version":3,"sources":["../../src/lib/turbopack-cache-seed.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport * as Log from '../build/output/log'\nimport { getTurbopackCacheVersion } from '../build/swc'\nimport {\n  getGitWorktreeInfo,\n  listLinkedWorktreeRoots,\n  type GitWorktreeInfo,\n} from './git-worktree'\n\nexport function seedTurbopackCacheIfNeeded({\n  projectDir,\n  distDir,\n}: {\n  projectDir: string\n  distDir: string\n}): void {\n  // This gets the version assuming that nothing is dirty.\n  // If things are dirty, turbopack would write things\n  // in a different location. There are other circumstances\n  // as well. This only matters for people developing turbopack\n  // see handle_db_versioning in turbotask backend for more details.\n  const version = getTurbopackCacheVersion()\n  if (!version) return\n\n  const worktreeInfo = getGitWorktreeInfo(projectDir)\n  if (!worktreeInfo) return\n\n  const cacheDir = path.join(distDir, 'cache', 'turbopack')\n  const targetVersionDir = path.join(cacheDir, version)\n  if (dirHasEntries(targetVersionDir)) return\n\n  let sourceVersionDir: string | undefined\n  try {\n    sourceVersionDir = findSeedSource(\n      worktreeInfo,\n      projectDir,\n      distDir,\n      version\n    )\n  } catch {\n    return\n  }\n  if (!sourceVersionDir) return\n\n  const tmpDir = `${targetVersionDir}.seeding`\n  // Making sure we don't copy partial data if process interrupted\n  // There is a potential race condition here\n  // if someone wrote to the cache while we were seeding it\n  // but with the immutable design and all that, I'm not super worried\n  try {\n    fs.mkdirSync(cacheDir, { recursive: true })\n    fs.rmSync(tmpDir, { recursive: true, force: true })\n    seedCacheDir(sourceVersionDir, tmpDir)\n    fs.renameSync(tmpDir, targetVersionDir)\n    Log.info(`Seeded Turbopack cache from ${sourceVersionDir}.`)\n  } catch {\n    fs.rmSync(tmpDir, { recursive: true, force: true })\n    Log.warn(\n      `Failed to seed Turbopack cache from ${sourceVersionDir} to ${targetVersionDir}.`\n    )\n  }\n}\n\nfunction findSeedSource(\n  worktreeInfo: GitWorktreeInfo,\n  projectDir: string,\n  distDir: string,\n  version: string\n): string | undefined {\n  const projectRelToWorktree = path.relative(\n    worktreeInfo.worktreeRoot,\n    projectDir\n  )\n  const distRelToProject = path.relative(projectDir, distDir)\n  const currentWorktree = path.resolve(worktreeInfo.worktreeRoot)\n\n  // We are going to find the best candidate worktree\n  // based on the most recently written cache directory.\n  // We only look at our version\n\n  let best: { versionDir: string; commitTimeMs: number } | undefined\n  for (const root of [\n    worktreeInfo.mainRepoRoot,\n    ...listLinkedWorktreeRoots(worktreeInfo.mainRepoRoot),\n  ]) {\n    if (path.resolve(root) === currentWorktree) continue\n    const versionDir = path.join(\n      root,\n      projectRelToWorktree,\n      distRelToProject,\n      'cache',\n      'turbopack',\n      version\n    )\n    const commitTimeMs = currentCommitTimeMs(versionDir)\n    if (commitTimeMs === undefined) continue\n    if (!best || commitTimeMs > best.commitTimeMs) {\n      best = { versionDir, commitTimeMs }\n    }\n  }\n  return best?.versionDir\n}\n\n// When the cache in `versionDir` was last committed to, in epoch milliseconds, or undefined if\n// there is no usable cache there. Read from the `commit_time` the persistence layer records in\n// CURRENT.\nfunction currentCommitTimeMs(versionDir: string): number | undefined {\n  let commitTime\n  try {\n    commitTime = JSON.parse(\n      fs.readFileSync(path.join(versionDir, 'CURRENT'), 'utf8')\n    ).commit_time\n  } catch {\n    // missing, unreadable, or not valid JSON - treat it as not a seed candidate\n    return undefined\n  }\n  if (typeof commitTime !== 'string') return undefined\n  const parsed = Date.parse(commitTime)\n  return Number.isNaN(parsed) ? undefined : parsed\n}\n\nfunction dirHasEntries(dir: string): boolean {\n  try {\n    return fs.readdirSync(dir).length > 0\n  } catch {\n    return false\n  }\n}\n\nconst IMMUTABLE_CACHE_FILE = /\\.(sst|blob|meta|del)$/\n\nfunction seedCacheDir(src: string, dst: string): void {\n  const stat = fs.lstatSync(src)\n  if (stat.isDirectory()) {\n    fs.mkdirSync(dst, { recursive: true })\n    for (const name of fs.readdirSync(src)) {\n      seedCacheDir(path.join(src, name), path.join(dst, name))\n    }\n  } else if (IMMUTABLE_CACHE_FILE.test(src)) {\n    fs.linkSync(src, dst)\n  } else {\n    // Mutable/unknown (CURRENT, LOG, …) - copy so it gets its own inode.\n    fs.copyFileSync(src, dst)\n  }\n}\n"],"names":["seedTurbopackCacheIfNeeded","projectDir","distDir","version","getTurbopackCacheVersion","worktreeInfo","getGitWorktreeInfo","cacheDir","path","join","targetVersionDir","dirHasEntries","sourceVersionDir","findSeedSource","tmpDir","fs","mkdirSync","recursive","rmSync","force","seedCacheDir","renameSync","Log","info","warn","projectRelToWorktree","relative","worktreeRoot","distRelToProject","currentWorktree","resolve","best","root","mainRepoRoot","listLinkedWorktreeRoots","versionDir","commitTimeMs","currentCommitTimeMs","undefined","commitTime","JSON","parse","readFileSync","commit_time","parsed","Date","Number","isNaN","dir","readdirSync","length","IMMUTABLE_CACHE_FILE","src","dst","stat","lstatSync","isDirectory","name","test","linkSync","copyFileSync"],"mappings":"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","ignoreList":[0]}