install-package.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright Google Inc. All Rights Reserved.
  5. *
  6. * Use of this source code is governed by an MIT-style license that can be
  7. * found in the LICENSE file at https://angular.io/license
  8. */
  9. Object.defineProperty(exports, "__esModule", { value: true });
  10. const child_process_1 = require("child_process");
  11. const fs_1 = require("fs");
  12. const os_1 = require("os");
  13. const path_1 = require("path");
  14. const rimraf = require("rimraf");
  15. const schema_1 = require("../lib/config/schema");
  16. const color_1 = require("../utilities/color");
  17. function installPackage(packageName, logger, packageManager = schema_1.PackageManager.Npm, extraArgs = [], cwd = process.cwd()) {
  18. const packageManagerArgs = getPackageManagerArguments(packageManager);
  19. const installArgs = [
  20. packageManagerArgs.install,
  21. packageName,
  22. packageManagerArgs.silent,
  23. packageManagerArgs.noLockfile,
  24. ];
  25. logger.info(color_1.colors.green(`Installing packages for tooling via ${packageManager}.`));
  26. const { status, stderr, stdout, error } = child_process_1.spawnSync(packageManager, [...installArgs, ...extraArgs], {
  27. stdio: 'pipe',
  28. encoding: 'utf8',
  29. shell: true,
  30. cwd,
  31. });
  32. if (status !== 0) {
  33. let errorMessage = ((error && error.message) || stderr || stdout || '').trim();
  34. if (errorMessage) {
  35. errorMessage += '\n';
  36. }
  37. throw new Error(errorMessage + `Package install failed${errorMessage ? ', see above' : ''}.`);
  38. }
  39. logger.info(color_1.colors.green(`Installed packages for tooling via ${packageManager}.`));
  40. }
  41. exports.installPackage = installPackage;
  42. function installTempPackage(packageName, logger, packageManager = schema_1.PackageManager.Npm) {
  43. const tempPath = fs_1.mkdtempSync(path_1.join(fs_1.realpathSync(os_1.tmpdir()), '.ng-temp-packages-'));
  44. // clean up temp directory on process exit
  45. process.on('exit', () => {
  46. try {
  47. rimraf.sync(tempPath);
  48. }
  49. catch (_a) { }
  50. });
  51. // NPM will warn when a `package.json` is not found in the install directory
  52. // Example:
  53. // npm WARN enoent ENOENT: no such file or directory, open '/tmp/.ng-temp-packages-84Qi7y/package.json'
  54. // npm WARN .ng-temp-packages-84Qi7y No description
  55. // npm WARN .ng-temp-packages-84Qi7y No repository field.
  56. // npm WARN .ng-temp-packages-84Qi7y No license field.
  57. // While we can use `npm init -y` we will end up needing to update the 'package.json' anyways
  58. // because of missing fields.
  59. fs_1.writeFileSync(path_1.join(tempPath, 'package.json'), JSON.stringify({
  60. name: 'temp-cli-install',
  61. description: 'temp-cli-install',
  62. repository: 'temp-cli-install',
  63. license: 'MIT',
  64. }));
  65. // setup prefix/global modules path
  66. const packageManagerArgs = getPackageManagerArguments(packageManager);
  67. const tempNodeModules = path_1.join(tempPath, 'node_modules');
  68. const installArgs = [
  69. packageManagerArgs.prefix,
  70. // Yarn will no append 'node_modules' to the path
  71. packageManager === schema_1.PackageManager.Yarn ? tempNodeModules : tempPath,
  72. packageManagerArgs.noLockfile,
  73. ];
  74. installPackage(packageName, logger, packageManager, installArgs, tempPath);
  75. // Needed to resolve schematics from this location since we use a custom
  76. // resolve strategy in '@angular/devkit-core/node'
  77. // todo: this should be removed when we change the resolutions to use require.resolve
  78. process.env.NG_TEMP_MODULES_DIR = tempNodeModules;
  79. return tempNodeModules;
  80. }
  81. exports.installTempPackage = installTempPackage;
  82. function runTempPackageBin(packageName, logger, packageManager = schema_1.PackageManager.Npm, args = []) {
  83. const tempNodeModulesPath = installTempPackage(packageName, logger, packageManager);
  84. // Remove version/tag etc... from package name
  85. // Ex: @angular/cli@latest -> @angular/cli
  86. const packageNameNoVersion = packageName.substring(0, packageName.lastIndexOf('@'));
  87. const pkgLocation = path_1.join(tempNodeModulesPath, packageNameNoVersion);
  88. const packageJsonPath = path_1.join(pkgLocation, 'package.json');
  89. // Get a binary location for this package
  90. let binPath;
  91. if (fs_1.existsSync(packageJsonPath)) {
  92. const content = fs_1.readFileSync(packageJsonPath, 'utf-8');
  93. if (content) {
  94. const { bin = {} } = JSON.parse(content);
  95. const binKeys = Object.keys(bin);
  96. if (binKeys.length) {
  97. binPath = path_1.resolve(pkgLocation, bin[binKeys[0]]);
  98. }
  99. }
  100. }
  101. if (!binPath) {
  102. throw new Error(`Cannot locate bin for temporary package: ${packageNameNoVersion}.`);
  103. }
  104. const argv = [binPath, ...args];
  105. const { status, error } = child_process_1.spawnSync('node', argv, {
  106. stdio: 'inherit',
  107. shell: true,
  108. env: {
  109. ...process.env,
  110. NG_DISABLE_VERSION_CHECK: 'true',
  111. NG_CLI_ANALYTICS: 'false',
  112. },
  113. });
  114. if (status === null && error) {
  115. throw error;
  116. }
  117. return status || 0;
  118. }
  119. exports.runTempPackageBin = runTempPackageBin;
  120. function getPackageManagerArguments(packageManager) {
  121. switch (packageManager) {
  122. case schema_1.PackageManager.Yarn:
  123. return {
  124. silent: '--silent',
  125. install: 'add',
  126. prefix: '--modules-folder',
  127. noLockfile: '--no-lockfile',
  128. };
  129. case schema_1.PackageManager.Pnpm:
  130. return {
  131. silent: '--silent',
  132. install: 'add',
  133. prefix: '--prefix',
  134. noLockfile: '--no-lockfile',
  135. };
  136. default:
  137. return {
  138. silent: '--quiet',
  139. install: 'install',
  140. prefix: '--prefix',
  141. noLockfile: '--no-package-lock',
  142. };
  143. }
  144. }