Skip to content

Commit b5c2134

Browse files
Merge pull request #8 from NativeScript/milanov/update-doctor-checks
Update doctor checks
2 parents 55cbe20 + 5ec1b66 commit b5c2134

File tree

7 files changed

+439
-295
lines changed

7 files changed

+439
-295
lines changed

Gruntfile.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ module.exports = function (grunt) {
44
options: grunt.file.readJSON("tsconfig.json").compilerOptions,
55

66
devlib: {
7-
src: ["lib/**/*.ts"],
7+
src: ["lib/**/*.ts", "typings/**/*.ts"],
88
reference: "lib/.d.ts"
99
},
1010

1111
devall: {
12-
src: ["lib/**/*.ts", "test/**/*.ts"],
12+
src: ["lib/**/*.ts", "test/**/*.ts", "typings/**/*.ts"],
1313
reference: "lib/.d.ts"
1414
},
1515

1616
release_build: {
17-
src: ["lib/**/*.ts", "test/**/*.ts"],
17+
src: ["lib/**/*.ts", "test/**/*.ts", "typings/**/*.ts"],
1818
reference: "lib/.d.ts",
1919
options: {
2020
sourceMap: false,
@@ -26,7 +26,7 @@ module.exports = function (grunt) {
2626
tslint: {
2727
build: {
2828
files: {
29-
src: ["lib/**/*.ts", "test/**/*.ts", "!**/*.d.ts"]
29+
src: ["lib/**/*.ts", "test/**/*.ts", "typings/**/*.ts", "!**/*.d.ts"]
3030
},
3131
options: {
3232
configuration: grunt.file.readJSON("./tslint.json")

lib/doctor.ts

+32-15
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ import { HostInfo } from "./host-info";
55
import { AndroidLocalBuildRequirements } from "./local-build-requirements/android-local-build-requirements";
66
import { IosLocalBuildRequirements } from "./local-build-requirements/ios-local-build-requirements";
77
import { Helpers } from "./helpers";
8-
import { IWarning } from "../typings/nativescript-doctor";
98
import * as semver from "semver";
109

11-
export class Doctor {
10+
export class Doctor implements NativeScriptDoctor.IDoctor {
1211
private static MIN_SUPPORTED_POD_VERSION = "0.38.2";
1312

1413
constructor(private androidLocalBuildRequirements: AndroidLocalBuildRequirements,
@@ -29,8 +28,8 @@ export class Doctor {
2928
return false;
3029
}
3130

32-
public async getWarnings(): Promise<IWarning[]> {
33-
const result: IWarning[] = [];
31+
public async getWarnings(): Promise<NativeScriptDoctor.IWarning[]> {
32+
const result: NativeScriptDoctor.IWarning[] = [];
3433
const sysInfoData = await this.sysInfo.getSysInfo();
3534

3635
if (!sysInfoData.adbVer) {
@@ -39,7 +38,8 @@ export class Doctor {
3938
additionalInformation: "For Android-related operations, the AppBuilder CLI will use a built-in version of adb." + EOL
4039
+ "To avoid possible issues with the native Android emulator, Genymotion or connected" + EOL
4140
+ "Android devices, verify that you have installed the latest Android SDK and" + EOL
42-
+ "its dependencies as described in http://developer.android.com/sdk/index.html#Requirements" + EOL
41+
+ "its dependencies as described in http://developer.android.com/sdk/index.html#Requirements" + EOL,
42+
platforms: [Constants.ANDROID_PLATFORM_NAME]
4343
});
4444
}
4545

@@ -48,7 +48,8 @@ export class Doctor {
4848
warning: "WARNING: The Android SDK is not installed or is not configured properly.",
4949
additionalInformation: "You will not be able to run your apps in the native emulator. To be able to run apps" + EOL
5050
+ "in the native Android emulator, verify that you have installed the latest Android SDK " + EOL
51-
+ "and its dependencies as described in http://developer.android.com/sdk/index.html#Requirements" + EOL
51+
+ "and its dependencies as described in http://developer.android.com/sdk/index.html#Requirements" + EOL,
52+
platforms: [Constants.ANDROID_PLATFORM_NAME]
5253
});
5354
}
5455

@@ -57,23 +58,34 @@ export class Doctor {
5758
result.push({
5859
warning: "WARNING: Xcode is not installed or is not configured properly.",
5960
additionalInformation: "You will not be able to build your projects for iOS or run them in the iOS Simulator." + EOL
60-
+ "To be able to build for iOS and run apps in the native emulator, verify that you have installed Xcode." + EOL
61+
+ "To be able to build for iOS and run apps in the native emulator, verify that you have installed Xcode." + EOL,
62+
platforms: [Constants.IOS_PLATFORM_NAME]
6163
});
6264
}
6365

6466
if (!sysInfoData.xcodeprojGemLocation) {
6567
result.push({
6668
warning: "WARNING: xcodeproj gem is not installed or is not configured properly.",
6769
additionalInformation: "You will not be able to build your projects for iOS." + EOL
68-
+ "To be able to build for iOS and run apps in the native emulator, verify that you have installed xcodeproj." + EOL
70+
+ "To be able to build for iOS and run apps in the native emulator, verify that you have installed xcodeproj." + EOL,
71+
platforms: [Constants.IOS_PLATFORM_NAME]
6972
});
7073
}
7174

7275
if (!sysInfoData.cocoaPodsVer) {
7376
result.push({
7477
warning: "WARNING: CocoaPods is not installed or is not configured properly.",
7578
additionalInformation: "You will not be able to build your projects for iOS if they contain plugin with CocoaPod file." + EOL
76-
+ "To be able to build such projects, verify that you have installed CocoaPods."
79+
+ "To be able to build such projects, verify that you have installed CocoaPods.",
80+
platforms: [Constants.IOS_PLATFORM_NAME]
81+
});
82+
}
83+
84+
if (sysInfoData.cocoaPodsVer && sysInfoData.isCocoaPodsUpdateRequired) {
85+
result.push({
86+
warning: "WARNING: CocoaPods update required.",
87+
additionalInformation: `You are using CocoaPods version ${sysInfoData.cocoaPodsVer} which does not support Xcode ${sysInfoData.xcodeVer} yet.${EOL}${EOL}You can update your cocoapods by running $sudo gem install cocoapods from a terminal.${EOL}${EOL}In order for the NativeScript CLI to be able to work correctly with this setup you need to install xcproj command line tool and add it to your PATH.Xcproj can be installed with homebrew by running $ brew install xcproj from the terminal`,
88+
platforms: [Constants.IOS_PLATFORM_NAME]
7789
});
7890
}
7991

@@ -82,7 +94,8 @@ export class Doctor {
8294
if (!isCocoaPodsWorkingCorrectly) {
8395
result.push({
8496
warning: "WARNING: There was a problem with CocoaPods",
85-
additionalInformation: "Verify that CocoaPods are configured properly."
97+
additionalInformation: "Verify that CocoaPods are configured properly.",
98+
platforms: [Constants.IOS_PLATFORM_NAME]
8699
});
87100
}
88101
}
@@ -91,13 +104,15 @@ export class Doctor {
91104
result.push({
92105
warning: `WARNING: Your current CocoaPods version is earlier than ${Doctor.MIN_SUPPORTED_POD_VERSION}.`,
93106
additionalInformation: "You will not be able to build your projects for iOS if they contain plugin with CocoaPod file." + EOL
94-
+ `To be able to build such projects, verify that you have at least ${Doctor.MIN_SUPPORTED_POD_VERSION} version installed.`
107+
+ `To be able to build such projects, verify that you have at least ${Doctor.MIN_SUPPORTED_POD_VERSION} version installed.`,
108+
platforms: [Constants.IOS_PLATFORM_NAME]
95109
});
96110
}
97111
} else {
98112
result.push({
99113
warning: "NOTE: You can develop for iOS only on Mac OS X systems.",
100-
additionalInformation: "To be able to work with iOS devices and projects, you need Mac OS X Mavericks or later." + EOL
114+
additionalInformation: "To be able to work with iOS devices and projects, you need Mac OS X Mavericks or later." + EOL,
115+
platforms: [Constants.IOS_PLATFORM_NAME]
101116
});
102117
}
103118

@@ -108,7 +123,8 @@ export class Doctor {
108123
+ "to perform some Android-related operations. To ensure that you can develop and" + EOL
109124
+ "test your apps for Android, verify that you have installed the JDK as" + EOL
110125
+ "described in http://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html (for JDK 8)" + EOL
111-
+ "or http://docs.oracle.com/javase/7/docs/webnotes/install/ (for JDK 7)." + EOL
126+
+ "or http://docs.oracle.com/javase/7/docs/webnotes/install/ (for JDK 7)." + EOL,
127+
platforms: [Constants.ANDROID_PLATFORM_NAME]
112128
});
113129
}
114130

@@ -117,7 +133,8 @@ export class Doctor {
117133
warning: "WARNING: Git is not installed or not configured properly.",
118134
additionalInformation: "You will not be able to create and work with Screen Builder projects." + EOL
119135
+ "To be able to work with Screen Builder projects, download and install Git as described" + EOL
120-
+ "in https://git-scm.com/downloads and add the git executable to your PATH." + EOL
136+
+ "in https://git-scm.com/downloads and add the git executable to your PATH." + EOL,
137+
platforms: Constants.SUPPORTED_PLATFORMS
121138
});
122139
}
123140

@@ -134,7 +151,7 @@ export class Doctor {
134151
}
135152

136153
if (!this.isPlatformSupported(platform)) {
137-
throw new Error(`Platform ${platform} is not supported. The supported platforms are: ${Constants.SUPPORTED_PLATFORMS.join(", ")}`);
154+
throw new Error(`Platform ${platform} is not supported.The supported platforms are: ${Constants.SUPPORTED_PLATFORMS.join(", ")} `);
138155
}
139156
}
140157
}

lib/index.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,21 @@ import { Helpers } from "./helpers";
77
import { Doctor } from "./doctor";
88
import { AndroidLocalBuildRequirements } from "./local-build-requirements/android-local-build-requirements";
99
import { IosLocalBuildRequirements } from "./local-build-requirements/ios-local-build-requirements";
10+
import { Constants as constants } from "./constants";
1011

1112
const childProcess = new ChildProcess();
12-
const winreg = new WinReg();
13-
const hostInfo = new HostInfo(winreg);
13+
const winReg = new WinReg();
14+
const hostInfo = new HostInfo(winReg);
1415
const fileSystem = new FileSystem();
1516
const helpers = new Helpers();
16-
const sysInfo = new SysInfo(childProcess, fileSystem, helpers, hostInfo, winreg);
17+
const sysInfo = new SysInfo(childProcess, fileSystem, helpers, hostInfo, winReg);
1718

1819
const androidLocalBuildRequirements = new AndroidLocalBuildRequirements(sysInfo);
1920
const iOSLocalBuildRequirements = new IosLocalBuildRequirements(sysInfo, hostInfo);
2021
const doctor = new Doctor(androidLocalBuildRequirements, helpers, hostInfo, iOSLocalBuildRequirements, sysInfo);
2122

2223
export {
2324
sysInfo,
24-
doctor
25+
doctor,
26+
constants
2527
};

lib/sys-info.ts

+59-10
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { ExecOptions } from "child_process";
55
import { WinReg } from "./winreg";
66
import { Helpers } from "./helpers";
77
import { platform } from "os";
8-
import { ISysInfoData } from "../typings/nativescript-doctor";
98
import * as path from "path";
109
import * as osenv from "osenv";
1110
import * as temp from "temp";
11+
import * as semver from "semver";
1212

13-
export class SysInfo {
13+
export class SysInfo implements NativeScriptDoctor.ISysInfo {
1414
// Different java has different format for `java -version` command.
1515
private static JAVA_VERSION_REGEXP = /(?:openjdk|java) version \"((?:\d+\.)+(?:\d+))/i;
1616

@@ -36,14 +36,17 @@ export class SysInfo {
3636
private monoVerCache: string;
3737
private gitVerCache: string;
3838
private gradleVerCache: string;
39-
private sysInfoCache: ISysInfoData;
39+
private sysInfoCache: NativeScriptDoctor.ISysInfoData;
4040
private isCocoaPodsWorkingCorrectlyCache: boolean = null;
41+
private nativeScriptCliVersionCache: string;
42+
private xcprojInfoCache: NativeScriptDoctor.IXcprojInfo;
43+
private isCocoaPodsUpdateRequiredCache: boolean = null;
4144

4245
constructor(private childProcess: ChildProcess,
4346
private fileSystem: FileSystem,
4447
private helpers: Helpers,
4548
private hostInfo: HostInfo,
46-
private winreg: WinReg) { }
49+
private winReg: WinReg) { }
4750

4851
public async getJavaVersion(): Promise<string> {
4952
if (!this.javaVerCache) {
@@ -224,9 +227,9 @@ export class SysInfo {
224227
return this.gradleVerCache;
225228
}
226229

227-
public async getSysInfo(): Promise<ISysInfoData> {
230+
public async getSysInfo(): Promise<NativeScriptDoctor.ISysInfoData> {
228231
if (!this.sysInfoCache) {
229-
const result: ISysInfoData = Object.create(null);
232+
const result: NativeScriptDoctor.ISysInfoData = Object.create(null);
230233

231234
// os stuff
232235
result.platform = platform();
@@ -252,6 +255,8 @@ export class SysInfo {
252255
result.gitVer = await this.getGitVersion();
253256
result.gradleVer = await this.getGradleVersion();
254257
result.isCocoaPodsWorkingCorrectly = await this.isCocoaPodsWorkingCorrectly();
258+
result.nativeScriptCliVersion = await this.getNativeScriptCliVersion();
259+
result.isCocoaPodsUpdateRequired = await this.isCocoaPodsUpdateRequired();
255260

256261
this.sysInfoCache = result;
257262
}
@@ -284,6 +289,50 @@ export class SysInfo {
284289
return !!this.isCocoaPodsWorkingCorrectlyCache;
285290
}
286291

292+
public async getNativeScriptCliVersion(): Promise<string> {
293+
if (!this.nativeScriptCliVersionCache) {
294+
const output = await this.execCommand("tns --version");
295+
this.nativeScriptCliVersionCache = output ? output.trim() : output;
296+
}
297+
298+
return this.nativeScriptCliVersionCache;
299+
}
300+
301+
public async getXcprojInfo(): Promise<NativeScriptDoctor.IXcprojInfo> {
302+
if (!this.xcprojInfoCache) {
303+
const cocoaPodsVersion = await this.getCocoaPodsVersion();
304+
const xcodeVersion = await this.getXcodeVersion();
305+
306+
// CocoaPods with version lower than 1.0.0 don't support Xcode 7.3 yet
307+
// https://github.com/CocoaPods/CocoaPods/issues/2530#issuecomment-210470123
308+
// as a result of this all .pbxprojects touched by CocoaPods get converted to XML plist format
309+
const shouldUseXcproj = cocoaPodsVersion && !!(semver.lt(cocoaPodsVersion, "1.0.0") && semver.gte(xcodeVersion, "7.3.0"));
310+
let xcprojAvailable: boolean;
311+
312+
if (shouldUseXcproj) {
313+
// If that's the case we can use xcproj gem to convert them back to ASCII plist format
314+
xcprojAvailable = !!(await this.exec("xcproj --version"))
315+
}
316+
317+
this.xcprojInfoCache = { shouldUseXcproj, xcprojAvailable };
318+
}
319+
320+
return this.xcprojInfoCache;
321+
}
322+
323+
public async isCocoaPodsUpdateRequired(): Promise<boolean> {
324+
if (this.isCocoaPodsUpdateRequiredCache === null) {
325+
let xcprojInfo = await this.getXcprojInfo();
326+
if (xcprojInfo.shouldUseXcproj && !xcprojInfo.xcprojAvailable) {
327+
this.isCocoaPodsUpdateRequiredCache = true;
328+
} else {
329+
this.isCocoaPodsUpdateRequiredCache = false;
330+
}
331+
}
332+
333+
return this.isCocoaPodsUpdateRequiredCache;
334+
}
335+
287336
private async exec(cmd: string, execOptions?: ExecOptions): Promise<IProcessInfo> {
288337
if (cmd) {
289338
try {
@@ -314,12 +363,12 @@ export class SysInfo {
314363
let productName: string;
315364
let currentVersion: string;
316365
let currentBuild: string;
317-
const hive = this.winreg.registryKeys.HKLM;
366+
const hive = this.winReg.registryKeys.HKLM;
318367
const key = "\\Software\\Microsoft\\Windows NT\\CurrentVersion";
319368

320-
productName = await this.winreg.getRegistryValue("ProductName", hive, key);
321-
currentVersion = await this.winreg.getRegistryValue("CurrentVersion", hive, key);
322-
currentBuild = await this.winreg.getRegistryValue("CurrentBuild", hive, key);
369+
productName = await this.winReg.getRegistryValue("ProductName", hive, key);
370+
currentVersion = await this.winReg.getRegistryValue("CurrentVersion", hive, key);
371+
currentBuild = await this.winReg.getRegistryValue("CurrentBuild", hive, key);
323372

324373
return `${productName} ${currentVersion}.${currentBuild}`;
325374
}

test/sys-info.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as assert from "assert";
22
import * as path from "path";
33
import { SysInfo } from "../lib/sys-info";
44
import { ChildProcess } from "../lib/wrappers/child-process";
5-
import { ISysInfoData } from "../typings/nativescript-doctor";
65

76
const JavaHomeName = "JAVA_HOME";
87
const AndroidHomeName = "ANDROID_HOME";
@@ -26,6 +25,7 @@ interface IChildProcessResults {
2625
gitVersion: IChildProcessResultDescription;
2726
podVersion: IChildProcessResultDescription;
2827
pod: IChildProcessResultDescription;
28+
nativeScriptCliVersion: IChildProcessResultDescription;
2929
}
3030

3131
interface IHostInfoMockOptions {
@@ -54,7 +54,8 @@ function createChildProcessResults(childProcessResult: IChildProcessResults): ID
5454
'android.bat': childProcessResult.androidInstalled, // for Windows
5555
"mono --version": childProcessResult.monoVersion,
5656
"git --version": childProcessResult.gitVersion,
57-
"gradle -v": childProcessResult.gradleVersion
57+
"gradle -v": childProcessResult.gradleVersion,
58+
"tns --version": childProcessResult.nativeScriptCliVersion
5859
};
5960
}
6061

@@ -182,7 +183,8 @@ describe("SysInfo unit tests", () => {
182183
gradleVersion: { result: setStdOut("Gradle 2.8") },
183184
gitVersion: { result: setStdOut("git version 1.9.5") },
184185
podVersion: { result: setStdOut("0.38.2") },
185-
pod: { result: setStdOut("success") }
186+
pod: { result: setStdOut("success") },
187+
nativeScriptCliVersion: { result: setStdOut("2.5.0") }
186188
};
187189

188190
delete process.env[JavaHomeName];
@@ -195,7 +197,7 @@ describe("SysInfo unit tests", () => {
195197
});
196198

197199
describe("returns correct results when everything is installed", () => {
198-
let assertCommonValues = (result: ISysInfoData) => {
200+
let assertCommonValues = (result: NativeScriptDoctor.ISysInfoData) => {
199201
assert.deepEqual(result.npmVer, childProcessResult.npmV.result.stdout);
200202
assert.deepEqual(result.javaVer, "1.8.0");
201203
assert.deepEqual(result.javacVersion, "1.8.0_60");
@@ -205,6 +207,7 @@ describe("SysInfo unit tests", () => {
205207
assert.deepEqual(result.monoVer, "1.0.6");
206208
assert.deepEqual(result.gradleVer, "2.8");
207209
assert.deepEqual(result.gitVer, "1.9.5");
210+
assert.deepEqual(result.nativeScriptCliVersion, childProcessResult.nativeScriptCliVersion.result.stdout);
208211
};
209212

210213
it("on Windows", async () => {
@@ -277,7 +280,8 @@ describe("SysInfo unit tests", () => {
277280
gradleVersion: { shouldThrowError: true },
278281
gitVersion: { shouldThrowError: true },
279282
podVersion: { shouldThrowError: true },
280-
pod: { shouldThrowError: true }
283+
pod: { shouldThrowError: true },
284+
nativeScriptCliVersion: { shouldThrowError: true }
281285
};
282286
});
283287

0 commit comments

Comments
 (0)