Skip to content

chore: merge release in master #5254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Feb 19, 2020
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
NativeScript CLI Changelog
================

6.4.1 (2020, February 19)
===

### Fixed

* [Fixed #5236](https://github.com/NativeScript/nativescript-cli/issues/5236): File paths from device logs are not clickable
* [Fixed #5251](https://github.com/NativeScript/nativescript-cli/issues/5251): External files are not livesynced
* [Fixed #5252](https://github.com/NativeScript/nativescript-cli/issues/5252): Logs from platform specific files point to incorrect file


6.4.0 (2020, February 11)
===

Expand Down
286 changes: 143 additions & 143 deletions lib/common/test/unit-tests/mobile/device-log-provider.ts

Large diffs are not rendered by default.

21 changes: 20 additions & 1 deletion lib/detached-processes/cleanup-process-definitions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ interface ISpawnCommandInfo extends ITimeout {
* Arguments that will be passed to the child process
*/
args: string[];

/**
* Options to be passed to the child process
*/
options?: any;
}

interface IRequestInfo extends ITimeout {
url: string,
method: string,
body: any,
headers: any
}

interface ICleanupMessageBase {
Expand All @@ -38,6 +50,13 @@ interface ISpawnCommandCleanupMessage extends ICleanupMessageBase {
commandInfo: ISpawnCommandInfo;
}

interface IRequestCleanupMessage extends ICleanupMessageBase {
/**
* Describes the request that must be executed
*/
requestInfo: IRequestInfo;
}

interface IFileCleanupMessage extends ICleanupMessageBase, IFilePath { }

interface IJSCommand extends ITimeout, IFilePath {
Expand All @@ -46,4 +65,4 @@ interface IJSCommand extends ITimeout, IFilePath {

interface IJSCleanupMessage extends ICleanupMessageBase {
jsCommand: IJSCommand;
}
}
50 changes: 48 additions & 2 deletions lib/detached-processes/cleanup-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ fileLogService.logData({ message: "Initializing Cleanup process." });
const commandsInfos: ISpawnCommandInfo[] = [];
const filesToDelete: string[] = [];
const jsCommands: IJSCommand[] = [];
const requests: IRequestInfo[] = [];

const executeRequest = async (request: IRequestInfo) => {
const $httpClient = $injector.resolve<Server.IHttpClient>("httpClient");
try {
fileLogService.logData({ message: `Start executing request: ${request.method} ${request.url}` });
const response = await $httpClient.httpRequest({
url: request.url,
method: request.method,
headers: request.headers,
body: request.body
});
const responseStatus = response && response.response && response.response.statusCode;
fileLogService.logData({ message: `Finished executing request: ${request.method} ${request.url} and got status ${responseStatus}` });
} catch (e) {
fileLogService.logData({ message: `Unable to execute request: ${request.method} ${request.url}` });
}
};

const executeJSCleanup = async (jsCommand: IJSCommand) => {
const $childProcess = $injector.resolve<IChildProcess>("childProcess");
Expand All @@ -28,7 +46,7 @@ const executeJSCleanup = async (jsCommand: IJSCommand) => {
fileLogService.logData({ message: `Start executing action for file: ${jsCommand.filePath} and data ${JSON.stringify(jsCommand.data)}` });

await $childProcess.trySpawnFromCloseEvent(process.execPath, [path.join(__dirname, "cleanup-js-subprocess.js"), pathToBootstrap, logFile, jsCommand.filePath, JSON.stringify(jsCommand.data)], {}, { throwError: true, timeout: jsCommand.timeout || 3000 });
fileLogService.logData({ message: `Finished xecuting action for file: ${jsCommand.filePath} and data ${JSON.stringify(jsCommand.data)}` });
fileLogService.logData({ message: `Finished executing action for file: ${jsCommand.filePath} and data ${JSON.stringify(jsCommand.data)}` });

} catch (err) {
fileLogService.logData({ message: `Unable to execute action for file ${jsCommand.filePath} with data ${JSON.stringify(jsCommand.data)}. Error is: ${err}.`, type: FileLogMessageType.Error });
Expand All @@ -38,6 +56,10 @@ const executeJSCleanup = async (jsCommand: IJSCommand) => {
const executeCleanup = async () => {
const $childProcess = $injector.resolve<IChildProcess>("childProcess");

for (const request of requests) {
await executeRequest(request);
}

for (const jsCommand of jsCommands) {
await executeJSCleanup(jsCommand);
}
Expand All @@ -46,7 +68,7 @@ const executeCleanup = async () => {
try {
fileLogService.logData({ message: `Start executing command: ${JSON.stringify(commandInfo)}` });

await $childProcess.trySpawnFromCloseEvent(commandInfo.command, commandInfo.args, {}, { throwError: true, timeout: commandInfo.timeout || 3000 });
await $childProcess.trySpawnFromCloseEvent(commandInfo.command, commandInfo.args, commandInfo.options || {}, { throwError: true, timeout: commandInfo.timeout || 3000 });
fileLogService.logData({ message: `Successfully executed command: ${JSON.stringify(commandInfo)}` });
} catch (err) {
fileLogService.logData({ message: `Unable to execute command: ${JSON.stringify(commandInfo)}. Error is: ${err}.`, type: FileLogMessageType.Error });
Expand Down Expand Up @@ -84,6 +106,24 @@ const removeCleanupAction = (commandInfo: ISpawnCommandInfo): void => {
}
};

const addRequest = (requestInfo: IRequestInfo): void => {
if (_.some(requests, currentRequestInfo => _.isEqual(currentRequestInfo, requestInfo))) {
fileLogService.logData({ message: `cleanup-process will not add request for execution as it has been added already: ${JSON.stringify(requestInfo)}` });
} else {
fileLogService.logData({ message: `cleanup-process added request for execution: ${JSON.stringify(requestInfo)}` });
requests.push(requestInfo);
}
};

const removeRequest = (requestInfo: IRequestInfo): void => {
if (_.some(requests, currentRequestInfo => _.isEqual(currentRequestInfo, currentRequestInfo))) {
_.remove(requests, currentRequestInfo => _.isEqual(currentRequestInfo, requestInfo));
fileLogService.logData({ message: `cleanup-process removed request for execution: ${JSON.stringify(requestInfo)}` });
} else {
fileLogService.logData({ message: `cleanup-process cannot remove request for execution as it has not been added before: ${JSON.stringify(requestInfo)}` });
}
};

const addDeleteAction = (filePath: string): void => {
const fullPath = path.resolve(filePath);

Expand Down Expand Up @@ -142,6 +182,12 @@ process.on("message", async (cleanupProcessMessage: ICleanupMessageBase) => {
case CleanupProcessMessage.RemoveCleanCommand:
removeCleanupAction((<ISpawnCommandCleanupMessage>cleanupProcessMessage).commandInfo);
break;
case CleanupProcessMessage.AddRequest:
addRequest((<IRequestCleanupMessage>cleanupProcessMessage).requestInfo);
break;
case CleanupProcessMessage.RemoveRequest:
removeRequest((<IRequestCleanupMessage>cleanupProcessMessage).requestInfo);
break;
case CleanupProcessMessage.AddDeleteFileAction:
addDeleteAction((<IFileCleanupMessage>cleanupProcessMessage).filePath);
break;
Expand Down
9 changes: 9 additions & 0 deletions lib/detached-processes/detached-process-enums.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ declare const enum CleanupProcessMessage {
* This type of message defines that cleanup procedure should not execute previously defined cleanup command.
*/
RemoveCleanCommand = "RemoveCleanCommand",
/**
* This type of message defines that cleanup procedure should execute specific request.
*/
AddRequest = "AddRequest",

/**
* This type of message defines that cleanup procedure should not execute previously defined request.
*/
RemoveRequest = "RemoveRequest",

/**
* This type of message defines that cleanup procedure should delete specified files.
Expand Down
12 changes: 11 additions & 1 deletion lib/services/cleanup-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ export class CleanupService implements ICleanupService {
cleanupProcess.send(<ISpawnCommandCleanupMessage>{ messageType: CleanupProcessMessage.RemoveCleanCommand, commandInfo });
}

public async addRequest(requestInfo: IRequestInfo): Promise<void> {
const cleanupProcess = await this.getCleanupProcess();
cleanupProcess.send(<IRequestCleanupMessage>{ messageType: CleanupProcessMessage.AddRequest, requestInfo });
}

public async removeRequest(requestInfo: IRequestInfo): Promise<void> {
const cleanupProcess = await this.getCleanupProcess();
cleanupProcess.send(<IRequestCleanupMessage>{ messageType: CleanupProcessMessage.RemoveRequest, requestInfo });
}

public async addCleanupDeleteAction(filePath: string): Promise<void> {
const cleanupProcess = await this.getCleanupProcess();
cleanupProcess.send(<IFileCleanupMessage>{ messageType: CleanupProcessMessage.AddDeleteFileAction, filePath });
Expand All @@ -42,7 +52,7 @@ export class CleanupService implements ICleanupService {

public async removeCleanupJS(jsCommand: IJSCommand): Promise<void> {
const cleanupProcess = await this.getCleanupProcess();
cleanupProcess.send(<IJSCleanupMessage>{ messageType: CleanupProcessMessage.RemoveJSFileToRequire, jsCommand});
cleanupProcess.send(<IJSCleanupMessage>{ messageType: CleanupProcessMessage.RemoveJSFileToRequire, jsCommand });
}

public async addKillProcess(pid: string): Promise<void> {
Expand Down
14 changes: 7 additions & 7 deletions lib/services/ios-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,29 +209,29 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
}

@hook('buildIOS')
public async buildProject(projectRoot: string, projectData: IProjectData, iOSBuildData: IOSBuildData): Promise<void> {
public async buildProject(projectRoot: string, projectData: IProjectData, buildData: IOSBuildData): Promise<void> {
const platformData = this.getPlatformData(projectData);

const handler = (data: any) => {
this.emit(constants.BUILD_OUTPUT_EVENT_NAME, data);
};

if (iOSBuildData.buildForDevice) {
await this.$iOSSigningService.setupSigningForDevice(projectRoot, projectData, iOSBuildData);
if (buildData.buildForDevice) {
await this.$iOSSigningService.setupSigningForDevice(projectRoot, projectData, buildData);
await attachAwaitDetach(constants.BUILD_OUTPUT_EVENT_NAME,
this.$childProcess,
handler,
this.$xcodebuildService.buildForDevice(platformData, projectData, <any>iOSBuildData));
} else if (iOSBuildData.buildForAppStore) {
this.$xcodebuildService.buildForDevice(platformData, projectData, <any>buildData));
} else if (buildData.buildForAppStore) {
await attachAwaitDetach(constants.BUILD_OUTPUT_EVENT_NAME,
this.$childProcess,
handler,
this.$xcodebuildService.buildForAppStore(platformData, projectData, <any>iOSBuildData));
this.$xcodebuildService.buildForAppStore(platformData, projectData, <any>buildData));
} else {
await attachAwaitDetach(constants.BUILD_OUTPUT_EVENT_NAME,
this.$childProcess,
handler,
this.$xcodebuildService.buildForSimulator(platformData, projectData, <any>iOSBuildData));
this.$xcodebuildService.buildForSimulator(platformData, projectData, <any>buildData));
}

this.validateApplicationIdentifier(projectData);
Expand Down
19 changes: 16 additions & 3 deletions lib/services/log-source-map-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ interface IFileLocation {

export class LogSourceMapService implements Mobile.ILogSourceMapService {
private static FILE_PREFIX = "file:///";
private static FILE_PREFIX_REPLACEMENT = "file: ";
private static MEMOIZE_FUNCTION_RANDOM_KEY_FOR_JOIN = "__some_random_value__";
private getProjectData: (projectDir: string) => IProjectData;
private getRuntimeVersion: (projectDir: string, platform: string) => string;
private cache: IDictionary<sourcemap.SourceMapConsumer> = {};
private originalFilesLocationCache: IStringDictionary = {};

private get $platformsDataService(): IPlatformsDataService {
return this.$injector.resolve<IPlatformsDataService>("platformsDataService");
Expand Down Expand Up @@ -81,9 +83,9 @@ export class LogSourceMapService implements Mobile.ILogSourceMapService {
const lastIndexOfFile = rawLine.lastIndexOf(LogSourceMapService.FILE_PREFIX);
const firstPart = rawLine.substr(0, lastIndexOfFile);

outputData += firstPart + rawLine.substr(lastIndexOfFile).replace(/file:\/\/\/.+?:\d+:\d+/, `${LogSourceMapService.FILE_PREFIX}${sourceFile}:${line}:${column}`) + '\n';
outputData += firstPart + rawLine.substr(lastIndexOfFile).replace(/file:\/\/\/.+?:\d+:\d+/, `${LogSourceMapService.FILE_PREFIX_REPLACEMENT}${sourceFile}:${line}:${column}`) + '\n';
} else {
outputData = `${outputData}${parsedLine.messagePrefix}${LogSourceMapService.FILE_PREFIX}${sourceFile}:${line}:${column}${parsedLine.messageSuffix}\n`;
outputData = `${outputData}${parsedLine.messagePrefix}${LogSourceMapService.FILE_PREFIX_REPLACEMENT}${sourceFile}:${line}:${column}${parsedLine.messageSuffix}\n`;
}
} else if (rawLine !== "") {
outputData = `${outputData}${rawLine}\n`;
Expand Down Expand Up @@ -122,7 +124,18 @@ export class LogSourceMapService implements Mobile.ILogSourceMapService {
}

sourceFile = stringReplaceAll(sourceFile, "/", path.sep);
return { sourceFile, line: originalPosition.line, column: originalPosition.column };
if (!this.originalFilesLocationCache[sourceFile]) {
const { dir, ext, name } = path.parse(sourceFile);
const platformSpecificName = `${name}.${platform.toLowerCase()}`;
const platformSpecificFile = path.format({ dir, ext, name: platformSpecificName });
if (this.$fs.exists(platformSpecificFile)) {
this.originalFilesLocationCache[sourceFile] = platformSpecificFile;
} else {
this.originalFilesLocationCache[sourceFile] = sourceFile;
}
}

return { sourceFile: this.originalFilesLocationCache[sourceFile], line: originalPosition.line, column: originalPosition.column };
}
}
}
Expand Down
13 changes: 8 additions & 5 deletions lib/services/webpack/webpack-compiler-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,8 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
return;
}

// the hash of the compilation is the same as the previous one
if (this.expectedHashes[platformData.platformNameLowerCase] === message.hash) {
return;
}

// Persist the previousHash value before calling `this.getUpdatedEmittedFiles` as it will modify the expectedHashes object with the current hash
const previousHash = this.expectedHashes[platformData.platformNameLowerCase];
let result;

if (prepareData.hmr) {
Expand All @@ -78,6 +75,12 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
};

this.$logger.trace("Generated data from webpack message:", data);

// the hash of the compilation is the same as the previous one and there are only hot updates produced
if (data.hasOnlyHotUpdateFiles && previousHash === message.hash) {
return;
}

if (data.files.length) {
this.emit(WEBPACK_COMPILATION_COMPLETE, data);
}
Expand Down
14 changes: 7 additions & 7 deletions test/services/log-source-map-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ const testCases: IDictionary<Array<{ caseName: string, message: string, expected
{
caseName: "trace message",
message: "JS: at module.exports.push../main-view-model.ts.HelloWorldModel.onTap (file:///data/data/org.nativescript.sourceMap/files/app/bundle.js:303:17)",
expected: `JS: at module.exports.push../main-view-model.ts.HelloWorldModel.onTap file:///${toPlatformSep("src/main-view-model.ts")}:30:16\n`
expected: `JS: at module.exports.push../main-view-model.ts.HelloWorldModel.onTap file: ${toPlatformSep("src/main-view-model.ts")}:30:16\n`
},
{
caseName: "error message",
message: "System.err: Frame: function:'module.exports.push../main-view-model.ts.HelloWorldModel.onTap', file:'file:///data/data/org.nativescript.sourceMap/files/app/bundle.js', line: 304, column: 15",
expected: `System.err: Frame: function:'module.exports.push../main-view-model.ts.HelloWorldModel.onTap', file:'file:///${toPlatformSep("src/main-view-model.ts")}:31:14\n`
expected: `System.err: Frame: function:'module.exports.push../main-view-model.ts.HelloWorldModel.onTap', file:'file: ${toPlatformSep("src/main-view-model.ts")}:31:14\n`
},
{
caseName: "error message no match",
Expand All @@ -75,22 +75,22 @@ const testCases: IDictionary<Array<{ caseName: string, message: string, expected
{
caseName: "console message",
message: "CONSOLE LOG file:///app/bundle.js:294:20: Test.",
expected: `CONSOLE LOG file:///${toPlatformSep("src/main-view-model.ts")}:29:20 Test.\n`
expected: `CONSOLE LOG file: ${toPlatformSep("src/main-view-model.ts")}:29:20 Test.\n`
},
{
caseName: "trace message",
message: "CONSOLE TRACE file:///app/bundle.js:295:22: Test",
expected: `CONSOLE TRACE file:///${toPlatformSep("src/main-view-model.ts")}:30:22 Test\n`
expected: `CONSOLE TRACE file: ${toPlatformSep("src/main-view-model.ts")}:30:22 Test\n`
},
{
caseName: "error message",
message: "file:///app/bundle.js:296:32: JS ERROR Error: Test",
expected: `file:///${toPlatformSep("src/main-view-model.ts")}:31:31 JS ERROR Error: Test\n`
expected: `file: ${toPlatformSep("src/main-view-model.ts")}:31:31 JS ERROR Error: Test\n`
},
{
caseName: "error stack tracew",
message: "onTap@file:///app/bundle.js:296:32",
expected: `onTap@file:///${toPlatformSep("src/main-view-model.ts")}:31:31\n`
expected: `onTap@file: ${toPlatformSep("src/main-view-model.ts")}:31:31\n`
},
{
caseName: "error message no match",
Expand All @@ -101,7 +101,7 @@ const testCases: IDictionary<Array<{ caseName: string, message: string, expected
caseName: "error stack trace (new runtime)",
runtimeVersion: "6.1.0",
message: "onTap(file:///app/bundle.js:296:22)",
expected: `onTap(file:///${toPlatformSep("src/main-view-model.ts")}:31:18)\n`
expected: `onTap(file: ${toPlatformSep("src/main-view-model.ts")}:31:18)\n`
},
]
};
Expand Down