2013-08-13 08:07:23 +08:00
#!/usr/bin/env node
/ *
Licensed to the Apache Software Foundation ( ASF ) under one
or more contributor license agreements . See the NOTICE file
distributed with this work for additional information
regarding copyright ownership . The ASF licenses this file
to you under the Apache License , Version 2.0 ( the
"License" ) ; you may not use this file except in compliance
with the License . You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing ,
software distributed under the License is distributed on an
"AS IS" BASIS , WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND , either express or implied . See the License for the
specific language governing permissions and limitations
under the License .
* /
2014-08-16 01:42:43 +08:00
var shelljs = require ( 'shelljs' ) ,
2013-09-27 23:48:55 +08:00
child _process = require ( 'child_process' ) ,
Q = require ( 'q' ) ,
2013-08-13 08:07:23 +08:00
path = require ( 'path' ) ,
fs = require ( 'fs' ) ,
2014-06-20 04:12:40 +08:00
which = require ( 'which' ) ,
2013-08-13 08:07:23 +08:00
ROOT = path . join ( _ _dirname , '..' , '..' ) ;
2014-08-16 01:42:43 +08:00
var isWindows = process . platform == 'win32' ;
2014-08-19 02:45:23 +08:00
function forgivingWhichSync ( cmd ) {
try {
2014-08-19 03:26:05 +08:00
return which . sync ( cmd ) ;
2014-08-19 02:45:23 +08:00
} catch ( e ) {
return '' ;
}
}
2014-08-16 01:42:43 +08:00
function tryCommand ( cmd , errMsg ) {
var d = Q . defer ( ) ;
child _process . exec ( cmd , function ( err , stdout , stderr ) {
if ( err ) d . reject ( new Error ( errMsg ) ) ;
else d . resolve ( stdout ) ;
} ) ;
return d . promise ;
}
2013-08-13 08:07:23 +08:00
// Get valid target from framework/project.properties
module . exports . get _target = function ( ) {
2014-09-11 00:43:40 +08:00
function extractFromFile ( filePath ) {
var target = shelljs . grep ( /\btarget=/ , filePath ) ;
if ( ! target ) {
throw new Error ( 'Could not find android target within: ' + filePath ) ;
2014-05-09 03:37:09 +08:00
}
2014-09-11 00:43:40 +08:00
return target . split ( '=' ) [ 1 ] . trim ( ) ;
}
if ( fs . existsSync ( path . join ( ROOT , 'framework' , 'project.properties' ) ) ) {
return extractFromFile ( path . join ( ROOT , 'framework' , 'project.properties' ) ) ;
}
if ( fs . existsSync ( path . join ( ROOT , 'project.properties' ) ) ) {
// if no target found, we're probably in a project and project.properties is in ROOT.
return extractFromFile ( path . join ( ROOT , 'project.properties' ) ) ;
2013-08-13 08:07:23 +08:00
}
2014-09-11 00:43:40 +08:00
throw new Error ( 'Could not find android target. File missing: ' + path . join ( ROOT , 'project.properties' ) ) ;
2013-08-13 08:07:23 +08:00
}
2014-08-16 01:58:53 +08:00
// Returns a promise. Called only by build and clean commands.
2013-08-13 08:07:23 +08:00
module . exports . check _ant = function ( ) {
2014-08-16 01:42:43 +08:00
return tryCommand ( 'ant -version' , 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.' ) ;
2014-08-19 11:21:26 +08:00
} ;
// Returns a promise. Called only by build and clean commands.
module . exports . check _gradle = function ( ) {
var sdkDir = process . env [ 'ANDROID_HOME' ] ;
var wrapperDir = path . join ( sdkDir , 'tools' , 'templates' , 'gradle' , 'wrapper' ) ;
if ( ! fs . existsSync ( wrapperDir ) ) {
return Q . reject ( new Error ( 'Could not find gradle wrapper within android sdk. Might need to update your Android SDK.\n' +
'Looked here: ' + wrapperDir ) ) ;
}
return Q . when ( ) ;
} ;
2013-08-13 08:07:23 +08:00
2013-09-27 23:48:55 +08:00
// Returns a promise.
2013-08-13 08:07:23 +08:00
module . exports . check _java = function ( ) {
2014-08-19 02:45:23 +08:00
var javacPath = forgivingWhichSync ( 'javac' ) ;
var hasJavaHome = ! ! process . env [ 'JAVA_HOME' ] ;
return Q ( ) . then ( function ( ) {
if ( hasJavaHome ) {
// Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
if ( ! javacPath ) {
process . env [ 'PATH' ] += path . delimiter + path . join ( process . env [ 'JAVA_HOME' ] , 'bin' ) ;
}
} else {
if ( javacPath ) {
// OS X has a command for finding JAVA_HOME.
if ( fs . existsSync ( '/usr/libexec/java_home' ) ) {
return tryCommand ( '/usr/libexec/java_home' , 'Failed to run: /usr/libexec/java_home' )
. then ( function ( stdout ) {
process . env [ 'JAVA_HOME' ] = stdout . trim ( ) ;
} ) ;
} else {
// See if we can derive it from javac's location.
var maybeJavaHome = path . dirname ( path . dirname ( javacPath ) ) ;
if ( fs . existsSync ( path . join ( maybeJavaHome , 'lib' , 'tools.jar' ) ) ) {
process . env [ 'JAVA_HOME' ] = maybeJavaHome ;
} else {
throw new Error ( 'Could not find JAVA_HOME. Try setting the environment variable manually' ) ;
}
}
} else if ( isWindows ) {
// Try to auto-detect java in the default install paths.
var firstJdkDir =
shelljs . ls ( process . env [ 'ProgramFiles' ] + '\\java\\jdk*' ) [ 0 ] ||
shelljs . ls ( 'C:\\Program Files\\java\\jdk*' ) [ 0 ] ||
shelljs . ls ( 'C:\\Program Files (x86)\\java\\jdk*' ) [ 0 ] ;
if ( firstJdkDir ) {
// shelljs always uses / in paths.
firstJdkDir = firstJdkDir . replace ( /\//g , path . sep ) ;
if ( ! javacPath ) {
process . env [ 'PATH' ] += path . delimiter + path . join ( firstJdkDir , 'bin' ) ;
}
process . env [ 'JAVA_HOME' ] = firstJdkDir ;
}
2014-08-16 01:42:43 +08:00
}
2013-11-28 05:59:20 +08:00
}
2014-08-19 02:45:23 +08:00
} ) . then ( function ( ) {
var msg =
'Failed to run "java -version", make sure your java environment is set up\n' +
'including JDK and JRE.\n' +
'Your JAVA_HOME variable is: ' + process . env [ 'JAVA_HOME' ] ;
return tryCommand ( 'java -version' , msg )
} ) . then ( function ( ) {
2014-08-16 01:42:43 +08:00
msg = 'Failed to run "javac -version", make sure you have a Java JDK (not just a JRE) installed.' ;
return tryCommand ( 'javac -version' , msg )
2013-11-28 05:59:20 +08:00
} ) ;
2013-08-13 08:07:23 +08:00
}
2013-09-27 23:48:55 +08:00
// Returns a promise.
2013-08-13 08:07:23 +08:00
module . exports . check _android = function ( ) {
2014-08-19 11:21:26 +08:00
return Q ( ) . then ( function ( ) {
var androidCmdPath = forgivingWhichSync ( 'android' ) ;
var adbInPath = ! ! forgivingWhichSync ( 'adb' ) ;
var hasAndroidHome = ! ! process . env [ 'ANDROID_HOME' ] && fs . existsSync ( process . env [ 'ANDROID_HOME' ] ) ;
2014-09-10 22:14:38 +08:00
function maybeSetAndroidHome ( value ) {
if ( fs . existsSync ( value ) ) {
hasAndroidHome = true ;
process . env [ 'ANDROID_HOME' ] = value ;
}
}
if ( ! hasAndroidHome && ! androidCmdPath ) {
if ( isWindows ) {
maybeSetAndroidHome ( path . join ( process . env [ 'LOCALAPPDATA' ] , 'Android' , 'android-studio' , 'sdk' ) ) ;
maybeSetAndroidHome ( path . join ( process . env [ 'ProgramFiles' ] , 'Android' , 'android-studio' , 'sdk' ) ) ;
} else if ( process . platform == 'darwin' ) {
maybeSetAndroidHome ( '/Applications/Android Studio.app/sdk' ) ;
}
}
2014-08-19 11:21:26 +08:00
if ( hasAndroidHome && ! androidCmdPath ) {
process . env [ 'PATH' ] += path . delimiter + path . join ( process . env [ 'ANDROID_HOME' ] , 'tools' ) ;
2014-08-19 02:45:23 +08:00
}
2014-08-19 11:21:26 +08:00
if ( androidCmdPath && ! hasAndroidHome ) {
var parentDir = path . dirname ( androidCmdPath ) ;
if ( path . basename ( parentDir ) == 'tools' ) {
process . env [ 'ANDROID_HOME' ] = path . dirname ( parentDir ) ;
hasAndroidHome = true ;
}
}
if ( hasAndroidHome && ! adbInPath ) {
process . env [ 'PATH' ] += path . delimiter + path . join ( process . env [ 'ANDROID_HOME' ] , 'platform-tools' ) ;
2013-09-27 23:48:55 +08:00
}
2014-08-19 02:45:23 +08:00
if ( ! process . env [ 'ANDROID_HOME' ] ) {
throw new Error ( 'ANDROID_HOME is not set and "android" command not in your PATH. You must fulfill at least one of these conditions.' ) ;
}
if ( ! fs . existsSync ( process . env [ 'ANDROID_HOME' ] ) ) {
throw new Error ( 'ANDROID_HOME is set to a non-existant path: ' + process . env [ 'ANDROID_HOME' ] ) ;
}
2014-08-19 11:21:26 +08:00
// Check that the target sdk level is installed.
return module . exports . check _android _target ( module . exports . get _target ( ) ) ;
2013-09-27 23:48:55 +08:00
} ) ;
2014-08-19 11:21:26 +08:00
} ;
module . exports . check _android _target = function ( valid _target ) {
2014-09-11 00:43:40 +08:00
// valid_target can look like:
// android-19
// android-L
// Google Inc.:Google APIs:20
// Google Inc.:Glass Development Kit Preview:20
2014-08-19 11:21:26 +08:00
var msg = 'Failed to run "android". Make sure you have the latest Android SDK installed, and that the "android" command (inside the tools/ folder) is added to your PATH.' ;
2014-09-11 00:43:40 +08:00
return tryCommand ( 'android list targets --compact' , msg )
2014-08-19 11:21:26 +08:00
. then ( function ( output ) {
2014-09-11 00:43:40 +08:00
if ( output . split ( '\n' ) . indexOf ( valid _target ) == - 1 ) {
throw new Error ( 'Please install Android target: "' + valid _target + '".\n' +
'Hint: Open the SDK manager by running: ' + forgivingWhichSync ( 'android' ) ) ;
2014-08-19 11:21:26 +08:00
}
} ) ;
} ;
2013-08-13 08:07:23 +08:00
2013-09-27 23:48:55 +08:00
// Returns a promise.
2013-08-13 08:07:23 +08:00
module . exports . run = function ( ) {
2014-08-16 01:58:53 +08:00
return Q . all ( [ this . check _java ( ) , this . check _android ( ) ] ) ;
2013-09-14 09:38:46 +08:00
}
2013-10-18 21:59:42 +08:00