blob: e4cfac6f052100f2665138841bb8ff0bd1339a47 [file] [log] [blame]
Randolf Jungbcb3bc82023-06-26 16:30:141/**
2 * Copyright 2023 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Randolf Jungbcb3bc82023-06-26 16:30:1416import fs from 'fs';
Alex Rudenkof7ea7ab2023-10-24 09:40:5117import os from 'os';
Randolf Jungbcb3bc82023-06-26 16:30:1418import path from 'path';
Alex Rudenkof7ea7ab2023-10-24 09:40:5119import { Browser, executablePathByBrowser, } from './browser-data/browser-data.js';
20import { detectBrowserPlatform } from './detectPlatform.js';
Randolf Jung3e526312023-08-08 06:20:3921/**
22 * @public
23 */
24export class InstalledBrowser {
25 browser;
26 buildId;
27 platform;
Alex Rudenkof7ea7ab2023-10-24 09:40:5128 executablePath;
Randolf Jung3e526312023-08-08 06:20:3929 #cache;
30 /**
31 * @internal
32 */
33 constructor(cache, browser, buildId, platform) {
34 this.#cache = cache;
35 this.browser = browser;
36 this.buildId = buildId;
37 this.platform = platform;
Alex Rudenkof7ea7ab2023-10-24 09:40:5138 this.executablePath = cache.computeExecutablePath({
39 browser,
40 buildId,
41 platform,
42 });
Randolf Jung3e526312023-08-08 06:20:3943 }
44 /**
45 * Path to the root of the installation folder. Use
46 * {@link computeExecutablePath} to get the path to the executable binary.
47 */
48 get path() {
49 return this.#cache.installationDir(this.browser, this.platform, this.buildId);
50 }
Randolf Jung3e526312023-08-08 06:20:3951}
Randolf Jungbcb3bc82023-06-26 16:30:1452/**
53 * The cache used by Puppeteer relies on the following structure:
54 *
55 * - rootDir
56 * -- <browser1> | browserRoot(browser1)
57 * ---- <platform>-<buildId> | installationDir()
58 * ------ the browser-platform-buildId
59 * ------ specific structure.
60 * -- <browser2> | browserRoot(browser2)
61 * ---- <platform>-<buildId> | installationDir()
62 * ------ the browser-platform-buildId
63 * ------ specific structure.
64 * @internal
65 */
66export class Cache {
Randolf Jung3e526312023-08-08 06:20:3967 #rootDir;
Randolf Jungbcb3bc82023-06-26 16:30:1468 constructor(rootDir) {
Randolf Jung3e526312023-08-08 06:20:3969 this.#rootDir = rootDir;
70 }
71 /**
72 * @internal
73 */
74 get rootDir() {
75 return this.#rootDir;
Randolf Jungbcb3bc82023-06-26 16:30:1476 }
77 browserRoot(browser) {
Randolf Jung3e526312023-08-08 06:20:3978 return path.join(this.#rootDir, browser);
Randolf Jungbcb3bc82023-06-26 16:30:1479 }
80 installationDir(browser, platform, buildId) {
81 return path.join(this.browserRoot(browser), `${platform}-${buildId}`);
82 }
83 clear() {
Randolf Jung3e526312023-08-08 06:20:3984 fs.rmSync(this.#rootDir, {
Randolf Jungbcb3bc82023-06-26 16:30:1485 force: true,
86 recursive: true,
87 maxRetries: 10,
88 retryDelay: 500,
89 });
90 }
91 uninstall(browser, platform, buildId) {
92 fs.rmSync(this.installationDir(browser, platform, buildId), {
93 force: true,
94 recursive: true,
95 maxRetries: 10,
96 retryDelay: 500,
97 });
98 }
99 getInstalledBrowsers() {
Randolf Jung3e526312023-08-08 06:20:39100 if (!fs.existsSync(this.#rootDir)) {
Randolf Jungbcb3bc82023-06-26 16:30:14101 return [];
102 }
Randolf Jung3e526312023-08-08 06:20:39103 const types = fs.readdirSync(this.#rootDir);
Randolf Jungbcb3bc82023-06-26 16:30:14104 const browsers = types.filter((t) => {
105 return Object.values(Browser).includes(t);
106 });
107 return browsers.flatMap(browser => {
108 const files = fs.readdirSync(this.browserRoot(browser));
109 return files
110 .map(file => {
111 const result = parseFolderPath(path.join(this.browserRoot(browser), file));
112 if (!result) {
113 return null;
114 }
Randolf Jung3e526312023-08-08 06:20:39115 return new InstalledBrowser(this, browser, result.buildId, result.platform);
Randolf Jungbcb3bc82023-06-26 16:30:14116 })
117 .filter((item) => {
118 return item !== null;
119 });
120 });
121 }
Alex Rudenkof7ea7ab2023-10-24 09:40:51122 computeExecutablePath(options) {
123 options.platform ??= detectBrowserPlatform();
124 if (!options.platform) {
125 throw new Error(`Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})`);
126 }
127 const installationDir = this.installationDir(options.browser, options.platform, options.buildId);
128 return path.join(installationDir, executablePathByBrowser[options.browser](options.platform, options.buildId));
129 }
Randolf Jungbcb3bc82023-06-26 16:30:14130}
Randolf Jungbcb3bc82023-06-26 16:30:14131function parseFolderPath(folderPath) {
132 const name = path.basename(folderPath);
133 const splits = name.split('-');
134 if (splits.length !== 2) {
135 return;
136 }
137 const [platform, buildId] = splits;
138 if (!buildId || !platform) {
139 return;
140 }
141 return { platform, buildId };
142}
143//# sourceMappingURL=Cache.js.map