Merge pull request #1562 from penguinho/doctor

Adding More Doctor Checks for Android and Dev
This commit is contained in:
Jonathan Lipps
2013-12-02 11:06:37 -08:00
5 changed files with 248 additions and 52 deletions

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env node
"use strict";
var ios = require('../lib/doctor/ios.js')
, android = require('../lib/doctor/android.js')
var IOSChecker = require('../lib/doctor/ios.js').IOSChecker
, AndroidChecker = require('../lib/doctor/android.js').AndroidChecker
, DevChecker = require('../lib/doctor/dev.js').DevChecker
, common = require("../lib/doctor/common.js")
, eol = require('os').EOL
, async = require('async');
@@ -9,6 +10,7 @@ var ios = require('../lib/doctor/ios.js')
var argv = process.argv
, doAndroid = argv.indexOf('--android') > -1
, doIOS = argv.indexOf('--ios') > -1
, doDev = argv.indexOf('--dev') > -1
, verbose = argv.indexOf('--verbose') > -1
, broadcast = argv.indexOf('--port') > -1
, port = null;
@@ -26,7 +28,7 @@ var log = new common.Log(port);
var runiOSChecks = function(cb) {
if (doIOS) {
var iosChecker = new ios.IOSChecker(log);
var iosChecker = new IOSChecker(log);
log.comment("Running iOS Checks");
iosChecker.runAllChecks(function(err) {
if (!err) {
@@ -41,7 +43,7 @@ var runiOSChecks = function(cb) {
var runAndroidChecks = function(cb) {
if (doAndroid) {
var androidChecker = new android.AndroidChecker(log);
var androidChecker = new AndroidChecker(log);
log.comment("Running Android Checks");
androidChecker.runAllChecks(function(err) {
if (!err) {
@@ -54,12 +56,28 @@ var runAndroidChecks = function(cb) {
}
};
var runDevChecks = function(cb) {
if (doDev) {
var devChecker = new DevChecker(log);
log.comment("Running Dev Checks");
devChecker.runAllChecks(function(err) {
if (!err) {
log.pass("Dev Checks were successful." + eol);
cb();
} else {
log.exitDoctor();
}
});
}
};
if (require.main === module) {
var mainMethod = function() {
async.series([
runiOSChecks,
runAndroidChecks
runAndroidChecks,
runDevChecks
], function(err) {
if (!err) {
log.pass("All Checks were successful");

View File

@@ -4,6 +4,7 @@ var path = require('path')
, env = process.env
, exec = require('child_process').exec
, common = require("./common.js")
, isWindows = require("../helpers.js").isWindows()
, async = require('async');
function AndroidChecker(log) {
@@ -13,41 +14,55 @@ exports.AndroidChecker = AndroidChecker;
AndroidChecker.prototype.runAllChecks = function(cb) {
async.series([
this.IsAndroidHomeExported.bind(this),
this.IsJavaHomeExported.bind(this)
this.checkAndroidHomeExported.bind(this),
this.checkJavaHomeExported.bind(this),
this.checkADBExists.bind(this),
this.checkAndroidExists.bind(this),
this.checkEmulatorExists.bind(this)
], cb);
};
AndroidChecker.prototype.IsAndroidHomeExported = function(cb) {
var msg;
AndroidChecker.prototype.checkAndroidHomeExported = function(cb) {
if (env.ANDROID_HOME === null) {
msg = 'ANDROID_HOME is not set';
this.log.fail(msg);
cb(msg, msg);
this.log.fail('ANDROID_HOME is not set', cb);
} else if (fs.existsSync(env.ANDROID_HOME)) {
msg = 'ANDROID_HOME is set to "' + env.ANDROID_HOME + '"';
this.log.pass(msg);
cb(null, msg);
this.log.pass('ANDROID_HOME is set to "' + env.ANDROID_HOME + '"', cb);
} else {
msg = 'ANDROID_HOME is set but does not exist on the file system at "' + env.ANDROID_HOME + '"';
this.log.fail(msg);
cb(msg, msg);
this.log.fail('ANDROID_HOME is set but does not exist on the file system at "' + env.ANDROID_HOME + '"', cb);
}
};
AndroidChecker.prototype.IsJavaHomeExported = function(cb) {
var msg;
AndroidChecker.prototype.checkJavaHomeExported = function(cb) {
if (env.JAVA_HOME === null) {
this.log.fail(msg);
msg = 'JAVA_HOME is not set';
cb(msg, msg);
this.log.fail('JAVA_HOME is not set', cb);
} else if (fs.existsSync(env.JAVA_HOME)) {
msg = 'JAVA_HOME is set to "' + env.JAVA_HOME + '."';
this.log.pass(msg);
cb(null, msg);
this.log.pass('JAVA_HOME is set to "' + env.JAVA_HOME + '."', cb);
} else {
msg = 'JAVA_HOME is set but does not exist on the file system at "' + env.JAVA_HOME + '"';
this.log.fail(msg);
cb(msg, msg);
this.log.fail('JAVA_HOME is set but does not exist on the file system at "' + env.JAVA_HOME + '"', cb);
}
};
AndroidChecker.prototype.checkADBExists = function(cb) {
this.checkAndroidSDKBinaryExists("ADB", path.join("platform-tools", (isWindows ? 'adb.exe' : 'adb')), cb);
};
AndroidChecker.prototype.checkAndroidExists = function(cb) {
this.checkAndroidSDKBinaryExists("Android", path.join("tools", (isWindows ? 'android.bat' : 'android')), cb);
};
AndroidChecker.prototype.checkEmulatorExists = function(cb) {
this.checkAndroidSDKBinaryExists("Emulator", path.join("tools", (isWindows ? 'emulator.exe' : 'emulator')), cb);
};
AndroidChecker.prototype.checkAndroidSDKBinaryExists = function(toolName, relativeToolPath, cb) {
if (env.ANDROID_HOME !== null) {
var adbPath = path.resolve(env.ANDROID_HOME, relativeToolPath);
if (fs.existsSync(adbPath)) {
this.log.pass(toolName + " exists at " + adbPath, cb);
} else {
this.log.fail(toolName + " could not be found at " + adbPath, cb);
}
} else {
this.log.fail(toolName + " could not be found because ANDROID_HOME is not set.", cb);
}
};

View File

@@ -15,12 +15,18 @@ function Log(port) {
}
exports.Log = Log;
Log.prototype.pass = function(msg) {
Log.prototype.pass = function(msg, cb) {
this.logEntry('\u2714 '.green + msg.white);
if (cb) {
cb(null, msg);
}
};
Log.prototype.fail = function(msg) {
Log.prototype.fail = function(msg, cb) {
this.logEntry('\u2716 '.red + msg.white);
if (cb) {
cb(msg, msg);
}
};
Log.prototype.warning = function(msg) {

35
lib/doctor/dev.js Normal file
View File

@@ -0,0 +1,35 @@
"use strict";
var path = require('path')
, fs = require('fs')
, env = process.env
, exec = require('child_process').exec
, common = require("./common.js")
, isWindows = require("../helpers.js").isWindows()
, eol = require('os').EOL
, async = require('async');
function DevChecker(log) {
this.log = log;
}
exports.DevChecker = DevChecker;
DevChecker.prototype.runAllChecks = function(cb) {
async.series([
this.checkMavenExistsInPath.bind(this)
], cb);
};
DevChecker.prototype.checkMavenExistsInPath = function(cb) {
exec(isWindows ? "where mvn.bat" : "which mvn", { maxBuffer: 524288 }, function(err, stdout) {
if (!err) {
var mvnPath = isWindows ? stdout.split(eol)[0] : stdout.replace(eol, "");
if (fs.existsSync(mvnPath)) {
this.log.pass("Maven was found at " + mvnPath, cb);
} else {
this.log.fail("Maven does not exist at path " + mvnPath, cb);
}
} else {
this.log.fail("Could not find mvn in path.", cb);
}
}.bind(this));
};

View File

@@ -18,12 +18,12 @@ IOSChecker.prototype.runAllChecks = function(cb) {
this.checkForXcode.bind(this),
this.checkForXcodeCommandLineTools.bind(this),
this.checkDevToolsSecurity.bind(this),
this.checkAuthorizationDB.bind(this)
this.checkAuthorizationDB.bind(this),
this.checkForNodeBinary.bind(this)
], cb);
};
IOSChecker.prototype.getMacOSXVersion = function(cb) {
var msg;
exec("sw_vers -productVersion", function(err, stdout) {
if (err === null) {
if (stdout.match('10.8') !== null) {
@@ -33,14 +33,10 @@ IOSChecker.prototype.getMacOSXVersion = function(cb) {
this.osVersion = '10.9';
cb(null, "Mac OS X 10.9 is installed.");
} else {
msg = "Could not detect Mac OS X Version";
this.log.fail(msg);
cb(msg, msg);
this.log.fail("Could not detect Mac OS X Version", cb);
}
} else {
msg = "Unknown SW Version Command: " + err;
this.log.fail(msg);
cb(msg, msg);
this.log.fail("Unknown SW Version Command: " + err, cb);
}
}.bind(this));
};
@@ -51,9 +47,7 @@ IOSChecker.prototype.checkForXcode = function(cb) {
if (err === null) {
var xcodePath = stdout.replace("\n","");
if(fs.existsSync(xcodePath)) {
msg = "Xcode is installed at " + xcodePath;
this.log.pass(msg);
cb(null, msg);
this.log.pass("Xcode is installed at " + xcodePath, cb);
} else {
msg = "Xcode is not installed.";
this.log.fail(msg);
@@ -82,9 +76,7 @@ IOSChecker.prototype.checkForXcodeCommandLineTools = function(cb) {
if (err === null) {
var match = stdout.match(/install-time/);
if (match !== null) {
msg = "Xcode Command Line Tools are installed.";
this.log.pass(msg);
cb(null, msg);
this.log.pass("Xcode Command Line Tools are installed.", cb);
} else {
msg = "Xcode Command Line Tools are NOT installed.";
this.log.fail(msg);
@@ -110,9 +102,7 @@ IOSChecker.prototype.checkDevToolsSecurity = function(cb) {
var msg;
exec("DevToolsSecurity", { maxBuffer: 524288}, function(err, stdout) {
if (err === null && stdout.match(/enabled/) !== null) {
msg = "DevToolsSecurity is enabled.";
this.log.pass(msg);
cb(null, msg);
this.log.pass("DevToolsSecurity is enabled.", cb);
} else {
msg = 'DevToolsSecurity is not enabled.';
this.log.fail(msg);
@@ -129,9 +119,7 @@ IOSChecker.prototype.checkAuthorizationDB = function(cb) {
var msg;
exec("security authorizationdb read system.privilege.taskport", { maxBuffer: 524288}, function(err, stdout) {
if (err === null && stdout.match(/is-developer/) !== null) {
msg = "The Authorization DB is set up properly.";
this.log.pass(msg);
cb(null, msg);
this.log.pass("The Authorization DB is set up properly.", cb);
} else {
msg = 'The Authorization DB is NOT set up properly.';
this.log.fail(msg);
@@ -144,6 +132,114 @@ IOSChecker.prototype.checkAuthorizationDB = function(cb) {
}.bind(this));
};
IOSChecker.prototype.checkForNodeBinary = function(cb) {
this.checkForNodeBinaryInCommonPlaces(function(err, msg) {
if (!err) {
cb(null, msg);
} else {
this.checkForNodeBinaryUsingWhichCommand(function(err, msg) {
if (!err) {
cb(null, msg);
} else {
this.checkForNodeBinaryUsingAppleScript(function(err, msg) {
if (!err) {
cb(null, msg);
} else {
this.checkForNodeBinaryUsingAppiumConfigFile(function(err, msg) {
if (!err) {
cb(null, msg);
} else {
msg = 'The node binary could not be found.';
this.log.fail(msg);
this.log.promptToFix("The node binary could not be found.", function() {
this.setupNodeBinaryPath(cb);
}.bind(this), function() {
cb(msg, msg);
});
}
}.bind(this));
}
}.bind(this));
}
}.bind(this));
}
}.bind(this));
};
IOSChecker.prototype.checkForNodeBinaryInCommonPlaces = function(cb) {
if (env.NODE_BIN !== null && fs.existsSync(env.NODE_BIN)) {
this.log.pass("Node binary found using NODE_BIN environment variable at " + env.NODE_BIN, cb);
} else if (fs.existsSync('/usr/local/bin/node')) {
this.log.pass("Node binary found at /usr/local/bin/node", cb);
} else if (fs.existsSync('/opt/local/bin/node')) {
this.log.pass("Node binary found at /opt/local/bin/node", cb);
} else {
var msg = 'Node binary could not be found in the usual places';
cb(msg, msg);
}
};
IOSChecker.prototype.checkForNodeBinaryUsingWhichCommand = function(cb) {
var msg;
exec("which node", { maxBuffer: 524288}, function(err, stdout) {
if (err === null && fs.existsSync(stdout.replace("\n",""))) {
this.log.pass("Node binary found using which command at " + stdout.replace("\n",""), cb);
} else {
msg = 'Node binary not found using the which command.';
cb(msg, msg);
}
}.bind(this));
};
IOSChecker.prototype.checkForNodeBinaryUsingAppleScript = function(cb) {
var msg;
var appScript = [
'try'
, ' set appiumIsRunning to false'
, ' tell application "System Events"'
, ' set appiumIsRunning to name of every process contains "Appium"'
, ' end tell'
, ' if appiumIsRunning then'
, ' tell application "Appium" to return node path'
, ' end if'
, 'end try'
, 'return "NULL"'
].join("\n");
exec("osascript -e '" + appScript + "'", { maxBuffer: 524288}, function(err, stdout) {
if (err === null && fs.existsSync(stdout.replace("\n",""))) {
this.log.pass("Node binary found using AppleScript at " + stdout.replace("\n",""), cb);
} else {
msg = 'Node binary not found using AppleScript.';
cb(msg, msg);
}
}.bind(this));
};
IOSChecker.prototype.checkForNodeBinaryUsingAppiumConfigFile = function(cb) {
var msg = 'Node binary not found in the .appiumconfig file.';
var appiumConfigPath = path.resolve(__dirname, "../..", ".appiumconfig");
if (fs.existsSync(appiumConfigPath)) {
fs.readFile(appiumConfigPath, 'utf8', function(err, data) {
if (err === null) {
try {
var jsonobj = JSON.parse(data);
if (jsonobj.node_bin !== undefined && fs.existsSync(jsonobj.node_bin)) {
this.log.pass("Node binary found using .appiumconfig at " + jsonobj.node_bin, cb);
} else {
cb(msg, msg);
}
} catch (jsonErr) {
cb(msg, msg);
}
} else {
cb(msg, msg);
}
}.bind(this));
} else {
cb(msg, msg);
}
};
IOSChecker.prototype.installXcode = function(cb) {
exec("xcode-select --install", { maxBuffer: 524288}, function() {
this.log.promptToConfirmFix(function() {
@@ -162,7 +258,7 @@ IOSChecker.prototype.installXcodeCommandLineTools = function(cb) {
IOSChecker.prototype.authorizeIOS = function(outerCb, innerCb) {
var authorizePath = path.resolve(__dirname, "../../bin", "authorize-ios.js");
exec("'" + process.execPath + "' '" + authorizePath + "'" , { maxBuffer: 524288}, function(err,stdout) {
exec("'" + process.execPath + "' '" + authorizePath + "'" , { maxBuffer: 524288}, function(err) {
if(err) {
this.log.error('Could not authorize iOS: ' + err);
}
@@ -172,3 +268,29 @@ IOSChecker.prototype.authorizeIOS = function(outerCb, innerCb) {
}.bind(this));
}.bind(this));
};
IOSChecker.prototype.setupNodeBinaryPath = function(cb) {
var appiumConfigPath = path.resolve(__dirname, "../../", ".appiumconfig");
if (fs.existsSync(appiumConfigPath)) {
fs.readFile(appiumConfigPath, 'utf8', function(err, data) {
if (!err) {
try {
var jsonobj = JSON.parse(data);
jsonobj.node_bin = process.execPath;
fs.writeFile(appiumConfigPath, JSON.stringify(jsonobj), function() {
this.checkForNodeBinary(cb);
}.bind(this));
} catch (jsonErr) {
this.log.error("Could not setup node binary path in .appiumconfig. Error parsing JSON: " + jsonErr );
this.checkForNodeBinary(cb);
}
} else {
this.log.error("Could not setup node binary path in .appiumconfig. Error reading config: " + err );
this.checkForNodeBinary(cb);
}
}.bind(this));
} else {
this.log.error('The .appiumconfig file was not found at ' + appiumConfigPath);
this.exitDoctor();
}
};