Bug 1384202 - Add --no-interactive bootstrap support for Android SDK and NDK. r=rillian
authorNick Alexander <nalexander@mozilla.com>
Wed, 19 Jul 2017 15:29:11 -0700
changeset 422030 95b831898973394e5d8e55fcd16b2f8926e5e500
parent 422029 bcfce9e21f29b6e719740ee13d4c0388d5fac2ab
child 422031 d856479d5d9a6663b8cd0091a0c35ca023826da1
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs1384202
milestone56.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 1384202 - Add --no-interactive bootstrap support for Android SDK and NDK. r=rillian Hacky, but it works -- until Google updates its license hashes. This looks ahead to using |mach bootstrap| to build docker images. MozReview-Commit-ID: DF23v8tr8SW
python/mozboot/mozboot/android.py
python/mozboot/mozboot/archlinux.py
python/mozboot/mozboot/centosfedora.py
python/mozboot/mozboot/debian.py
python/mozboot/mozboot/mach_commands.py
python/mozboot/mozboot/osx.py
--- a/python/mozboot/mozboot/android.py
+++ b/python/mozboot/mozboot/android.py
@@ -136,17 +136,27 @@ def get_paths(os_name):
                                    os.path.expanduser(os.path.join('~', '.mozbuild')))
     sdk_path = os.environ.get('ANDROID_SDK_HOME',
                               os.path.join(mozbuild_path, 'android-sdk-{}'.format(os_name)))
     ndk_path = os.environ.get('ANDROID_NDK_HOME',
                               os.path.join(mozbuild_path, 'android-ndk-r11c'))
     return (mozbuild_path, sdk_path, ndk_path)
 
 
-def ensure_android(os_name, artifact_mode):
+def ensure_dir(dir):
+    '''Ensures the given directory exists'''
+    if dir and not os.path.exists(dir):
+        try:
+            os.makedirs(dir)
+        except OSError as error:
+            if error.errno != errno.EEXIST:
+                raise
+
+
+def ensure_android(os_name, artifact_mode=False, no_interactive=False):
     '''
     Ensure the Android SDK (and NDK, if `artifact_mode` is falsy) are
     installed.  If not, fetch and unpack the SDK and/or NDK from the
     given URLs.  Ensure the required Android SDK packages are
     installed.
 
     `os_name` can be 'linux' or 'macosx'.
     '''
@@ -159,16 +169,31 @@ def ensure_android(os_name, artifact_mod
     sdk_url = 'https://dl.google.com/android/repository/sdk-tools-{}-3859397.zip'.format(os_tag)
     ndk_url = android_ndk_url(os_name)
 
     ensure_android_sdk_and_ndk(mozbuild_path, os_name,
                                sdk_path=sdk_path, sdk_url=sdk_url,
                                ndk_path=ndk_path, ndk_url=ndk_url,
                                artifact_mode=artifact_mode)
 
+    if no_interactive:
+        # Cribbed from observation and https://stackoverflow.com/a/38381577.
+        path = os.path.join(mozbuild_path, 'android-sdk-{}'.format(os_name), 'licenses')
+        ensure_dir(path)
+
+        licenses = {
+            'android-sdk-license': '8933bad161af4178b1185d1a37fbf41ea5269c55',
+            'android-sdk-preview-license': '84831b9409646a918e30573bab4c9c91346d8abd',
+        }
+        for license, tag in licenses.items():
+            lname = os.path.join(path, license)
+            if not os.path.isfile(lname):
+                open(lname, 'w').write('\n{}\n'.format(tag))
+
+
     # We expect the |sdkmanager| tool to be at
     # ~/.mozbuild/android-sdk-$OS_NAME/tools/bin/sdkmanager.
     sdkmanager_tool = os.path.join(sdk_path, 'tools', 'bin', 'sdkmanager')
     ensure_android_packages(sdkmanager_tool=sdkmanager_tool)
 
 
 def ensure_android_sdk_and_ndk(mozbuild_path, os_name, sdk_path, sdk_url, ndk_path, ndk_url, artifact_mode):
     '''
@@ -244,30 +269,32 @@ def android_ndk_url(os_name, ver='r11c')
 
 def main(argv):
     import optparse # No argparse, which is new in Python 2.7.
     import platform
 
     parser = optparse.OptionParser()
     parser.add_option('-a', '--artifact-mode', dest='artifact_mode', action='store_true',
                       help='If true, install only the Android SDK (and not the Android NDK).')
+    parser.add_option('--no-interactive', dest='no_interactive', action='store_true',
+                      help='Accept the Android SDK licenses without user interaction.')
 
     options, _ = parser.parse_args(argv)
 
     os_name = None
     if platform.system() == 'Darwin':
         os_name = 'macosx'
     elif platform.system() == 'Linux':
         os_name = 'linux'
     elif platform.system() == 'Windows':
         os_name = 'windows'
     else:
         raise NotImplementedError("We don't support bootstrapping the Android SDK (or Android NDK) "
                                   "on {} yet!".format(platform.system()))
 
-    ensure_android(os_name, options.artifact_mode)
+    ensure_android(os_name, artifact_mode=options.artifact_mode, no_interactive=options.no_interactive)
     suggest_mozconfig(os_name, options.artifact_mode)
 
     return 0
 
 
 if __name__ == '__main__':
     sys.exit(main(sys.argv))
--- a/python/mozboot/mozboot/archlinux.py
+++ b/python/mozboot/mozboot/archlinux.py
@@ -118,17 +118,18 @@ class ArchlinuxBootstrapper(StyloInstall
                   'toolchain requires 32 bit binaries be enabled (see '
                   'https://wiki.archlinux.org/index.php/Android).  You may need to '
                   'manually enable the multilib repository following the instructions '
                   'at https://wiki.archlinux.org/index.php/Multilib.')
             raise e
 
         # 2. Android pieces.
         import android
-        android.ensure_android('linux', artifact_mode=artifact_mode)
+        android.ensure_android('linux', artifact_mode=artifact_mode,
+                               no_interactive=self.no_interactive)
 
     def suggest_mobile_android_mozconfig(self, artifact_mode=False):
         import android
         android.suggest_mozconfig('linux', artifact_mode=artifact_mode)
 
     def suggest_mobile_android_artifact_mode_mozconfig(self):
         self.suggest_mobile_android_mozconfig(artifact_mode=True)
 
--- a/python/mozboot/mozboot/centosfedora.py
+++ b/python/mozboot/mozboot/centosfedora.py
@@ -107,17 +107,18 @@ class CentOSFedoraBootstrapper(StyloInst
 
             self.run_as_root(['rpm', '-ivh', yasm])
 
     def ensure_mobile_android_packages(self, artifact_mode=False):
         # Install Android specific packages.
         self.dnf_install(*self.mobile_android_packages)
 
         import android
-        android.ensure_android('linux', artifact_mode=artifact_mode)
+        android.ensure_android('linux', artifact_mode=artifact_mode,
+                               no_interactive=self.no_interactive)
 
     def suggest_mobile_android_mozconfig(self, artifact_mode=False):
         import android
         android.suggest_mozconfig('linux', artifact_mode=artifact_mode)
 
     def suggest_mobile_android_artifact_mode_mozconfig(self):
         self.suggest_mobile_android_mozconfig(artifact_mode=True)
 
--- a/python/mozboot/mozboot/debian.py
+++ b/python/mozboot/mozboot/debian.py
@@ -122,17 +122,18 @@ class DebianBootstrapper(StyloInstall, B
         # http://developer.android.com/sdk/installing/index.html?pkg=tools.
         self.run_as_root(['dpkg', '--add-architecture', 'i386'])
         # After adding a new arch, the list of packages has to be updated
         self.apt_update()
         self.apt_install(*self.mobile_android_packages)
 
         # 2. Android pieces.
         import android
-        android.ensure_android('linux', artifact_mode=artifact_mode)
+        android.ensure_android('linux', artifact_mode=artifact_mode,
+                               no_interactive=self.no_interactive)
 
     def suggest_mobile_android_mozconfig(self, artifact_mode=False):
         import android
         android.suggest_mozconfig('linux', artifact_mode=artifact_mode)
 
     def suggest_mobile_android_artifact_mode_mozconfig(self):
         self.suggest_mobile_android_mozconfig(artifact_mode=True)
 
--- a/python/mozboot/mozboot/mach_commands.py
+++ b/python/mozboot/mozboot/mach_commands.py
@@ -18,20 +18,22 @@ class Bootstrap(object):
     """Bootstrap system and mach for optimal development experience."""
 
     @Command('bootstrap', category='devenv',
              description='Install required system packages for building.')
     @CommandArgument('--application-choice',
                      default=None,
                      help='Pass in an application choice (see mozboot.bootstrap.APPLICATIONS) '
                      'instead of using the default interactive prompt.')
-    def bootstrap(self, application_choice=None):
+    @CommandArgument('--no-interactive', dest='no_interactive', action='store_true',
+                     help='Answer yes to any (Y/n) interactive prompts.')
+    def bootstrap(self, application_choice=None, no_interactive=False):
         from mozboot.bootstrap import Bootstrapper
 
-        bootstrapper = Bootstrapper(choice=application_choice)
+        bootstrapper = Bootstrapper(choice=application_choice, no_interactive=no_interactive)
         bootstrapper.bootstrap()
 
 
 @CommandProvider
 class VersionControlCommands(object):
     def __init__(self, context):
         self._context = context
 
--- a/python/mozboot/mozboot/osx.py
+++ b/python/mozboot/mozboot/osx.py
@@ -349,17 +349,18 @@ class OSXBootstrapper(BaseBootstrapper):
             print(JAVA_LICENSE_NOTICE)  # We accepted a license agreement for the user.
 
         is_64bits = sys.maxsize > 2**32
         if not is_64bits:
             raise Exception('You need a 64-bit version of Mac OS X to build Firefox for Android.')
 
         # 2. Android pieces.
         import android
-        android.ensure_android('macosx', artifact_mode=artifact_mode)
+        android.ensure_android('macosx', artifact_mode=artifact_mode,
+                               no_interactive=self.no_interactive)
 
     def suggest_homebrew_mobile_android_mozconfig(self, artifact_mode=False):
         import android
         android.suggest_mozconfig('macosx', artifact_mode=artifact_mode)
 
     def _ensure_macports_packages(self, packages):
         self.port = self.which('port')
         assert self.port is not None
@@ -412,17 +413,18 @@ class OSXBootstrapper(BaseBootstrapper):
                             'to get the latest version.')
 
         is_64bits = sys.maxsize > 2**32
         if not is_64bits:
             raise Exception('You need a 64-bit version of Mac OS X to build Firefox for Android.')
 
         # 2. Android pieces.
         import android
-        android.ensure_android('macosx', artifact_mode=artifact_mode)
+        android.ensure_android('macosx', artifact_mode=artifact_mode,
+                               no_interactive=self.no_interactive)
 
     def suggest_macports_mobile_android_mozconfig(self, artifact_mode=False):
         import android
         android.suggest_mozconfig('macosx', artifact_mode=artifact_mode)
 
     def ensure_package_manager(self):
         '''
         Search package mgr in sys.path, if none is found, prompt the user to install one.