mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-11 12:33:45 +03:00
chore: move working with browser channels to Registry Executables (#7581)
This commit is contained in:
parent
34777853f7
commit
0742cb9076
132
src/cli/cli.ts
132
src/cli/cli.ts
@ -32,46 +32,9 @@ import { BrowserType } from '../client/browserType';
|
||||
import { BrowserContextOptions, LaunchOptions } from '../client/types';
|
||||
import { spawn } from 'child_process';
|
||||
import { registry, Executable } from '../utils/registry';
|
||||
import * as utils from '../utils/utils';
|
||||
|
||||
const SCRIPTS_DIRECTORY = path.join(__dirname, '..', '..', 'bin');
|
||||
|
||||
|
||||
type BrowserChannel = 'chrome-beta'|'chrome'|'msedge'|'msedge-beta';
|
||||
const allBrowserChannels: Set<BrowserChannel> = new Set(['chrome-beta', 'chrome', 'msedge', 'msedge-beta']);
|
||||
const suggestedBrowsersToInstall = ['chromium', 'webkit', 'firefox', ...allBrowserChannels].map(name => `'${name}'`).join(', ');
|
||||
|
||||
const packageJSON = require('../../package.json');
|
||||
|
||||
const ChannelName = {
|
||||
'chrome-beta': 'Google Chrome Beta',
|
||||
'chrome': 'Google Chrome',
|
||||
'msedge': 'Microsoft Edge',
|
||||
'msedge-beta': 'Microsoft Edge Beta',
|
||||
};
|
||||
|
||||
const InstallationScriptName = {
|
||||
'chrome-beta': {
|
||||
'linux': 'reinstall_chrome_beta_linux.sh',
|
||||
'darwin': 'reinstall_chrome_beta_mac.sh',
|
||||
'win32': 'reinstall_chrome_beta_win.ps1',
|
||||
},
|
||||
'chrome': {
|
||||
'linux': 'reinstall_chrome_stable_linux.sh',
|
||||
'darwin': 'reinstall_chrome_stable_mac.sh',
|
||||
'win32': 'reinstall_chrome_stable_win.ps1',
|
||||
},
|
||||
'msedge': {
|
||||
'darwin': 'reinstall_msedge_stable_mac.sh',
|
||||
'win32': 'reinstall_msedge_stable_win.ps1',
|
||||
},
|
||||
'msedge-beta': {
|
||||
'darwin': 'reinstall_msedge_beta_mac.sh',
|
||||
'linux': 'reinstall_msedge_beta_linux.sh',
|
||||
'win32': 'reinstall_msedge_beta_win.ps1',
|
||||
},
|
||||
};
|
||||
|
||||
program
|
||||
.version('Version ' + packageJSON.version)
|
||||
.name(process.env.PW_CLI_NAME || 'npx playwright');
|
||||
@ -119,29 +82,36 @@ program
|
||||
console.log(' $ debug npm run test');
|
||||
});
|
||||
|
||||
function suggestedBrowsersToInstall() {
|
||||
return registry.executables().filter(e => e.installType !== 'none' && e.type !== 'tool').map(e => e.name).join(', ');
|
||||
}
|
||||
|
||||
function checkBrowsersToInstall(args: string[]) {
|
||||
const faultyArguments: string[] = [];
|
||||
const executables: Executable[] = [];
|
||||
for (const arg of args) {
|
||||
const executable = registry.findExecutable(arg);
|
||||
if (!executable || executable.installType === 'none')
|
||||
faultyArguments.push(arg);
|
||||
else
|
||||
executables.push(executable);
|
||||
}
|
||||
if (faultyArguments.length) {
|
||||
console.log(`Invalid installation targets: ${faultyArguments.map(name => `'${name}'`).join(', ')}. Expecting one of: ${suggestedBrowsersToInstall()}`);
|
||||
process.exit(1);
|
||||
}
|
||||
return executables;
|
||||
}
|
||||
|
||||
program
|
||||
.command('install [browserType...]')
|
||||
.command('install [browser...]')
|
||||
.description('ensure browsers necessary for this version of Playwright are installed')
|
||||
.action(async function(args: any[]) {
|
||||
.action(async function(args: string[]) {
|
||||
try {
|
||||
// Install default browsers when invoked without arguments.
|
||||
if (!args.length) {
|
||||
if (!args.length)
|
||||
await registry.install();
|
||||
return;
|
||||
}
|
||||
const binaries = args.map(arg => registry.findExecutable(arg)).filter(b => !!b) as Executable[];
|
||||
const browserChannels: Set<BrowserChannel> = new Set(args.filter(browser => allBrowserChannels.has(browser)));
|
||||
const faultyArguments: string[] = args.filter((browser: any) => !binaries.find(b => b.name === browser) && !browserChannels.has(browser));
|
||||
if (faultyArguments.length) {
|
||||
console.log(`Invalid installation targets: ${faultyArguments.map(name => `'${name}'`).join(', ')}. Expecting one of: ${suggestedBrowsersToInstall}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (browserChannels.has('chrome-beta') || browserChannels.has('chrome') || browserChannels.has('msedge') || browserChannels.has('msedge-beta'))
|
||||
binaries.push(registry.findExecutable('ffmpeg')!);
|
||||
if (binaries.length)
|
||||
await registry.install(binaries);
|
||||
for (const browserChannel of browserChannels)
|
||||
await installBrowserChannel(browserChannel);
|
||||
else
|
||||
await registry.install(checkBrowsersToInstall(args));
|
||||
} catch (e) {
|
||||
console.log(`Failed to install browsers\n${e}`);
|
||||
process.exit(1);
|
||||
@ -153,51 +123,31 @@ program
|
||||
console.log(` Install default browsers.`);
|
||||
console.log(``);
|
||||
console.log(` - $ install chrome firefox`);
|
||||
console.log(` Install custom browsers, supports ${suggestedBrowsersToInstall}.`);
|
||||
console.log(` Install custom browsers, supports ${suggestedBrowsersToInstall()}.`);
|
||||
});
|
||||
|
||||
async function installBrowserChannel(channel: BrowserChannel) {
|
||||
const platform = os.platform();
|
||||
const scriptName: (string|undefined) = (InstallationScriptName[channel] as any)[platform];
|
||||
if (!scriptName)
|
||||
throw new Error(`Cannot install ${ChannelName[channel]} on ${platform}`);
|
||||
|
||||
const scriptArgs = [];
|
||||
if ((channel === 'msedge' || channel === 'msedge-beta') && platform !== 'linux') {
|
||||
const products = JSON.parse(await utils.fetchData('https://edgeupdates.microsoft.com/api/products'));
|
||||
const productName = channel === 'msedge' ? 'Stable' : 'Beta';
|
||||
const product = products.find((product: any) => product.Product === productName);
|
||||
const searchConfig = ({
|
||||
darwin: {platform: 'MacOS', arch: 'universal', artifact: 'pkg'},
|
||||
win32: {platform: 'Windows', arch: os.arch() === 'x64' ? 'x64' : 'x86', artifact: 'msi'},
|
||||
} as any)[platform];
|
||||
const release = searchConfig ? product.Releases.find((release: any) => release.Platform === searchConfig.platform && release.Architecture === searchConfig.arch) : null;
|
||||
const artifact = release ? release.Artifacts.find((artifact: any) => artifact.ArtifactName === searchConfig.artifact) : null;
|
||||
if (artifact)
|
||||
scriptArgs.push(artifact.Location /* url */);
|
||||
else
|
||||
throw new Error(`Cannot install ${ChannelName[channel]} on ${platform}`);
|
||||
}
|
||||
|
||||
const shell = scriptName.endsWith('.ps1') ? 'powershell.exe' : 'bash';
|
||||
const {code} = await utils.spawnAsync(shell, [path.join(SCRIPTS_DIRECTORY, scriptName), ...scriptArgs], { cwd: SCRIPTS_DIRECTORY, stdio: 'inherit' });
|
||||
if (code !== 0)
|
||||
throw new Error(`Failed to install ${ChannelName[channel]}`);
|
||||
}
|
||||
|
||||
program
|
||||
.command('install-deps [browserType...]')
|
||||
.command('install-deps [browser...]')
|
||||
.description('install dependencies necessary to run browsers (will ask for sudo permissions)')
|
||||
.action(async function(browserTypes: string[]) {
|
||||
.action(async function(args: string[]) {
|
||||
try {
|
||||
// TODO: verify the list and print supported browserTypes in the error message.
|
||||
const binaries = browserTypes.map(arg => registry.findExecutable(arg)).filter(b => !!b) as Executable[];
|
||||
// When passed no arguments, assume default browsers.
|
||||
await registry.installDeps(browserTypes.length ? binaries : undefined);
|
||||
if (!args.length)
|
||||
await registry.installDeps();
|
||||
else
|
||||
await registry.installDeps(checkBrowsersToInstall(args));
|
||||
} catch (e) {
|
||||
console.log(`Failed to install browser dependencies\n${e}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}).on('--help', function() {
|
||||
console.log(``);
|
||||
console.log(`Examples:`);
|
||||
console.log(` - $ install-deps`);
|
||||
console.log(` Install dependecies fro default browsers.`);
|
||||
console.log(``);
|
||||
console.log(` - $ install-deps chrome firefox`);
|
||||
console.log(` Install dependencies for specific browsers, supports ${suggestedBrowsersToInstall()}.`);
|
||||
});
|
||||
|
||||
const browsers = [
|
||||
|
@ -44,8 +44,8 @@ export abstract class BrowserType extends SdkObject {
|
||||
this._name = browserName;
|
||||
}
|
||||
|
||||
executablePath(channel?: string): string {
|
||||
return registry.findExecutable(this._name).maybeExecutablePath() || '';
|
||||
executablePath(): string {
|
||||
return registry.findExecutable(this._name).executablePath() || '';
|
||||
}
|
||||
|
||||
name(): string {
|
||||
@ -156,21 +156,19 @@ export abstract class BrowserType extends SdkObject {
|
||||
else
|
||||
browserArguments.push(...this._defaultArgs(options, isPersistent, userDataDir));
|
||||
|
||||
const executable = executablePath || this.executablePath(options.channel);
|
||||
if (!executable)
|
||||
throw new Error(`No executable path is specified. Pass "executablePath" option directly.`);
|
||||
if (!(await existsAsync(executable))) {
|
||||
const errorMessageLines = [`Failed to launch ${this._name} because executable doesn't exist at ${executable}`];
|
||||
// If we tried using stock downloaded browser, suggest re-installing playwright.
|
||||
if (!executablePath)
|
||||
errorMessageLines.push(`Run "npx playwright install" to install browsers`);
|
||||
throw new Error(errorMessageLines.join('\n'));
|
||||
let executable: string;
|
||||
if (executablePath) {
|
||||
if (!(await existsAsync(executablePath)))
|
||||
throw new Error(`Failed to launch ${this._name} because executable doesn't exist at ${executablePath}`);
|
||||
executable = executablePath;
|
||||
} else {
|
||||
const registryExecutable = registry.findExecutable(options.channel || this._name);
|
||||
if (!registryExecutable || registryExecutable.browserName !== this._name)
|
||||
throw new Error(`Unsupported ${this._name} channel "${options.channel}"`);
|
||||
executable = registryExecutable.executablePathOrDie();
|
||||
await registryExecutable.validateHostRequirements();
|
||||
}
|
||||
|
||||
// Do not validate dependencies for custom binaries.
|
||||
if (!executablePath && !options.channel)
|
||||
await registry.findExecutable(this._name).validateHostRequirements();
|
||||
|
||||
let wsEndpointCallback: ((wsEndpoint: string) => void) | undefined;
|
||||
const shouldWaitForWSListening = options.useWebSocket || options.args?.some(a => a.startsWith('--remote-debugging-port'));
|
||||
const waitForWSEndpoint = shouldWaitForWSListening ? new Promise<string>(f => wsEndpointCallback = f) : undefined;
|
||||
|
@ -27,13 +27,12 @@ import { ConnectionTransport, ProtocolRequest, WebSocketTransport } from '../tra
|
||||
import { CRDevTools } from './crDevTools';
|
||||
import { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
|
||||
import * as types from '../types';
|
||||
import { assert, debugMode, headersArrayToObject, removeFolders } from '../../utils/utils';
|
||||
import { debugMode, headersArrayToObject, removeFolders } from '../../utils/utils';
|
||||
import { RecentLogsCollector } from '../../utils/debugLogger';
|
||||
import { ProgressController } from '../progress';
|
||||
import { TimeoutSettings } from '../../utils/timeoutSettings';
|
||||
import { helper } from '../helper';
|
||||
import { CallMetadata } from '../instrumentation';
|
||||
import { findChromiumChannel } from './findChromiumChannel';
|
||||
import http from 'http';
|
||||
import { registry } from '../../utils/registry';
|
||||
|
||||
@ -49,20 +48,6 @@ export class Chromium extends BrowserType {
|
||||
this._devtools = this._createDevTools();
|
||||
}
|
||||
|
||||
executablePath(channel?: string): string {
|
||||
if (channel) {
|
||||
let executablePath = undefined;
|
||||
if ((channel as any) === 'chromium-with-symbols')
|
||||
executablePath = registry.findExecutable('chromium-with-symbols')!.executablePathIfExists();
|
||||
else
|
||||
executablePath = findChromiumChannel(channel);
|
||||
assert(executablePath, `unsupported chromium channel "${channel}"`);
|
||||
assert(fs.existsSync(executablePath), `"${channel}" channel is not installed. Try running 'npx playwright install ${channel}'`);
|
||||
return executablePath;
|
||||
}
|
||||
return super.executablePath(channel);
|
||||
}
|
||||
|
||||
async connectOverCDP(metadata: CallMetadata, endpointURL: string, options: { slowMo?: number, sdkLanguage: string, headers?: types.HeadersArray }, timeout?: number) {
|
||||
const controller = new ProgressController(metadata, this);
|
||||
controller.setLogName('browser');
|
||||
@ -104,7 +89,7 @@ export class Chromium extends BrowserType {
|
||||
|
||||
private _createDevTools() {
|
||||
// TODO: this is totally wrong when using channels.
|
||||
const directory = registry.findExecutable('chromium').directoryIfExists();
|
||||
const directory = registry.findExecutable('chromium').directory;
|
||||
return directory ? new CRDevTools(path.join(directory, 'devtools-preferences.json')) : undefined;
|
||||
}
|
||||
|
||||
|
@ -845,10 +845,9 @@ class FrameSession {
|
||||
|
||||
async _createVideoRecorder(screencastId: string, options: types.PageScreencastOptions): Promise<void> {
|
||||
assert(!this._screencastId);
|
||||
const ffmpegPath = registry.findExecutable('ffmpeg')!.executablePathIfExists();
|
||||
if (!ffmpegPath)
|
||||
throw new Error('ffmpeg executable was not found');
|
||||
if (!canAccessFile(ffmpegPath)) {
|
||||
const ffmpegPath = registry.findExecutable('ffmpeg')!.executablePath();
|
||||
// TODO: use default error message once it's ready.
|
||||
if (!ffmpegPath || !canAccessFile(ffmpegPath)) {
|
||||
let message: string = '';
|
||||
switch (this._page._browserContext._options.sdkLanguage) {
|
||||
case 'python': message = 'playwright install ffmpeg'; break;
|
||||
|
@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* 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 path from 'path';
|
||||
import { canAccessFile } from '../../utils/utils';
|
||||
|
||||
function darwin(channel: string): string[] | undefined {
|
||||
switch (channel) {
|
||||
case 'chrome': return ['/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'];
|
||||
case 'chrome-beta': return ['/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta'];
|
||||
case 'chrome-dev': return ['/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev'];
|
||||
case 'chrome-canary': return ['/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'];
|
||||
case 'msedge': return ['/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'];
|
||||
case 'msedge-beta': return ['/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta'];
|
||||
case 'msedge-dev': return ['/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev'];
|
||||
case 'msedge-canary': return ['/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary'];
|
||||
}
|
||||
}
|
||||
|
||||
function linux(channel: string): string[] | undefined {
|
||||
switch (channel) {
|
||||
case 'chrome': return ['/opt/google/chrome/chrome'];
|
||||
case 'chrome-beta': return ['/opt/google/chrome-beta/chrome'];
|
||||
case 'chrome-dev': return ['/opt/google/chrome-unstable/chrome'];
|
||||
case 'msedge-dev': return ['/opt/microsoft/msedge-dev/msedge'];
|
||||
case 'msedge-beta': return ['/opt/microsoft/msedge-beta/msedge'];
|
||||
}
|
||||
}
|
||||
|
||||
function win32(channel: string): string[] | undefined {
|
||||
let suffix: string | undefined;
|
||||
switch (channel) {
|
||||
case 'chrome': suffix = `\\Google\\Chrome\\Application\\chrome.exe`; break;
|
||||
case 'chrome-beta': suffix = `\\Google\\Chrome Beta\\Application\\chrome.exe`; break;
|
||||
case 'chrome-dev': suffix = `\\Google\\Chrome Dev\\Application\\chrome.exe`; break;
|
||||
case 'chrome-canary': suffix = `\\Google\\Chrome SxS\\Application\\chrome.exe`; break;
|
||||
case 'msedge': suffix = `\\Microsoft\\Edge\\Application\\msedge.exe`; break;
|
||||
case 'msedge-beta': suffix = `\\Microsoft\\Edge Beta\\Application\\msedge.exe`; break;
|
||||
case 'msedge-dev': suffix = `\\Microsoft\\Edge Dev\\Application\\msedge.exe`; break;
|
||||
case 'msedge-canary': suffix = `\\Microsoft\\Edge SxS\\Application\\msedge.exe`; break;
|
||||
}
|
||||
if (!suffix)
|
||||
return;
|
||||
const prefixes = [
|
||||
process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']
|
||||
].filter(Boolean) as string[];
|
||||
return prefixes.map(prefix => path.join(prefix, suffix!));
|
||||
}
|
||||
|
||||
export function findChromiumChannel(channel: string): string {
|
||||
let installationPaths: string[] | undefined;
|
||||
if (process.platform === 'linux')
|
||||
installationPaths = linux(channel);
|
||||
else if (process.platform === 'win32')
|
||||
installationPaths = win32(channel);
|
||||
else if (process.platform === 'darwin')
|
||||
installationPaths = darwin(channel);
|
||||
|
||||
if (!installationPaths)
|
||||
throw new Error(`Chromium distribution '${channel}' is not supported on ${process.platform}`);
|
||||
|
||||
let result: string | undefined;
|
||||
installationPaths.forEach(chromePath => {
|
||||
if (canAccessFile(chromePath))
|
||||
result = chromePath;
|
||||
});
|
||||
if (result)
|
||||
return result;
|
||||
throw new Error(`Chromium distribution is not installed on the system: ${channel}`);
|
||||
}
|
@ -18,7 +18,6 @@
|
||||
import * as os from 'os';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { assert } from '../../utils/utils';
|
||||
import { FFBrowser } from './ffBrowser';
|
||||
import { kBrowserCloseMessageId } from './ffConnection';
|
||||
import { BrowserType } from '../browserType';
|
||||
@ -26,25 +25,12 @@ import { Env } from '../../utils/processLauncher';
|
||||
import { ConnectionTransport } from '../transport';
|
||||
import { BrowserOptions, PlaywrightOptions } from '../browser';
|
||||
import * as types from '../types';
|
||||
import { registry } from '../../utils/registry';
|
||||
|
||||
export class Firefox extends BrowserType {
|
||||
constructor(playwrightOptions: PlaywrightOptions) {
|
||||
super('firefox', playwrightOptions);
|
||||
}
|
||||
|
||||
executablePath(channel?: string): string {
|
||||
if (channel) {
|
||||
let executablePath = undefined;
|
||||
if ((channel as any) === 'firefox-beta')
|
||||
executablePath = registry.findExecutable('firefox-beta')!.executablePathIfExists();
|
||||
assert(executablePath, `unsupported firefox channel "${channel}"`);
|
||||
assert(fs.existsSync(executablePath), `"${channel}" channel is not installed. Try running 'npx playwright install ${channel}'`);
|
||||
return executablePath;
|
||||
}
|
||||
return super.executablePath(channel);
|
||||
}
|
||||
|
||||
_connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<FFBrowser> {
|
||||
return FFBrowser.connect(transport, options);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import { EventEmitter } from 'events';
|
||||
import { internalCallMetadata } from '../../instrumentation';
|
||||
import type { CallLog, EventData, Mode, Source } from './recorderTypes';
|
||||
import { BrowserContext } from '../../browserContext';
|
||||
import { existsAsync, isUnderTest } from '../../../utils/utils';
|
||||
import { isUnderTest } from '../../../utils/utils';
|
||||
import { installAppIcon } from '../../chromium/crApp';
|
||||
|
||||
declare global {
|
||||
@ -97,8 +97,7 @@ export class RecorderApp extends EventEmitter {
|
||||
let executablePath: string | undefined;
|
||||
if (inspectedContext._browser.options.isChromium) {
|
||||
channel = inspectedContext._browser.options.channel;
|
||||
const defaultExecutablePath = recorderPlaywright.chromium.executablePath(channel);
|
||||
if (!(await existsAsync(defaultExecutablePath)))
|
||||
if (!channel)
|
||||
executablePath = inspectedContext._browser.options.customExecutablePath;
|
||||
}
|
||||
const context = await recorderPlaywright.chromium.launchPersistentContext(internalCallMetadata(), '', {
|
||||
|
@ -30,7 +30,6 @@ import { internalCallMetadata } from '../../instrumentation';
|
||||
import { ProgressController } from '../../progress';
|
||||
import { BrowserContext } from '../../browserContext';
|
||||
import { registry } from '../../../utils/registry';
|
||||
import { findChromiumChannel } from '../../chromium/findChromiumChannel';
|
||||
import { installAppIcon } from '../../chromium/crApp';
|
||||
|
||||
export class TraceViewer {
|
||||
@ -140,21 +139,17 @@ export class TraceViewer {
|
||||
// Null means no installation and no channels found.
|
||||
let channel = null;
|
||||
if (traceViewerBrowser === 'chromium') {
|
||||
if (registry.findExecutable('chromium').executablePathIfExists()) {
|
||||
// This means we have a browser downloaded.
|
||||
channel = undefined;
|
||||
} else {
|
||||
for (const c of ['chrome', 'msedge']) {
|
||||
try {
|
||||
findChromiumChannel(c);
|
||||
channel = c;
|
||||
break;
|
||||
} catch (e) {
|
||||
}
|
||||
for (const name of ['chromium', 'chrome', 'msedge']) {
|
||||
try {
|
||||
registry.findExecutable(name)!.executablePathOrDie();
|
||||
channel = name === 'chromium' ? undefined : name;
|
||||
break;
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (channel === null) {
|
||||
// TODO: language-specific error message, or fallback to default error.
|
||||
throw new Error(`
|
||||
==================================================================
|
||||
Please run 'npx playwright install' to install Playwright browsers
|
||||
|
@ -35,7 +35,9 @@ function isSupportedWindowsVersion(): boolean {
|
||||
return major > 6 || (major === 6 && minor > 1);
|
||||
}
|
||||
|
||||
export async function installDependenciesWindows(targets: Set<'chromium' | 'firefox' | 'webkit' | 'tools'>) {
|
||||
export type DependencyGroup = 'chromium' | 'firefox' | 'webkit' | 'tools';
|
||||
|
||||
export async function installDependenciesWindows(targets: Set<DependencyGroup>) {
|
||||
if (targets.has('chromium')) {
|
||||
const {code} = await utils.spawnAsync('powershell.exe', [path.join(BIN_DIRECTORY, 'install_media_pack.ps1')], { cwd: BIN_DIRECTORY, stdio: 'inherit' });
|
||||
if (code !== 0)
|
||||
@ -43,7 +45,7 @@ export async function installDependenciesWindows(targets: Set<'chromium' | 'fire
|
||||
}
|
||||
}
|
||||
|
||||
export async function installDependenciesLinux(targets: Set<'chromium' | 'firefox' | 'webkit' | 'tools'>) {
|
||||
export async function installDependenciesLinux(targets: Set<DependencyGroup>) {
|
||||
const ubuntuVersion = await getUbuntuVersion();
|
||||
if (ubuntuVersion !== '18.04' && ubuntuVersion !== '20.04' && ubuntuVersion !== '21.04') {
|
||||
console.warn('Cannot install dependencies for this linux distribution!'); // eslint-disable-line no-console
|
||||
|
@ -21,11 +21,12 @@ import * as util from 'util';
|
||||
import * as fs from 'fs';
|
||||
import lockfile from 'proper-lockfile';
|
||||
import { getUbuntuVersion } from './ubuntuVersion';
|
||||
import { getFromENV, getAsBooleanFromENV, calculateSha1, removeFolders, existsAsync, hostPlatform, canAccessFile } from './utils';
|
||||
import { installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies';
|
||||
import { getFromENV, getAsBooleanFromENV, calculateSha1, removeFolders, existsAsync, hostPlatform, canAccessFile, spawnAsync, fetchData } from './utils';
|
||||
import { DependencyGroup, installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies';
|
||||
import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher';
|
||||
|
||||
const PACKAGE_PATH = path.join(__dirname, '..', '..');
|
||||
const BIN_PATH = path.join(__dirname, '..', '..', 'bin');
|
||||
|
||||
const EXECUTABLE_PATHS = {
|
||||
'chromium': {
|
||||
@ -215,21 +216,23 @@ function readDescriptors(packagePath: string) {
|
||||
|
||||
export type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
||||
type InternalTool = 'ffmpeg' | 'firefox-beta' | 'chromium-with-symbols';
|
||||
type ChromiumChannel = 'chrome' | 'chrome-beta' | 'chrome-dev' | 'chrome-canary' | 'msedge' | 'msedge-beta' | 'msedge-dev' | 'msedge-canary';
|
||||
const allDownloadable = ['chromium', 'firefox', 'webkit', 'ffmpeg', 'firefox-beta', 'chromium-with-symbols'];
|
||||
|
||||
export interface Executable {
|
||||
type: 'browser' | 'tool';
|
||||
name: BrowserName | InternalTool;
|
||||
type: 'browser' | 'tool' | 'channel';
|
||||
name: BrowserName | InternalTool | ChromiumChannel;
|
||||
browserName: BrowserName | undefined;
|
||||
installType: 'download-by-default' | 'download-on-demand';
|
||||
maybeExecutablePath(): string | undefined;
|
||||
executablePathIfExists(): string | undefined;
|
||||
directoryIfExists(): string | undefined;
|
||||
installType: 'download-by-default' | 'download-on-demand' | 'install-script' | 'none';
|
||||
directory: string | undefined;
|
||||
executablePathOrDie(): string;
|
||||
executablePath(): string | undefined;
|
||||
validateHostRequirements(): Promise<void>;
|
||||
}
|
||||
|
||||
interface ExecutableImpl extends Executable {
|
||||
_download?: () => Promise<void>;
|
||||
_install?: () => Promise<void>;
|
||||
_dependencyGroup?: DependencyGroup;
|
||||
}
|
||||
|
||||
export class Registry {
|
||||
@ -237,72 +240,146 @@ export class Registry {
|
||||
|
||||
constructor(packagePath: string) {
|
||||
const descriptors = readDescriptors(packagePath);
|
||||
const executablePath = (dir: string, name: keyof typeof EXECUTABLE_PATHS) => {
|
||||
const findExecutablePath = (dir: string, name: keyof typeof EXECUTABLE_PATHS) => {
|
||||
const tokens = EXECUTABLE_PATHS[name][hostPlatform];
|
||||
return tokens ? path.join(dir, ...tokens) : undefined;
|
||||
};
|
||||
const directoryIfExists = (d: string) => fs.existsSync(d) ? d : undefined;
|
||||
const executablePathIfExists = (e: string | undefined) => e && canAccessFile(e) ? e : undefined;
|
||||
const executablePathOrDie = (name: string, e: string | undefined) => {
|
||||
if (!e)
|
||||
throw new Error(`${name} is not supported on ${hostPlatform}`);
|
||||
// TODO: language-specific error message
|
||||
if (!canAccessFile(e))
|
||||
throw new Error(`Executable doesn't exist at ${e}\nRun "npx playwright install ${name}"`);
|
||||
return e;
|
||||
};
|
||||
this._executables = [];
|
||||
|
||||
const chromium = descriptors.find(d => d.name === 'chromium')!;
|
||||
const chromiumExecutable = executablePath(chromium.dir, 'chromium');
|
||||
const chromiumExecutable = findExecutablePath(chromium.dir, 'chromium');
|
||||
this._executables.push({
|
||||
type: 'browser',
|
||||
name: 'chromium',
|
||||
browserName: 'chromium',
|
||||
directoryIfExists: () => directoryIfExists(chromium.dir),
|
||||
maybeExecutablePath: () => chromiumExecutable,
|
||||
executablePathIfExists: () => executablePathIfExists(chromiumExecutable),
|
||||
directory: chromium.dir,
|
||||
executablePath: () => chromiumExecutable,
|
||||
executablePathOrDie: () => executablePathOrDie('chromium', chromiumExecutable),
|
||||
installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: () => this._validateHostRequirements('chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),
|
||||
_download: () => this._downloadExecutable(chromium, chromiumExecutable, DOWNLOAD_URLS['chromium'][hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),
|
||||
_install: () => this._downloadExecutable(chromium, chromiumExecutable, DOWNLOAD_URLS['chromium'][hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),
|
||||
_dependencyGroup: 'chromium',
|
||||
});
|
||||
|
||||
const chromiumWithSymbols = descriptors.find(d => d.name === 'chromium-with-symbols')!;
|
||||
const chromiumWithSymbolsExecutable = executablePath(chromiumWithSymbols.dir, 'chromium');
|
||||
const chromiumWithSymbolsExecutable = findExecutablePath(chromiumWithSymbols.dir, 'chromium');
|
||||
this._executables.push({
|
||||
type: 'tool',
|
||||
name: 'chromium-with-symbols',
|
||||
browserName: 'chromium',
|
||||
directoryIfExists: () => directoryIfExists(chromiumWithSymbols.dir),
|
||||
maybeExecutablePath: () => chromiumWithSymbolsExecutable,
|
||||
executablePathIfExists: () => executablePathIfExists(chromiumWithSymbolsExecutable),
|
||||
directory: chromiumWithSymbols.dir,
|
||||
executablePath: () => chromiumWithSymbolsExecutable,
|
||||
executablePathOrDie: () => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable),
|
||||
installType: chromiumWithSymbols.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: () => this._validateHostRequirements('chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']),
|
||||
_download: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable, DOWNLOAD_URLS['chromium-with-symbols'][hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),
|
||||
_install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable, DOWNLOAD_URLS['chromium-with-symbols'][hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),
|
||||
_dependencyGroup: 'chromium',
|
||||
});
|
||||
|
||||
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': '',
|
||||
'darwin': '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
||||
'win32': `\\Microsoft\\Edge\\Application\\msedge.exe`,
|
||||
}, () => this._installMSEdgeChannel('msedge', {
|
||||
'linux': '',
|
||||
'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._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 = executablePath(firefox.dir, 'firefox');
|
||||
const firefoxExecutable = findExecutablePath(firefox.dir, 'firefox');
|
||||
this._executables.push({
|
||||
type: 'browser',
|
||||
name: 'firefox',
|
||||
browserName: 'firefox',
|
||||
directoryIfExists: () => directoryIfExists(firefox.dir),
|
||||
maybeExecutablePath: () => firefoxExecutable,
|
||||
executablePathIfExists: () => executablePathIfExists(firefoxExecutable),
|
||||
directory: firefox.dir,
|
||||
executablePath: () => firefoxExecutable,
|
||||
executablePathOrDie: () => executablePathOrDie('firefox', firefoxExecutable),
|
||||
installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: () => this._validateHostRequirements('firefox', firefox.dir, ['firefox'], [], ['firefox']),
|
||||
_download: () => this._downloadExecutable(firefox, firefoxExecutable, DOWNLOAD_URLS['firefox'][hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),
|
||||
_install: () => this._downloadExecutable(firefox, firefoxExecutable, DOWNLOAD_URLS['firefox'][hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),
|
||||
_dependencyGroup: 'firefox',
|
||||
});
|
||||
|
||||
const firefoxBeta = descriptors.find(d => d.name === 'firefox-beta')!;
|
||||
const firefoxBetaExecutable = executablePath(firefoxBeta.dir, 'firefox');
|
||||
const firefoxBetaExecutable = findExecutablePath(firefoxBeta.dir, 'firefox');
|
||||
this._executables.push({
|
||||
type: 'tool',
|
||||
name: 'firefox-beta',
|
||||
browserName: 'firefox',
|
||||
directoryIfExists: () => directoryIfExists(firefoxBeta.dir),
|
||||
maybeExecutablePath: () => firefoxBetaExecutable,
|
||||
executablePathIfExists: () => executablePathIfExists(firefoxBetaExecutable),
|
||||
directory: firefoxBeta.dir,
|
||||
executablePath: () => firefoxBetaExecutable,
|
||||
executablePathOrDie: () => executablePathOrDie('firefox-beta', firefoxBetaExecutable),
|
||||
installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: () => this._validateHostRequirements('firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),
|
||||
_download: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable, DOWNLOAD_URLS['firefox-beta'][hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),
|
||||
_install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable, DOWNLOAD_URLS['firefox-beta'][hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),
|
||||
_dependencyGroup: 'firefox',
|
||||
});
|
||||
|
||||
const webkit = descriptors.find(d => d.name === 'webkit')!;
|
||||
const webkitExecutable = executablePath(webkit.dir, 'webkit');
|
||||
const webkitExecutable = findExecutablePath(webkit.dir, 'webkit');
|
||||
const webkitLinuxLddDirectories = [
|
||||
path.join('minibrowser-gtk'),
|
||||
path.join('minibrowser-gtk', 'bin'),
|
||||
@ -315,29 +392,73 @@ export class Registry {
|
||||
type: 'browser',
|
||||
name: 'webkit',
|
||||
browserName: 'webkit',
|
||||
directoryIfExists: () => directoryIfExists(webkit.dir),
|
||||
maybeExecutablePath: () => webkitExecutable,
|
||||
executablePathIfExists: () => executablePathIfExists(webkitExecutable),
|
||||
directory: webkit.dir,
|
||||
executablePath: () => webkitExecutable,
|
||||
executablePathOrDie: () => executablePathOrDie('webkit', webkitExecutable),
|
||||
installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: () => this._validateHostRequirements('webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),
|
||||
_download: () => this._downloadExecutable(webkit, webkitExecutable, DOWNLOAD_URLS['webkit'][hostPlatform], 'PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST'),
|
||||
_install: () => this._downloadExecutable(webkit, webkitExecutable, DOWNLOAD_URLS['webkit'][hostPlatform], 'PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST'),
|
||||
_dependencyGroup: 'webkit',
|
||||
});
|
||||
|
||||
const ffmpeg = descriptors.find(d => d.name === 'ffmpeg')!;
|
||||
const ffmpegExecutable = executablePath(ffmpeg.dir, 'ffmpeg');
|
||||
const ffmpegExecutable = findExecutablePath(ffmpeg.dir, 'ffmpeg');
|
||||
this._executables.push({
|
||||
type: 'tool',
|
||||
name: 'ffmpeg',
|
||||
browserName: undefined,
|
||||
directoryIfExists: () => directoryIfExists(ffmpeg.dir),
|
||||
maybeExecutablePath: () => ffmpegExecutable,
|
||||
executablePathIfExists: () => executablePathIfExists(ffmpegExecutable),
|
||||
directory: ffmpeg.dir,
|
||||
executablePath: () => ffmpegExecutable,
|
||||
executablePathOrDie: () => executablePathOrDie('ffmpeg', ffmpegExecutable),
|
||||
installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||
validateHostRequirements: () => Promise.resolve(),
|
||||
_download: () => this._downloadExecutable(ffmpeg, ffmpegExecutable, DOWNLOAD_URLS['ffmpeg'][hostPlatform], 'PLAYWRIGHT_FFMPEG_DOWNLOAD_HOST'),
|
||||
_install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable, DOWNLOAD_URLS['ffmpeg'][hostPlatform], 'PLAYWRIGHT_FFMPEG_DOWNLOAD_HOST'),
|
||||
_dependencyGroup: 'tools',
|
||||
});
|
||||
}
|
||||
|
||||
private _createChromiumChannel(name: ChromiumChannel, lookAt: Record<'linux' | 'darwin' | 'win32', string>, install?: () => Promise<void>): ExecutableImpl {
|
||||
const executablePath = (shouldThrow: boolean) => {
|
||||
const suffix = lookAt[process.platform as 'linux' | 'darwin' | 'win32'];
|
||||
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) : ['']) as string[];
|
||||
|
||||
for (const prefix of prefixes) {
|
||||
const executablePath = path.join(prefix, suffix);
|
||||
if (canAccessFile(executablePath))
|
||||
return executablePath;
|
||||
}
|
||||
if (!shouldThrow)
|
||||
return undefined;
|
||||
|
||||
const location = prefixes.length ? ` at ${path.join(prefixes[0], suffix)}` : ``;
|
||||
// TODO: language-specific error message
|
||||
const installation = install ? `\nRun "npx playwright install ${name}"` : '';
|
||||
throw new Error(`Chromium distribution '${name}' is not found${location}${installation}`);
|
||||
};
|
||||
return {
|
||||
type: 'channel',
|
||||
name,
|
||||
browserName: 'chromium',
|
||||
directory: undefined,
|
||||
executablePath: () => executablePath(false),
|
||||
executablePathOrDie: () => executablePath(true)!,
|
||||
installType: install ? 'install-script' : 'none',
|
||||
validateHostRequirements: () => Promise.resolve(),
|
||||
_install: install,
|
||||
};
|
||||
}
|
||||
|
||||
executables(): Executable[] {
|
||||
return this._executables;
|
||||
}
|
||||
|
||||
findExecutable(name: BrowserName): Executable;
|
||||
findExecutable(name: string): Executable | undefined;
|
||||
findExecutable(name: string): Executable | undefined {
|
||||
@ -373,10 +494,10 @@ export class Registry {
|
||||
|
||||
async installDeps(executablesToInstallDeps?: Executable[]) {
|
||||
const executables = this._addRequirementsAndDedupe(executablesToInstallDeps);
|
||||
const targets = new Set<'chromium' | 'firefox' | 'webkit' | 'tools'>();
|
||||
const targets = new Set<DependencyGroup>();
|
||||
for (const executable of executables) {
|
||||
if (executable.browserName)
|
||||
targets.add(executable.browserName);
|
||||
if (executable._dependencyGroup)
|
||||
targets.add(executable._dependencyGroup);
|
||||
}
|
||||
targets.add('tools');
|
||||
if (os.platform() === 'win32')
|
||||
@ -414,8 +535,8 @@ export class Registry {
|
||||
|
||||
// Install browsers for this package.
|
||||
for (const executable of executables) {
|
||||
if (executable._download)
|
||||
await executable._download();
|
||||
if (executable._install)
|
||||
await executable._install();
|
||||
else
|
||||
throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);
|
||||
}
|
||||
@ -440,6 +561,36 @@ export class Registry {
|
||||
await fs.promises.writeFile(markerFilePath(descriptor.dir), '');
|
||||
}
|
||||
|
||||
private async _installMSEdgeChannel(channel: string, scripts: Record<'linux' | 'darwin' | 'win32', string>) {
|
||||
const scriptArgs: string[] = [];
|
||||
if (process.platform !== 'linux') {
|
||||
const products = JSON.parse(await fetchData('https://edgeupdates.microsoft.com/api/products'));
|
||||
const productName = channel === 'msedge' ? 'Stable' : 'Beta';
|
||||
const product = products.find((product: any) => product.Product === productName);
|
||||
const searchConfig = ({
|
||||
darwin: {platform: 'MacOS', arch: 'universal', artifact: 'pkg'},
|
||||
win32: {platform: 'Windows', arch: os.arch() === 'x64' ? 'x64' : 'x86', artifact: 'msi'},
|
||||
} as any)[process.platform];
|
||||
const release = searchConfig ? product.Releases.find((release: any) => release.Platform === searchConfig.platform && release.Architecture === searchConfig.arch) : null;
|
||||
const artifact = release ? release.Artifacts.find((artifact: any) => 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);
|
||||
}
|
||||
|
||||
private async _installChromiumChannel(channel: string, scripts: Record<'linux' | 'darwin' | 'win32', string>, scriptArgs: string[] = []) {
|
||||
const scriptName = scripts[process.platform as 'linux' | 'darwin' | 'win32'];
|
||||
if (!scriptName)
|
||||
throw new Error(`Cannot install ${channel} on ${process.platform}`);
|
||||
const shell = scriptName.endsWith('.ps1') ? 'powershell.exe' : 'bash';
|
||||
const { code } = await spawnAsync(shell, [path.join(BIN_PATH, scriptName), ...scriptArgs], { cwd: BIN_PATH, stdio: 'inherit' });
|
||||
if (code !== 0)
|
||||
throw new Error(`Failed to install ${channel}`);
|
||||
}
|
||||
|
||||
private async _validateInstallationCache(linksDir: string) {
|
||||
// 1. Collect used downloads and package descriptors.
|
||||
const usedBrowserPaths: Set<string> = new Set();
|
||||
|
@ -20,7 +20,7 @@ import path from 'path';
|
||||
import { spawnSync } from 'child_process';
|
||||
import { registry } from '../../src/utils/registry';
|
||||
|
||||
const ffmpeg = registry.findExecutable('ffmpeg')!.executablePathIfExists() || '';
|
||||
const ffmpeg = registry.findExecutable('ffmpeg')!.executablePath();
|
||||
|
||||
export class VideoPlayer {
|
||||
videoWidth: number;
|
||||
|
@ -21,7 +21,7 @@ import { spawnSync } from 'child_process';
|
||||
import { PNG } from 'pngjs';
|
||||
import { registry } from '../src/utils/registry';
|
||||
|
||||
const ffmpeg = registry.findExecutable('ffmpeg')!.executablePathIfExists() || '';
|
||||
const ffmpeg = registry.findExecutable('ffmpeg')!.executablePath();
|
||||
|
||||
export class VideoPlayer {
|
||||
fileName: string;
|
||||
|
@ -78,7 +78,7 @@ Example:
|
||||
|
||||
// 4. Generate types.
|
||||
console.log('\nGenerating protocol types...');
|
||||
const executablePath = new Registry(ROOT_PATH).findBinary(binaryName).executablePathIfExists();
|
||||
const executablePath = new Registry(ROOT_PATH).findBinary(binaryName).executablePathOrDie();
|
||||
await protocolGenerator.generateProtocol(browserName, executablePath).catch(console.warn);
|
||||
|
||||
// 5. Update docs.
|
||||
|
Loading…
Reference in New Issue
Block a user