From 4a89fe1eac3ebfd79e51dc4e589922d5c291481e Mon Sep 17 00:00:00 2001 From: Krisztiaan Date: Tue, 15 Mar 2022 09:24:22 -0700 Subject: [PATCH] fix: `cliPath` should handle absolute paths (#32983) Summary: Avoid breaking tools relying on absolute path for `cliPath` ## Changelog [Android] [Fixed] - Enable cliPath to have an absolute path value Pull Request resolved: https://github.com/facebook/react-native/pull/32983 Test Plan: declare `cliPath` from `expo`: ```groovy cliPath: new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/cli.js", ``` and run an android build Reviewed By: ShikaSD Differential Revision: D33843275 Pulled By: cortinico fbshipit-source-id: 65f55a5e07a4ec0a6205d5f06f150377708c30cc --- .../com/facebook/react/utils/PathUtils.kt | 18 ++++++- .../com/facebook/react/utils/PathUtilsTest.kt | 41 +++++++++++++- react.gradle | 53 +++++++++++++------ 3 files changed, 93 insertions(+), 19 deletions(-) diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt index 302c1d83a7b412..d485aa69bdf424 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt @@ -67,7 +67,18 @@ private fun detectCliPath( ): String { // 1. preconfigured path if (preconfiguredCliPath != null) { - return File(projectDir, preconfiguredCliPath).toString() + val preconfiguredCliJsAbsolute = File(preconfiguredCliPath) + if (preconfiguredCliJsAbsolute.exists()) { + return preconfiguredCliJsAbsolute.absolutePath + } + val preconfiguredCliJsRelativeToReactRoot = File(reactRoot, preconfiguredCliPath) + if (preconfiguredCliJsRelativeToReactRoot.exists()) { + return preconfiguredCliJsRelativeToReactRoot.absolutePath + } + val preconfiguredCliJsRelativeToProject = File(projectDir, preconfiguredCliPath) + if (preconfiguredCliJsRelativeToProject.exists()) { + return preconfiguredCliJsRelativeToProject.absolutePath + } } // 2. node module path @@ -81,7 +92,10 @@ private fun detectCliPath( val nodeProcessOutput = nodeProcess.inputStream.use { it.bufferedReader().readText().trim() } if (nodeProcessOutput.isNotEmpty()) { - return nodeProcessOutput + val nodeModuleCliJs = File(nodeProcessOutput) + if (nodeModuleCliJs.exists()) { + return nodeModuleCliJs.absolutePath + } } // 3. cli.js in the root folder diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/PathUtilsTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/PathUtilsTest.kt index debba45740b3b0..0c9d3669079059 100644 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/PathUtilsTest.kt +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/PathUtilsTest.kt @@ -52,10 +52,47 @@ class PathUtilsTest { } @Test - fun detectedCliPath_withCliPathFromExtension() { + fun detectedCliPath_withCliPathFromExtensionAbsolute() { val project = ProjectBuilder.builder().build() val extension = TestReactExtension(project) - val expected = File(project.projectDir, "fake-cli.sh") + val expected = + File(project.projectDir, "abs/fake-cli.sh").apply { + parentFile.mkdirs() + writeText("") + } + extension.cliPath.set(project.projectDir + "/abs/fake-cli.sh") + + val actual = detectedCliPath(project.projectDir, extension) + + assertEquals(expected.toString(), actual) + } + + @Test + fun detectedCliPath_withCliPathFromExtensionInReactFolder() { + val project = ProjectBuilder.builder().build() + val extension = TestReactExtension(project) + val expected = + File(project.projectDir, "/react-root/fake-cli.sh").apply { + parentFile.mkdirs() + writeText("") + } + extension.cliPath.set("fake-cli.sh") + extension.reactRoot.set(project.projectDir + "/react-root") + + val actual = detectedCliPath(project.projectDir, extension) + + assertEquals(expected.toString(), actual) + } + + @Test + fun detectedCliPath_withCliPathFromExtensionInProjectFolder() { + val project = ProjectBuilder.builder().build() + val extension = TestReactExtension(project) + val expected = + File(project.projectDir, "fake-cli.sh").apply { + parentFile.mkdirs() + writeText("") + } extension.cliPath.set("fake-cli.sh") val actual = detectedCliPath(project.projectDir, extension) diff --git a/react.gradle b/react.gradle index 047560a998fc57..0283a18e73bb7a 100644 --- a/react.gradle +++ b/react.gradle @@ -22,20 +22,6 @@ def detectEntryFile(config) { return "index.js"; } -/** - * Detects CLI location in a similar fashion to the React Native CLI - */ -def detectCliPath(config) { - if (config.cliPath) { - return "${projectDir}/${config.cliPath}" - } - if (new File("${projectDir}/../../node_modules/react-native/cli.js").exists()) { - return "${projectDir}/../../node_modules/react-native/cli.js" - } - throw new Exception("Couldn't determine CLI location. " + - "Please set `project.ext.react.cliPath` to the path of the react-native cli.js file. This file typically resides in `node_modules/react-native/cli.js`"); -} - def composeSourceMapsPath = config.composeSourceMapsPath ?: "node_modules/react-native/scripts/compose-source-maps.js" def bundleAssetName = config.bundleAssetName ?: "index.android.bundle" def entryFile = detectEntryFile(config) @@ -46,6 +32,43 @@ def bundleConfig = config.bundleConfig ? "${reactRoot}/${config.bundleConfig}" : def enableVmCleanup = config.enableVmCleanup == null ? true : config.enableVmCleanup def hermesCommand = config.hermesCommand ?: "../../node_modules/hermes-engine/%OS-BIN%/hermesc" +/** + * Detects CLI location in a similar fashion to the React Native CLI + */ +def detectCliPath(config, reactRoot) { + // 1. preconfigured path + if (config.cliPath) { + def cliJsAbsolute = new File(config.cliPath) + if (cliJsAbsolute.exists()) { + return cliJsAbsolute.getAbsolutePath() + } + def cliJsRelativeToRoot = new File("${rootDir}/${config.cliPath}") + if (cliJsRelativeToRoot.exists()) { + return cliJsRelativeToRoot.getAbsolutePath() + } + def cliJsRelativeToProject = new File("${projectDir}/${config.cliPath}") + if (cliJsRelativeToProject.exists()) { + return cliJsRelativeToProject.getAbsolutePath() + } + } + + // 2. node module path + def cliJsFromNode = new File(["node", "--print", "require.resolve('react-native/cli').bin"].execute(null, rootDir).text.trim()) + if (cliJsFromNode.exists()) { + return cliJsFromNode.getAbsolutePath() + } + + // 3. cli.js in the root folder + def rootCliJs = new File(reactRoot, "node_modules/react-native/cli.js") + if (rootCliJs.exists()) { + return rootCliJs.getAbsolutePath() + } + + throw new Exception("Couldn't determine CLI location. " + + "Please set `project.ext.react.cliPath` to the path of the react-native cli.js file. " + + "This file typically resides in `node_modules/react-native/cli.js`"); +} + def reactNativeDevServerPort() { def value = project.getProperties().get("reactNativeDevServerPort") return value != null ? value : "8081" @@ -164,7 +187,7 @@ afterEvaluate { // Additional node and packager commandline arguments def nodeExecutableAndArgs = config.nodeExecutableAndArgs ?: ["node"] - def cliPath = detectCliPath(config) + def cliPath = detectCliPath(config, reactRoot) def execCommand = []