Skip to content
This repository was archived by the owner on Feb 2, 2021. It is now read-only.

Fix getting info for Android tools #906

Merged
merged 2 commits into from
Mar 16, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions declarations.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -852,8 +852,8 @@ interface ISysInfoData {
adbVer: string;
/** Whether iTunes is installed on the machine */
itunesInstalled: boolean;
/** Whether `android` executable can be run */
androidInstalled: boolean;
/** Whether `emulator` executable can be run */
emulatorInstalled: boolean;
/** mono version, relevant on Mac only **/
monoVer: string;
/** git version string, as returned by `git --version` **/
Expand All @@ -875,7 +875,7 @@ interface ISysInfo {
* @param {any} androidToolsInfo Defines paths to adb and android executables.
* @return {Promise<ISysInfoData>} Object containing information for current system.
*/
getSysInfo(pathToPackageJson: string, androidToolsInfo?: { pathToAdb: string, pathToAndroid: string }): Promise<ISysInfoData>;
getSysInfo(pathToPackageJson: string, androidToolsInfo?: { pathToAdb: string }): Promise<ISysInfoData>;

/** Returns Java version. **/
getJavaVersion(): Promise<string>;
Expand Down
1 change: 1 addition & 0 deletions definitions/mobile.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ declare module Mobile {

interface IAndroidEmulatorServices extends IEmulatorPlatformServices {
getAllRunningEmulators(): Promise<string[]>;
pathToEmulatorExecutable: string;
}

interface IiSimDevice {
Expand Down
22 changes: 18 additions & 4 deletions mobile/android/android-emulator-services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,25 @@ class AndroidEmulatorServices implements Mobile.IAndroidEmulatorServices {
this.adbFilePath = await this.$staticConfig.getAdbFilePath();
}

private get pathToEmulatorExecutable(): string {
public get pathToEmulatorExecutable(): string {
if (!this._pathToEmulatorExecutable) {
let androidHome = process.env.ANDROID_HOME;
let emulatorExecutableName = "emulator";
this._pathToEmulatorExecutable = androidHome ? path.join(androidHome, "tools", emulatorExecutableName) : emulatorExecutableName;
const androidHome = process.env.ANDROID_HOME;
const emulatorExecutableName = "emulator";

this._pathToEmulatorExecutable = emulatorExecutableName;

if (androidHome) {
// Check https://developer.android.com/studio/releases/sdk-tools.html (25.3.0)
// Since this version of SDK tools, the emulator is a separate package.
// However the emulator executable still exists in the "tools" dir.
const pathToEmulatorFromAndroidStudio = path.join(androidHome, emulatorExecutableName, emulatorExecutableName);

if (this.$fs.exists(pathToEmulatorFromAndroidStudio)) {
this._pathToEmulatorExecutable = pathToEmulatorFromAndroidStudio;
} else {
this._pathToEmulatorExecutable = path.join(androidHome, "tools", emulatorExecutableName);
}
}
}

return this._pathToEmulatorExecutable;
Expand Down
22 changes: 11 additions & 11 deletions sys-info-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export class SysInfoBase implements ISysInfo {
protected $hostInfo: IHostInfo,
protected $iTunesValidator: Mobile.IiTunesValidator,
protected $logger: ILogger,
protected $winreg: IWinReg) { }
protected $winreg: IWinReg,
protected $androidEmulatorServices: Mobile.IAndroidEmulatorServices) { }

private monoVerRegExp = /version (\d+[.]\d+[.]\d+) /gm;
private sysInfoCache: ISysInfoData = undefined;
Expand Down Expand Up @@ -134,7 +135,7 @@ export class SysInfoBase implements ISysInfo {
return this.cocoapodVersionCache;
}

public async getSysInfo(pathToPackageJson: string, androidToolsInfo?: { pathToAdb: string, pathToAndroid: string }): Promise<ISysInfoData> {
public async getSysInfo(pathToPackageJson: string, androidToolsInfo?: { pathToAdb: string }): Promise<ISysInfoData> {
if (!this.sysInfoCache) {
let res: ISysInfoData = Object.create(null);
let procOutput: string;
Expand Down Expand Up @@ -167,7 +168,6 @@ export class SysInfoBase implements ISysInfo {

res.cocoapodVer = await this.getCocoapodVersion();
let pathToAdb = androidToolsInfo ? androidToolsInfo.pathToAdb : "adb";
let pathToAndroid = androidToolsInfo ? androidToolsInfo.pathToAndroid : "android";

if (!androidToolsInfo) {
this.$logger.trace("'adb' and 'android' will be checked from PATH environment variable.");
Expand All @@ -176,7 +176,7 @@ export class SysInfoBase implements ISysInfo {
procOutput = await this.exec(`${quoteString(pathToAdb)} version`);
res.adbVer = procOutput ? procOutput.split(os.EOL)[0] : null;

res.androidInstalled = await this.checkAndroid(pathToAndroid);
res.emulatorInstalled = await this.checkEmulator();

procOutput = await this.exec("mono --version");
if (!!procOutput) {
Expand Down Expand Up @@ -212,16 +212,16 @@ export class SysInfoBase implements ISysInfo {
return null;
}

// `android -h` returns exit code 1 on successful invocation (Mac OS X for now, possibly Linux). Therefore, we cannot use $childProcess
private async checkAndroid(pathToAndroid: string): Promise<boolean> {
private async checkEmulator(): Promise<boolean> {
let result = false;
try {
if (pathToAndroid) {
let androidChildProcess = await this.$childProcess.spawnFromEvent(pathToAndroid, ["-h"], "close", {}, { throwError: false });
result = androidChildProcess && androidChildProcess.stdout && _.includes(androidChildProcess.stdout, "android");
}
// emulator -help exits with code 1 on Windows, so we should parse the output.
// First line of it should be:
// Android Emulator usage: emulator [options] [-qemu args]
const emulatorHelp = await this.$childProcess.spawnFromEvent(this.$androidEmulatorServices.pathToEmulatorExecutable, ["-help"], "close", {}, { throwError: false });
result = emulatorHelp.stdout.indexOf("usage: emulator") !== -1;
} catch (err) {
this.$logger.trace(`Error while checking is ${pathToAndroid} installed. Error is: ${err.messge}`);
this.$logger.trace(`Error while checking is emulator installed. Error is: ${err.messge}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we will never trace the error message from emulator -help, if there is one, because we set throwError: false on spawnFromEvent. You can check if result is false and trace the message from emulatorHelp.stdout or emulatorHelp.stderr.

}

return result;
Expand Down
26 changes: 15 additions & 11 deletions test/unit-tests/sys-info-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface IChildProcessResults {
nodeGypVersion: IChildProcessResultDescription;
xCodeVersion: IChildProcessResultDescription;
adbVersion: IChildProcessResultDescription;
androidInstalled: IChildProcessResultDescription;
emulatorInstalled: IChildProcessResultDescription;
monoVersion: IChildProcessResultDescription;
gradleVersion: IChildProcessResultDescription;
gitVersion: IChildProcessResultDescription;
Expand All @@ -50,7 +50,7 @@ function createChildProcessResults(childProcessResult: IChildProcessResults): ID
"pod --version": childProcessResult.podVersion,
'"adb" version': childProcessResult.adbVersion,
"'adb' version": childProcessResult.adbVersion, // for Mac and Linux
'android': childProcessResult.androidInstalled,
'emulator': childProcessResult.emulatorInstalled,
"mono --version": childProcessResult.monoVersion,
"git --version": childProcessResult.gitVersion,
"gradle -v": childProcessResult.gradleVersion
Expand Down Expand Up @@ -93,6 +93,10 @@ function createTestInjector(childProcessResult: IChildProcessResults, hostInfoDa

injector.register("sysInfoBase", SysInfoBase);

injector.register("androidEmulatorServices", {
pathToEmulatorExecutable: "emulator"
});

return injector;
}

Expand All @@ -116,7 +120,7 @@ describe("sysInfoBase", () => {
nodeGypVersion: { result: "2.0.0" },
xCodeVersion: { result: "6.4.0" },
adbVersion: { result: "Android Debug Bridge version 1.0.32" },
androidInstalled: { result: { stdout: "android" } },
emulatorInstalled: { result: { stdout: "Android Emulator usage: emulator [options] [-qemu args]" } },
monoVersion: { result: "version 1.0.6 " },
gradleVersion: { result: "Gradle 2.8" },
gitVersion: { result: "git version 1.9.5" },
Expand All @@ -134,7 +138,7 @@ describe("sysInfoBase", () => {
assert.deepEqual(result.javacVersion, "1.8.0_60");
assert.deepEqual(result.nodeGypVer, childProcessResult.nodeGypVersion.result);
assert.deepEqual(result.adbVer, childProcessResult.adbVersion.result);
assert.deepEqual(result.androidInstalled, true);
assert.deepEqual(result.emulatorInstalled, true);
assert.deepEqual(result.monoVer, "1.0.6");
assert.deepEqual(result.gradleVer, "2.8");
assert.deepEqual(result.gitVer, "1.9.5");
Expand Down Expand Up @@ -212,7 +216,7 @@ describe("sysInfoBase", () => {
nodeGypVersion: { shouldThrowError: true },
xCodeVersion: { shouldThrowError: true },
adbVersion: { shouldThrowError: true },
androidInstalled: { shouldThrowError: true },
emulatorInstalled: { shouldThrowError: true },
monoVersion: { shouldThrowError: true },
gradleVersion: { shouldThrowError: true },
gitVersion: { shouldThrowError: true },
Expand All @@ -221,18 +225,18 @@ describe("sysInfoBase", () => {
});

describe("when android info is incorrect", () => {
it("pathToAdb and pathToAndroid are null", async () => {
it("pathToAdb is null", async () => {
childProcessResult.adbVersion = {
result: null
};
childProcessResult.androidInstalled = {
result: false
childProcessResult.emulatorInstalled = {
result: null
};
testInjector = createTestInjector(childProcessResult, { isWindows: false, isDarwin: false, dotNetVersion: "4.5.1" }, null);
sysInfoBase = testInjector.resolve("sysInfoBase");
let result = await sysInfoBase.getSysInfo(toolsPackageJson, { pathToAdb: null, pathToAndroid: null });
let result = await sysInfoBase.getSysInfo(toolsPackageJson, { pathToAdb: null });
assert.deepEqual(result.adbVer, null);
assert.deepEqual(result.androidInstalled, false);
assert.deepEqual(result.emulatorInstalled, false);
});
});

Expand All @@ -246,7 +250,7 @@ describe("sysInfoBase", () => {
assert.deepEqual(result.nodeGypVer, null);
assert.deepEqual(result.xcodeVer, null);
assert.deepEqual(result.adbVer, null);
assert.deepEqual(result.androidInstalled, false);
assert.deepEqual(result.emulatorInstalled, false);
assert.deepEqual(result.monoVer, null);
assert.deepEqual(result.gradleVer, null);
assert.deepEqual(result.gitVer, null);
Expand Down