fix(build): turn off MSBuild file tracking for Windows native rebuilds

Default Windows native rebuilds to TrackFileAccess=false while preserving explicit caller preferences.

Co-authored-by: B1nh M1nh <43268322+b1nhm1nh@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Neil <neil@stably.ai>
This commit is contained in:
B1nh M1nh
2026-10-03 00:51:35 -07:00
committed by GitHub
co-authored by Claude Opus 5.5 Neil
parent 7b8498b406
commit 126f7096a3
7 changed files with 115 additions and 8 deletions
+2 -1
View File
@@ -13,6 +13,7 @@ import {
windowsProcessTreeAddonPath
} from './windows-process-tree-gyp-rebuild.mjs'
import { describeProcessFailure, runProcessSync } from './script-child-process.mjs'
import { disableMsbuildFileTrackingOnWindows } from './msbuild-file-tracking.mjs'
const require = createRequire(import.meta.url)
const { assertNodePtyJobOwnership, nodePtyAddonPath } = require('./node-pty-job-ownership.cjs')
@@ -420,7 +421,7 @@ function runNodeGyp({ args, cwd }) {
const env =
process.platform === 'linux'
? { ...process.env, CXXFLAGS: `${process.env.CXXFLAGS ?? ''} -std=gnu++2a`.trim() }
: process.env
: disableMsbuildFileTrackingOnWindows({ ...process.env })
const result = runProcessSync({
program: process.execPath,
args,
+20 -5
View File
@@ -60,6 +60,7 @@ describe('ensure-native-runtime', () => {
expect(result.stderr).toContain('node-gyp stderr complete\n')
const log = readFileSync(logPath, 'utf8')
expect(log).toContain(`node-gyp rebuild --arch=${process.arch}\n`)
expect(log).toContain(`trackFileAccess=${process.platform === 'win32' ? 'false' : ''}\n`)
expect(log).toContain(join('node_modules', 'node-pty'))
if (process.platform === 'linux') {
expect(log).toMatch(/^cxxflags=(?:.*\s)?-std=gnu\+\+2a$/m)
@@ -73,9 +74,14 @@ describe('ensure-native-runtime', () => {
}
})
it.skipIf(process.platform !== 'win32')(
'rebuilds other failed Windows addons with patched node-pty',
() => {
it.skipIf(process.platform !== 'win32').each([
{ trackingEnv: {}, tracking: 'false' },
{ trackingEnv: { TrackFileAccess: 'true' }, tracking: 'true' },
{ trackingEnv: { trackfileaccess: 'true' }, tracking: 'true' },
{ trackingEnv: { tRaCkFiLeAcCeSs: 'false' }, tracking: 'false' }
])(
'rebuilds other failed Windows addons with patched node-pty and tracking=$tracking',
({ trackingEnv, tracking }) => {
const projectDir = mkTempProject()
try {
@@ -90,6 +96,7 @@ describe('ensure-native-runtime', () => {
cwd: projectDir,
encoding: 'utf8',
env: envForNativeFixture(projectDir, {
...trackingEnv,
ORCA_NATIVE_TEST_LOG: logPath,
ORCA_NATIVE_TEST_MARKER: markerPath
})
@@ -100,6 +107,9 @@ describe('ensure-native-runtime', () => {
expect(
log.split('\n').filter((line) => line === `node-gyp rebuild --arch=${process.arch}`)
).toHaveLength(2)
expect(
log.split('\n').filter((line) => line === `trackFileAccess=${tracking}`)
).toHaveLength(2)
expect(log).toContain(join('node_modules', 'node-pty'))
expect(log).toContain(join('node_modules', '@orca', 'windows-registry'))
} finally {
@@ -277,8 +287,12 @@ function mkTempProject() {
}
function envForNativeFixture(projectDir, extraEnv) {
// An inherited tracking preference would mask the Windows default under test.
const inherited = Object.fromEntries(
Object.entries(process.env).filter(([key]) => key.toLowerCase() !== 'trackfileaccess')
)
return {
...process.env,
...inherited,
...extraEnv,
npm_config_node_gyp: join(projectDir, 'node_modules', 'node-gyp', 'bin', 'node-gyp.js')
}
@@ -323,7 +337,7 @@ exports.loadNativeModule = function loadNativeModule(nativeName) {
writeFakeWindowsRegistry(projectDir, { requiresMarker: windowsRegistryRequiresMarker })
if (process.platform === 'win32') {
const buildDir = join(nodePtyDir, 'build', 'Release')
mkdirSync(buildDir, { recursive: true })
writePatchedNodePtyBuildArtifacts(projectDir)
writeFileSync(join(buildDir, 'conpty.node'), Buffer.from('msys-2.0.dll', 'utf16le'))
}
}
@@ -419,6 +433,7 @@ const { appendFileSync, writeFileSync, writeSync } = require('node:fs')
appendFileSync(process.env.ORCA_NATIVE_TEST_LOG, \`node-gyp \${process.argv.slice(2).join(' ')}\\n\`)
appendFileSync(process.env.ORCA_NATIVE_TEST_LOG, \`cwd=\${process.cwd()}\\n\`)
appendFileSync(process.env.ORCA_NATIVE_TEST_LOG, \`cxxflags=\${process.env.CXXFLAGS || ''}\\n\`)
appendFileSync(process.env.ORCA_NATIVE_TEST_LOG, \`trackFileAccess=\${process.env.TrackFileAccess ?? ''}\\n\`)
if (process.env.ORCA_NATIVE_TEST_VERBOSE_OUTPUT_BYTES) {
const output = Buffer.alloc(Number(process.env.ORCA_NATIVE_TEST_VERBOSE_OUTPUT_BYTES), 'x')
for (let offset = 0; offset < output.length;) {
+14
View File
@@ -0,0 +1,14 @@
// FileTracker's long-path-unsafe .tlog files serve incremental builds; these rebuilds are forced.
export function disableMsbuildFileTrackingOnWindows(
env = process.env,
platform = process.platform
) {
// Windows environment keys are case-insensitive, including caller overrides in copied objects.
if (
platform === 'win32' &&
!Object.keys(env).some((key) => key.toLowerCase() === 'trackfileaccess')
) {
env.TrackFileAccess = 'false'
}
return env
}
@@ -0,0 +1,28 @@
import { describe, expect, it } from 'vitest'
import { disableMsbuildFileTrackingOnWindows } from './msbuild-file-tracking.mjs'
describe('disableMsbuildFileTrackingOnWindows', () => {
it('turns tracking off on Windows when the caller left it unset', () => {
expect(disableMsbuildFileTrackingOnWindows({ PATH: 'x' }, 'win32')).toEqual({
PATH: 'x',
TrackFileAccess: 'false'
})
})
it.each(['TrackFileAccess', 'trackfileaccess', 'TRACKFILEACCESS', 'tRaCkFiLeAcCeSs'])(
'preserves explicit %s values without adding a duplicate key',
(key) => {
for (const value of ['true', 'false', '']) {
const env = { [key]: value }
expect(disableMsbuildFileTrackingOnWindows(env, 'win32')).toBe(env)
expect(env).toEqual({ [key]: value })
}
}
)
it.each(['linux', 'darwin'])('leaves %s hosts alone', (platform) => {
const env = { PATH: 'x' }
expect(disableMsbuildFileTrackingOnWindows(env, platform)).toBe(env)
expect(env).toEqual({ PATH: 'x' })
})
})
@@ -22,6 +22,51 @@ import {
} from './rebuild-native-deps-test-fixtures.mjs'
describe('rebuild-native-deps patched node-pty rebuild', () => {
it.skipIf(process.platform !== 'win32')(
'passes the Windows tracking default and explicit overrides to forced Electron rebuilds',
() => {
const projectDir = mkTempProject()
try {
const rebuildLogPath = join(projectDir, 'electron-rebuild.log')
writeFakeUsableElectronPackage(projectDir, { platform: 'win32' })
writeFakeElectronRebuild(projectDir, { logPathEnv: 'ORCA_REBUILD_TEST_LOG' })
writeFakeLoadableNodePty(projectDir)
writeFakeWindowsProcessTree(projectDir)
writeFakeNodePtyConptyPayload(projectDir, process.arch)
const env = {
ORCA_REBUILD_TEST_LOG: rebuildLogPath,
npm_config_platform: 'win32',
npm_config_arch: process.arch
}
for (const override of [
{},
{ TrackFileAccess: 'true' },
{ trackfileaccess: 'true' },
{ tRaCkFiLeAcCeSs: 'false' }
]) {
const result = runRebuildScript(projectDir, { ...env, ...override })
expect(result.status, result.stderr).toBe(0)
}
const calls = readFileSync(rebuildLogPath, 'utf8')
.trim()
.split('\n')
.map((line) => JSON.parse(line))
expect(calls.map((call) => call.trackFileAccess)).toEqual([
'false',
'true',
'true',
'false'
])
expect(calls.every((call) => call.force)).toBe(true)
} finally {
removeTreeSync(projectDir)
}
}
)
it.skipIf(process.platform !== 'win32')(
'repairs a missing ConPTY runtime before probing without recompiling node-pty',
() => {
@@ -110,7 +110,7 @@ export function writeWindowsProcessTreePatchFile(projectDir) {
export function mkTempProject() {
const projectDir = mkdtempSync(join(tmpdir(), 'orca-rebuild-native-deps-'))
mkdirSync(join(projectDir, 'config', 'scripts'), { recursive: true })
copyFileSync(sourceScriptPath, join(projectDir, 'config', 'scripts', 'rebuild-native-deps.mjs'))
copyScriptWithLocalModules(sourceScriptPath, join(projectDir, 'config', 'scripts'))
copyScriptWithLocalModules(sourceInstallScriptPath, join(projectDir, 'config', 'scripts'))
copyScriptWithLocalModules(sourceNodePtyJobOwnershipPath, join(projectDir, 'config', 'scripts'))
copyFileSync(
@@ -134,7 +134,8 @@ export function runRebuildScript(projectDir, extraEnv = {}, args = []) {
for (const key of Object.keys(env)) {
if (
key.toLowerCase() === 'orca_strict_electron_install' ||
key.toLowerCase() === 'npm_lifecycle_event'
key.toLowerCase() === 'npm_lifecycle_event' ||
key.toLowerCase() === 'trackfileaccess'
) {
delete env[key]
}
@@ -286,6 +287,7 @@ export async function rebuild(options) {${emitAddon}
electronVersion: options.electronVersion,
force: options.force,
ignoreModules: options.ignoreModules,
trackFileAccess: process.env.TrackFileAccess ?? null,
onlyModules: options.onlyModules,
platform: options.platform
}) + '\\n'
+2
View File
@@ -26,6 +26,7 @@ import {
stageWindowsProcessTreeNodeAddonApiHeaders,
windowsProcessTreeAddonPath
} from './windows-process-tree-gyp-rebuild.mjs'
import { disableMsbuildFileTrackingOnWindows } from './msbuild-file-tracking.mjs'
import {
copyFileSync,
existsSync,
@@ -162,6 +163,7 @@ try {
console.warn('[rebuild] Repaired the un-applied windows-process-tree command-line patch.')
}
}
disableMsbuildFileTrackingOnWindows()
await rebuild({
buildPath: projectDir,
electronVersion,