You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
3.8 KiB

4 years ago
  1. // based on https://github.com/webpack/webpack/blob/master/bin/webpack.js
  2. /**
  3. * @param {string} command process to run
  4. * @param {string[]} args commandline arguments
  5. * @returns {Promise<void>} promise
  6. */
  7. const runCommand = (command, args) => {
  8. const cp = require("child_process");
  9. return new Promise((resolve, reject) => {
  10. const executedCommand = cp.spawn(command, args, {
  11. stdio: "inherit",
  12. shell: true
  13. });
  14. executedCommand.on("error", error => {
  15. reject(error);
  16. });
  17. executedCommand.on("exit", code => {
  18. if (code === 0) {
  19. resolve();
  20. } else {
  21. reject();
  22. }
  23. });
  24. });
  25. };
  26. const npmGlobalRoot = () => {
  27. const cp = require("child_process");
  28. return new Promise((resolve, reject) => {
  29. const command = cp.spawn("npm", ["root", "-g"]);
  30. command.on("error", error => reject(error));
  31. command.stdout.on("data", data => resolve(data.toString()));
  32. command.stderr.on("data", data => reject(data));
  33. });
  34. };
  35. const runWhenInstalled = (packages, pathForCmd, ...args) => {
  36. const currentPackage = require(pathForCmd);
  37. const func = currentPackage.default;
  38. if (typeof func !== "function") {
  39. throw new Error(`@webpack-cli/${packages} failed to export a default function`);
  40. }
  41. return func(...args);
  42. };
  43. module.exports = function promptForInstallation(packages, ...args) {
  44. const nameOfPackage = "@webpack-cli/" + packages;
  45. let packageIsInstalled = false;
  46. let pathForCmd;
  47. try {
  48. const path = require("path");
  49. const fs = require("fs");
  50. pathForCmd = path.resolve(process.cwd(), "node_modules", "@webpack-cli", packages);
  51. if (!fs.existsSync(pathForCmd)) {
  52. const globalModules = require("global-modules");
  53. pathForCmd = globalModules + "/@webpack-cli/" + packages;
  54. require.resolve(pathForCmd);
  55. } else {
  56. require.resolve(pathForCmd);
  57. }
  58. packageIsInstalled = true;
  59. } catch (err) {
  60. packageIsInstalled = false;
  61. }
  62. if (!packageIsInstalled) {
  63. const path = require("path");
  64. const fs = require("fs");
  65. const readLine = require("readline");
  66. const isYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock"));
  67. const packageManager = isYarn ? "yarn" : "npm";
  68. const options = ["install", "-D", nameOfPackage];
  69. if (isYarn) {
  70. options[0] = "add";
  71. }
  72. if (packages === "init") {
  73. if (isYarn) {
  74. options.splice(1, 1); // remove '-D'
  75. options.splice(0, 0, "global");
  76. } else {
  77. options[1] = "-g";
  78. }
  79. }
  80. const commandToBeRun = `${packageManager} ${options.join(" ")}`;
  81. const question = `Would you like to install ${packages}? (That will run ${commandToBeRun}) (yes/NO) : `;
  82. console.error(`The command moved into a separate package: ${nameOfPackage}`);
  83. const questionInterface = readLine.createInterface({
  84. input: process.stdin,
  85. output: process.stdout
  86. });
  87. questionInterface.question(question, answer => {
  88. questionInterface.close();
  89. switch (answer.toLowerCase()) {
  90. case "y":
  91. case "yes":
  92. case "1": {
  93. runCommand(packageManager, options)
  94. .then(_ => {
  95. if (packages === "init") {
  96. npmGlobalRoot()
  97. .then(root => {
  98. const pathtoInit = path.resolve(root.trim(), "@webpack-cli", "init");
  99. return pathtoInit;
  100. })
  101. .then(pathForInit => {
  102. return require(pathForInit).default(...args);
  103. })
  104. .catch(error => {
  105. console.error(error);
  106. process.exitCode = 1;
  107. });
  108. return;
  109. }
  110. pathForCmd = path.resolve(process.cwd(), "node_modules", "@webpack-cli", packages);
  111. return runWhenInstalled(packages, pathForCmd, ...args);
  112. })
  113. .catch(error => {
  114. console.error(error);
  115. process.exitCode = 1;
  116. });
  117. break;
  118. }
  119. default: {
  120. console.error(`${nameOfPackage} needs to be installed in order to run the command.`);
  121. process.exitCode = 1;
  122. break;
  123. }
  124. }
  125. });
  126. } else {
  127. return runWhenInstalled(packages, pathForCmd, ...args);
  128. }
  129. };