mirror of
https://github.com/nimbold/Firelink.git
synced 2026-09-09 17:25:42 +00:00
fix(ci): resolve Windows cross-drive engine workspace and strip verbatim paths
- allocate engine workspace on the repository drive when os.tmpdir() is cross-drive on Windows - resolve RUNNER_TEMP on GitHub Actions to align workspace drive with checkout - strip Win32 \\?\ verbatim prefixes to ensure Tauri resource normalizer compatibility
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { removePathWithRetry } from './engine-payload-promotion.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = path.resolve(__dirname, '..');
|
||||
|
||||
const ARCH_MAP = { x64: 'x86_64', arm64: 'aarch64' };
|
||||
const PLATFORM_MAP = {
|
||||
darwin: 'apple-darwin',
|
||||
@@ -94,18 +98,58 @@ export function assertSafeOutputRoot(outputRoot, forbiddenRoots = []) {
|
||||
return canonicalOutputRoot;
|
||||
}
|
||||
|
||||
export function stripVerbatimPrefix(filePath) {
|
||||
return typeof filePath === 'string' && filePath.startsWith('\\\\?\\')
|
||||
? filePath.slice(4)
|
||||
: filePath;
|
||||
}
|
||||
|
||||
export function resolveWorkspaceTempBase(referencePath = repoRoot) {
|
||||
if (process.env.FIRELINK_ENGINE_WORKSPACE_BASE) {
|
||||
return path.resolve(process.env.FIRELINK_ENGINE_WORKSPACE_BASE);
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
const referenceDrive = path.parse(path.resolve(referencePath)).root.toLowerCase();
|
||||
|
||||
if (process.env.RUNNER_TEMP) {
|
||||
const runnerTemp = path.resolve(process.env.RUNNER_TEMP);
|
||||
if (path.parse(runnerTemp).root.toLowerCase() === referenceDrive) {
|
||||
return runnerTemp;
|
||||
}
|
||||
}
|
||||
|
||||
const osTemp = path.resolve(os.tmpdir());
|
||||
if (path.parse(osTemp).root.toLowerCase() === referenceDrive) {
|
||||
return osTemp;
|
||||
}
|
||||
|
||||
const adjacentTemp = path.join(path.resolve(referencePath, '..'), '.firelink-engine-workspaces');
|
||||
fs.mkdirSync(adjacentTemp, { recursive: true, mode: 0o700 });
|
||||
return adjacentTemp;
|
||||
}
|
||||
|
||||
if (process.env.RUNNER_TEMP) {
|
||||
return path.resolve(process.env.RUNNER_TEMP);
|
||||
}
|
||||
|
||||
return os.tmpdir();
|
||||
}
|
||||
|
||||
export function createEngineWorkspace(target) {
|
||||
assertSafeTarget(target);
|
||||
const workspace = fs.realpathSync.native(
|
||||
fs.mkdtempSync(path.join(os.tmpdir(), `firelink-engine-${target}-${process.pid}-`)),
|
||||
const tempBase = resolveWorkspaceTempBase();
|
||||
const rawWorkspace = fs.realpathSync.native(
|
||||
fs.mkdtempSync(path.join(tempBase, `firelink-engine-${target}-${process.pid}-`)),
|
||||
);
|
||||
const workspace = stripVerbatimPrefix(rawWorkspace);
|
||||
const outputRoot = path.join(workspace, 'engine-dist');
|
||||
fs.mkdirSync(outputRoot, { recursive: true, mode: 0o700 });
|
||||
return { outputRoot, runtimeRoot: outputRoot, workspace };
|
||||
}
|
||||
|
||||
export function engineResourceConfig(outputRoot) {
|
||||
const source = `${path.resolve(outputRoot)}${path.sep}`;
|
||||
const source = `${stripVerbatimPrefix(path.resolve(outputRoot))}${path.sep}`;
|
||||
return JSON.stringify({
|
||||
bundle: {
|
||||
resources: {
|
||||
@@ -116,7 +160,7 @@ export function engineResourceConfig(outputRoot) {
|
||||
}
|
||||
|
||||
export async function removeEngineWorkspace(workspace) {
|
||||
const resolved = path.resolve(workspace);
|
||||
const resolved = stripVerbatimPrefix(path.resolve(workspace));
|
||||
const basename = path.basename(resolved);
|
||||
if (!basename.startsWith('firelink-engine-')) {
|
||||
throw new Error(`Refusing to remove an unexpected engine workspace: ${resolved}`);
|
||||
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
removeEngineWorkspace,
|
||||
resolveOutputRoot,
|
||||
resolveTargetTriple,
|
||||
resolveWorkspaceTempBase,
|
||||
stripVerbatimPrefix,
|
||||
} from './engine-workspace.js';
|
||||
|
||||
test('target resolution accepts explicit and inline target arguments', () => {
|
||||
@@ -90,3 +92,21 @@ test('output roots are checked after resolving symlinked parents', () => {
|
||||
fs.rmSync(temporaryRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('stripVerbatimPrefix removes Win32 verbatim namespaces', () => {
|
||||
assert.equal(stripVerbatimPrefix('\\\\?\\D:\\a\\_temp'), 'D:\\a\\_temp');
|
||||
assert.equal(stripVerbatimPrefix('D:\\a\\_temp'), 'D:\\a\\_temp');
|
||||
assert.equal(stripVerbatimPrefix('/tmp/firelink'), '/tmp/firelink');
|
||||
});
|
||||
|
||||
test('resolveWorkspaceTempBase honors FIRELINK_ENGINE_WORKSPACE_BASE override', () => {
|
||||
const custom = path.resolve('/custom/engine/base');
|
||||
const prev = process.env.FIRELINK_ENGINE_WORKSPACE_BASE;
|
||||
process.env.FIRELINK_ENGINE_WORKSPACE_BASE = custom;
|
||||
try {
|
||||
assert.equal(resolveWorkspaceTempBase(), custom);
|
||||
} finally {
|
||||
if (prev === undefined) delete process.env.FIRELINK_ENGINE_WORKSPACE_BASE;
|
||||
else process.env.FIRELINK_ENGINE_WORKSPACE_BASE = prev;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user