-
Notifications
You must be signed in to change notification settings - Fork 904
Commit
* feat: run npx from JS app dir * improve comment * use .sourceFile * extract getCommandOutput * better errors * apply feedback
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ import groovy.json.JsonSlurper | |
import org.gradle.initialization.DefaultSettings | ||
import org.apache.tools.ant.taskdefs.condition.Os | ||
|
||
def jsAppDir = buildscript.sourceFile.toString().split("node_modules/@react-native-community/cli-platform-android")[0] | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
thymikee
Author
Member
|
||
def generatedFileName = "PackageList.java" | ||
def generatedFilePackage = "com.facebook.react" | ||
def generatedFileContentsTemplate = """ | ||
|
@@ -71,12 +72,14 @@ public class PackageList { | |
class ReactNativeModules { | ||
private Logger logger | ||
private String packageName | ||
private String jsAppDir | ||
private ArrayList<HashMap<String, String>> reactNativeModules | ||
|
||
private static String LOG_PREFIX = ":ReactNative:" | ||
|
||
ReactNativeModules(Logger logger) { | ||
ReactNativeModules(Logger logger, String jsAppDir) { | ||
this.logger = logger | ||
this.jsAppDir = jsAppDir | ||
|
||
def (nativeModules, packageName) = this.getReactNativeConfig() | ||
this.reactNativeModules = nativeModules | ||
|
@@ -142,45 +145,66 @@ class ReactNativeModules { | |
} | ||
|
||
/** | ||
* Runs a process to call the React Native CLI Config command and parses the output | ||
* | ||
* @return ArrayList < HashMap < String , String > > | ||
* Runs a specified command using Runtime exec() in a specified directory. | ||
* Throws when the command result is empty. | ||
*/ | ||
ArrayList<HashMap<String, String>> getReactNativeConfig() { | ||
if (this.reactNativeModules != null) return this.reactNativeModules | ||
ArrayList<HashMap<String, String>> reactNativeModules = new ArrayList<HashMap<String, String>>() | ||
|
||
def cmdProcess | ||
def npx = Os.isFamily(Os.FAMILY_WINDOWS) ? "npx.cmd" : "npx" | ||
def command = "${npx} --quiet react-native config" | ||
def reactNativeConfigOutput = "" | ||
|
||
String getCommandOutput(String command, File directory = null) { | ||
try { | ||
cmdProcess = Runtime.getRuntime().exec(command) | ||
def output = "" | ||
def cmdProcess = Runtime.getRuntime().exec(command, null, directory) | ||
def bufferedReader = new BufferedReader(new InputStreamReader(cmdProcess.getInputStream())) | ||
def buff = "" | ||
def readBuffer = new StringBuffer() | ||
while ((buff = bufferedReader.readLine()) != null){ | ||
readBuffer.append(buff) | ||
while ((buff = bufferedReader.readLine()) != null) { | ||
readBuffer.append(buff) | ||
} | ||
output = readBuffer.toString() | ||
if (!output) { | ||
this.logger.error("${LOG_PREFIX}Unexpected empty result of running '${command}' command from '${directory}' directory.") | ||
def bufferedErrorReader = new BufferedReader(new InputStreamReader(cmdProcess.getErrorStream())) | ||
def errBuff = "" | ||
def readErrorBuffer = new StringBuffer() | ||
while ((errBuff = bufferedErrorReader.readLine()) != null) { | ||
readErrorBuffer.append(errBuff) | ||
} | ||
throw new Exception(readErrorBuffer.toString()) | ||
} | ||
reactNativeConfigOutput = readBuffer.toString() | ||
return output | ||
} catch (Exception exception) { | ||
this.logger.warn("${LOG_PREFIX}${exception.message}") | ||
this.logger.warn("${LOG_PREFIX}Automatic import of native modules failed.") | ||
this.logger.error("${LOG_PREFIX}Running '${command}' command from '${directory}' directory failed.") | ||
throw exception | ||
} | ||
} | ||
|
||
def bufferedErrorReader = new BufferedReader(new InputStreamReader(cmdProcess.getErrorStream())) | ||
def buff = "" | ||
def readBuffer = new StringBuffer() | ||
while ((buff = bufferedErrorReader.readLine()) != null){ | ||
readBuffer.append(buff) | ||
} | ||
this.logger.warn("${LOG_PREFIX}${readBuffer.toString()}") | ||
/** | ||
* Runs a process to call the React Native CLI Config command and parses the output | ||
*/ | ||
ArrayList<HashMap<String, String>> getReactNativeConfig() { | ||
if (this.reactNativeModules != null) return this.reactNativeModules | ||
|
||
return reactNativeModules | ||
ArrayList<HashMap<String, String>> reactNativeModules = new ArrayList<HashMap<String, String>>() | ||
def npx = Os.isFamily(Os.FAMILY_WINDOWS) ? "npx.cmd" : "npx" | ||
def command = "${npx} --quiet --no-install react-native config" | ||
/** | ||
* Running npx from the directory of the JS app which holds this script in its node_modules. | ||
* We do so, because Gradle may be ran with a different directory as CWD, that's outside of JS project | ||
* (e.g. when running with -p flag), in which case npx wouldn't resolve correct `react-native` binary. | ||
*/ | ||
def dir = new File(this.jsAppDir) | ||
def reactNativeConfigOutput = this.getCommandOutput(command, dir) | ||
def json | ||
try { | ||
json = new JsonSlurper().parseText(reactNativeConfigOutput) | ||
} catch (Exception exception) { | ||
this.logger.error("${LOG_PREFIX}Failed to parse React Native CLI configuration: ${exception.toString()}") | ||
throw new Exception("Failed to parse React Native CLI configuration. Expected running '${command}' command from '${dir}' directory to output valid JSON, but it didn't. This may be caused by npx resolving to a legacy global react-native binary. Please make sure to uninstall any global 'react-native' binaries: 'npm uninstall -g react-native react-native-cli' and try again") | ||
} | ||
|
||
def json = new JsonSlurper().parseText(reactNativeConfigOutput) | ||
def dependencies = json["dependencies"] | ||
def project = json["project"]["android"] | ||
|
||
if (project == null) { | ||
throw new Exception("React Native CLI failed to determine Android project configuration. This is likely due to misconfiguration. Config output:\n${json.toMapString()}") | ||
} | ||
|
||
dependencies.each { name, value -> | ||
def platformsConfig = value["platforms"]; | ||
|
@@ -211,7 +235,7 @@ class ReactNativeModules { | |
* Exported Extensions | ||
* ------------------------ */ | ||
|
||
def autoModules = new ReactNativeModules(logger) | ||
def autoModules = new ReactNativeModules(logger, jsAppDir) | ||
|
||
ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String root = null -> | ||
if (root != null) { | ||
|
1 comment
on commit a3a70a1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In retrospect, using npx
to execute a CLI configuration has this unwanted side effect that MANY out there do have global react-native
. Since we have never pointed out to remove a global binary, almost everybody is going to run into this error, earlier or later.
What can we do about this?
the directory seperator is \ in windows so this line is causing an error and it could be fixed for example this way :
def jsAppDir = buildscript.sourceFile.toString().split(/node_modules[/|\]@react-native-community[/|\]cli-platform-android/)[0]