From bcfb9038871ff696f99411ea71596e7dbfea767e Mon Sep 17 00:00:00 2001 From: DimitarTachev Date: Fri, 10 Aug 2018 18:39:26 +0300 Subject: [PATCH 01/13] fix: stop showing the command help on native build error --- lib/services/android-project-service.ts | 14 ++++++++++---- lib/services/ios-project-service.ts | 22 +++++++++++++++------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index c1ea8a4796..6a71bdfb8b 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -701,11 +701,17 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject const childProcessOpts = opts.childProcessOpts || {}; childProcessOpts.cwd = childProcessOpts.cwd || projectRoot; childProcessOpts.stdio = childProcessOpts.stdio || "inherit"; + let commandResult; + try { + commandResult = await this.spawn(gradlew, + gradleArgs, + childProcessOpts, + spawnFromEventOptions); + } catch (err) { + this.$errors.failWithoutHelp(err.message); + } - return await this.spawn(gradlew, - gradleArgs, - childProcessOpts, - spawnFromEventOptions); + return commandResult; } } diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index fd05c066ed..d48ffa805c 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -57,7 +57,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ private $plistParser: IPlistParser, private $sysInfo: ISysInfo, private $xCConfigService: XCConfigService) { - super($fs, $projectDataService); + super($fs, $projectDataService); } private _platformsDirCache: string = null; @@ -442,11 +442,19 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ localArgs.push("-quiet"); this.$logger.info("Xcode build..."); } - return this.$childProcess.spawnFromEvent("xcodebuild", - localArgs, - "exit", - { stdio: stdio || "inherit", cwd }, - { emitOptions: { eventName: constants.BUILD_OUTPUT_EVENT_NAME }, throwError: true }); + + let commandResult; + try { + commandResult = await this.$childProcess.spawnFromEvent("xcodebuild", + localArgs, + "exit", + { stdio: stdio || "inherit", cwd }, + { emitOptions: { eventName: constants.BUILD_OUTPUT_EVENT_NAME }, throwError: true }); + } catch (err) { + this.$errors.failWithoutHelp(err.message); + } + + return commandResult; } private async setupSigningFromTeam(projectRoot: string, projectData: IProjectData, teamId: string) { @@ -1112,7 +1120,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f private async prepareNativeSourceCode(pluginName: string, pluginPlatformsFolderPath: string, projectData: IProjectData): Promise { const project = this.createPbxProj(projectData); const group = this.getRootGroup(pluginName, pluginPlatformsFolderPath); - project.addPbxGroup(group.files, group.name, group.path, null, {isMain:true}); + project.addPbxGroup(group.files, group.name, group.path, null, { isMain: true }); project.addToHeaderSearchPaths(group.path); this.savePbxProj(project, projectData); } From d07c8aeaa05d29a274f79d69207f550b4a5b92a0 Mon Sep 17 00:00:00 2001 From: fatme Date: Mon, 13 Aug 2018 10:33:14 +0300 Subject: [PATCH 02/13] Respect timeout option when getting debugger port --- lib/definitions/ios-debugger-port-service.d.ts | 2 +- lib/services/ios-debug-service.ts | 8 ++++---- lib/services/ios-debugger-port-service.ts | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/definitions/ios-debugger-port-service.d.ts b/lib/definitions/ios-debugger-port-service.d.ts index 50f156afb0..1b6486a0f5 100644 --- a/lib/definitions/ios-debugger-port-service.d.ts +++ b/lib/definitions/ios-debugger-port-service.d.ts @@ -17,7 +17,7 @@ interface IIOSDebuggerPortService { * Gets iOS debugger port for specified deviceId and appId * @param {IIOSDebuggerPortInputData} data - Describes deviceId and appId */ - getPort(data: IIOSDebuggerPortInputData): Promise; + getPort(data: IIOSDebuggerPortInputData, debugOptions?: IDebugOptions): Promise; /** * Attaches on DEBUGGER_PORT_FOUND event and STARTING_IOS_APPLICATION events * In case when DEBUGGER_PORT_FOUND event is emitted, stores the port and clears the timeout if such. diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index c5f48b7f1a..9ee2412f87 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -202,7 +202,7 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS // the VSCode Ext starts `tns debug ios --no-client` to start/attach to debug sessions // check if --no-client is passed - default to opening a tcp socket (versus Chrome DevTools (websocket)) if ((debugOptions.inspector || !debugOptions.client) && this.$hostInfo.isDarwin) { - this._socketProxy = await this.$socketProxyFactory.createTCPSocketProxy(this.getSocketFactory(debugData, device)); + this._socketProxy = await this.$socketProxyFactory.createTCPSocketProxy(this.getSocketFactory(device, debugData, debugOptions)); await this.openAppInspector(this._socketProxy.address(), debugData, debugOptions); return null; } else { @@ -211,7 +211,7 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS } const deviceIdentifier = device ? device.deviceInfo.identifier : debugData.deviceIdentifier; - this._socketProxy = await this.$socketProxyFactory.createWebSocketProxy(this.getSocketFactory(debugData, device), deviceIdentifier); + this._socketProxy = await this.$socketProxyFactory.createWebSocketProxy(this.getSocketFactory(device, debugData, debugOptions), deviceIdentifier); return this.getChromeDebugUrl(debugOptions, this._socketProxy.options.port); } } @@ -230,9 +230,9 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS } } - private getSocketFactory(debugData: IDebugData, device?: Mobile.IiOSDevice): () => Promise { + private getSocketFactory(device: Mobile.IiOSDevice, debugData: IDebugData, debugOptions: IDebugOptions): () => Promise { const factory = async () => { - const port = await this.$iOSDebuggerPortService.getPort({ projectDir: debugData.projectDir, deviceId: debugData.deviceIdentifier, appId: debugData.applicationIdentifier }); + const port = await this.$iOSDebuggerPortService.getPort({ projectDir: debugData.projectDir, deviceId: debugData.deviceIdentifier, appId: debugData.applicationIdentifier }, debugOptions); if (!port) { this.$errors.fail("NativeScript debugger was not able to get inspector socket port."); } diff --git a/lib/services/ios-debugger-port-service.ts b/lib/services/ios-debugger-port-service.ts index 8dac0bb27e..e52f4b509d 100644 --- a/lib/services/ios-debugger-port-service.ts +++ b/lib/services/ios-debugger-port-service.ts @@ -14,7 +14,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { private $projectDataService: IProjectDataService, private $logger: ILogger) { } - public getPort(data: IIOSDebuggerPortInputData): Promise { + public getPort(data: IIOSDebuggerPortInputData, debugOptions?: IDebugOptions): Promise { return new Promise((resolve, reject) => { if (!this.canStartLookingForDebuggerPort(data)) { resolve(IOSDebuggerPortService.DEFAULT_PORT); @@ -22,7 +22,8 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { } const key = `${data.deviceId}${data.appId}`; - let retryCount: number = 10; + const timeout = this.getTimeout(debugOptions); + let retryCount = Math.max(timeout * 1000 / 500, 10); const interval = setInterval(() => { let port = this.getPortByKey(key); From 0c9d3e6d2bc81acd1a6682da754176f84a7b8b48 Mon Sep 17 00:00:00 2001 From: fatme Date: Mon, 13 Aug 2018 11:51:46 +0300 Subject: [PATCH 03/13] Fix unit tests --- test/services/ios-debugger-port-service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/services/ios-debugger-port-service.ts b/test/services/ios-debugger-port-service.ts index 765d255d11..66d4db19a4 100644 --- a/test/services/ios-debugger-port-service.ts +++ b/test/services/ios-debugger-port-service.ts @@ -157,7 +157,7 @@ describe("iOSDebuggerPortService", () => { } const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId, projectDir: mockProjectDirObj.projectDir }); - clock.tick(10000); + clock.tick(20000); const port = await promise; assert.deepEqual(port, testCase.emittedPort); }); @@ -171,7 +171,7 @@ describe("iOSDebuggerPortService", () => { } const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId, projectDir: mockProjectDirObj.projectDir }); - clock.tick(10000); + clock.tick(20000); const port = await promise; assert.deepEqual(port, testCase.emittedPort); }); From e8c06ab5c095c2296f5a7d1aa897fd6c9aaca29c Mon Sep 17 00:00:00 2001 From: DimitarTachev Date: Tue, 14 Aug 2018 16:34:12 +0300 Subject: [PATCH 04/13] fix: fix the activity regex in order to match activities with capital letters in the package name e.g. org.myApp.MainActivity --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index 9100f6cc82..4ac5712c8d 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 9100f6cc828c6bc2c585c67c2d550425e907b7d8 +Subproject commit 4ac5712c8df99547627a0477b2660c3089ca5b8f From 2072e1089fbbd474c91039c30b98f2225839b831 Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 15 Aug 2018 09:14:00 +0300 Subject: [PATCH 05/13] Update common lib --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index 4ac5712c8d..1383f3e88b 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 4ac5712c8df99547627a0477b2660c3089ca5b8f +Subproject commit 1383f3e88b873cefac8a0c6738ad139727e1f0ed From d3a805f1141fedddd295e479c1ab5ed8e5c6cd5e Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 15 Aug 2018 15:32:54 +0300 Subject: [PATCH 06/13] Bump version to 4.2.2 and add changelog --- CHANGELOG.md | 9 +++++++++ npm-shrinkwrap.json | 2 +- package.json | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2e4bf3540..4203322f21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ NativeScript CLI Changelog ================ +4.2.2 (2018, August 17) +== + +### Fixed +* [Fixed #3818](https://github.com/NativeScript/nativescript-cli/issues/3818): Unable to start application on Android device with a custom activity containing capital letters +* [Fixed #3820](https://github.com/NativeScript/nativescript-cli/issues/3820): A command help is shown on native build error +* [Fixed #3821](https://github.com/NativeScript/nativescript-cli/issues/3821): [Sporadic] Unable to start iOS debugger from VSCode extension + + 4.2.1 (2018, August 10) == diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d03661f709..acd79a388f 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "nativescript", - "version": "4.2.1", + "version": "4.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0f594a1488..d69cb4f040 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "preferGlobal": true, - "version": "4.2.1", + "version": "4.2.2", "author": "Telerik ", "description": "Command-line interface for building NativeScript projects", "bin": { From bf75573bd99d3b39a21e75f3e8d5c3a6691766a4 Mon Sep 17 00:00:00 2001 From: DimitarTachev Date: Wed, 22 Aug 2018 15:19:40 +0300 Subject: [PATCH 07/13] fix: clear the socket timer on timeout (avoid `Cannot set property 'socket' of null` on the next tick) --- lib/services/livesync/android-livesync-tool.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/services/livesync/android-livesync-tool.ts b/lib/services/livesync/android-livesync-tool.ts index 0f319faacb..83054d18c1 100644 --- a/lib/services/livesync/android-livesync-tool.ts +++ b/lib/services/livesync/android-livesync-tool.ts @@ -313,6 +313,10 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool { const connectionTimer = setTimeout(() => { if (!isConnected) { isConnected = true; + if (this.pendingConnectionData && this.pendingConnectionData.socketTimer) { + clearTimeout(this.pendingConnectionData.socketTimer); + } + reject(lastKnownError || new Error("Socket connection timeouted.")); this.pendingConnectionData = null; } From 86c15574fc336d263338309c87229f179ede3024 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 21 Aug 2018 19:10:14 +0300 Subject: [PATCH 08/13] fix: pacote does not respect CLI's proxy configuration Pacote does not respect the proxy settings set with `tns proxy set ...`. Pass the required options and add unit tests for the pacote service (use sinon instead of mocking with injector for the `pacote` and `tar` packages as the service is our wrapper for pacote). --- lib/common | 2 +- lib/definitions/pacote-service.d.ts | 2 +- lib/services/pacote-service.ts | 60 ++++-- test/project-service.ts | 3 + test/services/pacote-service.ts | 282 ++++++++++++++++++++++++++++ 5 files changed, 332 insertions(+), 17 deletions(-) create mode 100644 test/services/pacote-service.ts diff --git a/lib/common b/lib/common index 1383f3e88b..70ba4ca1ac 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 1383f3e88b873cefac8a0c6738ad139727e1f0ed +Subproject commit 70ba4ca1ac271b52c2cafbb4fbdbfb66a00744ed diff --git a/lib/definitions/pacote-service.d.ts b/lib/definitions/pacote-service.d.ts index 9f89b0e6df..8c24302a5c 100644 --- a/lib/definitions/pacote-service.d.ts +++ b/lib/definitions/pacote-service.d.ts @@ -18,7 +18,7 @@ declare global { extractPackage(packageName: string, destinationDirectory: string, options?: IPacoteExtractOptions): Promise; } - interface IPacoteBaseOptions { + interface IPacoteBaseOptions extends IProxySettingsBase { /** * The path to npm cache */ diff --git a/lib/services/pacote-service.ts b/lib/services/pacote-service.ts index a69f12481f..94c12fbd0c 100644 --- a/lib/services/pacote-service.ts +++ b/lib/services/pacote-service.ts @@ -4,48 +4,78 @@ import * as path from "path"; export class PacoteService implements IPacoteService { constructor(private $fs: IFileSystem, - private $npm: INodePackageManager) { } + private $npm: INodePackageManager, + private $proxyService: IProxyService, + private $logger: ILogger) { } public async manifest(packageName: string, options?: IPacoteManifestOptions): Promise { - // In case `tns create myapp --template https://github.com/NativeScript/template-hello-world.git` command is executed, pacote module throws an error if cache option is not provided. - const cache = await this.$npm.getCachePath(); - const manifestOptions = { cache }; + this.$logger.trace(`Calling pacoteService.manifest for packageName: '${packageName}' and options: ${options}`); + const manifestOptions: IPacoteBaseOptions = await this.getPacoteBaseOptions(); if (options) { _.extend(manifestOptions, options); } - if (this.$fs.exists(packageName)) { - packageName = path.resolve(packageName); - } - + packageName = this.getRealPackageName(packageName); + this.$logger.trace(`Calling pacote.manifest for packageName: ${packageName} and options: ${JSON.stringify(manifestOptions, null, 2)}`); return pacote.manifest(packageName, manifestOptions); } public async extractPackage(packageName: string, destinationDirectory: string, options?: IPacoteExtractOptions): Promise { // strip: Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped. More info: https://github.com/npm/node-tar/blob/e89c4d37519b1c20133a9f49d5f6b85fa34c203b/README.md // C: Create an archive + this.$logger.trace(`Calling pacoteService.extractPackage for packageName: '${packageName}', destinationDir: '${destinationDirectory}' and options: ${options}`); const extractOptions = { strip: 1, C: destinationDirectory }; if (options) { _.extend(extractOptions, options); } - if (this.$fs.exists(packageName)) { - packageName = path.resolve(packageName); - } + packageName = this.getRealPackageName(packageName); + const pacoteOptions = await this.getPacoteBaseOptions(); - const cache = await this.$npm.getCachePath(); return new Promise((resolve, reject) => { - const source = pacote.tarball.stream(packageName, { cache }); + this.$logger.trace(`Calling pacoteService.extractPackage for packageName: '${packageName}', destinationDir: '${destinationDirectory}' and options: ${options}`); + + const source = pacote.tarball.stream(packageName, pacoteOptions); source.on("error", (err: Error) => { + this.$logger.trace(`Error in source while trying to extract stream from ${packageName}. Error is ${err}`); reject(err); }); + this.$logger.trace(`Creating extract tar stream with options: ${JSON.stringify(extractOptions, null, 2)}`); const destination = tar.x(extractOptions); source.pipe(destination); - destination.on("error", (err: Error) => reject(err)); - destination.on("finish", () => resolve()); + destination.on("error", (err: Error) => { + this.$logger.trace(`Error in destination while trying to extract stream from ${packageName}. Error is ${err}`); + reject(err); + }); + + destination.on("finish", () => { + this.$logger.trace(`Successfully extracted '${packageName}' to ${destinationDirectory}`); + resolve(); + }); }); } + + private async getPacoteBaseOptions(): Promise { + // In case `tns create myapp --template https://github.com/NativeScript/template-hello-world.git` command is executed, pacote module throws an error if cache option is not provided. + const cache = await this.$npm.getCachePath(); + const pacoteOptions = { cache }; + const proxySettings = await this.$proxyService.getCache(); + if (proxySettings) { + _.extend(pacoteOptions, proxySettings); + } + + return pacoteOptions; + } + + private getRealPackageName(packageName: string): string { + if (this.$fs.exists(packageName)) { + this.$logger.trace(`Will resolve the full path to package ${packageName}.`); + packageName = path.resolve(packageName); + } + + return packageName; + } } $injector.register("pacoteService", PacoteService); diff --git a/test/project-service.ts b/test/project-service.ts index 441e8ca461..2e887c6eb0 100644 --- a/test/project-service.ts +++ b/test/project-service.ts @@ -152,6 +152,9 @@ class ProjectIntegrationTest { executeAfterHooks: async (commandName: string, hookArguments?: IDictionary): Promise => undefined }); this.testInjector.register("pacoteService", PacoteService); + this.testInjector.register("proxyService", { + getCache: async (): Promise => null + }); } } diff --git a/test/services/pacote-service.ts b/test/services/pacote-service.ts new file mode 100644 index 0000000000..1d00ae4bc8 --- /dev/null +++ b/test/services/pacote-service.ts @@ -0,0 +1,282 @@ +import { Yok } from "../../lib/common/yok"; +import { assert } from "chai"; +import { PacoteService } from '../../lib/services/pacote-service'; +import { LoggerStub } from "../stubs"; +import { sandbox, SinonSandbox, SinonStub } from "sinon"; +import { EventEmitter } from "events"; +const pacote = require("pacote"); +const tar = require("tar"); +const path = require("path"); + +const npmCachePath = "npmCachePath"; +const packageName = "testPackage"; +const fullPath = `/Users/username/${packageName}`; +const destinationDir = "destinationDir"; +const defaultPacoteOpts: IPacoteBaseOptions = { cache: npmCachePath }; +const errorMessage = "error message"; +const proxySettings: IProxySettings = { + hostname: "hostname", + proxy: "proxy", + port: "8888", + rejectUnauthorized: true, + username: null, + password: null +}; + +interface ITestSetup { + isLocalPackage?: boolean; + useProxySettings?: boolean; + npmGetCachePathError?: Error; +} + +interface ITestCase extends ITestSetup { + manifestOptions?: IPacoteManifestOptions; + additionalExtractOpts?: IPacoteExtractOptions; + name: string; + expectedArgs: any[]; +} + +const createTestInjector = (opts?: ITestSetup): IInjector => { + opts = opts || {}; + + const testInjector = new Yok(); + testInjector.register("logger", LoggerStub); + testInjector.register("pacoteService", PacoteService); + testInjector.register("fs", { + exists: (p: string): boolean => opts.isLocalPackage + }); + + testInjector.register("proxyService", { + getCache: async (): Promise => opts.useProxySettings ? proxySettings : null + }); + + testInjector.register("npm", { + getCachePath: async (): Promise => { + if (opts.npmGetCachePathError) { + throw opts.npmGetCachePathError; + } + + return npmCachePath; + } + }); + + return testInjector; +}; + +class MockStream extends EventEmitter { + public pipe(destination: any, options?: { end?: boolean; }): any { + // Nothing to do here, just mock the method. + } +} + +describe("pacoteService", () => { + const manifestResult: any = {}; + const manifestOptions: IPacoteManifestOptions = { fullMetadata: true }; + let sandboxInstance: SinonSandbox = null; + let manifestStub: SinonStub = null; + let tarballStreamStub: SinonStub = null; + let tarXStub: SinonStub = null; + let tarballSourceStream: MockStream = null; + let tarExtractDestinationStream: MockStream = null; + + beforeEach(() => { + sandboxInstance = sandbox.create(); + manifestStub = sandboxInstance.stub(pacote, "manifest").returns(Promise.resolve(manifestResult)); + tarballSourceStream = new MockStream(); + tarballStreamStub = sandboxInstance.stub(pacote.tarball, "stream").returns(tarballSourceStream); + tarExtractDestinationStream = new MockStream(); + tarXStub = sandboxInstance.stub(tar, "x").returns(tarExtractDestinationStream); + }); + + afterEach(() => { + sandboxInstance.restore(); + }); + + const setupTest = (opts?: ITestSetup): IPacoteService => { + opts = opts || {}; + const testInjector = createTestInjector(opts); + if (opts.isLocalPackage) { + sandboxInstance.stub(path, "resolve").withArgs(packageName).returns(fullPath); + } + + return testInjector.resolve("pacoteService"); + }; + + describe("manifest", () => { + describe("calls pacote.manifest", () => { + + const testData: ITestCase[] = [ + { + name: "with 'cache' only when no opts are passed", + expectedArgs: [packageName, defaultPacoteOpts] + }, + { + name: "with 'cache' and passed options", + manifestOptions, + expectedArgs: [packageName, _.extend({}, defaultPacoteOpts, manifestOptions)] + }, + { + name: "with 'cache' and proxy settings", + useProxySettings: true, + expectedArgs: [packageName, _.extend({}, defaultPacoteOpts, proxySettings)] + }, + { + name: "with 'cache', passed options and proxy settings when proxy is configured", + manifestOptions, + useProxySettings: true, + expectedArgs: [packageName, _.extend({}, defaultPacoteOpts, manifestOptions, proxySettings)] + }, + { + name: "with full path to file when it is local one", + isLocalPackage: true, + expectedArgs: [fullPath, defaultPacoteOpts] + }, + { + name: "with full path to file, 'cache' and passed options when local path is passed", + manifestOptions, + isLocalPackage: true, + expectedArgs: [fullPath, _.extend({}, defaultPacoteOpts, manifestOptions)] + }, + { + name: "with full path to file, 'cache' and proxy settings when proxy is configured", + manifestOptions, + isLocalPackage: true, + useProxySettings: true, + expectedArgs: [fullPath, _.extend({}, defaultPacoteOpts, manifestOptions, proxySettings)] + }, + { + name: "with full path to file, 'cache', passed options and proxy settings when proxy is configured and local path is passed", + manifestOptions, + useProxySettings: true, + isLocalPackage: true, + expectedArgs: [fullPath, _.extend({}, defaultPacoteOpts, manifestOptions, proxySettings)] + }, + ]; + + testData.forEach(testCase => { + it(testCase.name, async () => { + const pacoteService = setupTest(testCase); + const result = await pacoteService.manifest(packageName, testCase.manifestOptions); + + assert.equal(result, manifestResult); + assert.deepEqual(manifestStub.firstCall.args, testCase.expectedArgs); + }); + }); + }); + + it("fails with npm error when unable to get npm cache", async () => { + const npmGetCachePathError = new Error("npm error"); + const pacoteService = setupTest({ npmGetCachePathError }); + await assert.isRejected(pacoteService.manifest(packageName, null), npmGetCachePathError.message); + }); + }); + + describe("extractPackage", () => { + it("fails with correct error when pacote.tarball.stream raises error event", async () => { + const pacoteService = setupTest(); + + const pacoteExtractPackagePromise = pacoteService.extractPackage(packageName, destinationDir); + setImmediate(() => { + tarballSourceStream.emit("error", new Error(errorMessage)); + }); + + await assert.isRejected(pacoteExtractPackagePromise, errorMessage); + }); + + it("fails with correct error when the destination stream raises error event", async () => { + const pacoteService = setupTest(); + + const pacoteExtractPackagePromise = pacoteService.extractPackage(packageName, destinationDir); + setImmediate(() => { + tarExtractDestinationStream.emit("error", new Error(errorMessage)); + }); + + await assert.isRejected(pacoteExtractPackagePromise, errorMessage); + }); + + it("resolves when the destination stream emits finish event", async () => { + const pacoteService = setupTest(); + + const pacoteExtractPackagePromise = pacoteService.extractPackage(packageName, destinationDir); + setImmediate(() => { + tarExtractDestinationStream.emit("finish"); + }); + + await assert.isFulfilled(pacoteExtractPackagePromise); + }); + + describe("passes correct options to tar.x", () => { + const defaultExtractOpts = { strip: 1, C: destinationDir }; + const additionalExtractOpts: IPacoteExtractOptions = { + filter: (p: string, stat: any) => true + }; + + const testData: ITestCase[] = [ + { + name: "when only default options should be passed", + expectedArgs: [defaultExtractOpts], + }, + { + name: "when additional options are passed", + expectedArgs: [_.extend({}, defaultExtractOpts, additionalExtractOpts)], + additionalExtractOpts + }, + ]; + + testData.forEach(testCase => { + it(testCase.name, async () => { + const pacoteService = setupTest(); + + const pacoteExtractPackagePromise = pacoteService.extractPackage(packageName, destinationDir, testCase.additionalExtractOpts); + setImmediate(() => { + tarExtractDestinationStream.emit("finish"); + }); + + await assert.isFulfilled(pacoteExtractPackagePromise); + + assert.deepEqual(tarXStub.firstCall.args, testCase.expectedArgs); + }); + }); + }); + + describe("passes correct options to pacote.tarball.stream", () => { + const testData: ITestCase[] = [ + { + name: "when proxy is not set", + expectedArgs: [packageName, defaultPacoteOpts] + }, + { + name: "when proxy is not set and a local path is passed", + isLocalPackage: true, + expectedArgs: [fullPath, defaultPacoteOpts] + }, + { + name: "when proxy is set", + useProxySettings: true, + expectedArgs: [packageName, _.extend({}, defaultPacoteOpts, proxySettings)] + }, + { + name: "when proxy is set and a local path is passed", + useProxySettings: true, + isLocalPackage: true, + expectedArgs: [fullPath, _.extend({}, defaultPacoteOpts, proxySettings)] + }, + + ]; + + testData.forEach(testCase => { + it(testCase.name, async () => { + const pacoteService = setupTest(testCase); + + const pacoteExtractPackagePromise = pacoteService.extractPackage(packageName, destinationDir); + setImmediate(() => { + tarExtractDestinationStream.emit("finish"); + }); + + await assert.isFulfilled(pacoteExtractPackagePromise); + assert.deepEqual(tarballStreamStub.firstCall.args, testCase.expectedArgs); + }); + }); + }); + }); +}); From 71b0a4ee4b1bbc59f72357fae082fad7d5aa0d57 Mon Sep 17 00:00:00 2001 From: fatme Date: Thu, 23 Aug 2018 13:24:40 +0300 Subject: [PATCH 09/13] Bump version to 4.2.3 --- npm-shrinkwrap.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index acd79a388f..51098a1a84 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "nativescript", - "version": "4.2.2", + "version": "4.2.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index d69cb4f040..f040e592b2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "preferGlobal": true, - "version": "4.2.2", + "version": "4.2.3", "author": "Telerik ", "description": "Command-line interface for building NativeScript projects", "bin": { From 6a7dda1fd9be05a49c166c78af55b85452ba49cb Mon Sep 17 00:00:00 2001 From: fatme Date: Thu, 23 Aug 2018 13:25:02 +0300 Subject: [PATCH 10/13] Fix connect to port --- lib/services/ios-debug-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index 9ee2412f87..446698b477 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -236,7 +236,7 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS if (!port) { this.$errors.fail("NativeScript debugger was not able to get inspector socket port."); } - const socket = device ? await device.connectToPort(port) : net.connect(port); + const socket = device ? await device.connectToPort(port) : await this.$iOSEmulatorServices.connectToPort({ port }); this._sockets.push(socket); return socket; }; From d15fb00b4240a01677f539a63424dae4d6df53a0 Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 24 Aug 2018 15:10:36 +0300 Subject: [PATCH 11/13] Fix `tns debug ios --inspector` --- lib/common | 2 +- .../ios/socket-proxy-factory.ts | 2 +- lib/services/ios-debug-service.ts | 21 +++++++++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/common b/lib/common index 70ba4ca1ac..9623764190 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 70ba4ca1ac271b52c2cafbb4fbdbfb66a00744ed +Subproject commit 9623764190f3d7e1e64add933d9c31cb2148704d diff --git a/lib/device-sockets/ios/socket-proxy-factory.ts b/lib/device-sockets/ios/socket-proxy-factory.ts index 87eb3390ae..86215b9e05 100644 --- a/lib/device-sockets/ios/socket-proxy-factory.ts +++ b/lib/device-sockets/ios/socket-proxy-factory.ts @@ -90,7 +90,7 @@ export class SocketProxyFactory extends EventEmitter implements ISocketProxyFact this.$logger.info("Frontend client connected."); let _socket; try { - _socket = await factory(); + _socket = await helpers.connectEventuallyUntilTimeout(factory, 10000); } catch (err) { err.deviceIdentifier = deviceIdentifier; this.$logger.trace(err); diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index 446698b477..86ab0644e3 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -231,14 +231,23 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS } private getSocketFactory(device: Mobile.IiOSDevice, debugData: IDebugData, debugOptions: IDebugOptions): () => Promise { + let pendingExecution: Promise = null; const factory = async () => { - const port = await this.$iOSDebuggerPortService.getPort({ projectDir: debugData.projectDir, deviceId: debugData.deviceIdentifier, appId: debugData.applicationIdentifier }, debugOptions); - if (!port) { - this.$errors.fail("NativeScript debugger was not able to get inspector socket port."); + if (!pendingExecution) { + const func = async () => { + const port = await this.$iOSDebuggerPortService.getPort({ projectDir: debugData.projectDir, deviceId: debugData.deviceIdentifier, appId: debugData.applicationIdentifier }, debugOptions); + if (!port) { + this.$errors.fail("NativeScript debugger was not able to get inspector socket port."); + } + const socket = device ? await device.connectToPort(port) : net.connect(port); + this._sockets.push(socket); + pendingExecution = null; + return socket; + }; + pendingExecution = func(); } - const socket = device ? await device.connectToPort(port) : await this.$iOSEmulatorServices.connectToPort({ port }); - this._sockets.push(socket); - return socket; + + return pendingExecution; }; factory.bind(this); From 69c19e3a39625094dc0cd9fb72f9b6625e813c84 Mon Sep 17 00:00:00 2001 From: miroslavaivanova Date: Mon, 27 Aug 2018 16:42:42 +0300 Subject: [PATCH 12/13] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4203322f21..8ca50a1ae2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ NativeScript CLI Changelog ================ +4.2.3 (2018, August 27) +== + +### Fixed +* [Fixed #3840](https://github.com/NativeScript/nativescript-cli/issues/3840): Unable to reconnect to iOS Simulator when debugging +* [Fixed #3824](https://github.com/NativeScript/nativescript-cli/issues/3824): `tns create` command not using proxy set with `tns proxy set` + + 4.2.2 (2018, August 17) == From be85c3f891ffb5c181c5f55bbab7d828ad48bdc4 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 28 Aug 2018 09:31:50 +0300 Subject: [PATCH 13/13] chore: update to latest common lib --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index b02d994287..096936c04f 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit b02d99428798bbb85dac93f1649890d766bd3011 +Subproject commit 096936c04f4d350fbebf2c86811becfaaf392522