chore: move validateHostRequirements to Registry (#7428)

This is an effort to consolidate all handling of browser binaries in a single place.
This commit is contained in:
Dmitry Gozman 2021-07-01 16:17:59 -07:00 committed by GitHub
parent 8fb0454488
commit d46eae44d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 106 deletions

View file

@ -26,7 +26,6 @@ import { PipeTransport } from './pipeTransport';
import { Progress, ProgressController } from './progress';
import * as types from './types';
import { DEFAULT_TIMEOUT, TimeoutSettings } from '../utils/timeoutSettings';
import { validateHostRequirements } from './validateDependencies';
import { debugMode, existsAsync } from '../utils/utils';
import { helper } from './helper';
import { RecentLogsCollector } from '../utils/debugLogger';
@ -171,10 +170,9 @@ export abstract class BrowserType extends SdkObject {
}
// Only validate dependencies for downloadable browsers.
if (!executablePath && !options.channel)
await validateHostRequirements(this._registry, this._name);
else if (!executablePath && options.channel && this._registry.isSupportedBrowser(options.channel))
await validateHostRequirements(this._registry, options.channel as registry.BrowserName);
const browserName: registry.BrowserName = (options.channel || this._name) as registry.BrowserName;
if (!executablePath && this._registry.isSupportedBrowser(browserName))
await this._registry.validateHostRequirements(browserName);
let wsEndpointCallback: ((wsEndpoint: string) => void) | undefined;
const shouldWaitForWSListening = options.useWebSocket || options.args?.some(a => a.startsWith('--remote-debugging-port'));

View file

@ -1,32 +0,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.
*/
import fs from 'fs';
import path from 'path';
export function printDepsWindowsExecutable(): string | undefined {
return pathToExecutable(['bin', 'PrintDeps.exe']);
}
function pathToExecutable(relative: string[]): string | undefined {
try {
const defaultPath = path.join(__dirname, '..', '..', ...relative);
if (fs.existsSync(defaultPath))
return defaultPath;
} catch (e) {
}
}

View file

@ -18,8 +18,9 @@
import * as os from 'os';
import path from 'path';
import * as util from 'util';
import { getUbuntuVersionSync } from './ubuntuVersion';
import { assert, getFromENV } from './utils';
import { getUbuntuVersion, getUbuntuVersionSync } from './ubuntuVersion';
import { assert, getFromENV, getAsBooleanFromENV } from './utils';
import { validateDependenciesLinux, validateDependenciesWindows } from './validateDependencies';
export type BrowserName = 'chromium'|'chromium-with-symbols'|'webkit'|'firefox'|'firefox-beta'|'ffmpeg';
export const allBrowserNames: Set<BrowserName> = new Set(['chromium', 'chromium-with-symbols', 'webkit', 'firefox', 'ffmpeg', 'firefox-beta']);
@ -293,40 +294,6 @@ export class Registry {
return parseInt(browser.revision, 10);
}
linuxLddDirectories(browserName: BrowserName): string[] {
const browserDirectory = this.browserDirectory(browserName);
switch (browserName) {
case 'chromium':
case 'chromium-with-symbols':
return [path.join(browserDirectory, 'chrome-linux')];
case 'webkit':
return [
path.join(browserDirectory, 'minibrowser-gtk'),
path.join(browserDirectory, 'minibrowser-gtk', 'bin'),
path.join(browserDirectory, 'minibrowser-gtk', 'lib'),
path.join(browserDirectory, 'minibrowser-wpe'),
path.join(browserDirectory, 'minibrowser-wpe', 'bin'),
path.join(browserDirectory, 'minibrowser-wpe', 'lib'),
];
case 'firefox':
case 'firefox-beta':
return [path.join(browserDirectory, 'firefox')];
default:
return [];
}
}
windowsExeAndDllDirectories(browserName: BrowserName): string[] {
const browserDirectory = this.browserDirectory(browserName);
if (browserName === 'chromium' || browserName === 'chromium-with-symbols')
return [path.join(browserDirectory, 'chrome-win')];
if (browserName === 'firefox' || browserName === 'firefox-beta')
return [path.join(browserDirectory, 'firefox')];
if (browserName === 'webkit')
return [browserDirectory];
return [];
}
executablePath(browserName: BrowserName): string | undefined {
const browserDirectory = this.browserDirectory(browserName);
const tokens = EXECUTABLE_PATHS[browserName][hostPlatform];
@ -364,4 +331,47 @@ export class Registry {
installByDefault(): BrowserName[] {
return this._descriptors.filter(browser => browser.installByDefault).map(browser => browser.name);
}
async validateHostRequirements(browserName: BrowserName) {
if (getAsBooleanFromENV('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {
process.stdout.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');
return;
}
const ubuntuVersion = await getUbuntuVersion();
if ((browserName === 'firefox' || browserName === 'firefox-beta') && ubuntuVersion === '16.04')
throw new Error(`Cannot launch ${browserName} on Ubuntu 16.04! Minimum required Ubuntu version for Firefox browser is 18.04`);
const browserDirectory = this.browserDirectory(browserName);
if (os.platform() === 'linux') {
const dlOpenLibraries: string[] = [];
const linuxLddDirectories: string[] = [];
if (browserName === 'chromium' || browserName === 'chromium-with-symbols')
linuxLddDirectories.push(path.join(browserDirectory, 'chrome-linux'));
if (browserName === 'webkit') {
linuxLddDirectories.push(
path.join(browserDirectory, 'minibrowser-gtk'),
path.join(browserDirectory, 'minibrowser-gtk', 'bin'),
path.join(browserDirectory, 'minibrowser-gtk', 'lib'),
path.join(browserDirectory, 'minibrowser-wpe'),
path.join(browserDirectory, 'minibrowser-wpe', 'bin'),
path.join(browserDirectory, 'minibrowser-wpe', 'lib'),
);
dlOpenLibraries.push('libGLESv2.so.2', 'libx264.so');
}
if (browserName === 'firefox' || browserName === 'firefox-beta')
linuxLddDirectories.push(path.join(browserDirectory, 'firefox'));
return await validateDependenciesLinux(linuxLddDirectories, dlOpenLibraries);
}
if (os.platform() === 'win32' && os.arch() === 'x64') {
const windowsExeAndDllDirectories: string[] = [];
if (browserName === 'chromium' || browserName === 'chromium-with-symbols')
windowsExeAndDllDirectories.push(path.join(browserDirectory, 'chrome-win'));
if (browserName === 'firefox' || browserName === 'firefox-beta')
windowsExeAndDllDirectories.push(path.join(browserDirectory, 'firefox'));
if (browserName === 'webkit')
windowsExeAndDllDirectories.push(browserDirectory);
return await validateDependenciesWindows(windowsExeAndDllDirectories);
}
}
}

View file

@ -13,34 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import fs from 'fs';
import path from 'path';
import * as os from 'os';
import { getUbuntuVersion } from '../utils/ubuntuVersion';
import * as registry from '../utils/registry';
import * as utils from '../utils/utils';
import { printDepsWindowsExecutable } from '../utils/binaryPaths';
import { getUbuntuVersion } from './ubuntuVersion';
import * as utils from './utils';
const checkExecutable = (filePath: string) => fs.promises.access(filePath, fs.constants.X_OK).then(() => true).catch(e => false);
export async function validateHostRequirements(registry: registry.Registry, browserName: registry.BrowserName) {
if (utils.getAsBooleanFromENV('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {
process.stdout.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');
return;
}
const ubuntuVersion = await getUbuntuVersion();
if (browserName === 'firefox' && ubuntuVersion === '16.04')
throw new Error(`Cannot launch firefox on Ubuntu 16.04! Minimum required Ubuntu version for Firefox browser is 18.04`);
if (os.platform() === 'linux')
return await validateDependenciesLinux(registry, browserName);
if (os.platform() === 'win32' && os.arch() === 'x64')
return await validateDependenciesWindows(registry, browserName);
}
const DL_OPEN_LIBRARIES = {
'webkit': ['libGLESv2.so.2', 'libx264.so'],
};
function isSupportedWindowsVersion(): boolean {
if (os.platform() !== 'win32' || os.arch() !== 'x64')
return false;
@ -51,8 +32,8 @@ function isSupportedWindowsVersion(): boolean {
return major > 6 || (major === 6 && minor > 1);
}
async function validateDependenciesWindows(registry: registry.Registry, browserName: registry.BrowserName) {
const directoryPaths = registry.windowsExeAndDllDirectories(browserName);
export async function validateDependenciesWindows(windowsExeAndDllDirectories: string[]) {
const directoryPaths = windowsExeAndDllDirectories;
const lddPaths: string[] = [];
for (const directoryPath of directoryPaths)
lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
@ -112,8 +93,8 @@ async function validateDependenciesWindows(registry: registry.Registry, browserN
}
}
async function validateDependenciesLinux(registry: registry.Registry, browserName: registry.BrowserName) {
const directoryPaths = registry.linuxLddDirectories(browserName);
export async function validateDependenciesLinux(linuxLddDirectories: string[], dlOpenLibraries: string[]) {
const directoryPaths = linuxLddDirectories;
const lddPaths: string[] = [];
for (const directoryPath of directoryPaths)
lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
@ -123,7 +104,7 @@ async function validateDependenciesLinux(registry: registry.Registry, browserNam
for (const dep of deps)
missingDeps.add(dep);
}
for (const dep of (await missingDLOPENLibraries(browserName)))
for (const dep of (await missingDLOPENLibraries(dlOpenLibraries)))
missingDeps.add(dep);
if (!missingDeps.size)
return;
@ -202,10 +183,7 @@ async function executablesOrSharedLibraries(directoryPath: string): Promise<stri
}
async function missingFileDependenciesWindows(filePath: string): Promise<Array<string>> {
const executable = printDepsWindowsExecutable();
if (!executable)
return [];
const executable = path.join(__dirname, '..', '..', 'bin', 'PrintDeps.exe');
const dirname = path.dirname(filePath);
const {stdout, code} = await utils.spawnAsync(executable, [filePath], {
cwd: dirname,
@ -238,8 +216,7 @@ async function missingFileDependencies(filePath: string, extraLDPaths: string[])
return missingDeps;
}
async function missingDLOPENLibraries(browserName: registry.BrowserName): Promise<string[]> {
const libraries: string[] = (DL_OPEN_LIBRARIES as any)[browserName] || [];
async function missingDLOPENLibraries(libraries: string[]): Promise<string[]> {
if (!libraries.length)
return [];
// NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the