Skip to content

Commit fa10947

Browse files
committed
refactor: extract android tools info logic to doctor
1 parent 24b21c4 commit fa10947

File tree

4 files changed

+45
-166
lines changed

4 files changed

+45
-166
lines changed

lib/android-tools-info.ts

+40-161
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,63 @@
11
import * as path from "path";
2-
import * as semver from "semver";
32
import { cache } from "./common/decorators";
43
import { androidToolsInfo } from "nativescript-doctor";
54

65
export class AndroidToolsInfo implements IAndroidToolsInfo {
7-
private static ANDROID_TARGET_PREFIX = "android";
8-
private static SUPPORTED_TARGETS = [
9-
"android-17",
10-
"android-18",
11-
"android-19",
12-
"android-21",
13-
"android-22",
14-
"android-23",
15-
"android-24",
16-
"android-25",
17-
"android-26",
18-
"android-27",
19-
"android-28",
20-
];
21-
private static MIN_REQUIRED_COMPILE_TARGET = 28;
22-
private static REQUIRED_BUILD_TOOLS_RANGE_PREFIX = ">=23";
23-
private static VERSION_REGEX = /((\d+\.){2}\d+)/;
24-
25-
private showWarningsAsErrors: boolean;
26-
private toolsInfo: IAndroidToolsInfoData;
27-
private selectedCompileSdk: number;
28-
private get androidHome(): string {
29-
return process.env["ANDROID_HOME"];
30-
}
31-
326
constructor(private $errors: IErrors,
33-
private $fs: IFileSystem,
347
private $logger: ILogger,
358
private $options: IOptions,
369
protected $staticConfig: Config.IStaticConfig) {
3710
}
3811

3912
@cache()
4013
public getToolsInfo(): IAndroidToolsInfoData {
41-
if (!this.toolsInfo) {
42-
const infoData: IAndroidToolsInfoData = Object.create(null);
43-
infoData.androidHomeEnvVar = this.androidHome;
44-
infoData.compileSdkVersion = this.getCompileSdkVersion();
45-
infoData.buildToolsVersion = this.getBuildToolsVersion();
46-
infoData.targetSdkVersion = this.getTargetSdk();
47-
infoData.generateTypings = this.shouldGenerateTypings();
48-
49-
this.toolsInfo = infoData;
50-
}
14+
const infoData: IAndroidToolsInfoData = <IAndroidToolsInfoData>(androidToolsInfo.getToolsInfo());
15+
16+
infoData.androidHomeEnvVar = androidToolsInfo.androidHome;
17+
infoData.compileSdkVersion = this.getCompileSdkVersion(infoData.installedTargets, infoData.compileSdkVersion);
18+
infoData.targetSdkVersion = this.getTargetSdk(infoData.compileSdkVersion);
19+
infoData.generateTypings = this.shouldGenerateTypings();
20+
21+
this.$logger.trace("Installed Android Targets are: ", infoData.installedTargets);
22+
this.$logger.trace("Selected buildToolsVersion is:", infoData.buildToolsVersion);
5123

52-
return this.toolsInfo;
24+
return infoData;
5325
}
5426

5527
public validateInfo(options?: IAndroidToolsInfoValidateInput): boolean {
5628
let detectedErrors = false;
57-
this.showWarningsAsErrors = options && options.showWarningsAsErrors;
58-
const isAndroidHomeValid = this.validateAndroidHomeEnvVariable();
29+
const showWarningsAsErrors = options && options.showWarningsAsErrors;
30+
const isAndroidHomeValid = this.validateAndroidHomeEnvVariable(options);
5931

60-
detectedErrors = androidToolsInfo.validateInfo().map(warning => this.printMessage(warning.warning)).length > 0;
32+
detectedErrors = androidToolsInfo.validateInfo().map(warning => this.printMessage(warning.warning, showWarningsAsErrors)).length > 0;
6133

6234
if (options && options.validateTargetSdk) {
63-
detectedErrors = this.validateTargetSdk();
35+
detectedErrors = this.validateTargetSdk(options);
6436
}
6537

6638
return detectedErrors || !isAndroidHomeValid;
6739
}
6840

6941
public validateTargetSdk(options?: IAndroidToolsInfoOptions): boolean {
70-
this.showWarningsAsErrors = options && options.showWarningsAsErrors;
42+
let detectedErrors = false;
43+
const showWarningsAsErrors = options && options.showWarningsAsErrors;
7144

7245
const toolsInfoData = this.getToolsInfo();
7346
const targetSdk = toolsInfoData.targetSdkVersion;
74-
const newTarget = `${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-${targetSdk}`;
7547

76-
if (!_.includes(AndroidToolsInfo.SUPPORTED_TARGETS, newTarget)) {
77-
const supportedVersions = AndroidToolsInfo.SUPPORTED_TARGETS.sort();
78-
const minSupportedVersion = this.parseAndroidSdkString(_.first(supportedVersions));
48+
detectedErrors = androidToolsInfo.validateMinSupportedTargetSdk(targetSdk).map(warning => this.printMessage(warning.warning, showWarningsAsErrors)).length > 0;
7949

80-
if (targetSdk && (targetSdk < minSupportedVersion)) {
81-
this.printMessage(`The selected Android target SDK ${newTarget} is not supported. You must target ${minSupportedVersion} or later.`);
82-
return true;
83-
} else if (!targetSdk || targetSdk > this.getMaxSupportedVersion()) {
84-
this.$logger.warn(`Support for the selected Android target SDK ${newTarget} is not verified. Your Android app might not work as expected.`);
85-
}
50+
if (!detectedErrors) {
51+
androidToolsInfo.validataMaxSupportedTargetSdk(targetSdk).map(warning => this.$logger.warn(warning.warning));
8652
}
8753

88-
return false;
54+
return detectedErrors;
8955
}
9056

9157
public validateJavacVersion(installedJavacVersion: string, options?: IAndroidToolsInfoOptions): boolean {
92-
if (options) {
93-
this.showWarningsAsErrors = options.showWarningsAsErrors;
94-
}
58+
const showWarningsAsErrors = options && options.showWarningsAsErrors;
9559

96-
return androidToolsInfo.validateJavacVersion(installedJavacVersion).map(warning => this.printMessage(warning.warning)).length > 0;
60+
return androidToolsInfo.validateJavacVersion(installedJavacVersion).map(warning => this.printMessage(warning.warning, showWarningsAsErrors)).length > 0;
9761
}
9862

9963
public async getPathToAdbFromAndroidHome(): Promise<string> {
@@ -102,19 +66,17 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
10266
} catch (err) {
10367
// adb does not exist, so ANDROID_HOME is not set correctly
10468
// try getting default adb path (included in CLI package)
105-
this.$logger.trace(`Error while executing '${path.join(this.androidHome, "platform-tools", "adb")} help'. Error is: ${err.message}`);
69+
this.$logger.trace(`Error while executing '${path.join(androidToolsInfo.androidHome, "platform-tools", "adb")} help'. Error is: ${err.message}`);
10670
}
10771

10872
return null;
10973
}
11074

11175
@cache()
11276
public validateAndroidHomeEnvVariable(options?: IAndroidToolsInfoOptions): boolean {
113-
if (options) {
114-
this.showWarningsAsErrors = options.showWarningsAsErrors;
115-
}
77+
const showWarningsAsErrors = options && options.showWarningsAsErrors;
11678

117-
return androidToolsInfo.validateAndroidHomeEnvVariable().map(warning => this.printMessage(warning.warning)).length > 0;
79+
return androidToolsInfo.validateAndroidHomeEnvVariable().map(warning => this.printMessage(warning.warning, showWarningsAsErrors)).length > 0;
11880
}
11981

12082
private shouldGenerateTypings(): boolean {
@@ -127,119 +89,36 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
12789
* In case additional details must be shown as info message, use the second parameter.
12890
* NOTE: The additional information will not be printed when showWarningsAsErrors flag is set.
12991
* @param {string} msg The message that will be shown as warning or error.
130-
* @param {string} additionalMsg The additional message that will be shown as info message.
13192
* @return {void}
13293
*/
133-
private printMessage(msg: string, additionalMsg?: string): void {
134-
if (this.showWarningsAsErrors) {
94+
private printMessage(msg: string, showWarningsAsErrors: boolean): void {
95+
if (showWarningsAsErrors) {
13596
this.$errors.failWithoutHelp(msg);
13697
} else {
13798
this.$logger.warn(msg);
13899
}
139-
140-
if (additionalMsg) {
141-
this.$logger.printMarkdown(additionalMsg);
142-
}
143100
}
144101

145-
private getCompileSdkVersion(): number {
146-
if (!this.selectedCompileSdk) {
147-
const userSpecifiedCompileSdk = this.$options.compileSdk;
148-
if (userSpecifiedCompileSdk) {
149-
const installedTargets = this.getInstalledTargets();
150-
const androidCompileSdk = `${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-${userSpecifiedCompileSdk}`;
151-
if (!_.includes(installedTargets, androidCompileSdk)) {
152-
this.$errors.failWithoutHelp(`You have specified '${userSpecifiedCompileSdk}' for compile sdk, but it is not installed on your system.`);
153-
}
154-
155-
this.selectedCompileSdk = userSpecifiedCompileSdk;
156-
} else {
157-
const latestValidAndroidTarget = this.getLatestValidAndroidTarget();
158-
if (latestValidAndroidTarget) {
159-
const integerVersion = this.parseAndroidSdkString(latestValidAndroidTarget);
160-
161-
if (integerVersion && integerVersion >= AndroidToolsInfo.MIN_REQUIRED_COMPILE_TARGET) {
162-
this.selectedCompileSdk = integerVersion;
163-
}
164-
}
165-
}
166-
}
102+
private getCompileSdkVersion(installedTargets: string[], latestCompileSdk: number): number {
103+
const userSpecifiedCompileSdk = this.$options.compileSdk;
167104

168-
return this.selectedCompileSdk;
169-
}
170-
171-
private getTargetSdk(): number {
172-
const targetSdk = this.$options.sdk ? parseInt(this.$options.sdk) : this.getCompileSdkVersion();
173-
this.$logger.trace(`Selected targetSdk is: ${targetSdk}`);
174-
return targetSdk;
175-
}
176-
177-
private getMatchingDir(pathToDir: string, versionRange: string): string {
178-
let selectedVersion: string;
179-
if (this.$fs.exists(pathToDir)) {
180-
const subDirs = this.$fs.readDirectory(pathToDir);
181-
this.$logger.trace(`Directories found in ${pathToDir} are ${subDirs.join(", ")}`);
182-
183-
const subDirsVersions = subDirs
184-
.map(dirName => {
185-
const dirNameGroups = dirName.match(AndroidToolsInfo.VERSION_REGEX);
186-
if (dirNameGroups) {
187-
return dirNameGroups[1];
188-
}
189-
190-
return null;
191-
})
192-
.filter(dirName => !!dirName);
193-
this.$logger.trace(`Versions found in ${pathToDir} are ${subDirsVersions.join(", ")}`);
194-
const version = semver.maxSatisfying(subDirsVersions, versionRange);
195-
if (version) {
196-
selectedVersion = _.find(subDirs, dir => dir.indexOf(version) !== -1);
105+
if (userSpecifiedCompileSdk) {
106+
const androidCompileSdk = `${androidToolsInfo.ANDROID_TARGET_PREFIX}-${userSpecifiedCompileSdk}`;
107+
if (!_.includes(installedTargets, androidCompileSdk)) {
108+
this.$errors.failWithoutHelp(`You have specified '${userSpecifiedCompileSdk}' for compile sdk, but it is not installed on your system.`);
197109
}
198-
}
199-
this.$logger.trace("Selected version is: ", selectedVersion);
200-
return selectedVersion;
201-
}
202-
203-
private getBuildToolsRange(): string {
204-
return `${AndroidToolsInfo.REQUIRED_BUILD_TOOLS_RANGE_PREFIX} <=${this.getMaxSupportedVersion()}`;
205-
}
206110

207-
private getBuildToolsVersion(): string {
208-
let buildToolsVersion: string;
209-
if (this.androidHome) {
210-
const pathToBuildTools = path.join(this.androidHome, "build-tools");
211-
const buildToolsRange = this.getBuildToolsRange();
212-
buildToolsVersion = this.getMatchingDir(pathToBuildTools, buildToolsRange);
111+
return userSpecifiedCompileSdk;
213112
}
214113

215-
return buildToolsVersion;
216-
}
217-
218-
private getLatestValidAndroidTarget(): string {
219-
const installedTargets = this.getInstalledTargets();
220-
return _.findLast(AndroidToolsInfo.SUPPORTED_TARGETS.sort(), supportedTarget => _.includes(installedTargets, supportedTarget));
221-
}
222-
223-
private parseAndroidSdkString(androidSdkString: string): number {
224-
return parseInt(androidSdkString.replace(`${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-`, ""));
114+
return latestCompileSdk;
225115
}
226116

227-
@cache()
228-
private getInstalledTargets(): string[] {
229-
let installedTargets: string[] = [];
230-
if (this.androidHome) {
231-
const pathToInstalledTargets = path.join(this.androidHome, "platforms");
232-
if (this.$fs.exists(pathToInstalledTargets)) {
233-
installedTargets = this.$fs.readDirectory(pathToInstalledTargets);
234-
}
235-
}
236-
this.$logger.trace("Installed Android Targets are: ", installedTargets);
237-
238-
return installedTargets;
239-
}
240-
241-
private getMaxSupportedVersion(): number {
242-
return this.parseAndroidSdkString(_.last(AndroidToolsInfo.SUPPORTED_TARGETS.sort()));
117+
// TODO check if still needed
118+
private getTargetSdk(compileSdk: number): number {
119+
const targetSdk = this.$options.sdk ? parseInt(this.$options.sdk) : compileSdk;
120+
this.$logger.trace(`Selected targetSdk is: ${targetSdk}`);
121+
return targetSdk;
243122
}
244123
}
245124
$injector.register("androidToolsInfo", AndroidToolsInfo);

lib/declarations.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ interface IAndroidToolsInfo {
689689
/**
690690
* Describes information about installed Android tools and SDKs.
691691
*/
692-
interface IAndroidToolsInfoData {
692+
interface IAndroidToolsInfoData extends NativeScriptDoctor.IAndroidToolsInfoData {
693693
/**
694694
* The value of ANDROID_HOME environment variable.
695695
*/

npm-shrinkwrap.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"mkdirp": "0.5.1",
6060
"mute-stream": "0.0.5",
6161
"nativescript-dev-xcode": "0.2.0",
62-
"nativescript-doctor": "1.10.0",
62+
"nativescript-doctor": "1.11.0-rc.0",
6363
"nativescript-preview-sdk": "0.3.4",
6464
"open": "0.0.5",
6565
"ora": "2.0.0",

0 commit comments

Comments
 (0)