Skip to content

Commit c976048

Browse files
committed
devops: show package names instead of missing libs on Ubuntu 18.04
This patch starts putting package names to install on Ubuntu instead of missing dependencies list. The mapping of library to package name is obtained using the following script: https://gist.github.com/aslushnikov/2766200430228c3700537292fccad064 References microsoft#2745
1 parent 91e1a25 commit c976048

File tree

1 file changed

+144
-3
lines changed

1 file changed

+144
-3
lines changed

src/server/validateDependencies.ts

+144-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const accessAsync = util.promisify(fs.access.bind(fs));
2424
const checkExecutable = (filePath: string) => accessAsync(filePath, fs.constants.X_OK).then(() => true).catch(e => false);
2525
const statAsync = util.promisify(fs.stat.bind(fs));
2626
const readdirAsync = util.promisify(fs.readdir.bind(fs));
27+
const readFileAsync = util.promisify(fs.readFile.bind(fs));
2728

2829
export async function validateDependencies(browserPath: string, browser: BrowserDescriptor) {
2930
// We currently only support Linux.
@@ -34,15 +35,49 @@ export async function validateDependencies(browserPath: string, browser: Browser
3435
for (const directoryPath of directoryPaths)
3536
lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
3637
const allMissingDeps = await Promise.all(lddPaths.map(lddPath => missingFileDependencies(lddPath)));
37-
const missingDeps = new Set();
38+
const missingDeps: Set<string> = new Set();
3839
for (const deps of allMissingDeps) {
3940
for (const dep of deps)
4041
missingDeps.add(dep);
4142
}
4243
if (!missingDeps.size)
4344
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+
48+
const ubuntuVersion = await getUbuntuVersion();
49+
if (ubuntuVersion === '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 ${[...missingPackages].join('\\\n ')}`,
65+
``,
66+
``,
67+
].join('\n');
68+
}
69+
70+
let missingDependenciesMessage = '';
71+
if (missingDeps.size) {
72+
const header = missingPackages.size ? `Missing libraries we didn't find packages for:` : `Missing libraries are:`;
73+
missingDependenciesMessage = [
74+
` ${header}`,
75+
` ${[...missingDeps].join('\n ')}`,
76+
``,
77+
].join('\n');
78+
}
79+
80+
throw new Error('Host system is missing dependencies!\n\n' + missingPackagesMessage + missingDependenciesMessage);
4681
}
4782

4883
async function executablesOrSharedLibraries(directoryPath: string): Promise<string[]> {
@@ -86,3 +121,109 @@ function lddAsync(filePath: string): Promise<{stdout: string, stderr: string, co
86121
ldd.on('close', code => resolve({stdout, stderr, code}));
87122
});
88123
}
124+
125+
async function getUbuntuVersion(): Promise<string> {
126+
const osRelease = await readFileAsync('/etc/os-release', 'utf8').catch(e => '');
127+
if (!osRelease)
128+
return '';
129+
const fields = new Map();
130+
for (const line of osRelease.split('\n')) {
131+
const tokens = line.split('=');
132+
const name = tokens.shift();
133+
let value = tokens.join('=').trim();
134+
if (value.startsWith('"') && value.endsWith('"'))
135+
value = value.substring(1, value.length - 1);
136+
if (!name)
137+
continue;
138+
fields.set(name.toLowerCase(), value);
139+
}
140+
if (!fields.get('name') || fields.get('name').toLowerCase() !== 'ubuntu')
141+
return '';
142+
return fields.get('version_id') || '';
143+
}
144+
145+
// This list is generated with https://gist.github.com/aslushnikov/2766200430228c3700537292fccad064
146+
const LIBRARY_TO_PACKAGE_NAME_UBUNTU_18_04: { [s: string]: string} = {
147+
'libEGL.so.1': 'libegl1',
148+
'libGL.so.1': 'libgl1',
149+
'libX11-xcb.so.1': 'libx11-xcb1',
150+
'libX11.so.6': 'libx11-6',
151+
'libXcomposite.so.1': 'libxcomposite1',
152+
'libXcursor.so.1': 'libxcursor1',
153+
'libXdamage.so.1': 'libxdamage1',
154+
'libXext.so.6': 'libxext6',
155+
'libXfixes.so.3': 'libxfixes3',
156+
'libXi.so.6': 'libxi6',
157+
'libXrandr.so.2': 'libxrandr2',
158+
'libXrender.so.1': 'libxrender1',
159+
'libXt.so.6': 'libxt6',
160+
'libXtst.so.6': 'libxtst6',
161+
'libasound.so.2': 'libasound2',
162+
'libatk-1.0.so.0': 'libatk1.0-0',
163+
'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',
164+
'libatspi.so.0': 'libatspi2.0-0',
165+
'libbrotlidec.so.1': 'libbrotli1',
166+
'libcairo-gobject.so.2': 'libcairo-gobject2',
167+
'libcairo.so.2': 'libcairo2',
168+
'libcups.so.2': 'libcups2',
169+
'libdbus-1.so.3': 'libdbus-1-3',
170+
'libdbus-glib-1.so.2': 'libdbus-glib-1-2',
171+
'libdrm.so.2': 'libdrm2',
172+
'libenchant.so.1': 'libenchant1c2a',
173+
'libepoxy.so.0': 'libepoxy0',
174+
'libfontconfig.so.1': 'libfontconfig1',
175+
'libfreetype.so.6': 'libfreetype6',
176+
'libgbm.so.1': 'libgbm1',
177+
'libgdk-3.so.0': 'libgtk-3-0',
178+
'libgdk-x11-2.0.so.0': 'libgtk2.0-0',
179+
'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf2.0-0',
180+
'libgio-2.0.so.0': 'libglib2.0-0',
181+
'libglib-2.0.so.0': 'libglib2.0-0',
182+
'libgmodule-2.0.so.0': 'libglib2.0-0',
183+
'libgobject-2.0.so.0': 'libglib2.0-0',
184+
'libgstapp-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
185+
'libgstaudio-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
186+
'libgstbase-1.0.so.0': 'libgstreamer1.0-0',
187+
'libgstcodecparsers-1.0.so.0': 'libgstreamer-plugins-bad1.0-0',
188+
'libgstfft-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
189+
'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',
190+
'libgstpbutils-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
191+
'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',
192+
'libgsttag-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
193+
'libgstvideo-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
194+
'libgthread-2.0.so.0': 'libglib2.0-0',
195+
'libgtk-3.so.0': 'libgtk-3-0',
196+
'libgtk-x11-2.0.so.0': 'libgtk2.0-0',
197+
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
198+
'libharfbuzz.so.0': 'libharfbuzz0b',
199+
'libhyphen.so.0': 'libhyphen0',
200+
'libicui18n.so.60': 'libicu60',
201+
'libicuuc.so.60': 'libicu60',
202+
'libjpeg.so.8': 'libjpeg-turbo8',
203+
'libnotify.so.4': 'libnotify4',
204+
'libnspr4.so': 'libnspr4',
205+
'libnss3.so': 'libnss3',
206+
'libnssutil3.so': 'libnss3',
207+
'libopenjp2.so.7': 'libopenjp2-7',
208+
'libopus.so.0': 'libopus0',
209+
'libpango-1.0.so.0': 'libpango-1.0-0',
210+
'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',
211+
'libpangoft2-1.0.so.0': 'libpangoft2-1.0-0',
212+
'libpng16.so.16': 'libpng16-16',
213+
'libsecret-1.so.0': 'libsecret-1-0',
214+
'libsmime3.so': 'libnss3',
215+
'libssl3.so': 'libnss3',
216+
'libwayland-client.so.0': 'libwayland-client0',
217+
'libwayland-egl.so.1': 'libwayland-egl1',
218+
'libwayland-server.so.0': 'libwayland-server0',
219+
'libwebp.so.6': 'libwebp6',
220+
'libwebpdemux.so.2': 'libwebpdemux2',
221+
'libwoff2dec.so.1.0.2': 'libwoff1',
222+
'libxcb-dri3.so.0': 'libxcb-dri3-0',
223+
'libxcb-shm.so.0': 'libxcb-shm0',
224+
'libxcb.so.1': 'libxcb1',
225+
'libxkbcommon.so.0': 'libxkbcommon0',
226+
'libxml2.so.2': 'libxml2',
227+
'libxslt.so.1': 'libxslt1.1',
228+
};
229+

0 commit comments

Comments
 (0)