Too much tag mismatch on android-sdk tool, can't build docker image

Viewed 145

I run this command on docker to install some android-sdk components:

RUN mkdir ${ANDROID_HOME} && wget --output-document=android-sdk.zip https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip \
    && unzip android-sdk.zip -d ${ANDROID_HOME} \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} --list \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "build-tools;25.0.1" \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "build-tools;28.0.3" \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "build-tools;29.0.2" \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "platform-tools" \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "platforms;android-25" \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "platforms;android-28" \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "platforms;android-30" \ 
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "extras;android;m2repository" \
    && echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "extras;google;google_play_services" \
    && ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "ndk;${ANDROID_NDK_VERSION}" \
    && ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "cmake;3.10.2.4988404" \
    && yes | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} --update

since it's a docker image, I must run everything in the same command, otherwise the images will have too much extra layers and occupy too much space.

The problem is that because of mu unreliable internet, it's very likely that I get a tag mismatch for one of these components being installed, what makes me have to run the process again. I'm having to build my docker image more than 30 times to get it to execute all the commands sucessfully.

Is there a way to retry on tag mismatch in the android-sdk?

I also thought of trying to run each line individually but still inside one big command.

Maybe

while true; do
    subcommand1
    if [ $? -eq 0 ]; then
        break
    fi
    sleep 1
done

while true; do
    subcommand2
    if [ $? -eq 0 ]; then
        break
    fi
    sleep 1
done

This would be easy on a .sh file by creating a function that does the while loop, but what if I want to do everything in the Dockerfile?

Anyone has a better idea?

1 Answers

Disclaimer: I have no idea what your command is doing (aside from downloading the android-sdk), so you may need to modify my code slightly to get it to work. Also, your image might not include timeout

First, I would start by moving your script to a separate file, in the same directory as your Dockerfile, then execute it like this:

COPY ./build.sh .
RUN chmod +x ./build.sh && ./build.sh

Now in the script, you can check the output of each line before continuing:

#!/bin/bash

url="https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip"

mkdir ${ANDROID_HOME}
until (
  wget --output-document=android-sdk.zip "$url" && \
  unzip android-sdk.zip -d ${ANDROID_HOME} 
); do
  sleep 1
done

args=(
  "--list"
  "build-tools;25.0.1"
  "build-tools;28.0.3"
  "build-tools;29.0.2"
  "platform-tools"
  "platforms;android-25"
  "platforms;android-28"
  "platforms;android-30"
  "extras;android;m2repository"
  "extras;google;google_play_services"
)

# you may need to modify this slightly!
for arg in "${args[@]}";
do
  until ( echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "$arg" ); do
    sleep 5
  done
done

It would be a good idea to set a timeout so your build doesn't get stuck in an infinite loop. Instead of adding 2 separate checks in the script, I would just add it to the Dockerfile:

# might need adjusting
ARG MAX_TIMEOUT=60

COPY ./build.sh .
RUN chmod +x ./build.sh && timeout -k $MAX_TIMEOUT ./build.sh

I would recommend using this as a Base Image for your main project, rather than include it in the same Dockerfile. That way, if you need to tinker with your project's Dockerfile and rebuild, you won't have to rebuild the android-sdk every time.

Related