fix(packaging): prune non-target native binaries (#12174)
This commit is contained in:
parent
e08eba674c
commit
128e3e335e
|
|
@ -44,6 +44,14 @@ const PARCEL_WATCHER_PLATFORM_PREFIX_BY_PLATFORM = {
|
|||
linux: 'watcher-linux',
|
||||
win32: 'watcher-win32'
|
||||
}
|
||||
const ELECTRON_ARCHITECTURE_BY_ENUM = {
|
||||
0: 'ia32',
|
||||
1: 'x64',
|
||||
2: 'arm',
|
||||
3: 'arm64',
|
||||
4: 'universal'
|
||||
}
|
||||
const PACKAGED_NATIVE_ARCHITECTURES = new Set(['ia32', 'x64', 'arm', 'arm64'])
|
||||
const TYPE_DECLARATION_ARTIFACT_RE = /\.d\.(?:c|m)?ts(?:\.map)?$/
|
||||
const VERSIONED_ONNXRUNTIME_DYLIB_RE = /^libonnxruntime\.\d[\d.]*\.dylib$/
|
||||
|
||||
|
|
@ -170,7 +178,7 @@ function collectPackagedRuntimePackages(electronPlatformName = process.platform)
|
|||
// optionalDependency (e.g. @parcel/watcher-linux-x64-glibc) that the
|
||||
// dependencies graph above never reaches. Include the ones installed for the
|
||||
// build's supported architectures; afterPack pruning trims non-target
|
||||
// platforms. Without this the packaged main bundle's import of
|
||||
// platform/architecture variants. Without this the packaged main bundle's import of
|
||||
// '@parcel/watcher' resolves at runtime but throws loading its binary.
|
||||
const parcelWatcherDir = packages.get('@parcel/watcher')
|
||||
if (parcelWatcherDir) {
|
||||
|
|
@ -246,13 +254,44 @@ function verifyPackagedMainRuntimeDeps(resourcesDir, asar = require('@electron/a
|
|||
}
|
||||
|
||||
function normalizeNodePtyWindowsArch(electronArch) {
|
||||
if (electronArch === 'x64' || electronArch === 1) {
|
||||
return 'x64'
|
||||
const architecture = normalizeElectronArchitecture(electronArch)
|
||||
if (architecture !== 'x64' && architecture !== 'arm64') {
|
||||
throw new Error(`Unsupported packaged node-pty Windows architecture: ${architecture}`)
|
||||
}
|
||||
if (electronArch === 'arm64' || electronArch === 3) {
|
||||
return 'arm64'
|
||||
return architecture
|
||||
}
|
||||
|
||||
function normalizeElectronArchitecture(electronArch) {
|
||||
const architecture =
|
||||
typeof electronArch === 'number'
|
||||
? ELECTRON_ARCHITECTURE_BY_ENUM[electronArch]
|
||||
: electronArch === 'armv7l'
|
||||
? 'arm'
|
||||
: electronArch
|
||||
if (!PACKAGED_NATIVE_ARCHITECTURES.has(architecture)) {
|
||||
throw new Error(`Unsupported packaged runtime architecture: ${String(electronArch)}`)
|
||||
}
|
||||
return architecture
|
||||
}
|
||||
|
||||
function pruneNodePtyNativeDirectories(directory, platformPrefix, electronArch, allowsSuffix) {
|
||||
if (!existsSync(directory)) {
|
||||
return
|
||||
}
|
||||
const architecture = normalizeElectronArchitecture(electronArch)
|
||||
const targetPrefix = `${platformPrefix}${architecture}`
|
||||
const platformPrefixes = Object.values(NODE_PTY_PREBUILD_PREFIX_BY_PLATFORM)
|
||||
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
||||
if (!entry.isDirectory() || !platformPrefixes.some((prefix) => entry.name.startsWith(prefix))) {
|
||||
continue
|
||||
}
|
||||
const matchesTarget =
|
||||
entry.name.startsWith(platformPrefix) &&
|
||||
(entry.name === targetPrefix || (allowsSuffix && entry.name.startsWith(`${targetPrefix}-`)))
|
||||
if (!matchesTarget) {
|
||||
rmSync(join(directory, entry.name), { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
return process.arch === 'arm64' ? 'arm64' : 'x64'
|
||||
}
|
||||
|
||||
function findNodePtyConptySourceDir(nodePtyDir, windowsArch) {
|
||||
|
|
@ -308,14 +347,19 @@ function prunePackagedNodePty(resourcesDir, electronPlatformName, electronArch)
|
|||
|
||||
const allowedPrebuildPrefix = NODE_PTY_PREBUILD_PREFIX_BY_PLATFORM[electronPlatformName]
|
||||
if (allowedPrebuildPrefix) {
|
||||
const prebuildsDir = join(nodePtyDir, 'prebuilds')
|
||||
if (existsSync(prebuildsDir)) {
|
||||
for (const entry of readdirSync(prebuildsDir, { withFileTypes: true })) {
|
||||
if (entry.isDirectory() && !entry.name.startsWith(allowedPrebuildPrefix)) {
|
||||
rmSync(join(prebuildsDir, entry.name), { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
pruneNodePtyNativeDirectories(
|
||||
join(nodePtyDir, 'prebuilds'),
|
||||
allowedPrebuildPrefix,
|
||||
electronArch,
|
||||
false
|
||||
)
|
||||
// Why: sequential cross-arch rebuilds accumulate ABI-tagged outputs here.
|
||||
pruneNodePtyNativeDirectories(
|
||||
join(nodePtyDir, 'bin'),
|
||||
allowedPrebuildPrefix,
|
||||
electronArch,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
if (electronPlatformName === 'win32') {
|
||||
|
|
@ -328,7 +372,7 @@ function prunePackagedNodePty(resourcesDir, electronPlatformName, electronArch)
|
|||
}
|
||||
}
|
||||
|
||||
function prunePackagedParcelWatcher(resourcesDir, electronPlatformName) {
|
||||
function prunePackagedParcelWatcher(resourcesDir, electronPlatformName, electronArch) {
|
||||
const parcelDir = join(resourcesDir, 'node_modules', '@parcel')
|
||||
if (!existsSync(parcelDir)) {
|
||||
return
|
||||
|
|
@ -336,9 +380,11 @@ function prunePackagedParcelWatcher(resourcesDir, electronPlatformName) {
|
|||
|
||||
// Why: we package every installed @parcel/watcher-<platform> optional
|
||||
// subpackage (supportedArchitectures fetches all), but each build only needs
|
||||
// its own platform's binary. Keep the core package and the matching platform
|
||||
// subpackages; drop the rest so a Linux serve doesn't ship macOS/Windows .node.
|
||||
// its own platform/architecture binaries. Keep the core package and matching
|
||||
// native variants; drop the rest.
|
||||
const keepPrefix = PARCEL_WATCHER_PLATFORM_PREFIX_BY_PLATFORM[electronPlatformName]
|
||||
const architecture = normalizeElectronArchitecture(electronArch)
|
||||
const targetPrefix = keepPrefix ? `${keepPrefix}-${architecture}` : null
|
||||
for (const entry of readdirSync(parcelDir, { withFileTypes: true })) {
|
||||
if (!entry.isDirectory() || entry.name === 'watcher') {
|
||||
continue
|
||||
|
|
@ -348,7 +394,11 @@ function prunePackagedParcelWatcher(resourcesDir, electronPlatformName) {
|
|||
if (!entry.name.startsWith('watcher-')) {
|
||||
continue
|
||||
}
|
||||
if (keepPrefix && entry.name.startsWith(keepPrefix)) {
|
||||
if (
|
||||
keepPrefix &&
|
||||
entry.name.startsWith(keepPrefix) &&
|
||||
(entry.name === targetPrefix || entry.name.startsWith(`${targetPrefix}-`))
|
||||
) {
|
||||
continue
|
||||
}
|
||||
rmSync(join(parcelDir, entry.name), { recursive: true, force: true })
|
||||
|
|
@ -395,8 +445,9 @@ function prunePackagedZodSources(resourcesDir) {
|
|||
}
|
||||
|
||||
function prunePackagedRuntimeNodeModules(resourcesDir, electronPlatformName, electronArch) {
|
||||
prunePackagedNodePty(resourcesDir, electronPlatformName, electronArch)
|
||||
prunePackagedParcelWatcher(resourcesDir, electronPlatformName)
|
||||
const architecture = normalizeElectronArchitecture(electronArch)
|
||||
prunePackagedNodePty(resourcesDir, electronPlatformName, architecture)
|
||||
prunePackagedParcelWatcher(resourcesDir, electronPlatformName, architecture)
|
||||
prunePackagedRuntimeTypeDeclarations(resourcesDir)
|
||||
prunePackagedSherpaOnnx(resourcesDir, electronPlatformName)
|
||||
prunePackagedZodSources(resourcesDir)
|
||||
|
|
|
|||
|
|
@ -420,40 +420,42 @@ describe('electron-builder config', () => {
|
|||
expect(findAsarEntry(['/out/main/index.js'], 'out/main/index.js')).toBe('/out/main/index.js')
|
||||
})
|
||||
|
||||
it('prunes non-target node-pty prebuilds from packaged runtime resources', async () => {
|
||||
it('prunes non-target node-pty architecture outputs from packaged runtime resources', async () => {
|
||||
const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-node-pty-prune-'))
|
||||
try {
|
||||
const prebuildsDir = join(resourcesDir, 'node_modules', 'node-pty', 'prebuilds')
|
||||
const nodePtyDir = join(resourcesDir, 'node_modules', 'node-pty')
|
||||
const prebuildsDir = join(nodePtyDir, 'prebuilds')
|
||||
const binDir = join(nodePtyDir, 'bin')
|
||||
await mkdir(join(prebuildsDir, 'darwin-arm64'), { recursive: true })
|
||||
await mkdir(join(prebuildsDir, 'darwin-x64'), { recursive: true })
|
||||
await mkdir(join(prebuildsDir, 'linux-x64'), { recursive: true })
|
||||
await mkdir(join(prebuildsDir, 'win32-x64'), { recursive: true })
|
||||
await mkdir(join(resourcesDir, 'node_modules', 'node-pty', 'third_party', 'conpty'), {
|
||||
recursive: true
|
||||
})
|
||||
await mkdir(join(resourcesDir, 'node_modules', 'node-pty', 'deps', 'winpty'), {
|
||||
await mkdir(join(binDir, 'darwin-arm64-148'), { recursive: true })
|
||||
await mkdir(join(binDir, 'darwin-x64-148'), { recursive: true })
|
||||
await mkdir(join(nodePtyDir, 'third_party', 'conpty'), {
|
||||
recursive: true
|
||||
})
|
||||
await mkdir(join(nodePtyDir, 'deps', 'winpty'), { recursive: true })
|
||||
|
||||
prunePackagedNodePty(resourcesDir, 'darwin')
|
||||
prunePackagedNodePty(resourcesDir, 'darwin', 3)
|
||||
|
||||
await expect(readdir(prebuildsDir).then((entries) => entries.sort())).resolves.toEqual([
|
||||
'darwin-arm64',
|
||||
'darwin-x64'
|
||||
])
|
||||
await expect(
|
||||
readdir(join(resourcesDir, 'node_modules', 'node-pty', 'third_party'))
|
||||
).resolves.toEqual([])
|
||||
await expect(
|
||||
readdir(join(resourcesDir, 'node_modules', 'node-pty', 'deps'))
|
||||
).resolves.toEqual([])
|
||||
await expect(readdir(prebuildsDir)).resolves.toEqual(['darwin-arm64'])
|
||||
await expect(readdir(binDir)).resolves.toEqual(['darwin-arm64-148'])
|
||||
await expect(readdir(join(nodePtyDir, 'third_party'))).resolves.toEqual([])
|
||||
await expect(readdir(join(nodePtyDir, 'deps'))).resolves.toEqual([])
|
||||
expect(() => prunePackagedNodePty(resourcesDir, 'darwin', 4)).toThrow(
|
||||
'Unsupported packaged runtime architecture: 4'
|
||||
)
|
||||
} finally {
|
||||
await rm(resourcesDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('copies the Windows node-pty ConPTY runtime beside the rebuilt addon', async () => {
|
||||
for (const arch of ['x64', 'arm64']) {
|
||||
for (const [arch, electronArch] of [
|
||||
['x64', 1],
|
||||
['arm64', 3]
|
||||
]) {
|
||||
const resourcesDir = await mkdtemp(join(tmpdir(), `orca-node-pty-conpty-${arch}-`))
|
||||
try {
|
||||
const nodePtyDir = join(resourcesDir, 'node_modules', 'node-pty')
|
||||
|
|
@ -472,7 +474,7 @@ describe('electron-builder config', () => {
|
|||
)
|
||||
}
|
||||
|
||||
prunePackagedNodePty(resourcesDir, 'win32', arch)
|
||||
prunePackagedNodePty(resourcesDir, 'win32', electronArch)
|
||||
|
||||
await expect(readFile(join(releaseDir, 'conpty', 'conpty.dll'), 'utf8')).resolves.toBe(
|
||||
`dll payload ${arch}`
|
||||
|
|
@ -500,7 +502,7 @@ describe('electron-builder config', () => {
|
|||
).toBe(true)
|
||||
})
|
||||
|
||||
it('prunes non-target @parcel/watcher platform subpackages from packaged runtime resources', async () => {
|
||||
it('prunes non-target @parcel/watcher architecture subpackages', async () => {
|
||||
const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-parcel-watcher-prune-'))
|
||||
try {
|
||||
const parcelDir = join(resourcesDir, 'node_modules', '@parcel')
|
||||
|
|
@ -511,13 +513,15 @@ describe('electron-builder config', () => {
|
|||
await mkdir(join(parcelDir, 'watcher-linux-arm64-glibc'), { recursive: true })
|
||||
await mkdir(join(parcelDir, 'watcher-win32-x64'), { recursive: true })
|
||||
|
||||
prunePackagedParcelWatcher(resourcesDir, 'linux')
|
||||
prunePackagedParcelWatcher(resourcesDir, 'linux', 'arm64')
|
||||
|
||||
await expect(readdir(parcelDir).then((entries) => entries.sort())).resolves.toEqual([
|
||||
'watcher',
|
||||
'watcher-linux-arm64-glibc',
|
||||
'watcher-linux-x64-glibc'
|
||||
'watcher-linux-arm64-glibc'
|
||||
])
|
||||
expect(() => prunePackagedParcelWatcher(resourcesDir, 'linux', 'universal')).toThrow(
|
||||
'Unsupported packaged runtime architecture: universal'
|
||||
)
|
||||
} finally {
|
||||
await rm(resourcesDir, { recursive: true, force: true })
|
||||
}
|
||||
|
|
@ -533,7 +537,7 @@ describe('electron-builder config', () => {
|
|||
// A hypothetical future @parcel/* runtime dep that is NOT a watcher subpackage.
|
||||
await mkdir(join(parcelDir, 'transformer-js'), { recursive: true })
|
||||
|
||||
prunePackagedParcelWatcher(resourcesDir, 'linux')
|
||||
prunePackagedParcelWatcher(resourcesDir, 'linux', 1)
|
||||
|
||||
await expect(readdir(parcelDir).then((entries) => entries.sort())).resolves.toEqual([
|
||||
'transformer-js',
|
||||
|
|
@ -653,7 +657,8 @@ describe('electron-builder config', () => {
|
|||
|
||||
await electronBuilderConfig.afterPack({
|
||||
appOutDir: join(root, 'linux-unpacked'),
|
||||
electronPlatformName: 'linux'
|
||||
electronPlatformName: 'linux',
|
||||
arch: 1
|
||||
})
|
||||
|
||||
expect((await stat(launcherPath)).mode & 0o111).not.toBe(0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue