mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
perf(plugins): skip fresh boundary dts prep
This commit is contained in:
@@ -1,10 +1,93 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { resolve } from "node:path";
|
||||
import path, { resolve } from "node:path";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const repoRoot = resolve(import.meta.dirname, "..");
|
||||
const tscBin = require.resolve("typescript/bin/tsc");
|
||||
const TYPE_INPUT_EXTENSIONS = new Set([".ts", ".tsx", ".d.ts", ".js", ".mjs", ".json"]);
|
||||
|
||||
const ROOT_DTS_INPUTS = [
|
||||
"tsconfig.json",
|
||||
"tsconfig.plugin-sdk.dts.json",
|
||||
"src",
|
||||
"packages/memory-host-sdk/src",
|
||||
];
|
||||
const PACKAGE_DTS_INPUTS = [
|
||||
"tsconfig.json",
|
||||
"packages/plugin-sdk/tsconfig.json",
|
||||
"src/plugin-sdk",
|
||||
"src/video-generation/dashscope-compatible.ts",
|
||||
"src/video-generation/types.ts",
|
||||
"src/types",
|
||||
];
|
||||
const ENTRY_SHIMS_INPUTS = [
|
||||
"scripts/write-plugin-sdk-entry-dts.ts",
|
||||
"scripts/lib/plugin-sdk-entrypoints.json",
|
||||
"scripts/lib/plugin-sdk-entries.mjs",
|
||||
];
|
||||
|
||||
function isRelevantTypeInput(filePath) {
|
||||
const basename = path.basename(filePath);
|
||||
if (basename.endsWith(".test.ts")) {
|
||||
return false;
|
||||
}
|
||||
return TYPE_INPUT_EXTENSIONS.has(path.extname(filePath));
|
||||
}
|
||||
|
||||
function collectNewestMtime(paths, params = {}) {
|
||||
const rootDir = params.rootDir ?? repoRoot;
|
||||
const includeFile = params.includeFile ?? (() => true);
|
||||
let newestMtimeMs = 0;
|
||||
|
||||
function visit(entryPath) {
|
||||
if (!fs.existsSync(entryPath)) {
|
||||
return;
|
||||
}
|
||||
const stats = fs.statSync(entryPath);
|
||||
if (stats.isDirectory()) {
|
||||
for (const child of fs.readdirSync(entryPath)) {
|
||||
visit(path.join(entryPath, child));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!includeFile(entryPath)) {
|
||||
return;
|
||||
}
|
||||
newestMtimeMs = Math.max(newestMtimeMs, stats.mtimeMs);
|
||||
}
|
||||
|
||||
for (const relativePath of paths) {
|
||||
visit(resolve(rootDir, relativePath));
|
||||
}
|
||||
|
||||
return newestMtimeMs;
|
||||
}
|
||||
|
||||
function collectOldestMtime(paths, params = {}) {
|
||||
const rootDir = params.rootDir ?? repoRoot;
|
||||
let oldestMtimeMs = Number.POSITIVE_INFINITY;
|
||||
|
||||
for (const relativePath of paths) {
|
||||
const absolutePath = resolve(rootDir, relativePath);
|
||||
if (!fs.existsSync(absolutePath)) {
|
||||
return null;
|
||||
}
|
||||
oldestMtimeMs = Math.min(oldestMtimeMs, fs.statSync(absolutePath).mtimeMs);
|
||||
}
|
||||
|
||||
return Number.isFinite(oldestMtimeMs) ? oldestMtimeMs : null;
|
||||
}
|
||||
|
||||
export function isArtifactSetFresh(params) {
|
||||
const newestInputMtimeMs = collectNewestMtime(params.inputPaths, {
|
||||
rootDir: params.rootDir,
|
||||
includeFile: params.includeFile,
|
||||
});
|
||||
const oldestOutputMtimeMs = collectOldestMtime(params.outputPaths, { rootDir: params.rootDir });
|
||||
return oldestOutputMtimeMs !== null && oldestOutputMtimeMs >= newestInputMtimeMs;
|
||||
}
|
||||
|
||||
export function createPrefixedOutputWriter(label, target) {
|
||||
let buffered = "";
|
||||
@@ -118,23 +201,58 @@ export async function runNodeStepsInParallel(steps) {
|
||||
|
||||
export async function main() {
|
||||
try {
|
||||
await runNodeStepsInParallel([
|
||||
{
|
||||
const rootDtsFresh = isArtifactSetFresh({
|
||||
inputPaths: ROOT_DTS_INPUTS,
|
||||
outputPaths: ["dist/plugin-sdk/.tsbuildinfo"],
|
||||
includeFile: isRelevantTypeInput,
|
||||
});
|
||||
const packageDtsFresh = isArtifactSetFresh({
|
||||
inputPaths: PACKAGE_DTS_INPUTS,
|
||||
outputPaths: ["packages/plugin-sdk/dist/.tsbuildinfo"],
|
||||
includeFile: isRelevantTypeInput,
|
||||
});
|
||||
const entryShimsFresh = isArtifactSetFresh({
|
||||
inputPaths: [
|
||||
...ENTRY_SHIMS_INPUTS,
|
||||
"dist/plugin-sdk/.tsbuildinfo",
|
||||
"packages/plugin-sdk/dist/.tsbuildinfo",
|
||||
],
|
||||
outputPaths: ["dist/plugin-sdk/.boundary-entry-shims.stamp"],
|
||||
});
|
||||
|
||||
const pendingSteps = [];
|
||||
if (!rootDtsFresh) {
|
||||
pendingSteps.push({
|
||||
label: "plugin-sdk boundary dts",
|
||||
args: [tscBin, "-p", "tsconfig.plugin-sdk.dts.json"],
|
||||
timeoutMs: 300_000,
|
||||
},
|
||||
{
|
||||
});
|
||||
} else {
|
||||
process.stdout.write("[plugin-sdk boundary dts] fresh; skipping\n");
|
||||
}
|
||||
if (!packageDtsFresh) {
|
||||
pendingSteps.push({
|
||||
label: "plugin-sdk package boundary dts",
|
||||
args: [tscBin, "-p", "packages/plugin-sdk/tsconfig.json"],
|
||||
timeoutMs: 300_000,
|
||||
},
|
||||
]);
|
||||
await runNodeStep(
|
||||
"plugin-sdk boundary root shims",
|
||||
["--import", "tsx", resolve(repoRoot, "scripts/write-plugin-sdk-entry-dts.ts")],
|
||||
120_000,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
process.stdout.write("[plugin-sdk package boundary dts] fresh; skipping\n");
|
||||
}
|
||||
|
||||
if (pendingSteps.length > 0) {
|
||||
await runNodeStepsInParallel(pendingSteps);
|
||||
}
|
||||
|
||||
if (!entryShimsFresh || pendingSteps.length > 0) {
|
||||
await runNodeStep(
|
||||
"plugin-sdk boundary root shims",
|
||||
["--import", "tsx", resolve(repoRoot, "scripts/write-plugin-sdk-entry-dts.ts")],
|
||||
120_000,
|
||||
);
|
||||
} else {
|
||||
process.stdout.write("[plugin-sdk boundary root shims] fresh; skipping\n");
|
||||
}
|
||||
} catch (error) {
|
||||
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
||||
process.exit(1);
|
||||
|
||||
@@ -89,3 +89,7 @@ for (const entry of pluginSdkEntrypoints) {
|
||||
fs.mkdirSync(path.dirname(runtimeOut), { recursive: true });
|
||||
fs.writeFileSync(runtimeOut, runtimeShim, "utf8");
|
||||
}
|
||||
|
||||
const stampPath = path.join(process.cwd(), "dist/plugin-sdk/.boundary-entry-shims.stamp");
|
||||
fs.mkdirSync(path.dirname(stampPath), { recursive: true });
|
||||
fs.writeFileSync(stampPath, `${new Date().toISOString()}\n`, "utf8");
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
createPrefixedOutputWriter,
|
||||
isArtifactSetFresh,
|
||||
runNodeStepsInParallel,
|
||||
} from "../../scripts/prepare-extension-package-boundary-artifacts.mjs";
|
||||
|
||||
const tempRoots = new Set<string>();
|
||||
|
||||
afterEach(() => {
|
||||
for (const rootDir of tempRoots) {
|
||||
fs.rmSync(rootDir, { force: true, recursive: true });
|
||||
}
|
||||
tempRoots.clear();
|
||||
});
|
||||
|
||||
describe("prepare-extension-package-boundary-artifacts", () => {
|
||||
it("prefixes each completed line and flushes the trailing partial line", () => {
|
||||
let output = "";
|
||||
@@ -40,4 +53,36 @@ describe("prepare-extension-package-boundary-artifacts", () => {
|
||||
|
||||
expect(Date.now() - startedAt).toBeLessThan(2_000);
|
||||
});
|
||||
|
||||
it("treats artifacts as fresh only when outputs are newer than inputs", () => {
|
||||
const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-boundary-prep-"));
|
||||
tempRoots.add(rootDir);
|
||||
const inputPath = path.join(rootDir, "src", "demo.ts");
|
||||
const outputPath = path.join(rootDir, "dist", "demo.tsbuildinfo");
|
||||
fs.mkdirSync(path.dirname(inputPath), { recursive: true });
|
||||
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
||||
fs.writeFileSync(inputPath, "export const demo = 1;\n", "utf8");
|
||||
fs.writeFileSync(outputPath, "ok\n", "utf8");
|
||||
|
||||
fs.utimesSync(inputPath, new Date(1_000), new Date(1_000));
|
||||
fs.utimesSync(outputPath, new Date(2_000), new Date(2_000));
|
||||
|
||||
expect(
|
||||
isArtifactSetFresh({
|
||||
rootDir,
|
||||
inputPaths: ["src"],
|
||||
outputPaths: ["dist/demo.tsbuildinfo"],
|
||||
}),
|
||||
).toBe(true);
|
||||
|
||||
fs.utimesSync(inputPath, new Date(3_000), new Date(3_000));
|
||||
|
||||
expect(
|
||||
isArtifactSetFresh({
|
||||
rootDir,
|
||||
inputPaths: ["src"],
|
||||
outputPaths: ["dist/demo.tsbuildinfo"],
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user