11import type { BrowserPlatform } from "@puppeteer/browsers" ;
2- import { readJSONSync , outputJSONSync , existsSync } from "fs-extra" ;
2+ import _ from "lodash" ;
3+ import { outputJSONSync } from "fs-extra" ;
34import path from "path" ;
45import {
56 getRegistryPath ,
7+ readRegistry ,
68 browserInstallerDebug ,
79 Driver ,
810 Browser ,
@@ -12,87 +14,123 @@ import {
1214 type SupportedBrowser ,
1315 type SupportedDriver ,
1416 type DownloadProgressCallback ,
17+ type BinaryKey ,
18+ type BinaryName ,
19+ type OsName ,
20+ type OsVersion ,
21+ type OsPackagesKey ,
1522} from "../utils" ;
1623import { getFirefoxBuildId } from "../firefox/utils" ;
1724import logger from "../../utils/logger" ;
18- import type { createBrowserDownloadProgressBar } from "./cli-progress-bar" ;
19-
20- type VersionToPathMap = Record < string , string | Promise < string > > ;
21- type BinaryName = Exclude < SupportedBrowser | SupportedDriver , SupportedBrowser & SupportedDriver > ;
22- type RegistryKey = `${BinaryName } _${BrowserPlatform } `;
23- type Registry = Record < RegistryKey , VersionToPathMap > ;
2425
2526const registryPath = getRegistryPath ( ) ;
26- const registry : Registry = existsSync ( registryPath ) ? readJSONSync ( registryPath ) : { } ;
27+ const registry = readRegistry ( registryPath ) ;
28+
29+ const getRegistryBinaryKey = ( name : BinaryName , platform : BrowserPlatform ) : BinaryKey => `${ name } _${ platform } ` ;
30+ const getRegistryOsPackagesKey = ( name : OsName , version : OsVersion ) : OsPackagesKey => `${ name } _${ version } ` ;
2731
28- let cliProgressBar : ReturnType < typeof createBrowserDownloadProgressBar > | null = null ;
29- let warnedFirstTimeInstall = false ;
32+ const saveRegistry = ( ) : void => {
33+ const replacer = ( _ : string , value : unknown ) : unknown | undefined => {
34+ if ( ( value as Promise < unknown > ) . then ) {
35+ return ;
36+ }
3037
31- const getRegistryKey = ( name : BinaryName , platform : BrowserPlatform ) : RegistryKey => `${ name } _${ platform } ` ;
38+ return value ;
39+ } ;
40+
41+ outputJSONSync ( registryPath , registry , { replacer } ) ;
42+ } ;
43+
44+ const getCliProgressBar = _ . once ( async ( ) => {
45+ const { createBrowserDownloadProgressBar } = await import ( "./cli-progress-bar" ) ;
46+
47+ return createBrowserDownloadProgressBar ( ) ;
48+ } ) ;
3249
3350export const getBinaryPath = async ( name : BinaryName , platform : BrowserPlatform , version : string ) : Promise < string > => {
34- const registryKey = getRegistryKey ( name , platform ) ;
51+ const registryKey = getRegistryBinaryKey ( name , platform ) ;
3552
36- if ( ! registry [ registryKey ] ) {
53+ if ( ! registry . binaries [ registryKey ] ) {
3754 throw new Error ( `Binary '${ name } ' on '${ platform } ' is not installed` ) ;
3855 }
3956
40- if ( ! registry [ registryKey ] [ version ] ) {
57+ if ( ! registry . binaries [ registryKey ] [ version ] ) {
4158 throw new Error ( `Version '${ version } ' of driver '${ name } ' on '${ platform } ' is not installed` ) ;
4259 }
4360
44- const binaryRelativePath = await registry [ registryKey ] [ version ] ;
61+ const binaryRelativePath = await registry . binaries [ registryKey ] [ version ] ;
4562
4663 browserInstallerDebug ( `resolved '${ name } @${ version } ' on ${ platform } to ${ binaryRelativePath } ` ) ;
4764
4865 return path . resolve ( registryPath , binaryRelativePath ) ;
4966} ;
5067
68+ export const getOsPackagesPath = async ( name : OsName , version : OsVersion ) : Promise < string > => {
69+ const registryKey = getRegistryOsPackagesKey ( name , version ) ;
70+
71+ if ( ! registry . osPackages [ registryKey ] ) {
72+ throw new Error ( `Packages for ${ name } @${ version } are not installed` ) ;
73+ }
74+
75+ const osPackagesRelativePath = await registry . osPackages [ registryKey ] ;
76+
77+ browserInstallerDebug ( `resolved os packages for '${ name } @${ version } ' to ${ osPackagesRelativePath } ` ) ;
78+
79+ return path . resolve ( registryPath , osPackagesRelativePath ) ;
80+ } ;
81+
5182const addBinaryToRegistry = (
5283 name : BinaryName ,
5384 platform : BrowserPlatform ,
5485 version : string ,
5586 absoluteBinaryPath : string ,
5687) : void => {
57- const registryKey = getRegistryKey ( name , platform ) ;
88+ const registryKey = getRegistryBinaryKey ( name , platform ) ;
5889 const relativePath = path . relative ( registryPath , absoluteBinaryPath ) ;
5990
60- registry [ registryKey ] ||= { } ;
61- registry [ registryKey ] [ version ] = relativePath ;
91+ registry . binaries [ registryKey ] ||= { } ;
92+ registry . binaries [ registryKey ] [ version ] = relativePath ;
6293
63- const replacer = ( _ : string , value : unknown ) : unknown | undefined => {
64- if ( ( value as Promise < unknown > ) . then ) {
65- return ;
66- }
94+ browserInstallerDebug ( `adding '${ name } @${ version } ' on '${ platform } ' to registry at ${ relativePath } ` ) ;
6795
68- return value ;
69- } ;
96+ saveRegistry ( ) ;
97+ } ;
7098
71- browserInstallerDebug ( `adding '${ name } @${ version } ' on '${ platform } ' to registry at ${ relativePath } ` ) ;
72- outputJSONSync ( registryPath , registry , { replacer } ) ;
99+ const addOsPackageToRegistry = ( name : OsName , version : OsVersion , absolutePackagesDirPath : string ) : void => {
100+ const registryKey = getRegistryOsPackagesKey ( name , version ) ;
101+ const relativePath = path . relative ( registryPath , absolutePackagesDirPath ) ;
102+
103+ registry . osPackages [ registryKey ] = relativePath ;
104+
105+ browserInstallerDebug ( `adding os packages for '${ name } @${ version } ' to registry at ${ relativePath } ` ) ;
106+
107+ saveRegistry ( ) ;
73108} ;
74109
75110const getBinaryVersions = ( name : BinaryName , platform : BrowserPlatform ) : string [ ] => {
76- const registryKey = getRegistryKey ( name , platform ) ;
111+ const registryKey = getRegistryBinaryKey ( name , platform ) ;
77112
78- if ( ! registry [ registryKey ] ) {
113+ if ( ! registry . binaries [ registryKey ] ) {
79114 return [ ] ;
80115 }
81116
82- return Object . keys ( registry [ registryKey ] ) ;
117+ return Object . keys ( registry . binaries [ registryKey ] ) ;
83118} ;
84119
85120const hasBinaryVersion = ( name : BinaryName , platform : BrowserPlatform , version : string ) : boolean =>
86121 getBinaryVersions ( name , platform ) . includes ( version ) ;
87122
123+ export const hasOsPackages = ( name : OsName , version : OsVersion ) : boolean =>
124+ Boolean ( registry . osPackages [ getRegistryOsPackagesKey ( name , version ) ] ) ;
125+
88126export const getMatchedDriverVersion = (
89127 driverName : SupportedDriver ,
90128 platform : BrowserPlatform ,
91129 browserVersion : string ,
92130) : string | null => {
93- const registryKey = getRegistryKey ( driverName , platform ) ;
131+ const registryKey = getRegistryBinaryKey ( driverName , platform ) ;
94132
95- if ( ! registry [ registryKey ] ) {
133+ if ( ! registry . binaries [ registryKey ] ) {
96134 return null ;
97135 }
98136
@@ -109,7 +147,7 @@ export const getMatchedDriverVersion = (
109147 }
110148
111149 if ( driverName === Driver . GECKODRIVER ) {
112- const buildIds = Object . keys ( registry [ registryKey ] ) ;
150+ const buildIds = Object . keys ( registry . binaries [ registryKey ] ) ;
113151 const buildIdsSorted = buildIds . sort ( semverVersionsComparator ) ;
114152
115153 return buildIdsSorted . length ? buildIdsSorted [ buildIdsSorted . length - 1 ] : null ;
@@ -123,9 +161,9 @@ export const getMatchedBrowserVersion = (
123161 platform : BrowserPlatform ,
124162 browserVersion : string ,
125163) : string | null => {
126- const registryKey = getRegistryKey ( browserName , platform ) ;
164+ const registryKey = getRegistryBinaryKey ( browserName , platform ) ;
127165
128- if ( ! registry [ registryKey ] ) {
166+ if ( ! registry . binaries [ registryKey ] ) {
129167 return null ;
130168 }
131169
@@ -170,46 +208,88 @@ export const getMatchedBrowserVersion = (
170208 return suitableBuildIdsSorted [ suitableBuildIdsSorted . length - 1 ] ;
171209} ;
172210
211+ const logDownloadingOsPackagesWarningOnce = _ . once ( ( osName : string ) => {
212+ logger . warn ( `Downloading extra ${ osName } packages` ) ;
213+ } ) ;
214+
215+ const logDownloadingBrowsersWarningOnce = _ . once ( ( ) => {
216+ logger . warn ( "Downloading Testplane browsers" ) ;
217+ logger . warn ( "Note: this is one-time action. It may take a while..." ) ;
218+ } ) ;
219+
173220export const installBinary = async (
174221 name : BinaryName ,
175222 platform : BrowserPlatform ,
176223 version : string ,
177224 installFn : ( downloadProgressCallback : DownloadProgressCallback ) => Promise < string > ,
178225) : Promise < string > => {
179- const registryKey = getRegistryKey ( name , platform ) ;
226+ const registryKey = getRegistryBinaryKey ( name , platform ) ;
180227
181228 if ( hasBinaryVersion ( name , platform , version ) ) {
182229 return getBinaryPath ( name , platform , version ) ;
183230 }
184231
185232 browserInstallerDebug ( `installing '${ name } @${ version } ' on '${ platform } '` ) ;
186233
187- if ( ! cliProgressBar ) {
188- const { createBrowserDownloadProgressBar } = await import ( "./cli-progress-bar" ) ;
234+ const progressBar = await getCliProgressBar ( ) ;
189235
190- cliProgressBar = createBrowserDownloadProgressBar ( ) ;
191- }
192-
193- const originalDownloadProgressCallback = cliProgressBar . register ( name , version ) ;
236+ const originalDownloadProgressCallback = progressBar . register ( name , version ) ;
194237 const downloadProgressCallback : DownloadProgressCallback = ( ...args ) => {
195- if ( ! warnedFirstTimeInstall ) {
196- logger . warn ( "Downloading Testplane browsers" ) ;
197- logger . warn ( "Note: this is one-time action. It may take a while..." ) ;
198-
199- warnedFirstTimeInstall = true ;
200- }
238+ logDownloadingBrowsersWarningOnce ( ) ;
201239
202240 return originalDownloadProgressCallback ( ...args ) ;
203241 } ;
204242
205- const installPromise = installFn ( downloadProgressCallback ) . then ( executablePath => {
206- addBinaryToRegistry ( name , platform , version , executablePath ) ;
243+ const installPromise = installFn ( downloadProgressCallback )
244+ . then ( executablePath => {
245+ addBinaryToRegistry ( name , platform , version , executablePath ) ;
246+
247+ return executablePath ;
248+ } )
249+ . catch ( err => {
250+ progressBar ?. stop ( ) ;
251+
252+ throw err ;
253+ } ) ;
254+
255+ registry . binaries [ registryKey ] ||= { } ;
256+ registry . binaries [ registryKey ] [ version ] = installPromise ;
257+
258+ return installPromise ;
259+ } ;
260+
261+ export const installOsPackages = async (
262+ osName : OsName ,
263+ version : OsVersion ,
264+ installFn : ( downloadProgressCallback : DownloadProgressCallback ) => Promise < string > ,
265+ ) : Promise < string > => {
266+ const registryKey = getRegistryOsPackagesKey ( osName , version ) ;
267+
268+ if ( hasOsPackages ( osName , version ) ) {
269+ return getOsPackagesPath ( osName , version ) ;
270+ }
271+
272+ browserInstallerDebug ( `installing os packages for '${ osName } @${ version } '` ) ;
273+
274+ logDownloadingOsPackagesWarningOnce ( osName ) ;
275+
276+ const progressBar = await getCliProgressBar ( ) ;
277+
278+ const downloadProgressCallback = progressBar . register ( `extra packages for ${ osName } ` , version ) ;
279+
280+ const installPromise = installFn ( downloadProgressCallback )
281+ . then ( packagesPath => {
282+ addOsPackageToRegistry ( osName , version , packagesPath ) ;
283+
284+ return packagesPath ;
285+ } )
286+ . catch ( err => {
287+ progressBar . stop ( ) ;
207288
208- return executablePath ;
209- } ) ;
289+ throw err ;
290+ } ) ;
210291
211- registry [ registryKey ] ||= { } ;
212- registry [ registryKey ] [ version ] = installPromise ;
292+ registry . osPackages [ registryKey ] = installPromise ;
213293
214294 return installPromise ;
215295} ;
0 commit comments