Skip to content

Commit 8a6b640

Browse files
author
Fatme
authored
Merge pull request #3426 from NativeScript/fatme/getting-started-improvements
Getting started improvements
2 parents 4210877 + 4e51bc6 commit 8a6b640

22 files changed

+579
-221
lines changed

docs/man_pages/cloud/cloud-setup.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<% if (isJekyll) { %>---
2+
title: tns cloud setup
3+
position: 5
4+
---<% } %>
5+
# tns cloud setup
6+
==========
7+
8+
Usage | Synopsis
9+
------|-------
10+
Install the `nativescript-cloud extension` | `$ tns cloud setup`
11+
12+
Install the `nativescript-cloud extension` to configure your environment for cloud builds.
13+
14+
### Related Commands
15+
16+
Command | Description
17+
----------|----------
18+
[setup](setup.html) | Run the setup script to try to automatically configure your environment for local builds.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<% if (isJekyll) { %>---
2+
title: tns setup
3+
position: 5
4+
---<% } %>
5+
# tns setup
6+
==========
7+
8+
Usage | Synopsis
9+
------|-------
10+
Run the setup script | `$ tns setup`
11+
12+
Run the setup script to try to automatically configure your environment for local builds.
13+
14+
### Related Commands
15+
16+
Command | Description
17+
----------|----------
18+
[setup cloud](setup-cloud.html) | Install the nativescript-cloud extension to configure your environment for cloud builds.

docs/man_pages/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ Command | Description
5757
[device run](device/device-run.html) | Runs the selected application on a connected device.
5858
[device list-applications](device/device-list-applications.html) | Lists the installed applications on all connected devices.
5959

60+
## Environment Configuration Commands
61+
Command | Description
62+
---|---
63+
[setup](env-configuration/setup.html) | Run the setup script to try to automatically configure your environment for local builds.
64+
[setup cloud](cloud/cloud-setup.html) | Install the `nativescript-cloud extension` to configure your environment for cloud builds.
65+
6066
## Global Options
6167
Option | Description
6268
-------|---------

lib/android-tools-info.ts

Lines changed: 35 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import * as path from "path";
22
import * as semver from "semver";
3-
import { EOL } from "os";
43
import { cache } from "./common/decorators";
5-
import { appendZeroesToVersion } from './common/helpers';
4+
import { androidToolsInfo } from "nativescript-doctor";
65

76
export class AndroidToolsInfo implements IAndroidToolsInfo {
87
private static ANDROID_TARGET_PREFIX = "android";
98
private static SUPPORTED_TARGETS = ["android-17", "android-18", "android-19", "android-21", "android-22", "android-23", "android-24", "android-25", "android-26", "android-27"];
109
private static MIN_REQUIRED_COMPILE_TARGET = 22;
1110
private static REQUIRED_BUILD_TOOLS_RANGE_PREFIX = ">=23";
1211
private static VERSION_REGEX = /((\d+\.){2}\d+)/;
13-
private static MIN_JAVA_VERSION = "1.8.0";
14-
private static MAX_JAVA_VERSION = "1.9.0";
1512

1613
private showWarningsAsErrors: boolean;
1714
private toolsInfo: IAndroidToolsInfoData;
@@ -20,10 +17,8 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
2017
return process.env["ANDROID_HOME"];
2118
}
2219

23-
constructor(private $childProcess: IChildProcess,
24-
private $errors: IErrors,
20+
constructor(private $errors: IErrors,
2521
private $fs: IFileSystem,
26-
private $hostInfo: IHostInfo,
2722
private $logger: ILogger,
2823
private $options: IOptions,
2924
protected $staticConfig: Config.IStaticConfig) { }
@@ -45,151 +40,69 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
4540
return this.toolsInfo;
4641
}
4742

48-
public validateInfo(options?: { showWarningsAsErrors: boolean, validateTargetSdk: boolean }): boolean {
43+
public validateInfo(options?: IAndroidToolsInfoValidateInput): boolean {
4944
let detectedErrors = false;
5045
this.showWarningsAsErrors = options && options.showWarningsAsErrors;
51-
const toolsInfoData = this.getToolsInfo();
5246
const isAndroidHomeValid = this.validateAndroidHomeEnvVariable();
53-
if (!toolsInfoData.compileSdkVersion) {
54-
this.printMessage(`Cannot find a compatible Android SDK for compilation. To be able to build for Android, install Android SDK ${AndroidToolsInfo.MIN_REQUIRED_COMPILE_TARGET} or later.`,
55-
`Run \`\$ ${this.getPathToSdkManagementTool()}\` to manage your Android SDK versions.`);
56-
detectedErrors = true;
57-
}
5847

59-
if (!toolsInfoData.buildToolsVersion) {
60-
const buildToolsRange = this.getBuildToolsRange();
61-
const versionRangeMatches = buildToolsRange.match(/^.*?([\d\.]+)\s+.*?([\d\.]+)$/);
62-
let message = `You can install any version in the following range: '${buildToolsRange}'.`;
63-
64-
// Improve message in case buildToolsRange is something like: ">=22.0.0 <=22.0.0" - same numbers on both sides
65-
if (versionRangeMatches && versionRangeMatches[1] && versionRangeMatches[2] && versionRangeMatches[1] === versionRangeMatches[2]) {
66-
message = `You have to install version ${versionRangeMatches[1]}.`;
67-
}
48+
detectedErrors = androidToolsInfo.validateInfo().map(warning => this.printMessage(warning.warning)).length > 0;
6849

69-
let invalidBuildToolsAdditionalMsg = `Run \`\$ ${this.getPathToSdkManagementTool()}\` from your command-line to install required \`Android Build Tools\`.`;
70-
if (!isAndroidHomeValid) {
71-
invalidBuildToolsAdditionalMsg += ' In case you already have them installed, make sure `ANDROID_HOME` environment variable is set correctly.';
72-
}
73-
74-
this.printMessage("You need to have the Android SDK Build-tools installed on your system. " + message, invalidBuildToolsAdditionalMsg);
75-
detectedErrors = true;
50+
if (options && options.validateTargetSdk) {
51+
detectedErrors = this.validateTargetSdk();
7652
}
7753

78-
if (!toolsInfoData.supportRepositoryVersion) {
79-
let invalidSupportLibAdditionalMsg = `Run \`\$ ${this.getPathToSdkManagementTool()}\` to manage the Android Support Repository.`;
80-
if (!isAndroidHomeValid) {
81-
invalidSupportLibAdditionalMsg += ' In case you already have it installed, make sure `ANDROID_HOME` environment variable is set correctly.';
82-
}
83-
this.printMessage(`You need to have Android SDK ${AndroidToolsInfo.MIN_REQUIRED_COMPILE_TARGET} or later and the latest Android Support Repository installed on your system.`, invalidSupportLibAdditionalMsg);
84-
detectedErrors = true;
85-
}
54+
return detectedErrors || !isAndroidHomeValid;
55+
}
8656

87-
if (options && options.validateTargetSdk) {
88-
const targetSdk = toolsInfoData.targetSdkVersion;
89-
const newTarget = `${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-${targetSdk}`;
90-
if (!_.includes(AndroidToolsInfo.SUPPORTED_TARGETS, newTarget)) {
91-
const supportedVersions = AndroidToolsInfo.SUPPORTED_TARGETS.sort();
92-
const minSupportedVersion = this.parseAndroidSdkString(_.first(supportedVersions));
93-
94-
if (targetSdk && (targetSdk < minSupportedVersion)) {
95-
this.printMessage(`The selected Android target SDK ${newTarget} is not supported. You must target ${minSupportedVersion} or later.`);
96-
detectedErrors = true;
97-
} else if (!targetSdk || targetSdk > this.getMaxSupportedVersion()) {
98-
this.$logger.warn(`Support for the selected Android target SDK ${newTarget} is not verified. Your Android app might not work as expected.`);
99-
}
57+
public validateTargetSdk(options?: IAndroidToolsInfoOptions): boolean {
58+
this.showWarningsAsErrors = options && options.showWarningsAsErrors;
59+
60+
const toolsInfoData = this.getToolsInfo();
61+
const targetSdk = toolsInfoData.targetSdkVersion;
62+
const newTarget = `${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-${targetSdk}`;
63+
64+
if (!_.includes(AndroidToolsInfo.SUPPORTED_TARGETS, newTarget)) {
65+
const supportedVersions = AndroidToolsInfo.SUPPORTED_TARGETS.sort();
66+
const minSupportedVersion = this.parseAndroidSdkString(_.first(supportedVersions));
67+
68+
if (targetSdk && (targetSdk < minSupportedVersion)) {
69+
this.printMessage(`The selected Android target SDK ${newTarget} is not supported. You must target ${minSupportedVersion} or later.`);
70+
return true;
71+
} else if (!targetSdk || targetSdk > this.getMaxSupportedVersion()) {
72+
this.$logger.warn(`Support for the selected Android target SDK ${newTarget} is not verified. Your Android app might not work as expected.`);
10073
}
10174
}
10275

103-
return detectedErrors || !isAndroidHomeValid;
76+
return false;
10477
}
10578

106-
public validateJavacVersion(installedJavacVersion: string, options?: { showWarningsAsErrors: boolean }): boolean {
107-
let hasProblemWithJavaVersion = false;
79+
public validateJavacVersion(installedJavacVersion: string, options?: IAndroidToolsInfoOptions): boolean {
10880
if (options) {
10981
this.showWarningsAsErrors = options.showWarningsAsErrors;
11082
}
11183

112-
const additionalMessage = "You will not be able to build your projects for Android." + EOL
113-
+ "To be able to build for Android, verify that you have installed The Java Development Kit (JDK) and configured it according to system requirements as" + EOL +
114-
" described in " + this.$staticConfig.SYS_REQUIREMENTS_LINK;
115-
116-
const matchingVersion = appendZeroesToVersion(installedJavacVersion || "", 3).match(AndroidToolsInfo.VERSION_REGEX);
117-
const installedJavaCompilerVersion = matchingVersion && matchingVersion[1];
118-
if (installedJavaCompilerVersion) {
119-
if (semver.lt(installedJavaCompilerVersion, AndroidToolsInfo.MIN_JAVA_VERSION)) {
120-
hasProblemWithJavaVersion = true;
121-
this.printMessage(`Javac version ${installedJavacVersion} is not supported. You have to install at least ${AndroidToolsInfo.MIN_JAVA_VERSION}.`, additionalMessage);
122-
} else if (semver.gte(installedJavaCompilerVersion, AndroidToolsInfo.MAX_JAVA_VERSION)) {
123-
hasProblemWithJavaVersion = true;
124-
this.printMessage(`Javac version ${installedJavacVersion} is not supported. You have to install version ${AndroidToolsInfo.MIN_JAVA_VERSION}.`, additionalMessage);
125-
}
126-
} else {
127-
hasProblemWithJavaVersion = true;
128-
this.printMessage("Error executing command 'javac'. Make sure you have installed The Java Development Kit (JDK) and set JAVA_HOME environment variable.", additionalMessage);
129-
}
130-
131-
return hasProblemWithJavaVersion;
84+
return androidToolsInfo.validateJavacVersion(installedJavacVersion).map(warning => this.printMessage(warning.warning)).length > 0;
13285
}
13386

13487
public async getPathToAdbFromAndroidHome(): Promise<string> {
135-
if (this.androidHome) {
136-
const pathToAdb = path.join(this.androidHome, "platform-tools", "adb");
137-
try {
138-
await this.$childProcess.execFile(pathToAdb, ["help"]);
139-
return pathToAdb;
140-
} catch (err) {
141-
// adb does not exist, so ANDROID_HOME is not set correctly
142-
// try getting default adb path (included in CLI package)
143-
this.$logger.trace(`Error while executing '${pathToAdb} help'. Error is: ${err.message}`);
144-
}
88+
try {
89+
return androidToolsInfo.getPathToAdbFromAndroidHome();
90+
} catch (err) {
91+
// adb does not exist, so ANDROID_HOME is not set correctly
92+
// try getting default adb path (included in CLI package)
93+
this.$logger.trace(`Error while executing '${path.join(this.androidHome, "platform-tools", "adb")} help'. Error is: ${err.message}`);
14594
}
14695

14796
return null;
14897
}
14998

15099
@cache()
151-
public validateAndroidHomeEnvVariable(options?: { showWarningsAsErrors: boolean }): boolean {
100+
public validateAndroidHomeEnvVariable(options?: IAndroidToolsInfoOptions): boolean {
152101
if (options) {
153102
this.showWarningsAsErrors = options.showWarningsAsErrors;
154103
}
155104

156-
const expectedDirectoriesInAndroidHome = ["build-tools", "tools", "platform-tools", "extras"];
157-
let androidHomeValidationResult = true;
158-
159-
if (!this.androidHome || !this.$fs.exists(this.androidHome)) {
160-
this.printMessage("The ANDROID_HOME environment variable is not set or it points to a non-existent directory. You will not be able to perform any build-related operations for Android.",
161-
"To be able to perform Android build-related operations, set the `ANDROID_HOME` variable to point to the root of your Android SDK installation directory.");
162-
androidHomeValidationResult = false;
163-
} else if (!_.some(expectedDirectoriesInAndroidHome.map(dir => this.$fs.exists(path.join(this.androidHome, dir))))) {
164-
this.printMessage("The ANDROID_HOME environment variable points to incorrect directory. You will not be able to perform any build-related operations for Android.",
165-
"To be able to perform Android build-related operations, set the `ANDROID_HOME` variable to point to the root of your Android SDK installation directory, " +
166-
"where you will find `tools` and `platform-tools` directories.");
167-
androidHomeValidationResult = false;
168-
}
169-
170-
return androidHomeValidationResult;
171-
}
172-
173-
@cache()
174-
private getPathToSdkManagementTool(): string {
175-
const sdkManagerName = "sdkmanager";
176-
let sdkManagementToolPath = sdkManagerName;
177-
178-
const isAndroidHomeValid = this.validateAndroidHomeEnvVariable();
179-
180-
if (isAndroidHomeValid) {
181-
// In case ANDROID_HOME is correct, check if sdkmanager exists and if not it means the SDK has not been updated.
182-
// In this case user shoud use `android` from the command-line instead of sdkmanager.
183-
const pathToSdkManager = path.join(this.androidHome, "tools", "bin", sdkManagerName);
184-
const pathToAndroidExecutable = path.join(this.androidHome, "tools", "android");
185-
const pathToExecutable = this.$fs.exists(pathToSdkManager) ? pathToSdkManager : pathToAndroidExecutable;
186-
187-
this.$logger.trace(`Path to Android SDK Management tool is: ${pathToExecutable}`);
188-
189-
sdkManagementToolPath = pathToExecutable.replace(this.androidHome, this.$hostInfo.isWindows ? "%ANDROID_HOME%" : "$ANDROID_HOME");
190-
}
191-
192-
return sdkManagementToolPath;
105+
return androidToolsInfo.validateAndroidHomeEnvVariable().map(warning => this.printMessage(warning.warning)).length > 0;
193106
}
194107

195108
private shouldGenerateTypings(): boolean {

lib/bootstrap.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,15 @@ $injector.requireCommand("appstore|upload", "./commands/appstore-upload");
7272
$injector.requireCommand("publish|ios", "./commands/appstore-upload");
7373
$injector.require("itmsTransporterService", "./services/itmstransporter-service");
7474

75+
$injector.requireCommand("setup|*", "./commands/setup");
76+
$injector.requireCommand(["setup|cloud", "cloud|setup"], "./commands/setup");
77+
7578
$injector.requirePublic("npm", "./node-package-manager");
7679
$injector.require("npmInstallationManager", "./npm-installation-manager");
7780
$injector.require("dynamicHelpProvider", "./dynamic-help-provider");
7881
$injector.require("mobilePlatformsCapabilities", "./mobile-platforms-capabilities");
7982
$injector.require("commandsServiceProvider", "./providers/commands-service-provider");
80-
$injector.require("deviceAppDataProvider", "./providers/device-app-data-provider");
83+
$injector.require("AppDataProvider", "./providers/device-app-data-provider");
8184

8285
$injector.require("deviceLogProvider", "./common/mobile/device-log-provider");
8386
$injector.require("projectFilesProvider", "./providers/project-files-provider");
@@ -152,3 +155,5 @@ $injector.require("subscriptionService", "./services/subscription-service");
152155
$injector.require("terminalSpinnerService", "./services/terminal-spinner-service");
153156

154157
$injector.require('playgroundService', './services/playground-service');
158+
$injector.require("platformEnvironmentRequirements", "./services/platform-environment-requirements");
159+
$injector.require("nativescriptCloudExtensionService", "./services/nativescript-cloud-extension-service");

lib/commands/build.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export class BuildCommandBase {
88
protected $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
99
protected $platformService: IPlatformService,
1010
private $bundleValidatorHelper: IBundleValidatorHelper) {
11-
this.$projectData.initializeProjectData();
11+
this.$projectData.initializeProjectData();
1212
}
1313

1414
public async executeCore(args: string[]): Promise<void> {
@@ -44,12 +44,16 @@ export class BuildCommandBase {
4444
}
4545
}
4646

47-
protected validatePlatform(platform: string): void {
47+
protected async validatePlatform(platform: string): Promise<void> {
4848
if (!this.$platformService.isPlatformSupportedForOS(platform, this.$projectData)) {
4949
this.$errors.fail(`Applications for platform ${platform} can not be built on this OS`);
5050
}
5151

5252
this.$bundleValidatorHelper.validate();
53+
54+
const platformData = this.$platformsData.getPlatformData(platform, this.$projectData);
55+
const platformProjectService = platformData.platformProjectService;
56+
await platformProjectService.validate(this.$projectData);
5357
}
5458
}
5559

@@ -63,15 +67,15 @@ export class BuildIosCommand extends BuildCommandBase implements ICommand {
6367
$devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
6468
$platformService: IPlatformService,
6569
$bundleValidatorHelper: IBundleValidatorHelper) {
66-
super($options, $errors, $projectData, $platformsData, $devicePlatformsConstants, $platformService, $bundleValidatorHelper);
70+
super($options, $errors, $projectData, $platformsData, $devicePlatformsConstants, $platformService, $bundleValidatorHelper);
6771
}
6872

6973
public async execute(args: string[]): Promise<void> {
7074
return this.executeCore([this.$platformsData.availablePlatforms.iOS]);
7175
}
7276

73-
public canExecute(args: string[]): Promise<boolean> {
74-
super.validatePlatform(this.$devicePlatformsConstants.iOS);
77+
public async canExecute(args: string[]): Promise<boolean> {
78+
await super.validatePlatform(this.$devicePlatformsConstants.iOS);
7579
return args.length === 0 && this.$platformService.validateOptions(this.$options.provision, this.$options.teamId, this.$projectData, this.$platformsData.availablePlatforms.iOS);
7680
}
7781
}
@@ -88,23 +92,19 @@ export class BuildAndroidCommand extends BuildCommandBase implements ICommand {
8892
$devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
8993
$platformService: IPlatformService,
9094
$bundleValidatorHelper: IBundleValidatorHelper) {
91-
super($options, $errors, $projectData, $platformsData, $devicePlatformsConstants, $platformService, $bundleValidatorHelper);
95+
super($options, $errors, $projectData, $platformsData, $devicePlatformsConstants, $platformService, $bundleValidatorHelper);
9296
}
9397

9498
public async execute(args: string[]): Promise<void> {
9599
return this.executeCore([this.$platformsData.availablePlatforms.Android]);
96100
}
97101

98102
public async canExecute(args: string[]): Promise<boolean> {
99-
super.validatePlatform(this.$devicePlatformsConstants.Android);
103+
await super.validatePlatform(this.$devicePlatformsConstants.Android);
100104
if (this.$options.release && (!this.$options.keyStorePath || !this.$options.keyStorePassword || !this.$options.keyStoreAlias || !this.$options.keyStoreAliasPassword)) {
101105
this.$errors.fail(ANDROID_RELEASE_BUILD_ERROR_MESSAGE);
102106
}
103107

104-
const platformData = this.$platformsData.getPlatformData(this.$devicePlatformsConstants.Android, this.$projectData);
105-
const platformProjectService = platformData.platformProjectService;
106-
await platformProjectService.validate(this.$projectData);
107-
108108
return args.length === 0 && await this.$platformService.validateOptions(this.$options.provision, this.$options.teamId, this.$projectData, this.$platformsData.availablePlatforms.Android);
109109
}
110110
}

lib/commands/setup.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export class SetupCommand implements ICommand {
2+
public allowedParameters: ICommandParameter[] = [];
3+
4+
constructor(private $doctorService: IDoctorService) { }
5+
6+
public execute(args: string[]): Promise<any> {
7+
return this.$doctorService.runSetupScript();
8+
}
9+
}
10+
$injector.registerCommand("setup|*", SetupCommand);
11+
12+
export class CloudSetupCommand implements ICommand {
13+
public allowedParameters: ICommandParameter[] = [];
14+
15+
constructor(private $nativescriptCloudExtensionService: INativescriptCloudExtensionService) { }
16+
17+
public execute(args: string[]): Promise<any> {
18+
return this.$nativescriptCloudExtensionService.install();
19+
}
20+
}
21+
$injector.registerCommand(["setup|cloud", "cloud|setup"], CloudSetupCommand);

lib/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,5 @@ export const enum BuildStates {
137137
Clean = "Clean",
138138
Incremental = "Incremental"
139139
}
140+
141+
export const NATIVESCRIPT_CLOUD_EXTENSION_NAME = "nativescript-cloud";

0 commit comments

Comments
 (0)