Bug 1108771 - Part 1: Prompt for which application to bootstrap. r=gps
authorNick Alexander <nalexander@mozilla.com>
Sun, 21 Dec 2014 15:29:17 -0800
changeset 221185 f5758bdccc0a052d52206fc9ff4897ab4a8d9f4f
parent 221117 8b881bea204add0f733100601dc136be1698ac87
child 221186 3ecd0c6da57ba01c64ad467781c45d82510e3791
push id28013
push userphilringnalda@gmail.com
push dateWed, 24 Dec 2014 23:31:28 +0000
treeherdermozilla-central@38471b0310c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1108771
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1108771 - Part 1: Prompt for which application to bootstrap. r=gps This lays the foundation for adding support for bootstrapping mobile/android. * Queries for which application to bootstrap, currently browser or mobile/android; * Adds call to install_APPLICATION_packages after install_system_packages; * Adds call to suggest_APPLICATION_mozconfig after bootstrapping everything; * and splits install_browser_packages out of install_system_packages throughout (essentially untested, but generally simple). To implement a new application (b2g?), just add it to the list of applications and implement install_b2g_packages throughout.
python/mozboot/mozboot/base.py
python/mozboot/mozboot/bootstrap.py
python/mozboot/mozboot/centos.py
python/mozboot/mozboot/debian.py
python/mozboot/mozboot/fedora.py
python/mozboot/mozboot/freebsd.py
python/mozboot/mozboot/gentoo.py
python/mozboot/mozboot/openbsd.py
python/mozboot/mozboot/osx.py
--- a/python/mozboot/mozboot/base.py
+++ b/python/mozboot/mozboot/base.py
@@ -82,17 +82,59 @@ MODERN_PYTHON_VERSION = LooseVersion('2.
 
 class BaseBootstrapper(object):
     """Base class for system bootstrappers."""
 
     def __init__(self):
         self.package_manager_updated = False
 
     def install_system_packages(self):
-        raise NotImplemented('%s must implement install_system_packages()' %
+        '''
+        Install packages shared by all applications. These are usually
+        packages required by the development (like mercurial) or the
+        build system (like autoconf).
+        '''
+        raise NotImplementedError('%s must implement install_system_packages()' %
+            __name__)
+
+    def install_browser_packages(self):
+        '''
+        Install packages required to build Firefox for Desktop (application
+        'browser').
+        '''
+        raise NotImplementedError('Cannot bootstrap Firefox for Desktop: '
+            '%s does not yet implement install_browser_packages()' % __name__)
+
+    def suggest_browser_mozconfig(self):
+        '''
+        Print a message to the console detailing what the user's mozconfig
+        should contain.
+
+        Firefox for Desktop can in simple cases determine its build environment
+        entirely from configure.
+        '''
+        pass
+
+    def install_mobile_android_packages(self):
+        '''
+        Install packages required to build Firefox for Android (application
+        'mobile/android', also known as Fennec).
+        '''
+        raise NotImplementedError('Cannot bootstrap Firefox for Android: '
+            '%s does not yet implement install_mobile_android_packages()' % __name__)
+
+    def suggest_mobile_android_mozconfig(self):
+        '''
+        Print a message to the console detailing what the user's mozconfig
+        should contain.
+
+        Firefox for Android needs an application and an ABI set, and it needs
+        paths to the Android SDK and NDK.
+        '''
+        raise NotImplementedError('%s does not yet implement suggest_mobile_android_mozconfig()' %
             __name__)
 
     def which(self, name):
         """Python implementation of which.
 
         It returns the path of an executable or None if it couldn't be found.
         """
         for path in os.environ['PATH'].split(os.pathsep):
--- a/python/mozboot/mozboot/bootstrap.py
+++ b/python/mozboot/mozboot/bootstrap.py
@@ -12,19 +12,29 @@ from mozboot.centos import CentOSBootstr
 from mozboot.debian import DebianBootstrapper
 from mozboot.fedora import FedoraBootstrapper
 from mozboot.freebsd import FreeBSDBootstrapper
 from mozboot.gentoo import GentooBootstrapper
 from mozboot.osx import OSXBootstrapper
 from mozboot.openbsd import OpenBSDBootstrapper
 from mozboot.ubuntu import UbuntuBootstrapper
 
+APPLICATION_CHOICE = '''
+Please choose the version of Firefox you want to build:
+%s
+Your choice:
+'''
+
+APPLICATIONS = [
+    ('Firefox for Desktop', 'browser'),
+    ('Firefox for Android', 'mobile_android'),
+]
 
 FINISHED = '''
-Your system should be ready to build Firefox! If you have not already,
+Your system should be ready to build %s! If you have not already,
 obtain a copy of the source code by running:
 
     hg clone https://hg.mozilla.org/mozilla-central
 
 Or, if you prefer Git:
 
     git clone https://git.mozilla.org/integration/gecko-dev.git
 '''
@@ -88,13 +98,26 @@ class Bootstrapper(object):
         if cls is None:
             raise NotImplementedError('Bootstrap support is not yet available '
                                       'for your OS.')
 
         self.instance = cls(**args)
 
 
     def bootstrap(self):
+        # Like ['1. Firefox for Desktop', '2. Firefox for Android'].
+        labels = [ '%s. %s' % (i + 1, name) for (i, (name, _)) in enumerate(APPLICATIONS) ]
+        prompt = APPLICATION_CHOICE % '\n'.join(labels)
+        choice = self.instance.prompt_int(prompt=prompt, low=1, high=len(APPLICATIONS))
+        name, application = APPLICATIONS[choice-1]
+
         self.instance.install_system_packages()
+
+        # Like 'install_browser_packages' or 'install_mobile_android_packages'.
+        getattr(self.instance, 'install_%s_packages' % application)()
+
         self.instance.ensure_mercurial_modern()
         self.instance.ensure_python_modern()
 
-        print(self.finished)
+        print(self.finished % name)
+
+        # Like 'suggest_browser_mozconfig' or 'suggest_mobile_android_mozconfig'.
+        getattr(self.instance, 'suggest_%s_mozconfig' % application)()
--- a/python/mozboot/mozboot/centos.py
+++ b/python/mozboot/mozboot/centos.py
@@ -16,39 +16,49 @@ class CentOSBootstrapper(BaseBootstrappe
 
         self.group_packages = [
             'Development Tools',
             'Development Libraries',
             'GNOME Software Development',
         ]
 
         self.packages = [
-            'alsa-lib-devel',
             'autoconf213',
             'curl-devel',
+            'mercurial',
+        ]
+
+        self.browser_group_packages = [
+            'GNOME Software Development',
+        ]
+
+        self.browser_packages = [
+            'alsa-lib-devel',
             'dbus-glib-devel',
             'glibc-static',
             'gstreamer-devel',
             'gstreamer-plugins-base-devel',
             'gtk2-devel',
             'libstdc++-static',
             'libXt-devel',
-            'mercurial',
             'mesa-libGL-devel',
             'pulseaudio-libs-devel',
             'wireless-tools-devel',
             'yasm',
         ]
 
     def install_system_packages(self):
-        kern = platform.uname()
-
         self.yum_groupinstall(*self.group_packages)
         self.yum_install(*self.packages)
 
+    def install_browser_packages(self):
+        self.yum_groupinstall(*self.browser_group_packages)
+        self.yum_install(*self.browser_packages)
+
+        kern = platform.uname()
         yasm = 'http://pkgs.repoforge.org/yasm/yasm-1.1.0-1.el6.rf.i686.rpm'
         if 'x86_64' in kern[2]:
             yasm = 'http://pkgs.repoforge.org/yasm/yasm-1.1.0-1.el6.rf.x86_64.rpm'
 
         self.run_as_root(['rpm', '-ivh', yasm])
 
     def upgrade_mercurial(self, current):
         self.yum_update('mercurial')
--- a/python/mozboot/mozboot/debian.py
+++ b/python/mozboot/mozboot/debian.py
@@ -6,49 +6,59 @@ from mozboot.base import BaseBootstrappe
 
 class DebianBootstrapper(BaseBootstrapper):
     # These are common packages for all Debian-derived distros (such as
     # Ubuntu).
     COMMON_PACKAGES = [
         'autoconf2.13',
         'build-essential',
         'ccache',
+        'mercurial',
+        'python-dev',
+        'python-setuptools',
+        'unzip',
+        'uuid',
+        'zip',
+    ]
+
+    # Subclasses can add packages to this variable to have them installed.
+    DISTRO_PACKAGES = []
+
+    BROWSER_COMMON_PACKAGES = [
         'libasound2-dev',
         'libcurl4-openssl-dev',
         'libdbus-1-dev',
         'libdbus-glib-1-dev',
         'libgconf2-dev',
         'libgstreamer0.10-dev',
         'libgstreamer-plugins-base0.10-dev',
         'libgtk2.0-dev',
         'libiw-dev',
         'libnotify-dev',
         'libpulse-dev',
         'libxt-dev',
-        'mercurial',
         'mesa-common-dev',
         'python-dbus',
-        'python-dev',
-        'python-setuptools',
-        'unzip',
-        'uuid',
         'yasm',
         'xvfb',
-        'zip',
     ]
 
     # Subclasses can add packages to this variable to have them installed.
-    DISTRO_PACKAGES = []
+    BROWSER_DISTRO_PACKAGES = []
 
     def __init__(self, version, dist_id):
         BaseBootstrapper.__init__(self)
 
         self.version = version
         self.dist_id = dist_id
 
         self.packages = self.COMMON_PACKAGES + self.DISTRO_PACKAGES
+        self.browser_packages = self.BROWSER_COMMON_PACKAGES + self.BROWSER_DISTRO_PACKAGES
 
     def install_system_packages(self):
         self.apt_install(*self.packages)
 
+    def install_browser_packages(self):
+        self.apt_install(*self.browser_packages)
+
     def _update_package_manager(self):
         self.run_as_root(['apt-get', 'update'])
 
--- a/python/mozboot/mozboot/fedora.py
+++ b/python/mozboot/mozboot/fedora.py
@@ -11,33 +11,43 @@ class FedoraBootstrapper(BaseBootstrappe
         BaseBootstrapper.__init__(self)
 
         self.version = version
         self.dist_id = dist_id
 
         self.group_packages = [
             'Development Tools',
             'Development Libraries',
+        ]
+
+        self.packages = [
+            'autoconf213',
+            'mercurial',
+        ]
+
+        self.browser_group_packages = [
             'GNOME Software Development',
         ]
 
-        self.packages = [
+        self.browser_packages = [
             'alsa-lib-devel',
-            'autoconf213',
             'gcc-c++',
             'glibc-static',
             'gstreamer-devel',
             'gstreamer-plugins-base-devel',
             'libstdc++-static',
             'libXt-devel',
-            'mercurial',
             'mesa-libGL-devel',
             'pulseaudio-libs-devel',
             'wireless-tools-devel',
             'yasm',
         ]
 
     def install_system_packages(self):
         self.yum_groupinstall(*self.group_packages)
         self.yum_install(*self.packages)
 
+    def install_browser_packages(self):
+        self.yum_groupinstall(*self.browser_group_packages)
+        self.yum_install(*self.browser_packages)
+
     def upgrade_mercurial(self, current):
         self.yum_update('mercurial')
--- a/python/mozboot/mozboot/freebsd.py
+++ b/python/mozboot/mozboot/freebsd.py
@@ -7,42 +7,48 @@ from mozboot.base import BaseBootstrappe
 class FreeBSDBootstrapper(BaseBootstrapper):
     def __init__(self, version, flavor):
         BaseBootstrapper.__init__(self)
         self.version = int(version.split('.')[0])
         self.flavor  = flavor.lower()
 
         self.packages = [
             'autoconf213',
+            'gmake',
+            'mercurial',
+            'pkgconf',
+            'zip',
+        ]
+
+        self.browser_packages = [
             'dbus-glib',
-            'gmake',
             'gstreamer-plugins',
             'gtk2',
             'libGL',
-            'mercurial',
-            'pkgconf',
             'pulseaudio',
             'v4l_compat',
             'yasm',
-            'zip',
         ]
 
         if self.flavor == 'dragonfly':
             self.packages.append('unzip')
 
         # gcc in base is too old
         if self.flavor == 'freebsd' and self.version < 9:
-            self.packages.append('gcc')
+            self.browser_packages.append('gcc')
 
     def pkg_install(self, *packages):
         if self.which('pkg'):
             command = ['pkg', 'install']
         else:
             command = ['pkg_add', '-Fr']
 
         command.extend(packages)
         self.run_as_root(command)
 
     def install_system_packages(self):
         self.pkg_install(*self.packages)
 
+    def install_browser_packages(self):
+        self.pkg_install(*self.browser_packages)
+
     def upgrade_mercurial(self, current):
         self.pkg_install('mercurial')
--- a/python/mozboot/mozboot/gentoo.py
+++ b/python/mozboot/mozboot/gentoo.py
@@ -9,17 +9,18 @@ from mozboot.base import BaseBootstrappe
 class GentooBootstrapper(BaseBootstrapper):
     def __init__(self, version, dist_id):
         BaseBootstrapper.__init__(self)
 
         self.version = version
         self.dist_id = dist_id
 
     def install_system_packages(self):
-        self.run_as_root(['emerge', '--onlydeps', '--quiet', 'firefox'])
+        self.run_as_root(['emerge', '--quiet', 'git', 'mercurial'])
 
-        self.run_as_root(['emerge', '--quiet', 'git', 'mercurial'])
+    def install_browser_packages(self):
+        self.run_as_root(['emerge', '--onlydeps', '--quiet', 'firefox'])
 
     def _update_package_manager(self):
         self.run_as_root(['emerge', '--sync'])
 
     def upgrade_mercurial(self, current):
         self.run_as_root(['emerge', '--update', 'mercurial'])
--- a/python/mozboot/mozboot/openbsd.py
+++ b/python/mozboot/mozboot/openbsd.py
@@ -7,25 +7,32 @@ import os
 from mozboot.base import BaseBootstrapper
 
 class OpenBSDBootstrapper(BaseBootstrapper):
     def __init__(self, version):
         BaseBootstrapper.__init__(self)
 
         self.packages = [
             'mercurial',
-            'llvm',
             'autoconf-2.13',
-            'yasm',
-            'gtk+2',
-            'dbus-glib',
-            'gstreamer-plugins-base',
-            'pulseaudio',
             'gmake',
             'gtar',
             'wget',
             'unzip',
             'zip',
         ]
 
+        self.browser_packages = [
+            'llvm',
+            'yasm',
+            'gtk+2',
+            'dbus-glib',
+            'gstreamer-plugins-base',
+            'pulseaudio',
+        ]
+
     def install_system_packages(self):
         # we use -z because there's no other way to say "any autoconf-2.13"
         self.run_as_root(['pkg_add', '-z'] + self.packages)
+
+    def install_browser_packages(self):
+        # we use -z because there's no other way to say "any autoconf-2.13"
+        self.run_as_root(['pkg_add', '-z'] + self.browser_packages)
--- a/python/mozboot/mozboot/osx.py
+++ b/python/mozboot/mozboot/osx.py
@@ -172,17 +172,20 @@ class OSXBootstrapper(BaseBootstrapper):
 
         self.minor_version = version.split('.')[1]
 
     def install_system_packages(self):
         self.ensure_xcode()
 
         choice = self.ensure_package_manager()
         self.package_manager = choice
-        getattr(self, 'ensure_%s_packages' % choice)()
+        getattr(self, 'ensure_%s_system_packages' % self.package_manager)()
+
+    def install_browser_packages(self):
+        getattr(self, 'ensure_%s_browser_packages' % self.package_manager)()
 
     def ensure_xcode(self):
         if self.os_version < StrictVersion('10.7'):
             if not os.path.exists('/Developer/Applications/Xcode.app'):
                 print(XCODE_REQUIRED_LEGACY)
 
                 subprocess.check_call(['open', XCODE_LEGACY])
                 sys.exit(1)
@@ -251,17 +254,17 @@ class OSXBootstrapper(BaseBootstrapper):
                 print(INSTALL_XCODE_COMMAND_LINE_TOOLS_STEPS)
                 sys.exit(1)
 
     def _install_xcode_app_store(self):
         subprocess.check_call(['open', XCODE_APP_STORE])
         print('Once the install has finished, please relaunch this script.')
         sys.exit(1)
 
-    def ensure_homebrew_packages(self):
+    def ensure_homebrew_system_packages(self):
         self.brew = self.which('brew')
         assert self.brew is not None
 
         installed = self.check_output([self.brew, 'list']).split()
 
         packages = [
             # We need to install Python because Mercurial requires the Python
             # development headers which are missing from OS X (at least on
@@ -285,45 +288,73 @@ class OSXBootstrapper(BaseBootstrapper):
                 continue
 
             if not printed:
                 print(PACKAGE_MANAGER_PACKAGES % ('Homebrew',))
                 printed = True
 
             subprocess.check_call([self.brew, '-v', 'install', package])
 
+    def ensure_homebrew_browser_packages(self):
+        installed = self.check_output([self.brew, 'list']).split()
+
+        packages = [
+            ('yasm', 'yasm'),
+        ]
+
+        printed = False
+
+        for name, package in packages:
+            if name in installed:
+                continue
+
+            if not printed:
+                print(PACKAGE_MANAGER_PACKAGES % ('Homebrew',))
+                printed = True
+
+            subprocess.check_call([self.brew, '-v', 'install', package])
+
         if self.os_version < StrictVersion('10.7') and 'llvm' not in installed:
             print(PACKAGE_MANAGER_OLD_CLANG % ('Homebrew',))
 
             subprocess.check_call([self.brew, '-v', 'install', 'llvm',
                 '--with-clang', '--all-targets'])
 
-    def ensure_macports_packages(self):
+    def ensure_macports_system_packages(self):
         self.port = self.which('port')
         assert self.port is not None
 
         installed = set(self.check_output([self.port, 'installed']).split())
 
         packages = ['python27',
                     'mercurial',
-                    'yasm',
                     'autoconf213']
 
         missing = [package for package in packages if package not in installed]
         if missing:
             print(PACKAGE_MANAGER_PACKAGES % ('MacPorts',))
             self.run_as_root([self.port, '-v', 'install'] + missing)
 
+        self.run_as_root([self.port, 'select', '--set', 'python', 'python27'])
+
+    def ensure_macports_browser_packages(self):
+        installed = set(self.check_output([self.port, 'installed']).split())
+
+        packages = ['yasm']
+
+        missing = [package for package in packages if package not in installed]
+        if missing:
+            print(PACKAGE_MANAGER_PACKAGES % ('MacPorts',))
+            self.run_as_root([self.port, '-v', 'install'] + missing)
+
         if self.os_version < StrictVersion('10.7') and MACPORTS_CLANG_PACKAGE not in installed:
             print(PACKAGE_MANAGER_OLD_CLANG % ('MacPorts',))
             self.run_as_root([self.port, '-v', 'install', MACPORTS_CLANG_PACKAGE])
             self.run_as_root([self.port, 'select', '--set', 'clang', 'mp-' + MACPORTS_CLANG_PACKAGE])
 
-        self.run_as_root([self.port, 'select', '--set', 'python', 'python27'])
-
     def ensure_package_manager(self):
         '''
         Search package mgr in sys.path, if none is found, prompt the user to install one.
         If only one is found, use that one. If both are found, prompt the user to choose
         one.
         '''
         installed = []
         for name, cmd in PACKAGE_MANAGER.iteritems():