diff --git a/CHANGELOG.md b/CHANGELOG.md index edf411cf88..964c7eed2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,33 @@ NativeScript CLI Changelog ================ +1.5.0 (2015, November 24) +== + +### New +* [Implemented #493](https://github.com/NativeScript/nativescript-cli/issues/493): Enable transpilers support in NativeScript projects. +* [Implemented #594](https://github.com/NativeScript/nativescript-cli/issues/594): Implement a hard dependency on the node.js version and exit if not satisfied. +* [Implemented #684](https://github.com/NativeScript/nativescript-cli/issues/684): Enable commands hooks. +* [Implemented #955](https://github.com/NativeScript/nativescript-cli/issues/955): Support for Xcode7 simulator. +* [Implemented #1007](https://github.com/NativeScript/nativescript-cli/issues/1007): Smarter and faster LiveSync. +* [Implemented #1048](https://github.com/NativeScript/nativescript-cli/issues/1048): Support Gradle files from plugins, merge android resource files using aapt and respect AndroidManifest.xml from App_Resources. +* [Implemented #1113](https://github.com/NativeScript/nativescript-cli/issues/1113): Let users create and execute unit tests in their projects. +* [Implemented #1117](https://github.com/NativeScript/nativescript-cli/issues/1117): Support for TypeScript-based NativeScript projects. +* [Implemented #1130](https://github.com/NativeScript/nativescript-cli/issues/1130): Show application output from livesync command for iOS devices and android devices and emulators. +* [Implemented #1164](https://github.com/NativeScript/nativescript-cli/issues/1164): Use android tools from ANDROID_HOME. +* [Implemented #1229](https://github.com/NativeScript/nativescript-cli/issues/1229): Support for Node 5.1.0. + +### Fixed +* [Fixed #727](https://github.com/NativeScript/nativescript-cli/issues/727): Double logging with tns run ios. +* [Fixed #1044](https://github.com/NativeScript/nativescript-cli/issues/1044): iOS debug break on Simulator causes app crash when the debugger is paused on the first line for a long time. +* [Fixed #1086](https://github.com/NativeScript/nativescript-cli/issues/1086): --key-store-path option to look for the keystore file path relative to the app root. +* [Fixed #1106](https://github.com/NativeScript/nativescript-cli/issues/1106): Livesync double restarts for TS projects. +* [Fixed #1110](https://github.com/NativeScript/nativescript-cli/issues/1110): `tns doctor` command should detect invalid java version. +* [Fixed #1167](https://github.com/NativeScript/nativescript-cli/issues/1167): `tns run`, `tns emulate` and `tns deploy` commands do not check if device is available before build. +* [Fixed #1177](https://github.com/NativeScript/nativescript-cli/issues/1177): `tns run` command fails when multiple devices with same platform are attached. +* [Fixed #1185](https://github.com/NativeScript/nativescript-cli/issues/1185): `tns device` command fails when VS Emulator is running. +* [Fixed #1204](https://github.com/NativeScript/nativescript-cli/issues/1204): Incorrect prepare when using npm 3.x. + 1.4.3 (2015, October 21) == diff --git a/PLUGINS.md b/PLUGINS.md index f1909f9724..4e5346a6a4 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -74,14 +74,16 @@ my-plugin/ │ └── AndroidManifest.xml └── ios/ └── Info.plist + └── Podfile ``` -* `index.js`: This file is the CommonJS module which exposes the native API. You can use platform-specific `*.platform.js` files. For example: `index.ios.js` and `index.android.js`. During the plugin installation, the NativeScript CLI will copy the platform resources to the `tns_modules` subdirectory in the correct platform destination in the `platforms` directory of your project.
Alternatively, you can give any name to this CommonJS module. In this case, however, you need to point to this file by setting the `main` key in the `package.json` for the plugin. For more information, see [Folders as Modules](https://nodejs.org/api/modules.html#modules_folders_as_modules). +* `index.js`: This file is the CommonJS module which exposes the native API. You can use platform-specific `*.platform.js` files. For example: `index.ios.js` and `index.android.js`. During the plugin installation, the NativeScript CLI will copy the platform resources to the `tns_modules` subdirectory in the correct platform destination in the `platforms` directory of your project.
Alternatively, you can give any name to this CommonJS module. In this case, however, you need to point to this file by setting the `main` key in the `package.json` for the plugin. For more information, see [Folders as Modules](https://nodejs.org/api/modules.html#modules_folders_as_modules). * `package.json`: This file contains the metadata for your plugin. It sets the supported runtimes, the plugin name and version and any dependencies. The `package.json` specification is described in detail below. * `platforms\android\AndroidManifest.xml`: This file describes any specific configuration changes required for your plugin to work. For example: required permissions. For more information about the format of `AndroidManifest.xml`, see [App Manifest](http://developer.android.com/guide/topics/manifest/manifest-intro.html).
During build, gradle will merge the plugin `AndroidManifest.xml` with the `AndroidManifest.xml` for your project. The NativeScript CLI will not resolve any contradicting or duplicate entries during the merge. After the plugin is installed, you need to manually resolve such issues. * `platforms\android\include.gradle`: This file modifies the native Android configuration of your NativeScript project such as native dependencies, build types and configurations. For more information about the format of `include.gradle`, see [include.gradle file](#includegradle-specification). * `platforms/android/res`: (Optional) This directory contains resources declared by the `AndroidManifest.xml` file. You can look at the folder structure [here](http://developer.android.com/guide/topics/resources/providing-resources.html#ResourceTypes). -* `platforms/ios/Info.plist`: This file describes any specific configuration changes required for your plugin to work. For example: required permissions. For more information about the format of `Info.plist`, see [About Information Property List Files](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html).
During the plugin installation, the NativeScript CLI will merge the plugin `Info.plist` with the `Info.plist` for your project. The NativeScript CLI will not resolve any contradicting or duplicate entries during the merge. After the plugin is installed, you need to manually resolve such issues. +* `platforms/ios/Info.plist`: This file describes any specific configuration changes required for your plugin to work. For example: required permissions. For more information about the format of `Info.plist`, see [About Information Property List Files](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html).
During the plugin installation, the NativeScript CLI will merge the plugin `Info.plist` with the `Info.plist` for your project. The NativeScript CLI will not resolve any contradicting or duplicate entries during the merge. After the plugin is installed, you need to manually resolve such issues. +* `platforms/ios/Podfile`: This file describes the dependency to the library that you want to use. For more information, see [CocoaPods.md](CocoaPods.md). NativeScript plugins which contain both native Android and iOS libraries might have the following directory structure. diff --git a/lib/android-tools-info.ts b/lib/android-tools-info.ts index 84723e6581..7f52036ac6 100644 --- a/lib/android-tools-info.ts +++ b/lib/android-tools-info.ts @@ -44,10 +44,10 @@ export class AndroidToolsInfo implements IAndroidToolsInfo { if(this.validateAndroidHomeEnvVariable(this.androidHome).wait()) { let androidPath = path.join(this.androidHome, "tools", this.androidExecutableName); if(!this.trySetAndroidPath(androidPath).wait() && !this.trySetAndroidPath(this.androidExecutableName).wait()) { - this.$errors.failWithoutHelp(`Unable to find "${this.androidExecutableName}" executable file. Make sure you have set ANDROID_HOME environment variable correctly.`); + this.printMessage(`Unable to find "${this.androidExecutableName}" executable file. Make sure you have set ANDROID_HOME environment variable correctly.`); } } else { - this.$errors.failWithoutHelp("ANDROID_HOME environment variable is not set correctly."); + this.printMessage("ANDROID_HOME environment variable is not set correctly."); } } diff --git a/lib/commands/prepare.ts b/lib/commands/prepare.ts index 7f07f4644e..4fbf79ad92 100644 --- a/lib/commands/prepare.ts +++ b/lib/commands/prepare.ts @@ -2,11 +2,16 @@ "use strict"; export class PrepareCommand implements ICommand { - constructor(private $platformService: IPlatformService, + constructor(private $errors: IErrors, + private $platformService: IPlatformService, private $platformCommandParameter: ICommandParameter) { } execute(args: string[]): IFuture { - return this.$platformService.preparePlatform(args[0]); + return (() => { + if (!this.$platformService.preparePlatform(args[0]).wait()) { + this.$errors.failWithoutHelp("Unable to prepare the project."); + } + }).future()(); } allowedParameters = [this.$platformCommandParameter]; diff --git a/lib/common b/lib/common index 6e5218d5c5..66516b388a 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 6e5218d5c5303f359a5957c559abe613231ffe83 +Subproject commit 66516b388a771dc24018d56367aa5c6f1cbe945d diff --git a/lib/definitions/platform.d.ts b/lib/definitions/platform.d.ts index b3a068c579..7f46dcbdab 100644 --- a/lib/definitions/platform.d.ts +++ b/lib/definitions/platform.d.ts @@ -6,7 +6,7 @@ interface IPlatformService { removePlatforms(platforms: string[]): IFuture; updatePlatforms(platforms: string[]): IFuture; runPlatform(platform: string, buildConfig?: IBuildConfig): IFuture; - preparePlatform(platform: string): IFuture; + preparePlatform(platform: string): IFuture; buildPlatform(platform: string, buildConfig?: IBuildConfig): IFuture; installOnDevice(platform: string, buildConfig?: IBuildConfig): IFuture; deployOnDevice(platform: string, buildConfig?: IBuildConfig): IFuture; diff --git a/lib/providers/device-log-provider.ts b/lib/providers/device-log-provider.ts index 746a60cd65..3b2230f127 100644 --- a/lib/providers/device-log-provider.ts +++ b/lib/providers/device-log-provider.ts @@ -3,7 +3,9 @@ export class DeviceLogProvider implements Mobile.IDeviceLogProvider { //sample line is "I/Web Console( 4438): Received Event: deviceready at file:///storage/emulated/0/Icenium/com.telerik.TestApp/js/index.js:48" - private static LINE_REGEX = /.\/(.+?)\s*\(\s*(\d+?)\): (.*)/; + private static LINE_REGEX = /.\/(.+?)\s*\(\s*\d+?\): (.*)/; + // sample line is "11-23 12:39:07.310 1584 1597 I art : Background sticky concurrent mark sweep GC freed 21966(1780KB) AllocSpace objects, 4(80KB) LOS objects, 77% free, 840KB/3MB, paused 4.018ms total 158.629ms" + private static API_LEVEL_23_LINE_REGEX = /.+?\s+?(?:[A-Z]\s+?)([A-Za-z ]+?)\s+?\: (.*)/; constructor(private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants, private $logger: ILogger) { } @@ -25,15 +27,12 @@ export class DeviceLogProvider implements Mobile.IDeviceLogProvider { private getConsoleLogFromLine(lineText: String): any { let acceptedTags = ["chromium", "Web Console", "JS"]; - let match = lineText.match(DeviceLogProvider.LINE_REGEX); - if (match) { - if(acceptedTags.indexOf(match[1]) !== -1) { - return {tag: match[1], message: match[3]}; - } - } else if (_.any(acceptedTags, (tag: string) => { return lineText.indexOf(tag) !== -1; })) { - return {message: match[3]}; + let match = lineText.match(DeviceLogProvider.LINE_REGEX) || lineText.match(DeviceLogProvider.API_LEVEL_23_LINE_REGEX); + if (match && acceptedTags.indexOf(match[1].trim()) !== -1) { + return {tag: match[1].trim(), message: match[2]}; } - return null; + let matchingTag = _.any(acceptedTags, (tag: string) => { return lineText.indexOf(tag) !== -1; }); + return matchingTag ? { message: lineText } : null; } } $injector.register("deviceLogProvider", DeviceLogProvider); diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index 6a66beccc3..bdca9896d3 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -80,7 +80,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject // this call will fail in case `android` is not set correctly. this.$androidToolsInfo.getPathToAndroidExecutable().wait(); - this.$androidToolsInfo.validateJavacVersion(this.$sysInfo.getSysInfo().wait().javacVersion, {showWarningsAsErrors: true}).wait(); + this.$androidToolsInfo.validateJavacVersion(this.$sysInfo.getSysInfo(path.join(__dirname, "..", "..", "package.json")).wait().javacVersion, {showWarningsAsErrors: true}).wait(); }).future()(); } diff --git a/lib/services/doctor-service.ts b/lib/services/doctor-service.ts index f016d51834..9cc8ec43d7 100644 --- a/lib/services/doctor-service.ts +++ b/lib/services/doctor-service.ts @@ -2,6 +2,7 @@ "use strict"; import {EOL} from "os"; import * as semver from "semver"; +import * as path from "path"; class DoctorService implements IDoctorService { private static MIN_SUPPORTED_POD_VERSION = "0.38.2"; @@ -13,7 +14,7 @@ class DoctorService implements IDoctorService { public printWarnings(): boolean { let result = false; - let sysInfo = this.$sysInfo.getSysInfo().wait(); + let sysInfo = this.$sysInfo.getSysInfo(path.join(__dirname, "..", "..", "package.json")).wait(); if (!sysInfo.adbVer) { this.$logger.warn("WARNING: adb from the Android SDK is not installed or is not configured properly."); diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index ac709a3922..279b33f631 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -76,13 +76,14 @@ class IOSDebugService implements IDebugService { this.$platformService.buildPlatform(this.platform).wait(); let emulatorPackage = this.$platformService.getLatestApplicationPackageForEmulator(platformData).wait(); - let child_process = this.$iOSEmulatorServices.startEmulator(emulatorPackage.packageName, { waitForDebugger: true, captureStdin: true, args: "--nativescript-debug-brk" }).wait(); + let child_process = this.$iOSEmulatorServices.startEmulator(emulatorPackage.packageName, { waitForDebugger: true, captureStdin: true, + args: "--nativescript-debug-brk", appId: this.$projectData.projectId }).wait(); let lineStream = byline(child_process.stdout); lineStream.on('data', (line: NodeBuffer) => { let lineText = line.toString(); - if(lineText && _.startsWith(lineText, emulatorPackage.packageName)) { - let pid = _.trimLeft(lineText, emulatorPackage.packageName + ": "); + if(lineText && _.startsWith(lineText, this.$projectData.projectId)) { + let pid = _.trimLeft(lineText, this.$projectData.projectId + ": "); this.$childProcess.exec(`lldb -p ${pid} -o "process continue"`); } else { diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index 5b7b510829..5cc1698b69 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -154,7 +154,7 @@ export class PlatformService implements IPlatformService { }).future()(); } - public preparePlatform(platform: string): IFuture { + public preparePlatform(platform: string): IFuture { return (() => { this.validatePlatform(platform); @@ -166,12 +166,36 @@ export class PlatformService implements IPlatformService { this.$errors.failWithoutHelp(`Unable to install dependencies. Make sure your package.json is valid and all dependencies are correct. Error is: ${err.message}`); } - this.preparePlatformCore(platform).wait(); - }).future()(); + return this.preparePlatformCore(platform).wait(); + }).future()(); + } + + private checkXmlFiles(sourceFiles: string[]): IFuture { + return (() => { + let xmlHasErrors = false; + let DomParser = require("xmldom").DOMParser; + sourceFiles + .filter(file => _.endsWith(file, ".xml")) + .forEach(file => { + let fileContents = this.$fs.readText(file).wait(); + let hasErrors = false; + let domErrorHandler = (level:any, msg:string) => hasErrors = true; + let parser = new DomParser({ + locator:{}, + errorHandler: domErrorHandler + }); + parser.parseFromString(fileContents, "text/xml"); + xmlHasErrors = xmlHasErrors || hasErrors; + if (xmlHasErrors) { + this.$logger.out("Error: ".red.bold + file + " has syntax errors.".red.bold); + } + }); + return !xmlHasErrors; + }).future()(); } @helpers.hook('prepare') - private preparePlatformCore(platform: string): IFuture { + private preparePlatformCore(platform: string): IFuture { return (() => { platform = platform.toLowerCase(); this.ensurePlatformInstalled(platform).wait(); @@ -206,6 +230,12 @@ export class PlatformService implements IPlatformService { sourceFiles = sourceFiles.filter(source => !minimatch(source, `**/${constants.TNS_MODULES_FOLDER_NAME}/**`, {nocase: true})); } + // verify .xml files are well-formed + let validXmlFiles = this.checkXmlFiles(sourceFiles).wait(); + if (!validXmlFiles) { + return false; + } + // Remove .ts and .js.map files PlatformService.EXCLUDE_FILES_PATTERN.forEach(pattern => sourceFiles = sourceFiles.filter(file => !minimatch(file, pattern, {nocase: true}))); let copyFileFutures = sourceFiles.map(source => { @@ -245,13 +275,16 @@ export class PlatformService implements IPlatformService { platformData.platformProjectService.processConfigurationFilesFromAppResources().wait(); this.$logger.out("Project successfully prepared"); - }).future()(); + return true; + }).future()(); } public buildPlatform(platform: string, buildConfig?: IBuildConfig): IFuture { return (() => { platform = platform.toLowerCase(); - this.preparePlatform(platform).wait(); + if (!this.preparePlatform(platform).wait()) { + this.$errors.failWithoutHelp("Verify that listed files are well-formed and try again the operation."); + } let platformData = this.$platformsData.getPlatformData(platform); platformData.platformProjectService.buildProject(platformData.projectRoot, buildConfig).wait(); diff --git a/lib/services/test-execution-service.ts b/lib/services/test-execution-service.ts index 0ce884f7e1..0fccee6b09 100644 --- a/lib/services/test-execution-service.ts +++ b/lib/services/test-execution-service.ts @@ -33,7 +33,8 @@ class TestExecutionService implements ITestExecutionService { private $logger: ILogger, private $fs: IFileSystem, private $options: IOptions, - private $pluginsService: IPluginsService) { + private $pluginsService: IPluginsService, + private $errors: IErrors) { } public startTestRunner(platform: string) : IFuture { @@ -58,7 +59,9 @@ class TestExecutionService implements ITestExecutionService { let socketIoJs = this.$httpClient.httpRequest(socketIoJsUrl).wait().body; this.$fs.writeFile(path.join(projectDir, TestExecutionService.SOCKETIO_JS_FILE_NAME), socketIoJs).wait(); - this.$platformService.preparePlatform(platform).wait(); + if (!this.$platformService.preparePlatform(platform).wait()) { + this.$errors.failWithoutHelp("Verify that listed files are well-formed and try again the operation."); + } this.detourEntryPoint(projectFilesPath).wait(); let watchGlob = path.join(projectDir, constants.APP_FOLDER_NAME); @@ -88,13 +91,22 @@ class TestExecutionService implements ITestExecutionService { let beforeBatchLiveSyncAction = (filePath: string): IFuture => { return (() => { - this.$platformService.preparePlatform(platform).wait(); + if (!this.$platformService.preparePlatform(platform).wait()) { + this.$logger.out("Verify that listed files are well-formed and try again the operation."); + return; + } return path.join(projectFilesPath, path.relative(path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME), filePath)); }).future()(); }; let localProjectRootPath = platform.toLowerCase() === "ios" ? platformData.appDestinationDirectoryPath : null; + let getApplicationPathForiOSSimulatorAction = (): IFuture => { + return (() => { + return this.$platformService.getLatestApplicationPackageForEmulator(platformData).wait().packageName; + }).future()(); + }; + let liveSyncData = { platform: platform, appIdentifier: this.$projectData.projectId, @@ -104,6 +116,7 @@ class TestExecutionService implements ITestExecutionService { platformSpecificLiveSyncServices: platformSpecificLiveSyncServices, notInstalledAppOnDeviceAction: notInstalledAppOnDeviceAction, notRunningiOSSimulatorAction: notRunningiOSSimulatorAction, + getApplicationPathForiOSSimulatorAction: getApplicationPathForiOSSimulatorAction, localProjectRootPath: localProjectRootPath, beforeBatchLiveSyncAction: beforeBatchLiveSyncAction, shouldRestartApplication: (localToDevicePaths: Mobile.ILocalToDevicePathData[]) => Future.fromResult(!this.$options.debugBrk), diff --git a/lib/services/usb-livesync-service.ts b/lib/services/usb-livesync-service.ts index 79c378cef6..299920d45a 100644 --- a/lib/services/usb-livesync-service.ts +++ b/lib/services/usb-livesync-service.ts @@ -34,6 +34,7 @@ export class UsbLiveSyncService extends usbLivesyncServiceBaseLib.UsbLiveSyncSer private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants, private $projectDataService: IProjectDataService, private $prompter: IPrompter, + private $errors: IErrors, $hostInfo: IHostInfo) { super($devicesService, $mobileHelper, $localToDevicePathDataFactory, $logger, $options, $deviceAppDataFactory, $fs, $dispatcher, $injector, $childProcess, $iOSEmulatorServices, @@ -65,7 +66,9 @@ export class UsbLiveSyncService extends usbLivesyncServiceBaseLib.UsbLiveSyncSer } } - this.$platformService.preparePlatform(platform).wait(); + if (!this.$platformService.preparePlatform(platform).wait()) { + this.$errors.failWithoutHelp("Verify that listed files are well-formed and try again the operation."); + } let projectFilesPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME); @@ -83,7 +86,7 @@ export class UsbLiveSyncService extends usbLivesyncServiceBaseLib.UsbLiveSyncSer let beforeBatchLiveSyncAction = (filePath: string): IFuture => { return (() => { - let projectFileInfo = this.getProjectFileInfo(filePath); + let projectFileInfo = this.getProjectFileInfo(filePath, platform); let mappedFilePath = path.join(projectFilesPath, path.relative(path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME), projectFileInfo.onDeviceName)); // Handle files that are in App_Resources/ @@ -121,7 +124,10 @@ export class UsbLiveSyncService extends usbLivesyncServiceBaseLib.UsbLiveSyncSer let fastLiveSync = (filePath: string) => { this.$dispatcher.dispatch(() => { return (() => { - this.$platformService.preparePlatform(platform).wait(); + if (!this.$platformService.preparePlatform(platform).wait()) { + this.$logger.out("Verify that listed files are well-formed and try again the operation."); + return; + } let mappedFilePath = beforeBatchLiveSyncAction(filePath).wait(); if (this.shouldSynciOSSimulator(platform).wait()) { @@ -148,6 +154,12 @@ export class UsbLiveSyncService extends usbLivesyncServiceBaseLib.UsbLiveSyncSer }); }; + let getApplicationPathForiOSSimulatorAction = (): IFuture => { + return (() => { + return this.$platformService.getLatestApplicationPackageForEmulator(platformData).wait().packageName; + }).future()(); + }; + let liveSyncData = { platform: platform, appIdentifier: this.$projectData.projectId, @@ -157,6 +169,7 @@ export class UsbLiveSyncService extends usbLivesyncServiceBaseLib.UsbLiveSyncSer platformSpecificLiveSyncServices: platformSpecificLiveSyncServices, notInstalledAppOnDeviceAction: notInstalledAppOnDeviceAction, notRunningiOSSimulatorAction: notRunningiOSSimulatorAction, + getApplicationPathForiOSSimulatorAction: getApplicationPathForiOSSimulatorAction, localProjectRootPath: localProjectRootPath, beforeLiveSyncAction: beforeLiveSyncAction, beforeBatchLiveSyncAction: beforeBatchLiveSyncAction, @@ -170,7 +183,10 @@ export class UsbLiveSyncService extends usbLivesyncServiceBaseLib.UsbLiveSyncSer } protected preparePlatformForSync(platform: string) { - this.$platformService.preparePlatform(platform).wait(); + if (!this.$platformService.preparePlatform(platform).wait()) { + this.$logger.out("Verify that listed files are well-formed and try again the operation."); + return; + } } private resolveUsbLiveSyncService(platform: string, device: Mobile.IDevice): IPlatformSpecificUsbLiveSyncService { diff --git a/lib/sys-info.ts b/lib/sys-info.ts index 0a7f1c47b6..6d660177cc 100644 --- a/lib/sys-info.ts +++ b/lib/sys-info.ts @@ -2,23 +2,25 @@ "use strict"; import {SysInfoBase} from "./common/sys-info-base"; +import * as path from "path"; export class SysInfo extends SysInfoBase { constructor(protected $childProcess: IChildProcess, protected $hostInfo: IHostInfo, protected $iTunesValidator: Mobile.IiTunesValidator, protected $logger: ILogger, + protected $winreg: IWinReg, private $androidToolsInfo: IAndroidToolsInfo) { - super($childProcess, $hostInfo, $iTunesValidator, $logger); + super($childProcess, $hostInfo, $iTunesValidator, $logger, $winreg); } - public getSysInfo(androidToolsInfo?: {pathToAdb: string, pathToAndroid: string}): IFuture { + public getSysInfo(pathToPackageJson: string, androidToolsInfo?: {pathToAdb: string, pathToAndroid: string}): IFuture { return ((): ISysInfoData => { let defaultAndroidToolsInfo = { pathToAdb: this.$androidToolsInfo.getPathToAdbFromAndroidHome().wait(), pathToAndroid: this.$androidToolsInfo.getPathToAndroidExecutable().wait() }; - return super.getSysInfo(androidToolsInfo || defaultAndroidToolsInfo).wait(); + return super.getSysInfo(pathToPackageJson || path.join(__dirname, "..", "package.json"), androidToolsInfo || defaultAndroidToolsInfo).wait(); }).future()(); } } diff --git a/package.json b/package.json index 13472763f7..8531b29067 100644 --- a/package.json +++ b/package.json @@ -29,20 +29,20 @@ "broccoli": "0.16.4", "broccoli-funnel": "0.2.3", "bufferpack": "0.0.6", - "bufferutil": "https://github.com/telerik/bufferutil/tarball/v1.0.1.0", + "bufferutil": "https://github.com/telerik/bufferutil/tarball/v1.0.1.1", "byline": "4.2.1", "chalk": "1.1.0", "cli-table": "https://github.com/telerik/cli-table/tarball/v0.3.1.1", "colors": "1.1.2", "esprima": "2.7.0", - "ffi": "https://github.com/icenium/node-ffi/tarball/v2.0.0.0", - "fibers": "https://github.com/icenium/node-fibers/tarball/v1.0.6.2", + "ffi": "https://github.com/icenium/node-ffi/tarball/v2.0.0.1", + "fibers": "https://github.com/icenium/node-fibers/tarball/v1.0.6.3", "filesize": "3.1.2", "gaze": "0.5.1", "gulp": "3.9.0", "iconv-lite": "0.4.11", "inquirer": "0.9.0", - "ios-sim-portable": "1.0.13-epsilon", + "ios-sim-portable": "1.0.15", "lockfile": "1.0.1", "lodash": "3.10.0", "log4js": "0.6.26", @@ -50,6 +50,7 @@ "marked-terminal": "1.5.0", "minimatch": "2.0.10", "mkdirp": "0.5.1", + "moment": "2.10.6", "mute-stream": "0.0.5", "node-inspector": "https://github.com/NativeScript/node-inspector/tarball/v0.7.4.0", "node-uuid": "1.4.3", @@ -61,15 +62,15 @@ "progress-stream": "1.1.1", "prompt": "https://github.com/Icenium/prompt/tarball/master", "properties-parser": "0.2.3", - "ref": "https://github.com/icenium/ref/tarball/v1.1.3.0", - "ref-struct": "https://github.com/telerik/ref-struct/tarball/v1.0.2.0", + "ref": "https://github.com/icenium/ref/tarball/v1.1.3.1", + "ref-struct": "https://github.com/telerik/ref-struct/tarball/v1.0.2.1", "rimraf": "2.4.2", "semver": "5.0.1", "shelljs": "0.5.1", "tabtab": "https://github.com/Icenium/node-tabtab/tarball/master", "temp": "0.8.3", "through2": "2.0.0", - "utf-8-validate": "https://github.com/telerik/utf-8-validate/tarball/v1.0.1.0", + "utf-8-validate": "https://github.com/telerik/utf-8-validate/tarball/v1.0.1.1", "vinyl-filter-since": "2.0.2", "winreg": "0.0.12", "ws": "0.7.1", @@ -98,6 +99,6 @@ }, "license": "Apache-2.0", "engines": { - "node": ">=0.10.40 <0.11.0 || >=0.12.7 <0.13.0 || >=4.2.1 <5.0.0" + "node": ">=0.10.40 <0.11.0 || >=0.12.7 <0.13.0 || >=4.2.1 <5.0.0 || >=5.1.0 <6.0.0" } } diff --git a/test/platform-service.ts b/test/platform-service.ts index a4a766ecb5..edac69f78e 100644 --- a/test/platform-service.ts +++ b/test/platform-service.ts @@ -181,7 +181,8 @@ describe('Platform Service Tests', () => { testInjector.register("fs", fsLib.FileSystem); fs = testInjector.resolve("fs"); }); - it("should process only files in app folder when preparing for iOS platform", () => { + + function prepareDirStructure() { let tempFolder = temp.mkdirSync("prepare platform"); let appFolderPath = path.join(tempFolder, "app"); @@ -193,6 +194,12 @@ describe('Platform Service Tests', () => { let appDestFolderPath = path.join(tempFolder, "appDest"); let appResourcesFolderPath = path.join(appDestFolderPath, "App_Resources"); + return { tempFolder, appFolderPath, app1FolderPath, appDestFolderPath, appResourcesFolderPath }; + } + + it("should process only files in app folder when preparing for iOS platform", () => { + let { tempFolder, appFolderPath, app1FolderPath, appDestFolderPath, appResourcesFolderPath } = prepareDirStructure(); + // Add platform specific files to app and app1 folders let platformSpecificFiles = [ "test1.ios.js", "test1-ios-js", "test2.android.js", "test2-android-js" @@ -242,16 +249,7 @@ describe('Platform Service Tests', () => { assert.isFalse(fs.exists(path.join(appDestFolderPath, "app1")).wait()); }); it("should process only files in app folder when preparing for Android platform", () => { - let tempFolder = temp.mkdirSync("prepare platform"); - - let appFolderPath = path.join(tempFolder, "app"); - fs.createDirectory(appFolderPath).wait(); - - let app1FolderPath = path.join(tempFolder, "app1"); - fs.createDirectory(app1FolderPath).wait(); - - let appDestFolderPath = path.join(tempFolder, "appDest"); - let appResourcesFolderPath = path.join(appDestFolderPath, "App_Resources"); + let { tempFolder, appFolderPath, app1FolderPath, appDestFolderPath, appResourcesFolderPath } = prepareDirStructure(); // Add platform specific files to app and app1 folders let platformSpecificFiles = [ @@ -301,5 +299,42 @@ describe('Platform Service Tests', () => { // Asserts that the files in app1 folder aren't process as platform specific assert.isFalse(fs.exists(path.join(appDestFolderPath, "app1")).wait()); }); + + it("invalid xml is caught", () => { + require("colors"); + let { tempFolder, appFolderPath, appDestFolderPath, appResourcesFolderPath } = prepareDirStructure(); + + // generate invalid xml + let fileFullPath = path.join(appFolderPath, "file.xml"); + fs.writeFile(fileFullPath, "").wait(); + + let platformsData = testInjector.resolve("platformsData"); + platformsData.platformsNames = ["android"]; + platformsData.getPlatformData = (platform: string) => { + return { + appDestinationDirectoryPath: appDestFolderPath, + appResourcesDestinationDirectoryPath: appResourcesFolderPath, + normalizedPlatformName: "Android", + platformProjectService: { + prepareProject: () => Future.fromResult(), + validate: () => Future.fromResult(), + createProject: (projectRoot: string, frameworkDir: string) => Future.fromResult(), + interpolateData: (projectRoot: string) => Future.fromResult(), + afterCreateProject: (projectRoot: string) => Future.fromResult(), + getAppResourcesDestinationDirectoryPath: () => Future.fromResult(""), + processConfigurationFilesFromAppResources: () => Future.fromResult() + } + }; + }; + + let projectData = testInjector.resolve("projectData"); + projectData.projectDir = tempFolder; + + platformService = testInjector.resolve("platformService"); + let result = platformService.preparePlatform("android").wait(); + + // Asserts that prepare has caught invalid xml + assert.isFalse(result); + }); }); });