mirror of
https://github.com/appium/appium.git
synced 2026-02-11 20:39:04 -06:00
finish migrating install logic
This commit is contained in:
@@ -147,6 +147,11 @@ ADB.prototype.exec = function(cmd, cb) {
|
||||
});
|
||||
};
|
||||
|
||||
ADB.prototype.shell = function(cmd, cb) {
|
||||
var execCmd = 'shell ' + cmd;
|
||||
this.exec(execCmd, cb);
|
||||
};
|
||||
|
||||
ADB.prototype.insertSelendroidManifest = function(serverPath, cb) {
|
||||
logger.info("Inserting selendroid manifest");
|
||||
var newServerPath = this.selendroidServerPath
|
||||
@@ -409,7 +414,7 @@ ADB.prototype.checkApkCert = function(apk, cb) {
|
||||
function(cb) { checkKeystoreMD5(cb); },
|
||||
function(cb) { checkApkMD5(cb); }
|
||||
], function() { logger.debug("checkApkCert match? " + match);
|
||||
cb(match); });
|
||||
cb(null, match); });
|
||||
|
||||
// exit checkApkCert
|
||||
return;
|
||||
@@ -421,10 +426,10 @@ ADB.prototype.checkApkCert = function(apk, cb) {
|
||||
exec(resign, { maxBuffer: 524288 }, function(err) {
|
||||
if (err) {
|
||||
logger.debug("App not signed with debug cert.");
|
||||
return cb(false);
|
||||
return cb(null, false);
|
||||
}
|
||||
logger.debug("App already signed.");
|
||||
cb(true);
|
||||
cb(null, true);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -478,7 +483,7 @@ ADB.prototype.getEmulatorPort = function(cb) {
|
||||
};
|
||||
|
||||
ADB.prototype.rimraf = function(path, cb) {
|
||||
this.exec('shell rm -rf ' + path, cb);
|
||||
this.shell('rm -rf ' + path, cb);
|
||||
};
|
||||
|
||||
ADB.prototype.push = function(localPath, remotePath, cb) {
|
||||
@@ -832,7 +837,7 @@ ADB.prototype.waitForDevice = function(cb) {
|
||||
movedOn = true;
|
||||
innerCb(err);
|
||||
} else {
|
||||
this.exec("shell echo 'ready'", function(err) {
|
||||
this.shell("echo 'ready'", function(err) {
|
||||
if (!movedOn) {
|
||||
movedOn = true;
|
||||
if (err) {
|
||||
@@ -1123,101 +1128,38 @@ ADB.prototype.installApk = function(apk, cb) {
|
||||
});
|
||||
};
|
||||
|
||||
ADB.prototype.removeOldApks = function(cb) {
|
||||
var listApks = function(cb) {
|
||||
var cmd = this.adbCmd + ' shell "ls /data/local/tmp/*.apk"';
|
||||
logger.info("listApks: " + cmd);
|
||||
exec(cmd, { maxBuffer: 524288 }, function(err, stdout) {
|
||||
if (err || stdout.indexOf("No such file") !== -1) {
|
||||
return cb(null, []);
|
||||
}
|
||||
|
||||
var apks = stdout.split("\n");
|
||||
cb(null, apks);
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
var removeOtherApks = function(apks, cb) {
|
||||
var matchingApkFound = false;
|
||||
var removeString = "";
|
||||
_.each(apks, function(path) {
|
||||
path = path.trim();
|
||||
if (path.indexOf(this.appMD5) === -1 && path !== '') {
|
||||
removeString += ' rm \\"' + path + '\\";';
|
||||
logger.info("removeOtherApks pushing: " + removeString);
|
||||
} else {
|
||||
matchingApkFound = true;
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
// Invoking adb shell with an empty string will open a shell console
|
||||
// so return here if there's nothing to remove.
|
||||
if (removeString === '') {
|
||||
return cb(null, matchingApkFound);
|
||||
}
|
||||
|
||||
var cmd = this.adbCmd + ' shell "' + removeString + '"';
|
||||
logger.info("removeOtherApks: " + cmd);
|
||||
exec(cmd, { maxBuffer: 524288 }, function(err, stdout) {
|
||||
if (stdout) logger.info(stdout);
|
||||
if (err) logger.info(err);
|
||||
cb(null, matchingApkFound);
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
async.waterfall([
|
||||
function(cb){ listApks(cb); },
|
||||
function(apks, cb) { removeOtherApks(apks, cb); }
|
||||
], function(err, matchingApkFound) { cb(null, matchingApkFound); });
|
||||
ADB.prototype.installRemote = function(remoteApk, cb) {
|
||||
var cmd = 'pm install -r ' + remoteApk;
|
||||
this.shell(cmd, cb);
|
||||
};
|
||||
|
||||
ADB.prototype.installApp = function(apk, cb) {
|
||||
var remotePath = '';
|
||||
ADB.prototype.install = function(apk, cb) {
|
||||
var cmd = 'install -r ' + apk;
|
||||
this.exec(cmd, cb);
|
||||
};
|
||||
|
||||
var getMD5 = function(cb) {
|
||||
fs.readFile(apk, function(err, buffer) {
|
||||
this.appMD5 = md5(buffer);
|
||||
remotePath = '/data/local/tmp/' + this.appMD5 + '.apk';
|
||||
ADB.prototype.mkdir = function(remotePath, cb) {
|
||||
this.shell('mkdir -p ' + remotePath, cb);
|
||||
};
|
||||
|
||||
ADB.prototype.checkAndSignApk = function(apk, cb) {
|
||||
this.checkApkCert(apk, function(err, appSigned) {
|
||||
if (err) return cb(err);
|
||||
if (!appSigned) {
|
||||
this.sign([apk], cb);
|
||||
} else {
|
||||
cb();
|
||||
}.bind(this));
|
||||
}.bind(this);
|
||||
|
||||
var makeFolder = function(cb) {
|
||||
this.exec('shell "mkdir /data/local/tmp/"', cb);
|
||||
}.bind(this);
|
||||
|
||||
var pushApp = function(cb) {
|
||||
this.push(apk, remotePath, cb);
|
||||
}.bind(this);
|
||||
|
||||
var installFromDevice = function(cb) {
|
||||
var cmd = 'shell "pm install -r ' + remotePath + '"';
|
||||
this.exec(cmd, cb);
|
||||
}.bind(this);
|
||||
|
||||
var signLocalApk = function(cb) {
|
||||
this.checkApkCert(apk, function(appSigned) {
|
||||
if (!appSigned) {
|
||||
this.sign([apk], cb);
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this);
|
||||
|
||||
async.waterfall([
|
||||
function(cb) { signLocalApk(cb); },
|
||||
function(cb) { makeFolder(cb); },
|
||||
function(cb) { getMD5(cb); },
|
||||
function(cb) { this.removeOldApks(cb); }.bind(this),
|
||||
// If the apk is already on device, then don't push it again.
|
||||
function(matchingApkFound, cb) {
|
||||
if (matchingApkFound) { cb(null); } else { pushApp(cb); }
|
||||
},
|
||||
function(cb) {
|
||||
installFromDevice(cb);
|
||||
}
|
||||
], cb);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
||||
ADB.prototype.pushAndInstallApp = function(apk, remoteApk, cb) {
|
||||
this.push(apk, remoteApk, function(err) {
|
||||
if (err) return err;
|
||||
this.installRemote(remoteApk, cb);
|
||||
});
|
||||
};
|
||||
|
||||
ADB.prototype.runFastReset = function(cb) {
|
||||
@@ -1250,8 +1192,8 @@ ADB.prototype.isAppInstalled = function(pkg, cb) {
|
||||
var installed = false;
|
||||
|
||||
logger.debug("Getting install status for " + pkg);
|
||||
var listPkgCmd = "shell pm list packages -3 " + pkg;
|
||||
this.exec(listPkgCmd, function(err, stdout) {
|
||||
var listPkgCmd = "pm list packages -3 " + pkg;
|
||||
this.shell(listPkgCmd, function(err, stdout) {
|
||||
if (err) return cb(err);
|
||||
var apkInstalledRgx = new RegExp('^package:' +
|
||||
pkg.replace(/([^a-zA-Z])/g, "\\$1") + '$', 'm');
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
var logger = require('../../server/logger.js').get('appium')
|
||||
, _ = require('underscore')
|
||||
, fs = require('fs')
|
||||
, md5 = require('MD5')
|
||||
, async = require('async');
|
||||
|
||||
var androidCommon = {};
|
||||
@@ -74,44 +75,100 @@ androidCommon.prepareActiveDevice = function(cb) {
|
||||
};
|
||||
|
||||
androidCommon.installApp = function(cb) {
|
||||
var installApp = false;
|
||||
|
||||
if (this.apkPath === null) {
|
||||
logger.info("Not installing app since we launched with a package instead " +
|
||||
logger.info("Skipping install since we launched with a package instead " +
|
||||
"of an app path");
|
||||
return cb();
|
||||
}
|
||||
|
||||
var determineInstallStatus = function(cb) {
|
||||
logger.info("Determining app install");
|
||||
this.adb.isAppInstalled(this.appPackage, function(err, installed) {
|
||||
installApp = !installed;
|
||||
cb();
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
var doInstall = function(cb) {
|
||||
if (installApp) {
|
||||
this.debug("Installing app apk");
|
||||
this.adb.installApp(this.apkPath, cb);
|
||||
this.adb.isAppInstalled(this.appPackage, function(err, installed) {
|
||||
if (installed && this.fastReset) {
|
||||
this.runFastReset(cb);
|
||||
} else if (!installed) {
|
||||
this.adb.checkAndSignApk(this.apkPath, function(err) {
|
||||
if (err) return cb(err);
|
||||
this.adb.mkdir(this.remoteTempPath(), function(err) {
|
||||
if (err) return cb(err);
|
||||
this.getAppMd5(function(err, md5) {
|
||||
var remoteApk = this.remoteTempPath() + md5 + '.apk';
|
||||
if (err) return cb(err);
|
||||
this.removeTempApks([md5], function(err, appExists) {
|
||||
if (err) return cb(err);
|
||||
if (appExists) return cb();
|
||||
this.adb.pushAndInstallApp(this.apkPath, remoteApk, cb);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
var doFastReset = function(cb) {
|
||||
// App is already installed so reset it.
|
||||
if (!installApp && this.fastReset) {
|
||||
this.runFastReset(cb);
|
||||
} else { cb(null); }
|
||||
}.bind(this);
|
||||
|
||||
async.series([
|
||||
function(cb) { determineInstallStatus(cb); },
|
||||
function(cb) { doInstall(cb); },
|
||||
function(cb) { doFastReset(cb); }
|
||||
], cb);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
androidCommon.getAppMd5 = function(cb) {
|
||||
fs.readFile(this.apkPath, function(err, buffer) {
|
||||
if (err) return cb(err);
|
||||
cb(md5(buffer));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
androidCommon.remoteTempPath = function() {
|
||||
return "/data/local/tmp/";
|
||||
};
|
||||
|
||||
androidCommon.removeTempApks = function(exceptMd5s, cb) {
|
||||
if (typeof exceptMd5s === "function") {
|
||||
cb = exceptMd5s;
|
||||
exceptMd5s = [];
|
||||
}
|
||||
|
||||
var listApks = function(cb) {
|
||||
var cmd = 'ls /data/local/tmp/*.apk';
|
||||
this.adb.shell(cmd, function(err, stdout) {
|
||||
if (err || stdout.indexOf("No such file") !== -1) {
|
||||
return cb(null, []);
|
||||
}
|
||||
var apks = stdout.split("\n");
|
||||
cb(null, apks);
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
var removeApks = function(apks, cb) {
|
||||
var matchingApkFound = false;
|
||||
var noMd5Matched = true;
|
||||
var removes = [];
|
||||
_.each(apks, function(path) {
|
||||
path = path.trim();
|
||||
noMd5Matched = true;
|
||||
_.each(exceptMd5s, function(md5) {
|
||||
if (path !== '' && path.indexOf(md5) !== -1) {
|
||||
noMd5Matched = false;
|
||||
}
|
||||
});
|
||||
if (noMd5Matched) {
|
||||
removes.push('rm \\"' + path + '\\"');
|
||||
} else {
|
||||
matchingApkFound = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Invoking adb shell with an empty string will open a shell console
|
||||
// so return here if there's nothing to remove.
|
||||
if (removes.length < 1) {
|
||||
return cb(null, matchingApkFound);
|
||||
}
|
||||
|
||||
var cmd = removes.join[" && "];
|
||||
this.adb.shell(cmd, function() {
|
||||
cb(null, matchingApkFound);
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
async.waterfall([
|
||||
function(cb) { listApks(cb); },
|
||||
function(apks, cb) { removeApks(apks, cb); }
|
||||
], function(err, matchingApkFound) { cb(null, matchingApkFound); });
|
||||
};
|
||||
|
||||
module.exports = androidCommon;
|
||||
|
||||
@@ -4,7 +4,6 @@ var uuid = require('uuid-js')
|
||||
, fs = require('fs')
|
||||
, _ = require('underscore')
|
||||
, status = require("../../server/status.js")
|
||||
, async = require('async')
|
||||
, logger = require('../../server/logger.js').get('appium')
|
||||
, helpers = require('../../helpers.js')
|
||||
, escapeSpecialChars = helpers.escapeSpecialChars
|
||||
|
||||
Reference in New Issue
Block a user