source: frontend/node_modules/open/index.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.7 KB
RevLine 
[9af201e]1const path = require('path');
2const childProcess = require('child_process');
3const {promises: fs, constants: fsConstants} = require('fs');
4const isWsl = require('is-wsl');
5const isDocker = require('is-docker');
6const defineLazyProperty = require('define-lazy-prop');
7
8// Path to included `xdg-open`.
9const localXdgOpenPath = path.join(__dirname, 'xdg-open');
10
11const {platform, arch} = process;
12
13// Podman detection
14const hasContainerEnv = () => {
15 try {
16 fs.statSync('/run/.containerenv');
17 return true;
18 } catch {
19 return false;
20 }
21};
22
23let cachedResult;
24function isInsideContainer() {
25 if (cachedResult === undefined) {
26 cachedResult = hasContainerEnv() || isDocker();
27 }
28
29 return cachedResult;
30}
31
32/**
33Get the mount point for fixed drives in WSL.
34
35@inner
36@returns {string} The mount point.
37*/
38const getWslDrivesMountPoint = (() => {
39 // Default value for "root" param
40 // according to https://docs.microsoft.com/en-us/windows/wsl/wsl-config
41 const defaultMountPoint = '/mnt/';
42
43 let mountPoint;
44
45 return async function () {
46 if (mountPoint) {
47 // Return memoized mount point value
48 return mountPoint;
49 }
50
51 const configFilePath = '/etc/wsl.conf';
52
53 let isConfigFileExists = false;
54 try {
55 await fs.access(configFilePath, fsConstants.F_OK);
56 isConfigFileExists = true;
57 } catch {}
58
59 if (!isConfigFileExists) {
60 return defaultMountPoint;
61 }
62
63 const configContent = await fs.readFile(configFilePath, {encoding: 'utf8'});
64 const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
65
66 if (!configMountPoint) {
67 return defaultMountPoint;
68 }
69
70 mountPoint = configMountPoint.groups.mountPoint.trim();
71 mountPoint = mountPoint.endsWith('/') ? mountPoint : `${mountPoint}/`;
72
73 return mountPoint;
74 };
75})();
76
77const pTryEach = async (array, mapper) => {
78 let latestError;
79
80 for (const item of array) {
81 try {
82 return await mapper(item); // eslint-disable-line no-await-in-loop
83 } catch (error) {
84 latestError = error;
85 }
86 }
87
88 throw latestError;
89};
90
91const baseOpen = async options => {
92 options = {
93 wait: false,
94 background: false,
95 newInstance: false,
96 allowNonzeroExitCode: false,
97 ...options
98 };
99
100 if (Array.isArray(options.app)) {
101 return pTryEach(options.app, singleApp => baseOpen({
102 ...options,
103 app: singleApp
104 }));
105 }
106
107 let {name: app, arguments: appArguments = []} = options.app || {};
108 appArguments = [...appArguments];
109
110 if (Array.isArray(app)) {
111 return pTryEach(app, appName => baseOpen({
112 ...options,
113 app: {
114 name: appName,
115 arguments: appArguments
116 }
117 }));
118 }
119
120 let command;
121 const cliArguments = [];
122 const childProcessOptions = {};
123
124 if (platform === 'darwin') {
125 command = 'open';
126
127 if (options.wait) {
128 cliArguments.push('--wait-apps');
129 }
130
131 if (options.background) {
132 cliArguments.push('--background');
133 }
134
135 if (options.newInstance) {
136 cliArguments.push('--new');
137 }
138
139 if (app) {
140 cliArguments.push('-a', app);
141 }
142 } else if (platform === 'win32' || (isWsl && !isInsideContainer() && !app)) {
143 const mountPoint = await getWslDrivesMountPoint();
144
145 command = isWsl ?
146 `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe` :
147 `${process.env.SYSTEMROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell`;
148
149 cliArguments.push(
150 '-NoProfile',
151 '-NonInteractive',
152 '–ExecutionPolicy',
153 'Bypass',
154 '-EncodedCommand'
155 );
156
157 if (!isWsl) {
158 childProcessOptions.windowsVerbatimArguments = true;
159 }
160
161 const encodedArguments = ['Start'];
162
163 if (options.wait) {
164 encodedArguments.push('-Wait');
165 }
166
167 if (app) {
168 // Double quote with double quotes to ensure the inner quotes are passed through.
169 // Inner quotes are delimited for PowerShell interpretation with backticks.
170 encodedArguments.push(`"\`"${app}\`""`, '-ArgumentList');
171 if (options.target) {
172 appArguments.unshift(options.target);
173 }
174 } else if (options.target) {
175 encodedArguments.push(`"${options.target}"`);
176 }
177
178 if (appArguments.length > 0) {
179 appArguments = appArguments.map(arg => `"\`"${arg}\`""`);
180 encodedArguments.push(appArguments.join(','));
181 }
182
183 // Using Base64-encoded command, accepted by PowerShell, to allow special characters.
184 options.target = Buffer.from(encodedArguments.join(' '), 'utf16le').toString('base64');
185 } else {
186 if (app) {
187 command = app;
188 } else {
189 // When bundled by Webpack, there's no actual package file path and no local `xdg-open`.
190 const isBundled = !__dirname || __dirname === '/';
191
192 // Check if local `xdg-open` exists and is executable.
193 let exeLocalXdgOpen = false;
194 try {
195 await fs.access(localXdgOpenPath, fsConstants.X_OK);
196 exeLocalXdgOpen = true;
197 } catch {}
198
199 const useSystemXdgOpen = process.versions.electron ||
200 platform === 'android' || isBundled || !exeLocalXdgOpen;
201 command = useSystemXdgOpen ? 'xdg-open' : localXdgOpenPath;
202 }
203
204 if (appArguments.length > 0) {
205 cliArguments.push(...appArguments);
206 }
207
208 if (!options.wait) {
209 // `xdg-open` will block the process unless stdio is ignored
210 // and it's detached from the parent even if it's unref'd.
211 childProcessOptions.stdio = 'ignore';
212 childProcessOptions.detached = true;
213 }
214 }
215
216 if (options.target) {
217 cliArguments.push(options.target);
218 }
219
220 if (platform === 'darwin' && appArguments.length > 0) {
221 cliArguments.push('--args', ...appArguments);
222 }
223
224 const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
225
226 if (options.wait) {
227 return new Promise((resolve, reject) => {
228 subprocess.once('error', reject);
229
230 subprocess.once('close', exitCode => {
231 if (!options.allowNonzeroExitCode && exitCode > 0) {
232 reject(new Error(`Exited with code ${exitCode}`));
233 return;
234 }
235
236 resolve(subprocess);
237 });
238 });
239 }
240
241 subprocess.unref();
242
243 return subprocess;
244};
245
246const open = (target, options) => {
247 if (typeof target !== 'string') {
248 throw new TypeError('Expected a `target`');
249 }
250
251 return baseOpen({
252 ...options,
253 target
254 });
255};
256
257const openApp = (name, options) => {
258 if (typeof name !== 'string') {
259 throw new TypeError('Expected a `name`');
260 }
261
262 const {arguments: appArguments = []} = options || {};
263 if (appArguments !== undefined && appArguments !== null && !Array.isArray(appArguments)) {
264 throw new TypeError('Expected `appArguments` as Array type');
265 }
266
267 return baseOpen({
268 ...options,
269 app: {
270 name,
271 arguments: appArguments
272 }
273 });
274};
275
276function detectArchBinary(binary) {
277 if (typeof binary === 'string' || Array.isArray(binary)) {
278 return binary;
279 }
280
281 const {[arch]: archBinary} = binary;
282
283 if (!archBinary) {
284 throw new Error(`${arch} is not supported`);
285 }
286
287 return archBinary;
288}
289
290function detectPlatformBinary({[platform]: platformBinary}, {wsl}) {
291 if (wsl && isWsl) {
292 return detectArchBinary(wsl);
293 }
294
295 if (!platformBinary) {
296 throw new Error(`${platform} is not supported`);
297 }
298
299 return detectArchBinary(platformBinary);
300}
301
302const apps = {};
303
304defineLazyProperty(apps, 'chrome', () => detectPlatformBinary({
305 darwin: 'google chrome',
306 win32: 'chrome',
307 linux: ['google-chrome', 'google-chrome-stable', 'chromium']
308}, {
309 wsl: {
310 ia32: '/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe',
311 x64: ['/mnt/c/Program Files/Google/Chrome/Application/chrome.exe', '/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe']
312 }
313}));
314
315defineLazyProperty(apps, 'firefox', () => detectPlatformBinary({
316 darwin: 'firefox',
317 win32: 'C:\\Program Files\\Mozilla Firefox\\firefox.exe',
318 linux: 'firefox'
319}, {
320 wsl: '/mnt/c/Program Files/Mozilla Firefox/firefox.exe'
321}));
322
323defineLazyProperty(apps, 'edge', () => detectPlatformBinary({
324 darwin: 'microsoft edge',
325 win32: 'msedge',
326 linux: ['microsoft-edge', 'microsoft-edge-dev']
327}, {
328 wsl: '/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe'
329}));
330
331open.apps = apps;
332open.openApp = openApp;
333
334module.exports = open;
Note: See TracBrowser for help on using the repository browser.