openclaw/scripts/stage-bundled-plugin-runtim...

101 lines
3.0 KiB
JavaScript

import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { removePathIfExists } from "./runtime-postbuild-shared.mjs";
function linkOrCopyFile(sourcePath, targetPath) {
try {
fs.linkSync(sourcePath, targetPath);
} catch (error) {
if (error && typeof error === "object" && "code" in error) {
const code = error.code;
if (code === "EXDEV" || code === "EPERM" || code === "EMLINK") {
fs.copyFileSync(sourcePath, targetPath);
return;
}
}
throw error;
}
}
function mirrorTreeWithHardlinks(sourceRoot, targetRoot) {
fs.mkdirSync(targetRoot, { recursive: true });
const queue = [{ sourceDir: sourceRoot, targetDir: targetRoot }];
while (queue.length > 0) {
const current = queue.pop();
if (!current) {
continue;
}
for (const dirent of fs.readdirSync(current.sourceDir, { withFileTypes: true })) {
const sourcePath = path.join(current.sourceDir, dirent.name);
const targetPath = path.join(current.targetDir, dirent.name);
if (dirent.isDirectory()) {
fs.mkdirSync(targetPath, { recursive: true });
queue.push({ sourceDir: sourcePath, targetDir: targetPath });
continue;
}
if (dirent.isSymbolicLink()) {
fs.symlinkSync(fs.readlinkSync(sourcePath), targetPath);
continue;
}
if (!dirent.isFile()) {
continue;
}
linkOrCopyFile(sourcePath, targetPath);
}
}
}
function symlinkType() {
return process.platform === "win32" ? "junction" : "dir";
}
function linkPluginNodeModules(params) {
const runtimeNodeModulesDir = path.join(params.runtimePluginDir, "node_modules");
removePathIfExists(runtimeNodeModulesDir);
if (!fs.existsSync(params.sourcePluginNodeModulesDir)) {
return;
}
fs.symlinkSync(params.sourcePluginNodeModulesDir, runtimeNodeModulesDir, symlinkType());
}
export function stageBundledPluginRuntime(params = {}) {
const repoRoot = params.cwd ?? params.repoRoot ?? process.cwd();
const distRoot = path.join(repoRoot, "dist");
const runtimeRoot = path.join(repoRoot, "dist-runtime");
const sourceExtensionsRoot = path.join(repoRoot, "extensions");
const distExtensionsRoot = path.join(distRoot, "extensions");
const runtimeExtensionsRoot = path.join(runtimeRoot, "extensions");
if (!fs.existsSync(distExtensionsRoot)) {
removePathIfExists(runtimeRoot);
return;
}
removePathIfExists(runtimeRoot);
mirrorTreeWithHardlinks(distRoot, runtimeRoot);
for (const dirent of fs.readdirSync(distExtensionsRoot, { withFileTypes: true })) {
if (!dirent.isDirectory()) {
continue;
}
const runtimePluginDir = path.join(runtimeExtensionsRoot, dirent.name);
const sourcePluginNodeModulesDir = path.join(sourceExtensionsRoot, dirent.name, "node_modules");
linkPluginNodeModules({
runtimePluginDir,
sourcePluginNodeModulesDir,
});
}
}
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
stageBundledPluginRuntime();
}