/
githubmr
/
facebook-react-native
Обзор
Документация
Войти
/
githubmr
/
facebook-react-native
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js
377 строк
12 KB
Sam Zhou
Update prettier-plugin-hermes-parser in fbsource to 0.31.1 (#52996)
02 авг 2025, 06:18
02 авг 2025, 06:18
16fa3d5
Код
Авторство
О чём код?
/** * 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. * * @flow * @format */ /*:: import type {BuildFlavor} from './types'; */ const {computeNightlyTarballURL, createLogger} = require('./utils'); const {execSync} = require('child_process'); const fs = require('fs'); const path = require('path'); const stream = require('stream'); const {promisify} = require('util'); const pipeline = promisify(stream.pipeline); const dependencyLog = createLogger('ReactNativeDependencies'); /** * Downloads ReactNativeDependencies artifacts from the specified version and build type. If you want to specify a specific * version of ReactNativeDependencies, use the RN_DEP_VERSION environment variable. The path to the artifacts will be inside * the packages/react-native/third-party folder. */ async function prepareReactNativeDependenciesArtifactsAsync( version /*:string*/, buildType /*: BuildFlavor */, ) /*: Promise<string> */ { dependencyLog(`Preparing ReactNativeDependencies...`); // Create artifacts folder const artifactsPath /*: string*/ = path.resolve(process.cwd(), 'third-party'); // Ensure that the artifacts folder exists fs.mkdirSync(artifactsPath, {recursive: true}); // Path for keeping track of the current version in the artifacts folder const versionFilePath = path.join(artifactsPath, 'version.txt'); // Resolve the version from the environment variable or use the default version let resolvedVersion = process.env.RN_DEP_VERSION ?? version; if (resolvedVersion === 'nightly') { dependencyLog('Using latest nightly tarball'); const rnVersion = await getNightlyVersionFromNPM(); resolvedVersion = rnVersion; } // Check if the ReactNativeDependencies artifacts are already downloaded if ( checkExistingVersion( versionFilePath, resolvedVersion, buildType, artifactsPath, ) ) { return artifactsPath; } const sourceType = await reactNativeDependenciesSourceType( resolvedVersion, buildType, ); const localPath = await resolveSourceFromSourceType( sourceType, resolvedVersion, buildType, artifactsPath, ); // Extract the tar.gz const tmpPath = '/tmp/react-native-dependencies'; fs.mkdirSync(tmpPath, {recursive: true}); execSync(`tar -xzf "${localPath}" -C "${tmpPath}"`, { stdio: 'inherit', }); const xcframeworkSource = path.join( tmpPath, 'packages', 'react-native', 'third-party', 'ReactNativeDependencies.xcframework', ); // Copy the extracted files to the artifacts folder execSync(`cp -R "${xcframeworkSource}" "${artifactsPath}"`, { stdio: 'inherit', }); // Delete the tarball after extraction if (!process.env.HERMES_ENGINE_TARBALL_PATH) { fs.unlinkSync(localPath); } return artifactsPath; } async function getNightlyVersionFromNPM() /*: Promise<string> */ { const npmResponse /*: Response */ = await fetch( 'https://registry.npmjs.org/react-native/nightly', ); if (!npmResponse.ok) { throw new Error( `Couldn't get an answer from NPM: ${npmResponse.status} ${npmResponse.statusText}`, ); } const json = await npmResponse.json(); const latestNightly = json.version; dependencyLog(`Using version ${latestNightly}`); return latestNightly; } /*:: type ReactNativeDependenciesEngineSourceType = | 'download_prebuild_tarball' | 'download_prebuilt_nightly_tarball' */ const ReactNativeDependenciesEngineSourceTypes /*: { +DOWNLOAD_PREBUILD_TARBALL: "download_prebuild_tarball", +DOWNLOAD_PREBUILT_NIGHTLY_TARBALL: "download_prebuilt_nightly_tarball" } */ = { DOWNLOAD_PREBUILD_TARBALL: 'download_prebuild_tarball', DOWNLOAD_PREBUILT_NIGHTLY_TARBALL: 'download_prebuilt_nightly_tarball', }; /** * Checks if the ReactNativeDependencies artifacts are already downloaded and up to date with the specified version. * Returns true if the artifacts are up to date, false otherwise. */ function checkExistingVersion( versionFilePath /*: string */, version /*: string */, buildType /*: BuildFlavor */, artifactsPath /*: string */, ) { const resolvedVersion = `${version}-${buildType}`; const rndepXCFramework = path.join( artifactsPath, 'ReactNativeDependencies.xcframework', ); if (fs.existsSync(rndepXCFramework)) { if (fs.existsSync(versionFilePath)) { const versionFileContent = fs.readFileSync(versionFilePath, 'utf8'); dependencyLog(`Version found on disk: ${versionFileContent}`); if (versionFileContent.trim() === resolvedVersion) { dependencyLog( `ReactNativeDependencies artifacts already downloaded and up to date: ${artifactsPath}`, ); return true; } } else { dependencyLog( `React Native Dependencies found on disk at: ${artifactsPath}.\nNo version file has been found. We are going to use it anyway, but there might be some unexpected behaviors.`, ); } } else { dependencyLog('React Native Dependencies not found on disk'); } // If the version file does not exist or the version does not match, delete the artifacts folder fs.rmSync(artifactsPath, {recursive: true, force: true}); // Lets create the version.txt file fs.mkdirSync(artifactsPath, {recursive: true}); fs.writeFileSync(versionFilePath, resolvedVersion, 'utf8'); dependencyLog( `ReactNativeDependencies artifacts folder created: ${artifactsPath} with version: ${resolvedVersion}`, ); return false; } function getTarballUrl( version /*: string */, buildType /*: BuildFlavor */, ) /*: string */ { // You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded. // The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central. const mavenRepoUrl = process.env.ENTERPRISE_REPOSITORY ?? 'https://repo1.maven.org/maven2'; const namespace = 'com/facebook/react'; return `${mavenRepoUrl}/${namespace}/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-${buildType.toLowerCase()}.tar.gz`; } async function getNightlyTarballUrl( version /*: string */, buildType /*: BuildFlavor */, ) /*: Promise<string> */ { const coordinate = 'react-native-artifacts'; const artifactName = `reactnative-dependencies-${buildType.toLowerCase()}.tar.gz`; return await computeNightlyTarballURL( version, buildType, coordinate, artifactName, ); } /** * Checks if a ReactNativeDependencies artifact exists at the given URL using fetch instead of curl */ async function reactNativeDependenciesArtifactExists( tarballUrl /*: string */, ) /*: Promise<boolean> */ { try { const response /*: Response */ = await fetch(tarballUrl, { method: 'HEAD', }); return response.status === 200; } catch (e) { return false; } } /** * Determines the source type for ReactNativeDependencies based on availability */ async function reactNativeDependenciesSourceType( version /*: string */, buildType /*: BuildFlavor */, ) /*: Promise<ReactNativeDependenciesEngineSourceType> */ { const tarballUrl = getTarballUrl(version, buildType); if (await reactNativeDependenciesArtifactExists(tarballUrl)) { dependencyLog(`Using download prebuild ${buildType} tarball`); return ReactNativeDependenciesEngineSourceTypes.DOWNLOAD_PREBUILD_TARBALL; } // For nightly tarball, we need to resolve redirects first const nightlyUrl = await getNightlyTarballUrl(version, buildType); if (await reactNativeDependenciesArtifactExists(nightlyUrl)) { dependencyLog('Using download prebuild nightly tarball'); return ReactNativeDependenciesEngineSourceTypes.DOWNLOAD_PREBUILT_NIGHTLY_TARBALL; } dependencyLog( 'Using download prebuild nightly tarball - this is a fallback and might not work.', ); return ReactNativeDependenciesEngineSourceTypes.DOWNLOAD_PREBUILT_NIGHTLY_TARBALL; } async function resolveSourceFromSourceType( sourceType /*: ReactNativeDependenciesEngineSourceType */, version /*: string */, buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise<string> */ { switch (sourceType) { case ReactNativeDependenciesEngineSourceTypes.DOWNLOAD_PREBUILD_TARBALL: return downloadPrebuildTarball(version, buildType, artifactsPath); case ReactNativeDependenciesEngineSourceTypes.DOWNLOAD_PREBUILT_NIGHTLY_TARBALL: return downloadPrebuiltNightlyTarball(version, buildType, artifactsPath); default: abort( `[ReactNativeDependencies] Unsupported or invalid source type provided: ${sourceType}`, ); return ''; } } async function downloadPrebuildTarball( version /*: string */, buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise<string> */ { const url = getTarballUrl(version, buildType); dependencyLog(`Using release tarball from URL: ${url}`); return downloadStableReactNativeDependencies( version, buildType, artifactsPath, ); } async function downloadPrebuiltNightlyTarball( version /*: string */, buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise<string> */ { const url = await getNightlyTarballUrl(version, buildType); dependencyLog(`Using nightly tarball from URL: ${url}`); return downloadReactNativeDependenciesTarball( url, version, buildType, artifactsPath, ); } async function downloadStableReactNativeDependencies( version /*: string */, buildType /*: BuildFlavor */, artifactsPath /*: string */, ) /*: Promise<string> */ { const tarballUrl = getTarballUrl(version, buildType); return downloadReactNativeDependenciesTarball( tarballUrl, version, buildType, artifactsPath, ); } /** * Downloads a ReactNativeDependencies tarball using fetch instead of curl */ async function downloadReactNativeDependenciesTarball( tarballUrl /*: string */, version /*: string */, buildType /*: BuildFlavor */, artifactsPath /*: string */, ) /*: Promise<string> */ { const destPath = buildType ? `${artifactsPath}/reactnative-dependencies-${version}-${buildType}.tar.gz` : `${artifactsPath}/reactnative-dependencies-${version}.tar.gz`; if (!fs.existsSync(destPath)) { const tmpFile = `${artifactsPath}/reactnative-dependencies.download`; try { fs.mkdirSync(artifactsPath, {recursive: true}); dependencyLog( `Downloading ReactNativeDependencies tarball from ${tarballUrl}`, ); const response /*: Response */ = await fetch(tarballUrl); if (!response.ok) { throw new Error( `Failed to download: ${response.status} ${response.statusText}`, ); } // Create a write stream to the temporary file const fileStream = fs.createWriteStream(tmpFile); // Use Node.js stream pipeline to safely pipe the response body to the file if (response.body) { await pipeline(response.body, fileStream); } else { // For older fetch implementations that don't support response.body as a stream const buffer = await response.arrayBuffer(); fs.writeFileSync(tmpFile, Buffer.from(buffer)); } // Move the temporary file to the destination path fs.renameSync(tmpFile, destPath); } catch (e) { // Clean up the temporary file if it exists if (fs.existsSync(tmpFile)) { fs.unlinkSync(tmpFile); } abort( `Failed to download ReactNativeDependencies tarball from ${tarballUrl}: ${e.message}`, ); } } return destPath; } function abort(message /*: string */) { dependencyLog(message, 'error'); throw new Error(message); } module.exports = { prepareReactNativeDependenciesArtifactsAsync, };