mirror of
https://github.com/stablyai/orca.git
synced 2026-10-24 16:03:45 +00:00
fix(windows): stage node-addon-api headers before process-tree rebuild
Patched windows-process-tree binding.gyp includes deps/node-addon-api, but those headers were only copied by the later relay-addon script. Postinstall electron-rebuild then failed CI Windows installs with C1083 napi.h.
This commit is contained in:
@@ -29,11 +29,11 @@ import {
|
||||
readSync,
|
||||
writeFileSync
|
||||
} from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { RELAY_WINDOWS_PROCESS_TREE_FILENAME } from '../../src/shared/relay-artifacts.ts'
|
||||
import {
|
||||
nodeGypRebuildInvocation,
|
||||
stageWindowsProcessTreeNodeAddonApiHeaders,
|
||||
WINDOWS_PROCESS_TREE_PACKAGE_DIR as PACKAGE_DIR
|
||||
} from './windows-process-tree-gyp-rebuild.mjs'
|
||||
|
||||
@@ -96,10 +96,6 @@ function assertPatchApplied() {
|
||||
function applyWindowsProcessTreeBuildFixes() {
|
||||
const bindingPath = join(PACKAGE_DIR, 'binding.gyp')
|
||||
const processPath = join(PACKAGE_DIR, 'src', 'process.cc')
|
||||
const nodeAddonApiDir = dirname(
|
||||
createRequire(join(PACKAGE_DIR, 'package.json')).resolve('node-addon-api/package.json')
|
||||
)
|
||||
const stagedHeaderDir = join(PACKAGE_DIR, 'deps', 'node-addon-api')
|
||||
let bindingGyp = readFileSync(bindingPath, 'utf8')
|
||||
let processCc = readFileSync(processPath, 'utf8')
|
||||
const originalBinding = bindingGyp
|
||||
@@ -134,10 +130,7 @@ function applyWindowsProcessTreeBuildFixes() {
|
||||
if (processCc !== originalProcess) {
|
||||
writeFileSync(processPath, processCc)
|
||||
}
|
||||
mkdirSync(stagedHeaderDir, { recursive: true })
|
||||
for (const header of ['napi.h', 'napi-inl.h', 'napi-inl.deprecated.h']) {
|
||||
copyFileSync(join(nodeAddonApiDir, header), join(stagedHeaderDir, header))
|
||||
}
|
||||
stageWindowsProcessTreeNodeAddonApiHeaders(PACKAGE_DIR)
|
||||
if (bindingGyp !== originalBinding || processCc !== originalProcess) {
|
||||
console.warn('[windows-process-tree] Repaired un-applied pnpm patch hunks before build.')
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
import { rebuild } from '@electron/rebuild'
|
||||
import { execFileSync, spawnSync } from 'node:child_process'
|
||||
import { stageWindowsProcessTreeNodeAddonApiHeaders } from './windows-process-tree-gyp-rebuild.mjs'
|
||||
import {
|
||||
copyFileSync,
|
||||
existsSync,
|
||||
@@ -132,6 +133,14 @@ if (!ignoreModules.includes('cpu-features')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
rebuildPlatform === 'win32' &&
|
||||
modulesToRebuild.includes('@vscode/windows-process-tree') &&
|
||||
existsSync(join(projectDir, 'node_modules', '@vscode', 'windows-process-tree', 'package.json'))
|
||||
) {
|
||||
stageWindowsProcessTreeNodeAddonApiHeaders()
|
||||
}
|
||||
|
||||
try {
|
||||
await rebuild({
|
||||
buildPath: projectDir,
|
||||
|
||||
@@ -21,6 +21,9 @@ const sourceInstallScriptPath = fileURLToPath(
|
||||
const sourceNodePtyJobOwnershipPath = fileURLToPath(
|
||||
new URL('./node-pty-job-ownership.cjs', import.meta.url)
|
||||
)
|
||||
const sourceWindowsProcessTreeGypRebuildPath = fileURLToPath(
|
||||
new URL('./windows-process-tree-gyp-rebuild.mjs', import.meta.url)
|
||||
)
|
||||
|
||||
describe('rebuild-native-deps Electron install fallback', () => {
|
||||
it('continues non-strict postinstall when Electron retry download fails', () => {
|
||||
@@ -159,6 +162,41 @@ describe('rebuild-native-deps patched node-pty rebuild', () => {
|
||||
}
|
||||
)
|
||||
|
||||
it('stages windows-process-tree node-addon-api headers before a Windows rebuild', () => {
|
||||
const projectDir = mkTempProject()
|
||||
|
||||
try {
|
||||
writeFakeUsableElectronPackage(projectDir, { platform: 'win32' })
|
||||
writeFakeElectronRebuild(projectDir)
|
||||
writeFakeNodePtyConptyPayload(projectDir, 'x64')
|
||||
writeFakeWindowsProcessTreeWithNodeAddonApi(projectDir)
|
||||
|
||||
const result = runRebuildScript(
|
||||
projectDir,
|
||||
{ npm_config_platform: 'win32', npm_config_arch: 'x64' },
|
||||
['--platform=win32', '--arch=x64', '--force']
|
||||
)
|
||||
|
||||
expect(result.status, result.stderr).toBe(0)
|
||||
expect(
|
||||
readFileSync(
|
||||
join(
|
||||
projectDir,
|
||||
'node_modules',
|
||||
'@vscode',
|
||||
'windows-process-tree',
|
||||
'deps',
|
||||
'node-addon-api',
|
||||
'napi.h'
|
||||
),
|
||||
'utf8'
|
||||
)
|
||||
).toBe('// napi.h\n')
|
||||
} finally {
|
||||
rmSync(projectDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('restores the ConPTY runtime payload after a Windows Electron rebuild', () => {
|
||||
const projectDir = mkTempProject()
|
||||
|
||||
@@ -344,6 +382,10 @@ function mkTempProject() {
|
||||
sourceNodePtyJobOwnershipPath,
|
||||
join(projectDir, 'config', 'scripts', 'node-pty-job-ownership.cjs')
|
||||
)
|
||||
copyFileSync(
|
||||
sourceWindowsProcessTreeGypRebuildPath,
|
||||
join(projectDir, 'config', 'scripts', 'windows-process-tree-gyp-rebuild.mjs')
|
||||
)
|
||||
return projectDir
|
||||
}
|
||||
|
||||
@@ -578,6 +620,18 @@ function writeFakeWindowsProcessTree(projectDir) {
|
||||
writeFileSync(join(processTreeDir, 'index.js'), 'module.exports = {}\n')
|
||||
}
|
||||
|
||||
function writeFakeWindowsProcessTreeWithNodeAddonApi(projectDir) {
|
||||
const processTreeDir = join(projectDir, 'node_modules', '@vscode', 'windows-process-tree')
|
||||
const nodeAddonApiDir = join(processTreeDir, 'node_modules', 'node-addon-api')
|
||||
mkdirSync(nodeAddonApiDir, { recursive: true })
|
||||
writeFileSync(join(processTreeDir, 'package.json'), '{"dependencies":{"node-addon-api":"*"}}\n')
|
||||
writeFileSync(join(processTreeDir, 'index.js'), 'module.exports = {}\n')
|
||||
writeFileSync(join(nodeAddonApiDir, 'package.json'), '{"name":"node-addon-api"}\n')
|
||||
writeFileSync(join(nodeAddonApiDir, 'napi.h'), '// napi.h\n')
|
||||
writeFileSync(join(nodeAddonApiDir, 'napi-inl.h'), '// napi-inl.h\n')
|
||||
writeFileSync(join(nodeAddonApiDir, 'napi-inl.deprecated.h'), '// napi-inl.deprecated.h\n')
|
||||
}
|
||||
|
||||
function writeNodePtyPatchFile(projectDir) {
|
||||
mkdirSync(join(projectDir, 'config', 'patches'), { recursive: true })
|
||||
writeFileSync(join(projectDir, 'config', 'patches', 'node-pty@1.1.0.patch'), 'patch marker\n')
|
||||
|
||||
@@ -20,15 +20,22 @@ describe('windows-process-tree node-addon-api gyp path', () => {
|
||||
join(projectDir, 'config/scripts/build-windows-process-tree-relay-addon.mjs'),
|
||||
'utf8'
|
||||
)
|
||||
expect(buildScript).toContain(
|
||||
"for (const header of ['napi.h', 'napi-inl.h', 'napi-inl.deprecated.h'])"
|
||||
)
|
||||
expect(buildScript).toContain("import { createRequire } from 'node:module'")
|
||||
expect(buildScript).toContain("import { dirname, join, resolve } from 'node:path'")
|
||||
expect(buildScript).toContain(
|
||||
"createRequire(join(PACKAGE_DIR, 'package.json')).resolve('node-addon-api/package.json')"
|
||||
)
|
||||
expect(buildScript).toContain('stageWindowsProcessTreeNodeAddonApiHeaders(PACKAGE_DIR)')
|
||||
expect(buildScript).toContain('Repaired un-applied pnpm patch hunks before build.')
|
||||
const rebuildHelper = readFileSync(
|
||||
join(projectDir, 'config/scripts/windows-process-tree-gyp-rebuild.mjs'),
|
||||
'utf8'
|
||||
)
|
||||
expect(rebuildHelper).toContain("createRequire(join(packageDir, 'package.json'))")
|
||||
expect(rebuildHelper).toContain("resolve('node-addon-api/package.json')")
|
||||
expect(rebuildHelper).toContain("'napi.h'")
|
||||
expect(rebuildHelper).toContain("'napi-inl.h'")
|
||||
expect(rebuildHelper).toContain("'napi-inl.deprecated.h'")
|
||||
const rebuildScript = readFileSync(
|
||||
join(projectDir, 'config/scripts/rebuild-native-deps.mjs'),
|
||||
'utf8'
|
||||
)
|
||||
expect(rebuildScript).toContain('stageWindowsProcessTreeNodeAddonApiHeaders()')
|
||||
})
|
||||
|
||||
it('resolves node_addon_api.gyp to a real file from the package directory', () => {
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
* hop escapes the store and configure fails with "node_addon_api.gyp not
|
||||
* found" (run 32999886072).
|
||||
*/
|
||||
import { realpathSync } from 'node:fs'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { copyFileSync, mkdirSync, realpathSync } from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
|
||||
const ROOT = resolve(import.meta.dirname, '..', '..')
|
||||
|
||||
@@ -21,6 +22,12 @@ export const WINDOWS_PROCESS_TREE_PACKAGE_DIR = join(
|
||||
'windows-process-tree'
|
||||
)
|
||||
|
||||
export const WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS = [
|
||||
'napi.h',
|
||||
'napi-inl.h',
|
||||
'napi-inl.deprecated.h'
|
||||
]
|
||||
|
||||
export function nodeGypRebuildInvocation(arch, packageDir = WINDOWS_PROCESS_TREE_PACKAGE_DIR) {
|
||||
return {
|
||||
args: [
|
||||
@@ -31,3 +38,18 @@ export function nodeGypRebuildInvocation(arch, packageDir = WINDOWS_PROCESS_TREE
|
||||
cwd: realpathSync(packageDir)
|
||||
}
|
||||
}
|
||||
|
||||
// Patched binding.gyp includes deps/node-addon-api; the tarball does not ship those headers.
|
||||
export function stageWindowsProcessTreeNodeAddonApiHeaders(
|
||||
packageDir = WINDOWS_PROCESS_TREE_PACKAGE_DIR
|
||||
) {
|
||||
const nodeAddonApiDir = dirname(
|
||||
createRequire(join(packageDir, 'package.json')).resolve('node-addon-api/package.json')
|
||||
)
|
||||
const stagedHeaderDir = join(packageDir, 'deps', 'node-addon-api')
|
||||
mkdirSync(stagedHeaderDir, { recursive: true })
|
||||
for (const header of WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS) {
|
||||
copyFileSync(join(nodeAddonApiDir, header), join(stagedHeaderDir, header))
|
||||
}
|
||||
return stagedHeaderDir
|
||||
}
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { existsSync, realpathSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import {
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
mkdtempSync,
|
||||
readFileSync,
|
||||
realpathSync,
|
||||
rmSync,
|
||||
writeFileSync
|
||||
} from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
nodeGypRebuildInvocation,
|
||||
stageWindowsProcessTreeNodeAddonApiHeaders,
|
||||
WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS,
|
||||
WINDOWS_PROCESS_TREE_PACKAGE_DIR
|
||||
} from './windows-process-tree-gyp-rebuild.mjs'
|
||||
|
||||
@@ -26,4 +37,25 @@ describe('windows-process-tree node-gyp rebuild', () => {
|
||||
expect(args).toContain('rebuild')
|
||||
expect(args).toContain('--arch=arm64')
|
||||
})
|
||||
|
||||
it('copies node-addon-api headers into the patched include dir', () => {
|
||||
const packageDir = mkdtempSync(join(tmpdir(), 'orca-windows-process-tree-headers-'))
|
||||
try {
|
||||
const nodeAddonApiDir = join(packageDir, 'node_modules', 'node-addon-api')
|
||||
mkdirSync(nodeAddonApiDir, { recursive: true })
|
||||
writeFileSync(join(packageDir, 'package.json'), '{"dependencies":{"node-addon-api":"*"}}\n')
|
||||
writeFileSync(join(nodeAddonApiDir, 'package.json'), '{"name":"node-addon-api"}\n')
|
||||
for (const header of WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS) {
|
||||
writeFileSync(join(nodeAddonApiDir, header), `// ${header}\n`)
|
||||
}
|
||||
|
||||
const stagedDir = stageWindowsProcessTreeNodeAddonApiHeaders(packageDir)
|
||||
expect(stagedDir).toBe(join(packageDir, 'deps', 'node-addon-api'))
|
||||
for (const header of WINDOWS_PROCESS_TREE_NODE_ADDON_API_HEADERS) {
|
||||
expect(readFileSync(join(stagedDir, header), 'utf8')).toBe(`// ${header}\n`)
|
||||
}
|
||||
} finally {
|
||||
rmSync(packageDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user