|  | #!/usr/bin/env python | 
|  | # Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | import argparse | 
|  | import operator | 
|  | import os | 
|  | import platform | 
|  | import re | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  |  | 
|  | SUPPORTED_UBUNTU_VERSIONS = ( | 
|  | {'number': '14.04', 'codename': 'trusty'}, | 
|  | {'number': '14.10', 'codename': 'utopic'}, | 
|  | {'number': '15.04', 'codename': 'vivid'}, | 
|  | {'number': '15.10', 'codename': 'wily'}, | 
|  | ) | 
|  |  | 
|  |  | 
|  | # Packages needed for chromeos only. | 
|  | _packages_chromeos_dev = ( | 
|  | 'libbluetooth-dev', | 
|  | 'libxkbcommon-dev', | 
|  | 'realpath', | 
|  | ) | 
|  |  | 
|  |  | 
|  | # Packages needed for development. | 
|  | _packages_dev = ( | 
|  | 'bison', | 
|  | 'cdbs', | 
|  | 'curl', | 
|  | 'devscripts', | 
|  | 'dpkg-dev', | 
|  | 'elfutils', | 
|  | 'fakeroot', | 
|  | 'flex', | 
|  | 'fonts-ipafont', | 
|  | 'fonts-thai-tlwg', | 
|  | 'g++', | 
|  | 'git-core', | 
|  | 'git-svn', | 
|  | 'gperf', | 
|  | 'language-pack-da', | 
|  | 'language-pack-fr', | 
|  | 'language-pack-he', | 
|  | 'language-pack-zh-hant', | 
|  | 'libapache2-mod-php5', | 
|  | 'libasound2-dev', | 
|  | 'libav-tools', | 
|  | 'libbrlapi-dev', | 
|  | 'libbz2-dev', | 
|  | 'libcairo2-dev', | 
|  | 'libcap-dev', | 
|  | 'libcups2-dev', | 
|  | 'libcurl4-gnutls-dev', | 
|  | 'libdrm-dev', | 
|  | 'libelf-dev', | 
|  | 'libgconf2-dev', | 
|  | 'libglib2.0-dev', | 
|  | 'libglu1-mesa-dev', | 
|  | 'libgnome-keyring-dev', | 
|  | 'libgtk2.0-dev', | 
|  | 'libkrb5-dev', | 
|  | 'libnspr4-dev', | 
|  | 'libnss3-dev', | 
|  | 'libpam0g-dev', | 
|  | 'libpci-dev', | 
|  | 'libpulse-dev', | 
|  | 'libsctp-dev', | 
|  | 'libspeechd-dev', | 
|  | 'libsqlite3-dev', | 
|  | 'libssl-dev', | 
|  | 'libudev-dev', | 
|  | 'libwww-perl', | 
|  | 'libxslt1-dev', | 
|  | 'libxss-dev', | 
|  | 'libxt-dev', | 
|  | 'libxtst-dev', | 
|  | 'openbox', | 
|  | 'patch', | 
|  | 'perl', | 
|  | 'php5-cgi', | 
|  | 'pkg-config', | 
|  | 'python', | 
|  | 'python-cherrypy3', | 
|  | 'python-crypto', | 
|  | 'python-dev', | 
|  | 'python-numpy', | 
|  | 'python-opencv', | 
|  | 'python-openssl', | 
|  | 'python-psutil', | 
|  | 'python-yaml', | 
|  | 'rpm', | 
|  | 'ruby', | 
|  | 'subversion', | 
|  | 'ttf-dejavu-core', | 
|  | 'ttf-indic-fonts', | 
|  | 'wdiff', | 
|  | 'zip', | 
|  | ) | 
|  |  | 
|  |  | 
|  | # Run-time libraries required by chromeos only. | 
|  | _packages_chromeos_lib = ( | 
|  | 'libbz2-1.0', | 
|  | 'libpulse0', | 
|  | ) | 
|  |  | 
|  |  | 
|  | # Full list of required run-time libraries. | 
|  | _packages_lib = ( | 
|  | 'libasound2', | 
|  | 'libatk1.0-0', | 
|  | 'libc6', | 
|  | 'libcairo2', | 
|  | 'libcap2', | 
|  | 'libcups2', | 
|  | 'libexpat1', | 
|  | 'libfontconfig1', | 
|  | 'libfreetype6', | 
|  | 'libglib2.0-0', | 
|  | 'libgnome-keyring0', | 
|  | 'libgtk2.0-0', | 
|  | 'libpam0g', | 
|  | 'libpango1.0-0', | 
|  | 'libpci3', | 
|  | 'libpcre3', | 
|  | 'libpixman-1-0', | 
|  | 'libpng12-0', | 
|  | 'libspeechd2', | 
|  | 'libsqlite3-0', | 
|  | 'libstdc++6', | 
|  | 'libx11-6', | 
|  | 'libx11-xcb1', | 
|  | 'libxau6', | 
|  | 'libxcb1', | 
|  | 'libxcomposite1', | 
|  | 'libxcursor1', | 
|  | 'libxdamage1', | 
|  | 'libxdmcp6', | 
|  | 'libxext6', | 
|  | 'libxfixes3', | 
|  | 'libxi6', | 
|  | 'libxinerama1', | 
|  | 'libxrandr2', | 
|  | 'libxrender1', | 
|  | 'libxtst6', | 
|  | 'zlib1g', | 
|  | ) | 
|  |  | 
|  |  | 
|  | # Debugging symbols for all of the run-time libraries. | 
|  | _packages_dbg = ( | 
|  | 'libatk1.0-dbg', | 
|  | 'libc6-dbg', | 
|  | 'libcairo2-dbg', | 
|  | 'libfontconfig1-dbg', | 
|  | 'libglib2.0-0-dbg', | 
|  | 'libgtk2.0-0-dbg', | 
|  | 'libpango1.0-0-dbg', | 
|  | 'libpcre3-dbg', | 
|  | 'libpixman-1-0-dbg', | 
|  | 'libsqlite3-0-dbg', | 
|  | 'libx11-6-dbg', | 
|  | 'libx11-xcb1-dbg', | 
|  | 'libxau6-dbg', | 
|  | 'libxcb1-dbg', | 
|  | 'libxcomposite1-dbg', | 
|  | 'libxcursor1-dbg', | 
|  | 'libxdamage1-dbg', | 
|  | 'libxdmcp6-dbg', | 
|  | 'libxext6-dbg', | 
|  | 'libxfixes3-dbg', | 
|  | 'libxi6-dbg', | 
|  | 'libxinerama1-dbg', | 
|  | 'libxrandr2-dbg', | 
|  | 'libxrender1-dbg', | 
|  | 'libxtst6-dbg', | 
|  | 'zlib1g-dbg', | 
|  | ) | 
|  |  | 
|  |  | 
|  | # 32-bit libraries needed e.g. to compile V8 snapshot for Android or armhf. | 
|  | _packages_lib32 = ( | 
|  | 'linux-libc-dev:i386', | 
|  | ) | 
|  |  | 
|  |  | 
|  | # arm cross toolchain packages needed to build chrome on armhf. | 
|  | _packages_arm = ( | 
|  | 'g++-arm-linux-gnueabihf', | 
|  | 'libc6-dev-armhf-cross', | 
|  | 'linux-libc-dev-armhf-cross', | 
|  | ) | 
|  |  | 
|  |  | 
|  | # Packages to build NaCl, its toolchains, and its ports. | 
|  | _packages_naclports = ( | 
|  | 'ant', | 
|  | 'autoconf', | 
|  | 'bison', | 
|  | 'cmake', | 
|  | 'gawk', | 
|  | 'intltool', | 
|  | 'xsltproc', | 
|  | 'xutils-dev', | 
|  | ) | 
|  | _packages_nacl = ( | 
|  | 'g++-mingw-w64-i686', | 
|  | 'lib32ncurses5-dev', | 
|  | 'lib32z1-dev', | 
|  | 'libasound2:i386', | 
|  | 'libcap2:i386', | 
|  | 'libelf-dev:i386', | 
|  | 'libfontconfig1:i386', | 
|  | 'libgconf-2-4:i386', | 
|  | 'libglib2.0-0:i386', | 
|  | 'libgpm2:i386', | 
|  | 'libgtk2.0-0:i386', | 
|  | 'libncurses5:i386', | 
|  | 'libnss3:i386', | 
|  | 'libpango1.0-0:i386', | 
|  | 'libssl1.0.0:i386', | 
|  | 'libtinfo-dev', | 
|  | 'libtinfo-dev:i386', | 
|  | 'libtool', | 
|  | 'libxcomposite1:i386', | 
|  | 'libxcursor1:i386', | 
|  | 'libxdamage1:i386', | 
|  | 'libxi6:i386', | 
|  | 'libxrandr2:i386', | 
|  | 'libxss1:i386', | 
|  | 'libxtst6:i386', | 
|  | 'texinfo', | 
|  | 'xvfb', | 
|  | ) | 
|  |  | 
|  |  | 
|  | def is_userland_64_bit(): | 
|  | return platform.architecture()[0] == '64bit' | 
|  |  | 
|  |  | 
|  | def package_exists(pkg): | 
|  | return pkg in subprocess.check_output(['apt-cache', 'pkgnames']).splitlines() | 
|  |  | 
|  |  | 
|  | def lsb_release_short_codename(): | 
|  | return subprocess.check_output( | 
|  | ['lsb_release', '--codename', '--short']).strip() | 
|  |  | 
|  |  | 
|  | def write_error(message): | 
|  | sys.stderr.write('ERROR: %s\n' % message) | 
|  | sys.stderr.flush() | 
|  |  | 
|  |  | 
|  | def nonfatal_get_output(*popenargs, **kwargs): | 
|  | process = subprocess.Popen( | 
|  | stdout=subprocess.PIPE, stderr=subprocess.PIPE, *popenargs, **kwargs) | 
|  | stdout, stderr = process.communicate() | 
|  | retcode = process.poll() | 
|  | return retcode, stdout, stderr | 
|  |  | 
|  |  | 
|  | def compute_dynamic_package_lists(): | 
|  | global _packages_arm | 
|  | global _packages_dbg | 
|  | global _packages_dev | 
|  | global _packages_lib | 
|  | global _packages_lib32 | 
|  | global _packages_nacl | 
|  |  | 
|  | if is_userland_64_bit(): | 
|  | # 64-bit systems need a minimum set of 32-bit compat packages | 
|  | # for the pre-built NaCl binaries. | 
|  | _packages_dev += ( | 
|  | 'lib32gcc1', | 
|  | 'lib32stdc++6', | 
|  | 'libc6-i386', | 
|  | ) | 
|  |  | 
|  | # When cross building for arm/Android on 64-bit systems the host binaries | 
|  | # that are part of v8 need to be compiled with -m32 which means | 
|  | # that basic multilib support is needed. | 
|  | # gcc-multilib conflicts with the arm cross compiler (at least in trusty) | 
|  | # but g++-X.Y-multilib gives us the 32-bit support that we need. Find out | 
|  | # the appropriate value of X and Y by seeing what version the current | 
|  | # distribution's g++-multilib package depends on. | 
|  | output = subprocess.check_output(['apt-cache', 'depends', 'g++-multilib']) | 
|  | multilib_package = re.search(r'g\+\+-[0-9.]+-multilib', output).group() | 
|  | _packages_lib32 += (multilib_package,) | 
|  |  | 
|  | lsb_codename = lsb_release_short_codename() | 
|  |  | 
|  | # Find the proper version of libstdc++6-4.x-dbg. | 
|  | if lsb_codename == 'trusty': | 
|  | _packages_dbg += ('libstdc++6-4.8-dbg',) | 
|  | else: | 
|  | _packages_dbg += ('libstdc++6-4.9-dbg',) | 
|  |  | 
|  | # Work around for dependency issue Ubuntu/Trusty: http://crbug.com/435056 . | 
|  | if lsb_codename == 'trusty': | 
|  | _packages_arm += ( | 
|  | 'g++-4.8-multilib-arm-linux-gnueabihf', | 
|  | 'gcc-4.8-multilib-arm-linux-gnueabihf', | 
|  | ) | 
|  |  | 
|  | # Find the proper version of libgbm-dev. We can't just install libgbm-dev as | 
|  | # it depends on mesa, and only one version of mesa can exists on the system. | 
|  | # Hence we must match the same version or this entire script will fail. | 
|  | mesa_variant = '' | 
|  | for variant in ('-lts-trusty', '-lts-utopic'): | 
|  | rc, stdout, stderr = nonfatal_get_output( | 
|  | ['dpkg-query', '-Wf\'{Status}\'', 'libgl1-mesa-glx' + variant]) | 
|  | if 'ok installed' in output: | 
|  | mesa_variant = variant | 
|  | _packages_dev += ( | 
|  | 'libgbm-dev' + mesa_variant, | 
|  | 'libgl1-mesa-dev' + mesa_variant, | 
|  | 'libgles2-mesa-dev' + mesa_variant, | 
|  | 'mesa-common-dev' + mesa_variant, | 
|  | ) | 
|  |  | 
|  | if package_exists('ttf-mscorefonts-installer'): | 
|  | _packages_dev += ('ttf-mscorefonts-installer',) | 
|  | else: | 
|  | _packages_dev += ('msttcorefonts',) | 
|  |  | 
|  | if package_exists('libnspr4-dbg'): | 
|  | _packages_dbg += ('libnspr4-dbg', 'libnss3-dbg') | 
|  | _packages_lib += ('libnspr4', 'libnss3') | 
|  | else: | 
|  | _packages_dbg += ('libnspr4-0d-dbg', 'libnss3-1d-dbg') | 
|  | _packages_lib += ('libnspr4-0d', 'libnss3-1d') | 
|  |  | 
|  | if package_exists('libjpeg-dev'): | 
|  | _packages_dev += ('libjpeg-dev',) | 
|  | else: | 
|  | _packages_dev += ('libjpeg62-dev',) | 
|  |  | 
|  | if package_exists('libudev1'): | 
|  | _packages_dev += ('libudev1',) | 
|  | _packages_nacl += ('libudev1:i386',) | 
|  | else: | 
|  | _packages_dev += ('libudev0',) | 
|  | _packages_nacl += ('libudev0:i386',) | 
|  |  | 
|  | if package_exists('libbrlapi0.6'): | 
|  | _packages_dev += ('libbrlapi0.6',) | 
|  | else: | 
|  | _packages_dev += ('libbrlapi0.5',) | 
|  |  | 
|  | if package_exists('apache2-bin'): | 
|  | _packages_dev += ('apache2-bin',) | 
|  | else: | 
|  | _packages_dev += ('apache2.2-bin',) | 
|  |  | 
|  | if package_exists('xfonts-mathml'): | 
|  | _packages_dev += ('xfonts-mathml',) | 
|  |  | 
|  | # Some packages are only needed if the distribution actually supports | 
|  | # installing them. | 
|  | if package_exists('appmenu-gtk'): | 
|  | _packages_lib += ('appmenu-gtk',) | 
|  |  | 
|  | _packages_dev += _packages_chromeos_dev | 
|  | _packages_lib += _packages_chromeos_lib | 
|  | _packages_nacl += _packages_naclports | 
|  |  | 
|  |  | 
|  | def quick_check(packages): | 
|  | rc, stdout, stderr = nonfatal_get_output([ | 
|  | 'dpkg-query', '-W', '-f', '${PackageSpec}:${Status}\n'] + list(packages)) | 
|  | if rc == 0 and not stderr: | 
|  | return 0 | 
|  | print stderr | 
|  | return 1 | 
|  |  | 
|  |  | 
|  | def main(argv): | 
|  | parser = argparse.ArgumentParser() | 
|  | parser.add_argument('--quick-check', action='store_true', | 
|  | help='quickly try to determine if dependencies are ' | 
|  | 'installed (this avoids interactive prompts and ' | 
|  | 'sudo commands so might not be 100% accurate)') | 
|  | parser.add_argument('--unsupported', action='store_true', | 
|  | help='attempt installation even on unsupported systems') | 
|  | args = parser.parse_args(argv) | 
|  |  | 
|  | lsb_codename = lsb_release_short_codename() | 
|  | if not args.unsupported and not args.quick_check: | 
|  | if lsb_codename not in map( | 
|  | operator.itemgetter('codename'), SUPPORTED_UBUNTU_VERSIONS): | 
|  | supported_ubuntus = ['%(number)s (%(codename)s)' % v | 
|  | for v in SUPPORTED_UBUNTU_VERSIONS] | 
|  | write_error('Only Ubuntu %s are currently supported.' % | 
|  | ', '.join(supported_ubuntus)) | 
|  | return 1 | 
|  |  | 
|  | if platform.machine() not in ('i686', 'x86_64'): | 
|  | write_error('Only x86 architectures are currently supported.') | 
|  | return 1 | 
|  |  | 
|  | if os.geteuid() != 0 and not args.quick_check: | 
|  | print 'Running as non-root user.' | 
|  | print 'You might have to enter your password one or more times' | 
|  | print 'for \'sudo\'.' | 
|  | print | 
|  |  | 
|  | compute_dynamic_package_lists() | 
|  |  | 
|  | packages = (_packages_dev + _packages_lib + _packages_dbg + _packages_lib32 + | 
|  | _packages_arm + _packages_nacl) | 
|  | def packages_key(pkg): | 
|  | s = pkg.rsplit(':', 1) | 
|  | if len(s) == 1: | 
|  | return (s, '') | 
|  | return s | 
|  | packages = sorted(set(packages), key=packages_key) | 
|  |  | 
|  | if args.quick_check: | 
|  | return quick_check(packages) | 
|  |  | 
|  | return 0 | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(main(sys.argv[1:])) |