init commit
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.downloadBrowserWithProgressBar = downloadBrowserWithProgressBar;
|
||||
exports.logPolitely = logPolitely;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _child_process = _interopRequireDefault(require("child_process"));
|
||||
var _userAgent = require("../../utils/userAgent");
|
||||
var _fileUtils = require("../../utils/fileUtils");
|
||||
var _debugLogger = require("../../common/debugLogger");
|
||||
var _zipBundle = require("../../zipBundle");
|
||||
var _manualPromise = require("../../utils/manualPromise");
|
||||
var _utilsBundle = require("../../utilsBundle");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
async function downloadBrowserWithProgressBar(title, browserDirectory, executablePath, downloadURLs, downloadFileName, downloadConnectionTimeout) {
|
||||
if (await (0, _fileUtils.existsAsync)(browserDirectory)) {
|
||||
// Already downloaded.
|
||||
_debugLogger.debugLogger.log('install', `${title} is already downloaded.`);
|
||||
return false;
|
||||
}
|
||||
const zipPath = _path.default.join(_os.default.tmpdir(), downloadFileName);
|
||||
try {
|
||||
const retryCount = 3;
|
||||
for (let attempt = 1; attempt <= retryCount; ++attempt) {
|
||||
_debugLogger.debugLogger.log('install', `downloading ${title} - attempt #${attempt}`);
|
||||
const url = downloadURLs[(attempt - 1) % downloadURLs.length];
|
||||
logPolitely(`Downloading ${title}` + _utilsBundle.colors.dim(` from ${url}`));
|
||||
const {
|
||||
error
|
||||
} = await downloadFileOutOfProcess(url, zipPath, (0, _userAgent.getUserAgent)(), downloadConnectionTimeout);
|
||||
if (!error) {
|
||||
_debugLogger.debugLogger.log('install', `SUCCESS downloading ${title}`);
|
||||
break;
|
||||
}
|
||||
const errorMessage = (error === null || error === void 0 ? void 0 : error.message) || '';
|
||||
_debugLogger.debugLogger.log('install', `attempt #${attempt} - ERROR: ${errorMessage}`);
|
||||
if (attempt >= retryCount) throw error;
|
||||
}
|
||||
_debugLogger.debugLogger.log('install', `extracting archive`);
|
||||
_debugLogger.debugLogger.log('install', `-- zip: ${zipPath}`);
|
||||
_debugLogger.debugLogger.log('install', `-- location: ${browserDirectory}`);
|
||||
await (0, _zipBundle.extract)(zipPath, {
|
||||
dir: browserDirectory
|
||||
});
|
||||
if (executablePath) {
|
||||
_debugLogger.debugLogger.log('install', `fixing permissions at ${executablePath}`);
|
||||
await _fs.default.promises.chmod(executablePath, 0o755);
|
||||
}
|
||||
} catch (e) {
|
||||
_debugLogger.debugLogger.log('install', `FAILED installation ${title} with error: ${e}`);
|
||||
process.exitCode = 1;
|
||||
throw e;
|
||||
} finally {
|
||||
if (await (0, _fileUtils.existsAsync)(zipPath)) await _fs.default.promises.unlink(zipPath);
|
||||
}
|
||||
logPolitely(`${title} downloaded to ${browserDirectory}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Node.js has a bug where the process can exit with 0 code even though there was an uncaught exception.
|
||||
* Thats why we execute it in a separate process and check manually if the destination file exists.
|
||||
* https://github.com/microsoft/playwright/issues/17394
|
||||
*/
|
||||
function downloadFileOutOfProcess(url, destinationPath, userAgent, downloadConnectionTimeout) {
|
||||
const cp = _child_process.default.fork(_path.default.join(__dirname, 'oopDownloadMain.js'), [url, destinationPath, userAgent, String(downloadConnectionTimeout)]);
|
||||
const promise = new _manualPromise.ManualPromise();
|
||||
cp.on('message', message => {
|
||||
if ((message === null || message === void 0 ? void 0 : message.method) === 'log') _debugLogger.debugLogger.log('install', message.params.message);
|
||||
});
|
||||
cp.on('exit', code => {
|
||||
if (code !== 0) {
|
||||
promise.resolve({
|
||||
error: new Error(`Download failure, code=${code}`)
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!_fs.default.existsSync(destinationPath)) promise.resolve({
|
||||
error: new Error(`Download failure, ${destinationPath} does not exist`)
|
||||
});else promise.resolve({
|
||||
error: null
|
||||
});
|
||||
});
|
||||
cp.on('error', error => {
|
||||
promise.resolve({
|
||||
error
|
||||
});
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
function logPolitely(toBeLogged) {
|
||||
const logLevel = process.env.npm_config_loglevel;
|
||||
const logLevelDisplay = ['silent', 'error', 'warn'].indexOf(logLevel || '') > -1;
|
||||
if (!logLevelDisplay) console.log(toBeLogged); // eslint-disable-line no-console
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.dockerVersion = dockerVersion;
|
||||
exports.installDependenciesLinux = installDependenciesLinux;
|
||||
exports.installDependenciesWindows = installDependenciesWindows;
|
||||
exports.readDockerVersionSync = readDockerVersionSync;
|
||||
exports.transformCommandsForRoot = transformCommandsForRoot;
|
||||
exports.validateDependenciesLinux = validateDependenciesLinux;
|
||||
exports.validateDependenciesWindows = validateDependenciesWindows;
|
||||
exports.writeDockerVersion = writeDockerVersion;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var os = _interopRequireWildcard(require("os"));
|
||||
var _child_process = _interopRequireDefault(require("child_process"));
|
||||
var utils = _interopRequireWildcard(require("../../utils"));
|
||||
var _spawnAsync = require("../../utils/spawnAsync");
|
||||
var _hostPlatform = require("../../utils/hostPlatform");
|
||||
var _ = require(".");
|
||||
var _nativeDeps = require("./nativeDeps");
|
||||
var _userAgent = require("../../utils/userAgent");
|
||||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
||||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const BIN_DIRECTORY = _path.default.join(__dirname, '..', '..', '..', 'bin');
|
||||
const languageBindingVersion = process.env.PW_CLI_DISPLAY_VERSION || require('../../../package.json').version;
|
||||
const dockerVersionFilePath = '/ms-playwright/.docker-info';
|
||||
async function writeDockerVersion(dockerImageNameTemplate) {
|
||||
await _fs.default.promises.mkdir(_path.default.dirname(dockerVersionFilePath), {
|
||||
recursive: true
|
||||
});
|
||||
await _fs.default.promises.writeFile(dockerVersionFilePath, JSON.stringify(dockerVersion(dockerImageNameTemplate), null, 2), 'utf8');
|
||||
// Make sure version file is globally accessible.
|
||||
await _fs.default.promises.chmod(dockerVersionFilePath, 0o777);
|
||||
}
|
||||
function dockerVersion(dockerImageNameTemplate) {
|
||||
return {
|
||||
driverVersion: languageBindingVersion,
|
||||
dockerImageName: dockerImageNameTemplate.replace('%version%', languageBindingVersion)
|
||||
};
|
||||
}
|
||||
function readDockerVersionSync() {
|
||||
try {
|
||||
const data = JSON.parse(_fs.default.readFileSync(dockerVersionFilePath, 'utf8'));
|
||||
return {
|
||||
...data,
|
||||
dockerImageNameTemplate: data.dockerImageName.replace(data.driverVersion, '%version%')
|
||||
};
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const checkExecutable = filePath => _fs.default.promises.access(filePath, _fs.default.constants.X_OK).then(() => true).catch(e => false);
|
||||
function isSupportedWindowsVersion() {
|
||||
if (os.platform() !== 'win32' || os.arch() !== 'x64') return false;
|
||||
const [major, minor] = os.release().split('.').map(token => parseInt(token, 10));
|
||||
// This is based on: https://stackoverflow.com/questions/42524606/how-to-get-windows-version-using-node-js/44916050#44916050
|
||||
// The table with versions is taken from: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexw#remarks
|
||||
// Windows 7 is not supported and is encoded as `6.1`.
|
||||
return major > 6 || major === 6 && minor > 1;
|
||||
}
|
||||
async function installDependenciesWindows(targets, dryRun) {
|
||||
if (targets.has('chromium')) {
|
||||
const command = 'powershell.exe';
|
||||
const args = ['-ExecutionPolicy', 'Bypass', '-File', _path.default.join(BIN_DIRECTORY, 'install_media_pack.ps1')];
|
||||
if (dryRun) {
|
||||
console.log(`${command} ${quoteProcessArgs(args).join(' ')}`); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
const {
|
||||
code
|
||||
} = await (0, _spawnAsync.spawnAsync)(command, args, {
|
||||
cwd: BIN_DIRECTORY,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
if (code !== 0) throw new Error('Failed to install windows dependencies!');
|
||||
}
|
||||
}
|
||||
async function installDependenciesLinux(targets, dryRun) {
|
||||
const libraries = [];
|
||||
let platform = _hostPlatform.hostPlatform;
|
||||
if (platform === 'generic-linux' || platform === 'generic-linux-arm64') {
|
||||
console.warn('BEWARE: your OS is not officially supported by Playwright; installing dependencies for Ubuntu as a fallback.'); // eslint-disable-line no-console
|
||||
platform = _hostPlatform.hostPlatform === 'generic-linux' ? 'ubuntu20.04' : 'ubuntu20.04-arm64';
|
||||
}
|
||||
for (const target of targets) {
|
||||
const info = _nativeDeps.deps[platform];
|
||||
if (!info) {
|
||||
console.warn('Cannot install dependencies for this linux distribution!'); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
libraries.push(...info[target]);
|
||||
}
|
||||
const uniqueLibraries = Array.from(new Set(libraries));
|
||||
if (!dryRun) console.log(`Installing dependencies...`); // eslint-disable-line no-console
|
||||
const commands = [];
|
||||
commands.push('apt-get update');
|
||||
commands.push(['apt-get', 'install', '-y', '--no-install-recommends', ...uniqueLibraries].join(' '));
|
||||
const {
|
||||
command,
|
||||
args,
|
||||
elevatedPermissions
|
||||
} = await transformCommandsForRoot(commands);
|
||||
if (dryRun) {
|
||||
console.log(`${command} ${quoteProcessArgs(args).join(' ')}`); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
if (elevatedPermissions) console.log('Switching to root user to install dependencies...'); // eslint-disable-line no-console
|
||||
const child = _child_process.default.spawn(command, args, {
|
||||
stdio: 'inherit'
|
||||
});
|
||||
await new Promise((resolve, reject) => {
|
||||
child.on('exit', code => code === 0 ? resolve() : reject(new Error(`Installation process exited with code: ${code}`)));
|
||||
child.on('error', reject);
|
||||
});
|
||||
}
|
||||
async function validateDependenciesWindows(windowsExeAndDllDirectories) {
|
||||
const directoryPaths = windowsExeAndDllDirectories;
|
||||
const lddPaths = [];
|
||||
for (const directoryPath of directoryPaths) lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
|
||||
const allMissingDeps = await Promise.all(lddPaths.map(lddPath => missingFileDependenciesWindows(lddPath)));
|
||||
const missingDeps = new Set();
|
||||
for (const deps of allMissingDeps) {
|
||||
for (const dep of deps) missingDeps.add(dep);
|
||||
}
|
||||
if (!missingDeps.size) return;
|
||||
let isCrtMissing = false;
|
||||
let isMediaFoundationMissing = false;
|
||||
for (const dep of missingDeps) {
|
||||
if (dep.startsWith('api-ms-win-crt') || dep === 'vcruntime140.dll' || dep === 'vcruntime140_1.dll' || dep === 'msvcp140.dll') isCrtMissing = true;else if (dep === 'mf.dll' || dep === 'mfplat.dll' || dep === 'msmpeg2vdec.dll' || dep === 'evr.dll' || dep === 'avrt.dll') isMediaFoundationMissing = true;
|
||||
}
|
||||
const details = [];
|
||||
if (isCrtMissing) {
|
||||
details.push(`Some of the Universal C Runtime files cannot be found on the system. You can fix`, `that by installing Microsoft Visual C++ Redistributable for Visual Studio from:`, `https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads`, ``);
|
||||
}
|
||||
if (isMediaFoundationMissing) {
|
||||
details.push(`Some of the Media Foundation files cannot be found on the system. If you are`, `on Windows Server try fixing this by running the following command in PowerShell`, `as Administrator:`, ``, ` Install-WindowsFeature Server-Media-Foundation`, ``, `For Windows N editions visit:`, `https://support.microsoft.com/en-us/help/3145500/media-feature-pack-list-for-windows-n-editions`, ``);
|
||||
}
|
||||
details.push(`Full list of missing libraries:`, ` ${[...missingDeps].join('\n ')}`, ``);
|
||||
const message = `Host system is missing dependencies!\n\n${details.join('\n')}`;
|
||||
if (isSupportedWindowsVersion()) {
|
||||
throw new Error(message);
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(`WARNING: running on unsupported windows version!`);
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
async function validateDependenciesLinux(sdkLanguage, linuxLddDirectories, dlOpenLibraries) {
|
||||
var _deps$hostPlatform;
|
||||
const directoryPaths = linuxLddDirectories;
|
||||
const lddPaths = [];
|
||||
for (const directoryPath of directoryPaths) lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
|
||||
const missingDepsPerFile = await Promise.all(lddPaths.map(lddPath => missingFileDependencies(lddPath, directoryPaths)));
|
||||
const missingDeps = new Set();
|
||||
for (const deps of missingDepsPerFile) {
|
||||
for (const dep of deps) missingDeps.add(dep);
|
||||
}
|
||||
for (const dep of await missingDLOPENLibraries(dlOpenLibraries)) missingDeps.add(dep);
|
||||
if (!missingDeps.size) return;
|
||||
const allMissingDeps = new Set(missingDeps);
|
||||
// Check Ubuntu version.
|
||||
const missingPackages = new Set();
|
||||
const libraryToPackageNameMapping = _nativeDeps.deps[_hostPlatform.hostPlatform] ? {
|
||||
...(((_deps$hostPlatform = _nativeDeps.deps[_hostPlatform.hostPlatform]) === null || _deps$hostPlatform === void 0 ? void 0 : _deps$hostPlatform.lib2package) || {}),
|
||||
...MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU
|
||||
} : {};
|
||||
// Translate missing dependencies to package names to install with apt.
|
||||
for (const missingDep of missingDeps) {
|
||||
const packageName = libraryToPackageNameMapping[missingDep];
|
||||
if (packageName) {
|
||||
missingPackages.add(packageName);
|
||||
missingDeps.delete(missingDep);
|
||||
}
|
||||
}
|
||||
const maybeSudo = process.getuid() !== 0 && os.platform() !== 'win32' ? 'sudo ' : '';
|
||||
const dockerInfo = readDockerVersionSync();
|
||||
const errorLines = [`Host system is missing dependencies to run browsers.`];
|
||||
// Ignore patch versions when comparing docker container version and Playwright version:
|
||||
// we **NEVER** roll browsers in patch releases, so native dependencies do not change.
|
||||
if (dockerInfo && !dockerInfo.driverVersion.startsWith((0, _userAgent.getPlaywrightVersion)(true /* majorMinorOnly */) + '.')) {
|
||||
// We are running in a docker container with unmatching version.
|
||||
// In this case, we know how to install dependencies in it.
|
||||
const pwVersion = (0, _userAgent.getPlaywrightVersion)();
|
||||
const requiredDockerImage = dockerInfo.dockerImageName.replace(dockerInfo.driverVersion, pwVersion);
|
||||
errorLines.push(...[`This is most likely due to docker image version not matching Playwright version:`, `- Playwright: ${pwVersion}`, `- Docker: ${dockerInfo.driverVersion}`, ``, `Either:`, `- (recommended) use docker image "${requiredDockerImage}"`, `- (alternative 1) run the following command inside docker to install missing dependencies:`, ``, ` ${maybeSudo}${(0, _.buildPlaywrightCLICommand)(sdkLanguage, 'install-deps')}`, ``, `- (alternative 2) use apt inside docker:`, ``, ` ${maybeSudo}apt-get install ${[...missingPackages].join('\\\n ')}`, ``, `<3 Playwright Team`]);
|
||||
} else if (missingPackages.size && !missingDeps.size) {
|
||||
// Only known dependencies are missing for browsers.
|
||||
// Suggest installation with a Playwright CLI.
|
||||
errorLines.push(...[`Please install them with the following command:`, ``, ` ${maybeSudo}${(0, _.buildPlaywrightCLICommand)(sdkLanguage, 'install-deps')}`, ``, `Alternatively, use apt:`, ` ${maybeSudo}apt-get install ${[...missingPackages].join('\\\n ')}`, ``, `<3 Playwright Team`]);
|
||||
} else {
|
||||
// Unhappy path: we either run on unknown distribution, or we failed to resolve all missing
|
||||
// libraries to package names.
|
||||
// Print missing libraries only:
|
||||
errorLines.push(...[`Missing libraries:`, ...[...allMissingDeps].map(dep => ' ' + dep)]);
|
||||
}
|
||||
throw new Error('\n' + utils.wrapInASCIIBox(errorLines.join('\n'), 1));
|
||||
}
|
||||
function isSharedLib(basename) {
|
||||
switch (os.platform()) {
|
||||
case 'linux':
|
||||
return basename.endsWith('.so') || basename.includes('.so.');
|
||||
case 'win32':
|
||||
return basename.endsWith('.dll');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
async function executablesOrSharedLibraries(directoryPath) {
|
||||
if (!_fs.default.existsSync(directoryPath)) return [];
|
||||
const allPaths = (await _fs.default.promises.readdir(directoryPath)).map(file => _path.default.resolve(directoryPath, file));
|
||||
const allStats = await Promise.all(allPaths.map(aPath => _fs.default.promises.stat(aPath)));
|
||||
const filePaths = allPaths.filter((aPath, index) => allStats[index].isFile());
|
||||
const executablersOrLibraries = (await Promise.all(filePaths.map(async filePath => {
|
||||
const basename = _path.default.basename(filePath).toLowerCase();
|
||||
if (isSharedLib(basename)) return filePath;
|
||||
if (await checkExecutable(filePath)) return filePath;
|
||||
return false;
|
||||
}))).filter(Boolean);
|
||||
return executablersOrLibraries;
|
||||
}
|
||||
async function missingFileDependenciesWindows(filePath) {
|
||||
const executable = _path.default.join(__dirname, '..', '..', '..', 'bin', 'PrintDeps.exe');
|
||||
const dirname = _path.default.dirname(filePath);
|
||||
const {
|
||||
stdout,
|
||||
code
|
||||
} = await (0, _spawnAsync.spawnAsync)(executable, [filePath], {
|
||||
cwd: dirname,
|
||||
env: {
|
||||
...process.env,
|
||||
LD_LIBRARY_PATH: process.env.LD_LIBRARY_PATH ? `${process.env.LD_LIBRARY_PATH}:${dirname}` : dirname
|
||||
}
|
||||
});
|
||||
if (code !== 0) return [];
|
||||
const missingDeps = stdout.split('\n').map(line => line.trim()).filter(line => line.endsWith('not found') && line.includes('=>')).map(line => line.split('=>')[0].trim().toLowerCase());
|
||||
return missingDeps;
|
||||
}
|
||||
async function missingFileDependencies(filePath, extraLDPaths) {
|
||||
const dirname = _path.default.dirname(filePath);
|
||||
let LD_LIBRARY_PATH = extraLDPaths.join(':');
|
||||
if (process.env.LD_LIBRARY_PATH) LD_LIBRARY_PATH = `${process.env.LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}`;
|
||||
const {
|
||||
stdout,
|
||||
code
|
||||
} = await (0, _spawnAsync.spawnAsync)('ldd', [filePath], {
|
||||
cwd: dirname,
|
||||
env: {
|
||||
...process.env,
|
||||
LD_LIBRARY_PATH
|
||||
}
|
||||
});
|
||||
if (code !== 0) return [];
|
||||
const missingDeps = stdout.split('\n').map(line => line.trim()).filter(line => line.endsWith('not found') && line.includes('=>')).map(line => line.split('=>')[0].trim());
|
||||
return missingDeps;
|
||||
}
|
||||
async function missingDLOPENLibraries(libraries) {
|
||||
if (!libraries.length) return [];
|
||||
// NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the
|
||||
// default PATH in CRON.
|
||||
// @see https://github.com/microsoft/playwright/issues/3397
|
||||
const {
|
||||
stdout,
|
||||
code,
|
||||
error
|
||||
} = await (0, _spawnAsync.spawnAsync)('/sbin/ldconfig', ['-p'], {});
|
||||
if (code !== 0 || error) return [];
|
||||
const isLibraryAvailable = library => stdout.toLowerCase().includes(library.toLowerCase());
|
||||
return libraries.filter(library => !isLibraryAvailable(library));
|
||||
}
|
||||
const MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU = {
|
||||
// libgstlibav.so (the only actual library provided by gstreamer1.0-libav) is not
|
||||
// in the ldconfig cache, so we detect the actual library required for playing h.264
|
||||
// and if it's missing recommend installing missing gstreamer lib.
|
||||
// gstreamer1.0-libav -> libavcodec57 -> libx264-152
|
||||
'libx264.so': 'gstreamer1.0-libav'
|
||||
};
|
||||
function quoteProcessArgs(args) {
|
||||
return args.map(arg => {
|
||||
if (arg.includes(' ')) return `"${arg}"`;
|
||||
return arg;
|
||||
});
|
||||
}
|
||||
async function transformCommandsForRoot(commands) {
|
||||
const isRoot = process.getuid() === 0;
|
||||
if (isRoot) return {
|
||||
command: 'sh',
|
||||
args: ['-c', `${commands.join('&& ')}`],
|
||||
elevatedPermissions: false
|
||||
};
|
||||
const sudoExists = await (0, _spawnAsync.spawnAsync)('which', ['sudo']);
|
||||
if (sudoExists.code === 0) return {
|
||||
command: 'sudo',
|
||||
args: ['--', 'sh', '-c', `${commands.join('&& ')}`],
|
||||
elevatedPermissions: true
|
||||
};
|
||||
return {
|
||||
command: 'su',
|
||||
args: ['root', '-c', `${commands.join('&& ')}`],
|
||||
elevatedPermissions: true
|
||||
};
|
||||
}
|
||||
847
bin/pac/tools/.playwright/package/lib/server/registry/index.js
Normal file
847
bin/pac/tools/.playwright/package/lib/server/registry/index.js
Normal file
@@ -0,0 +1,847 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Registry = void 0;
|
||||
exports.buildPlaywrightCLICommand = buildPlaywrightCLICommand;
|
||||
exports.findChromiumChannel = findChromiumChannel;
|
||||
exports.installBrowsersForNpmInstall = installBrowsersForNpmInstall;
|
||||
exports.installDefaultBrowsersForNpmInstall = installDefaultBrowsersForNpmInstall;
|
||||
exports.registryDirectory = exports.registry = void 0;
|
||||
Object.defineProperty(exports, "writeDockerVersion", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _dependencies.writeDockerVersion;
|
||||
}
|
||||
});
|
||||
var os = _interopRequireWildcard(require("os"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var util = _interopRequireWildcard(require("util"));
|
||||
var fs = _interopRequireWildcard(require("fs"));
|
||||
var _utilsBundle = require("../../utilsBundle");
|
||||
var _linuxUtils = require("../../utils/linuxUtils");
|
||||
var _network = require("../../utils/network");
|
||||
var _userAgent = require("../../utils/userAgent");
|
||||
var _utils = require("../../utils");
|
||||
var _fileUtils = require("../../utils/fileUtils");
|
||||
var _hostPlatform = require("../../utils/hostPlatform");
|
||||
var _spawnAsync = require("../../utils/spawnAsync");
|
||||
var _dependencies = require("./dependencies");
|
||||
var _browserFetcher = require("./browserFetcher");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
||||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const PACKAGE_PATH = _path.default.join(__dirname, '..', '..', '..');
|
||||
const BIN_PATH = _path.default.join(__dirname, '..', '..', '..', 'bin');
|
||||
const PLAYWRIGHT_CDN_MIRRORS = ['https://playwright.azureedge.net', 'https://playwright-akamai.azureedge.net', 'https://playwright-verizon.azureedge.net'];
|
||||
if (process.env.PW_TEST_CDN_THAT_SHOULD_WORK) {
|
||||
for (let i = 0; i < PLAYWRIGHT_CDN_MIRRORS.length; i++) {
|
||||
const cdn = PLAYWRIGHT_CDN_MIRRORS[i];
|
||||
if (cdn !== process.env.PW_TEST_CDN_THAT_SHOULD_WORK) PLAYWRIGHT_CDN_MIRRORS[i] = cdn + '.does-not-resolve.playwright.dev';
|
||||
}
|
||||
}
|
||||
const EXECUTABLE_PATHS = {
|
||||
'chromium': {
|
||||
'linux': ['chrome-linux', 'chrome'],
|
||||
'mac': ['chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'],
|
||||
'win': ['chrome-win', 'chrome.exe']
|
||||
},
|
||||
'firefox': {
|
||||
'linux': ['firefox', 'firefox'],
|
||||
'mac': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'],
|
||||
'win': ['firefox', 'firefox.exe']
|
||||
},
|
||||
'webkit': {
|
||||
'linux': ['pw_run.sh'],
|
||||
'mac': ['pw_run.sh'],
|
||||
'win': ['Playwright.exe']
|
||||
},
|
||||
'ffmpeg': {
|
||||
'linux': ['ffmpeg-linux'],
|
||||
'mac': ['ffmpeg-mac'],
|
||||
'win': ['ffmpeg-win64.exe']
|
||||
}
|
||||
};
|
||||
const DOWNLOAD_PATHS = {
|
||||
'chromium': {
|
||||
'<unknown>': undefined,
|
||||
'generic-linux': 'builds/chromium/%s/chromium-linux.zip',
|
||||
'generic-linux-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
|
||||
'ubuntu18.04': 'builds/chromium/%s/chromium-linux.zip',
|
||||
'ubuntu20.04': 'builds/chromium/%s/chromium-linux.zip',
|
||||
'ubuntu22.04': 'builds/chromium/%s/chromium-linux.zip',
|
||||
'ubuntu18.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
|
||||
'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
|
||||
'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
|
||||
'debian11': 'builds/chromium/%s/chromium-linux.zip',
|
||||
'debian11-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
|
||||
'mac10.13': 'builds/chromium/%s/chromium-mac.zip',
|
||||
'mac10.14': 'builds/chromium/%s/chromium-mac.zip',
|
||||
'mac10.15': 'builds/chromium/%s/chromium-mac.zip',
|
||||
'mac11': 'builds/chromium/%s/chromium-mac.zip',
|
||||
'mac11-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
|
||||
'mac12': 'builds/chromium/%s/chromium-mac.zip',
|
||||
'mac12-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
|
||||
'mac13': 'builds/chromium/%s/chromium-mac.zip',
|
||||
'mac13-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
|
||||
'win64': 'builds/chromium/%s/chromium-win64.zip'
|
||||
},
|
||||
'chromium-tip-of-tree': {
|
||||
'<unknown>': undefined,
|
||||
'generic-linux': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
|
||||
'generic-linux-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
|
||||
'ubuntu18.04': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
|
||||
'ubuntu20.04': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
|
||||
'ubuntu22.04': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
|
||||
'ubuntu18.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
|
||||
'ubuntu20.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
|
||||
'ubuntu22.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
|
||||
'debian11': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
|
||||
'debian11-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
|
||||
'mac10.13': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
|
||||
'mac10.14': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
|
||||
'mac10.15': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
|
||||
'mac11': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
|
||||
'mac11-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
|
||||
'mac12': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
|
||||
'mac12-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
|
||||
'mac13': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
|
||||
'mac13-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
|
||||
'win64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-win64.zip'
|
||||
},
|
||||
'chromium-with-symbols': {
|
||||
'<unknown>': undefined,
|
||||
'generic-linux': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
|
||||
'generic-linux-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
|
||||
'ubuntu18.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
|
||||
'ubuntu20.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
|
||||
'ubuntu22.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
|
||||
'ubuntu18.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
|
||||
'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
|
||||
'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
|
||||
'debian11': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
|
||||
'debian11-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
|
||||
'mac10.13': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
|
||||
'mac10.14': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
|
||||
'mac10.15': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
|
||||
'mac11': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
|
||||
'mac11-arm64': 'builds/chromium/%s/chromium-with-symbols-mac-arm64.zip',
|
||||
'mac12': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
|
||||
'mac12-arm64': 'builds/chromium/%s/chromium-with-symbols-mac-arm64.zip',
|
||||
'mac13': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
|
||||
'mac13-arm64': 'builds/chromium/%s/chromium-with-symbols-mac-arm64.zip',
|
||||
'win64': 'builds/chromium/%s/chromium-with-symbols-win64.zip'
|
||||
},
|
||||
'firefox': {
|
||||
'<unknown>': undefined,
|
||||
'generic-linux': 'builds/firefox/%s/firefox-ubuntu-20.04.zip',
|
||||
'generic-linux-arm64': 'builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip',
|
||||
'ubuntu18.04': 'builds/firefox/%s/firefox-ubuntu-18.04.zip',
|
||||
'ubuntu20.04': 'builds/firefox/%s/firefox-ubuntu-20.04.zip',
|
||||
'ubuntu22.04': 'builds/firefox/%s/firefox-ubuntu-22.04.zip',
|
||||
'ubuntu18.04-arm64': undefined,
|
||||
'ubuntu20.04-arm64': 'builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip',
|
||||
'ubuntu22.04-arm64': 'builds/firefox/%s/firefox-ubuntu-22.04-arm64.zip',
|
||||
'debian11': 'builds/firefox/%s/firefox-debian-11.zip',
|
||||
'debian11-arm64': 'builds/firefox/%s/firefox-debian-11-arm64.zip',
|
||||
'mac10.13': 'builds/firefox/%s/firefox-mac-11.zip',
|
||||
'mac10.14': 'builds/firefox/%s/firefox-mac-11.zip',
|
||||
'mac10.15': 'builds/firefox/%s/firefox-mac-11.zip',
|
||||
'mac11': 'builds/firefox/%s/firefox-mac-11.zip',
|
||||
'mac11-arm64': 'builds/firefox/%s/firefox-mac-11-arm64.zip',
|
||||
'mac12': 'builds/firefox/%s/firefox-mac-11.zip',
|
||||
'mac12-arm64': 'builds/firefox/%s/firefox-mac-11-arm64.zip',
|
||||
'mac13': 'builds/firefox/%s/firefox-mac-11.zip',
|
||||
'mac13-arm64': 'builds/firefox/%s/firefox-mac-11-arm64.zip',
|
||||
'win64': 'builds/firefox/%s/firefox-win64.zip'
|
||||
},
|
||||
'firefox-beta': {
|
||||
'<unknown>': undefined,
|
||||
'generic-linux': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip',
|
||||
'generic-linux-arm64': undefined,
|
||||
'ubuntu18.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-18.04.zip',
|
||||
'ubuntu20.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip',
|
||||
'ubuntu22.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04.zip',
|
||||
'ubuntu18.04-arm64': undefined,
|
||||
'ubuntu20.04-arm64': undefined,
|
||||
'ubuntu22.04-arm64': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04-arm64.zip',
|
||||
'debian11': 'builds/firefox-beta/%s/firefox-beta-debian-11.zip',
|
||||
'debian11-arm64': 'builds/firefox-beta/%s/firefox-beta-debian-11-arm64.zip',
|
||||
'mac10.13': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',
|
||||
'mac10.14': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',
|
||||
'mac10.15': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',
|
||||
'mac11': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',
|
||||
'mac11-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-11-arm64.zip',
|
||||
'mac12': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',
|
||||
'mac12-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-11-arm64.zip',
|
||||
'mac13': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',
|
||||
'mac13-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-11-arm64.zip',
|
||||
'win64': 'builds/firefox-beta/%s/firefox-beta-win64.zip'
|
||||
},
|
||||
'webkit': {
|
||||
'<unknown>': undefined,
|
||||
'generic-linux': 'builds/webkit/%s/webkit-ubuntu-20.04.zip',
|
||||
'generic-linux-arm64': 'builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip',
|
||||
'ubuntu18.04': 'builds/deprecated-webkit-ubuntu-18.04/%s/deprecated-webkit-ubuntu-18.04.zip',
|
||||
'ubuntu20.04': 'builds/webkit/%s/webkit-ubuntu-20.04.zip',
|
||||
'ubuntu22.04': 'builds/webkit/%s/webkit-ubuntu-22.04.zip',
|
||||
'ubuntu18.04-arm64': undefined,
|
||||
'ubuntu20.04-arm64': 'builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip',
|
||||
'ubuntu22.04-arm64': 'builds/webkit/%s/webkit-ubuntu-22.04-arm64.zip',
|
||||
'debian11': 'builds/webkit/%s/webkit-debian-11.zip',
|
||||
'debian11-arm64': 'builds/webkit/%s/webkit-debian-11-arm64.zip',
|
||||
'mac10.13': undefined,
|
||||
'mac10.14': 'builds/deprecated-webkit-mac-10.14/%s/deprecated-webkit-mac-10.14.zip',
|
||||
'mac10.15': 'builds/deprecated-webkit-mac-10.15/%s/deprecated-webkit-mac-10.15.zip',
|
||||
'mac11': 'builds/webkit/%s/webkit-mac-11.zip',
|
||||
'mac11-arm64': 'builds/webkit/%s/webkit-mac-11-arm64.zip',
|
||||
'mac12': 'builds/webkit/%s/webkit-mac-12.zip',
|
||||
'mac12-arm64': 'builds/webkit/%s/webkit-mac-12-arm64.zip',
|
||||
'mac13': 'builds/webkit/%s/webkit-mac-13.zip',
|
||||
'mac13-arm64': 'builds/webkit/%s/webkit-mac-13-arm64.zip',
|
||||
'win64': 'builds/webkit/%s/webkit-win64.zip'
|
||||
},
|
||||
'ffmpeg': {
|
||||
'<unknown>': undefined,
|
||||
'generic-linux': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
|
||||
'generic-linux-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
|
||||
'ubuntu18.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
|
||||
'ubuntu20.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
|
||||
'ubuntu22.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
|
||||
'ubuntu18.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
|
||||
'ubuntu20.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
|
||||
'ubuntu22.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
|
||||
'debian11': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
|
||||
'debian11-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
|
||||
'mac10.13': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
|
||||
'mac10.14': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
|
||||
'mac10.15': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
|
||||
'mac11': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
|
||||
'mac11-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
|
||||
'mac12': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
|
||||
'mac12-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
|
||||
'mac13': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
|
||||
'mac13-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
|
||||
'win64': 'builds/ffmpeg/%s/ffmpeg-win64.zip'
|
||||
},
|
||||
'android': {
|
||||
'<unknown>': 'builds/android/%s/android.zip'
|
||||
}
|
||||
};
|
||||
const registryDirectory = (() => {
|
||||
let result;
|
||||
const envDefined = (0, _utils.getFromENV)('PLAYWRIGHT_BROWSERS_PATH');
|
||||
if (envDefined === '0') {
|
||||
result = _path.default.join(__dirname, '..', '..', '..', '.local-browsers');
|
||||
} else if (envDefined) {
|
||||
result = envDefined;
|
||||
} else {
|
||||
let cacheDirectory;
|
||||
if (process.platform === 'linux') cacheDirectory = process.env.XDG_CACHE_HOME || _path.default.join(os.homedir(), '.cache');else if (process.platform === 'darwin') cacheDirectory = _path.default.join(os.homedir(), 'Library', 'Caches');else if (process.platform === 'win32') cacheDirectory = process.env.LOCALAPPDATA || _path.default.join(os.homedir(), 'AppData', 'Local');else throw new Error('Unsupported platform: ' + process.platform);
|
||||
result = _path.default.join(cacheDirectory, 'ms-playwright');
|
||||
}
|
||||
if (!_path.default.isAbsolute(result)) {
|
||||
// It is important to resolve to the absolute path:
|
||||
// - for unzipping to work correctly;
|
||||
// - so that registry directory matches between installation and execution.
|
||||
// INIT_CWD points to the root of `npm/yarn install` and is probably what
|
||||
// the user meant when typing the relative path.
|
||||
result = _path.default.resolve((0, _utils.getFromENV)('INIT_CWD') || process.cwd(), result);
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
exports.registryDirectory = registryDirectory;
|
||||
function isBrowserDirectory(browserDirectory) {
|
||||
const baseName = _path.default.basename(browserDirectory);
|
||||
for (const browserName of allDownloadable) {
|
||||
if (baseName.startsWith(browserName + '-')) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function readDescriptors(browsersJSON) {
|
||||
return browsersJSON['browsers'].map(obj => {
|
||||
const name = obj.name;
|
||||
const revisionOverride = (obj.revisionOverrides || {})[_hostPlatform.hostPlatform];
|
||||
const revision = revisionOverride || obj.revision;
|
||||
const browserDirectoryPrefix = revisionOverride ? `${name}_${_hostPlatform.hostPlatform}_special` : `${name}`;
|
||||
const descriptor = {
|
||||
name,
|
||||
revision,
|
||||
// We only put browser version for the supported operating systems.
|
||||
browserVersion: revisionOverride ? undefined : obj.browserVersion,
|
||||
installByDefault: !!obj.installByDefault,
|
||||
// Method `isBrowserDirectory` determines directory to be browser iff
|
||||
// it starts with some browser name followed by '-'. Some browser names
|
||||
// are prefixes of others, e.g. 'webkit' is a prefix of `webkit-technology-preview`.
|
||||
// To avoid older registries erroneously removing 'webkit-technology-preview', we have to
|
||||
// ensure that browser folders to never include dashes inside.
|
||||
dir: _path.default.join(registryDirectory, browserDirectoryPrefix.replace(/-/g, '_') + '-' + revision)
|
||||
};
|
||||
return descriptor;
|
||||
});
|
||||
}
|
||||
const allDownloadable = ['chromium', 'firefox', 'webkit', 'ffmpeg', 'firefox-beta', 'chromium-with-symbols', 'chromium-tip-of-tree'];
|
||||
class Registry {
|
||||
constructor(browsersJSON) {
|
||||
this._executables = void 0;
|
||||
const descriptors = readDescriptors(browsersJSON);
|
||||
const findExecutablePath = (dir, name) => {
|
||||
let tokens = undefined;
|
||||
if (process.platform === 'linux') tokens = EXECUTABLE_PATHS[name]['linux'];else if (process.platform === 'darwin') tokens = EXECUTABLE_PATHS[name]['mac'];else if (process.platform === 'win32') tokens = EXECUTABLE_PATHS[name]['win'];
|
||||
return tokens ? _path.default.join(dir, ...tokens) : undefined;
|
||||
};
|
||||
const executablePathOrDie = (name, e, installByDefault, sdkLanguage) => {
|
||||
if (!e) throw new Error(`${name} is not supported on ${_hostPlatform.hostPlatform}`);
|
||||
const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install${installByDefault ? '' : ' ' + name}`);
|
||||
if (!(0, _fileUtils.canAccessFile)(e)) {
|
||||
const currentDockerVersion = (0, _dependencies.readDockerVersionSync)();
|
||||
const preferredDockerVersion = currentDockerVersion ? (0, _dependencies.dockerVersion)(currentDockerVersion.dockerImageNameTemplate) : null;
|
||||
const isOutdatedDockerImage = currentDockerVersion && preferredDockerVersion && currentDockerVersion.dockerImageName !== preferredDockerVersion.dockerImageName;
|
||||
const prettyMessage = isOutdatedDockerImage ? [`Looks like ${sdkLanguage === 'javascript' ? 'Playwright Test or ' : ''}Playwright was just updated to ${preferredDockerVersion.driverVersion}.`, `Please update docker image as well.`, `- current: ${currentDockerVersion.dockerImageName}`, `- required: ${preferredDockerVersion.dockerImageName}`, ``, `<3 Playwright Team`].join('\n') : [`Looks like ${sdkLanguage === 'javascript' ? 'Playwright Test or ' : ''}Playwright was just installed or updated.`, `Please run the following command to download new browser${installByDefault ? 's' : ''}:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team`].join('\n');
|
||||
throw new Error(`Executable doesn't exist at ${e}\n${(0, _utils.wrapInASCIIBox)(prettyMessage, 1)}`);
|
||||
}
|
||||
return e;
|
||||
};
|
||||
this._executables = [];
|
||||
const chromium = descriptors.find(d => d.name === 'chromium');
|
||||
const chromiumExecutable = findExecutablePath(chromium.dir, 'chromium');
|
||||
this._executables.push({
|
||||
type: 'browser',
|
||||
name: 'chromium',
|
||||
browserName: 'chromium',
|
||||
directory: chromium.dir,
|
||||
executablePath: () => chromiumExecutable,
|
||||
executablePathOrDie: sdkLanguage => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage),
|
||||
installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),
|
||||
downloadURLs: this._downloadURLs(chromium),
|
||||
browserVersion: chromium.browserVersion,
|
||||
_install: () => this._downloadExecutable(chromium, chromiumExecutable),
|
||||
_dependencyGroup: 'chromium',
|
||||
_isHermeticInstallation: true
|
||||
});
|
||||
const chromiumWithSymbols = descriptors.find(d => d.name === 'chromium-with-symbols');
|
||||
const chromiumWithSymbolsExecutable = findExecutablePath(chromiumWithSymbols.dir, 'chromium');
|
||||
this._executables.push({
|
||||
type: 'tool',
|
||||
name: 'chromium-with-symbols',
|
||||
browserName: 'chromium',
|
||||
directory: chromiumWithSymbols.dir,
|
||||
executablePath: () => chromiumWithSymbolsExecutable,
|
||||
executablePathOrDie: sdkLanguage => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable, chromiumWithSymbols.installByDefault, sdkLanguage),
|
||||
installType: chromiumWithSymbols.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']),
|
||||
downloadURLs: this._downloadURLs(chromiumWithSymbols),
|
||||
browserVersion: chromiumWithSymbols.browserVersion,
|
||||
_install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable),
|
||||
_dependencyGroup: 'chromium',
|
||||
_isHermeticInstallation: true
|
||||
});
|
||||
const chromiumTipOfTree = descriptors.find(d => d.name === 'chromium-tip-of-tree');
|
||||
const chromiumTipOfTreeExecutable = findExecutablePath(chromiumTipOfTree.dir, 'chromium');
|
||||
this._executables.push({
|
||||
type: 'tool',
|
||||
name: 'chromium-tip-of-tree',
|
||||
browserName: 'chromium',
|
||||
directory: chromiumTipOfTree.dir,
|
||||
executablePath: () => chromiumTipOfTreeExecutable,
|
||||
executablePathOrDie: sdkLanguage => executablePathOrDie('chromium-tip-of-tree', chromiumTipOfTreeExecutable, chromiumTipOfTree.installByDefault, sdkLanguage),
|
||||
installType: chromiumTipOfTree.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumTipOfTree.dir, ['chrome-linux'], [], ['chrome-win']),
|
||||
downloadURLs: this._downloadURLs(chromiumTipOfTree),
|
||||
browserVersion: chromiumTipOfTree.browserVersion,
|
||||
_install: () => this._downloadExecutable(chromiumTipOfTree, chromiumTipOfTreeExecutable),
|
||||
_dependencyGroup: 'chromium',
|
||||
_isHermeticInstallation: true
|
||||
});
|
||||
this._executables.push(this._createChromiumChannel('chrome', {
|
||||
'linux': '/opt/google/chrome/chrome',
|
||||
'darwin': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
||||
'win32': `\\Google\\Chrome\\Application\\chrome.exe`
|
||||
}, () => this._installChromiumChannel('chrome', {
|
||||
'linux': 'reinstall_chrome_stable_linux.sh',
|
||||
'darwin': 'reinstall_chrome_stable_mac.sh',
|
||||
'win32': 'reinstall_chrome_stable_win.ps1'
|
||||
})));
|
||||
this._executables.push(this._createChromiumChannel('chrome-beta', {
|
||||
'linux': '/opt/google/chrome-beta/chrome',
|
||||
'darwin': '/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta',
|
||||
'win32': `\\Google\\Chrome Beta\\Application\\chrome.exe`
|
||||
}, () => this._installChromiumChannel('chrome-beta', {
|
||||
'linux': 'reinstall_chrome_beta_linux.sh',
|
||||
'darwin': 'reinstall_chrome_beta_mac.sh',
|
||||
'win32': 'reinstall_chrome_beta_win.ps1'
|
||||
})));
|
||||
this._executables.push(this._createChromiumChannel('chrome-dev', {
|
||||
'linux': '/opt/google/chrome-unstable/chrome',
|
||||
'darwin': '/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev',
|
||||
'win32': `\\Google\\Chrome Dev\\Application\\chrome.exe`
|
||||
}));
|
||||
this._executables.push(this._createChromiumChannel('chrome-canary', {
|
||||
'linux': '',
|
||||
'darwin': '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
|
||||
'win32': `\\Google\\Chrome SxS\\Application\\chrome.exe`
|
||||
}));
|
||||
this._executables.push(this._createChromiumChannel('msedge', {
|
||||
'linux': '/opt/microsoft/msedge/msedge',
|
||||
'darwin': '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
||||
'win32': `\\Microsoft\\Edge\\Application\\msedge.exe`
|
||||
}, () => this._installMSEdgeChannel('msedge', {
|
||||
'linux': 'reinstall_msedge_stable_linux.sh',
|
||||
'darwin': 'reinstall_msedge_stable_mac.sh',
|
||||
'win32': 'reinstall_msedge_stable_win.ps1'
|
||||
})));
|
||||
this._executables.push(this._createChromiumChannel('msedge-beta', {
|
||||
'linux': '/opt/microsoft/msedge-beta/msedge',
|
||||
'darwin': '/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta',
|
||||
'win32': `\\Microsoft\\Edge Beta\\Application\\msedge.exe`
|
||||
}, () => this._installMSEdgeChannel('msedge-beta', {
|
||||
'darwin': 'reinstall_msedge_beta_mac.sh',
|
||||
'linux': 'reinstall_msedge_beta_linux.sh',
|
||||
'win32': 'reinstall_msedge_beta_win.ps1'
|
||||
})));
|
||||
this._executables.push(this._createChromiumChannel('msedge-dev', {
|
||||
'linux': '/opt/microsoft/msedge-dev/msedge',
|
||||
'darwin': '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev',
|
||||
'win32': `\\Microsoft\\Edge Dev\\Application\\msedge.exe`
|
||||
}, () => this._installMSEdgeChannel('msedge-dev', {
|
||||
'darwin': 'reinstall_msedge_dev_mac.sh',
|
||||
'linux': 'reinstall_msedge_dev_linux.sh',
|
||||
'win32': 'reinstall_msedge_dev_win.ps1'
|
||||
})));
|
||||
this._executables.push(this._createChromiumChannel('msedge-canary', {
|
||||
'linux': '',
|
||||
'darwin': '/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary',
|
||||
'win32': `\\Microsoft\\Edge SxS\\Application\\msedge.exe`
|
||||
}));
|
||||
const firefox = descriptors.find(d => d.name === 'firefox');
|
||||
const firefoxExecutable = findExecutablePath(firefox.dir, 'firefox');
|
||||
this._executables.push({
|
||||
type: 'browser',
|
||||
name: 'firefox',
|
||||
browserName: 'firefox',
|
||||
directory: firefox.dir,
|
||||
executablePath: () => firefoxExecutable,
|
||||
executablePathOrDie: sdkLanguage => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage),
|
||||
installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']),
|
||||
downloadURLs: this._downloadURLs(firefox),
|
||||
browserVersion: firefox.browserVersion,
|
||||
_install: () => this._downloadExecutable(firefox, firefoxExecutable),
|
||||
_dependencyGroup: 'firefox',
|
||||
_isHermeticInstallation: true
|
||||
});
|
||||
const firefoxBeta = descriptors.find(d => d.name === 'firefox-beta');
|
||||
const firefoxBetaExecutable = findExecutablePath(firefoxBeta.dir, 'firefox');
|
||||
this._executables.push({
|
||||
type: 'tool',
|
||||
name: 'firefox-beta',
|
||||
browserName: 'firefox',
|
||||
directory: firefoxBeta.dir,
|
||||
executablePath: () => firefoxBetaExecutable,
|
||||
executablePathOrDie: sdkLanguage => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage),
|
||||
installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),
|
||||
downloadURLs: this._downloadURLs(firefoxBeta),
|
||||
browserVersion: firefoxBeta.browserVersion,
|
||||
_install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable),
|
||||
_dependencyGroup: 'firefox',
|
||||
_isHermeticInstallation: true
|
||||
});
|
||||
const webkit = descriptors.find(d => d.name === 'webkit');
|
||||
const webkitExecutable = findExecutablePath(webkit.dir, 'webkit');
|
||||
const webkitLinuxLddDirectories = [_path.default.join('minibrowser-gtk'), _path.default.join('minibrowser-gtk', 'bin'), _path.default.join('minibrowser-gtk', 'lib'), _path.default.join('minibrowser-gtk', 'sys', 'lib'), _path.default.join('minibrowser-wpe'), _path.default.join('minibrowser-wpe', 'bin'), _path.default.join('minibrowser-wpe', 'lib'), _path.default.join('minibrowser-wpe', 'sys', 'lib')];
|
||||
this._executables.push({
|
||||
type: 'browser',
|
||||
name: 'webkit',
|
||||
browserName: 'webkit',
|
||||
directory: webkit.dir,
|
||||
executablePath: () => webkitExecutable,
|
||||
executablePathOrDie: sdkLanguage => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage),
|
||||
installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),
|
||||
downloadURLs: this._downloadURLs(webkit),
|
||||
browserVersion: webkit.browserVersion,
|
||||
_install: () => this._downloadExecutable(webkit, webkitExecutable),
|
||||
_dependencyGroup: 'webkit',
|
||||
_isHermeticInstallation: true
|
||||
});
|
||||
const ffmpeg = descriptors.find(d => d.name === 'ffmpeg');
|
||||
const ffmpegExecutable = findExecutablePath(ffmpeg.dir, 'ffmpeg');
|
||||
this._executables.push({
|
||||
type: 'tool',
|
||||
name: 'ffmpeg',
|
||||
browserName: undefined,
|
||||
directory: ffmpeg.dir,
|
||||
executablePath: () => ffmpegExecutable,
|
||||
executablePathOrDie: sdkLanguage => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage),
|
||||
installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: () => Promise.resolve(),
|
||||
downloadURLs: this._downloadURLs(ffmpeg),
|
||||
_install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable),
|
||||
_dependencyGroup: 'tools',
|
||||
_isHermeticInstallation: true
|
||||
});
|
||||
const android = descriptors.find(d => d.name === 'android');
|
||||
this._executables.push({
|
||||
type: 'tool',
|
||||
name: 'android',
|
||||
browserName: undefined,
|
||||
directory: android.dir,
|
||||
executablePath: () => undefined,
|
||||
executablePathOrDie: () => '',
|
||||
installType: 'download-on-demand',
|
||||
validateHostRequirements: () => Promise.resolve(),
|
||||
downloadURLs: this._downloadURLs(android),
|
||||
_install: () => this._downloadExecutable(android),
|
||||
_dependencyGroup: 'tools',
|
||||
_isHermeticInstallation: true
|
||||
});
|
||||
}
|
||||
_createChromiumChannel(name, lookAt, install) {
|
||||
const executablePath = (sdkLanguage, shouldThrow) => {
|
||||
const suffix = lookAt[process.platform];
|
||||
if (!suffix) {
|
||||
if (shouldThrow) throw new Error(`Chromium distribution '${name}' is not supported on ${process.platform}`);
|
||||
return undefined;
|
||||
}
|
||||
const prefixes = process.platform === 'win32' ? [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']].filter(Boolean) : [''];
|
||||
for (const prefix of prefixes) {
|
||||
const executablePath = _path.default.join(prefix, suffix);
|
||||
if ((0, _fileUtils.canAccessFile)(executablePath)) return executablePath;
|
||||
}
|
||||
if (!shouldThrow) return undefined;
|
||||
const location = prefixes.length ? ` at ${_path.default.join(prefixes[0], suffix)}` : ``;
|
||||
const installation = install ? `\nRun "${buildPlaywrightCLICommand(sdkLanguage, 'install ' + name)}"` : '';
|
||||
throw new Error(`Chromium distribution '${name}' is not found${location}${installation}`);
|
||||
};
|
||||
return {
|
||||
type: 'channel',
|
||||
name,
|
||||
browserName: 'chromium',
|
||||
directory: undefined,
|
||||
executablePath: sdkLanguage => executablePath(sdkLanguage, false),
|
||||
executablePathOrDie: sdkLanguage => executablePath(sdkLanguage, true),
|
||||
installType: install ? 'install-script' : 'none',
|
||||
validateHostRequirements: () => Promise.resolve(),
|
||||
_isHermeticInstallation: false,
|
||||
_install: install
|
||||
};
|
||||
}
|
||||
executables() {
|
||||
return this._executables;
|
||||
}
|
||||
findExecutable(name) {
|
||||
return this._executables.find(b => b.name === name);
|
||||
}
|
||||
defaultExecutables() {
|
||||
return this._executables.filter(e => e.installType === 'download-by-default');
|
||||
}
|
||||
_addRequirementsAndDedupe(executables) {
|
||||
const set = new Set();
|
||||
for (const executable of executables) {
|
||||
set.add(executable);
|
||||
if (executable.browserName === 'chromium') set.add(this.findExecutable('ffmpeg'));
|
||||
}
|
||||
return Array.from(set);
|
||||
}
|
||||
async _validateHostRequirements(sdkLanguage, browserName, browserDirectory, linuxLddDirectories, dlOpenLibraries, windowsExeAndDllDirectories) {
|
||||
if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {
|
||||
process.stderr.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');
|
||||
return;
|
||||
}
|
||||
const distributionInfo = await (0, _linuxUtils.getLinuxDistributionInfo)();
|
||||
if (browserName === 'firefox' && (distributionInfo === null || distributionInfo === void 0 ? void 0 : distributionInfo.id) === 'ubuntu' && (distributionInfo === null || distributionInfo === void 0 ? void 0 : distributionInfo.version) === '16.04') throw new Error(`Cannot launch Firefox on Ubuntu 16.04! Minimum required Ubuntu version for Firefox browser is 20.04`);
|
||||
if (os.platform() === 'linux') return await (0, _dependencies.validateDependenciesLinux)(sdkLanguage, linuxLddDirectories.map(d => _path.default.join(browserDirectory, d)), dlOpenLibraries);
|
||||
if (os.platform() === 'win32' && os.arch() === 'x64') return await (0, _dependencies.validateDependenciesWindows)(windowsExeAndDllDirectories.map(d => _path.default.join(browserDirectory, d)));
|
||||
}
|
||||
async installDeps(executablesToInstallDeps, dryRun) {
|
||||
const executables = this._addRequirementsAndDedupe(executablesToInstallDeps);
|
||||
const targets = new Set();
|
||||
for (const executable of executables) {
|
||||
if (executable._dependencyGroup) targets.add(executable._dependencyGroup);
|
||||
}
|
||||
targets.add('tools');
|
||||
if (os.platform() === 'win32') return await (0, _dependencies.installDependenciesWindows)(targets, dryRun);
|
||||
if (os.platform() === 'linux') return await (0, _dependencies.installDependenciesLinux)(targets, dryRun);
|
||||
}
|
||||
async install(executablesToInstall, forceReinstall) {
|
||||
const executables = this._addRequirementsAndDedupe(executablesToInstall);
|
||||
await fs.promises.mkdir(registryDirectory, {
|
||||
recursive: true
|
||||
});
|
||||
const lockfilePath = _path.default.join(registryDirectory, '__dirlock');
|
||||
const linksDir = _path.default.join(registryDirectory, '.links');
|
||||
let releaseLock;
|
||||
try {
|
||||
releaseLock = await _utilsBundle.lockfile.lock(registryDirectory, {
|
||||
retries: {
|
||||
// Retry 20 times during 10 minutes with
|
||||
// exponential back-off.
|
||||
// See documentation at: https://www.npmjs.com/package/retry#retrytimeoutsoptions
|
||||
retries: 20,
|
||||
factor: 1.27579
|
||||
},
|
||||
onCompromised: err => {
|
||||
throw new Error(`${err.message} Path: ${lockfilePath}`);
|
||||
},
|
||||
lockfilePath
|
||||
});
|
||||
// Create a link first, so that cache validation does not remove our own browsers.
|
||||
await fs.promises.mkdir(linksDir, {
|
||||
recursive: true
|
||||
});
|
||||
await fs.promises.writeFile(_path.default.join(linksDir, (0, _utils.calculateSha1)(PACKAGE_PATH)), PACKAGE_PATH);
|
||||
|
||||
// Remove stale browsers.
|
||||
await this._validateInstallationCache(linksDir);
|
||||
|
||||
// Install browsers for this package.
|
||||
for (const executable of executables) {
|
||||
if (!executable._install) throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);
|
||||
const {
|
||||
embedderName
|
||||
} = (0, _userAgent.getEmbedderName)();
|
||||
if (!(0, _utils.getAsBooleanFromENV)('CI') && !executable._isHermeticInstallation && !forceReinstall && executable.executablePath(embedderName)) {
|
||||
const command = buildPlaywrightCLICommand(embedderName, 'install --force ' + executable.name);
|
||||
throw new Error('\n' + (0, _utils.wrapInASCIIBox)([`ATTENTION: "${executable.name}" is already installed on the system!`, ``, `"${executable.name}" installation is not hermetic; installing newer version`, `requires *removal* of a current installation first.`, ``, `To *uninstall* current version and re-install latest "${executable.name}":`, ``, `- Close all running instances of "${executable.name}", if any`, `- Use "--force" to install browser:`, ``, ` ${command}`, ``, `<3 Playwright Team`].join('\n'), 1));
|
||||
}
|
||||
await executable._install();
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.code === 'ELOCKED') {
|
||||
const rmCommand = process.platform === 'win32' ? 'rm -R' : 'rm -rf';
|
||||
throw new Error('\n' + (0, _utils.wrapInASCIIBox)([`An active lockfile is found at:`, ``, ` ${lockfilePath}`, ``, `Either:`, `- wait a few minutes if other Playwright is installing browsers in parallel`, `- remove lock manually with:`, ``, ` ${rmCommand} ${lockfilePath}`, ``, `<3 Playwright Team`].join('\n'), 1));
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
if (releaseLock) await releaseLock();
|
||||
}
|
||||
}
|
||||
async uninstall(all) {
|
||||
const linksDir = _path.default.join(registryDirectory, '.links');
|
||||
if (all) {
|
||||
const links = await fs.promises.readdir(linksDir).catch(() => []);
|
||||
for (const link of links) await fs.promises.unlink(_path.default.join(linksDir, link));
|
||||
} else {
|
||||
await fs.promises.unlink(_path.default.join(linksDir, (0, _utils.calculateSha1)(PACKAGE_PATH))).catch(() => {});
|
||||
}
|
||||
|
||||
// Remove stale browsers.
|
||||
await this._validateInstallationCache(linksDir);
|
||||
return {
|
||||
numberOfBrowsersLeft: (await fs.promises.readdir(registryDirectory).catch(() => [])).filter(browserDirectory => isBrowserDirectory(browserDirectory)).length
|
||||
};
|
||||
}
|
||||
_downloadURLs(descriptor) {
|
||||
const paths = DOWNLOAD_PATHS[descriptor.name];
|
||||
const downloadPathTemplate = paths[_hostPlatform.hostPlatform] || paths['<unknown>'];
|
||||
if (!downloadPathTemplate) return [];
|
||||
const downloadPath = util.format(downloadPathTemplate, descriptor.revision);
|
||||
let downloadURLs = PLAYWRIGHT_CDN_MIRRORS.map(mirror => `${mirror}/${downloadPath}`);
|
||||
let downloadHostEnv;
|
||||
if (descriptor.name.startsWith('chromium')) downloadHostEnv = 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST';else if (descriptor.name.startsWith('firefox')) downloadHostEnv = 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST';else if (descriptor.name.startsWith('webkit')) downloadHostEnv = 'PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST';
|
||||
const customHostOverride = downloadHostEnv && (0, _utils.getFromENV)(downloadHostEnv) || (0, _utils.getFromENV)('PLAYWRIGHT_DOWNLOAD_HOST');
|
||||
if (customHostOverride) downloadURLs = [`${customHostOverride}/${downloadPath}`];
|
||||
return downloadURLs;
|
||||
}
|
||||
async _downloadExecutable(descriptor, executablePath) {
|
||||
const downloadURLs = this._downloadURLs(descriptor);
|
||||
if (!downloadURLs.length) throw new Error(`ERROR: Playwright does not support ${descriptor.name} on ${_hostPlatform.hostPlatform}`);
|
||||
if (_hostPlatform.hostPlatform === 'generic-linux' || _hostPlatform.hostPlatform === 'generic-linux-arm64') (0, _browserFetcher.logPolitely)('BEWARE: your OS is not officially supported by Playwright; downloading fallback build.');
|
||||
const displayName = descriptor.name.split('-').map(word => {
|
||||
return word === 'ffmpeg' ? 'FFMPEG' : word.charAt(0).toUpperCase() + word.slice(1);
|
||||
}).join(' ');
|
||||
const title = descriptor.browserVersion ? `${displayName} ${descriptor.browserVersion} (playwright build v${descriptor.revision})` : `${displayName} playwright build v${descriptor.revision}`;
|
||||
const downloadFileName = `playwright-download-${descriptor.name}-${_hostPlatform.hostPlatform}-${descriptor.revision}.zip`;
|
||||
const downloadConnectionTimeoutEnv = (0, _utils.getFromENV)('PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT');
|
||||
const downloadConnectionTimeout = +(downloadConnectionTimeoutEnv || '0') || 30_000;
|
||||
await (0, _browserFetcher.downloadBrowserWithProgressBar)(title, descriptor.dir, executablePath, downloadURLs, downloadFileName, downloadConnectionTimeout).catch(e => {
|
||||
throw new Error(`Failed to download ${title}, caused by\n${e.stack}`);
|
||||
});
|
||||
await fs.promises.writeFile(markerFilePath(descriptor.dir), '');
|
||||
}
|
||||
async _installMSEdgeChannel(channel, scripts) {
|
||||
const scriptArgs = [];
|
||||
if (process.platform !== 'linux') {
|
||||
const products = lowercaseAllKeys(JSON.parse(await (0, _network.fetchData)({
|
||||
url: 'https://edgeupdates.microsoft.com/api/products'
|
||||
})));
|
||||
const productName = {
|
||||
'msedge': 'Stable',
|
||||
'msedge-beta': 'Beta',
|
||||
'msedge-dev': 'Dev'
|
||||
}[channel];
|
||||
const product = products.find(product => product.product === productName);
|
||||
const searchConfig = {
|
||||
darwin: {
|
||||
platform: 'MacOS',
|
||||
arch: 'universal',
|
||||
artifact: 'pkg'
|
||||
},
|
||||
win32: {
|
||||
platform: 'Windows',
|
||||
arch: 'x64',
|
||||
artifact: 'msi'
|
||||
}
|
||||
}[process.platform];
|
||||
const release = searchConfig ? product.releases.find(release => release.platform === searchConfig.platform && release.architecture === searchConfig.arch) : null;
|
||||
const artifact = release ? release.artifacts.find(artifact => artifact.artifactname === searchConfig.artifact) : null;
|
||||
if (artifact) scriptArgs.push(artifact.location /* url */);else throw new Error(`Cannot install ${channel} on ${process.platform}`);
|
||||
}
|
||||
await this._installChromiumChannel(channel, scripts, scriptArgs);
|
||||
}
|
||||
async _installChromiumChannel(channel, scripts, scriptArgs = []) {
|
||||
const scriptName = scripts[process.platform];
|
||||
if (!scriptName) throw new Error(`Cannot install ${channel} on ${process.platform}`);
|
||||
const cwd = BIN_PATH;
|
||||
const isPowerShell = scriptName.endsWith('.ps1');
|
||||
if (isPowerShell) {
|
||||
const args = ['-ExecutionPolicy', 'Bypass', '-File', _path.default.join(BIN_PATH, scriptName), ...scriptArgs];
|
||||
const {
|
||||
code
|
||||
} = await (0, _spawnAsync.spawnAsync)('powershell.exe', args, {
|
||||
cwd,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
if (code !== 0) throw new Error(`Failed to install ${channel}`);
|
||||
} else {
|
||||
const {
|
||||
command,
|
||||
args,
|
||||
elevatedPermissions
|
||||
} = await (0, _dependencies.transformCommandsForRoot)([`bash "${_path.default.join(BIN_PATH, scriptName)}" ${scriptArgs.join('')}`]);
|
||||
if (elevatedPermissions) console.log('Switching to root user to install dependencies...'); // eslint-disable-line no-console
|
||||
const {
|
||||
code
|
||||
} = await (0, _spawnAsync.spawnAsync)(command, args, {
|
||||
cwd,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
if (code !== 0) throw new Error(`Failed to install ${channel}`);
|
||||
}
|
||||
}
|
||||
async _validateInstallationCache(linksDir) {
|
||||
// 1. Collect used downloads and package descriptors.
|
||||
const usedBrowserPaths = new Set();
|
||||
for (const fileName of await fs.promises.readdir(linksDir)) {
|
||||
const linkPath = _path.default.join(linksDir, fileName);
|
||||
let linkTarget = '';
|
||||
try {
|
||||
linkTarget = (await fs.promises.readFile(linkPath)).toString();
|
||||
const browsersJSON = require(_path.default.join(linkTarget, 'browsers.json'));
|
||||
const descriptors = readDescriptors(browsersJSON);
|
||||
for (const browserName of allDownloadable) {
|
||||
// We retain browsers if they are found in the descriptor.
|
||||
// Note, however, that there are older versions out in the wild that rely on
|
||||
// the "download" field in the browser descriptor and use its value
|
||||
// to retain and download browsers.
|
||||
// As of v1.10, we decided to abandon "download" field.
|
||||
const descriptor = descriptors.find(d => d.name === browserName);
|
||||
if (!descriptor) continue;
|
||||
const usedBrowserPath = descriptor.dir;
|
||||
const browserRevision = parseInt(descriptor.revision, 10);
|
||||
// Old browser installations don't have marker file.
|
||||
// We switched chromium from 999999 to 1000, 300000 is the new Y2K.
|
||||
const shouldHaveMarkerFile = browserName === 'chromium' && (browserRevision >= 786218 || browserRevision < 300000) || browserName === 'firefox' && browserRevision >= 1128 || browserName === 'webkit' && browserRevision >= 1307 ||
|
||||
// All new applications have a marker file right away.
|
||||
browserName !== 'firefox' && browserName !== 'chromium' && browserName !== 'webkit';
|
||||
if (!shouldHaveMarkerFile || (await (0, _fileUtils.existsAsync)(markerFilePath(usedBrowserPath)))) usedBrowserPaths.add(usedBrowserPath);
|
||||
}
|
||||
} catch (e) {
|
||||
await fs.promises.unlink(linkPath).catch(e => {});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Delete all unused browsers.
|
||||
if (!(0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_GC')) {
|
||||
let downloadedBrowsers = (await fs.promises.readdir(registryDirectory)).map(file => _path.default.join(registryDirectory, file));
|
||||
downloadedBrowsers = downloadedBrowsers.filter(file => isBrowserDirectory(file));
|
||||
const directories = new Set(downloadedBrowsers);
|
||||
for (const browserDirectory of usedBrowserPaths) directories.delete(browserDirectory);
|
||||
for (const directory of directories) (0, _browserFetcher.logPolitely)('Removing unused browser at ' + directory);
|
||||
await (0, _fileUtils.removeFolders)([...directories]);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Registry = Registry;
|
||||
function markerFilePath(browserDirectory) {
|
||||
return _path.default.join(browserDirectory, 'INSTALLATION_COMPLETE');
|
||||
}
|
||||
function buildPlaywrightCLICommand(sdkLanguage, parameters) {
|
||||
switch (sdkLanguage) {
|
||||
case 'python':
|
||||
return `playwright ${parameters}`;
|
||||
case 'java':
|
||||
return `mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="${parameters}"`;
|
||||
case 'csharp':
|
||||
return `pwsh bin/Debug/netX/playwright.ps1 ${parameters}`;
|
||||
default:
|
||||
return `npx playwright ${parameters}`;
|
||||
}
|
||||
}
|
||||
async function installDefaultBrowsersForNpmInstall() {
|
||||
const defaultBrowserNames = registry.defaultExecutables().map(e => e.name);
|
||||
return installBrowsersForNpmInstall(defaultBrowserNames);
|
||||
}
|
||||
async function installBrowsersForNpmInstall(browsers) {
|
||||
// PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD should have a value of 0 or 1
|
||||
if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD')) {
|
||||
(0, _browserFetcher.logPolitely)('Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set');
|
||||
return false;
|
||||
}
|
||||
const executables = [];
|
||||
for (const browserName of browsers) {
|
||||
const executable = registry.findExecutable(browserName);
|
||||
if (!executable || executable.installType === 'none') throw new Error(`Cannot install ${browserName}`);
|
||||
executables.push(executable);
|
||||
}
|
||||
await registry.install(executables, false /* forceReinstall */);
|
||||
}
|
||||
|
||||
function findChromiumChannel(sdkLanguage) {
|
||||
// Fall back to the stable channels of popular vendors to work out of the box.
|
||||
// Null means no installation and no channels found.
|
||||
let channel = null;
|
||||
for (const name of ['chromium', 'chrome', 'msedge']) {
|
||||
try {
|
||||
registry.findExecutable(name).executablePathOrDie(sdkLanguage);
|
||||
channel = name === 'chromium' ? undefined : name;
|
||||
break;
|
||||
} catch (e) {}
|
||||
}
|
||||
if (channel === null) {
|
||||
const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install chromium`);
|
||||
const prettyMessage = [`No chromium-based browser found on the system.`, `Please run the following command to download one:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team`].join('\n');
|
||||
throw new Error('\n' + (0, _utils.wrapInASCIIBox)(prettyMessage, 1));
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
function lowercaseAllKeys(json) {
|
||||
if (typeof json !== 'object' || !json) return json;
|
||||
if (Array.isArray(json)) return json.map(lowercaseAllKeys);
|
||||
const result = {};
|
||||
for (const [key, value] of Object.entries(json)) result[key.toLowerCase()] = lowercaseAllKeys(value);
|
||||
return result;
|
||||
}
|
||||
const registry = new Registry(require('../../../browsers.json'));
|
||||
exports.registry = registry;
|
||||
@@ -0,0 +1,437 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.deps = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// - This file is used to execute 'npx playwright install-deps'
|
||||
// - The reverse mappings "lib2package" are generated with the following script:
|
||||
// ./utils/linux-browser-dependencies/run.sh ubuntu:20.04
|
||||
|
||||
const deps = {
|
||||
'ubuntu18.04': {
|
||||
tools: ['xvfb', 'fonts-noto-color-emoji', 'ttf-unifont', 'libfontconfig', 'libfreetype6', 'xfonts-cyrillic', 'xfonts-scalable', 'fonts-liberation', 'fonts-ipafont-gothic', 'fonts-wqy-zenhei', 'fonts-tlwg-loma-otf', 'ttf-ubuntu-font-family'],
|
||||
chromium: ['fonts-liberation', 'libasound2', 'libatk-bridge2.0-0', 'libatk1.0-0', 'libatspi2.0-0', 'libcairo2', 'libcups2', 'libdbus-1-3', 'libdrm2', 'libegl1', 'libgbm1', 'libglib2.0-0', 'libgtk-3-0', 'libnspr4', 'libnss3', 'libpango-1.0-0', 'libx11-6', 'libx11-xcb1', 'libxcb1', 'libxcomposite1', 'libxdamage1', 'libxext6', 'libxfixes3', 'libxrandr2', 'libxshmfence1'],
|
||||
firefox: ['ffmpeg', 'libatk1.0-0', 'libcairo-gobject2', 'libcairo2', 'libdbus-1-3', 'libdbus-glib-1-2', 'libfontconfig1', 'libfreetype6', 'libgdk-pixbuf2.0-0', 'libglib2.0-0', 'libgtk-3-0', 'libpango-1.0-0', 'libpangocairo-1.0-0', 'libpangoft2-1.0-0', 'libx11-6', 'libx11-xcb1', 'libxcb-shm0', 'libxcb1', 'libxcomposite1', 'libxcursor1', 'libxdamage1', 'libxext6', 'libxfixes3', 'libxi6', 'libxrender1', 'libxt6', 'libxtst6'],
|
||||
webkit: [],
|
||||
lib2package: {
|
||||
'libasound.so.2': 'libasound2',
|
||||
'libatk-1.0.so.0': 'libatk1.0-0',
|
||||
'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',
|
||||
'libatspi.so.0': 'libatspi2.0-0',
|
||||
'libbrotlidec.so.1': 'libbrotli1',
|
||||
'libcairo-gobject.so.2': 'libcairo-gobject2',
|
||||
'libcairo.so.2': 'libcairo2',
|
||||
'libcups.so.2': 'libcups2',
|
||||
'libdbus-1.so.3': 'libdbus-1-3',
|
||||
'libdbus-glib-1.so.2': 'libdbus-glib-1-2',
|
||||
'libdrm.so.2': 'libdrm2',
|
||||
'libEGL.so.1': 'libegl1',
|
||||
'libenchant.so.1': 'libenchant1c2a',
|
||||
'libepoxy.so.0': 'libepoxy0',
|
||||
'libevent-2.1.so.6': 'libevent-2.1-6',
|
||||
'libevdev.so.2': 'libevdev2',
|
||||
'libfontconfig.so.1': 'libfontconfig1',
|
||||
'libfreetype.so.6': 'libfreetype6',
|
||||
'libgbm.so.1': 'libgbm1',
|
||||
'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf2.0-0',
|
||||
'libgdk-3.so.0': 'libgtk-3-0',
|
||||
'libgdk-x11-2.0.so.0': 'libgtk2.0-0',
|
||||
'libgio-2.0.so.0': 'libglib2.0-0',
|
||||
'libGL.so.1': 'libgl1',
|
||||
'libGLESv2.so.2': 'libgles2',
|
||||
'libglib-2.0.so.0': 'libglib2.0-0',
|
||||
'libgmodule-2.0.so.0': 'libglib2.0-0',
|
||||
'libgobject-2.0.so.0': 'libglib2.0-0',
|
||||
'libgstapp-1.0.so.0': 'gstreamer1.0-plugins-base',
|
||||
'libgstaudio-1.0.so.0': 'gstreamer1.0-plugins-base',
|
||||
'libgstbase-1.0.so.0': 'libgstreamer1.0-0',
|
||||
'libgstcodecparsers-1.0.so.0': 'gstreamer1.0-plugins-bad',
|
||||
'libgstfft-1.0.so.0': 'gstreamer1.0-plugins-base',
|
||||
'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',
|
||||
'libgstpbutils-1.0.so.0': 'gstreamer1.0-plugins-base',
|
||||
'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',
|
||||
'libgsttag-1.0.so.0': 'gstreamer1.0-plugins-base',
|
||||
'libgstvideo-1.0.so.0': 'gstreamer1.0-plugins-base',
|
||||
'libgthread-2.0.so.0': 'libglib2.0-0',
|
||||
'libgtk-3.so.0': 'libgtk-3-0',
|
||||
'libgtk-x11-2.0.so.0': 'libgtk2.0-0',
|
||||
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
|
||||
'libharfbuzz.so.0': 'libharfbuzz0b',
|
||||
'libhyphen.so.0': 'libhyphen0',
|
||||
'libicudata.so.60': 'libicu60',
|
||||
'libicui18n.so.60': 'libicu60',
|
||||
'libicuuc.so.60': 'libicu60',
|
||||
'libjpeg.so.8': 'libjpeg-turbo8',
|
||||
'libnotify.so.4': 'libnotify4',
|
||||
'libnspr4.so': 'libnspr4',
|
||||
'libnss3.so': 'libnss3',
|
||||
'libnssutil3.so': 'libnss3',
|
||||
'libopenjp2.so.7': 'libopenjp2-7',
|
||||
'libopus.so.0': 'libopus0',
|
||||
'libpango-1.0.so.0': 'libpango-1.0-0',
|
||||
'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',
|
||||
'libpangoft2-1.0.so.0': 'libpangoft2-1.0-0',
|
||||
'libpng16.so.16': 'libpng16-16',
|
||||
'libsecret-1.so.0': 'libsecret-1-0',
|
||||
'libsmime3.so': 'libnss3',
|
||||
'libvpx.so.5': 'libvpx5',
|
||||
'libwayland-client.so.0': 'libwayland-client0',
|
||||
'libwayland-egl.so.1': 'libwayland-egl1',
|
||||
'libwayland-server.so.0': 'libwayland-server0',
|
||||
'libwebp.so.6': 'libwebp6',
|
||||
'libwebpdemux.so.2': 'libwebpdemux2',
|
||||
'libwoff2dec.so.1.0.2': 'libwoff1',
|
||||
'libX11-xcb.so.1': 'libx11-xcb1',
|
||||
'libX11.so.6': 'libx11-6',
|
||||
'libxcb-dri3.so.0': 'libxcb-dri3-0',
|
||||
'libxcb-shm.so.0': 'libxcb-shm0',
|
||||
'libxcb.so.1': 'libxcb1',
|
||||
'libXcomposite.so.1': 'libxcomposite1',
|
||||
'libXcursor.so.1': 'libxcursor1',
|
||||
'libXdamage.so.1': 'libxdamage1',
|
||||
'libXext.so.6': 'libxext6',
|
||||
'libXfixes.so.3': 'libxfixes3',
|
||||
'libXi.so.6': 'libxi6',
|
||||
'libxkbcommon.so.0': 'libxkbcommon0',
|
||||
'libxml2.so.2': 'libxml2',
|
||||
'libXrandr.so.2': 'libxrandr2',
|
||||
'libXrender.so.1': 'libxrender1',
|
||||
'libxslt.so.1': 'libxslt1.1',
|
||||
'libXt.so.6': 'libxt6',
|
||||
'libXtst.so.6': 'libxtst6',
|
||||
'libevent-2.1-6': 'libevent-2.1-6'
|
||||
}
|
||||
},
|
||||
'ubuntu20.04': {
|
||||
tools: ['xvfb', 'fonts-noto-color-emoji', 'ttf-unifont', 'libfontconfig', 'libfreetype6', 'xfonts-cyrillic', 'xfonts-scalable', 'fonts-liberation', 'fonts-ipafont-gothic', 'fonts-wqy-zenhei', 'fonts-tlwg-loma-otf', 'ttf-ubuntu-font-family'],
|
||||
chromium: ['fonts-liberation', 'libasound2', 'libatk-bridge2.0-0', 'libatk1.0-0', 'libatspi2.0-0', 'libcairo2', 'libcups2', 'libdbus-1-3', 'libdrm2', 'libegl1', 'libgbm1', 'libglib2.0-0', 'libgtk-3-0', 'libnspr4', 'libnss3', 'libpango-1.0-0', 'libx11-6', 'libx11-xcb1', 'libxcb1', 'libxcomposite1', 'libxdamage1', 'libxext6', 'libxfixes3', 'libxrandr2', 'libxshmfence1'],
|
||||
firefox: ['ffmpeg', 'libatk1.0-0', 'libcairo-gobject2', 'libcairo2', 'libdbus-1-3', 'libdbus-glib-1-2', 'libfontconfig1', 'libfreetype6', 'libgdk-pixbuf2.0-0', 'libglib2.0-0', 'libgtk-3-0', 'libpango-1.0-0', 'libpangocairo-1.0-0', 'libpangoft2-1.0-0', 'libx11-6', 'libx11-xcb1', 'libxcb-shm0', 'libxcb1', 'libxcomposite1', 'libxcursor1', 'libxdamage1', 'libxext6', 'libxfixes3', 'libxi6', 'libxrender1', 'libxt6', 'libxtst6'],
|
||||
webkit: ['libenchant-2-2', 'libflite1', 'libx264-155', 'libatk-bridge2.0-0', 'libatk1.0-0', 'libcairo2', 'libegl1', 'libenchant1c2a', 'libepoxy0', 'libevdev2', 'libfontconfig1', 'libfreetype6', 'libgdk-pixbuf2.0-0', 'libgl1', 'libgles2', 'libglib2.0-0', 'libgtk-3-0', 'libgudev-1.0-0', 'libharfbuzz-icu0', 'libharfbuzz0b', 'libhyphen0', 'libicu66', 'libjpeg-turbo8', 'libnotify4', 'libopengl0', 'libopenjp2-7', 'libopus0', 'libpango-1.0-0', 'libpng16-16', 'libsecret-1-0', 'libsoup2.4-1', 'libvpx6', 'libwayland-client0', 'libwayland-egl1', 'libwayland-server0', 'libwebp6', 'libwebpdemux2', 'libwoff1', 'libx11-6', 'libxcomposite1', 'libxdamage1', 'libxkbcommon0', 'libxml2', 'libxslt1.1', 'libatomic1', 'libevent-2.1-7'],
|
||||
lib2package: {
|
||||
'libflite.so.1': 'libflite1',
|
||||
'libflite_usenglish.so.1': 'libflite1',
|
||||
'libflite_cmu_grapheme_lang.so.1': 'libflite1',
|
||||
'libflite_cmu_grapheme_lex.so.1': 'libflite1',
|
||||
'libflite_cmu_indic_lang.so.1': 'libflite1',
|
||||
'libflite_cmu_indic_lex.so.1': 'libflite1',
|
||||
'libflite_cmulex.so.1': 'libflite1',
|
||||
'libflite_cmu_time_awb.so.1': 'libflite1',
|
||||
'libflite_cmu_us_awb.so.1': 'libflite1',
|
||||
'libflite_cmu_us_kal16.so.1': 'libflite1',
|
||||
'libflite_cmu_us_kal.so.1': 'libflite1',
|
||||
'libflite_cmu_us_rms.so.1': 'libflite1',
|
||||
'libflite_cmu_us_slt.so.1': 'libflite1',
|
||||
'libx264.so': 'libx264-155',
|
||||
'libasound.so.2': 'libasound2',
|
||||
'libatk-1.0.so.0': 'libatk1.0-0',
|
||||
'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',
|
||||
'libatspi.so.0': 'libatspi2.0-0',
|
||||
'libcairo-gobject.so.2': 'libcairo-gobject2',
|
||||
'libcairo.so.2': 'libcairo2',
|
||||
'libcups.so.2': 'libcups2',
|
||||
'libdbus-1.so.3': 'libdbus-1-3',
|
||||
'libdbus-glib-1.so.2': 'libdbus-glib-1-2',
|
||||
'libdrm.so.2': 'libdrm2',
|
||||
'libEGL.so.1': 'libegl1',
|
||||
'libenchant.so.1': 'libenchant1c2a',
|
||||
'libevdev.so.2': 'libevdev2',
|
||||
'libepoxy.so.0': 'libepoxy0',
|
||||
'libfontconfig.so.1': 'libfontconfig1',
|
||||
'libfreetype.so.6': 'libfreetype6',
|
||||
'libgbm.so.1': 'libgbm1',
|
||||
'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf2.0-0',
|
||||
'libgdk-3.so.0': 'libgtk-3-0',
|
||||
'libgdk-x11-2.0.so.0': 'libgtk2.0-0',
|
||||
'libgio-2.0.so.0': 'libglib2.0-0',
|
||||
'libGL.so.1': 'libgl1',
|
||||
'libGLESv2.so.2': 'libgles2',
|
||||
'libglib-2.0.so.0': 'libglib2.0-0',
|
||||
'libgmodule-2.0.so.0': 'libglib2.0-0',
|
||||
'libgobject-2.0.so.0': 'libglib2.0-0',
|
||||
'libgthread-2.0.so.0': 'libglib2.0-0',
|
||||
'libgtk-3.so.0': 'libgtk-3-0',
|
||||
'libgtk-x11-2.0.so.0': 'libgtk2.0-0',
|
||||
'libgudev-1.0.so.0': 'libgudev-1.0-0',
|
||||
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
|
||||
'libharfbuzz.so.0': 'libharfbuzz0b',
|
||||
'libhyphen.so.0': 'libhyphen0',
|
||||
'libicui18n.so.66': 'libicu66',
|
||||
'libicuuc.so.66': 'libicu66',
|
||||
'libjpeg.so.8': 'libjpeg-turbo8',
|
||||
'libnotify.so.4': 'libnotify4',
|
||||
'libnspr4.so': 'libnspr4',
|
||||
'libnss3.so': 'libnss3',
|
||||
'libnssutil3.so': 'libnss3',
|
||||
'libOpenGL.so.0': 'libopengl0',
|
||||
'libopenjp2.so.7': 'libopenjp2-7',
|
||||
'libopus.so.0': 'libopus0',
|
||||
'libpango-1.0.so.0': 'libpango-1.0-0',
|
||||
'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',
|
||||
'libpangoft2-1.0.so.0': 'libpangoft2-1.0-0',
|
||||
'libpng16.so.16': 'libpng16-16',
|
||||
'libsecret-1.so.0': 'libsecret-1-0',
|
||||
'libsmime3.so': 'libnss3',
|
||||
'libsoup-2.4.so.1': 'libsoup2.4-1',
|
||||
'libvpx.so.6': 'libvpx6',
|
||||
'libwayland-client.so.0': 'libwayland-client0',
|
||||
'libwayland-egl.so.1': 'libwayland-egl1',
|
||||
'libwayland-server.so.0': 'libwayland-server0',
|
||||
'libwebp.so.6': 'libwebp6',
|
||||
'libwebpdemux.so.2': 'libwebpdemux2',
|
||||
'libwoff2dec.so.1.0.2': 'libwoff1',
|
||||
'libX11-xcb.so.1': 'libx11-xcb1',
|
||||
'libX11.so.6': 'libx11-6',
|
||||
'libxcb-dri3.so.0': 'libxcb-dri3-0',
|
||||
'libxcb-shm.so.0': 'libxcb-shm0',
|
||||
'libxcb.so.1': 'libxcb1',
|
||||
'libXcomposite.so.1': 'libxcomposite1',
|
||||
'libXcursor.so.1': 'libxcursor1',
|
||||
'libXdamage.so.1': 'libxdamage1',
|
||||
'libXext.so.6': 'libxext6',
|
||||
'libXfixes.so.3': 'libxfixes3',
|
||||
'libXi.so.6': 'libxi6',
|
||||
'libxkbcommon.so.0': 'libxkbcommon0',
|
||||
'libxml2.so.2': 'libxml2',
|
||||
'libXrandr.so.2': 'libxrandr2',
|
||||
'libXrender.so.1': 'libxrender1',
|
||||
'libxslt.so.1': 'libxslt1.1',
|
||||
'libXt.so.6': 'libxt6',
|
||||
'libXtst.so.6': 'libxtst6',
|
||||
'libxshmfence.so.1': 'libxshmfence1',
|
||||
'libatomic.so.1': 'libatomic1',
|
||||
'libenchant-2.so.2': 'libenchant-2-2',
|
||||
'libevent-2.1.so.7': 'libevent-2.1-7'
|
||||
}
|
||||
},
|
||||
'ubuntu22.04': {
|
||||
tools: ['xvfb', 'fonts-noto-color-emoji', 'fonts-unifont', 'libfontconfig1', 'libfreetype6', 'xfonts-cyrillic', 'xfonts-scalable', 'fonts-liberation', 'fonts-ipafont-gothic', 'fonts-wqy-zenhei', 'fonts-tlwg-loma-otf', 'fonts-freefont-ttf'],
|
||||
chromium: ['libasound2', 'libatk-bridge2.0-0', 'libatk1.0-0', 'libatspi2.0-0', 'libcairo2', 'libcups2', 'libdbus-1-3', 'libdrm2', 'libgbm1', 'libglib2.0-0', 'libnspr4', 'libnss3', 'libpango-1.0-0', 'libwayland-client0', 'libx11-6', 'libxcb1', 'libxcomposite1', 'libxdamage1', 'libxext6', 'libxfixes3', 'libxkbcommon0', 'libxrandr2'],
|
||||
firefox: ['ffmpeg', 'libasound2', 'libatk1.0-0', 'libcairo-gobject2', 'libcairo2', 'libdbus-1-3', 'libdbus-glib-1-2', 'libfontconfig1', 'libfreetype6', 'libgdk-pixbuf-2.0-0', 'libglib2.0-0', 'libgtk-3-0', 'libpango-1.0-0', 'libpangocairo-1.0-0', 'libx11-6', 'libx11-xcb1', 'libxcb-shm0', 'libxcb1', 'libxcomposite1', 'libxcursor1', 'libxdamage1', 'libxext6', 'libxfixes3', 'libxi6', 'libxrandr2', 'libxrender1', 'libxtst6'],
|
||||
webkit: ['libenchant-2-2', 'gstreamer1.0-libav', 'gstreamer1.0-plugins-bad', 'gstreamer1.0-plugins-base', 'gstreamer1.0-plugins-good', 'libicu70', 'libatk-bridge2.0-0', 'libatk1.0-0', 'libcairo2', 'libdbus-1-3', 'libdrm2', 'libegl1', 'libepoxy0', 'libevdev2', 'libffi7', 'libfontconfig1', 'libfreetype6', 'libgbm1', 'libgdk-pixbuf-2.0-0', 'libgles2', 'libglib2.0-0', 'libglx0', 'libgstreamer-gl1.0-0', 'libgstreamer-plugins-base1.0-0', 'libgstreamer1.0-0', 'libgtk-3-0', 'libgudev-1.0-0', 'libharfbuzz-icu0', 'libharfbuzz0b', 'libhyphen0', 'libjpeg-turbo8', 'liblcms2-2', 'libmanette-0.2-0', 'libnotify4', 'libopengl0', 'libopenjp2-7', 'libopus0', 'libpango-1.0-0', 'libpng16-16', 'libproxy1v5', 'libsecret-1-0', 'libsoup2.4-1', 'libwayland-client0', 'libwayland-egl1', 'libwayland-server0', 'libwebpdemux2', 'libwoff1', 'libx11-6', 'libxcomposite1', 'libxdamage1', 'libxkbcommon0', 'libxml2', 'libxslt1.1', 'libx264-163', 'libatomic1', 'libevent-2.1-7'],
|
||||
lib2package: {
|
||||
'libasound.so.2': 'libasound2',
|
||||
'libatk-1.0.so.0': 'libatk1.0-0',
|
||||
'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',
|
||||
'libatspi.so.0': 'libatspi2.0-0',
|
||||
'libcairo-gobject.so.2': 'libcairo-gobject2',
|
||||
'libcairo.so.2': 'libcairo2',
|
||||
'libcups.so.2': 'libcups2',
|
||||
'libdbus-1.so.3': 'libdbus-1-3',
|
||||
'libdbus-glib-1.so.2': 'libdbus-glib-1-2',
|
||||
'libdrm.so.2': 'libdrm2',
|
||||
'libEGL.so.1': 'libegl1',
|
||||
'libepoxy.so.0': 'libepoxy0',
|
||||
'libevdev.so.2': 'libevdev2',
|
||||
'libffi.so.7': 'libffi7',
|
||||
'libfontconfig.so.1': 'libfontconfig1',
|
||||
'libfreetype.so.6': 'libfreetype6',
|
||||
'libgbm.so.1': 'libgbm1',
|
||||
'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf-2.0-0',
|
||||
'libgdk-3.so.0': 'libgtk-3-0',
|
||||
'libgio-2.0.so.0': 'libglib2.0-0',
|
||||
'libGLESv2.so.2': 'libgles2',
|
||||
'libglib-2.0.so.0': 'libglib2.0-0',
|
||||
'libGLX.so.0': 'libglx0',
|
||||
'libgmodule-2.0.so.0': 'libglib2.0-0',
|
||||
'libgobject-2.0.so.0': 'libglib2.0-0',
|
||||
'libgstallocators-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstapp-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstaudio-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstbase-1.0.so.0': 'libgstreamer1.0-0',
|
||||
'libgstfft-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',
|
||||
'libgstpbutils-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',
|
||||
'libgsttag-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstvideo-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgtk-3.so.0': 'libgtk-3-0',
|
||||
'libgudev-1.0.so.0': 'libgudev-1.0-0',
|
||||
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
|
||||
'libharfbuzz.so.0': 'libharfbuzz0b',
|
||||
'libhyphen.so.0': 'libhyphen0',
|
||||
'libjpeg.so.8': 'libjpeg-turbo8',
|
||||
'liblcms2.so.2': 'liblcms2-2',
|
||||
'libmanette-0.2.so.0': 'libmanette-0.2-0',
|
||||
'libnotify.so.4': 'libnotify4',
|
||||
'libnspr4.so': 'libnspr4',
|
||||
'libnss3.so': 'libnss3',
|
||||
'libnssutil3.so': 'libnss3',
|
||||
'libOpenGL.so.0': 'libopengl0',
|
||||
'libopenjp2.so.7': 'libopenjp2-7',
|
||||
'libopus.so.0': 'libopus0',
|
||||
'libpango-1.0.so.0': 'libpango-1.0-0',
|
||||
'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',
|
||||
'libpng16.so.16': 'libpng16-16',
|
||||
'libproxy.so.1': 'libproxy1v5',
|
||||
'libsecret-1.so.0': 'libsecret-1-0',
|
||||
'libsmime3.so': 'libnss3',
|
||||
'libsoup-2.4.so.1': 'libsoup2.4-1',
|
||||
'libwayland-client.so.0': 'libwayland-client0',
|
||||
'libwayland-egl.so.1': 'libwayland-egl1',
|
||||
'libwayland-server.so.0': 'libwayland-server0',
|
||||
'libwebpdemux.so.2': 'libwebpdemux2',
|
||||
'libwoff2dec.so.1.0.2': 'libwoff1',
|
||||
'libX11-xcb.so.1': 'libx11-xcb1',
|
||||
'libX11.so.6': 'libx11-6',
|
||||
'libxcb-shm.so.0': 'libxcb-shm0',
|
||||
'libxcb.so.1': 'libxcb1',
|
||||
'libXcomposite.so.1': 'libxcomposite1',
|
||||
'libXcursor.so.1': 'libxcursor1',
|
||||
'libXdamage.so.1': 'libxdamage1',
|
||||
'libXext.so.6': 'libxext6',
|
||||
'libXfixes.so.3': 'libxfixes3',
|
||||
'libXi.so.6': 'libxi6',
|
||||
'libxkbcommon.so.0': 'libxkbcommon0',
|
||||
'libxml2.so.2': 'libxml2',
|
||||
'libXrandr.so.2': 'libxrandr2',
|
||||
'libXrender.so.1': 'libxrender1',
|
||||
'libxslt.so.1': 'libxslt1.1',
|
||||
'libXtst.so.6': 'libxtst6',
|
||||
'libicui18n.so.60': 'libicu70',
|
||||
'libicuuc.so.66': 'libicu70',
|
||||
'libicui18n.so.66': 'libicu70',
|
||||
'libwebp.so.6': 'libwebp6',
|
||||
'libenchant-2.so.2': 'libenchant-2-2',
|
||||
'libx264.so': 'libx264-163',
|
||||
'libvpx.so.7': 'libvpx7',
|
||||
'libatomic.so.1': 'libatomic1',
|
||||
'libevent-2.1.so.7': 'libevent-2.1-7'
|
||||
}
|
||||
},
|
||||
'debian11': {
|
||||
tools: ['xvfb', 'fonts-noto-color-emoji', 'fonts-unifont', 'libfontconfig1', 'libfreetype6', 'xfonts-cyrillic', 'xfonts-scalable', 'fonts-liberation', 'fonts-ipafont-gothic', 'fonts-wqy-zenhei', 'fonts-tlwg-loma-otf', 'fonts-freefont-ttf'],
|
||||
chromium: ['libasound2', 'libatk-bridge2.0-0', 'libatk1.0-0', 'libatspi2.0-0', 'libcairo2', 'libcups2', 'libdbus-1-3', 'libdrm2', 'libgbm1', 'libglib2.0-0', 'libnspr4', 'libnss3', 'libpango-1.0-0', 'libwayland-client0', 'libx11-6', 'libxcb1', 'libxcomposite1', 'libxdamage1', 'libxext6', 'libxfixes3', 'libxkbcommon0', 'libxrandr2'],
|
||||
firefox: ['libasound2', 'libatk1.0-0', 'libcairo-gobject2', 'libcairo2', 'libdbus-1-3', 'libdbus-glib-1-2', 'libfontconfig1', 'libfreetype6', 'libgdk-pixbuf-2.0-0', 'libglib2.0-0', 'libgtk-3-0', 'libharfbuzz0b', 'libpango-1.0-0', 'libpangocairo-1.0-0', 'libx11-6', 'libx11-xcb1', 'libxcb-shm0', 'libxcb1', 'libxcomposite1', 'libxcursor1', 'libxdamage1', 'libxext6', 'libxfixes3', 'libxi6', 'libxrandr2', 'libxrender1', 'libxtst6'],
|
||||
webkit: ['gstreamer1.0-libav', 'gstreamer1.0-plugins-bad', 'gstreamer1.0-plugins-base', 'gstreamer1.0-plugins-good', 'libatk-bridge2.0-0', 'libatk1.0-0', 'libcairo2', 'libdbus-1-3', 'libdrm2', 'libegl1', 'libenchant-2-2', 'libepoxy0', 'libevdev2', 'libfontconfig1', 'libfreetype6', 'libgbm1', 'libgdk-pixbuf-2.0-0', 'libgles2', 'libglib2.0-0', 'libglx0', 'libgstreamer-gl1.0-0', 'libgstreamer-plugins-base1.0-0', 'libgstreamer1.0-0', 'libgtk-3-0', 'libgudev-1.0-0', 'libharfbuzz-icu0', 'libharfbuzz0b', 'libhyphen0', 'libicu67', 'libjpeg62-turbo', 'liblcms2-2', 'libmanette-0.2-0', 'libnotify4', 'libopengl0', 'libopenjp2-7', 'libopus0', 'libpango-1.0-0', 'libpng16-16', 'libproxy1v5', 'libsecret-1-0', 'libsoup2.4-1', 'libwayland-client0', 'libwayland-egl1', 'libwayland-server0', 'libwebp6', 'libwebpdemux2', 'libwoff1', 'libx11-6', 'libxcomposite1', 'libxdamage1', 'libxkbcommon0', 'libxml2', 'libxslt1.1', 'libatomic1', 'libevent-2.1-7'],
|
||||
lib2package: {
|
||||
'libasound.so.2': 'libasound2',
|
||||
'libatk-1.0.so.0': 'libatk1.0-0',
|
||||
'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',
|
||||
'libatspi.so.0': 'libatspi2.0-0',
|
||||
'libcairo-gobject.so.2': 'libcairo-gobject2',
|
||||
'libcairo.so.2': 'libcairo2',
|
||||
'libcups.so.2': 'libcups2',
|
||||
'libdbus-1.so.3': 'libdbus-1-3',
|
||||
'libdbus-glib-1.so.2': 'libdbus-glib-1-2',
|
||||
'libdrm.so.2': 'libdrm2',
|
||||
'libEGL.so.1': 'libegl1',
|
||||
'libenchant-2.so.2': 'libenchant-2-2',
|
||||
'libepoxy.so.0': 'libepoxy0',
|
||||
'libevdev.so.2': 'libevdev2',
|
||||
'libfontconfig.so.1': 'libfontconfig1',
|
||||
'libfreetype.so.6': 'libfreetype6',
|
||||
'libgbm.so.1': 'libgbm1',
|
||||
'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf-2.0-0',
|
||||
'libgdk-3.so.0': 'libgtk-3-0',
|
||||
'libgio-2.0.so.0': 'libglib2.0-0',
|
||||
'libGLESv2.so.2': 'libgles2',
|
||||
'libglib-2.0.so.0': 'libglib2.0-0',
|
||||
'libGLX.so.0': 'libglx0',
|
||||
'libgmodule-2.0.so.0': 'libglib2.0-0',
|
||||
'libgobject-2.0.so.0': 'libglib2.0-0',
|
||||
'libgstallocators-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstapp-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstaudio-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstbase-1.0.so.0': 'libgstreamer1.0-0',
|
||||
'libgstfft-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',
|
||||
'libgstpbutils-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',
|
||||
'libgsttag-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgstvideo-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
|
||||
'libgtk-3.so.0': 'libgtk-3-0',
|
||||
'libgudev-1.0.so.0': 'libgudev-1.0-0',
|
||||
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
|
||||
'libharfbuzz.so.0': 'libharfbuzz0b',
|
||||
'libhyphen.so.0': 'libhyphen0',
|
||||
'libicui18n.so.67': 'libicu67',
|
||||
'libicuuc.so.67': 'libicu67',
|
||||
'libjpeg.so.62': 'libjpeg62-turbo',
|
||||
'liblcms2.so.2': 'liblcms2-2',
|
||||
'libmanette-0.2.so.0': 'libmanette-0.2-0',
|
||||
'libnotify.so.4': 'libnotify4',
|
||||
'libnspr4.so': 'libnspr4',
|
||||
'libnss3.so': 'libnss3',
|
||||
'libnssutil3.so': 'libnss3',
|
||||
'libOpenGL.so.0': 'libopengl0',
|
||||
'libopenjp2.so.7': 'libopenjp2-7',
|
||||
'libopus.so.0': 'libopus0',
|
||||
'libpango-1.0.so.0': 'libpango-1.0-0',
|
||||
'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',
|
||||
'libpng16.so.16': 'libpng16-16',
|
||||
'libproxy.so.1': 'libproxy1v5',
|
||||
'libsecret-1.so.0': 'libsecret-1-0',
|
||||
'libsmime3.so': 'libnss3',
|
||||
'libsoup-2.4.so.1': 'libsoup2.4-1',
|
||||
'libwayland-client.so.0': 'libwayland-client0',
|
||||
'libwayland-egl.so.1': 'libwayland-egl1',
|
||||
'libwayland-server.so.0': 'libwayland-server0',
|
||||
'libwebp.so.6': 'libwebp6',
|
||||
'libwebpdemux.so.2': 'libwebpdemux2',
|
||||
'libwoff2dec.so.1.0.2': 'libwoff1',
|
||||
'libX11-xcb.so.1': 'libx11-xcb1',
|
||||
'libX11.so.6': 'libx11-6',
|
||||
'libxcb-shm.so.0': 'libxcb-shm0',
|
||||
'libxcb.so.1': 'libxcb1',
|
||||
'libXcomposite.so.1': 'libxcomposite1',
|
||||
'libXcursor.so.1': 'libxcursor1',
|
||||
'libXdamage.so.1': 'libxdamage1',
|
||||
'libXext.so.6': 'libxext6',
|
||||
'libXfixes.so.3': 'libxfixes3',
|
||||
'libXi.so.6': 'libxi6',
|
||||
'libxkbcommon.so.0': 'libxkbcommon0',
|
||||
'libxml2.so.2': 'libxml2',
|
||||
'libXrandr.so.2': 'libxrandr2',
|
||||
'libXrender.so.1': 'libxrender1',
|
||||
'libxslt.so.1': 'libxslt1.1',
|
||||
'libXtst.so.6': 'libxtst6',
|
||||
'libatomic.so.1': 'libatomic1',
|
||||
'libevent-2.1.so.7': 'libevent-2.1-7'
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.deps = deps;
|
||||
deps['ubuntu20.04-arm64'] = {
|
||||
tools: [...deps['ubuntu20.04'].tools],
|
||||
chromium: [...deps['ubuntu20.04'].chromium],
|
||||
firefox: [...deps['ubuntu20.04'].firefox],
|
||||
webkit: [...deps['ubuntu20.04'].webkit],
|
||||
lib2package: {
|
||||
...deps['ubuntu20.04'].lib2package
|
||||
}
|
||||
};
|
||||
deps['ubuntu22.04-arm64'] = {
|
||||
tools: [...deps['ubuntu22.04'].tools],
|
||||
chromium: [...deps['ubuntu22.04'].chromium],
|
||||
firefox: [...deps['ubuntu22.04'].firefox],
|
||||
webkit: [...deps['ubuntu22.04'].webkit],
|
||||
lib2package: {
|
||||
...deps['ubuntu22.04'].lib2package
|
||||
}
|
||||
};
|
||||
deps['debian11-arm64'] = {
|
||||
tools: [...deps['debian11'].tools],
|
||||
chromium: [...deps['debian11'].chromium],
|
||||
firefox: [...deps['debian11'].firefox],
|
||||
webkit: [...deps['debian11'].webkit],
|
||||
lib2package: {
|
||||
...deps['debian11'].lib2package
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
"use strict";
|
||||
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _utilsBundle = require("../../utilsBundle");
|
||||
var _network = require("../../utils/network");
|
||||
var _manualPromise = require("../../utils/manualPromise");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function downloadFile(url, destinationPath, options) {
|
||||
const {
|
||||
progressCallback,
|
||||
log = () => {}
|
||||
} = options;
|
||||
log(`running download:`);
|
||||
log(`-- from url: ${url}`);
|
||||
log(`-- to location: ${destinationPath}`);
|
||||
let downloadedBytes = 0;
|
||||
let totalBytes = 0;
|
||||
const promise = new _manualPromise.ManualPromise();
|
||||
(0, _network.httpRequest)({
|
||||
url,
|
||||
headers: {
|
||||
'User-Agent': options.userAgent
|
||||
},
|
||||
timeout: options.connectionTimeout
|
||||
}, response => {
|
||||
log(`-- response status code: ${response.statusCode}`);
|
||||
if (response.statusCode !== 200) {
|
||||
let content = '';
|
||||
const handleError = () => {
|
||||
const error = new Error(`Download failed: server returned code ${response.statusCode} body '${content}'. URL: ${url}`);
|
||||
// consume response data to free up memory
|
||||
response.resume();
|
||||
promise.reject(error);
|
||||
};
|
||||
response.on('data', chunk => content += chunk).on('end', handleError).on('error', handleError);
|
||||
return;
|
||||
}
|
||||
const file = _fs.default.createWriteStream(destinationPath);
|
||||
file.on('finish', () => promise.resolve());
|
||||
file.on('error', error => promise.reject(error));
|
||||
response.pipe(file);
|
||||
totalBytes = parseInt(response.headers['content-length'] || '0', 10);
|
||||
log(`-- total bytes: ${totalBytes}`);
|
||||
response.on('data', onData);
|
||||
}, error => promise.reject(error));
|
||||
return promise;
|
||||
function onData(chunk) {
|
||||
downloadedBytes += chunk.length;
|
||||
progressCallback(downloadedBytes, totalBytes);
|
||||
}
|
||||
}
|
||||
function getDownloadProgress() {
|
||||
if (process.stdout.isTTY) return getAnimatedDownloadProgress();
|
||||
return getBasicDownloadProgress();
|
||||
}
|
||||
function getAnimatedDownloadProgress() {
|
||||
let progressBar;
|
||||
let lastDownloadedBytes = 0;
|
||||
return (downloadedBytes, totalBytes) => {
|
||||
if (!progressBar) {
|
||||
progressBar = new _utilsBundle.progress(`${toMegabytes(totalBytes)} [:bar] :percent :etas`, {
|
||||
complete: '=',
|
||||
incomplete: ' ',
|
||||
width: 20,
|
||||
total: totalBytes
|
||||
});
|
||||
}
|
||||
const delta = downloadedBytes - lastDownloadedBytes;
|
||||
lastDownloadedBytes = downloadedBytes;
|
||||
progressBar.tick(delta);
|
||||
};
|
||||
}
|
||||
function getBasicDownloadProgress() {
|
||||
// eslint-disable-next-line no-console
|
||||
const totalRows = 10;
|
||||
const stepWidth = 8;
|
||||
let lastRow = -1;
|
||||
return (downloadedBytes, totalBytes) => {
|
||||
const percentage = downloadedBytes / totalBytes;
|
||||
const row = Math.floor(totalRows * percentage);
|
||||
if (row > lastRow) {
|
||||
lastRow = row;
|
||||
const percentageString = String(percentage * 100 | 0).padStart(3);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`|${'■'.repeat(row * stepWidth)}${' '.repeat((totalRows - row) * stepWidth)}| ${percentageString}% of ${toMegabytes(totalBytes)}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
function toMegabytes(bytes) {
|
||||
const mb = bytes / 1024 / 1024;
|
||||
return `${Math.round(mb * 10) / 10} Mb`;
|
||||
}
|
||||
async function main() {
|
||||
const [url, destination, userAgent, downloadConnectionTimeout] = process.argv.slice(2);
|
||||
await downloadFile(url, destination, {
|
||||
progressCallback: getDownloadProgress(),
|
||||
userAgent,
|
||||
log: message => {
|
||||
var _process$send, _process;
|
||||
return (_process$send = (_process = process).send) === null || _process$send === void 0 ? void 0 : _process$send.call(_process, {
|
||||
method: 'log',
|
||||
params: {
|
||||
message
|
||||
}
|
||||
});
|
||||
},
|
||||
connectionTimeout: +downloadConnectionTimeout
|
||||
});
|
||||
}
|
||||
main().catch(error => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user