@@ -24,6 +24,7 @@ const accessAsync = util.promisify(fs.access.bind(fs));
24
24
const checkExecutable = ( filePath : string ) => accessAsync ( filePath , fs . constants . X_OK ) . then ( ( ) => true ) . catch ( e => false ) ;
25
25
const statAsync = util . promisify ( fs . stat . bind ( fs ) ) ;
26
26
const readdirAsync = util . promisify ( fs . readdir . bind ( fs ) ) ;
27
+ const readFileAsync = util . promisify ( fs . readFile . bind ( fs ) ) ;
27
28
28
29
export async function validateDependencies ( browserPath : string , browser : BrowserDescriptor ) {
29
30
// We currently only support Linux.
@@ -34,15 +35,49 @@ export async function validateDependencies(browserPath: string, browser: Browser
34
35
for ( const directoryPath of directoryPaths )
35
36
lddPaths . push ( ...( await executablesOrSharedLibraries ( directoryPath ) ) ) ;
36
37
const allMissingDeps = await Promise . all ( lddPaths . map ( lddPath => missingFileDependencies ( lddPath ) ) ) ;
37
- const missingDeps = new Set ( ) ;
38
+ const missingDeps : Set < string > = new Set ( ) ;
38
39
for ( const deps of allMissingDeps ) {
39
40
for ( const dep of deps )
40
41
missingDeps . add ( dep ) ;
41
42
}
42
43
if ( ! missingDeps . size )
43
44
return ;
44
- const deps = [ ...missingDeps ] . sort ( ) . map ( dep => ' ' + dep ) . join ( '\n' ) ;
45
- throw new Error ( 'Host system is missing the following dependencies to run browser\n' + deps ) ;
45
+ // Check Ubuntu version.
46
+ const missingPackages = new Set ( ) ;
47
+ const osRelease = await readFileAsync ( '/etc/os-release' , 'utf8' ) . catch ( e => '' ) ;
48
+ const [ ubuntuName = '' , ubuntuVersion = '' ] = osRelease . trim ( ) . split ( '\n' ) ;
49
+ if ( ubuntuName . toLowerCase ( ) . includes ( 'ubuntu' ) && ubuntuVersion . includes ( '18.04' ) ) {
50
+ // Translate missing dependencies to package names to install with apt.
51
+ for ( const missingDep of missingDeps ) {
52
+ const packageName = LIBRARY_TO_PACKAGE_NAME_UBUNTU_18_04 [ missingDep ] ;
53
+ if ( packageName ) {
54
+ missingPackages . add ( packageName ) ;
55
+ missingDeps . delete ( missingDep ) ;
56
+ }
57
+ }
58
+ }
59
+
60
+ let missingPackagesMessage = ''
61
+ if ( missingPackages . size ) {
62
+ missingPackagesMessage = [
63
+ ` Install missing packages with:` ,
64
+ ` apt-get install -y ${ [ ...missingPackages ] . join ( ' ' ) } ` ,
65
+ `` ,
66
+ `` ,
67
+ ] . join ( '\n' ) ;
68
+ }
69
+
70
+ let missingDependenciesMessage = '' ;
71
+ if ( missingDeps . size ) {
72
+ const header = missingPackages . size ? `Missing libraries we don't know packages for:` : `Missing libraries are:` ;
73
+ missingDependenciesMessage = [
74
+ ` ${ header } ` ,
75
+ ` ${ [ ...missingDeps ] . join ( ' ' ) } ` ,
76
+ `` ,
77
+ ] . join ( '\n' ) ;
78
+ }
79
+
80
+ throw new Error ( 'Host system is missing dependencies!\n\n' + missingPackagesMessage + missingDependenciesMessage ) ;
46
81
}
47
82
48
83
async function executablesOrSharedLibraries ( directoryPath : string ) : Promise < string [ ] > {
@@ -86,3 +121,88 @@ function lddAsync(filePath: string): Promise<{stdout: string, stderr: string, co
86
121
ldd . on ( 'close' , code => resolve ( { stdout, stderr, code} ) ) ;
87
122
} ) ;
88
123
}
124
+
125
+ const LIBRARY_TO_PACKAGE_NAME_UBUNTU_18_04 : { [ s : string ] : string } = {
126
+ 'libEGL.so.1' : 'libegl1' ,
127
+ 'libGL.so.1' : 'libgl1' ,
128
+ 'libX11-xcb.so.1' : 'libx11-xcb1' ,
129
+ 'libX11.so.6' : 'libx11-6' ,
130
+ 'libXcomposite.so.1' : 'libxcomposite1' ,
131
+ 'libXcursor.so.1' : 'libxcursor1' ,
132
+ 'libXdamage.so.1' : 'libxdamage1' ,
133
+ 'libXext.so.6' : 'libxext6' ,
134
+ 'libXfixes.so.3' : 'libxfixes3' ,
135
+ 'libXi.so.6' : 'libxi6' ,
136
+ 'libXrandr.so.2' : 'libxrandr2' ,
137
+ 'libXrender.so.1' : 'libxrender1' ,
138
+ 'libXt.so.6' : 'libxt6' ,
139
+ 'libXtst.so.6' : 'libxtst6' ,
140
+ 'libasound.so.2' : 'libasound2' ,
141
+ 'libatk-1.0.so.0' : 'libatk1.0-0' ,
142
+ 'libatk-bridge-2.0.so.0' : 'libatk-bridge2.0-0' ,
143
+ 'libatspi.so.0' : 'libatspi2.0-0' ,
144
+ 'libbrotlidec.so.1' : 'libbrotli1' ,
145
+ 'libcairo-gobject.so.2' : 'libcairo-gobject2' ,
146
+ 'libcairo.so.2' : 'libcairo2' ,
147
+ 'libcups.so.2' : 'libcups2' ,
148
+ 'libdbus-1.so.3' : 'libdbus-1-3' ,
149
+ 'libdbus-glib-1.so.2' : 'libdbus-glib-1-2' ,
150
+ 'libdrm.so.2' : 'libdrm2' ,
151
+ 'libenchant.so.1' : 'libenchant1c2a' ,
152
+ 'libepoxy.so.0' : 'libepoxy0' ,
153
+ 'libfontconfig.so.1' : 'libfontconfig1' ,
154
+ 'libfreetype.so.6' : 'libfreetype6' ,
155
+ 'libgbm.so.1' : 'libgbm1' ,
156
+ 'libgdk-3.so.0' : 'libgtk-3-0' ,
157
+ 'libgdk-x11-2.0.so.0' : 'libgtk2.0-0' ,
158
+ 'libgdk_pixbuf-2.0.so.0' : 'libgdk-pixbuf2.0-0' ,
159
+ 'libgio-2.0.so.0' : 'libglib2.0-0' ,
160
+ 'libglib-2.0.so.0' : 'libglib2.0-0' ,
161
+ 'libgmodule-2.0.so.0' : 'libglib2.0-0' ,
162
+ 'libgobject-2.0.so.0' : 'libglib2.0-0' ,
163
+ 'libgstapp-1.0.so.0' : 'libgstreamer-plugins-base1.0-0' ,
164
+ 'libgstaudio-1.0.so.0' : 'libgstreamer-plugins-base1.0-0' ,
165
+ 'libgstbase-1.0.so.0' : 'libgstreamer1.0-0' ,
166
+ 'libgstcodecparsers-1.0.so.0' : 'libgstreamer-plugins-bad1.0-0' ,
167
+ 'libgstfft-1.0.so.0' : 'libgstreamer-plugins-base1.0-0' ,
168
+ 'libgstgl-1.0.so.0' : 'libgstreamer-gl1.0-0' ,
169
+ 'libgstpbutils-1.0.so.0' : 'libgstreamer-plugins-base1.0-0' ,
170
+ 'libgstreamer-1.0.so.0' : 'libgstreamer1.0-0' ,
171
+ 'libgsttag-1.0.so.0' : 'libgstreamer-plugins-base1.0-0' ,
172
+ 'libgstvideo-1.0.so.0' : 'libgstreamer-plugins-base1.0-0' ,
173
+ 'libgthread-2.0.so.0' : 'libglib2.0-0' ,
174
+ 'libgtk-3.so.0' : 'libgtk-3-0' ,
175
+ 'libgtk-x11-2.0.so.0' : 'libgtk2.0-0' ,
176
+ 'libharfbuzz-icu.so.0' : 'libharfbuzz-icu0' ,
177
+ 'libharfbuzz.so.0' : 'libharfbuzz0b' ,
178
+ 'libhyphen.so.0' : 'libhyphen0' ,
179
+ 'libicui18n.so.60' : 'libicu60' ,
180
+ 'libicuuc.so.60' : 'libicu60' ,
181
+ 'libjpeg.so.8' : 'libjpeg-turbo8' ,
182
+ 'libnotify.so.4' : 'libnotify4' ,
183
+ 'libnspr4.so' : 'libnspr4' ,
184
+ 'libnss3.so' : 'libnss3' ,
185
+ 'libnssutil3.so' : 'libnss3' ,
186
+ 'libopenjp2.so.7' : 'libopenjp2-7' ,
187
+ 'libopus.so.0' : 'libopus0' ,
188
+ 'libpango-1.0.so.0' : 'libpango-1.0-0' ,
189
+ 'libpangocairo-1.0.so.0' : 'libpangocairo-1.0-0' ,
190
+ 'libpangoft2-1.0.so.0' : 'libpangoft2-1.0-0' ,
191
+ 'libpng16.so.16' : 'libpng16-16' ,
192
+ 'libsecret-1.so.0' : 'libsecret-1-0' ,
193
+ 'libsmime3.so' : 'libnss3' ,
194
+ 'libssl3.so' : 'libnss3' ,
195
+ 'libwayland-client.so.0' : 'libwayland-client0' ,
196
+ 'libwayland-egl.so.1' : 'libwayland-egl1' ,
197
+ 'libwayland-server.so.0' : 'libwayland-server0' ,
198
+ 'libwebp.so.6' : 'libwebp6' ,
199
+ 'libwebpdemux.so.2' : 'libwebpdemux2' ,
200
+ 'libwoff2dec.so.1.0.2' : 'libwoff1' ,
201
+ 'libxcb-dri3.so.0' : 'libxcb-dri3-0' ,
202
+ 'libxcb-shm.so.0' : 'libxcb-shm0' ,
203
+ 'libxcb.so.1' : 'libxcb1' ,
204
+ 'libxkbcommon.so.0' : 'libxkbcommon0' ,
205
+ 'libxml2.so.2' : 'libxml2' ,
206
+ 'libxslt.so.1' : 'libxslt1.1' ,
207
+ } ;
208
+
0 commit comments