2020import com .google .common .collect .ImmutableMap ;
2121import io .appium .java_client .service .local .flags .ServerArgument ;
2222import org .apache .commons .io .FileUtils ;
23- import org .apache .commons .lang3 .ArrayUtils ;
2423import org .apache .commons .lang3 .StringUtils ;
2524import org .apache .commons .validator .routines .InetAddressValidator ;
2625import org .openqa .selenium .Platform ;
26+ import org .openqa .selenium .os .CommandLine ;
2727import org .openqa .selenium .remote .service .DriverService ;
2828
2929import java .io .*;
30- import java .nio .charset .Charset ;
3130import java .util .*;
3231import java .util .concurrent .TimeUnit ;
3332
3736
3837public final class AppiumServiceBuilder extends DriverService .Builder <AppiumDriverLocalService , AppiumServiceBuilder > {
3938
39+ public static final String APPIUM_NODE_PROPERTY = "appium.node.path" ;
40+ public static final String NODE_JS_EXECUTABLE_PROPERTY = "appium.node.js.exec.path" ;
41+
4042 private static final String APPIUM_FOLDER = "appium" ;
4143 private static final String BIN_FOLDER = "bin" ;
4244 private static final String APPIUM_JS = "appium.js" ;
4345 private static final String APPIUM_NODE_MASK = File .separator +
4446 APPIUM_FOLDER + File .separator + BIN_FOLDER + File .separator + APPIUM_JS ;
4547
46- public static final String APPIUM_NODE_PROPERTY = "appium.node.path" ;
4748 public static final String DEFAULT_LOCAL_IP_ADDRESS = "0.0.0.0" ;
4849
4950 private static final int DEFAULT_APPIUM_PORT = 4723 ;
5051 private final static String BASH = "bash" ;
51- private final static String CMD_EXE [] = { "cmd.exe" , "/C" } ;
52+ private final static String CMD_EXE = "cmd.exe" ;
5253 private final static String NODE = "node" ;
53- private final static String PATH_NAME = getPathVarName ();
54-
5554
5655 final Map <String , String > serverArguments = new HashMap <>();
5756 private File appiumJS ;
5857 private String ipAddress = DEFAULT_LOCAL_IP_ADDRESS ;
5958 private File npmScript ;
59+ private File getNodeJSExecutable ;
6060
6161 //The first starting is slow sometimes on some
6262 //environment
6363 private long startupTimeout = 120 ;
6464 private TimeUnit timeUnit = TimeUnit .SECONDS ;
6565
66- private static String getPathVarName (){
67- Map <String , String > envVariables = System .getenv ();
68- Set <String > keys = envVariables .keySet ();
69-
70- for (String key : keys ) {
71- if (key .toUpperCase ().trim ().equals ("Path" .toUpperCase ())) {
72- return key ;
73- }
74- }
75- return null ;
76- }
77-
78- private static String getTheLastStringFromsOutput (InputStream stream ) throws IOException {
79- BufferedReader reader = new BufferedReader (
80- new InputStreamReader (stream , Charset .forName ("UTF-8" )));
81- String current ;
82- String result = null ;
83- while ((current = reader .readLine ()) != null ) {
84- if (StringUtils .isBlank (current )) {
85- continue ;
86- }
87- result = current ;
88- }
89- reader .close ();
90- return result ;
91- }
92-
93- private static String readErrorStream (Process process ) {
94- BufferedReader reader = new BufferedReader (
95- new InputStreamReader (process .getErrorStream (), Charset .forName ("UTF-8" )));
96- String current ;
97- String result = StringUtils .EMPTY ;
98- try {
99- while ((current = reader .readLine ()) != null ) {
100- if (StringUtils .isBlank (current )) {
101- continue ;
102- }
103- result = result + current + "\n " ;
104- }
105- reader .close ();
106- } catch (IOException e ) {
107- throw new RuntimeException (e );
66+ private void setUpNPMScript (){
67+ if (npmScript != null ) {
68+ return ;
10869 }
109- return result ;
110- }
11170
112- private static Process getSearchingProcess (String ... command ) throws Throwable {
113- ProcessBuilder processBuilder = new ProcessBuilder (command );
114- if (!StringUtils .isBlank (PATH_NAME )) {
115- String path = System .getenv ().get (PATH_NAME );
116- processBuilder .environment ().put (PATH_NAME , path );
71+ if (!Platform .getCurrent ().is (Platform .WINDOWS )) {
72+ npmScript = Scripts .GET_PATH_TO_DEFAULT_NODE_UNIX .getScriptFile ();
11773 }
118- return processBuilder .start ();
11974 }
12075
121- private void setUpNPMScript () {
122- if (npmScript != null ) {
76+ private void setUpGetNodeJSExecutableScript () {
77+ if (getNodeJSExecutable != null ) {
12378 return ;
12479 }
12580
126- if (Platform .getCurrent ().is (Platform .WINDOWS )) {
127- npmScript = NPMScript .GET_PATH_TO_DEFAULT_NODE_WIN .getScriptFile ();
128- }
129- else {
130- npmScript = NPMScript .GET_PATH_TO_DEFAULT_NODE_UNIX .getScriptFile ();
131- }
81+ getNodeJSExecutable = Scripts .GET_NODE_JS_EXECUTABLE .getScriptFile ();
13282 }
13383
13484 private File findNodeInCurrentFileSystem (){
13585 setUpNPMScript ();
13686
13787 String instancePath ;
138- Process p ;
88+ CommandLine commandLine ;
13989 try {
14090 if (Platform .getCurrent ().is (Platform .WINDOWS )) {
141- p = getSearchingProcess (ArrayUtils .add (CMD_EXE , npmScript .getAbsolutePath ()));
142- p .waitFor ();
91+ commandLine = new CommandLine (CMD_EXE , "/C" , "npm root -g" );
14392 }
14493 else {
145- p = getSearchingProcess (BASH , "-l" , npmScript .getAbsolutePath ());
94+ commandLine = new CommandLine (BASH , "-l" , npmScript .getAbsolutePath ());
14695 }
147- instancePath = getTheLastStringFromsOutput ( p . getInputStream () );
96+ commandLine . execute ( );
14897 } catch (Throwable e ) {
14998 throw new RuntimeException (e );
15099 }
151100
101+ instancePath = (commandLine .getStdOut ()).trim ();
152102 try {
153103 File result ;
154104 if (StringUtils .isBlank (instancePath ) || !(result = new File (instancePath + File .separator +
155105 APPIUM_NODE_MASK )).exists ()) {
156- String errorOutput = readErrorStream ( p );
106+ String errorOutput = commandLine . getStdOut ( );
157107 throw new InvalidServerInstanceException ("There is no installed nodes! Please install " +
158108 " node via NPM (https://www.npmjs.com/package/appium#using-node-js) or download and " +
159109 "install Appium app (http://appium.io/downloads.html)" ,
@@ -162,7 +112,7 @@ private File findNodeInCurrentFileSystem(){
162112 return result ;
163113 }
164114 finally {
165- p .destroy ();
115+ commandLine .destroy ();
166116 }
167117 }
168118
@@ -186,41 +136,42 @@ public AppiumServiceBuilder() {
186136
187137 @ Override
188138 protected File findDefaultExecutable () {
189- Process p ;
139+
140+ String nodeJSExec = System .getProperty (NODE_JS_EXECUTABLE_PROPERTY );
141+ if (!StringUtils .isBlank (nodeJSExec )) {
142+ File result = new File (nodeJSExec );
143+ if (result .exists ()) {
144+ return result ;
145+ }
146+ }
147+
148+ CommandLine commandLine ;
149+ setUpGetNodeJSExecutableScript ();
190150 try {
191151 if (Platform .getCurrent ().is (Platform .WINDOWS )) {
192- p = getSearchingProcess ( ArrayUtils . add ( CMD_EXE , NODE ));
152+ commandLine = new CommandLine ( NODE + ".exe" , getNodeJSExecutable . getAbsolutePath ( ));
193153 }
194154 else {
195- p = getSearchingProcess ( BASH , "-l" , "-c" , NODE );
155+ commandLine = new CommandLine ( NODE , getNodeJSExecutable . getAbsolutePath () );
196156 }
157+ commandLine .execute ();
197158 } catch (Throwable t ) {
198159 throw new InvalidNodeJSInstance ("Node.js is not installed!" , t );
199160 }
200161
201- String filePath ;
202- try {
203- OutputStream outputStream = p .getOutputStream ();
204- PrintStream out = new PrintStream (outputStream ) ;
205- out .println ("console.log(process.execPath);" ) ;
206- out .close ();
207- filePath = getTheLastStringFromsOutput (p .getInputStream ());
208- }
209- catch (Throwable t ){
210- p .destroy ();
211- throw new RuntimeException (t );
212- }
162+
163+ String filePath = (commandLine .getStdOut ()).trim ();
213164
214165 try {
215- if (StringUtils .isBlank (filePath )) {
216- String errorOutput = readErrorStream ( p );
166+ if (StringUtils .isBlank (filePath ) || ! new File ( filePath ). exists () ) {
167+ String errorOutput = commandLine . getStdOut ( );
217168 String errorMessage = "Can't get a path to the default Node.js instance" ;
218169 throw new InvalidNodeJSInstance (errorMessage , new IOException (errorOutput ));
219170 }
220171 return new File (filePath );
221172 }
222173 finally {
223- p .destroy ();
174+ commandLine .destroy ();
224175 }
225176 }
226177
@@ -394,14 +345,19 @@ protected AppiumDriverLocalService createDriverService(File nodeJSExecutable, in
394345 }
395346 }
396347
397- @ Override
398- protected void finalize () throws Throwable {
399- if (npmScript != null ) {
348+ private static void disposeCachedFile (File file ) {
349+ if (file != null ) {
400350 try {
401- FileUtils .forceDelete (npmScript );
351+ FileUtils .forceDelete (file );
402352 } catch (IOException ignored ) {
403353 }
404354 }
355+ }
356+
357+ @ Override
358+ protected void finalize () throws Throwable {
359+ disposeCachedFile (npmScript );
360+ disposeCachedFile (getNodeJSExecutable );
405361 super .finalize ();
406362 }
407- }
363+ }
0 commit comments