fix: Skip lipo if native module is already universal. Add native module fixtures for lipo tests (#126)
* fix: when native modules are already universal, don't lipo. adds `node-mac-permissions` fixture from https://github.com/codebytere/node-mac-permissions and resolves 3 `it.todo` test cases * add test `different app dirs with different macho files (shim and lipo)` * add additional test * PR feedback * gotta close `fd` * use `stream` to read first 4 bytes. copy native fixture before packing into asar to leverage `unpack: "**/*.node"` properly. * convert params to object * rename `createTestApp` to `createStagingAppDir` and add jsdoc to the function * compiler error from merge conflict * update snapshots * update snapshots * only check x64Content since it's the tmp app * compile macho binaries at runtime using hellow-world.c for fixtures in lipo tests * Update jest.setup.ts Co-authored-by: Erik Moura <erikian@erikian.dev> * Update jest.setup.ts Co-authored-by: Erik Moura <erikian@erikian.dev> * remove unstable properties for specific keys * force redo * update snapshots * stripping only hello-world from snapshot and only hash from macho-specific asar integrity * optimize logic :) --------- Co-authored-by: Erik Moura <erikian@erikian.dev>
This commit is contained in:
@@ -148,14 +148,13 @@ export const mergeASARs = async ({
|
||||
const x64Content = asar.extractFile(x64AsarPath, file);
|
||||
const arm64Content = asar.extractFile(arm64AsarPath, file);
|
||||
|
||||
// Skip file if the same content
|
||||
if (x64Content.compare(arm64Content) === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
MACHO_UNIVERSAL_MAGIC.has(x64Content.readUInt32LE(0)) &&
|
||||
MACHO_UNIVERSAL_MAGIC.has(arm64Content.readUInt32LE(0))
|
||||
) {
|
||||
// Skip universal Mach-O files.
|
||||
if (isUniversalMachO(x64Content)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -223,3 +222,7 @@ export const mergeASARs = async ({
|
||||
await Promise.all([fs.remove(x64Dir), fs.remove(arm64Dir)]);
|
||||
}
|
||||
};
|
||||
|
||||
export const isUniversalMachO = (fileContent: Buffer) => {
|
||||
return MACHO_UNIVERSAL_MAGIC.has(fileContent.readUInt32LE(0));
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { spawn, ExitCodeError } from '@malept/cross-spawn-promise';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { promises as stream } from 'node:stream';
|
||||
|
||||
const MACHO_PREFIX = 'Mach-O ';
|
||||
|
||||
@@ -71,3 +72,14 @@ export const getAllAppFiles = async (appPath: string): Promise<AppFile[]> => {
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
export const readMachOHeader = async (path: string) => {
|
||||
const chunks: Buffer[] = [];
|
||||
// no need to read the entire file, we only need the first 4 bytes of the file to determine the header
|
||||
await stream.pipeline(fs.createReadStream(path, { start: 0, end: 3 }), async function* (source) {
|
||||
for await (const chunk of source) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
});
|
||||
return Buffer.concat(chunks);
|
||||
};
|
||||
|
||||
17
src/index.ts
17
src/index.ts
@@ -1,14 +1,14 @@
|
||||
import { spawn } from '@malept/cross-spawn-promise';
|
||||
import * as asar from '@electron/asar';
|
||||
import { spawn } from '@malept/cross-spawn-promise';
|
||||
import * as dircompare from 'dir-compare';
|
||||
import * as fs from 'fs-extra';
|
||||
import { minimatch } from 'minimatch';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as plist from 'plist';
|
||||
import * as dircompare from 'dir-compare';
|
||||
|
||||
import { AppFile, AppFileType, getAllAppFiles } from './file-utils';
|
||||
import { AsarMode, detectAsarMode, mergeASARs } from './asar-utils';
|
||||
import { AsarMode, detectAsarMode, isUniversalMachO, mergeASARs } from './asar-utils';
|
||||
import { AppFile, AppFileType, getAllAppFiles, readMachOHeader } from './file-utils';
|
||||
import { sha } from './sha';
|
||||
import { d } from './debug';
|
||||
import { computeIntegrityData } from './integrity';
|
||||
@@ -162,6 +162,15 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
|
||||
const first = await fs.realpath(path.resolve(tmpApp, machOFile.relativePath));
|
||||
const second = await fs.realpath(path.resolve(opts.arm64AppPath, machOFile.relativePath));
|
||||
|
||||
if (
|
||||
isUniversalMachO(await readMachOHeader(first)) &&
|
||||
isUniversalMachO(await readMachOHeader(second))
|
||||
) {
|
||||
d(machOFile.relativePath, `is already universal across builds, skipping lipo`);
|
||||
knownMergedMachOFiles.add(machOFile.relativePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
const x64Sha = await sha(path.resolve(opts.x64AppPath, machOFile.relativePath));
|
||||
const arm64Sha = await sha(path.resolve(opts.arm64AppPath, machOFile.relativePath));
|
||||
if (x64Sha === arm64Sha) {
|
||||
|
||||
Reference in New Issue
Block a user