fix runtime deps update from legacy symlinks

This commit is contained in:
Mark Goldenstein
2026-04-30 15:29:24 -07:00
committed by Peter Steinberger
parent d61c919106
commit 1e6bdf3a55
4 changed files with 84 additions and 0 deletions

View File

@@ -11,6 +11,7 @@ import { pruneStagedRuntimeDependencyCargo } from "./bundled-runtime-deps-prune.
import {
assertPathIsNotSymlink,
makePluginOwnedTempDir,
removeLegacyBundledRuntimeDepsSymlink,
removeOwnedTempPathBestEffort,
removePathIfExists,
replaceDirAtomically,
@@ -155,6 +156,7 @@ export function stageInstalledRootRuntimeDeps(params) {
const rootsToCopy = selectRuntimeDependencyRootsToCopy(resolution);
const nodeModulesDir = path.join(pluginDir, "node_modules");
if (rootsToCopy.length === 0) {
removeLegacyBundledRuntimeDepsSymlink(nodeModulesDir, repoRoot);
assertPathIsNotSymlink(nodeModulesDir, "remove runtime deps");
removePathIfExists(nodeModulesDir);
writeJsonAtomically(stampPath, {
@@ -196,6 +198,7 @@ export function stageInstalledRootRuntimeDeps(params) {
}
pruneStagedRuntimeDependencyCargo(stagedNodeModulesDir, pruneConfig);
removeLegacyBundledRuntimeDepsSymlink(nodeModulesDir, repoRoot);
replaceDirAtomically(nodeModulesDir, stagedNodeModulesDir);
writeJsonAtomically(stampPath, {
cheapFingerprint,

View File

@@ -95,6 +95,46 @@ export function assertPathIsNotSymlink(targetPath, label) {
}
}
function isPathInside(parentPath, childPath) {
const relativePath = path.relative(parentPath, childPath);
return (
relativePath.length > 0 && !relativePath.startsWith("..") && !path.isAbsolute(relativePath)
);
}
export function removeLegacyBundledRuntimeDepsSymlink(targetPath, repoRoot) {
let stats;
try {
stats = fs.lstatSync(targetPath);
} catch (error) {
if (error?.code === "ENOENT") {
return false;
}
throw error;
}
if (!stats.isSymbolicLink()) {
return false;
}
const legacyRuntimeDepsRoot = path.resolve(repoRoot, ".local", "bundled-plugin-runtime-deps");
let linkedPath;
try {
linkedPath = fs.readlinkSync(targetPath);
} catch {
return false;
}
const resolvedLinkedPath = path.resolve(path.dirname(targetPath), linkedPath);
if (
path.basename(resolvedLinkedPath) !== "node_modules" ||
!isPathInside(legacyRuntimeDepsRoot, resolvedLinkedPath)
) {
return false;
}
removePathIfExists(targetPath);
return true;
}
export function replaceDirAtomically(targetPath, sourcePath) {
assertPathIsNotSymlink(targetPath, "replace runtime deps");
const targetParentDir = path.dirname(targetPath);

View File

@@ -24,6 +24,7 @@ import {
import {
assertPathIsNotSymlink,
makePluginOwnedTempDir,
removeLegacyBundledRuntimeDepsSymlink,
removeOwnedTempPathBestEffort,
removePathIfExists,
removeStaleRuntimeDepsTempDirs,
@@ -323,8 +324,10 @@ function installPluginRuntimeDeps(params) {
}
if (fs.existsSync(stagedNodeModulesDir)) {
pruneStagedRuntimeDependencyCargo(stagedNodeModulesDir, pruneConfig);
removeLegacyBundledRuntimeDepsSymlink(nodeModulesDir, repoRoot);
replaceDirAtomically(nodeModulesDir, stagedNodeModulesDir);
} else {
removeLegacyBundledRuntimeDepsSymlink(nodeModulesDir, repoRoot);
assertPathIsNotSymlink(nodeModulesDir, "remove runtime deps");
removePathIfExists(nodeModulesDir);
}