diff --git a/src/server/browserType.ts b/src/server/browserType.ts index cf48507e39..d489d5ecfb 100644 --- a/src/server/browserType.ts +++ b/src/server/browserType.ts @@ -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')); diff --git a/src/utils/binaryPaths.ts b/src/utils/binaryPaths.ts deleted file mode 100644 index 8f4f88582e..0000000000 --- a/src/utils/binaryPaths.ts +++ /dev/null @@ -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) { - } -} - diff --git a/src/utils/registry.ts b/src/utils/registry.ts index 1594632a7a..a1a1aafdbf 100644 --- a/src/utils/registry.ts +++ b/src/utils/registry.ts @@ -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 = 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); + } + } } diff --git a/src/server/validateDependencies.ts b/src/utils/validateDependencies.ts similarity index 91% rename from src/server/validateDependencies.ts rename to src/utils/validateDependencies.ts index 6c4a0135d9..ddd702648a 100644 --- a/src/server/validateDependencies.ts +++ b/src/utils/validateDependencies.ts @@ -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> { - 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 { - const libraries: string[] = (DL_OPEN_LIBRARIES as any)[browserName] || []; +async function missingDLOPENLibraries(libraries: string[]): Promise { if (!libraries.length) return []; // NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the