From 46d541f7b32aa76286179e09fa73c8217ec76a21 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Thu, 5 Oct 2023 07:40:50 -0700 Subject: [PATCH] Remove flags to turn on/off the new architecture (#39780) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/39780 This diff removes flags and setups from the files to turn on and off the new architecture. The script is meant to run only on pre-alpha builds. ## Changelog: [Internal] - Add script to remove prealpha flags Reviewed By: cortinico Differential Revision: D49376471 fbshipit-source-id: 754bf6f9d5b94da77111798200bbaaa3347fb678 --- .../remove-new-arch-flags-fixture.js | 92 ++++++++++++ .../__tests__/remove-new-arch-flags-test.js | 135 ++++++++++++++++++ scripts/releases/remove-new-arch-flags.js | 108 ++++++++++++++ 3 files changed, 335 insertions(+) create mode 100644 scripts/releases/__tests__/__fixtures__/remove-new-arch-flags-fixture.js create mode 100644 scripts/releases/__tests__/remove-new-arch-flags-test.js create mode 100644 scripts/releases/remove-new-arch-flags.js diff --git a/scripts/releases/__tests__/__fixtures__/remove-new-arch-flags-fixture.js b/scripts/releases/__tests__/__fixtures__/remove-new-arch-flags-fixture.js new file mode 100644 index 0000000000..f04486b05e --- /dev/null +++ b/scripts/releases/__tests__/__fixtures__/remove-new-arch-flags-fixture.js @@ -0,0 +1,92 @@ +/** + * 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 + * @oncall react-native + */ + +const validReactNativePodsFile = ` +def use_react_native! ( + path: "../node_modules/react-native", + fabric_enabled: false, + new_arch_enabled: NewArchitectureHelper.new_arch_enabled, + production: false, # deprecated + hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true, + flipper_configuration: FlipperConfiguration.disabled, + app_path: '..', + config_file_dir: '', + ios_folder: 'ios' +) +end +`; + +const invalidReactNativePodsFile = ` +def use_react_native! ( + path: "../node_modules/react-native", + fabric_enabled: false, + production: false, # deprecated + hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true, + flipper_configuration: FlipperConfiguration.disabled, + app_path: '..', + config_file_dir: '', + ios_folder: 'ios' +) +end +`; + +const expectedReactNativePodsFile = ` +def use_react_native! ( + path: "../node_modules/react-native", + production: false, # deprecated + hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true, + flipper_configuration: FlipperConfiguration.disabled, + app_path: '..', + config_file_dir: '', + ios_folder: 'ios' +) +end +`; + +const validGradlePropertiesFile = ` +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=false + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true +`; + +const invalidGradlePropertiesFile = ` +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true +`; + +const expectedGradlePropertiesFile = ` +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=true + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true +`; + +module.exports = { + validReactNativePodsFile, + invalidReactNativePodsFile, + expectedReactNativePodsFile, + validGradlePropertiesFile, + invalidGradlePropertiesFile, + expectedGradlePropertiesFile, +}; diff --git a/scripts/releases/__tests__/remove-new-arch-flags-test.js b/scripts/releases/__tests__/remove-new-arch-flags-test.js new file mode 100644 index 0000000000..39b2d21342 --- /dev/null +++ b/scripts/releases/__tests__/remove-new-arch-flags-test.js @@ -0,0 +1,135 @@ +/** + * 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 + * @oncall react-native + */ + +const fs = require('fs'); +const path = require('path'); +const removeNewArchFlags = require('../remove-new-arch-flags'); +const { + validReactNativePodsFile, + invalidReactNativePodsFile, + expectedReactNativePodsFile, + validGradlePropertiesFile, + invalidGradlePropertiesFile, + expectedGradlePropertiesFile, +} = require('./__fixtures__/remove-new-arch-flags-fixture'); + +describe('removeNewArchFlags', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + it('throws an exception if not run from react-native-github', async () => { + jest.spyOn(process, 'cwd').mockReturnValue('/path/to/react-native'); + expect(removeNewArchFlags).toThrow(); + }); + + it('it updates the required files', async () => { + const cwd = '/path/to/react-native-github'; + const reactNativePodsPath = + '/packages/react-native/scripts/react_native_pods.rb'; + const templateGradlePropertiesPath = + '/packages/react-native/template/android/gradle.properties'; + jest.spyOn(process, 'cwd').mockReturnValue(cwd); + jest.spyOn(fs, 'readFileSync').mockImplementation(filename => { + if (filename === path.join(cwd, reactNativePodsPath)) { + return validReactNativePodsFile; + } else if (filename === path.join(cwd, templateGradlePropertiesPath)) { + return validGradlePropertiesFile; + } else { + throw new Error(`Unexpected call to fs.readFileSync(${filename}).`); + } + }); + let returnedReactNativePodsBackup = ''; + let returnedReactNativePods = ''; + let returnedGradlePropertiesBackup = ''; + let returnedGradleProperties = ''; + jest.spyOn(fs, 'writeFileSync').mockImplementation((filename, content) => { + if (filename === path.join(cwd, `${reactNativePodsPath}.bak`)) { + returnedReactNativePodsBackup = content; + } else if (filename === path.join(cwd, reactNativePodsPath)) { + returnedReactNativePods = content; + } else if ( + filename === path.join(cwd, `${templateGradlePropertiesPath}.bak`) + ) { + returnedGradlePropertiesBackup = content; + } else if (filename === path.join(cwd, templateGradlePropertiesPath)) { + returnedGradleProperties = content; + } else { + throw new Error(`Unexpected call to fs.writeFileSync(${filename}).`); + } + }); + + let deletedFiles = []; + jest.spyOn(fs, 'unlinkSync').mockImplementation(filename => { + deletedFiles.push(filename); + }); + removeNewArchFlags(); + + expect(returnedReactNativePodsBackup).toEqual(validReactNativePodsFile); + expect(returnedReactNativePods).toEqual(expectedReactNativePodsFile); + expect(returnedGradlePropertiesBackup).toEqual(validGradlePropertiesFile); + expect(returnedGradleProperties).toEqual(expectedGradlePropertiesFile); + expect(deletedFiles).toEqual([ + path.join(cwd, `${reactNativePodsPath}.bak`), + path.join(cwd, `${templateGradlePropertiesPath}.bak`), + ]); + }); + + it('does not update the required files if they are not valid', async () => { + const cwd = '/path/to/react-native-github'; + const reactNativePodsPath = + '/packages/react-native/scripts/react_native_pods.rb'; + const templateGradlePropertiesPath = + '/packages/react-native/template/android/gradle.properties'; + jest.spyOn(process, 'cwd').mockReturnValue(cwd); + jest.spyOn(fs, 'readFileSync').mockImplementation(filename => { + if (filename === path.join(cwd, reactNativePodsPath)) { + return invalidReactNativePodsFile; + } else if (filename === path.join(cwd, templateGradlePropertiesPath)) { + return invalidGradlePropertiesFile; + } else { + throw new Error(`Unexpected call to fs.readFileSync(${filename}).`); + } + }); + let returnedReactNativePodsBackup = ''; + let returnedReactNativePods = ''; + let returnedGradlePropertiesBackup = ''; + let returnedGradleProperties = ''; + jest.spyOn(fs, 'writeFileSync').mockImplementation((filename, content) => { + if (filename === path.join(cwd, `${reactNativePodsPath}.bak`)) { + returnedReactNativePodsBackup = content; + } else if (filename === path.join(cwd, reactNativePodsPath)) { + returnedReactNativePods = content; + } else if ( + filename === path.join(cwd, `${templateGradlePropertiesPath}.bak`) + ) { + returnedGradlePropertiesBackup = content; + } else if (filename === path.join(cwd, templateGradlePropertiesPath)) { + returnedGradleProperties = content; + } else { + throw new Error(`Unexpected call to fs.writeFileSync(${filename}).`); + } + }); + + let deletedFiles = []; + jest.spyOn(fs, 'unlinkSync').mockImplementation(filename => { + deletedFiles.push(filename); + }); + removeNewArchFlags(); + + expect(returnedReactNativePodsBackup).toEqual(invalidReactNativePodsFile); + expect(returnedReactNativePods).toEqual(invalidReactNativePodsFile); + expect(returnedGradlePropertiesBackup).toEqual(invalidGradlePropertiesFile); + expect(returnedGradleProperties).toEqual(invalidGradlePropertiesFile); + expect(deletedFiles).toEqual([ + path.join(cwd, `${reactNativePodsPath}.bak`), + path.join(cwd, `${templateGradlePropertiesPath}.bak`), + ]); + }); +}); diff --git a/scripts/releases/remove-new-arch-flags.js b/scripts/releases/remove-new-arch-flags.js new file mode 100644 index 0000000000..a6ffa38e6b --- /dev/null +++ b/scripts/releases/remove-new-arch-flags.js @@ -0,0 +1,108 @@ +/** + * 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 + * @oncall react-native + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +function removeNewArchFlags() { + console.log('Removing new arch flags'); + const cwd = getValidCwd(); + + const iosBackups = removeFlagsForiOS(cwd); + + const androidBackups = flipNewArchFlagForAndroid(cwd); + + iosBackups.concat(androidBackups).forEach(file => { + fs.unlinkSync(file); + }); +} + +// === Helpers === +function getValidCwd() /*: string*/ { + const cwd = process.cwd(); + + if (!cwd.endsWith('react-native-github')) { + throw new Error( + `Please call this script from react-native root folder. Current path: ${cwd}`, + ); + } + return cwd; +} + +function replaceContentsOfFile( + contentToBeReplaced /*: string | RegExp*/, + replacement /*: string*/, + filepath /*: string*/, +) /*: string*/ { + const content = fs.readFileSync(filepath, 'utf8'); + + const backupPath = `${filepath}.bak`; + fs.writeFileSync(backupPath, content, 'utf8'); + let newContent = content.replaceAll(contentToBeReplaced, replacement); + fs.writeFileSync(filepath, newContent, 'utf8'); + return backupPath; +} + +function removeContentsFromFile( + contentToBeRemoved /*: string | RegExp*/, + filepath /*: string*/, +) /*: string*/ { + return replaceContentsOfFile(contentToBeRemoved, '', filepath); +} + +function removeFlagsForiOS(cwd /*: string*/) /*: $ReadOnlyArray*/ { + let backupPath /*: Array*/ = []; + const iosPath = path.join( + cwd, + '/packages/react-native/scripts/react_native_pods.rb', + ); + backupPath.push( + removeContentsFromFile( + / {2}fabric_enabled: false,\n {2}new_arch_enabled: NewArchitectureHelper.new_arch_enabled,\n/g, + iosPath, + ), + ); + return backupPath; +} + +function newArchEnabledGradleProps(boolValue /*: boolean*/) /*: string */ { + return `newArchEnabled=${boolValue.toString()}`; +} + +function flipNewArchFlagForAndroid( + cwd /*: string */, +) /*: $ReadOnlyArray*/ { + let backupPath /*: Array */ = []; + + // Gradle.properties + const gradlePropertiesPath = path.join( + cwd, + '/packages/react-native/template/android/gradle.properties', + ); + backupPath.push( + replaceContentsOfFile( + new RegExp(newArchEnabledGradleProps(false), 'g'), + newArchEnabledGradleProps(true), + gradlePropertiesPath, + ), + ); + + return backupPath; +} +// =============== + +module.exports = removeNewArchFlags; + +if (require.main === module) { + removeNewArchFlags(); +}