mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Gradle: extend the algoritm to find hermesc paths.
Summary: This diff extends the Gradle algo used to search for `hermesc`. Currently we look into `node_modules/hermes-engine/%OS-BIN%/hermesc` With this change the algo will look into: - A user provided path to hermesc - Built from source version of hermesc (for users of New Architecture) - Bundled version of hermesc inside react-native - hermesc from the hermes-engine NPM package I've added tests for the new algo. I also realized our tests were broken (since they stopped running on CI), I fixed them as well. Changelog: [Android] [Changed] - Gradle: extend the algoritm to find hermesc paths Reviewed By: ShikaSD Differential Revision: D35649911 fbshipit-source-id: d4bcbe06a6bfa8d98b91c1612fc28b300de91661
This commit is contained in:
committed by
Facebook GitHub Bot
parent
8ac8439e0d
commit
aeac6ab677
+5
-3
@@ -141,9 +141,11 @@ abstract class ReactExtension @Inject constructor(project: Project) {
|
||||
|
||||
/** Hermes Config */
|
||||
|
||||
/** The command to use to invoke hermes. Default is `hermesc` for the correct OS. */
|
||||
val hermesCommand: Property<String> =
|
||||
objects.property(String::class.java).convention("node_modules/hermes-engine/%OS-BIN%/hermesc")
|
||||
/**
|
||||
* The command to use to invoke hermesc (the hermes compiler). Default is "", the plugin will
|
||||
* autodetect it.
|
||||
*/
|
||||
val hermesCommand: Property<String> = objects.property(String::class.java).convention("")
|
||||
|
||||
/** Toggle Hermes for the whole build. Default: false */
|
||||
val enableHermes: Property<Boolean> = objects.property(Boolean::class.java).convention(false)
|
||||
|
||||
@@ -12,6 +12,14 @@ object Os {
|
||||
fun isWindows(): Boolean =
|
||||
System.getProperty("os.name")?.lowercase()?.contains("windows") ?: false
|
||||
|
||||
fun isMac(): Boolean = System.getProperty("os.name")?.lowercase()?.contains("mac") ?: false
|
||||
|
||||
fun isLinuxAmd64(): Boolean {
|
||||
val osNameMatch = System.getProperty("os.name")?.lowercase()?.contains("linux") ?: false
|
||||
val archMatch = System.getProperty("os.arch")?.lowercase()?.contains("amd64") ?: false
|
||||
return osNameMatch && archMatch
|
||||
}
|
||||
|
||||
fun String.unixifyPath() =
|
||||
this.replace('\\', '/').replace(":", "").let {
|
||||
if (!it.startsWith("/")) {
|
||||
|
||||
+51
-16
@@ -11,7 +11,6 @@ package com.facebook.react.utils
|
||||
|
||||
import com.facebook.react.ReactExtension
|
||||
import java.io.File
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
/**
|
||||
* Computes the entry file for React Native. The Algo follows this order:
|
||||
@@ -44,13 +43,16 @@ internal fun detectedCliPath(
|
||||
|
||||
/**
|
||||
* Computes the `hermesc` command location. The Algo follows this order:
|
||||
* 1. The path provided by the `hermesCommand` config in the `reactApp` Gradle extension
|
||||
* 2. The file located in `node_modules/hermes-engine/%OS-BIN%/hermesc` where `%OS-BIN%` is
|
||||
* substituted with the correct OS arch.
|
||||
* 3. Fails otherwise
|
||||
* 1. The path provided by the `hermesCommand` config in the `react` Gradle extension
|
||||
* 2. The file located in `node_modules/react-native/sdks/hermes/build/bin/hermesc`. This will be
|
||||
* used if the user is building Hermes from source.
|
||||
* 3. The file located in `node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc` where `%OS-BIN%`
|
||||
* is substituted with the correct OS arch. This will be used if the user is using a precompiled
|
||||
* hermes-engine package.
|
||||
* 4. Fails otherwise
|
||||
*/
|
||||
internal fun detectedHermesCommand(config: ReactExtension): String =
|
||||
detectOSAwareHermesCommand(config.hermesCommand.get())
|
||||
detectOSAwareHermesCommand(config.root.get().asFile, config.hermesCommand.get())
|
||||
|
||||
private fun detectEntryFile(entryFile: File?, reactRoot: File): File =
|
||||
when {
|
||||
@@ -112,20 +114,48 @@ private fun detectCliPath(
|
||||
|
||||
// Make sure not to inspect the Hermes config unless we need it,
|
||||
// to avoid breaking any JSC-only setups.
|
||||
private fun detectOSAwareHermesCommand(hermesCommand: String): String {
|
||||
// If the project specifies a Hermes command, don't second guess it.
|
||||
if (!hermesCommand.contains("%OS-BIN%")) {
|
||||
return hermesCommand
|
||||
internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String): String {
|
||||
// 1. If the project specifies a Hermes command, don't second guess it.
|
||||
if (hermesCommand.isNotBlank()) {
|
||||
val osSpecificHermesCommand =
|
||||
if ("%OS-BIN%" in hermesCommand) {
|
||||
hermesCommand.replace("%OS-BIN%", getHermesOSBin())
|
||||
} else {
|
||||
hermesCommand
|
||||
}
|
||||
return osSpecificHermesCommand
|
||||
// Execution on Windows fails with / as separator
|
||||
.replace('/', File.separatorChar)
|
||||
}
|
||||
|
||||
// Execution on Windows fails with / as separator
|
||||
return hermesCommand.replace("%OS-BIN%", getHermesOSBin()).replace('/', File.separatorChar)
|
||||
// 2. If the project is building hermes-engine from source, use hermesc from there
|
||||
val builtHermesc = File(projectRoot, HERMESC_BUILT_FROM_SOURCE_PATH)
|
||||
if (builtHermesc.exists()) {
|
||||
return builtHermesc.absolutePath
|
||||
}
|
||||
|
||||
// 3. If the react-native contains a pre-built hermesc, use it.
|
||||
val prebuiltHermesPath =
|
||||
HERMESC_IN_REACT_NATIVE_PATH
|
||||
.replace("%OS-BIN%", getHermesOSBin())
|
||||
// Execution on Windows fails with / as separator
|
||||
.replace('/', File.separatorChar)
|
||||
|
||||
val prebuiltHermes = File(projectRoot, prebuiltHermesPath)
|
||||
if (prebuiltHermes.exists()) {
|
||||
return prebuiltHermes.absolutePath
|
||||
}
|
||||
|
||||
error(
|
||||
"Couldn't determine Hermesc location. " +
|
||||
"Please set `react.hermesCommand` to the path of the hermesc binary file. " +
|
||||
"node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc")
|
||||
}
|
||||
|
||||
private fun getHermesOSBin(): String {
|
||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) return "win64-bin"
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) return "osx-bin"
|
||||
if (Os.isOs(null, "linux", "amd64", null)) return "linux64-bin"
|
||||
internal fun getHermesOSBin(): String {
|
||||
if (Os.isWindows()) return "win64-bin"
|
||||
if (Os.isMac()) return "osx-bin"
|
||||
if (Os.isLinuxAmd64()) return "linux64-bin"
|
||||
error(
|
||||
"OS not recognized. Please set project.react.hermesCommand " +
|
||||
"to the path of a working Hermes compiler.")
|
||||
@@ -136,3 +166,8 @@ internal fun projectPathToLibraryName(projectPath: String): String =
|
||||
.split(':', '-', '_', '.')
|
||||
.joinToString("") { token -> token.replaceFirstChar { it.uppercase() } }
|
||||
.plus("Spec")
|
||||
|
||||
private const val HERMESC_IN_REACT_NATIVE_PATH =
|
||||
"node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
private const val HERMESC_BUILT_FROM_SOURCE_PATH =
|
||||
"node_modules/react-native/sdks/hermes/build/bin/hermesc"
|
||||
|
||||
-1
@@ -97,7 +97,6 @@ class GenerateCodegenArtifactsTaskTest {
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
"yarn",
|
||||
"--verbose",
|
||||
File(reactNativeDir, "scripts/generate-specs-cli.js").toString(),
|
||||
"--platform",
|
||||
|
||||
-1
@@ -105,7 +105,6 @@ class GenerateCodegenSchemaTaskTest {
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
"yarn",
|
||||
"--verbose",
|
||||
File(codegenDir, "lib/cli/combine/combine-js-to-schema-cli.js").toString(),
|
||||
File(outputDir, "schema.json").toString(),
|
||||
|
||||
+8
-2
@@ -21,20 +21,26 @@ class OsTest {
|
||||
|
||||
@Test
|
||||
@WithOs(OS.UNIX)
|
||||
fun isWindows_onUnix_returnsFalse() {
|
||||
fun onUnix_checksOsCorrectly() {
|
||||
assertFalse(Os.isWindows())
|
||||
assertFalse(Os.isMac())
|
||||
assertFalse(Os.isLinuxAmd64())
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.MAC)
|
||||
fun isWindows_onMac_returnsTrue() {
|
||||
fun onMac_checksOsCorrectly() {
|
||||
assertFalse(Os.isWindows())
|
||||
assertTrue(Os.isMac())
|
||||
assertFalse(Os.isLinuxAmd64())
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.WIN)
|
||||
fun isWindows_onWindows_returnsTrue() {
|
||||
assertTrue(Os.isWindows())
|
||||
assertFalse(Os.isMac())
|
||||
assertFalse(Os.isLinuxAmd64())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+61
-8
@@ -8,6 +8,9 @@
|
||||
package com.facebook.react.utils
|
||||
|
||||
import com.facebook.react.TestReactExtension
|
||||
import com.facebook.react.tests.OS
|
||||
import com.facebook.react.tests.OsRule
|
||||
import com.facebook.react.tests.WithOs
|
||||
import java.io.File
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.junit.Assert.*
|
||||
@@ -18,6 +21,7 @@ import org.junit.rules.TemporaryFolder
|
||||
class PathUtilsTest {
|
||||
|
||||
@get:Rule val tempFolder = TemporaryFolder()
|
||||
@get:Rule val osRule = OsRule()
|
||||
|
||||
@Test
|
||||
fun detectedEntryFile_withProvidedVariable() {
|
||||
@@ -60,7 +64,7 @@ class PathUtilsTest {
|
||||
parentFile.mkdirs()
|
||||
writeText("<!-- nothing to see here -->")
|
||||
}
|
||||
extension.cliPath.set(project.projectDir + "/abs/fake-cli.sh")
|
||||
extension.cliPath.set(project.projectDir.toString() + "/abs/fake-cli.sh")
|
||||
|
||||
val actual = detectedCliPath(project.projectDir, extension)
|
||||
|
||||
@@ -77,7 +81,7 @@ class PathUtilsTest {
|
||||
writeText("<!-- nothing to see here -->")
|
||||
}
|
||||
extension.cliPath.set("fake-cli.sh")
|
||||
extension.reactRoot.set(project.projectDir + "/react-root")
|
||||
extension.root.set(File(project.projectDir.toString(), "react-root"))
|
||||
|
||||
val actual = detectedCliPath(project.projectDir, extension)
|
||||
|
||||
@@ -104,6 +108,7 @@ class PathUtilsTest {
|
||||
fun detectedCliPath_withCliPathFromExtensionInParentFolder() {
|
||||
val rootProject = ProjectBuilder.builder().build()
|
||||
val project = ProjectBuilder.builder().withParent(rootProject).build()
|
||||
project.projectDir.mkdirs()
|
||||
val extension = TestReactExtension(project)
|
||||
val expected = File(rootProject.projectDir, "cli-in-root.sh").apply { writeText("#!/bin/bash") }
|
||||
extension.cliPath.set("../cli-in-root.sh")
|
||||
@@ -148,15 +153,11 @@ class PathUtilsTest {
|
||||
assertEquals(expected.toString(), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectedHermesCommand_withOSSpecificBin() {
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun detectedHermesCommand_failsIfNotFound() {
|
||||
val extension = TestReactExtension(ProjectBuilder.builder().build())
|
||||
|
||||
val actual = detectedHermesCommand(extension)
|
||||
|
||||
assertTrue(actual.startsWith("node_modules/hermes-engine/"))
|
||||
assertTrue(actual.endsWith("hermesc"))
|
||||
assertFalse(actual.contains("%OS-BIN%"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -178,4 +179,56 @@ class PathUtilsTest {
|
||||
fun projectPathToLibraryName_withDotsAndUnderscores() {
|
||||
assertEquals("SampleAndroidAppSpec", projectPathToLibraryName("sample_android.app"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectOSAwareHermesCommand_withProvidedCommand() {
|
||||
assertEquals(
|
||||
"./my-home/hermes", detectOSAwareHermesCommand(tempFolder.root, "./my-home/hermes"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun detectOSAwareHermesCommand_withHermescBuiltLocally() {
|
||||
tempFolder.newFolder("node_modules/react-native/sdks/hermes/build/bin/")
|
||||
val expected = tempFolder.newFile("node_modules/react-native/sdks/hermes/build/bin/hermesc")
|
||||
|
||||
assertEquals(expected.toString(), detectOSAwareHermesCommand(tempFolder.root, ""))
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.MAC)
|
||||
fun detectOSAwareHermesCommand_withBundledHermescInsideRN() {
|
||||
tempFolder.newFolder("node_modules/react-native/sdks/hermesc/osx-bin/")
|
||||
val expected = tempFolder.newFile("node_modules/react-native/sdks/hermesc/osx-bin/hermesc")
|
||||
|
||||
assertEquals(expected.toString(), detectOSAwareHermesCommand(tempFolder.root, ""))
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
@WithOs(OS.MAC)
|
||||
fun detectOSAwareHermesCommand_failsIfNotFound() {
|
||||
detectOSAwareHermesCommand(tempFolder.root, "")
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.MAC)
|
||||
fun detectOSAwareHermesCommand_withProvidedCommand_takesPrecedence() {
|
||||
tempFolder.newFolder("node_modules/react-native/sdks/hermes/build/bin/")
|
||||
tempFolder.newFile("node_modules/react-native/sdks/hermes/build/bin/hermesc")
|
||||
tempFolder.newFolder("node_modules/react-native/sdks/hermesc/osx-bin/")
|
||||
tempFolder.newFile("node_modules/react-native/sdks/hermesc/osx-bin/hermesc")
|
||||
|
||||
assertEquals(
|
||||
"./my-home/hermes", detectOSAwareHermesCommand(tempFolder.root, "./my-home/hermes"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.MAC)
|
||||
fun detectOSAwareHermesCommand_withoutProvidedCommand_builtHermescTakesPrecedence() {
|
||||
tempFolder.newFolder("node_modules/react-native/sdks/hermes/build/bin/")
|
||||
val expected = tempFolder.newFile("node_modules/react-native/sdks/hermes/build/bin/hermesc")
|
||||
tempFolder.newFolder("node_modules/react-native/sdks/hermesc/osx-bin/")
|
||||
tempFolder.newFile("node_modules/react-native/sdks/hermesc/osx-bin/hermesc")
|
||||
|
||||
assertEquals(expected.toString(), detectOSAwareHermesCommand(tempFolder.root, ""))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ react {
|
||||
root = rootDir
|
||||
inputExcludes = ["android/**", "./**", ".gradle/**"]
|
||||
composeSourceMapsPath = "$rootDir/scripts/compose-source-maps.js"
|
||||
hermesCommand = "$rootDir/node_modules/hermes-engine/%OS-BIN%/hermesc"
|
||||
hermesCommand = "$rootDir/sdks/hermes/build/bin/hermesc"
|
||||
enableHermesForVariant { def v -> v.name.contains("hermes") }
|
||||
|
||||
// Codegen Configs
|
||||
|
||||
+29
-8
@@ -30,7 +30,7 @@ def reactRoot = file(config.root ?: "../../")
|
||||
def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
|
||||
def bundleConfig = config.bundleConfig ? "${reactRoot}/${config.bundleConfig}" : null ;
|
||||
def enableVmCleanup = config.enableVmCleanup == null ? true : config.enableVmCleanup
|
||||
def hermesCommand = config.hermesCommand ?: "../../node_modules/hermes-engine/%OS-BIN%/hermesc"
|
||||
def hermesCommand = config.hermesCommand
|
||||
|
||||
/**
|
||||
* Detects CLI location in a similar fashion to the React Native CLI
|
||||
@@ -90,15 +90,36 @@ def getHermesOSBin() {
|
||||
// Make sure not to inspect the Hermes config unless we need it,
|
||||
// to avoid breaking any JSC-only setups.
|
||||
def getHermesCommand = {
|
||||
// If the project specifies a Hermes command, don't second guess it.
|
||||
if (!hermesCommand.contains("%OS-BIN%")) {
|
||||
return hermesCommand
|
||||
// 1. If the project specifies a Hermes command, don't second guess it.
|
||||
if (config.hermesCommand?.trim()) {
|
||||
if (hermesCommand.contains("%OS-BIN%")) {
|
||||
return hermesCommand
|
||||
.replaceAll("%OS-BIN%", getHermesOSBin())
|
||||
.replace('/' as char, File.separatorChar)
|
||||
} else {
|
||||
return hermesCommand
|
||||
.replace('/' as char, File.separatorChar)
|
||||
}
|
||||
}
|
||||
|
||||
// Execution on Windows fails with / as separator
|
||||
return hermesCommand
|
||||
.replaceAll("%OS-BIN%", getHermesOSBin())
|
||||
.replace('/' as char, File.separatorChar);
|
||||
// 2. If the project is building hermes-engine from source, use hermesc from there
|
||||
def builtHermesc = new File(reactRoot, "node_modules/react-native/sdks/hermes/build/bin/hermesc")
|
||||
if (builtHermesc.exists()) {
|
||||
return builtHermesc.getAbsolutePath()
|
||||
}
|
||||
|
||||
// 3. If the react-native contains a pre-built hermesc, use it.
|
||||
def prebuiltHermesPath = "node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
.replaceAll("%OS-BIN%", getHermesOSBin())
|
||||
.replace('/' as char, File.separatorChar);
|
||||
def prebuiltHermes = new File(reactRoot, prebuiltHermesPath)
|
||||
if (prebuiltHermes.exists()) {
|
||||
return prebuiltHermes.getAbsolutePath()
|
||||
}
|
||||
|
||||
throw new Exception("Couldn't determine Hermesc location. " +
|
||||
"Please set `project.ext.react.hermesCommand` to the path of the hermesc binary file. " +
|
||||
"node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc");
|
||||
}
|
||||
|
||||
// Set enableHermesForVariant to a function to configure per variant,
|
||||
|
||||
Reference in New Issue
Block a user