prompt-command.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. module.exports = function promptForInstallation(packages, ...args) {
  36. const nameOfPackage = "@webpack-cli/" + packages;
  37. let packageIsInstalled = false;
  38. let pathForCmd;
  39. try {
  40. const path = require("path");
  41. const fs = require("fs");
  42. pathForCmd = path.resolve(process.cwd(), "node_modules", "@webpack-cli", packages);
  43. if (!fs.existsSync(pathForCmd)) {
  44. const globalModules = require("global-modules");
  45. pathForCmd = globalModules + "/@webpack-cli/" + packages;
  46. require.resolve(pathForCmd);
  47. } else {
  48. require.resolve(pathForCmd);
  49. }
  50. packageIsInstalled = true;
  51. } catch (err) {
  52. packageIsInstalled = false;
  53. }
  54. if (!packageIsInstalled) {
  55. const path = require("path");
  56. const fs = require("fs");
  57. const readLine = require("readline");
  58. const isYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock"));
  59. const packageManager = isYarn ? "yarn" : "npm";
  60. const options = ["install", "-D", nameOfPackage];
  61. if (isYarn) {
  62. options[0] = "add";
  63. }
  64. if (packages === "init") {
  65. if (isYarn) {
  66. options.splice(1, 1); // remove '-D'
  67. options.splice(0, 0, "global");
  68. } else {
  69. options[1] = "-g";
  70. }
  71. }
  72. const commandToBeRun = `${packageManager} ${options.join(" ")}`;
  73. const question = `Would you like to install ${packages}? (That will run ${commandToBeRun}) (yes/NO) : `;
  74. console.error(`The command moved into a separate package: ${nameOfPackage}`);
  75. const questionInterface = readLine.createInterface({
  76. input: process.stdin,
  77. output: process.stdout
  78. });
  79. questionInterface.question(question, answer => {
  80. questionInterface.close();
  81. switch (answer.toLowerCase()) {
  82. case "y":
  83. case "yes":
  84. case "1": {
  85. runCommand(packageManager, options)
  86. .then(_=> {
  87. if (packages === "init") {
  88. npmGlobalRoot()
  89. .then((root) => {
  90. const pathtoInit = path.resolve(root.trim(), "@webpack-cli", "init");
  91. return pathtoInit;
  92. })
  93. .then((pathForInit) => {
  94. return require(pathForInit).default(...args);
  95. })
  96. .catch((error) => {
  97. console.error(error);
  98. process.exitCode = 1;
  99. });
  100. return;
  101. }
  102. pathForCmd = path.resolve(process.cwd(), "node_modules", "@webpack-cli", packages);
  103. if (packages === "serve") {
  104. return require(pathForCmd).default.serve();
  105. }
  106. return require(pathForCmd).default(...args); //eslint-disable-line
  107. })
  108. .catch(error => {
  109. console.error(error);
  110. process.exitCode = 1;
  111. });
  112. break;
  113. }
  114. default: {
  115. console.error(`${nameOfPackage} needs to be installed in order to run the command.`);
  116. process.exitCode = 1;
  117. break;
  118. }
  119. }
  120. });
  121. } else {
  122. require(pathForCmd).default(...args); // eslint-disable-line
  123. }
  124. };