source: node_modules/open/index.js

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 4.7 KB
RevLine 
[d24f17c]1'use strict';
2const {promisify} = require('util');
3const path = require('path');
4const childProcess = require('child_process');
5const fs = require('fs');
6const isWsl = require('is-wsl');
7const isDocker = require('is-docker');
8
9const pAccess = promisify(fs.access);
10const pReadFile = promisify(fs.readFile);
11
12// Path to included `xdg-open`.
13const localXdgOpenPath = path.join(__dirname, 'xdg-open');
14
15/**
16Get the mount point for fixed drives in WSL.
17
18@inner
19@returns {string} The mount point.
20*/
21const getWslDrivesMountPoint = (() => {
22 // Default value for "root" param
23 // according to https://docs.microsoft.com/en-us/windows/wsl/wsl-config
24 const defaultMountPoint = '/mnt/';
25
26 let mountPoint;
27
28 return async function () {
29 if (mountPoint) {
30 // Return memoized mount point value
31 return mountPoint;
32 }
33
34 const configFilePath = '/etc/wsl.conf';
35
36 let isConfigFileExists = false;
37 try {
38 await pAccess(configFilePath, fs.constants.F_OK);
39 isConfigFileExists = true;
40 } catch (_) {}
41
42 if (!isConfigFileExists) {
43 return defaultMountPoint;
44 }
45
46 const configContent = await pReadFile(configFilePath, {encoding: 'utf8'});
47 const configMountPoint = /root\s*=\s*(.*)/g.exec(configContent);
48
49 if (!configMountPoint) {
50 return defaultMountPoint;
51 }
52
53 mountPoint = configMountPoint[1].trim();
54 mountPoint = mountPoint.endsWith('/') ? mountPoint : mountPoint + '/';
55
56 return mountPoint;
57 };
58})();
59
60module.exports = async (target, options) => {
61 if (typeof target !== 'string') {
62 throw new TypeError('Expected a `target`');
63 }
64
65 options = {
66 wait: false,
67 background: false,
68 allowNonzeroExitCode: false,
69 ...options
70 };
71
72 let command;
73 let {app} = options;
74 let appArguments = [];
75 const cliArguments = [];
76 const childProcessOptions = {};
77
78 if (Array.isArray(app)) {
79 appArguments = app.slice(1);
80 app = app[0];
81 }
82
83 if (process.platform === 'darwin') {
84 command = 'open';
85
86 if (options.wait) {
87 cliArguments.push('--wait-apps');
88 }
89
90 if (options.background) {
91 cliArguments.push('--background');
92 }
93
94 if (app) {
95 cliArguments.push('-a', app);
96 }
97 } else if (process.platform === 'win32' || (isWsl && !isDocker())) {
98 const mountPoint = await getWslDrivesMountPoint();
99
100 command = isWsl ?
101 `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe` :
102 `${process.env.SYSTEMROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell`;
103
104 cliArguments.push(
105 '-NoProfile',
106 '-NonInteractive',
107 '–ExecutionPolicy',
108 'Bypass',
109 '-EncodedCommand'
110 );
111
112 if (!isWsl) {
113 childProcessOptions.windowsVerbatimArguments = true;
114 }
115
116 const encodedArguments = ['Start'];
117
118 if (options.wait) {
119 encodedArguments.push('-Wait');
120 }
121
122 if (app) {
123 // Double quote with double quotes to ensure the inner quotes are passed through.
124 // Inner quotes are delimited for PowerShell interpretation with backticks.
125 encodedArguments.push(`"\`"${app}\`""`, '-ArgumentList');
126 appArguments.unshift(target);
127 } else {
128 encodedArguments.push(`"${target}"`);
129 }
130
131 if (appArguments.length > 0) {
132 appArguments = appArguments.map(arg => `"\`"${arg}\`""`);
133 encodedArguments.push(appArguments.join(','));
134 }
135
136 // Using Base64-encoded command, accepted by PowerShell, to allow special characters.
137 target = Buffer.from(encodedArguments.join(' '), 'utf16le').toString('base64');
138 } else {
139 if (app) {
140 command = app;
141 } else {
142 // When bundled by Webpack, there's no actual package file path and no local `xdg-open`.
143 const isBundled = !__dirname || __dirname === '/';
144
145 // Check if local `xdg-open` exists and is executable.
146 let exeLocalXdgOpen = false;
147 try {
148 await pAccess(localXdgOpenPath, fs.constants.X_OK);
149 exeLocalXdgOpen = true;
150 } catch (_) {}
151
152 const useSystemXdgOpen = process.versions.electron ||
153 process.platform === 'android' || isBundled || !exeLocalXdgOpen;
154 command = useSystemXdgOpen ? 'xdg-open' : localXdgOpenPath;
155 }
156
157 if (appArguments.length > 0) {
158 cliArguments.push(...appArguments);
159 }
160
161 if (!options.wait) {
162 // `xdg-open` will block the process unless stdio is ignored
163 // and it's detached from the parent even if it's unref'd.
164 childProcessOptions.stdio = 'ignore';
165 childProcessOptions.detached = true;
166 }
167 }
168
169 cliArguments.push(target);
170
171 if (process.platform === 'darwin' && appArguments.length > 0) {
172 cliArguments.push('--args', ...appArguments);
173 }
174
175 const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
176
177 if (options.wait) {
178 return new Promise((resolve, reject) => {
179 subprocess.once('error', reject);
180
181 subprocess.once('close', exitCode => {
182 if (options.allowNonzeroExitCode && exitCode > 0) {
183 reject(new Error(`Exited with code ${exitCode}`));
184 return;
185 }
186
187 resolve(subprocess);
188 });
189 });
190 }
191
192 subprocess.unref();
193
194 return subprocess;
195};
Note: See TracBrowser for help on using the repository browser.