mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat: support local aliases when launching a browser (#11947)
This commit is contained in:
parent
bf71b34fca
commit
561e4cd6ee
@ -23,3 +23,10 @@ The constructor for this class is marked as internal. Third-party code should no
|
|||||||
| executablePath | <code>readonly</code> | string | |
|
| executablePath | <code>readonly</code> | string | |
|
||||||
| path | <code>readonly</code> | string | Path to the root of the installation folder. Use [computeExecutablePath()](./browsers.computeexecutablepath.md) to get the path to the executable binary. |
|
| path | <code>readonly</code> | string | Path to the root of the installation folder. Use [computeExecutablePath()](./browsers.computeexecutablepath.md) to get the path to the executable binary. |
|
||||||
| platform | | [BrowserPlatform](./browsers.browserplatform.md) | |
|
| platform | | [BrowserPlatform](./browsers.browserplatform.md) | |
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
| Method | Modifiers | Description |
|
||||||
|
| ----------------------------------------------------------------------- | --------- | ----------- |
|
||||||
|
| [readMetadata()](./browsers.installedbrowser.readmetadata.md) | | |
|
||||||
|
| [writeMetadata(metadata)](./browsers.installedbrowser.writemetadata.md) | | |
|
||||||
|
17
docs/browsers-api/browsers.installedbrowser.readmetadata.md
Normal file
17
docs/browsers-api/browsers.installedbrowser.readmetadata.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
sidebar_label: InstalledBrowser.readMetadata
|
||||||
|
---
|
||||||
|
|
||||||
|
# InstalledBrowser.readMetadata() method
|
||||||
|
|
||||||
|
#### Signature:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class InstalledBrowser {
|
||||||
|
readMetadata(): Metadata;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
Metadata
|
23
docs/browsers-api/browsers.installedbrowser.writemetadata.md
Normal file
23
docs/browsers-api/browsers.installedbrowser.writemetadata.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
sidebar_label: InstalledBrowser.writeMetadata
|
||||||
|
---
|
||||||
|
|
||||||
|
# InstalledBrowser.writeMetadata() method
|
||||||
|
|
||||||
|
#### Signature:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class InstalledBrowser {
|
||||||
|
writeMetadata(metadata: Metadata): void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | -------- | ----------- |
|
||||||
|
| metadata | Metadata | |
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
void
|
@ -12,12 +12,13 @@ export interface InstallOptions
|
|||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
| Property | Modifiers | Type | Description | Default |
|
| Property | Modifiers | Type | Description | Default |
|
||||||
| ------------------------ | --------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------ | --------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| baseUrl | <code>optional</code> | string | Determines the host that will be used for downloading. | <p>Either</p><p>- https://storage.googleapis.com/chrome-for-testing-public or - https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central</p> |
|
| baseUrl | <code>optional</code> | string | Determines the host that will be used for downloading. | <p>Either</p><p>- https://storage.googleapis.com/chrome-for-testing-public or - https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central</p> |
|
||||||
| browser | | [Browser](./browsers.browser.md) | Determines which browser to install. | |
|
| browser | | [Browser](./browsers.browser.md) | Determines which browser to install. | |
|
||||||
| buildId | | string | Determines which buildId to download. BuildId should uniquely identify binaries and they are used for caching. | |
|
| buildId | | string | Determines which buildId to download. BuildId should uniquely identify binaries and they are used for caching. | |
|
||||||
| cacheDir | | string | Determines the path to download browsers to. | |
|
| buildIdAlias | <code>optional</code> | string | An alias for the provided <code>buildId</code>. It will be used to maintain local metadata to support aliases in the <code>launch</code> command. | |
|
||||||
| downloadProgressCallback | <code>optional</code> | (downloadedBytes: number, totalBytes: number) => void | Provides information about the progress of the download. | |
|
| cacheDir | | string | Determines the path to download browsers to. | |
|
||||||
| platform | <code>optional</code> | [BrowserPlatform](./browsers.browserplatform.md) | Determines which platform the browser will be suited for. | **Auto-detected.** |
|
| downloadProgressCallback | <code>optional</code> | (downloadedBytes: number, totalBytes: number) => void | Provides information about the progress of the download. | |
|
||||||
| unpack | <code>optional</code> | boolean | Whether to unpack and install browser archives. | <code>true</code> |
|
| platform | <code>optional</code> | [BrowserPlatform](./browsers.browserplatform.md) | Determines which platform the browser will be suited for. | **Auto-detected.** |
|
||||||
|
| unpack | <code>optional</code> | boolean | Whether to unpack and install browser archives. | <code>true</code> |
|
||||||
|
@ -238,6 +238,7 @@ export class CLI {
|
|||||||
}
|
}
|
||||||
args.browser.buildId = pinnedVersion;
|
args.browser.buildId = pinnedVersion;
|
||||||
}
|
}
|
||||||
|
const originalBuildId = args.browser.buildId;
|
||||||
args.browser.buildId = await resolveBuildId(
|
args.browser.buildId = await resolveBuildId(
|
||||||
args.browser.name,
|
args.browser.name,
|
||||||
args.platform,
|
args.platform,
|
||||||
@ -253,6 +254,10 @@ export class CLI {
|
|||||||
args.browser.buildId
|
args.browser.buildId
|
||||||
),
|
),
|
||||||
baseUrl: args.baseUrl,
|
baseUrl: args.baseUrl,
|
||||||
|
buildIdAlias:
|
||||||
|
originalBuildId !== args.browser.buildId
|
||||||
|
? originalBuildId
|
||||||
|
: undefined,
|
||||||
});
|
});
|
||||||
console.log(
|
console.log(
|
||||||
`${args.browser.name}@${
|
`${args.browser.name}@${
|
||||||
|
@ -8,13 +8,18 @@ import fs from 'fs';
|
|||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
import debug from 'debug';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Browser,
|
Browser,
|
||||||
type BrowserPlatform,
|
type BrowserPlatform,
|
||||||
executablePathByBrowser,
|
executablePathByBrowser,
|
||||||
|
getVersionComparator,
|
||||||
} from './browser-data/browser-data.js';
|
} from './browser-data/browser-data.js';
|
||||||
import {detectBrowserPlatform} from './detectPlatform.js';
|
import {detectBrowserPlatform} from './detectPlatform.js';
|
||||||
|
|
||||||
|
const debugCache = debug('puppeteer:browsers:cache');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -57,6 +62,14 @@ export class InstalledBrowser {
|
|||||||
this.buildId
|
this.buildId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readMetadata(): Metadata {
|
||||||
|
return this.#cache.readMetadata(this.browser);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeMetadata(metadata: Metadata): void {
|
||||||
|
this.#cache.writeMetadata(this.browser, metadata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,6 +93,11 @@ export interface ComputeExecutablePathOptions {
|
|||||||
buildId: string;
|
buildId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Metadata {
|
||||||
|
// Maps an alias (canary/latest/dev/etc.) to a buildId.
|
||||||
|
aliases: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cache used by Puppeteer relies on the following structure:
|
* The cache used by Puppeteer relies on the following structure:
|
||||||
*
|
*
|
||||||
@ -112,6 +130,39 @@ export class Cache {
|
|||||||
return path.join(this.#rootDir, browser);
|
return path.join(this.#rootDir, browser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metadataFile(browser: Browser): string {
|
||||||
|
return path.join(this.browserRoot(browser), '.metadata');
|
||||||
|
}
|
||||||
|
|
||||||
|
readMetadata(browser: Browser): Metadata {
|
||||||
|
const metatadaPath = this.metadataFile(browser);
|
||||||
|
if (!fs.existsSync(metatadaPath)) {
|
||||||
|
return {aliases: {}};
|
||||||
|
}
|
||||||
|
// TODO: add type-safe parsing.
|
||||||
|
const data = JSON.parse(fs.readFileSync(metatadaPath, 'utf8'));
|
||||||
|
if (typeof data !== 'object') {
|
||||||
|
throw new Error('.metadata is not an object');
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeMetadata(browser: Browser, metadata: Metadata): void {
|
||||||
|
const metatadaPath = this.metadataFile(browser);
|
||||||
|
fs.mkdirSync(path.dirname(metatadaPath), {recursive: true});
|
||||||
|
fs.writeFileSync(metatadaPath, JSON.stringify(metadata, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveAlias(browser: Browser, alias: string): string | undefined {
|
||||||
|
const metadata = this.readMetadata(browser);
|
||||||
|
if (alias === 'latest') {
|
||||||
|
return Object.values(metadata.aliases || {})
|
||||||
|
.sort(getVersionComparator(browser))
|
||||||
|
.at(-1);
|
||||||
|
}
|
||||||
|
return metadata.aliases[alias];
|
||||||
|
}
|
||||||
|
|
||||||
installationDir(
|
installationDir(
|
||||||
browser: Browser,
|
browser: Browser,
|
||||||
platform: BrowserPlatform,
|
platform: BrowserPlatform,
|
||||||
@ -134,6 +185,12 @@ export class Cache {
|
|||||||
platform: BrowserPlatform,
|
platform: BrowserPlatform,
|
||||||
buildId: string
|
buildId: string
|
||||||
): void {
|
): void {
|
||||||
|
const metadata = this.readMetadata(browser);
|
||||||
|
for (const alias of Object.keys(metadata.aliases)) {
|
||||||
|
if (metadata.aliases[alias] === buildId) {
|
||||||
|
delete metadata.aliases[alias];
|
||||||
|
}
|
||||||
|
}
|
||||||
fs.rmSync(this.installationDir(browser, platform, buildId), {
|
fs.rmSync(this.installationDir(browser, platform, buildId), {
|
||||||
force: true,
|
force: true,
|
||||||
recursive: true,
|
recursive: true,
|
||||||
@ -180,6 +237,12 @@ export class Cache {
|
|||||||
`Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})`
|
`Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
options.buildId =
|
||||||
|
this.resolveAlias(options.browser, options.buildId) ?? options.buildId;
|
||||||
|
} catch {
|
||||||
|
debugCache('could not read .metadata file for the browser');
|
||||||
|
}
|
||||||
const installationDir = this.installationDir(
|
const installationDir = this.installationDir(
|
||||||
options.browser,
|
options.browser,
|
||||||
options.platform,
|
options.platform,
|
||||||
|
@ -62,6 +62,13 @@ export interface InstallOptions {
|
|||||||
* binaries and they are used for caching.
|
* binaries and they are used for caching.
|
||||||
*/
|
*/
|
||||||
buildId: string;
|
buildId: string;
|
||||||
|
/**
|
||||||
|
* An alias for the provided `buildId`. It will be used to maintain local
|
||||||
|
* metadata to support aliases in the `launch` command.
|
||||||
|
*
|
||||||
|
* @example 'canary'
|
||||||
|
*/
|
||||||
|
buildIdAlias?: string;
|
||||||
/**
|
/**
|
||||||
* Provides information about the progress of the download.
|
* Provides information about the progress of the download.
|
||||||
*/
|
*/
|
||||||
@ -233,17 +240,23 @@ async function installUrl(
|
|||||||
} finally {
|
} finally {
|
||||||
debugTimeEnd('extract');
|
debugTimeEnd('extract');
|
||||||
}
|
}
|
||||||
|
const installedBrowser = new InstalledBrowser(
|
||||||
|
cache,
|
||||||
|
options.browser,
|
||||||
|
options.buildId,
|
||||||
|
options.platform
|
||||||
|
);
|
||||||
|
if (options.buildIdAlias) {
|
||||||
|
const metadata = installedBrowser.readMetadata();
|
||||||
|
metadata.aliases[options.buildIdAlias] = options.buildId;
|
||||||
|
installedBrowser.writeMetadata(metadata);
|
||||||
|
}
|
||||||
|
return installedBrowser;
|
||||||
} finally {
|
} finally {
|
||||||
if (existsSync(archivePath)) {
|
if (existsSync(archivePath)) {
|
||||||
await unlink(archivePath);
|
await unlink(archivePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new InstalledBrowser(
|
|
||||||
cache,
|
|
||||||
options.browser,
|
|
||||||
options.buildId,
|
|
||||||
options.platform
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
72
packages/browsers/test/src/Cache.spec.ts
Normal file
72
packages/browsers/test/src/Cache.spec.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2024 Google Inc.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import assert from 'assert';
|
||||||
|
import fs from 'fs';
|
||||||
|
import os from 'os';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import {Browser, Cache} from '../../lib/cjs/main.js';
|
||||||
|
|
||||||
|
describe('Cache', () => {
|
||||||
|
let tmpDir = '/tmp/puppeteer-browsers-test';
|
||||||
|
let cache: Cache;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'puppeteer-browsers-test'));
|
||||||
|
cache = new Cache(tmpDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
cache.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('return empty metadata if .metadata file does not exist', async function () {
|
||||||
|
assert.deepStrictEqual(cache.readMetadata(Browser.CHROME), {
|
||||||
|
aliases: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throw an error if .metadata is malformed', async function () {
|
||||||
|
// @ts-expect-error wrong type on purpose;
|
||||||
|
cache.writeMetadata(Browser.CHROME, 'metadata');
|
||||||
|
assert.throws(() => {
|
||||||
|
return cache.readMetadata(Browser.CHROME);
|
||||||
|
}, new Error(`.metadata is not an object`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('writes and reads .metadata', async function () {
|
||||||
|
cache.writeMetadata(Browser.CHROME, {
|
||||||
|
aliases: {
|
||||||
|
canary: '123.0.0.0',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.deepStrictEqual(cache.readMetadata(Browser.CHROME), {
|
||||||
|
aliases: {
|
||||||
|
canary: '123.0.0.0',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
cache.resolveAlias(Browser.CHROME, 'canary'),
|
||||||
|
'123.0.0.0'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves latest', async function () {
|
||||||
|
cache.writeMetadata(Browser.CHROME, {
|
||||||
|
aliases: {
|
||||||
|
canary: '115.0.5789',
|
||||||
|
stable: '114.0.5789',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
cache.resolveAlias(Browser.CHROME, 'latest'),
|
||||||
|
'115.0.5789'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -74,6 +74,8 @@ export async function downloadBrowser(): Promise<void> {
|
|||||||
buildId,
|
buildId,
|
||||||
downloadProgressCallback: makeProgressCallback(browser, buildId),
|
downloadProgressCallback: makeProgressCallback(browser, buildId),
|
||||||
baseUrl: downloadBaseUrl,
|
baseUrl: downloadBaseUrl,
|
||||||
|
buildIdAlias:
|
||||||
|
buildId !== unresolvedBuildId ? unresolvedBuildId : undefined,
|
||||||
})
|
})
|
||||||
.then(result => {
|
.then(result => {
|
||||||
logPolitely(
|
logPolitely(
|
||||||
@ -112,6 +114,10 @@ export async function downloadBrowser(): Promise<void> {
|
|||||||
shellBuildId
|
shellBuildId
|
||||||
),
|
),
|
||||||
baseUrl: downloadBaseUrl,
|
baseUrl: downloadBaseUrl,
|
||||||
|
buildIdAlias:
|
||||||
|
shellBuildId !== unresolvedShellBuildId
|
||||||
|
? unresolvedShellBuildId
|
||||||
|
: undefined,
|
||||||
})
|
})
|
||||||
.then(result => {
|
.then(result => {
|
||||||
logPolitely(
|
logPolitely(
|
||||||
|
Loading…
Reference in New Issue
Block a user