added adb controller in node and some grunt utilities

This commit is contained in:
Jonathan Lipps
2013-02-26 11:11:36 -08:00
parent a797b3e5be
commit c4523950e8
5 changed files with 201 additions and 0 deletions

View File

@@ -7,6 +7,8 @@ var path = require('path')
, tail = gruntHelpers.tail
, buildApp = gruntHelpers.buildApp
, signApp = gruntHelpers.signApp
, setupAndroidBootstrap = gruntHelpers.setupAndroidBootstrap
, buildAndroidBootstrap = gruntHelpers.buildAndroidBootstrap
, runTestsWithServer = gruntHelpers.runTestsWithServer;
module.exports = function(grunt) {
@@ -90,4 +92,16 @@ module.exports = function(grunt) {
grunt.registerTask('log', "Tail appium.log", function() {
tail(grunt, path.resolve(__dirname, "appium.log"), this.async());
});
grunt.registerTask('configAndroidBootstrap', function() {
var cb = this.async();
setupAndroidBootstrap(grunt, function(exitCode) {
cb(exitCode === 0);
});
});
grunt.registerTask('buildAndroidBootstrap', function() {
var cb = this.async();
buildAndroidBootstrap(grunt, function(exitCode) {
cb(exitCode === 0);
});
});
};

View File

@@ -245,3 +245,54 @@ module.exports.downloadUICatalog = function(cb) {
});
});
};
module.exports.setupAndroidBootstrap = function(grunt, cb) {
if (!process.env.ANDROID_HOME) {
grunt.fatal("Could not find Android SDK, make sure to export ANDROID_HOME");
}
var cmd = path.resolve(process.env.ANDROID_HOME, "tools", "android");
var projPath = path.resolve(__dirname, "uiautomator", "bootstrap");
var args = ["create", "uitest-project", "-n", "AppiumBootstrap", "-t",
"android-17", "-p", "."];
var proc = spawn(cmd, args, {cwd: projPath});
proc.stdout.setEncoding('utf8');
proc.stderr.setEncoding('utf8');
proc.stdout.on('data', function(data) {
grunt.log.write(data);
});
proc.stderr.on('data', function(data) {
grunt.log.write(data);
});
proc.on('exit', function(code) {
cb(code);
});
};
module.exports.buildAndroidBootstrap = function(grunt, cb) {
exec('which ant', function(err, stdout) {
if (err) {
grunt.fatal(err);
} else {
if (stdout) {
var ant = stdout.trim();
grunt.log.write("Using ant found at " + ant);
var projPath = path.resolve(__dirname, "uiautomator", "bootstrap");
var proc = spawn(ant, ["build"], {cwd: projPath});
proc.stdout.setEncoding('utf8');
proc.stderr.setEncoding('utf8');
proc.stdout.on('data', function(data) {
grunt.log.write(data);
});
proc.stderr.on('data', function(data) {
grunt.log.write(data);
});
proc.on('exit', function(code) {
cb(code);
});
} else {
grunt.fatal("Could not find ant installed; please make sure it's on PATH");
}
}
});
};

115
uiautomator/adb.js Normal file
View File

@@ -0,0 +1,115 @@
"use strict";
var spawn = require('child_process').spawn
, exec = require('child_process').exec
, path = require('path')
, logger = require('../logger').get('appium')
, _ = require('underscore');
var ADB = function(opts, cb) {
if (!opts) {
opts = {};
}
if (typeof opts.sdkRoot === "undefined") {
opts.sdkRoot = process.env.ANDROID_HOME || '';
}
this.sdkRoot = opts.sdkRoot;
this.avdName = opts.avdName;
this.adb = "adb";
this.curDeviceId = null;
if (this.sdkRoot) {
this.adb = path.resolve(this.sdkRoot, "platform-tools", "adb");
logger.info("Using adb from " + this.adb);
cb(null, this);
} else {
exec("which adb", _.bind(function(err, stdout) {
if (stdout) {
logger.info("Using adb from " + stdout);
this.adb = stdout;
cb(null, this);
} else {
cb("Could not find adb; do you have android SDK installed?", null);
}
}, this));
}
};
ADB.prototype.getConnectedDevices = function(cb) {
logger.info("Getting connected devices...");
exec(this.adb + " devices", _.bind(function(err, stdout) {
if (err) {
logger.error(err);
cb(err);
} else {
var output = stdout.replace("List of devices attached", "").trim();
var devices = [];
_.each(output.split("\n"), function(device) {
if (device) {
devices.push(device.split("\t"));
}
});
logger.info("\t" + devices.length + " device(s) connected");
if (devices.length) {
this.curDeviceId = devices[0][0];
}
cb(null, devices);
}
}, this));
};
ADB.prototype.forwardPort = function(systemPort, devicePort) {
};
ADB.prototype.isDeviceConnected = function(cb) {
this.getConnectedDevices(function(err, devices) {
if (err) {
cb(err);
} else {
cb(null, devices.length > 0);
}
});
};
ADB.prototype.setDeviceId = function(deviceId) {
this.curDeviceId = deviceId;
};
ADB.prototype.requireDeviceId = function() {
if (!this.curDeviceId) {
throw new Error("This method requires that a device ID is set. " +
"Call getConnectedDevices or setDeviceId");
}
};
ADB.prototype.waitForDevice = function(cb) {
this.requireDeviceId();
logger.info("Waiting for device " + this.curDeviceId + " to be ready");
exec(this.adb + " -s " + this.curDeviceId + " wait-for-device", function(err) {
if (err) {
logger.error(err);
cb(err);
} else {
logger.info("\tready!");
cb(null);
}
});
};
ADB.prototype.pushAppium = function(cb) {
logger.info("Pushing appium bootstrap to device...");
var binPath = path.resolve(__dirname, "bootstrap", "bin", "AppiumBootstrap.jar");
var remotePath = "/data/local/tmp";
exec(this.adb + " push " + binPath + " " + remotePath, function(err) {
if (err) {
logger.error(err);
cb(err);
} else {
logger.info("\tdone");
cb(null);
}
});
};
module.exports = function(opts, cb) {
return new ADB(opts, cb);
};

21
uiautomator/example.js Normal file
View File

@@ -0,0 +1,21 @@
"use strict";
var makeAdb = require('./adb');
var adbOpts = {
sdkRoot: process.env.ANDROID_HOME
, avd: "jlipps1"
};
makeAdb(adbOpts, function(err, adb) {
adb.getConnectedDevices(function(err, devices) {
if (devices.length) {
adb.waitForDevice(function(err) {
adb.pushAppium(function(err) {
});
});
} else {
console.log("Can't proceed without a connected device!");
process.exit(1);
}
});
});