mirror of
https://github.com/Pandipipas/scoreko-electron-dev.git
synced 2026-06-06 05:32:06 +00:00
feat: enhance NodeCG runtime management and packaging
- Update .gitignore and .prettierignore to exclude additional cache and configuration files. - Revise README.md for clarity on build processes and runtime behavior. - Improve architecture documentation to reflect changes in startup flow and module responsibilities. - Modify troubleshooting guide to address common runtime issues and installation steps. - Enhance ESLint configuration to ignore more directories. - Update package.json scripts for better build and distribution processes. - Introduce build-scoreko-bundle.mjs for building the Scoreko bundle. - Implement prepare-nodecg-runtime.mjs for managing NodeCG runtime installation and updates. - Add runtime-provisioner.ts to handle user-specific NodeCG runtime provisioning. - Create tests for runtime provisioning to ensure correct behavior. - Refactor process-manager.ts and main.ts to integrate new runtime management logic.
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
import assert from "node:assert/strict";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
|
||||
import { prepareUserNodecgRuntime } from "../main/nodecg/runtime-provisioner";
|
||||
|
||||
type FakeFsState = {
|
||||
paths: Set<string>;
|
||||
files: Map<string, string>;
|
||||
removed: string[];
|
||||
copied: Array<{ from: string; to: string }>;
|
||||
};
|
||||
|
||||
function createFakeFs(initialPaths: string[] = [], initialFiles: Record<string, string> = {}) {
|
||||
const state: FakeFsState = {
|
||||
paths: new Set(initialPaths.map((candidatePath) => path.normalize(candidatePath))),
|
||||
files: new Map(Object.entries(initialFiles).map(([filePath, content]) => [path.normalize(filePath), content])),
|
||||
removed: [],
|
||||
copied: [],
|
||||
};
|
||||
|
||||
for (const filePath of state.files.keys()) {
|
||||
state.paths.add(filePath);
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
deps: {
|
||||
existsSync: (candidatePath: string) => state.paths.has(path.normalize(candidatePath)),
|
||||
mkdirSync: (candidatePath: string) => {
|
||||
state.paths.add(path.normalize(candidatePath));
|
||||
return undefined;
|
||||
},
|
||||
rmSync: (candidatePath: string) => {
|
||||
state.removed.push(path.normalize(candidatePath));
|
||||
state.paths.delete(path.normalize(candidatePath));
|
||||
},
|
||||
cpSync: (from: string, to: string) => {
|
||||
state.copied.push({ from: path.normalize(from), to: path.normalize(to) });
|
||||
state.paths.add(path.normalize(to));
|
||||
state.paths.add(path.join(path.normalize(to), "index.js"));
|
||||
state.paths.add(path.join(path.normalize(to), "package.json"));
|
||||
state.paths.add(path.join(path.normalize(to), "node_modules", "nodecg", "dist", "server", "bootstrap.js"));
|
||||
state.paths.add(path.join(path.normalize(to), "bundles", "scoreko-dev", "package.json"));
|
||||
},
|
||||
readFileSync: (filePath: string) => state.files.get(path.normalize(filePath)) ?? "{}",
|
||||
writeFileSync: (filePath: string, content: string) => {
|
||||
state.files.set(path.normalize(filePath), content);
|
||||
state.paths.add(path.normalize(filePath));
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function getSourcePaths(source: string) {
|
||||
return [
|
||||
source,
|
||||
path.join(source, "index.js"),
|
||||
path.join(source, "package.json"),
|
||||
path.join(source, "node_modules", "nodecg", "dist", "server", "bootstrap.js"),
|
||||
path.join(source, "bundles", "scoreko-dev", "package.json"),
|
||||
path.join(source, ".scoreko-runtime.json"),
|
||||
];
|
||||
}
|
||||
|
||||
test("prepareUserNodecgRuntime copies the packaged runtime into userData", () => {
|
||||
const source = path.normalize("/app/lib/nodecg");
|
||||
const userData = path.normalize("/user/scoreko");
|
||||
const { state, deps } = createFakeFs(getSourcePaths(source), {
|
||||
[path.join(source, ".scoreko-runtime.json")]: JSON.stringify({ bundleVersion: "0.1.0", nodecgVersion: "2.6.4" }),
|
||||
});
|
||||
|
||||
const runtimePath = prepareUserNodecgRuntime({
|
||||
sourceRuntimePath: source,
|
||||
userDataPath: userData,
|
||||
appVersion: "0.1.0",
|
||||
bundleName: "scoreko-dev",
|
||||
log: () => undefined,
|
||||
deps,
|
||||
});
|
||||
|
||||
assert.equal(runtimePath, path.join(userData, "nodecg"));
|
||||
assert.equal(state.copied.length, 1);
|
||||
assert.ok(state.paths.has(path.join(userData, "nodecg", "cfg")));
|
||||
assert.ok(state.paths.has(path.join(userData, "nodecg", "db")));
|
||||
assert.ok(state.paths.has(path.join(userData, "nodecg", "logs")));
|
||||
assert.ok(state.files.has(path.join(userData, "nodecg", ".scoreko-installed-runtime.json")));
|
||||
});
|
||||
|
||||
test("prepareUserNodecgRuntime keeps an up-to-date runtime in place", () => {
|
||||
const source = path.normalize("/app/lib/nodecg");
|
||||
const userData = path.normalize("/user/scoreko");
|
||||
const target = path.join(userData, "nodecg");
|
||||
const sourceManifest = { bundleVersion: "0.1.0", nodecgVersion: "2.6.4" };
|
||||
const targetManifest = { appVersion: "0.1.0", bundleName: "scoreko-dev", sourceRuntime: sourceManifest };
|
||||
const { state, deps } = createFakeFs(
|
||||
[
|
||||
...getSourcePaths(source),
|
||||
path.join(target, "node_modules", "nodecg", "dist", "server", "bootstrap.js"),
|
||||
path.join(target, "bundles", "scoreko-dev", "package.json"),
|
||||
path.join(target, ".scoreko-installed-runtime.json"),
|
||||
],
|
||||
{
|
||||
[path.join(source, ".scoreko-runtime.json")]: JSON.stringify(sourceManifest),
|
||||
[path.join(target, ".scoreko-installed-runtime.json")]: JSON.stringify(targetManifest),
|
||||
},
|
||||
);
|
||||
|
||||
prepareUserNodecgRuntime({
|
||||
sourceRuntimePath: source,
|
||||
userDataPath: userData,
|
||||
appVersion: "0.1.0",
|
||||
bundleName: "scoreko-dev",
|
||||
log: () => undefined,
|
||||
deps,
|
||||
});
|
||||
|
||||
assert.equal(state.copied.length, 0);
|
||||
assert.equal(state.removed.length, 0);
|
||||
});
|
||||
|
||||
test("prepareUserNodecgRuntime refreshes managed files when the app version changes", () => {
|
||||
const source = path.normalize("/app/lib/nodecg");
|
||||
const userData = path.normalize("/user/scoreko");
|
||||
const target = path.join(userData, "nodecg");
|
||||
const sourceManifest = { bundleVersion: "0.1.0", nodecgVersion: "2.6.4" };
|
||||
const targetManifest = { appVersion: "0.0.9", bundleName: "scoreko-dev", sourceRuntime: sourceManifest };
|
||||
const { state, deps } = createFakeFs(
|
||||
[
|
||||
...getSourcePaths(source),
|
||||
path.join(target, "node_modules", "nodecg", "dist", "server", "bootstrap.js"),
|
||||
path.join(target, "bundles", "scoreko-dev", "package.json"),
|
||||
path.join(target, ".scoreko-installed-runtime.json"),
|
||||
],
|
||||
{
|
||||
[path.join(source, ".scoreko-runtime.json")]: JSON.stringify(sourceManifest),
|
||||
[path.join(target, ".scoreko-installed-runtime.json")]: JSON.stringify(targetManifest),
|
||||
},
|
||||
);
|
||||
|
||||
prepareUserNodecgRuntime({
|
||||
sourceRuntimePath: source,
|
||||
userDataPath: userData,
|
||||
appVersion: "0.1.0",
|
||||
bundleName: "scoreko-dev",
|
||||
log: () => undefined,
|
||||
deps,
|
||||
});
|
||||
|
||||
assert.equal(state.copied.length, 1);
|
||||
assert.ok(state.removed.includes(path.join(target, "node_modules")));
|
||||
assert.ok(state.removed.includes(path.join(target, "bundles")));
|
||||
assert.ok(!state.removed.includes(path.join(target, "db")));
|
||||
});
|
||||
Reference in New Issue
Block a user