Skip to content

Commit ef235f1

Browse files
author
Fatme
authored
Merge pull request #27 from NativeScript/fatme/ns-cli-integration
Integrate doctor package in {N} CLI
2 parents 361a443 + c4374c5 commit ef235f1

File tree

6 files changed

+193
-33
lines changed

6 files changed

+193
-33
lines changed

README.md

+23-9
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,19 @@ Library that helps identifying if the environment can be used for development of
9999
console.log("mono: ", monoVersion);
100100

101101
const nodeVersion = await sysInfo.getNodeVersion();
102-
console.log("node: ", nodeVer);
102+
console.log("node: ", nodeVersion);
103+
104+
const npmVersion = await sysInfo.getNpmVersion();
105+
console.log("npm: ", npmVersion);
103106

104107
const nodeGypVersion = await sysInfo.getNodeGypVersion();
105108
console.log("node-gyp: ", nodeGypVersion);
106109

107110
const osName = await sysInfo.getOs();
108111
console.log("os: ", osName);
109112

110-
const xcodeprojGemLocation = await sysInfo.getXCodeProjGemLocation();
111-
console.log("xcodeproj gem location: ", xcodeprojGemLocation);
113+
const xcodeprojLocation = await sysInfo.getXCodeProjLocation();
114+
console.log("xcodeproj location: ", xcodeprojLocation);
112115

113116
const xcodeVersion = await sysInfo.getXCodeVersion();
114117
console.log("xcode: ", xcodeVersion);
@@ -131,6 +134,9 @@ Library that helps identifying if the environment can be used for development of
131134
const isCocoaPodsUpdateRequired = await sysInfo.isCocoaPodsUpdateRequired();
132135
console.log("is CocoaPods update required: ", isCocoaPodsUpdateRequired);
133136

137+
const pythonInfo = await sysInfo.getPythonInfo();
138+
console.log("python info: ", pythonInfo );
139+
134140
const sysInfoData = await sysInfo.getSysInfo();
135141
console.log("sysInfo: ", sysInfoData);
136142

@@ -166,17 +172,23 @@ Library that helps identifying if the environment can be used for development of
166172
*/
167173
getNodeVersion(): Promise<string>;
168174

175+
/**
176+
* Returns the currently installed npm version.
177+
* @return {Promise<string>} Returns the currently installed npm version.
178+
*/
179+
getNpmVersion(): Promise<string>;
180+
169181
/**
170182
* Returns the currently installed node-gyp version.
171183
* @return {Promise<string>} Returns the currently installed node-gyp version. If node-gyp is not installed it will return null.
172184
*/
173185
getNodeGypVersion(): Promise<string>;
174186

175187
/**
176-
* Returns the xcodeproj gem location.
177-
* @return {Promise<string>} Returns the xcodeproj gem location. If the the xcodeproj gem is not installed it will return null.
188+
* Returns the xcodeproj location.
189+
* @return {Promise<string>} Returns the xcodeproj location. If the the xcodeproj is not installed it will return null.
178190
*/
179-
getXcodeprojGemLocation(): Promise<string>;
191+
getXcodeprojLocation(): Promise<string>;
180192

181193
/**
182194
* Checks if iTunes is installed.
@@ -198,9 +210,10 @@ Library that helps identifying if the environment can be used for development of
198210

199211
/**
200212
* Returns the currently installed ADB version.
213+
* @param {string} pathToAdb Defines path to adb
201214
* @return {Promise<string>} Returns the currently installed ADB version. It will return null if ADB is not installed.
202215
*/
203-
getAdbVersion(): Promise<string>;
216+
getAdbVersion(pathToAdb?: string): Promise<string>;
204217

205218
/**
206219
* Checks if Android is installed.
@@ -258,9 +271,10 @@ Library that helps identifying if the environment can be used for development of
258271

259272
/**
260273
* Returns the whole system information.
274+
* @param {ISysInfoConfig} config
261275
* @return {Promise<ISysInfoData>} The system information.
262276
*/
263-
getSysInfo(): Promise<ISysInfoData>;
277+
getSysInfo(config?: ISysInfoConfig): Promise<ISysInfoData>;
264278

265279
/**
266280
* If set to true each method will cache it's result. The default value is true.
@@ -386,7 +400,7 @@ Library that helps identifying if the environment can be used for development of
386400
* xcodeproj gem location, as returned by `which gem xcodeproj`.
387401
* @type {string}
388402
*/
389-
xcodeprojGemLocation: string;
403+
xcodeprojLocation: string;
390404

391405
/**
392406
* true id CocoaPods can successfully execute pod install.

lib/doctor.ts

+20-3
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ export class Doctor implements NativeScriptDoctor.IDoctor {
2828
return false;
2929
}
3030

31-
public async getWarnings(): Promise<NativeScriptDoctor.IWarning[]> {
31+
public async getWarnings(config?: NativeScriptDoctor.ISysInfoConfig): Promise<NativeScriptDoctor.IWarning[]> {
3232
let result: NativeScriptDoctor.IWarning[] = [];
33-
const sysInfoData = await this.sysInfo.getSysInfo();
33+
const sysInfoData = await this.sysInfo.getSysInfo(config);
3434

3535
const androidHomeValidationErrors = this.androidToolsInfo.validateAndroidHomeEnvVariable();
3636
if (androidHomeValidationErrors.length > 0) {
@@ -78,7 +78,7 @@ export class Doctor implements NativeScriptDoctor.IDoctor {
7878
});
7979
}
8080

81-
if (!sysInfoData.xcodeprojGemLocation) {
81+
if (!sysInfoData.xcodeprojLocation) {
8282
result.push({
8383
warning: "WARNING: xcodeproj gem is not installed or is not configured properly.",
8484
additionalInformation: "You will not be able to build your projects for iOS." + EOL
@@ -123,6 +123,23 @@ export class Doctor implements NativeScriptDoctor.IDoctor {
123123
platforms: [Constants.IOS_PLATFORM_NAME]
124124
});
125125
}
126+
127+
if (!sysInfoData.pythonInfo.isInstalled) {
128+
result.push({
129+
warning: `WARNING: Couldn't retrieve installed python packages.`,
130+
additionalInformation: "We cannot verify your python installation is setup correctly. Please, make sure you have both 'python' and 'pip' installed." + EOL
131+
+ `Error while validating Python packages. Error is: ${sysInfoData.pythonInfo.installationErrorMessage}`,
132+
platforms: [Constants.IOS_PLATFORM_NAME]
133+
});
134+
}
135+
136+
if (!sysInfoData.pythonInfo.isSixPackageInstalled) {
137+
result.push({
138+
warning: `WARNING: The Python 'six' package not found.`,
139+
additionalInformation: "This package is required by the Debugger library (LLDB) for iOS. You can install it by first making sure you have pip installed and then running 'pip install six' from the terminal.",
140+
platforms: [Constants.IOS_PLATFORM_NAME]
141+
});
142+
}
126143
} else {
127144
result.push({
128145
warning: "NOTE: You can develop for iOS only on Mac OS X systems.",

lib/local-build-requirements/ios-local-build-requirements.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export class IosLocalBuildRequirements {
77
public async checkRequirements(): Promise<boolean> {
88
if (!this.hostInfo.isDarwin ||
99
!await this.sysInfo.getXcodeVersion() ||
10-
!await this.sysInfo.getXcodeprojGemLocation()) {
10+
!await this.sysInfo.getXcodeprojLocation()) {
1111
return false;
1212
}
1313

lib/sys-info.ts

+36-11
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
2525
private npmVerCache: string;
2626
private nodeVerCache: string;
2727
private nodeGypVerCache: string;
28-
private xCodeprojGemLocationCache: string;
28+
private xCodeprojLocationCache: string;
2929
private iTunesInstalledCache: boolean;
3030
private cocoaPodsVerCache: string;
3131
private osCache: string;
@@ -38,6 +38,7 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
3838
private isCocoaPodsWorkingCorrectlyCache: boolean;
3939
private nativeScriptCliVersionCache: string;
4040
private xcprojInfoCache: NativeScriptDoctor.IXcprojInfo;
41+
private pythonInfoCache: NativeScriptDoctor.IPythonInfo;
4142
private isCocoaPodsUpdateRequiredCache: boolean;
4243
private shouldCache: boolean = true;
4344
private isAndroidSdkConfiguredCorrectlyCache: boolean;
@@ -102,9 +103,9 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
102103
});
103104
}
104105

105-
public getXcodeprojGemLocation(): Promise<string> {
106-
return this.getValueForProperty(() => this.xCodeprojGemLocationCache, async (): Promise<string> => {
107-
const output = await this.execCommand("gem which xcodeproj");
106+
public getXcodeprojLocation(): Promise<string> {
107+
return this.getValueForProperty(() => this.xCodeprojLocationCache, async (): Promise<string> => {
108+
const output = await this.execCommand("which xcodeproj");
108109
return output ? output.trim() : null;
109110
});
110111
}
@@ -152,12 +153,13 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
152153
});
153154
}
154155

155-
public getAdbVersion(): Promise<string> {
156+
public getAdbVersion(pathToAdb?: string): Promise<string> {
156157
return this.getValueForProperty(() => this.adbVerCache, async (): Promise<string> => {
157158
let output: IProcessInfo = null;
158-
const pathToAdbFromAndroidHome = await this.androidToolsInfo.getPathToAdbFromAndroidHome();
159-
if (pathToAdbFromAndroidHome) {
160-
output = await this.childProcess.spawnFromEvent(pathToAdbFromAndroidHome, ["version"], "close", { ignoreError: true });
159+
160+
pathToAdb = pathToAdb || await this.androidToolsInfo.getPathToAdbFromAndroidHome();
161+
if (pathToAdb) {
162+
output = await this.childProcess.spawnFromEvent(pathToAdb, ["version"], "close", { ignoreError: true });
161163
}
162164

163165
return output && output.stdout ? this.getVersionFromString(output.stdout) : null;
@@ -213,7 +215,7 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
213215
});
214216
}
215217

216-
public getSysInfo(): Promise<NativeScriptDoctor.ISysInfoData> {
218+
public getSysInfo(config?: NativeScriptDoctor.ISysInfoConfig): Promise<NativeScriptDoctor.ISysInfoData> {
217219
return this.getValueForProperty(() => this.sysInfoCache, async (): Promise<NativeScriptDoctor.ISysInfoData> => {
218220
const result: NativeScriptDoctor.ISysInfoData = Object.create(null);
219221

@@ -231,10 +233,10 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
231233
result.dotNetVer = await this.hostInfo.dotNetVersion();
232234
result.javacVersion = await this.getJavaCompilerVersion();
233235
result.xcodeVer = await this.getXcodeVersion();
234-
result.xcodeprojGemLocation = await this.getXcodeprojGemLocation();
236+
result.xcodeprojLocation = await this.getXcodeprojLocation();
235237
result.itunesInstalled = await this.isITunesInstalled();
236238
result.cocoaPodsVer = await this.getCocoaPodsVersion();
237-
result.adbVer = await this.getAdbVersion();
239+
result.adbVer = await this.getAdbVersion(config && config.androidToolsInfo && config.androidToolsInfo.pathToAdb);
238240
result.androidInstalled = await this.isAndroidInstalled();
239241
result.monoVer = await this.getMonoVersion();
240242
result.gitVer = await this.getGitVersion();
@@ -246,6 +248,8 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
246248
result.isCocoaPodsUpdateRequired = await this.isCocoaPodsUpdateRequired();
247249
result.isAndroidSdkConfiguredCorrectly = await this.isAndroidSdkConfiguredCorrectly();
248250

251+
result.pythonInfo = await this.getPythonInfo();
252+
249253
return result;
250254
});
251255
}
@@ -307,6 +311,27 @@ export class SysInfo implements NativeScriptDoctor.ISysInfo {
307311
});
308312
}
309313

314+
public getPythonInfo(): Promise<NativeScriptDoctor.IPythonInfo> {
315+
return this.getValueForProperty(() => this.pythonInfoCache, async (): Promise<NativeScriptDoctor.IPythonInfo> => {
316+
if (this.hostInfo.isDarwin) {
317+
try {
318+
await this.childProcess.exec(`python -c "import six"`);
319+
} catch (error) {
320+
// error.code = 1 so the Python is present, but we don't have six.
321+
if (error.code === 1) {
322+
return { isInstalled: true, isSixPackageInstalled: false };
323+
}
324+
325+
return { isInstalled: false, isSixPackageInstalled: false, installationErrorMessage: error.message };
326+
}
327+
328+
return { isInstalled: true, isSixPackageInstalled: true };
329+
}
330+
331+
return null;
332+
});
333+
}
334+
310335
public isCocoaPodsUpdateRequired(): Promise<boolean> {
311336
return this.getValueForProperty(() => this.isCocoaPodsUpdateRequiredCache, async (): Promise<boolean> => {
312337
let xcprojInfo = await this.getXcprojInfo();

test/sys-info.ts

+54-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const PROGRAM_FILES_ENV_PATH = "C:\\Program Files";
1313
interface IChildProcessResultDescription {
1414
result?: any;
1515
shouldThrowError?: boolean;
16+
errorCode?: number;
1617
}
1718

1819
interface ICLIOutputVersionTestCase {
@@ -37,6 +38,7 @@ interface IChildProcessResults {
3738
pod: IChildProcessResultDescription;
3839
nativeScriptCliVersion: IChildProcessResultDescription;
3940
git: IChildProcessResultDescription;
41+
pythonInfo?: IChildProcessResultDescription;
4042
}
4143

4244
interface IHostInfoMockOptions {
@@ -92,7 +94,8 @@ function createChildProcessResults(childProcessResult: IChildProcessResults): ID
9294
"gradle -v": childProcessResult.gradleVersion,
9395
"tns --version": childProcessResult.nativeScriptCliVersion,
9496
"emulator": { shouldThrowError: false },
95-
"which git": childProcessResult.git
97+
"which git": childProcessResult.git,
98+
'python -c "import six"': childProcessResult.pythonInfo
9699
};
97100
}
98101

@@ -101,7 +104,12 @@ function getResultFromChildProcess(childProcessResultDescription: IChildProcessR
101104
if (options && options.ignoreError) {
102105
return null;
103106
} else {
104-
throw new Error(`This one throws error. (${command})`);
107+
const error = new Error(`This one throws error. (${command})`);
108+
if (childProcessResultDescription.errorCode) {
109+
(<any>error).code = childProcessResultDescription.errorCode;
110+
}
111+
112+
throw error;
105113
}
106114
}
107115

@@ -331,6 +339,50 @@ describe("SysInfo unit tests", () => {
331339
});
332340
});
333341

342+
describe("when android info is incorrect", () => {
343+
it("pathToAdb is null", async () => {
344+
childProcessResult.adbVersion = {
345+
result: null
346+
};
347+
sysInfo = mockSysInfo(childProcessResult, { isWindows: false, isDarwin: false, dotNetVersion: "4.5.1"}, null);
348+
const adbVersion = await sysInfo.getAdbVersion();
349+
const isAndroidSdkConfiguredCorrectly = await sysInfo.isAndroidSdkConfiguredCorrectly();
350+
assert.deepEqual(adbVersion, null);
351+
assert.deepEqual(isAndroidSdkConfiguredCorrectly, undefined);
352+
});
353+
});
354+
355+
describe("pythonInfo", () => {
356+
it("should return null when platform is windows", async () => {
357+
sysInfo = mockSysInfo(childProcessResult, { isWindows: true, isDarwin: false, dotNetVersion: "4.5.1"}, null);
358+
const pythonInfo = await sysInfo.getPythonInfo();
359+
assert.deepEqual(pythonInfo, null);
360+
});
361+
it("should return null when platform is linux", async () => {
362+
sysInfo = mockSysInfo(childProcessResult, { isWindows: false, isDarwin: false, dotNetVersion: "4.5.1"}, null);
363+
const pythonInfo = await sysInfo.getPythonInfo();
364+
assert.deepEqual(pythonInfo, null);
365+
});
366+
it("should return {isInstalled: true, isSixPackageInstalled: true} when python is correctly installed on Mac", async () => {
367+
childProcessResult.pythonInfo = { result: "" };
368+
sysInfo = mockSysInfo(childProcessResult, { isWindows: false, isDarwin: true, dotNetVersion: "4.5.1" }, null);
369+
const pythonInfo = await sysInfo.getPythonInfo();
370+
assert.deepEqual(pythonInfo, { isInstalled: true, isSixPackageInstalled: true });
371+
});
372+
it("should return {isInstalled: false, isSixPackageInstalled: false} when python check throws an error", async () => {
373+
childProcessResult.pythonInfo = { shouldThrowError: true };
374+
sysInfo = mockSysInfo(childProcessResult, { isWindows: false, isDarwin: true, dotNetVersion: "4.5.1" }, null);
375+
const pythonInfo = await sysInfo.getPythonInfo();
376+
assert.deepEqual(pythonInfo, { isInstalled: false, isSixPackageInstalled: false, installationErrorMessage: "This one throws error. (python -c \"import six\")" });
377+
});
378+
it("should return {isInstalled: true, isSixPackageInstalled: false} when python is installed but six package is not", async () => {
379+
childProcessResult.pythonInfo = { shouldThrowError: true, errorCode: 1 };
380+
sysInfo = mockSysInfo(childProcessResult, { isWindows: false, isDarwin: true, dotNetVersion: "4.5.1"}, null);
381+
const pythonInfo = await sysInfo.getPythonInfo();
382+
assert.deepEqual(pythonInfo, { isInstalled: true, isSixPackageInstalled: false });
383+
});
384+
});
385+
334386
const testData: ICLIOutputVersionTestCase[] = [
335387
{
336388
testedProperty: "nativeScriptCliVersion",

0 commit comments

Comments
 (0)