UNPKG

next

Version:

The React Framework

107 lines (106 loc) 4 kB
import fs from 'fs'; import path from 'path'; import * as Log from '../build/output/log'; import { getTurbopackCacheVersion } from '../build/swc'; import { getGitWorktreeInfo, listLinkedWorktreeRoots } from './git-worktree'; export function seedTurbopackCacheIfNeeded({ projectDir, distDir }) { // This gets the version assuming that nothing is dirty. // If things are dirty, turbopack would write things // in a different location. There are other circumstances // as well. This only matters for people developing turbopack // see handle_db_versioning in turbotask backend for more details. const version = getTurbopackCacheVersion(); if (!version) return; const worktreeInfo = getGitWorktreeInfo(projectDir); if (!worktreeInfo) return; const cacheDir = path.join(distDir, 'cache', 'turbopack'); const targetVersionDir = path.join(cacheDir, version); if (dirHasEntries(targetVersionDir)) return; let sourceVersionDir; try { sourceVersionDir = findSeedSource(worktreeInfo, projectDir, distDir, version); } catch { return; } if (!sourceVersionDir) return; const tmpDir = `${targetVersionDir}.seeding`; // Making sure we don't copy partial data if process interrupted // There is a potential race condition here // if someone wrote to the cache while we were seeding it // but with the immutable design and all that, I'm not super worried try { fs.mkdirSync(cacheDir, { recursive: true }); fs.rmSync(tmpDir, { recursive: true, force: true }); seedCacheDir(sourceVersionDir, tmpDir); fs.renameSync(tmpDir, targetVersionDir); Log.info(`Seeded Turbopack cache from ${sourceVersionDir}.`); } catch { fs.rmSync(tmpDir, { recursive: true, force: true }); Log.warn(`Failed to seed Turbopack cache from ${sourceVersionDir} to ${targetVersionDir}.`); } } function findSeedSource(worktreeInfo, projectDir, distDir, version) { const projectRelToWorktree = path.relative(worktreeInfo.worktreeRoot, projectDir); const distRelToProject = path.relative(projectDir, distDir); const currentWorktree = path.resolve(worktreeInfo.worktreeRoot); // We are going to find the best candidate worktree // based on the newest mtime of the CURRENT file in the cache directory. // We only look at our version let best; for (const root of [ worktreeInfo.mainRepoRoot, ...listLinkedWorktreeRoots(worktreeInfo.mainRepoRoot) ]){ if (path.resolve(root) === currentWorktree) continue; const versionDir = path.join(root, projectRelToWorktree, distRelToProject, 'cache', 'turbopack', version); const mtimeMs = currentMtimeMs(versionDir); if (mtimeMs === undefined) continue; if (!best || mtimeMs > best.mtimeMs) { best = { versionDir, mtimeMs }; } } return best == null ? void 0 : best.versionDir; } function currentMtimeMs(versionDir) { try { return fs.statSync(path.join(versionDir, 'CURRENT')).mtimeMs; } catch { return undefined; } } function dirHasEntries(dir) { try { return fs.readdirSync(dir).length > 0; } catch { return false; } } const IMMUTABLE_CACHE_FILE = /\.(sst|blob|meta|del)$/; function seedCacheDir(src, dst) { const stat = fs.lstatSync(src); if (stat.isDirectory()) { fs.mkdirSync(dst, { recursive: true }); for (const name of fs.readdirSync(src)){ seedCacheDir(path.join(src, name), path.join(dst, name)); } } else if (IMMUTABLE_CACHE_FILE.test(src)) { fs.linkSync(src, dst); } else { // Mutable/unknown (CURRENT, LOG, …) - copy so it gets its own inode. fs.copyFileSync(src, dst); } } //# sourceMappingURL=turbopack-cache-seed.js.map