mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: move extracting of browser out-of-process (#23739)
https://github.com/microsoft/playwright/issues/23729
This commit is contained in:
parent
de422b5afb
commit
b44723708c
@ -19,15 +19,14 @@ import fs from 'fs';
|
|||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import childProcess from 'child_process';
|
import childProcess from 'child_process';
|
||||||
import { getUserAgent } from '../../utils/userAgent';
|
|
||||||
import { existsAsync } from '../../utils/fileUtils';
|
import { existsAsync } from '../../utils/fileUtils';
|
||||||
import { debugLogger } from '../../common/debugLogger';
|
import { debugLogger } from '../../common/debugLogger';
|
||||||
import { extract } from '../../zipBundle';
|
|
||||||
import { ManualPromise } from '../../utils/manualPromise';
|
import { ManualPromise } from '../../utils/manualPromise';
|
||||||
import { colors } from '../../utilsBundle';
|
import { colors } from '../../utilsBundle';
|
||||||
|
import { browserDirectoryToMarkerFilePath } from '.';
|
||||||
|
|
||||||
export async function downloadBrowserWithProgressBar(title: string, browserDirectory: string, executablePath: string | undefined, downloadURLs: string[], downloadFileName: string, downloadConnectionTimeout: number): Promise<boolean> {
|
export async function downloadBrowserWithProgressBar(title: string, browserDirectory: string, executablePath: string | undefined, downloadURLs: string[], downloadFileName: string, downloadConnectionTimeout: number): Promise<boolean> {
|
||||||
if (await existsAsync(browserDirectory)) {
|
if (await existsAsync(browserDirectoryToMarkerFilePath(browserDirectory))) {
|
||||||
// Already downloaded.
|
// Already downloaded.
|
||||||
debugLogger.log('install', `${title} is already downloaded.`);
|
debugLogger.log('install', `${title} is already downloaded.`);
|
||||||
return false;
|
return false;
|
||||||
@ -40,24 +39,20 @@ export async function downloadBrowserWithProgressBar(title: string, browserDirec
|
|||||||
debugLogger.log('install', `downloading ${title} - attempt #${attempt}`);
|
debugLogger.log('install', `downloading ${title} - attempt #${attempt}`);
|
||||||
const url = downloadURLs[(attempt - 1) % downloadURLs.length];
|
const url = downloadURLs[(attempt - 1) % downloadURLs.length];
|
||||||
logPolitely(`Downloading ${title}` + colors.dim(` from ${url}`));
|
logPolitely(`Downloading ${title}` + colors.dim(` from ${url}`));
|
||||||
const { error } = await downloadFileOutOfProcess(url, zipPath, getUserAgent(), downloadConnectionTimeout);
|
const { error } = await downloadBrowserWithProgressBarOutOfProcess(title, browserDirectory, url, zipPath, executablePath, downloadConnectionTimeout);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
debugLogger.log('install', `SUCCESS downloading ${title}`);
|
debugLogger.log('install', `SUCCESS installing ${title}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (await existsAsync(zipPath))
|
||||||
|
await fs.promises.unlink(zipPath);
|
||||||
|
if (await existsAsync(browserDirectory))
|
||||||
|
await fs.promises.rmdir(browserDirectory, { recursive: true });
|
||||||
const errorMessage = error?.message || '';
|
const errorMessage = error?.message || '';
|
||||||
debugLogger.log('install', `attempt #${attempt} - ERROR: ${errorMessage}`);
|
debugLogger.log('install', `attempt #${attempt} - ERROR: ${errorMessage}`);
|
||||||
if (attempt >= retryCount)
|
if (attempt >= retryCount)
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
debugLogger.log('install', `extracting archive`);
|
|
||||||
debugLogger.log('install', `-- zip: ${zipPath}`);
|
|
||||||
debugLogger.log('install', `-- location: ${browserDirectory}`);
|
|
||||||
await extract(zipPath, { dir: browserDirectory });
|
|
||||||
if (executablePath) {
|
|
||||||
debugLogger.log('install', `fixing permissions at ${executablePath}`);
|
|
||||||
await fs.promises.chmod(executablePath, 0o755);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugLogger.log('install', `FAILED installation ${title} with error: ${e}`);
|
debugLogger.log('install', `FAILED installation ${title} with error: ${e}`);
|
||||||
process.exitCode = 1;
|
process.exitCode = 1;
|
||||||
@ -75,8 +70,8 @@ export async function downloadBrowserWithProgressBar(title: string, browserDirec
|
|||||||
* Thats why we execute it in a separate process and check manually if the destination file exists.
|
* Thats why we execute it in a separate process and check manually if the destination file exists.
|
||||||
* https://github.com/microsoft/playwright/issues/17394
|
* https://github.com/microsoft/playwright/issues/17394
|
||||||
*/
|
*/
|
||||||
function downloadFileOutOfProcess(url: string, destinationPath: string, userAgent: string, downloadConnectionTimeout: number): Promise<{ error: Error | null }> {
|
function downloadBrowserWithProgressBarOutOfProcess(title: string, browserDirectory: string, url: string, zipPath: string, executablePath: string | undefined, downloadConnectionTimeout: number): Promise<{ error: Error | null }> {
|
||||||
const cp = childProcess.fork(path.join(__dirname, 'oopDownloadMain.js'), [url, destinationPath, userAgent, String(downloadConnectionTimeout)]);
|
const cp = childProcess.fork(path.join(__dirname, 'oopDownloadBrowserMain.js'), [title, browserDirectory, url, zipPath, executablePath || '', String(downloadConnectionTimeout)]);
|
||||||
const promise = new ManualPromise<{ error: Error | null }>();
|
const promise = new ManualPromise<{ error: Error | null }>();
|
||||||
cp.on('message', (message: any) => {
|
cp.on('message', (message: any) => {
|
||||||
if (message?.method === 'log')
|
if (message?.method === 'log')
|
||||||
@ -87,8 +82,8 @@ function downloadFileOutOfProcess(url: string, destinationPath: string, userAgen
|
|||||||
promise.resolve({ error: new Error(`Download failure, code=${code}`) });
|
promise.resolve({ error: new Error(`Download failure, code=${code}`) });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!fs.existsSync(destinationPath))
|
if (!fs.existsSync(browserDirectoryToMarkerFilePath(browserDirectory)))
|
||||||
promise.resolve({ error: new Error(`Download failure, ${destinationPath} does not exist`) });
|
promise.resolve({ error: new Error(`Download failure, ${browserDirectoryToMarkerFilePath(browserDirectory)} does not exist`) });
|
||||||
else
|
else
|
||||||
promise.resolve({ error: null });
|
promise.resolve({ error: null });
|
||||||
});
|
});
|
||||||
|
|||||||
@ -839,7 +839,6 @@ export class Registry {
|
|||||||
await downloadBrowserWithProgressBar(title, descriptor.dir, executablePath, downloadURLs, downloadFileName, downloadConnectionTimeout).catch(e => {
|
await downloadBrowserWithProgressBar(title, descriptor.dir, executablePath, downloadURLs, downloadFileName, downloadConnectionTimeout).catch(e => {
|
||||||
throw new Error(`Failed to download ${title}, caused by\n${e.stack}`);
|
throw new Error(`Failed to download ${title}, caused by\n${e.stack}`);
|
||||||
});
|
});
|
||||||
await fs.promises.writeFile(markerFilePath(descriptor.dir), '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _installMSEdgeChannel(channel: 'msedge'|'msedge-beta'|'msedge-dev', scripts: Record<'linux' | 'darwin' | 'win32', string>) {
|
private async _installMSEdgeChannel(channel: 'msedge'|'msedge-beta'|'msedge-dev', scripts: Record<'linux' | 'darwin' | 'win32', string>) {
|
||||||
@ -920,7 +919,7 @@ export class Registry {
|
|||||||
(browserName === 'webkit' && browserRevision >= 1307) ||
|
(browserName === 'webkit' && browserRevision >= 1307) ||
|
||||||
// All new applications have a marker file right away.
|
// All new applications have a marker file right away.
|
||||||
(browserName !== 'firefox' && browserName !== 'chromium' && browserName !== 'webkit');
|
(browserName !== 'firefox' && browserName !== 'chromium' && browserName !== 'webkit');
|
||||||
if (!shouldHaveMarkerFile || (await existsAsync(markerFilePath(usedBrowserPath))))
|
if (!shouldHaveMarkerFile || (await existsAsync(browserDirectoryToMarkerFilePath(usedBrowserPath))))
|
||||||
usedBrowserPaths.add(usedBrowserPath);
|
usedBrowserPaths.add(usedBrowserPath);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -942,7 +941,7 @@ export class Registry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function markerFilePath(browserDirectory: string): string {
|
export function browserDirectoryToMarkerFilePath(browserDirectory: string): string {
|
||||||
return path.join(browserDirectory, 'INSTALLATION_COMPLETE');
|
return path.join(browserDirectory, 'INSTALLATION_COMPLETE');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,9 @@ import fs from 'fs';
|
|||||||
import { progress as ProgressBar } from '../../utilsBundle';
|
import { progress as ProgressBar } from '../../utilsBundle';
|
||||||
import { httpRequest } from '../../utils/network';
|
import { httpRequest } from '../../utils/network';
|
||||||
import { ManualPromise } from '../../utils/manualPromise';
|
import { ManualPromise } from '../../utils/manualPromise';
|
||||||
|
import { extract } from '../../zipBundle';
|
||||||
|
import { getUserAgent } from '../../utils/userAgent';
|
||||||
|
import { browserDirectoryToMarkerFilePath } from '.';
|
||||||
|
|
||||||
type OnProgressCallback = (downloadedBytes: number, totalBytes: number) => void;
|
type OnProgressCallback = (downloadedBytes: number, totalBytes: number) => void;
|
||||||
type DownloadFileLogger = (message: string) => void;
|
type DownloadFileLogger = (message: string) => void;
|
||||||
@ -140,13 +143,24 @@ function toMegabytes(bytes: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const [url, destination, userAgent, downloadConnectionTimeout] = process.argv.slice(2);
|
const log = (message: string) => process.send?.({ method: 'log', params: { message } });
|
||||||
await downloadFile(url, destination, {
|
const [title, browserDirectory, url, zipPath, executablePath, downloadConnectionTimeout] = process.argv.slice(2);
|
||||||
|
await downloadFile(url, zipPath, {
|
||||||
progressCallback: getDownloadProgress(),
|
progressCallback: getDownloadProgress(),
|
||||||
userAgent,
|
userAgent: getUserAgent(),
|
||||||
log: message => process.send?.({ method: 'log', params: { message } }),
|
log,
|
||||||
connectionTimeout: +downloadConnectionTimeout,
|
connectionTimeout: +downloadConnectionTimeout,
|
||||||
});
|
});
|
||||||
|
log(`SUCCESS downloading ${title}`);
|
||||||
|
log(`extracting archive`);
|
||||||
|
log(`-- zip: ${zipPath}`);
|
||||||
|
log(`-- location: ${browserDirectory}`);
|
||||||
|
await extract(zipPath, { dir: browserDirectory });
|
||||||
|
if (executablePath) {
|
||||||
|
log(`fixing permissions at ${executablePath}`);
|
||||||
|
await fs.promises.chmod(executablePath, 0o755);
|
||||||
|
}
|
||||||
|
await fs.promises.writeFile(browserDirectoryToMarkerFilePath(browserDirectory), '');
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(error => {
|
main().catch(error => {
|
||||||
Loading…
x
Reference in New Issue
Block a user