mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
e36c492ace
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/35285 While doing the release 0f 0.71.0-RC0, we noticed that having the RN version in the hermes tarball was causing more harm than good. With the version in the name, we ended up with multiple tarballs for debug and release and we were not able to explicitly pick the right tarball given a build. This change remove the version from the tarball name. ## Changelog [General][Changed] - Remove React Native version from Hermes tarball name Reviewed By: lunaleaps Differential Revision: D41156353 fbshipit-source-id: 8899d5e1e1555bc728d923f3b78d1261e6ff09c7
450 lines
14 KiB
JavaScript
450 lines
14 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
import * as path from 'path';
|
|
|
|
const os = require('os');
|
|
|
|
const {
|
|
configureMakeForPrebuiltHermesC,
|
|
copyBuildScripts,
|
|
copyPodSpec,
|
|
createHermesPrebuiltArtifactsTarball,
|
|
createTarballFromDirectory,
|
|
downloadHermesSourceTarball,
|
|
expandHermesSourceTarball,
|
|
getHermesTarballDownloadPath,
|
|
getHermesPrebuiltArtifactsTarballName,
|
|
getHermesTagSHA,
|
|
readHermesTag,
|
|
setHermesTag,
|
|
shouldUsePrebuiltHermesC,
|
|
} = require('../hermes-utils');
|
|
|
|
const hermesTag =
|
|
'hermes-2022-04-28-RNv0.69.0-15d07c2edd29a4ea0b8f15ab0588a0c1adb1200f';
|
|
const tarballContents = 'dummy string';
|
|
const hermescContents = 'dummy string';
|
|
const hermesTagSha = '5244f819b2f3949ca94a3a1bf75d54a8ed59d94a';
|
|
|
|
const ROOT_DIR = path.normalize(path.join(__dirname, '../../..'));
|
|
const SDKS_DIR = path.join(ROOT_DIR, 'sdks');
|
|
|
|
const MemoryFs = require('metro-memory-fs');
|
|
|
|
let execCalls, spawnCalls;
|
|
let fs;
|
|
|
|
jest.mock('child_process', () => ({
|
|
execSync: jest.fn((command, options) => {
|
|
// git is used in getHermesTagSHA to obtain the commit sha for the latest commit to Hermes main
|
|
if (command.startsWith('git')) {
|
|
execCalls.git = true;
|
|
return hermesTagSha + '\n';
|
|
}
|
|
}),
|
|
spawnSync: jest.fn((command, args, options) => {
|
|
// curl is used in downloadHermesSourceTarball to fetch the source code from github.com/facebook/hermes for a specific Hermes commit sha
|
|
if (command === 'curl') {
|
|
const downloadPath = args[2];
|
|
fs.writeFileSync(downloadPath, tarballContents);
|
|
spawnCalls.curl = true;
|
|
return {code: 0};
|
|
}
|
|
|
|
// tar is used in createTarballFromDirectory
|
|
if (command === 'tar') {
|
|
spawnCalls.tar = true;
|
|
|
|
if (args[0] === '-zxf') {
|
|
// We are expanding the tarball
|
|
fs.mkdirSync(path.join(SDKS_DIR, 'hermes/utils'), {
|
|
recursive: true,
|
|
});
|
|
fs.writeFileSync(path.join(SDKS_DIR, 'hermes/package.json'), '{}');
|
|
return {code: 0};
|
|
} else if (args[2] === '-czvf') {
|
|
// We are creating the tarball
|
|
const filename = args[3];
|
|
fs.writeFileSync(filename, tarballContents);
|
|
return {code: 0};
|
|
}
|
|
}
|
|
|
|
// rsync is used in createHermesPrebuiltArtifactsTarball
|
|
if (command === 'rsync') {
|
|
spawnCalls.rsync = true;
|
|
spawnCalls.rsyncArgs = args;
|
|
const destination = args[args.length - 1];
|
|
|
|
// Create destination directory
|
|
fs.mkdirSync(path.join(options.cwd, destination), {
|
|
recursive: true,
|
|
});
|
|
}
|
|
}),
|
|
}));
|
|
|
|
function populateMockFilesystemWithHermesBuildScripts() {
|
|
fs.mkdirSync(path.join(SDKS_DIR, 'hermes-engine/utils'), {
|
|
recursive: true,
|
|
});
|
|
fs.writeFileSync(
|
|
path.join(SDKS_DIR, 'hermes-engine/utils/build-apple-framework.sh'),
|
|
'Dummy file',
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(SDKS_DIR, 'hermes-engine/utils/build-ios-framework.sh'),
|
|
'Dummy file',
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(SDKS_DIR, 'hermes-engine/utils/build-mac-framework.sh'),
|
|
'Dummy file',
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(SDKS_DIR, 'hermes-engine/hermes-engine.podspec'),
|
|
'Dummy file',
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(SDKS_DIR, 'hermes-engine/hermes-utils.rb'),
|
|
'Dummy file',
|
|
);
|
|
}
|
|
|
|
function populateMockFilesystemWithHermesBuildArtifacts() {
|
|
fs.mkdirSync(os.tmpdir(), {recursive: true});
|
|
const frameworksDir = path.join(
|
|
SDKS_DIR,
|
|
'hermes/destroot/Library/Frameworks',
|
|
);
|
|
fs.mkdirSync(path.join(frameworksDir, 'macosx/hermes.framework'), {
|
|
recursive: true,
|
|
});
|
|
fs.mkdirSync(path.join(frameworksDir, 'universal/hermes.xcframework'), {
|
|
recursive: true,
|
|
});
|
|
|
|
const dsymsDirs = [
|
|
'macosx',
|
|
'universal/hermes.xcframework/ios-arm64/dSYMs',
|
|
'universal/hermes.xcframework/ios-arm64_x86_64-simulator/dSYMs',
|
|
'universal/hermes.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs',
|
|
];
|
|
|
|
for (const dsymsDir of dsymsDirs) {
|
|
fs.mkdirSync(path.join(frameworksDir, dsymsDir, 'hermes.framework.dSYM'), {
|
|
recursive: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
describe('hermes-utils', () => {
|
|
beforeEach(() => {
|
|
jest.resetModules();
|
|
|
|
jest.mock(
|
|
'fs',
|
|
() =>
|
|
new MemoryFs({
|
|
platform: process.platform === 'win32' ? 'win32' : 'posix',
|
|
}),
|
|
);
|
|
fs = require('fs');
|
|
fs.reset();
|
|
|
|
populateMockFilesystemWithHermesBuildScripts();
|
|
|
|
execCalls = Object.create(null);
|
|
spawnCalls = Object.create(null);
|
|
});
|
|
|
|
describe('Versioning Hermes', () => {
|
|
describe('readHermesTag', () => {
|
|
it('should return main if .hermesversion does not exist', () => {
|
|
expect(readHermesTag()).toEqual('main');
|
|
});
|
|
it('should fail if hermes tag is empty', () => {
|
|
fs.writeFileSync(path.join(SDKS_DIR, '.hermesversion'), '');
|
|
expect(() => {
|
|
readHermesTag();
|
|
}).toThrow('[Hermes] .hermesversion file is empty.');
|
|
});
|
|
it('should return tag from .hermesversion if file exists', () => {
|
|
fs.writeFileSync(path.join(SDKS_DIR, '.hermesversion'), hermesTag);
|
|
expect(readHermesTag()).toEqual(hermesTag);
|
|
});
|
|
});
|
|
|
|
describe('setHermesTag', () => {
|
|
it('should write tag to .hermesversion file', () => {
|
|
setHermesTag(hermesTag);
|
|
expect(
|
|
fs.readFileSync(path.join(SDKS_DIR, '.hermesversion'), {
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
}),
|
|
).toEqual(hermesTag);
|
|
});
|
|
it('should set Hermes tag and read it back', () => {
|
|
setHermesTag(hermesTag);
|
|
expect(readHermesTag()).toEqual(hermesTag);
|
|
});
|
|
});
|
|
|
|
describe('getHermesTagSHA', () => {
|
|
it('should return trimmed commit SHA for Hermes tag', () => {
|
|
expect(getHermesTagSHA(hermesTag)).toEqual(hermesTagSha);
|
|
expect(execCalls.git).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Downloading Hermes', () => {
|
|
describe('getHermesTarballDownloadPath', () => {
|
|
it('returns download path with Hermes tag sha', () => {
|
|
const hermesTarballDownloadPath =
|
|
getHermesTarballDownloadPath(hermesTag);
|
|
expect(hermesTarballDownloadPath).toEqual(
|
|
path.join(
|
|
SDKS_DIR,
|
|
'download',
|
|
`hermes-${getHermesTagSHA(hermesTag)}.tgz`,
|
|
),
|
|
);
|
|
});
|
|
});
|
|
describe('downloadHermesSourceTarball', () => {
|
|
it('should download Hermes source tarball to download dir', () => {
|
|
fs.writeFileSync(path.join(SDKS_DIR, '.hermesversion'), hermesTag);
|
|
const hermesTarballDownloadPath =
|
|
getHermesTarballDownloadPath(hermesTag);
|
|
downloadHermesSourceTarball();
|
|
expect(spawnCalls.curl).toBe(true);
|
|
expect(
|
|
fs.readFileSync(hermesTarballDownloadPath, {
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
}),
|
|
).toEqual(tarballContents);
|
|
});
|
|
it('should not re-download Hermes source tarball if tarball exists', () => {
|
|
fs.mkdirSync(path.join(SDKS_DIR, 'download'), {recursive: true});
|
|
fs.writeFileSync(
|
|
path.join(SDKS_DIR, 'download', `hermes-${hermesTagSha}.tgz`),
|
|
tarballContents,
|
|
);
|
|
|
|
downloadHermesSourceTarball();
|
|
expect(spawnCalls.curl).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('expandHermesSourceTarball', () => {
|
|
it('should expand Hermes source tarball to Hermes source dir', () => {
|
|
fs.mkdirSync(path.join(SDKS_DIR, 'download'), {recursive: true});
|
|
fs.writeFileSync(
|
|
path.join(SDKS_DIR, 'download', `hermes-${hermesTagSha}.tgz`),
|
|
tarballContents,
|
|
);
|
|
expect(fs.existsSync(path.join(SDKS_DIR, 'hermes'))).toBeFalsy();
|
|
expandHermesSourceTarball();
|
|
expect(fs.existsSync(path.join(SDKS_DIR, 'hermes'))).toBe(true);
|
|
});
|
|
it('should fail if Hermes source tarball does not exist', () => {
|
|
expect(() => {
|
|
expandHermesSourceTarball();
|
|
}).toThrow('[Hermes] Could not locate Hermes tarball.');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Configuring Hermes Build', () => {
|
|
describe('copyBuildScripts', () => {
|
|
it('should copy React Native Hermes build scripts to Hermes source directory', () => {
|
|
copyBuildScripts();
|
|
|
|
[
|
|
'build-apple-framework.sh',
|
|
'build-ios-framework.sh',
|
|
'build-mac-framework.sh',
|
|
].forEach(buildScript => {
|
|
expect(
|
|
fs.readFileSync(
|
|
path.join(ROOT_DIR, 'sdks/hermes/utils', buildScript),
|
|
{
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
},
|
|
),
|
|
).toEqual(
|
|
fs.readFileSync(
|
|
path.join(ROOT_DIR, 'sdks/hermes-engine/utils', buildScript),
|
|
{
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
},
|
|
),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
describe('copyPodSpec', () => {
|
|
it('should copy React Native Hermes Podspec to Hermes source directory', () => {
|
|
copyPodSpec();
|
|
expect(
|
|
fs.readFileSync(path.join(SDKS_DIR, 'hermes/hermes-engine.podspec'), {
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
}),
|
|
).toEqual(
|
|
fs.readFileSync(
|
|
path.join(SDKS_DIR, 'hermes-engine/hermes-engine.podspec'),
|
|
{
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
},
|
|
),
|
|
);
|
|
});
|
|
it('should copy hermes-utils.rb to Hermes source directory', () => {
|
|
copyPodSpec();
|
|
expect(
|
|
fs.readFileSync(path.join(SDKS_DIR, 'hermes/hermes-utils.rb'), {
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
}),
|
|
).toEqual(
|
|
fs.readFileSync(
|
|
path.join(SDKS_DIR, 'hermes-engine/hermes-utils.rb'),
|
|
{
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
},
|
|
),
|
|
);
|
|
});
|
|
});
|
|
describe('shouldUsePrebuiltHermesC', () => {
|
|
it('returns false if path to osx hermesc does not exist', () => {
|
|
expect(shouldUsePrebuiltHermesC('macos')).toBeFalsy();
|
|
});
|
|
it('returns false for non-macOS', () => {
|
|
expect(shouldUsePrebuiltHermesC('windows')).toBeFalsy();
|
|
});
|
|
it('return true only if path to hermesc exists', () => {
|
|
fs.mkdirSync(path.join(SDKS_DIR, 'hermesc/osx-bin'), {
|
|
recursive: true,
|
|
});
|
|
fs.writeFileSync(
|
|
path.join(SDKS_DIR, 'hermesc/osx-bin/hermesc'),
|
|
hermescContents,
|
|
);
|
|
expect(shouldUsePrebuiltHermesC('macos')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('configureMakeForPrebuiltHermesC', () => {
|
|
it('creates ImportHermesC file', () => {
|
|
fs.mkdirSync(path.join(SDKS_DIR, 'hermesc/osx-bin'), {
|
|
recursive: true,
|
|
});
|
|
configureMakeForPrebuiltHermesC();
|
|
expect(
|
|
fs.existsSync(
|
|
path.join(SDKS_DIR, 'hermesc/osx-bin/ImportHermesc.cmake'),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Packaging Hermes', () => {
|
|
beforeEach(() => {
|
|
populateMockFilesystemWithHermesBuildArtifacts();
|
|
});
|
|
|
|
describe('createTarballFromDirectory', () => {
|
|
it('should create the tarball', () => {
|
|
fs.mkdirSync(path.join(SDKS_DIR, 'downloads'), {recursive: true});
|
|
const tarballFilename = path.join(
|
|
SDKS_DIR,
|
|
'downloads/hermes-runtime-darwin.tar.gz',
|
|
);
|
|
createTarballFromDirectory(
|
|
path.join(SDKS_DIR, 'hermes/destroot'),
|
|
tarballFilename,
|
|
);
|
|
expect(spawnCalls.tar).toBe(true);
|
|
expect(fs.existsSync(tarballFilename)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('getHermesPrebuiltArtifactsTarballName', () => {
|
|
it('should return Hermes prebuilts tarball name', () => {
|
|
expect(getHermesPrebuiltArtifactsTarballName('Debug')).toEqual(
|
|
'hermes-ios-debug.tar.gz',
|
|
);
|
|
});
|
|
it('should throw if build type is undefined', () => {
|
|
expect(() => {
|
|
getHermesPrebuiltArtifactsTarballName();
|
|
}).toThrow('Did not specify build type.');
|
|
});
|
|
});
|
|
|
|
describe('createHermesPrebuiltArtifactsTarball', () => {
|
|
it('creates tarball', () => {
|
|
const tarballOutputDir = fs.mkdtempSync(
|
|
path.join(os.tmpdir(), 'hermes-prebuilts-'),
|
|
);
|
|
fs.mkdirSync(tarballOutputDir, {
|
|
recursive: true,
|
|
});
|
|
|
|
const excludeDebugSymbols = false;
|
|
const tarballOutputPath = createHermesPrebuiltArtifactsTarball(
|
|
path.join(SDKS_DIR, 'hermes'),
|
|
'Debug',
|
|
tarballOutputDir,
|
|
excludeDebugSymbols,
|
|
);
|
|
expect(fs.existsSync(tarballOutputPath)).toBe(true);
|
|
expect(spawnCalls.rsync).toBe(true);
|
|
// rsync -a src dest
|
|
expect(spawnCalls.rsyncArgs.length).toEqual(3);
|
|
});
|
|
|
|
it('creates tarball with debug symbols excluded', () => {
|
|
const tarballOutputDir = fs.mkdtempSync(
|
|
path.join(os.tmpdir(), 'hermes-prebuilts-'),
|
|
);
|
|
fs.mkdirSync(tarballOutputDir, {
|
|
recursive: true,
|
|
});
|
|
|
|
const excludeDebugSymbols = true;
|
|
const tarballOutputPath = createHermesPrebuiltArtifactsTarball(
|
|
path.join(SDKS_DIR, 'hermes'),
|
|
'Debug',
|
|
tarballOutputDir,
|
|
excludeDebugSymbols,
|
|
);
|
|
expect(fs.existsSync(tarballOutputPath)).toBe(true);
|
|
expect(spawnCalls.rsync).toBe(true);
|
|
|
|
// When the debug symbols are excluded, we pass an additional two parameters to rsync:
|
|
// rsync -a --exclude=dSYMs/ --exclude=*.dSYM/ src dest
|
|
expect(spawnCalls.rsyncArgs.length).toEqual(5);
|
|
expect(spawnCalls.rsyncArgs[1]).toEqual('--exclude=dSYMs/');
|
|
expect(spawnCalls.rsyncArgs[2]).toEqual('--exclude=*.dSYM/');
|
|
});
|
|
});
|
|
});
|
|
});
|