feat!: deprecate createBrowserFetcher
in favor of BrowserFetcher
(#9079)
This PR deprecates the `createBrowserFetcher` API and requests users to import the `BrowserFetcher` directly. Fixed: #8999
This commit is contained in:
parent
1847704789
commit
7294dfe9c6
21
docs/api/puppeteer.browserfetcher._constructor_.md
Normal file
21
docs/api/puppeteer.browserfetcher._constructor_.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
sidebar_label: BrowserFetcher.(constructor)
|
||||||
|
---
|
||||||
|
|
||||||
|
# BrowserFetcher.(constructor)
|
||||||
|
|
||||||
|
Constructs a browser fetcher for the given options.
|
||||||
|
|
||||||
|
**Signature:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class BrowserFetcher {
|
||||||
|
constructor(options?: BrowserFetcherOptions);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ------------------------------------------------------------- | ----------------- |
|
||||||
|
| options | [BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md) | <i>(Optional)</i> |
|
@ -14,23 +14,25 @@ export declare class BrowserFetcher
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
BrowserFetcher operates on revision strings that specify a precise version of Chromium, e.g. `"533271"`. Revision strings can be obtained from [omahaproxy.appspot.com](http://omahaproxy.appspot.com/). In the Firefox case, BrowserFetcher downloads Firefox Nightly and operates on version numbers such as `"75"`.
|
BrowserFetcher is not designed to work concurrently with other instances of BrowserFetcher that share the same downloads directory.
|
||||||
|
|
||||||
The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `BrowserFetcher` class.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
An example of using BrowserFetcher to download a specific version of Chromium and running Puppeteer against it:
|
An example of using BrowserFetcher to download a specific version of Chromium and running Puppeteer against it:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const browserFetcher = puppeteer.createBrowserFetcher();
|
const browserFetcher = new BrowserFetcher();
|
||||||
const revisionInfo = await browserFetcher.download('533271');
|
const revisionInfo = await browserFetcher.download('533271');
|
||||||
const browser = await puppeteer.launch({
|
const browser = await puppeteer.launch({
|
||||||
executablePath: revisionInfo.executablePath,
|
executablePath: revisionInfo.executablePath,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE** BrowserFetcher is not designed to work concurrently with other instances of BrowserFetcher that share the same downloads directory.
|
## Constructors
|
||||||
|
|
||||||
|
| Constructor | Modifiers | Description |
|
||||||
|
| --------------------------------------------------------------------- | --------- | --------------------------------------------------- |
|
||||||
|
| [(constructor)(options)](./puppeteer.browserfetcher._constructor_.md) | | Constructs a browser fetcher for the given options. |
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ sidebar_label: BrowserFetcherOptions.host
|
|||||||
|
|
||||||
# BrowserFetcherOptions.host property
|
# BrowserFetcherOptions.host property
|
||||||
|
|
||||||
|
Determines the host that will be used for downloading.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
@ -12,9 +12,9 @@ export interface BrowserFetcherOptions
|
|||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
| Property | Modifiers | Type | Description |
|
| Property | Modifiers | Type | Description |
|
||||||
| ---------------------------------------------------------- | --------- | ----------------------------------- | ----------------- |
|
| ---------------------------------------------------------- | --------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||||
| [host?](./puppeteer.browserfetcheroptions.host.md) | | string | <i>(Optional)</i> |
|
| [host?](./puppeteer.browserfetcheroptions.host.md) | | string | <i>(Optional)</i> Determines the host that will be used for downloading. |
|
||||||
| [path?](./puppeteer.browserfetcheroptions.path.md) | | string | <i>(Optional)</i> |
|
| [path?](./puppeteer.browserfetcheroptions.path.md) | | string | <i>(Optional)</i> Determines the path to download browsers to. |
|
||||||
| [platform?](./puppeteer.browserfetcheroptions.platform.md) | | [Platform](./puppeteer.platform.md) | <i>(Optional)</i> |
|
| [platform?](./puppeteer.browserfetcheroptions.platform.md) | | [Platform](./puppeteer.platform.md) | <i>(Optional)</i> Determines which platform the browser will be suited for. |
|
||||||
| [product?](./puppeteer.browserfetcheroptions.product.md) | | string | <i>(Optional)</i> |
|
| [product?](./puppeteer.browserfetcheroptions.product.md) | | 'chrome' \| 'firefox' | <i>(Optional)</i> Determines which product the [BrowserFetcher](./puppeteer.browserfetcher.md) is for. |
|
||||||
|
@ -4,6 +4,8 @@ sidebar_label: BrowserFetcherOptions.path
|
|||||||
|
|
||||||
# BrowserFetcherOptions.path property
|
# BrowserFetcherOptions.path property
|
||||||
|
|
||||||
|
Determines the path to download browsers to.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
@ -4,6 +4,8 @@ sidebar_label: BrowserFetcherOptions.platform
|
|||||||
|
|
||||||
# BrowserFetcherOptions.platform property
|
# BrowserFetcherOptions.platform property
|
||||||
|
|
||||||
|
Determines which platform the browser will be suited for.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
@ -4,10 +4,12 @@ sidebar_label: BrowserFetcherOptions.product
|
|||||||
|
|
||||||
# BrowserFetcherOptions.product property
|
# BrowserFetcherOptions.product property
|
||||||
|
|
||||||
|
Determines which product the [BrowserFetcher](./puppeteer.browserfetcher.md) is for.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface BrowserFetcherOptions {
|
interface BrowserFetcherOptions {
|
||||||
product?: string;
|
product?: 'chrome' | 'firefox';
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -4,6 +4,10 @@ sidebar_label: createBrowserFetcher
|
|||||||
|
|
||||||
# createBrowserFetcher variable
|
# createBrowserFetcher variable
|
||||||
|
|
||||||
|
> Warning: This API is now obsolete.
|
||||||
|
>
|
||||||
|
> Import [BrowserFetcher](./puppeteer.browserfetcher.md) directly and use the constructor.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
@ -4,6 +4,10 @@ sidebar_label: PuppeteerNode.createBrowserFetcher
|
|||||||
|
|
||||||
# PuppeteerNode.createBrowserFetcher() method
|
# PuppeteerNode.createBrowserFetcher() method
|
||||||
|
|
||||||
|
> Warning: This API is now obsolete.
|
||||||
|
>
|
||||||
|
> Import [BrowserFetcher](./puppeteer.browserfetcher.md) directly and use the constructor.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
@ -14,9 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as childProcess from 'child_process';
|
import {exec as execChildProcess} from 'child_process';
|
||||||
import extractZip from 'extract-zip';
|
import extractZip from 'extract-zip';
|
||||||
import * as fs from 'fs';
|
import {createReadStream, createWriteStream, existsSync} from 'fs';
|
||||||
|
import {chmod, mkdir, readdir, unlink} from 'fs/promises';
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
import createHttpsProxyAgent, {
|
import createHttpsProxyAgent, {
|
||||||
@ -69,6 +70,8 @@ const browserConfig = {
|
|||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
const exec = promisify(execChildProcess);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported platforms.
|
* Supported platforms.
|
||||||
*
|
*
|
||||||
@ -117,11 +120,11 @@ function downloadURL(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleArm64(): void {
|
function handleArm64(): void {
|
||||||
let exists = fs.existsSync('/usr/bin/chromium-browser');
|
let exists = existsSync('/usr/bin/chromium-browser');
|
||||||
if (exists) {
|
if (exists) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
exists = fs.existsSync('/usr/bin/chromium');
|
exists = existsSync('/usr/bin/chromium');
|
||||||
if (exists) {
|
if (exists) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -134,27 +137,32 @@ function handleArm64(): void {
|
|||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
const readdirAsync = promisify(fs.readdir.bind(fs));
|
|
||||||
const mkdirAsync = promisify(fs.mkdir.bind(fs));
|
|
||||||
const unlinkAsync = promisify(fs.unlink.bind(fs));
|
|
||||||
const chmodAsync = promisify(fs.chmod.bind(fs));
|
|
||||||
|
|
||||||
function existsAsync(filePath: string): Promise<boolean> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
fs.access(filePath, err => {
|
|
||||||
return resolve(!err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface BrowserFetcherOptions {
|
export interface BrowserFetcherOptions {
|
||||||
|
/**
|
||||||
|
* Determines which platform the browser will be suited for.
|
||||||
|
*/
|
||||||
platform?: Platform;
|
platform?: Platform;
|
||||||
product?: string;
|
/**
|
||||||
|
* Determines which product the {@link BrowserFetcher} is for.
|
||||||
|
*
|
||||||
|
* @defaultValue `"chrome"`
|
||||||
|
*/
|
||||||
|
product?: 'chrome' | 'firefox';
|
||||||
|
/**
|
||||||
|
* Determines the path to download browsers to.
|
||||||
|
*/
|
||||||
path?: string;
|
path?: string;
|
||||||
|
/**
|
||||||
|
* Determines the host that will be used for downloading.
|
||||||
|
*/
|
||||||
host?: string;
|
host?: string;
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
projectRoot?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -168,29 +176,38 @@ export interface BrowserFetcherRevisionInfo {
|
|||||||
revision: string;
|
revision: string;
|
||||||
product: string;
|
product: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BrowserFetcher can download and manage different versions of Chromium and Firefox.
|
* BrowserFetcher can download and manage different versions of Chromium and
|
||||||
|
* Firefox.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* BrowserFetcher operates on revision strings that specify a precise version of Chromium, e.g. `"533271"`. Revision strings can be obtained from {@link http://omahaproxy.appspot.com/ | omahaproxy.appspot.com}.
|
* BrowserFetcher operates on revision strings that specify a precise version of
|
||||||
* In the Firefox case, BrowserFetcher downloads Firefox Nightly and
|
* Chromium, e.g. `"533271"`. Revision strings can be obtained from
|
||||||
* operates on version numbers such as `"75"`.
|
* {@link http://omahaproxy.appspot.com/ | omahaproxy.appspot.com}. For Firefox,
|
||||||
|
* BrowserFetcher downloads Firefox Nightly and operates on version numbers such
|
||||||
|
* as `"75"`.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* The default constructed fetcher will always be for Chromium unless otherwise
|
||||||
|
* specified.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* BrowserFetcher is not designed to work concurrently with other instances of
|
||||||
|
* BrowserFetcher that share the same downloads directory.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* An example of using BrowserFetcher to download a specific version of Chromium
|
* An example of using BrowserFetcher to download a specific version of Chromium
|
||||||
* and running Puppeteer against it:
|
* and running Puppeteer against it:
|
||||||
*
|
*
|
||||||
* ```ts
|
* ```ts
|
||||||
* const browserFetcher = puppeteer.createBrowserFetcher();
|
* const browserFetcher = new BrowserFetcher();
|
||||||
* const revisionInfo = await browserFetcher.download('533271');
|
* const revisionInfo = await browserFetcher.download('533271');
|
||||||
* const browser = await puppeteer.launch({
|
* const browser = await puppeteer.launch({
|
||||||
* executablePath: revisionInfo.executablePath,
|
* executablePath: revisionInfo.executablePath,
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* **NOTE** BrowserFetcher is not designed to work concurrently with other
|
|
||||||
* instances of BrowserFetcher that share the same downloads directory.
|
|
||||||
*
|
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -201,9 +218,9 @@ export class BrowserFetcher {
|
|||||||
#platform: Platform;
|
#platform: Platform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* Constructs a browser fetcher for the given options.
|
||||||
*/
|
*/
|
||||||
constructor(projectRoot: string, options: BrowserFetcherOptions = {}) {
|
constructor(options: BrowserFetcherOptions = {}) {
|
||||||
this.#product = (options.product || 'chrome').toLowerCase() as Product;
|
this.#product = (options.product || 'chrome').toLowerCase() as Product;
|
||||||
assert(
|
assert(
|
||||||
this.#product === 'chrome' || this.#product === 'firefox',
|
this.#product === 'chrome' || this.#product === 'firefox',
|
||||||
@ -212,7 +229,7 @@ export class BrowserFetcher {
|
|||||||
|
|
||||||
this.#downloadsFolder =
|
this.#downloadsFolder =
|
||||||
options.path ||
|
options.path ||
|
||||||
path.join(projectRoot, browserConfig[this.#product].destination);
|
path.join(options.projectRoot!, browserConfig[this.#product].destination);
|
||||||
this.#downloadHost = options.host || browserConfig[this.#product].host;
|
this.#downloadHost = options.host || browserConfig[this.#product].host;
|
||||||
|
|
||||||
if (options.platform) {
|
if (options.platform) {
|
||||||
@ -240,7 +257,7 @@ export class BrowserFetcher {
|
|||||||
this.#platform =
|
this.#platform =
|
||||||
os.arch() === 'x64' ||
|
os.arch() === 'x64' ||
|
||||||
// Windows 11 for ARM supports x64 emulation
|
// Windows 11 for ARM supports x64 emulation
|
||||||
(os.arch() === 'arm64' && _isWindows11(os.release()))
|
(os.arch() === 'arm64' && isWindows11(os.release()))
|
||||||
? 'win64'
|
? 'win64'
|
||||||
: 'win32';
|
: 'win32';
|
||||||
return;
|
return;
|
||||||
@ -333,11 +350,11 @@ export class BrowserFetcher {
|
|||||||
assert(fileName, `A malformed download URL was found: ${url}.`);
|
assert(fileName, `A malformed download URL was found: ${url}.`);
|
||||||
const archivePath = path.join(this.#downloadsFolder, fileName);
|
const archivePath = path.join(this.#downloadsFolder, fileName);
|
||||||
const outputPath = this.#getFolderPath(revision);
|
const outputPath = this.#getFolderPath(revision);
|
||||||
if (await existsAsync(outputPath)) {
|
if (existsSync(outputPath)) {
|
||||||
return this.revisionInfo(revision);
|
return this.revisionInfo(revision);
|
||||||
}
|
}
|
||||||
if (!(await existsAsync(this.#downloadsFolder))) {
|
if (!existsSync(this.#downloadsFolder)) {
|
||||||
await mkdirAsync(this.#downloadsFolder);
|
await mkdir(this.#downloadsFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use system Chromium builds on Linux ARM devices
|
// Use system Chromium builds on Linux ARM devices
|
||||||
@ -349,13 +366,13 @@ export class BrowserFetcher {
|
|||||||
await _downloadFile(url, archivePath, progressCallback);
|
await _downloadFile(url, archivePath, progressCallback);
|
||||||
await install(archivePath, outputPath);
|
await install(archivePath, outputPath);
|
||||||
} finally {
|
} finally {
|
||||||
if (await existsAsync(archivePath)) {
|
if (existsSync(archivePath)) {
|
||||||
await unlinkAsync(archivePath);
|
await unlink(archivePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const revisionInfo = this.revisionInfo(revision);
|
const revisionInfo = this.revisionInfo(revision);
|
||||||
if (revisionInfo) {
|
if (revisionInfo) {
|
||||||
await chmodAsync(revisionInfo.executablePath, 0o755);
|
await chmod(revisionInfo.executablePath, 0o755);
|
||||||
}
|
}
|
||||||
return revisionInfo;
|
return revisionInfo;
|
||||||
}
|
}
|
||||||
@ -367,10 +384,10 @@ export class BrowserFetcher {
|
|||||||
* available locally on disk.
|
* available locally on disk.
|
||||||
*/
|
*/
|
||||||
async localRevisions(): Promise<string[]> {
|
async localRevisions(): Promise<string[]> {
|
||||||
if (!(await existsAsync(this.#downloadsFolder))) {
|
if (!existsSync(this.#downloadsFolder)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const fileNames = await readdirAsync(this.#downloadsFolder);
|
const fileNames = await readdir(this.#downloadsFolder);
|
||||||
return fileNames
|
return fileNames
|
||||||
.map(fileName => {
|
.map(fileName => {
|
||||||
return parseFolderPath(this.#product, fileName);
|
return parseFolderPath(this.#product, fileName);
|
||||||
@ -397,7 +414,7 @@ export class BrowserFetcher {
|
|||||||
async remove(revision: string): Promise<void> {
|
async remove(revision: string): Promise<void> {
|
||||||
const folderPath = this.#getFolderPath(revision);
|
const folderPath = this.#getFolderPath(revision);
|
||||||
assert(
|
assert(
|
||||||
await existsAsync(folderPath),
|
existsSync(folderPath),
|
||||||
`Failed to remove: revision ${revision} is not downloaded`
|
`Failed to remove: revision ${revision} is not downloaded`
|
||||||
);
|
);
|
||||||
await new Promise(fulfill => {
|
await new Promise(fulfill => {
|
||||||
@ -412,57 +429,66 @@ export class BrowserFetcher {
|
|||||||
revisionInfo(revision: string): BrowserFetcherRevisionInfo {
|
revisionInfo(revision: string): BrowserFetcherRevisionInfo {
|
||||||
const folderPath = this.#getFolderPath(revision);
|
const folderPath = this.#getFolderPath(revision);
|
||||||
let executablePath = '';
|
let executablePath = '';
|
||||||
if (this.#product === 'chrome') {
|
switch (this.#product) {
|
||||||
if (this.#platform === 'mac' || this.#platform === 'mac_arm') {
|
case 'chrome':
|
||||||
executablePath = path.join(
|
switch (this.#platform) {
|
||||||
folderPath,
|
case 'mac':
|
||||||
archiveName(this.#product, this.#platform, revision),
|
case 'mac_arm':
|
||||||
'Chromium.app',
|
executablePath = path.join(
|
||||||
'Contents',
|
folderPath,
|
||||||
'MacOS',
|
archiveName(this.#product, this.#platform, revision),
|
||||||
'Chromium'
|
'Chromium.app',
|
||||||
);
|
'Contents',
|
||||||
} else if (this.#platform === 'linux') {
|
'MacOS',
|
||||||
executablePath = path.join(
|
'Chromium'
|
||||||
folderPath,
|
);
|
||||||
archiveName(this.#product, this.#platform, revision),
|
break;
|
||||||
'chrome'
|
case 'linux':
|
||||||
);
|
executablePath = path.join(
|
||||||
} else if (this.#platform === 'win32' || this.#platform === 'win64') {
|
folderPath,
|
||||||
executablePath = path.join(
|
archiveName(this.#product, this.#platform, revision),
|
||||||
folderPath,
|
'chrome'
|
||||||
archiveName(this.#product, this.#platform, revision),
|
);
|
||||||
'chrome.exe'
|
break;
|
||||||
);
|
case 'win32':
|
||||||
} else {
|
case 'win64':
|
||||||
throw new Error('Unsupported platform: ' + this.#platform);
|
executablePath = path.join(
|
||||||
}
|
folderPath,
|
||||||
} else if (this.#product === 'firefox') {
|
archiveName(this.#product, this.#platform, revision),
|
||||||
if (this.#platform === 'mac' || this.#platform === 'mac_arm') {
|
'chrome.exe'
|
||||||
executablePath = path.join(
|
);
|
||||||
folderPath,
|
break;
|
||||||
'Firefox Nightly.app',
|
}
|
||||||
'Contents',
|
break;
|
||||||
'MacOS',
|
case 'firefox':
|
||||||
'firefox'
|
switch (this.#platform) {
|
||||||
);
|
case 'mac':
|
||||||
} else if (this.#platform === 'linux') {
|
case 'mac_arm':
|
||||||
executablePath = path.join(folderPath, 'firefox', 'firefox');
|
executablePath = path.join(
|
||||||
} else if (this.#platform === 'win32' || this.#platform === 'win64') {
|
folderPath,
|
||||||
executablePath = path.join(folderPath, 'firefox', 'firefox.exe');
|
'Firefox Nightly.app',
|
||||||
} else {
|
'Contents',
|
||||||
throw new Error('Unsupported platform: ' + this.#platform);
|
'MacOS',
|
||||||
}
|
'firefox'
|
||||||
} else {
|
);
|
||||||
throw new Error('Unsupported product: ' + this.#product);
|
break;
|
||||||
|
case 'linux':
|
||||||
|
executablePath = path.join(folderPath, 'firefox', 'firefox');
|
||||||
|
break;
|
||||||
|
case 'win32':
|
||||||
|
case 'win64':
|
||||||
|
executablePath = path.join(folderPath, 'firefox', 'firefox.exe');
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = downloadURL(
|
const url = downloadURL(
|
||||||
this.#product,
|
this.#product,
|
||||||
this.#platform,
|
this.#platform,
|
||||||
this.#downloadHost,
|
this.#downloadHost,
|
||||||
revision
|
revision
|
||||||
);
|
);
|
||||||
const local = fs.existsSync(folderPath);
|
const local = existsSync(folderPath);
|
||||||
debugFetcher({
|
debugFetcher({
|
||||||
revision,
|
revision,
|
||||||
executablePath,
|
executablePath,
|
||||||
@ -506,7 +532,7 @@ function parseFolderPath(
|
|||||||
* Windows 11 is identified by 10.0.22000 or greater
|
* Windows 11 is identified by 10.0.22000 or greater
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
function _isWindows11(version: string): boolean {
|
function isWindows11(version: string): boolean {
|
||||||
const parts = version.split('.');
|
const parts = version.split('.');
|
||||||
if (parts.length > 2) {
|
if (parts.length > 2) {
|
||||||
const major = parseInt(parts[0] as string, 10);
|
const major = parseInt(parts[0] as string, 10);
|
||||||
@ -550,7 +576,7 @@ function _downloadFile(
|
|||||||
reject(error);
|
reject(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const file = fs.createWriteStream(destinationPath);
|
const file = createWriteStream(destinationPath);
|
||||||
file.on('finish', () => {
|
file.on('finish', () => {
|
||||||
return fulfill();
|
return fulfill();
|
||||||
});
|
});
|
||||||
@ -574,16 +600,15 @@ function _downloadFile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function install(archivePath: string, folderPath: string): Promise<unknown> {
|
async function install(archivePath: string, folderPath: string): Promise<void> {
|
||||||
debugFetcher(`Installing ${archivePath} to ${folderPath}`);
|
debugFetcher(`Installing ${archivePath} to ${folderPath}`);
|
||||||
if (archivePath.endsWith('.zip')) {
|
if (archivePath.endsWith('.zip')) {
|
||||||
return extractZip(archivePath, {dir: folderPath});
|
await extractZip(archivePath, {dir: folderPath});
|
||||||
} else if (archivePath.endsWith('.tar.bz2')) {
|
} else if (archivePath.endsWith('.tar.bz2')) {
|
||||||
return _extractTar(archivePath, folderPath);
|
await extractTar(archivePath, folderPath);
|
||||||
} else if (archivePath.endsWith('.dmg')) {
|
} else if (archivePath.endsWith('.dmg')) {
|
||||||
return mkdirAsync(folderPath).then(() => {
|
await mkdir(folderPath);
|
||||||
return _installDMG(archivePath, folderPath);
|
await installDMG(archivePath, folderPath);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unsupported archive format: ${archivePath}`);
|
throw new Error(`Unsupported archive format: ${archivePath}`);
|
||||||
}
|
}
|
||||||
@ -592,12 +617,12 @@ function install(archivePath: string, folderPath: string): Promise<unknown> {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
function _extractTar(tarPath: string, folderPath: string): Promise<unknown> {
|
function extractTar(tarPath: string, folderPath: string): Promise<void> {
|
||||||
return new Promise((fulfill, reject) => {
|
return new Promise((fulfill, reject) => {
|
||||||
const tarStream = tar.extract(folderPath);
|
const tarStream = tar.extract(folderPath);
|
||||||
tarStream.on('error', reject);
|
tarStream.on('error', reject);
|
||||||
tarStream.on('finish', fulfill);
|
tarStream.on('finish', fulfill);
|
||||||
const readStream = fs.createReadStream(tarPath);
|
const readStream = createReadStream(tarPath);
|
||||||
readStream.pipe(bzip()).pipe(tarStream);
|
readStream.pipe(bzip()).pipe(tarStream);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -605,56 +630,33 @@ function _extractTar(tarPath: string, folderPath: string): Promise<unknown> {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
function _installDMG(dmgPath: string, folderPath: string): Promise<void> {
|
async function installDMG(dmgPath: string, folderPath: string): Promise<void> {
|
||||||
let mountPath: string | undefined;
|
const {stdout} = await exec(
|
||||||
|
`hdiutil attach -nobrowse -noautoopen "${dmgPath}"`
|
||||||
|
);
|
||||||
|
|
||||||
return new Promise<void>((fulfill, reject): void => {
|
const volumes = stdout.match(/\/Volumes\/(.*)/m);
|
||||||
const mountCommand = `hdiutil attach -nobrowse -noautoopen "${dmgPath}"`;
|
if (!volumes) {
|
||||||
childProcess.exec(mountCommand, (err, stdout) => {
|
throw new Error(`Could not find volume path in ${stdout}`);
|
||||||
if (err) {
|
}
|
||||||
return reject(err);
|
const mountPath = volumes[0]!;
|
||||||
}
|
|
||||||
const volumes = stdout.match(/\/Volumes\/(.*)/m);
|
try {
|
||||||
if (!volumes) {
|
const fileNames = await readdir(mountPath);
|
||||||
return reject(new Error(`Could not find volume path in ${stdout}`));
|
const appName = fileNames.find(item => {
|
||||||
}
|
return typeof item === 'string' && item.endsWith('.app');
|
||||||
mountPath = volumes[0]!;
|
|
||||||
readdirAsync(mountPath)
|
|
||||||
.then(fileNames => {
|
|
||||||
const appName = fileNames.find(item => {
|
|
||||||
return typeof item === 'string' && item.endsWith('.app');
|
|
||||||
});
|
|
||||||
if (!appName) {
|
|
||||||
return reject(new Error(`Cannot find app in ${mountPath}`));
|
|
||||||
}
|
|
||||||
const copyPath = path.join(mountPath!, appName);
|
|
||||||
debugFetcher(`Copying ${copyPath} to ${folderPath}`);
|
|
||||||
childProcess.exec(`cp -R "${copyPath}" "${folderPath}"`, err => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
fulfill();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error(error);
|
|
||||||
})
|
|
||||||
.finally((): void => {
|
|
||||||
if (!mountPath) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const unmountCommand = `hdiutil detach "${mountPath}" -quiet`;
|
|
||||||
debugFetcher(`Unmounting ${mountPath}`);
|
|
||||||
childProcess.exec(unmountCommand, err => {
|
|
||||||
if (err) {
|
|
||||||
console.error(`Error unmounting dmg: ${err}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
if (!appName) {
|
||||||
|
throw new Error(`Cannot find app in ${mountPath}`);
|
||||||
|
}
|
||||||
|
const mountedPath = path.join(mountPath!, appName);
|
||||||
|
|
||||||
|
debugFetcher(`Copying ${mountedPath} to ${folderPath}`);
|
||||||
|
await exec(`cp -R "${mountedPath}" "${folderPath}"`);
|
||||||
|
} finally {
|
||||||
|
debugFetcher(`Unmounting ${mountPath}`);
|
||||||
|
await exec(`hdiutil detach "${mountPath}" -quiet`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function httpRequest(
|
function httpRequest(
|
||||||
@ -675,11 +677,7 @@ function httpRequest(
|
|||||||
let options: Options = {
|
let options: Options = {
|
||||||
...urlParsed,
|
...urlParsed,
|
||||||
method,
|
method,
|
||||||
headers: keepAlive
|
headers: keepAlive ? {Connection: 'keep-alive'} : undefined,
|
||||||
? {
|
|
||||||
Connection: 'keep-alive',
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const proxyURL = getProxyForUrl(url);
|
const proxyURL = getProxyForUrl(url);
|
||||||
|
@ -221,7 +221,8 @@ export class FirefoxLauncher implements ProductLauncher {
|
|||||||
'_projectRoot is undefined. Unable to create a BrowserFetcher.'
|
'_projectRoot is undefined. Unable to create a BrowserFetcher.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const browserFetcher = new BrowserFetcher(this._projectRoot, {
|
const browserFetcher = new BrowserFetcher({
|
||||||
|
projectRoot: this._projectRoot,
|
||||||
product: this.product,
|
product: this.product,
|
||||||
});
|
});
|
||||||
const localRevisions = await browserFetcher.localRevisions();
|
const localRevisions = await browserFetcher.localRevisions();
|
||||||
|
@ -160,7 +160,8 @@ export function resolveExecutablePath(
|
|||||||
'_projectRoot is undefined. Unable to create a BrowserFetcher.'
|
'_projectRoot is undefined. Unable to create a BrowserFetcher.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const browserFetcher = new BrowserFetcher(_projectRoot, {
|
const browserFetcher = new BrowserFetcher({
|
||||||
|
projectRoot: _projectRoot,
|
||||||
product: product,
|
product: product,
|
||||||
path: downloadPath,
|
path: downloadPath,
|
||||||
});
|
});
|
||||||
|
@ -234,16 +234,13 @@ export class PuppeteerNode extends Puppeteer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated Import {@link BrowserFetcher} directly and use the constructor.
|
||||||
|
*
|
||||||
* @param options - Set of configurable options to specify the settings of the
|
* @param options - Set of configurable options to specify the settings of the
|
||||||
* BrowserFetcher.
|
* BrowserFetcher.
|
||||||
* @returns A new BrowserFetcher instance.
|
* @returns A new BrowserFetcher instance.
|
||||||
*/
|
*/
|
||||||
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher {
|
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher {
|
||||||
if (!this.#projectRoot) {
|
return new BrowserFetcher({...options, projectRoot: this.#projectRoot});
|
||||||
throw new Error(
|
|
||||||
'_projectRoot is undefined. Unable to create a BrowserFetcher.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return new BrowserFetcher(this.#projectRoot, options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ export * from './common/Device.js';
|
|||||||
export * from './common/Errors.js';
|
export * from './common/Errors.js';
|
||||||
export * from './common/PredefinedNetworkConditions.js';
|
export * from './common/PredefinedNetworkConditions.js';
|
||||||
export * from './common/Puppeteer.js';
|
export * from './common/Puppeteer.js';
|
||||||
|
export * from './node/BrowserFetcher.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the query handler API defined on {@link Puppeteer}
|
* @deprecated Use the query handler API defined on {@link Puppeteer}
|
||||||
@ -39,6 +40,7 @@ const puppeteer = new PuppeteerNode({
|
|||||||
|
|
||||||
export const {
|
export const {
|
||||||
connect,
|
connect,
|
||||||
|
/** @deprecated Import {@link BrowserFetcher} directly and use the constructor. */
|
||||||
createBrowserFetcher,
|
createBrowserFetcher,
|
||||||
defaultArgs,
|
defaultArgs,
|
||||||
executablePath,
|
executablePath,
|
||||||
|
@ -59,7 +59,7 @@ export async function downloadBrowser(): Promise<void> {
|
|||||||
process.env['PUPPETEER_DOWNLOAD_PATH'] ||
|
process.env['PUPPETEER_DOWNLOAD_PATH'] ||
|
||||||
process.env['npm_config_puppeteer_download_path'] ||
|
process.env['npm_config_puppeteer_download_path'] ||
|
||||||
process.env['npm_package_config_puppeteer_download_path'];
|
process.env['npm_package_config_puppeteer_download_path'];
|
||||||
const browserFetcher = (puppeteer as PuppeteerNode).createBrowserFetcher({
|
const browserFetcher = puppeteer.createBrowserFetcher({
|
||||||
product,
|
product,
|
||||||
host: downloadHost,
|
host: downloadHost,
|
||||||
path: downloadPath,
|
path: downloadPath,
|
||||||
|
@ -19,11 +19,11 @@ export * from 'puppeteer-core/internal/common/Device.js';
|
|||||||
export * from 'puppeteer-core/internal/common/Errors.js';
|
export * from 'puppeteer-core/internal/common/Errors.js';
|
||||||
export * from 'puppeteer-core/internal/common/PredefinedNetworkConditions.js';
|
export * from 'puppeteer-core/internal/common/PredefinedNetworkConditions.js';
|
||||||
export * from 'puppeteer-core/internal/common/Puppeteer.js';
|
export * from 'puppeteer-core/internal/common/Puppeteer.js';
|
||||||
|
export * from 'puppeteer-core/internal/node/BrowserFetcher.js';
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the query handler API defined on {@link Puppeteer}
|
* @deprecated Use the query handler API defined on {@link Puppeteer}
|
||||||
*/
|
*/
|
||||||
export * from 'puppeteer-core/internal/common/QueryHandler.js';
|
export * from 'puppeteer-core/internal/common/QueryHandler.js';
|
||||||
export {BrowserFetcher} from 'puppeteer-core/internal/node/BrowserFetcher.js';
|
|
||||||
export {LaunchOptions} from 'puppeteer-core/internal/node/LaunchOptions.js';
|
export {LaunchOptions} from 'puppeteer-core/internal/node/LaunchOptions.js';
|
||||||
|
|
||||||
import {Product} from 'puppeteer-core';
|
import {Product} from 'puppeteer-core';
|
||||||
@ -57,6 +57,7 @@ const puppeteer = new PuppeteerNode({
|
|||||||
|
|
||||||
export const {
|
export const {
|
||||||
connect,
|
connect,
|
||||||
|
/** @deprecated Import {@link BrowserFetcher} directly and use the constructor. */
|
||||||
createBrowserFetcher,
|
createBrowserFetcher,
|
||||||
defaultArgs,
|
defaultArgs,
|
||||||
executablePath,
|
executablePath,
|
||||||
|
Loading…
Reference in New Issue
Block a user