Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

index.js 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. 'use strict';
  2. const {promisify} = require('util');
  3. const path = require('path');
  4. const childProcess = require('child_process');
  5. const fs = require('fs');
  6. const isWsl = require('is-wsl');
  7. const isDocker = require('is-docker');
  8. const pAccess = promisify(fs.access);
  9. const pExecFile = promisify(childProcess.execFile);
  10. // Path to included `xdg-open`.
  11. const localXdgOpenPath = path.join(__dirname, 'xdg-open');
  12. // Convert a path from WSL format to Windows format:
  13. // `/mnt/c/Program Files/Example/MyApp.exe` → `C:\Program Files\Example\MyApp.exe`
  14. const wslToWindowsPath = async path => {
  15. const {stdout} = await pExecFile('wslpath', ['-w', path]);
  16. return stdout.trim();
  17. };
  18. module.exports = async (target, options) => {
  19. if (typeof target !== 'string') {
  20. throw new TypeError('Expected a `target`');
  21. }
  22. options = {
  23. wait: false,
  24. background: false,
  25. allowNonzeroExitCode: false,
  26. ...options
  27. };
  28. let command;
  29. let {app} = options;
  30. let appArguments = [];
  31. const cliArguments = [];
  32. const childProcessOptions = {};
  33. if (Array.isArray(app)) {
  34. appArguments = app.slice(1);
  35. app = app[0];
  36. }
  37. if (process.platform === 'darwin') {
  38. command = 'open';
  39. if (options.wait) {
  40. cliArguments.push('--wait-apps');
  41. }
  42. if (options.background) {
  43. cliArguments.push('--background');
  44. }
  45. if (app) {
  46. cliArguments.push('-a', app);
  47. }
  48. } else if (process.platform === 'win32' || (isWsl && !isDocker())) {
  49. command = 'powershell' + (isWsl ? '.exe' : '');
  50. cliArguments.push(
  51. '-NoProfile',
  52. '-NonInteractive',
  53. '–ExecutionPolicy',
  54. 'Bypass',
  55. '-EncodedCommand'
  56. );
  57. if (!isWsl) {
  58. childProcessOptions.windowsVerbatimArguments = true;
  59. }
  60. const encodedArguments = ['Start'];
  61. if (options.wait) {
  62. encodedArguments.push('-Wait');
  63. }
  64. if (app) {
  65. if (isWsl && app.startsWith('/mnt/')) {
  66. const windowsPath = await wslToWindowsPath(app);
  67. app = windowsPath;
  68. }
  69. // Double quote with double quotes to ensure the inner quotes are passed through.
  70. // Inner quotes are delimited for PowerShell interpretation with backticks.
  71. encodedArguments.push(`"\`"${app}\`""`, '-ArgumentList');
  72. appArguments.unshift(target);
  73. } else {
  74. encodedArguments.push(`"\`"${target}\`""`);
  75. }
  76. if (appArguments.length > 0) {
  77. appArguments = appArguments.map(arg => `"\`"${arg}\`""`);
  78. encodedArguments.push(appArguments.join(','));
  79. }
  80. // Using Base64-encoded command, accepted by PowerShell, to allow special characters.
  81. target = Buffer.from(encodedArguments.join(' '), 'utf16le').toString('base64');
  82. } else {
  83. if (app) {
  84. command = app;
  85. } else {
  86. // When bundled by Webpack, there's no actual package file path and no local `xdg-open`.
  87. const isBundled = !__dirname || __dirname === '/';
  88. // Check if local `xdg-open` exists and is executable.
  89. let exeLocalXdgOpen = false;
  90. try {
  91. await pAccess(localXdgOpenPath, fs.constants.X_OK);
  92. exeLocalXdgOpen = true;
  93. } catch (_) {}
  94. const useSystemXdgOpen = process.versions.electron ||
  95. process.platform === 'android' || isBundled || !exeLocalXdgOpen;
  96. command = useSystemXdgOpen ? 'xdg-open' : localXdgOpenPath;
  97. }
  98. if (appArguments.length > 0) {
  99. cliArguments.push(...appArguments);
  100. }
  101. if (!options.wait) {
  102. // `xdg-open` will block the process unless stdio is ignored
  103. // and it's detached from the parent even if it's unref'd.
  104. childProcessOptions.stdio = 'ignore';
  105. childProcessOptions.detached = true;
  106. }
  107. }
  108. cliArguments.push(target);
  109. if (process.platform === 'darwin' && appArguments.length > 0) {
  110. cliArguments.push('--args', ...appArguments);
  111. }
  112. const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
  113. if (options.wait) {
  114. return new Promise((resolve, reject) => {
  115. subprocess.once('error', reject);
  116. subprocess.once('close', exitCode => {
  117. if (options.allowNonzeroExitCode && exitCode > 0) {
  118. reject(new Error(`Exited with code ${exitCode}`));
  119. return;
  120. }
  121. resolve(subprocess);
  122. });
  123. });
  124. }
  125. subprocess.unref();
  126. return subprocess;
  127. };