diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b6445ac82..bf20f9bd3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,24 @@ NativeScript CLI Changelog ================ -6.4.1 (2020, February 19) +6.4.1 (2020, February 21) === +### New + +* [Implemented #5255](https://github.com/NativeScript/nativescript-cli/issues/5255): Warn if the CLI might print sensitive data to the output + ### 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 +* [Fixed #5259](https://github.com/NativeScript/nativescript-cli/issues/5259): Unable to use pnpm on macOS and Linux +* [Fixed #5260](https://github.com/NativeScript/nativescript-cli/issues/5260): `tns package-manager set invalid_value` does not say pnpm is supported +* [Fixed #5261](https://github.com/NativeScript/nativescript-cli/issues/5261): `tns package-manager set ` does not give any output +* [Fixed #5262](https://github.com/NativeScript/nativescript-cli/issues/5262): `tns package-manager` fails with error +* [Fixed #5263](https://github.com/NativeScript/nativescript-cli/issues/5263): `tns package-manager` docs does not list pnpm as supported value +* [Fixed #5264](https://github.com/NativeScript/nativescript-cli/issues/5264): `tns package-manager --help` fails with error 6.4.0 (2020, February 11) diff --git a/docs/man_pages/general/package-manager-get.md b/docs/man_pages/general/package-manager-get.md index ba516da2a3..103e923d05 100644 --- a/docs/man_pages/general/package-manager-get.md +++ b/docs/man_pages/general/package-manager-get.md @@ -21,5 +21,6 @@ General | `$ tns package-manager get` Command | Description ----------|---------- -[package-manager-set](package-manager-set.html) | Enables the specified package manager for the NativeScript CLI. Supported values are npm and yarn. +[package-manager-set](package-manager-set.html) | Enables the specified package manager for the NativeScript CLI. Supported values are npm, yarn and pnpm. +[package-manager-get](package-manager-get.html) | Prints the value of the current package manager. <% } %> \ No newline at end of file diff --git a/docs/man_pages/general/package-manager-set.md b/docs/man_pages/general/package-manager-set.md index 333ae3c93a..aa745b54d6 100644 --- a/docs/man_pages/general/package-manager-set.md +++ b/docs/man_pages/general/package-manager-set.md @@ -7,7 +7,7 @@ position: 18 ### Description -Enables the specified package manager for the NativeScript CLI. Supported values are npm and yarn. +Enables the specified package manager for the NativeScript CLI. Supported values are npm, yarn and pnpm. ### Commands @@ -17,7 +17,7 @@ General | `$ tns package-manager set ` ### Arguments -* `` is the name of the package manager. Supported values are npm and yarn. +* `` is the name of the package manager. Supported values are npm, yarn and pnpm. <% if(isHtml) { %> diff --git a/docs/man_pages/general/package-manager.md b/docs/man_pages/general/package-manager.md new file mode 100644 index 0000000000..9a73a20eca --- /dev/null +++ b/docs/man_pages/general/package-manager.md @@ -0,0 +1,25 @@ +<% if (isJekyll) { %>--- +title: tns package-manager get +position: 19 +---<% } %> + +# tns package-manager get + +### Description + +Prints the value of the current package manager. + +### Commands + +Usage | Synopsis +------|------- +General | `$ tns package-manager get` + +<% if(isHtml) { %> + +### Related Commands + +Command | Description +----------|---------- +[package-manager-set](package-manager-set.html) | Enables the specified package manager for the NativeScript CLI. Supported values are npm, yarn and pnpm. +<% } %> \ No newline at end of file diff --git a/docs/man_pages/start.md b/docs/man_pages/start.md index 50996a387f..d719cbfff2 100644 --- a/docs/man_pages/start.md +++ b/docs/man_pages/start.md @@ -23,6 +23,7 @@ Command | Description [proxy](general/proxy.html) | Displays proxy settings. [migrate](general/migrate.html) | Migrates the app dependencies to a form compatible with NativeScript 6.0. [update](general/update.html) | Updates the project with the latest versions of iOS/Android runtimes and cross-platform modules. +[package-manager](general/package-manager.html) | Prints the value of the current package manager. ## Project Development Commands Command | Description diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index 865c99723b..3e51ddaed5 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -113,8 +113,8 @@ $injector.requirePublic("packageManager", "./package-manager"); $injector.requirePublic("npm", "./node-package-manager"); $injector.requirePublic("yarn", "./yarn-package-manager"); $injector.requirePublic("pnpm", "./pnpm-package-manager"); +$injector.requireCommand("package-manager|*get", "./commands/package-manager-get"); $injector.requireCommand("package-manager|set", "./commands/package-manager-set"); -$injector.requireCommand("package-manager|get", "./commands/package-manager-get"); $injector.require("packageInstallationManager", "./package-installation-manager"); diff --git a/lib/common/commands/package-manager-get.ts b/lib/common/commands/package-manager-get.ts index c6de826b6c..6d3f87e8d0 100644 --- a/lib/common/commands/package-manager-get.ts +++ b/lib/common/commands/package-manager-get.ts @@ -15,8 +15,8 @@ export class PackageManagerGetCommand implements ICommand { } const result = await this.$userSettingsService.getSettingValue("packageManager"); - this.$logger.info(`Your current package manager is ${result || "npm"}.`); + this.$logger.printMarkdown(`Your current package manager is \`${result || "npm"}\`.`); } } -$injector.registerCommand("package-manager|get", PackageManagerGetCommand); +$injector.registerCommand("package-manager|*get", PackageManagerGetCommand); diff --git a/lib/common/commands/package-manager-set.ts b/lib/common/commands/package-manager-set.ts index c9abe185a2..ad302de109 100644 --- a/lib/common/commands/package-manager-set.ts +++ b/lib/common/commands/package-manager-set.ts @@ -1,21 +1,25 @@ +import { PackageManagers } from "../../constants"; export class PackageManagerCommand implements ICommand { constructor(private $userSettingsService: IUserSettingsService, private $errors: IErrors, + private $logger: ILogger, private $stringParameter: ICommandParameter) { } public allowedParameters: ICommandParameter[] = [this.$stringParameter]; - public execute(args: string[]): Promise { - if (args[0] === 'yarn') { - return this.$userSettingsService.saveSetting("packageManager", "yarn"); - } else if (args[0] === 'pnpm') { - return this.$userSettingsService.saveSetting("packageManager", "pnpm"); - } else if (args[0] === 'npm') { - return this.$userSettingsService.saveSetting("packageManager", "npm"); + public async execute(args: string[]): Promise { + const packageManagerName = args[0]; + const supportedPackageManagers = Object.keys(PackageManagers); + if (supportedPackageManagers.indexOf(packageManagerName) === -1) { + this.$errors.fail(`${packageManagerName} is not a valid package manager. Supported values are: ${supportedPackageManagers.join(", ")}.`); } - return this.$errors.fail(`${args[0]} is not a valid package manager. Only yarn or npm are supported.`); + + await this.$userSettingsService.saveSetting("packageManager", packageManagerName); + + this.$logger.printMarkdown(`Please ensure you have the directory containing \`${packageManagerName}\` executable available in your PATH.`); + this.$logger.printMarkdown(`You've successfully set \`${packageManagerName}\` as your package manager.`); } } diff --git a/lib/common/logger/logger.ts b/lib/common/logger/logger.ts index 744d338b14..5d44771e9e 100644 --- a/lib/common/logger/logger.ts +++ b/lib/common/logger/logger.ts @@ -48,6 +48,9 @@ export class Logger implements ILogger { log4js.configure({ appenders, categories }); this.log4jsLogger = log4js.getLogger(); + if (level === LoggerLevel.TRACE || level === LoggerLevel.ALL) { + this.warn(`The "${level}" log level might print some sensitive data like secrets or access tokens in request URLs. Be careful when you share this output.`, { wrapMessageWithBorders: true }); + } } public initializeCliLogger(opts?: ILoggerOptions): void { diff --git a/lib/common/services/help-service.ts b/lib/common/services/help-service.ts index 70edce02eb..60228b5327 100644 --- a/lib/common/services/help-service.ts +++ b/lib/common/services/help-service.ts @@ -183,7 +183,7 @@ export class HelpService implements IHelpService { private async convertCommandNameToFileName(commandData: ICommandData): Promise { let { commandName } = commandData; - const defaultCommandMatch = commandName && commandName.match(/(\w+?)\|\*/); + const defaultCommandMatch = commandName && commandName.match(/([\w-]+?)\|\*/); if (defaultCommandMatch) { this.$logger.trace("Default command found. Replace current command name '%s' with '%s'.", commandName, defaultCommandMatch[1]); commandName = defaultCommandMatch[1]; diff --git a/lib/common/test/unit-tests/mobile/device-log-provider.ts b/lib/common/test/unit-tests/mobile/device-log-provider.ts index def5c9efb2..e2d0188a17 100644 --- a/lib/common/test/unit-tests/mobile/device-log-provider.ts +++ b/lib/common/test/unit-tests/mobile/device-log-provider.ts @@ -39,7 +39,8 @@ const createTestInjector = (): IInjector => { projectIdentifiers: { android: "org.nativescript.appTestLogs", ios: "org.nativescript.appTestLogs" - } + }, + projectDir: "projectDir" }; }, getNSValue: (projectDir: string, propertyName: string): any => { diff --git a/lib/constants.ts b/lib/constants.ts index ae885229f4..e9dcd6366d 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -415,3 +415,9 @@ export enum LoggerConfigData { } export const EMIT_APPENDER_EVENT_NAME = "logData"; + +export enum PackageManagers { + npm = "npm", + pnpm = "pnpm", + yarn = "yarn" +} diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index 9dacaa4111..47b945d5e4 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -76,6 +76,12 @@ interface INodePackageManager { } interface IPackageManager extends INodePackageManager { + /** + * Gets the name of the package manager used for the current process. + * It can be read from the user settings or by passing -- option. + */ + getPackageManagerName(): Promise; + /** * Gets the version corresponding to the tag for the package * @param {string} packageName The name of the package. diff --git a/lib/package-manager.ts b/lib/package-manager.ts index 6e9439f8fc..418919aa79 100644 --- a/lib/package-manager.ts +++ b/lib/package-manager.ts @@ -1,8 +1,10 @@ import { cache, exported, invokeInit } from './common/decorators'; import { performanceLog } from "./common/decorators"; +import { PackageManagers } from './constants'; export class PackageManager implements IPackageManager { private packageManager: INodePackageManager; + private _packageManagerName: string; constructor( private $errors: IErrors, @@ -19,6 +21,11 @@ export class PackageManager implements IPackageManager { this.packageManager = await this._determinePackageManager(); } + @invokeInit() + public async getPackageManagerName(): Promise { + return this._packageManagerName; + } + @exported("packageManager") @performanceLog() @invokeInit() @@ -97,11 +104,14 @@ export class PackageManager implements IPackageManager { this.$errors.fail(`Unable to read package manager config from user settings ${err}`); } - if (pm === 'yarn' || this.$options.yarn) { + if (pm === PackageManagers.yarn || this.$options.yarn) { + this._packageManagerName = PackageManagers.yarn; return this.$yarn; - } else if (pm === 'pnpm' || this.$options.pnpm) { + } else if (pm === PackageManagers.pnpm || this.$options.pnpm) { + this._packageManagerName = PackageManagers.pnpm; return this.$pnpm; } else { + this._packageManagerName = PackageManagers.npm; return this.$npm; } } diff --git a/lib/services/log-source-map-service.ts b/lib/services/log-source-map-service.ts index aabd8b25a3..61c4b6dffb 100644 --- a/lib/services/log-source-map-service.ts +++ b/lib/services/log-source-map-service.ts @@ -128,7 +128,7 @@ export class LogSourceMapService implements Mobile.ILogSourceMapService { 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)) { + if (this.$fs.exists(path.join(projectData.projectDir, platformSpecificFile))) { this.originalFilesLocationCache[sourceFile] = platformSpecificFile; } else { this.originalFilesLocationCache[sourceFile] = sourceFile; diff --git a/lib/services/webpack/webpack-compiler-service.ts b/lib/services/webpack/webpack-compiler-service.ts index 3151f8d813..d95e027c2b 100644 --- a/lib/services/webpack/webpack-compiler-service.ts +++ b/lib/services/webpack/webpack-compiler-service.ts @@ -3,7 +3,7 @@ import * as child_process from "child_process"; import * as semver from "semver"; import { EventEmitter } from "events"; import { performanceLog } from "../../common/decorators"; -import { WEBPACK_COMPILATION_COMPLETE, WEBPACK_PLUGIN_NAME } from "../../constants"; +import { WEBPACK_COMPILATION_COMPLETE, WEBPACK_PLUGIN_NAME, PackageManagers } from "../../constants"; export class WebpackCompilerService extends EventEmitter implements IWebpackCompilerService { private webpackProcesses: IDictionary = {}; @@ -18,6 +18,7 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp private $logger: ILogger, private $mobileHelper: Mobile.IMobileHelper, private $cleanupService: ICleanupService, + private $packageManager: IPackageManager, private $packageInstallationManager: IPackageInstallationManager ) { super(); } @@ -155,6 +156,15 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp } } + private async shouldUsePreserveSymlinksOption(): Promise { + // pnpm does not require symlink (https://github.com/nodejs/node-eps/issues/46#issuecomment-277373566) + // and it also does not work in some cases. + // Check https://github.com/NativeScript/nativescript-cli/issues/5259 for more information + const currentPackageManager = await this.$packageManager.getPackageManagerName(); + const res = currentPackageManager !== PackageManagers.pnpm; + return res; + } + @performanceLog() private async startWebpackProcess(platformData: IPlatformData, projectData: IProjectData, prepareData: IPrepareData): Promise { if (!this.$fs.exists(projectData.webpackConfigPath)) { @@ -164,18 +174,22 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp const envData = this.buildEnvData(platformData.platformNameLowerCase, projectData, prepareData); const envParams = await this.buildEnvCommandLineParams(envData, platformData, projectData, prepareData); const additionalNodeArgs = semver.major(process.version) <= 8 ? ["--harmony"] : []; + + if (await this.shouldUsePreserveSymlinksOption()) { + additionalNodeArgs.push("--preserve-symlinks"); + } + + if (process.arch === "x64") { + additionalNodeArgs.unshift("--max_old_space_size=4096"); + } + const args = [ ...additionalNodeArgs, - "--preserve-symlinks", path.join(projectData.projectDir, "node_modules", "webpack", "bin", "webpack.js"), `--config=${projectData.webpackConfigPath}`, ...envParams ]; - if (process.arch === "x64") { - args.unshift("--max_old_space_size=4096"); - } - if (prepareData.watch) { args.push("--watch"); } diff --git a/test/services/log-source-map-service.ts b/test/services/log-source-map-service.ts index f89697f543..eaaa0f0209 100644 --- a/test/services/log-source-map-service.ts +++ b/test/services/log-source-map-service.ts @@ -19,7 +19,8 @@ function createTestInjector(): IInjector { projectIdentifiers: { android: "org.nativescript.sourceMap", ios: "org.nativescript.sourceMap" - } + }, + projectDir: "projectDir" }; }, getNSValue: (projectDir: string, propertyName: string): any => { diff --git a/test/services/webpack/webpack-compiler-service.ts b/test/services/webpack/webpack-compiler-service.ts index 8da3183c24..a1539ae88f 100644 --- a/test/services/webpack/webpack-compiler-service.ts +++ b/test/services/webpack/webpack-compiler-service.ts @@ -13,6 +13,9 @@ function getAllEmittedFiles(hash: string) { function createTestInjector(): IInjector { const testInjector = new Yok(); + testInjector.register("packageManager", { + getPackageManagerName: async () => "npm" + }); testInjector.register("webpackCompilerService", WebpackCompilerService); testInjector.register("childProcess", {}); testInjector.register("hooksService", {});