Skip to content

Commit cb0de9c

Browse files
committed
Merge branch 'master' into tdermendzhiev/objc-source-support
2 parents 9a33b41 + 8655173 commit cb0de9c

29 files changed

+594
-96
lines changed

CHANGELOG.md

+25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
11
NativeScript CLI Changelog
22
================
33

4+
4.0.2 (2018, May 18)
5+
==
6+
7+
### Fixed
8+
* [Fixed #3595](https://github.com/NativeScript/nativescript-cli/issues/3595): Do not track local paths in Analytics
9+
* [Fixed #3597](https://github.com/NativeScript/nativescript-cli/issues/3597): Users who subscribe to Progess Newsletter are not informed for the privacy policy
10+
11+
4.0.1 (2018, May 11)
12+
==
13+
14+
### New
15+
* [Implemented #3535](https://github.com/NativeScript/nativescript-cli/pull/3535) API: Expose androidProcessService - getAppProcessId method
16+
17+
18+
### Fixed
19+
* [Fixed #1548](https://github.com/NativeScript/nativescript-cli/issues/1548): `--sdk` flag not working properly when starting emulators in iOS
20+
* [Fixed #2131](https://github.com/NativeScript/nativescript-cli/issues/2131): Simulators with `(` in name are not started after `tns run ios --device <device_name>`
21+
* [Fixed #2727](https://github.com/NativeScript/nativescript-cli/issues/2727): Passing more than one parameter on `tns create` returns unappropriate error message
22+
* [Fixed #3529](https://github.com/NativeScript/nativescript-cli/issues/3529): iOS logging does not work on multiple simulators
23+
* [Fixed #3536](https://github.com/NativeScript/nativescript-cli/issues/3536): Message for tracking in Google Analytics is always printed
24+
* [Fixed #3554](https://github.com/NativeScript/nativescript-cli/issues/3554): NativeScript is not compatible with Node.js 10.x.x
25+
* [Fixed #3557](https://github.com/NativeScript/nativescript-cli/pull/3557): Asset generation should not fail in case some App_Resources are missing.
26+
* [Fixed #3560](https://github.com/NativeScript/nativescript-cli/issues/3560): Android build fails when path to app has space and plugin should be build
27+
28+
429
4.0.0 (2018, April 10)
530
==
631

PublicAPI.md

+46
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ const tns = require("nativescript");
5050
* [generateSplashScreens](#generatesplashscreens)
5151
* [androidProcessService](#androidprocessservice)
5252
* [getAppProcessId](#getappprocessid)
53+
* [sysInfo](#sysinfo)
54+
* [getSupportedNodeVersionRange](#getsupportednodeversionrange)
55+
* [getSystemWarnings](#getsystemwarnings)
5356

5457
## Module projectService
5558

@@ -1017,6 +1020,7 @@ tns.liveSyncService.on("debuggerDetached", debugInfo => {
10171020
console.log(`Detached debugger for device with id ${debugInfo.deviceIdentifier}`);
10181021
});
10191022
```
1023+
10201024
## analyticsSettingsService
10211025
Provides methods for accessing the analytics settings file data.
10221026
@@ -1078,6 +1082,7 @@ tns.analyticsSettingsService.getPlaygroundInfo("/my/project/path")
10781082
console.log(playgroundInfo.usedTutorial);
10791083
});
10801084
```
1085+
10811086
## constants
10821087
Contains various constants related to NativeScript.
10831088
@@ -1151,6 +1156,47 @@ tns.androidProcessService.getAppProcessId("4df18f307d8a8f1b", "org.nativescript.
11511156
.catch(err => console.error(`Error while checking for PID: ${err}`));
11521157
```
11531158
1159+
## sysInfo
1160+
The `sysInfo` module exposes methods to get the current environment setup and warnings for it.
1161+
1162+
### getSupportedNodeVersionRange
1163+
The `getSupportedNodeVersionRange` method gives information about the supported Node.js versions for the current CLI. The result is a valid semver range, for example `>=6.0.0`.
1164+
1165+
* Definition
1166+
```TypeScript
1167+
/**
1168+
* Returns the value of engines.node key from CLI's package.json file.
1169+
* @return {string} The range of supported Node.js versions.
1170+
*/
1171+
getSupportedNodeVersionRange(): string;
1172+
```
1173+
1174+
* Usage
1175+
```JavaScript
1176+
const nodeJsRange = tns.sysInfo.getSupportedNodeVersionRange();
1177+
console.log(nodeJsRange);
1178+
```
1179+
1180+
### getSystemWarnings
1181+
The `getSystemWarnings` methods returns all deprecation warnings for current environment. For example, in case the support for the current OS is deprecated by CLI, the method will return array with one message describing the deprecation.
1182+
1183+
* Definition
1184+
```TypeScript
1185+
/**
1186+
* Gets all global warnings for the current environment, for example Node.js version compatibility, OS compatibility, etc.
1187+
* @return {Promise<string[]>} All warnings. Empty array is returned in case the system is setup correctly.
1188+
*/
1189+
getSystemWarnings(): Promise<string[]>;
1190+
```
1191+
1192+
* Usage
1193+
```JavaScript
1194+
tns.sysInfo.getSystemWarnings()
1195+
.then(warnings => {
1196+
warnings.forEach(warn => console.log(warn));
1197+
})
1198+
.catch(err => console.error(`Error while trying to get system warnings: ${err}`));
1199+
```
11541200
11551201
## How to add a new method to Public API
11561202
CLI is designed as command line tool and when it is used as a library, it does not give you access to all of the methods. This is mainly implementation detail. Most of the CLI's code is created to work in command line, not as a library, so before adding method to public API, most probably it will require some modification.

bin/tns

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ var path = require("path"),
66
pathToLib = path.join(__dirname, "..", "lib"),
77
pathToCommon = path.join(pathToLib, "common");
88

9-
require(path.join(pathToCommon, "verify-node-version")).verifyNodeVersion(node, "NativeScript", [ "^4.0.0" ]);
9+
require(path.join(pathToCommon, "verify-node-version")).verifyNodeVersion();
1010

1111
var pathToCliExecutable = path.join(pathToLib, "nativescript-cli.js");
1212

lib/bootstrap.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ $injector.requirePublicClass("liveSyncService", "./services/livesync/livesync-se
125125
$injector.require("androidLiveSyncService", "./services/livesync/android-livesync-service");
126126
$injector.require("iOSLiveSyncService", "./services/livesync/ios-livesync-service");
127127
$injector.require("usbLiveSyncService", "./services/livesync/livesync-service"); // The name is used in https://github.com/NativeScript/nativescript-dev-typescript
128-
$injector.require("sysInfo", "./sys-info");
128+
$injector.requirePublic("sysInfo", "./sys-info");
129129

130130
$injector.require("iOSNotificationService", "./services/ios-notification-service");
131131
$injector.require("socketProxyFactory", "./device-sockets/ios/socket-proxy-factory");
@@ -165,3 +165,5 @@ $injector.require("nativeScriptCloudExtensionService", "./services/nativescript-
165165
$injector.requireCommand("resources|generate|icons", "./commands/generate-assets");
166166
$injector.requireCommand("resources|generate|splashes", "./commands/generate-assets");
167167
$injector.requirePublic("assetsGenerationService", "./services/assets-generation/assets-generation-service");
168+
169+
$injector.require("filesHashService", "./services/files-hash-service");

lib/constants.ts

+19
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require("colors");
2+
13
export const APP_FOLDER_NAME = "app";
24
export const APP_RESOURCES_FOLDER_NAME = "App_Resources";
35
export const PROJECT_FRAMEWORK_FOLDER_NAME = "framework";
@@ -78,6 +80,8 @@ export const RESERVED_TEMPLATE_NAMES: IStringDictionary = {
7880
"angular": "tns-template-hello-world-ng"
7981
};
8082

83+
export const ANALYTICS_LOCAL_TEMPLATE_PREFIX = "localTemplate_";
84+
8185
export class ITMSConstants {
8286
static ApplicationMetadataFile = "metadata.xml";
8387
static VerboseLoggingLevels = {
@@ -170,3 +174,18 @@ export class AssetConstants {
170174
public static defaultScale = 1;
171175
public static defaultOverlayImageScale = 0.8;
172176
}
177+
178+
// https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history
179+
export class MacOSVersions {
180+
public static Sierra = "10.12";
181+
public static HighSierra = "10.13";
182+
}
183+
184+
export const MacOSDeprecationStringFormat = "Support for macOS %s is deprecated and will be removed in one of the next releases of NativeScript. Please, upgrade to the latest macOS version.";
185+
export const PROGRESS_PRIVACY_POLICY_URL = "https://www.progress.com/legal/privacy-policy";
186+
export class SubscribeForNewsletterMessages {
187+
public static AgreeToReceiveEmailMsg = "I agree to receive email communications from Progress Software or its Partners (`https://www.progress.com/partners/partner-directory`)," +
188+
"containing information about Progress Software's products. Consent may be withdrawn at any time.";
189+
public static ReviewPrivacyPolicyMsg = `You can review the Progress Software Privacy Policy at \`${PROGRESS_PRIVACY_POLICY_URL}\``;
190+
public static PromptMsg = "Input your e-mail address to agree".green + " or " + "leave empty to decline".red.bold + ":";
191+
}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface IFilesHashService {
2+
generateHashes(files: string[]): Promise<IStringDictionary>;
3+
getChanges(files: string[], oldHashes: IStringDictionary): Promise<IStringDictionary>;
4+
}

lib/definitions/platform.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ interface IPlatformService extends IBuildPlatformAction, NodeJS.EventEmitter {
8888
* @param {IShouldPrepareInfo} shouldPrepareInfo Options needed to decide whether to prepare.
8989
* @returns {Promise<boolean>} true indicates that the project should be prepared.
9090
*/
91-
shouldPrepare(shouldPrepareInfo: IShouldPrepareInfo): Promise<boolean>
91+
shouldPrepare(shouldPrepareInfo: IShouldPrepareInfo): Promise<boolean>;
9292

9393
/**
9494
* Installs the application on specified device.
@@ -213,7 +213,7 @@ interface IPlatformService extends IBuildPlatformAction, NodeJS.EventEmitter {
213213
* @param {string} buildInfoFileDirname The directory where the build file should be written to.
214214
* @returns {void}
215215
*/
216-
saveBuildInfoFile(platform: string, projectDir: string, buildInfoFileDirname: string): void
216+
saveBuildInfoFile(platform: string, projectDir: string, buildInfoFileDirname: string): void;
217217
}
218218

219219
interface IPlatformOptions extends IPlatformSpecificData, ICreateProjectOptions { }

lib/definitions/project-changes.d.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
interface IPrepareInfo extends IAddedNativePlatform {
1+
interface IAppFilesHashes {
2+
appFilesHashes: IStringDictionary;
3+
}
4+
5+
interface IPrepareInfo extends IAddedNativePlatform, IAppFilesHashes {
26
time: string;
37
bundle: boolean;
48
release: boolean;

lib/nativescript-cli.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require("./bootstrap");
2+
import { EOL } from "os";
23
import * as shelljs from "shelljs";
34
shelljs.config.silent = true;
45
shelljs.config.fatal = true;
@@ -21,6 +22,13 @@ import { settlePromises } from "./common/helpers";
2122
logger.trace("Unable to load extensions. Error is: ", err);
2223
}
2324

25+
const $sysInfo = $injector.resolve<ISysInfo>("sysInfo");
26+
const macOSWarning = await $sysInfo.getMacOSWarningMessage();
27+
if (macOSWarning) {
28+
const message = EOL + macOSWarning + EOL ;
29+
logger.warn(message);
30+
}
31+
2432
const commandDispatcher: ICommandDispatcher = $injector.resolve("commandDispatcher");
2533

2634
const messages: IMessagesService = $injector.resolve("$messagesService");

lib/services/debug-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class DebugService extends EventEmitter implements IDebugService {
3131
await this.$analyticsService.trackEventActionInGoogleAnalytics({
3232
action: TrackActionNames.Debug,
3333
device,
34-
additionalData: this.$mobileHelper.isiOSPlatform(device.deviceInfo.platform) && (!options || !options.chrome) ? DebugTools.Inspector : DebugTools.Chrome,
34+
additionalData: this.$mobileHelper.isiOSPlatform(device.deviceInfo.platform) && options && options.inspector ? DebugTools.Inspector : DebugTools.Chrome,
3535
projectDir: debugData.projectDir
3636
});
3737

lib/services/files-hash-service.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { executeActionByChunks } from "../common/helpers";
2+
import { DEFAULT_CHUNK_SIZE } from "../common/constants";
3+
4+
export class FilesHashService implements IFilesHashService {
5+
constructor(private $fs: IFileSystem,
6+
private $logger: ILogger) { }
7+
8+
public async generateHashes(files: string[]): Promise<IStringDictionary> {
9+
const result: IStringDictionary = {};
10+
11+
const action = async (file: string) => {
12+
try {
13+
const isFile = this.$fs.getFsStats(file).isFile();
14+
if (isFile) {
15+
result[file] = await this.$fs.getFileShasum(file);
16+
}
17+
} catch (err) {
18+
this.$logger.trace(`Unable to generate hash for file ${file}. Error is: ${err}`);
19+
}
20+
};
21+
22+
await executeActionByChunks(files, DEFAULT_CHUNK_SIZE, action);
23+
24+
return result;
25+
}
26+
27+
public async getChanges(files: string[], oldHashes: IStringDictionary): Promise<IStringDictionary> {
28+
const newHashes = await this.generateHashes(files);
29+
return _.omitBy(newHashes, (hash: string, pathToFile: string) => !!_.find(oldHashes, (oldHash: string, oldPath: string) => pathToFile === oldPath && hash === oldHash));
30+
}
31+
}
32+
$injector.register("filesHashService", FilesHashService);

lib/services/livesync/livesync-service.ts

+18-16
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi
4141
super();
4242
}
4343

44-
public async liveSync(deviceDescriptors: ILiveSyncDeviceInfo[],
45-
liveSyncData: ILiveSyncInfo): Promise<void> {
44+
public async liveSync(deviceDescriptors: ILiveSyncDeviceInfo[], liveSyncData: ILiveSyncInfo): Promise<void> {
4645
const projectData = this.$projectDataService.getProjectData(liveSyncData.projectDir);
4746
await this.$pluginsService.ensureAllDependenciesAreInstalled(projectData);
4847
await this.liveSyncOperation(deviceDescriptors, liveSyncData, projectData);
@@ -318,27 +317,19 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi
318317
}
319318

320319
@hook("liveSync")
321-
private async liveSyncOperation(deviceDescriptors: ILiveSyncDeviceInfo[],
322-
liveSyncData: ILiveSyncInfo, projectData: IProjectData): Promise<void> {
320+
private async liveSyncOperation(deviceDescriptors: ILiveSyncDeviceInfo[], liveSyncData: ILiveSyncInfo, projectData: IProjectData): Promise<void> {
323321
// In case liveSync is called for a second time for the same projectDir.
324322
const isAlreadyLiveSyncing = this.liveSyncProcessesInfo[projectData.projectDir] && !this.liveSyncProcessesInfo[projectData.projectDir].isStopped;
325323

326-
// Prevent cases where liveSync is called consecutive times with the same device, for example [ A, B, C ] and then [ A, B, D ] - we want to execute initialSync only for D.
327-
const currentlyRunningDeviceDescriptors = this.getLiveSyncDeviceDescriptors(projectData.projectDir);
328-
const deviceDescriptorsForInitialSync = isAlreadyLiveSyncing ? _.differenceBy(deviceDescriptors, currentlyRunningDeviceDescriptors, deviceDescriptorPrimaryKey) : deviceDescriptors;
329324
this.setLiveSyncProcessInfo(liveSyncData.projectDir, deviceDescriptors);
330325

331-
await this.initialSync(projectData, deviceDescriptorsForInitialSync, liveSyncData);
332-
333326
if (!liveSyncData.skipWatcher && this.liveSyncProcessesInfo[projectData.projectDir].deviceDescriptors.length) {
334327
// Should be set after prepare
335328
this.$usbLiveSyncService.isInitialized = true;
336-
337-
const devicesIds = deviceDescriptors.map(dd => dd.identifier);
338-
const devices = _.filter(this.$devicesService.getDeviceInstances(), device => _.includes(devicesIds, device.deviceInfo.identifier));
339-
const platforms = _(devices).map(device => device.deviceInfo.platform).uniq().value();
340-
await this.startWatcher(projectData, liveSyncData, platforms);
329+
await this.startWatcher(projectData, liveSyncData, deviceDescriptors, { isAlreadyLiveSyncing });
341330
}
331+
332+
await this.initialSync(projectData, liveSyncData, deviceDescriptors, { isAlreadyLiveSyncing });
342333
}
343334

344335
private setLiveSyncProcessInfo(projectDir: string, deviceDescriptors: ILiveSyncDeviceInfo[]): void {
@@ -351,6 +342,13 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi
351342
this.liveSyncProcessesInfo[projectDir].deviceDescriptors = _.uniqBy(currentDeviceDescriptors.concat(deviceDescriptors), deviceDescriptorPrimaryKey);
352343
}
353344

345+
private async initialSync(projectData: IProjectData, liveSyncData: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceInfo[], options: { isAlreadyLiveSyncing: boolean }): Promise<void> {
346+
// Prevent cases where liveSync is called consecutive times with the same device, for example [ A, B, C ] and then [ A, B, D ] - we want to execute initialSync only for D.
347+
const currentlyRunningDeviceDescriptors = this.getLiveSyncDeviceDescriptors(projectData.projectDir);
348+
const deviceDescriptorsForInitialSync = options.isAlreadyLiveSyncing ? _.differenceBy(deviceDescriptors, currentlyRunningDeviceDescriptors, deviceDescriptorPrimaryKey) : deviceDescriptors;
349+
await this.initialSyncCore(projectData, deviceDescriptorsForInitialSync, liveSyncData);
350+
}
351+
354352
private getLiveSyncService(platform: string): IPlatformLiveSyncService {
355353
if (this.$mobileHelper.isiOSPlatform(platform)) {
356354
return this.$injector.resolve("iOSLiveSyncService");
@@ -452,7 +450,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi
452450
return null;
453451
}
454452

455-
private async initialSync(projectData: IProjectData, deviceDescriptors: ILiveSyncDeviceInfo[], liveSyncData: ILiveSyncInfo): Promise<void> {
453+
private async initialSyncCore(projectData: IProjectData, deviceDescriptors: ILiveSyncDeviceInfo[], liveSyncData: ILiveSyncInfo): Promise<void> {
456454
const preparedPlatforms: string[] = [];
457455
const rebuiltInformation: ILiveSyncBuildInfo[] = [];
458456

@@ -483,6 +481,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi
483481
useLiveEdit: liveSyncData.useLiveEdit,
484482
watch: !liveSyncData.skipWatcher
485483
});
484+
486485
await this.$platformService.trackActionForPlatform({ action: "LiveSync", platform: device.deviceInfo.platform, isForDevice: !device.isEmulator, deviceOsVersion: device.deviceInfo.version });
487486
await this.refreshApplication(projectData, liveSyncResultInfo, deviceBuildInfoDescriptor.debugOptions, deviceBuildInfoDescriptor.outputPath);
488487

@@ -525,7 +524,10 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi
525524
};
526525
}
527526

528-
private async startWatcher(projectData: IProjectData, liveSyncData: ILiveSyncInfo, platforms: string[]): Promise<void> {
527+
private async startWatcher(projectData: IProjectData, liveSyncData: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceInfo[], options: { isAlreadyLiveSyncing: boolean }): Promise<void> {
528+
const devicesIds = deviceDescriptors.map(dd => dd.identifier);
529+
const devices = _.filter(this.$devicesService.getDeviceInstances(), device => _.includes(devicesIds, device.deviceInfo.identifier));
530+
const platforms = _(devices).map(device => device.deviceInfo.platform).uniq().value();
529531
const patterns = await this.getWatcherPatterns(liveSyncData, projectData, platforms);
530532

531533
if (liveSyncData.watchAllFiles) {

0 commit comments

Comments
 (0)