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:
parent
8fb0454488
commit
d46eae44d1
|
|
@ -26,7 +26,6 @@ import { PipeTransport } from './pipeTransport';
|
||||||
import { Progress, ProgressController } from './progress';
|
import { Progress, ProgressController } from './progress';
|
||||||
import * as types from './types';
|
import * as types from './types';
|
||||||
import { DEFAULT_TIMEOUT, TimeoutSettings } from '../utils/timeoutSettings';
|
import { DEFAULT_TIMEOUT, TimeoutSettings } from '../utils/timeoutSettings';
|
||||||
import { validateHostRequirements } from './validateDependencies';
|
|
||||||
import { debugMode, existsAsync } from '../utils/utils';
|
import { debugMode, existsAsync } from '../utils/utils';
|
||||||
import { helper } from './helper';
|
import { helper } from './helper';
|
||||||
import { RecentLogsCollector } from '../utils/debugLogger';
|
import { RecentLogsCollector } from '../utils/debugLogger';
|
||||||
|
|
@ -171,10 +170,9 @@ export abstract class BrowserType extends SdkObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only validate dependencies for downloadable browsers.
|
// Only validate dependencies for downloadable browsers.
|
||||||
if (!executablePath && !options.channel)
|
const browserName: registry.BrowserName = (options.channel || this._name) as registry.BrowserName;
|
||||||
await validateHostRequirements(this._registry, this._name);
|
if (!executablePath && this._registry.isSupportedBrowser(browserName))
|
||||||
else if (!executablePath && options.channel && this._registry.isSupportedBrowser(options.channel))
|
await this._registry.validateHostRequirements(browserName);
|
||||||
await validateHostRequirements(this._registry, options.channel as registry.BrowserName);
|
|
||||||
|
|
||||||
let wsEndpointCallback: ((wsEndpoint: string) => void) | undefined;
|
let wsEndpointCallback: ((wsEndpoint: string) => void) | undefined;
|
||||||
const shouldWaitForWSListening = options.useWebSocket || options.args?.some(a => a.startsWith('--remote-debugging-port'));
|
const shouldWaitForWSListening = options.useWebSocket || options.args?.some(a => a.startsWith('--remote-debugging-port'));
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -18,8 +18,9 @@
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as util from 'util';
|
import * as util from 'util';
|
||||||
import { getUbuntuVersionSync } from './ubuntuVersion';
|
import { getUbuntuVersion, getUbuntuVersionSync } from './ubuntuVersion';
|
||||||
import { assert, getFromENV } from './utils';
|
import { assert, getFromENV, getAsBooleanFromENV } from './utils';
|
||||||
|
import { validateDependenciesLinux, validateDependenciesWindows } from './validateDependencies';
|
||||||
|
|
||||||
export type BrowserName = 'chromium'|'chromium-with-symbols'|'webkit'|'firefox'|'firefox-beta'|'ffmpeg';
|
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']);
|
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);
|
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 {
|
executablePath(browserName: BrowserName): string | undefined {
|
||||||
const browserDirectory = this.browserDirectory(browserName);
|
const browserDirectory = this.browserDirectory(browserName);
|
||||||
const tokens = EXECUTABLE_PATHS[browserName][hostPlatform];
|
const tokens = EXECUTABLE_PATHS[browserName][hostPlatform];
|
||||||
|
|
@ -364,4 +331,47 @@ export class Registry {
|
||||||
installByDefault(): BrowserName[] {
|
installByDefault(): BrowserName[] {
|
||||||
return this._descriptors.filter(browser => browser.installByDefault).map(browser => browser.name);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,34 +13,15 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import { getUbuntuVersion } from '../utils/ubuntuVersion';
|
import { getUbuntuVersion } from './ubuntuVersion';
|
||||||
import * as registry from '../utils/registry';
|
import * as utils from './utils';
|
||||||
import * as utils from '../utils/utils';
|
|
||||||
import { printDepsWindowsExecutable } from '../utils/binaryPaths';
|
|
||||||
|
|
||||||
const checkExecutable = (filePath: string) => fs.promises.access(filePath, fs.constants.X_OK).then(() => true).catch(e => false);
|
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 {
|
function isSupportedWindowsVersion(): boolean {
|
||||||
if (os.platform() !== 'win32' || os.arch() !== 'x64')
|
if (os.platform() !== 'win32' || os.arch() !== 'x64')
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -51,8 +32,8 @@ function isSupportedWindowsVersion(): boolean {
|
||||||
return major > 6 || (major === 6 && minor > 1);
|
return major > 6 || (major === 6 && minor > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateDependenciesWindows(registry: registry.Registry, browserName: registry.BrowserName) {
|
export async function validateDependenciesWindows(windowsExeAndDllDirectories: string[]) {
|
||||||
const directoryPaths = registry.windowsExeAndDllDirectories(browserName);
|
const directoryPaths = windowsExeAndDllDirectories;
|
||||||
const lddPaths: string[] = [];
|
const lddPaths: string[] = [];
|
||||||
for (const directoryPath of directoryPaths)
|
for (const directoryPath of directoryPaths)
|
||||||
lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
|
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) {
|
export async function validateDependenciesLinux(linuxLddDirectories: string[], dlOpenLibraries: string[]) {
|
||||||
const directoryPaths = registry.linuxLddDirectories(browserName);
|
const directoryPaths = linuxLddDirectories;
|
||||||
const lddPaths: string[] = [];
|
const lddPaths: string[] = [];
|
||||||
for (const directoryPath of directoryPaths)
|
for (const directoryPath of directoryPaths)
|
||||||
lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
|
lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
|
||||||
|
|
@ -123,7 +104,7 @@ async function validateDependenciesLinux(registry: registry.Registry, browserNam
|
||||||
for (const dep of deps)
|
for (const dep of deps)
|
||||||
missingDeps.add(dep);
|
missingDeps.add(dep);
|
||||||
}
|
}
|
||||||
for (const dep of (await missingDLOPENLibraries(browserName)))
|
for (const dep of (await missingDLOPENLibraries(dlOpenLibraries)))
|
||||||
missingDeps.add(dep);
|
missingDeps.add(dep);
|
||||||
if (!missingDeps.size)
|
if (!missingDeps.size)
|
||||||
return;
|
return;
|
||||||
|
|
@ -202,10 +183,7 @@ async function executablesOrSharedLibraries(directoryPath: string): Promise<stri
|
||||||
}
|
}
|
||||||
|
|
||||||
async function missingFileDependenciesWindows(filePath: string): Promise<Array<string>> {
|
async function missingFileDependenciesWindows(filePath: string): Promise<Array<string>> {
|
||||||
const executable = printDepsWindowsExecutable();
|
const executable = path.join(__dirname, '..', '..', 'bin', 'PrintDeps.exe');
|
||||||
if (!executable)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
const dirname = path.dirname(filePath);
|
const dirname = path.dirname(filePath);
|
||||||
const {stdout, code} = await utils.spawnAsync(executable, [filePath], {
|
const {stdout, code} = await utils.spawnAsync(executable, [filePath], {
|
||||||
cwd: dirname,
|
cwd: dirname,
|
||||||
|
|
@ -238,8 +216,7 @@ async function missingFileDependencies(filePath: string, extraLDPaths: string[])
|
||||||
return missingDeps;
|
return missingDeps;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function missingDLOPENLibraries(browserName: registry.BrowserName): Promise<string[]> {
|
async function missingDLOPENLibraries(libraries: string[]): Promise<string[]> {
|
||||||
const libraries: string[] = (DL_OPEN_LIBRARIES as any)[browserName] || [];
|
|
||||||
if (!libraries.length)
|
if (!libraries.length)
|
||||||
return [];
|
return [];
|
||||||
// NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the
|
// NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the
|
||||||
Loading…
Reference in a new issue