Skip to content

Commit

Permalink
devops: show package names instead of missing libs on Ubuntu 18.04 (#…
Browse files Browse the repository at this point in the history
…3013)

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 #2745
  • Loading branch information
aslushnikov authored Jul 17, 2020
1 parent ef2a652 commit 9a2245d
Showing 1 changed file with 144 additions and 3 deletions.
147 changes: 144 additions & 3 deletions src/server/validateDependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const accessAsync = util.promisify(fs.access.bind(fs));
const checkExecutable = (filePath: string) => accessAsync(filePath, fs.constants.X_OK).then(() => true).catch(e => false);
const statAsync = util.promisify(fs.stat.bind(fs));
const readdirAsync = util.promisify(fs.readdir.bind(fs));
const readFileAsync = util.promisify(fs.readFile.bind(fs));

export async function validateDependencies(browserPath: string, browser: BrowserDescriptor) {
// We currently only support Linux.
Expand All @@ -34,15 +35,49 @@ export async function validateDependencies(browserPath: string, browser: Browser
for (const directoryPath of directoryPaths)
lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));
const allMissingDeps = await Promise.all(lddPaths.map(lddPath => missingFileDependencies(lddPath)));
const missingDeps = new Set();
const missingDeps: Set<string> = new Set();
for (const deps of allMissingDeps) {
for (const dep of deps)
missingDeps.add(dep);
}
if (!missingDeps.size)
return;
const deps = [...missingDeps].sort().map(dep => ' ' + dep).join('\n');
throw new Error('Host system is missing the following dependencies to run browser\n' + deps);
// Check Ubuntu version.
const missingPackages = new Set();

const ubuntuVersion = await getUbuntuVersion();
if (ubuntuVersion === '18.04') {
// Translate missing dependencies to package names to install with apt.
for (const missingDep of missingDeps) {
const packageName = LIBRARY_TO_PACKAGE_NAME_UBUNTU_18_04[missingDep];
if (packageName) {
missingPackages.add(packageName);
missingDeps.delete(missingDep);
}
}
}

let missingPackagesMessage = '';
if (missingPackages.size) {
missingPackagesMessage = [
` Install missing packages with:`,
` apt-get install ${[...missingPackages].join('\\\n ')}`,
``,
``,
].join('\n');
}

let missingDependenciesMessage = '';
if (missingDeps.size) {
const header = missingPackages.size ? `Missing libraries we didn't find packages for:` : `Missing libraries are:`;
missingDependenciesMessage = [
` ${header}`,
` ${[...missingDeps].join('\n ')}`,
``,
].join('\n');
}

throw new Error('Host system is missing dependencies!\n\n' + missingPackagesMessage + missingDependenciesMessage);
}

async function executablesOrSharedLibraries(directoryPath: string): Promise<string[]> {
Expand Down Expand Up @@ -86,3 +121,109 @@ function lddAsync(filePath: string): Promise<{stdout: string, stderr: string, co
ldd.on('close', code => resolve({stdout, stderr, code}));
});
}

async function getUbuntuVersion(): Promise<string> {
const osRelease = await readFileAsync('/etc/os-release', 'utf8').catch(e => '');
if (!osRelease)
return '';
const fields = new Map();
for (const line of osRelease.split('\n')) {
const tokens = line.split('=');
const name = tokens.shift();
let value = tokens.join('=').trim();
if (value.startsWith('"') && value.endsWith('"'))
value = value.substring(1, value.length - 1);
if (!name)
continue;
fields.set(name.toLowerCase(), value);
}
if (!fields.get('name') || fields.get('name').toLowerCase() !== 'ubuntu')
return '';
return fields.get('version_id') || '';
}

// This list is generated with https://gist.github.com/aslushnikov/2766200430228c3700537292fccad064
const LIBRARY_TO_PACKAGE_NAME_UBUNTU_18_04: { [s: string]: string} = {
'libEGL.so.1': 'libegl1',
'libGL.so.1': 'libgl1',
'libX11-xcb.so.1': 'libx11-xcb1',
'libX11.so.6': 'libx11-6',
'libXcomposite.so.1': 'libxcomposite1',
'libXcursor.so.1': 'libxcursor1',
'libXdamage.so.1': 'libxdamage1',
'libXext.so.6': 'libxext6',
'libXfixes.so.3': 'libxfixes3',
'libXi.so.6': 'libxi6',
'libXrandr.so.2': 'libxrandr2',
'libXrender.so.1': 'libxrender1',
'libXt.so.6': 'libxt6',
'libXtst.so.6': 'libxtst6',
'libasound.so.2': 'libasound2',
'libatk-1.0.so.0': 'libatk1.0-0',
'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',
'libatspi.so.0': 'libatspi2.0-0',
'libbrotlidec.so.1': 'libbrotli1',
'libcairo-gobject.so.2': 'libcairo-gobject2',
'libcairo.so.2': 'libcairo2',
'libcups.so.2': 'libcups2',
'libdbus-1.so.3': 'libdbus-1-3',
'libdbus-glib-1.so.2': 'libdbus-glib-1-2',
'libdrm.so.2': 'libdrm2',
'libenchant.so.1': 'libenchant1c2a',
'libepoxy.so.0': 'libepoxy0',
'libfontconfig.so.1': 'libfontconfig1',
'libfreetype.so.6': 'libfreetype6',
'libgbm.so.1': 'libgbm1',
'libgdk-3.so.0': 'libgtk-3-0',
'libgdk-x11-2.0.so.0': 'libgtk2.0-0',
'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf2.0-0',
'libgio-2.0.so.0': 'libglib2.0-0',
'libglib-2.0.so.0': 'libglib2.0-0',
'libgmodule-2.0.so.0': 'libglib2.0-0',
'libgobject-2.0.so.0': 'libglib2.0-0',
'libgstapp-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
'libgstaudio-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
'libgstbase-1.0.so.0': 'libgstreamer1.0-0',
'libgstcodecparsers-1.0.so.0': 'libgstreamer-plugins-bad1.0-0',
'libgstfft-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',
'libgstpbutils-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',
'libgsttag-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
'libgstvideo-1.0.so.0': 'libgstreamer-plugins-base1.0-0',
'libgthread-2.0.so.0': 'libglib2.0-0',
'libgtk-3.so.0': 'libgtk-3-0',
'libgtk-x11-2.0.so.0': 'libgtk2.0-0',
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
'libharfbuzz.so.0': 'libharfbuzz0b',
'libhyphen.so.0': 'libhyphen0',
'libicui18n.so.60': 'libicu60',
'libicuuc.so.60': 'libicu60',
'libjpeg.so.8': 'libjpeg-turbo8',
'libnotify.so.4': 'libnotify4',
'libnspr4.so': 'libnspr4',
'libnss3.so': 'libnss3',
'libnssutil3.so': 'libnss3',
'libopenjp2.so.7': 'libopenjp2-7',
'libopus.so.0': 'libopus0',
'libpango-1.0.so.0': 'libpango-1.0-0',
'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',
'libpangoft2-1.0.so.0': 'libpangoft2-1.0-0',
'libpng16.so.16': 'libpng16-16',
'libsecret-1.so.0': 'libsecret-1-0',
'libsmime3.so': 'libnss3',
'libssl3.so': 'libnss3',
'libwayland-client.so.0': 'libwayland-client0',
'libwayland-egl.so.1': 'libwayland-egl1',
'libwayland-server.so.0': 'libwayland-server0',
'libwebp.so.6': 'libwebp6',
'libwebpdemux.so.2': 'libwebpdemux2',
'libwoff2dec.so.1.0.2': 'libwoff1',
'libxcb-dri3.so.0': 'libxcb-dri3-0',
'libxcb-shm.so.0': 'libxcb-shm0',
'libxcb.so.1': 'libxcb1',
'libxkbcommon.so.0': 'libxkbcommon0',
'libxml2.so.2': 'libxml2',
'libxslt.so.1': 'libxslt1.1',
};

0 comments on commit 9a2245d

Please sign in to comment.