Export `detected*` functions fron `ReactAppExtension` to its own file

Summary:
Ideally a Gradle `Extension` should contain only properties as it's the public facing API of our
Gradle surface. Here I'm movign a couple of functions away from it. Now they're located inside their
own Util file. Moreover I've added tests and documentation to those.

Changelog:
[Internal] [Changed] - Export `detected*` functions fron `ReactAppExtension` to its own file

Reviewed By: mdvacca

Differential Revision: D30865494

fbshipit-source-id: 59925414c0eb427161691950f5b9b6495121da00
This commit is contained in:
Nicola Corti 2021-09-10 08:30:13 -07:00 коммит произвёл Facebook GitHub Bot
Родитель c40b177f61
Коммит d4c347c052
4 изменённых файлов: 169 добавлений и 51 удалений

Просмотреть файл

@ -35,58 +35,9 @@ open class ReactAppExtension(private val project: Project) {
var resourcesDir: Map<String, File> = emptyMap()
var jsBundleDir: Map<String, File> = emptyMap()
internal val detectedEntryFile: File
get() = detectEntryFile(entryFile = entryFile, reactRoot = reactRoot)
internal val detectedCliPath: String
get() =
detectCliPath(
projectDir = project.projectDir, reactRoot = reactRoot, preconfuredCliPath = cliPath)
internal val osAwareHermesCommand: String
get() = getOSAwareHermesCommand(hermesCommand)
private fun detectEntryFile(entryFile: File?, reactRoot: File): File =
when {
System.getenv("ENTRY_FILE") != null -> File(System.getenv("ENTRY_FILE"))
entryFile != null -> entryFile
File(reactRoot, "index.android.js").exists() -> File(reactRoot, "index.android.js")
else -> File(reactRoot, "index.android.js")
}
private fun detectCliPath(
projectDir: File,
reactRoot: File,
preconfuredCliPath: String?
): String {
// 1. preconfigured path
if (preconfuredCliPath != null) return preconfuredCliPath
// 2. node module path
val nodeProcess =
Runtime.getRuntime()
.exec(
arrayOf("node", "-e", "console.log(require('react-native/cli').bin);"),
emptyArray(),
projectDir)
val nodeProcessOutput = nodeProcess.inputStream.use { it.bufferedReader().readText().trim() }
if (nodeProcessOutput.isNotEmpty()) {
return nodeProcessOutput
}
// 3. cli.js in the root folder
val rootCliJs = File(reactRoot, "node_modules/react-native/cli.js")
if (rootCliJs.exists()) {
return rootCliJs.absolutePath
}
error(
"Couldn't determine CLI location. " +
"Please set `project.react.cliPath` to the path of the react-native cli.js")
}
// Make sure not to inspect the Hermes config unless we need it,
// to avoid breaking any JSC-only setups.
private fun getOSAwareHermesCommand(hermesCommand: String): String {

Просмотреть файл

@ -13,6 +13,8 @@ import com.android.build.gradle.api.LibraryVariant
import com.android.build.gradle.internal.tasks.factory.dependsOn
import com.facebook.react.tasks.BundleJsAndAssetsTask
import com.facebook.react.tasks.HermesBinaryTask
import com.facebook.react.utils.detectedCliPath
import com.facebook.react.utils.detectedEntryFile
import java.io.File
import org.gradle.api.Project
import org.gradle.api.tasks.Copy
@ -40,7 +42,7 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE
// Additional node and packager commandline arguments
val nodeExecutableAndArgs = config.nodeExecutableAndArgs
val cliPath = config.detectedCliPath
val cliPath = detectedCliPath(project.projectDir, config)
val execCommand = nodeExecutableAndArgs + cliPath
val enableHermes = config.enableHermesForVariant(variant)
@ -57,7 +59,7 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE
it.execCommand = execCommand
it.bundleCommand = config.bundleCommand
it.devEnabled = !(variant.name in config.devDisabledInVariants || isRelease)
it.entryFile = config.detectedEntryFile
it.entryFile = detectedEntryFile(config)
val extraArgs = mutableListOf<String>()

Просмотреть файл

@ -0,0 +1,74 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.utils
import com.facebook.react.ReactAppExtension
import java.io.File
/**
* Computes the entry file for React Native. The Algo follows this order:
* 1. The file pointed by the ENTRY_FILE env variable, if set.
* 2. The file provided by the `entryFile` config in the `reactApp` Gradle extension
* 3. The `index.android.js` file, if available.
* 4. Fallback to the `index.js` file.
*
* @param config The [ReactAppExtension] configured for this project
*/
internal fun detectedEntryFile(config: ReactAppExtension): File =
detectEntryFile(entryFile = config.entryFile, reactRoot = config.reactRoot)
/**
* Computes the CLI location for React Native. The Algo follows this order:
* 1. The path provided by the `cliPath` config in the `reactApp` Gradle extension
* 2. The output of `node -e "console.log(require('react-native/cli').bin);"` if not failing.
* 3. The `node_modules/react-native/cli.js` file if exists
* 4. Fails otherwise
*/
internal fun detectedCliPath(
projectDir: File,
config: ReactAppExtension,
): String =
detectCliPath(
projectDir = projectDir, reactRoot = config.reactRoot, preconfuredCliPath = config.cliPath)
private fun detectEntryFile(entryFile: File?, reactRoot: File): File =
when {
System.getenv("ENTRY_FILE") != null -> File(System.getenv("ENTRY_FILE"))
entryFile != null -> entryFile
File(reactRoot, "index.android.js").exists() -> File(reactRoot, "index.android.js")
else -> File(reactRoot, "index.js")
}
private fun detectCliPath(projectDir: File, reactRoot: File, preconfuredCliPath: String?): String {
// 1. preconfigured path
if (preconfuredCliPath != null) return preconfuredCliPath
// 2. node module path
val nodeProcess =
Runtime.getRuntime()
.exec(
arrayOf("node", "-e", "console.log(require('react-native/cli').bin);"),
emptyArray(),
projectDir)
val nodeProcessOutput = nodeProcess.inputStream.use { it.bufferedReader().readText().trim() }
if (nodeProcessOutput.isNotEmpty()) {
return nodeProcessOutput
}
// 3. cli.js in the root folder
val rootCliJs = File(reactRoot, "node_modules/react-native/cli.js")
if (rootCliJs.exists()) {
return rootCliJs.absolutePath
}
error(
"Couldn't determine CLI location. " +
"Please set `project.react.cliPath` to the path of the react-native cli.js")
}

Просмотреть файл

@ -0,0 +1,91 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.tests
import com.facebook.react.ReactAppExtension
import com.facebook.react.utils.detectedCliPath
import com.facebook.react.utils.detectedEntryFile
import java.io.File
import org.gradle.testfixtures.ProjectBuilder
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
class PathUtilsTest {
@get:Rule val tempFolder = TemporaryFolder()
@Test
fun detectedEntryFile_withProvidedVariable() {
val extension = ReactAppExtension(ProjectBuilder.builder().build())
val expected = tempFolder.newFile("fake.index.js")
extension.entryFile = expected
val actual = detectedEntryFile(extension)
assertEquals(expected, actual)
}
@Test
fun detectedEntryFile_withAndroidEntryPoint() {
val extension = ReactAppExtension(ProjectBuilder.builder().build())
extension.reactRoot = tempFolder.root
tempFolder.newFile("index.android.js")
val actual = detectedEntryFile(extension)
assertEquals(File(tempFolder.root, "index.android.js"), actual)
}
@Test
fun detectedEntryFile_withDefaultEntryPoint() {
val extension = ReactAppExtension(ProjectBuilder.builder().build())
extension.reactRoot = tempFolder.root
val actual = detectedEntryFile(extension)
assertEquals(File(tempFolder.root, "index.js"), actual)
}
@Test
fun detectedCliPath_withCliPathFromExtension() {
val project = ProjectBuilder.builder().build()
val extension = ReactAppExtension(project)
val expected = tempFolder.newFile("fake-cli.sh")
extension.cliPath = expected.toString()
val actual = detectedCliPath(project.projectDir, extension)
assertEquals(expected.toString(), actual)
}
@Test
fun detectedCliPath_withCliFromNodeModules() {
val project = ProjectBuilder.builder().build()
val extension = ReactAppExtension(project)
extension.reactRoot = tempFolder.root
val expected =
File(tempFolder.root, "node_modules/react-native/cli.js").apply {
parentFile.mkdirs()
writeText("<!-- nothing to see here -->")
}
val actual = detectedCliPath(project.projectDir, extension)
assertEquals(expected.toString(), actual)
}
@Test(expected = IllegalStateException::class)
fun detectedCliPath_failsIfNotFound() {
val project = ProjectBuilder.builder().build()
val extension = ReactAppExtension(project)
detectedCliPath(project.projectDir, extension)
}
}