hexo/node_modules/open/index.js

196 lines
4.9 KiB
JavaScript
Raw Normal View History

2023-10-03 11:14:36 +08:00
'use strict';
const {promisify} = require('util');
const path = require('path');
const childProcess = require('child_process');
const fs = require('fs');
const isWsl = require('is-wsl');
const isDocker = require('is-docker');
const pAccess = promisify(fs.access);
const pReadFile = promisify(fs.readFile);
// Path to included `xdg-open`.
const localXdgOpenPath = path.join(__dirname, 'xdg-open');
/**
Get the mount point for fixed drives in WSL.
@inner
@returns {string} The mount point.
*/
const getWslDrivesMountPoint = (() => {
// Default value for "root" param
// according to https://docs.microsoft.com/en-us/windows/wsl/wsl-config
const defaultMountPoint = '/mnt/';
let mountPoint;
return async function () {
if (mountPoint) {
// Return memoized mount point value
return mountPoint;
}
const configFilePath = '/etc/wsl.conf';
let isConfigFileExists = false;
try {
await pAccess(configFilePath, fs.constants.F_OK);
isConfigFileExists = true;
} catch (_) {}
if (!isConfigFileExists) {
return defaultMountPoint;
}
const configContent = await pReadFile(configFilePath, {encoding: 'utf8'});
const configMountPoint = /root\s*=\s*(.*)/g.exec(configContent);
if (!configMountPoint) {
return defaultMountPoint;
}
mountPoint = configMountPoint[1].trim();
mountPoint = mountPoint.endsWith('/') ? mountPoint : mountPoint + '/';
return mountPoint;
};
})();
module.exports = async (target, options) => {
if (typeof target !== 'string') {
throw new TypeError('Expected a `target`');
}
options = {
wait: false,
background: false,
allowNonzeroExitCode: false,
...options
};
let command;
let {app} = options;
let appArguments = [];
const cliArguments = [];
const childProcessOptions = {};
if (Array.isArray(app)) {
appArguments = app.slice(1);
app = app[0];
}
if (process.platform === 'darwin') {
command = 'open';
if (options.wait) {
cliArguments.push('--wait-apps');
}
if (options.background) {
cliArguments.push('--background');
}
if (app) {
cliArguments.push('-a', app);
}
} else if (process.platform === 'win32' || (isWsl && !isDocker())) {
const mountPoint = await getWslDrivesMountPoint();
command = isWsl ?
`${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe` :
`${process.env.SYSTEMROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell`;
cliArguments.push(
'-NoProfile',
'-NonInteractive',
'ExecutionPolicy',
'Bypass',
'-EncodedCommand'
);
if (!isWsl) {
childProcessOptions.windowsVerbatimArguments = true;
}
const encodedArguments = ['Start'];
if (options.wait) {
encodedArguments.push('-Wait');
}
if (app) {
// Double quote with double quotes to ensure the inner quotes are passed through.
// Inner quotes are delimited for PowerShell interpretation with backticks.
encodedArguments.push(`"\`"${app}\`""`, '-ArgumentList');
appArguments.unshift(target);
} else {
encodedArguments.push(`"${target}"`);
}
if (appArguments.length > 0) {
appArguments = appArguments.map(arg => `"\`"${arg}\`""`);
encodedArguments.push(appArguments.join(','));
}
// Using Base64-encoded command, accepted by PowerShell, to allow special characters.
target = Buffer.from(encodedArguments.join(' '), 'utf16le').toString('base64');
} else {
if (app) {
command = app;
} else {
// When bundled by Webpack, there's no actual package file path and no local `xdg-open`.
const isBundled = !__dirname || __dirname === '/';
// Check if local `xdg-open` exists and is executable.
let exeLocalXdgOpen = false;
try {
await pAccess(localXdgOpenPath, fs.constants.X_OK);
exeLocalXdgOpen = true;
} catch (_) {}
const useSystemXdgOpen = process.versions.electron ||
process.platform === 'android' || isBundled || !exeLocalXdgOpen;
command = useSystemXdgOpen ? 'xdg-open' : localXdgOpenPath;
}
if (appArguments.length > 0) {
cliArguments.push(...appArguments);
}
if (!options.wait) {
// `xdg-open` will block the process unless stdio is ignored
// and it's detached from the parent even if it's unref'd.
childProcessOptions.stdio = 'ignore';
childProcessOptions.detached = true;
}
}
cliArguments.push(target);
if (process.platform === 'darwin' && appArguments.length > 0) {
cliArguments.push('--args', ...appArguments);
}
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
if (options.wait) {
return new Promise((resolve, reject) => {
subprocess.once('error', reject);
subprocess.once('close', exitCode => {
if (options.allowNonzeroExitCode && exitCode > 0) {
reject(new Error(`Exited with code ${exitCode}`));
return;
}
resolve(subprocess);
});
});
}
subprocess.unref();
return subprocess;
};