Bug 1460355 - Fix: Change how the packages are sent to the sdkmanager to install, avoid missing argument. r?nalexander draft
authorAniket Kadam <anikadamg@gmail.com>
Tue, 24 Jul 2018 18:37:57 +0530
changeset 821971 880831526323cecbd455ff4cf39826929fdb7f39
parent 821479 143984185dcece46031c970179ddea4837a6c01d
push id117239
push userbmo:anikadamg@gmail.com
push dateTue, 24 Jul 2018 13:12:56 +0000
reviewersnalexander
bugs1460355
milestone63.0a1
Bug 1460355 - Fix: Change how the packages are sent to the sdkmanager to install, avoid missing argument. r?nalexander The argument --package_file was removed in the latest sdkmanager by Google's Android. But the docs for it say packages can also be sent by putting them in quotes and calling the sdk manager with them as individual args. So now instead of sending the file directly with the --package_file argument, the package names are read from the file and the sdk manager is called with them as individual args. Historically this has been thought of as a bug that happens with the wrong version of the JDK, but this can be reproduced with just java 1.8.0_181 and the most up to date version of sdkmanager currently 26.1.1 Important note, the mach bootstrap command downloads an older version of the sdk and this bug is not present in the older version. Since the way of updating packages I'm proposiing to use is backwards compatible, there shouldn't be any problem in any version of the sdkamanger. This is a simpler fix than trying the --package_file argument, particularly because it would involve capturing output (to detect this particular bug) that's also supposed to be shown to the user because this also happens when the user is supposed to be interacting with the install. MozReview-Commit-ID: L7VhCVKJNIf
python/mozboot/mozboot/android.py
--- a/python/mozboot/mozboot/android.py
+++ b/python/mozboot/mozboot/android.py
@@ -224,30 +224,49 @@ def ensure_android_sdk_and_ndk(mozbuild_
     else:
         # The SDK archive used to include a top-level
         # android-sdk-$OS_NAME directory; it no longer does so.  We
         # preserve the old convention to smooth detecting existing SDK
         # installations.
         install_mobile_android_sdk_or_ndk(sdk_url, os.path.join(mozbuild_path,
                                           'android-sdk-{0}'.format(os_name)))
 
+def get_packages_to_install(packages_file_name):
+    """
+    sdkmanager version 26.1.1 (current) and some versions below have a bug that makes this command fail:
+        args = [sdkmanager_tool, '--package_file={0}'.format(package_file_name)]
+        subprocess.check_call(args)
+    The error is in the sdkmanager, where the --package_file param isn't recognized.
+        The error is being tracked here https://issuetracker.google.com/issues/66465833
+    Meanwhile, this workaround achives installing all required Android packages by reading
+    them out of the same file that --package_file would have used, and passing them as strings.
+    So from here: https://developer.android.com/studio/command-line/sdkmanager
+    Instead of:
+        sdkmanager --package_file=package_file [options]
+    We're doing:
+        sdkmanager "platform-tools" "platforms;android-26"
+    """
+    with open(packages_file_name) as package_file:
+        return map(lambda package: package.strip(), package_file.readlines())
 
 def ensure_android_packages(sdkmanager_tool, packages=None, no_interactive=False):
     '''
     Use the given sdkmanager tool (like 'sdkmanager') to install required
     Android packages.
     '''
 
     # This tries to install all the required Android packages.  The user
     # may be prompted to agree to the Android license.
     package_file_name = os.path.abspath(os.path.join(os.path.dirname(__file__),
                                         'android-packages.txt'))
     print(INSTALLING_ANDROID_PACKAGES % open(package_file_name, 'rt').read())
 
-    args = [sdkmanager_tool, '--package_file={0}'.format(package_file_name)]
+    args = [sdkmanager_tool]
+    args.extend(get_packages_to_install(package_file_name))
+
     if not no_interactive:
         subprocess.check_call(args)
         return
 
     # Emulate yes.  For a discussion of passing input to check_output,
     # see https://stackoverflow.com/q/10103551.
     yes = '\n'.join(['y']*100)
     proc = subprocess.Popen(args,