ARG USER_NAME=keil FROM scottyhardy/docker-wine:devel-8.4 ARG USER_NAME ARG KEIL_URL=https://armkeil.blob.core.windows.net/eval/MDK537.EXE ARG PACK_URL=https://ennis.zhaw.ch/pack/InES.CTBoard14_DFP.4.0.3.pack ARG DEBUG=0 RUN \ apt-get update \ && apt-get upgrade -y \ && apt-get install -y \ dwm \ clangd \ gdb-multiarch \ htop \ inotify-tools \ python3 \ python-is-python3 \ python3-pip \ ssh \ vim \ xmlstarlet \ && { \ [ "$DEBUG" -eq 1 ] \ && apt-get install -y \ build-essential \ imagemagick \ || true; \ } \ && rm -rf /var/lib/apt/lists/ RUN pip install pyocd RUN \ [ "$DEBUG" -eq 1 ] && { \ git clone https://github.com/stefanhaustein/TerminalImageViewer.git && \ cd TerminalImageViewer/src/main/cpp && \ make && \ make install && \ cd - && \ rm -rf TerminalImageViewer; \ } \ || true RUN \ printHeading() { \ local heading; \ heading="====================================================="; \ echo "$heading"; \ [ -z "$1" ] && cat || echo "$1"; \ echo "$heading"; \ }; \ wget "${KEIL_URL}" --progress=bar:force:noscroll -O MDK537.exe; \ [ "$DEBUG" -eq 1 ] && { \ mkdir -p logs; \ mkdir -p screens; \ } \ || true && \ # Handle console output of MDK537 installer handle_output() { \ # A pattern that is supposed to indicates that wine got stuck pattern="fixme:win:NtUserLockWindowUpdate ((nil))"; \ # The amount of times the pattern should occur for the process to be considered stuck patternCount=2; \ sed \ -u \ # Handle multiple occurrences of $pattern -e "/$pattern/{ x; s/^x\{$(expr $patternCount - 1)\}$/\0/; x; t stuck; x; s/^\(x*\)$/\1x/; x; };" \ # Delete output and return to start -e "b;" \ # Branch "stuck": delete output and exit with code 42 -e ":stuck q42;" \ # Branch "end": exit with code 0 -e ":end q;"; \ exitCode="$?"; \ # Kill installer if it got stuck (according to console output) [ "$exitCode" -eq 42 ] && pkill -9 MDK537.exe; \ # Use `sed`s exit code if non-zero [ "$exitCode" -ne 0 ] && exit "$exitCode" || \ # Return true otherwise true; \ }; \ # Run actual MDK537 installer install_keil() { \ printHeading "Starting ARM Keil installation"; \ try="$1"; \ logFile="$(mktemp)"; \ # Run installer asynchronously { \ { \ local exitCode; \ exitCodeFile="$(mktemp)"; \ { \ 2>&1 WINEDEBUG=+all,trace-all,warn-all /usr/bin/entrypoint wine MDK537.exe --batch-install; \ echo "$?" > "$exitCodeFile"; \ } \ # Write output to a log file when debugging | { [ "$DEBUG" -eq 1 ] && tee "$logFile" || cat; } \ # Pipe stdout and stderr to `handle_output` function | handle_output; \ outputHandlerCode="$?"; \ exitCode="$(cat "$exitCodeFile")"; \ rm "$exitCodeFile"; \ bash -c "exit $([ "$outputHandlerCode" -ne 0 ] && echo "$outputHandlerCode" || echo "$exitCode")"; \ } & \ }; \ pid="$!"; \ # Continuously display screenshots and iteration number [ "$DEBUG" -eq 1 ] \ && { \ { \ x=0; \ maxCount=120; \ while ps -p "$pid" > /dev/null && [ "$x" -ne "$maxCount" ]; do \ # Create screenshot and print it to the console fileName="screens/install-try$try-$x.png"; \ import -window root "$fileName"; \ tiv -w 10000 -h 10000 "$fileName"; \ x="$(expr "$x" + 1)"; \ echo "Frame #$x"; \ sleep 1; \ done; \ # Kill installer after timeout indicated by `maxCount` [ "$x" -eq "$maxCount" ] && { pkill -9 MDK537.exe; mv "$logFile" "logs/timeout-try$try.log"; }; \ } & \ }; \ wait "$pid"; \ exitCode="$?"; \ # Rename log file according to the state of the installer [ "$DEBUG" -eq 1 ] \ && [ -f "$logFile" ] \ && { \ # Move logs to location based on exit code [ "$exitCode" -eq 0 ] && mv "$logFile" "logs/success-try$try.log"; \ [ "$exitCode" -eq 42 ] && mv "$logFile" "logs/timeout-handled-try$try.log"; \ [ "$exitCode" -ne 0 ] && mv "$logFile" "logs/fail-try$try.log"; \ }; \ { \ [ "$exitCode" -ne 0 ] && { \ [ "$exitCode" -eq 42 ] && echo "The installation Got Stuck" || \ echo "The Installation Failed"; \ } || \ echo "The Installation Was Successful"; \ echo "Installation Process Exited With Code $exitCode"; \ } | printHeading; \ return "$exitCode"; \ }; \ display=:90; \ export DISPLAY="$display"; \ mkdir -p --mode=777 /tmp/.X11-unix; \ # Create job for waiting for Xvfb to start watchStarting="$(mktemp)"; \ { 2>&1 inotifywait -e create /tmp/.X11-unix/; } | { sed -u -e "/^Watches established.\$/e rm \"$watchStarting\""; } & \ resolver="$!"; \ while [ -f "$watchStarting" ]; do true; done; \ { \ # Improve arguments for screenshots ARGS="$([ $DEBUG -eq 1 ] && echo "-screen 0 640x480x24 -dpi 192" || echo "")"; \ Xvfb "${DISPLAY}" ${ARGS} & \ }; \ displayPID="$!"; \ # Wait for Xvfb to start wait "$resolver"; \ y=0; \ while ! \ install_keil \ "$y" \ ; \ do \ printHeading "Restarting Installation"; \ # Increase counter y="$(expr "$y" + 1)"; \ done && \ kill -9 "$displayPID" > /dev/null 2>&1; \ # Delete unfinished installations rm -rf "$(/usr/bin/entrypoint winepath 'C:\Keil_v5')/Backup."*; \ rm MDK537.exe; \ rm -f /tmp/.X*-lock; RUN \ keilConfig="$(/usr/bin/entrypoint winepath 'C:\Keil_v5\TOOLS.INI')" && \ winAppData="$(/usr/bin/entrypoint wine cmd.exe /c 'echo %LOCALAPPDATA%' | tr -d '\r' | sed 's/\\/\\\\/g')" && \ packDir="$winAppData"'\Arm\Packs' && \ sed -i '/^RTEPATH=/d' "$keilConfig" && \ echo 'RTEPATH="'"$packDir"'"' | sed -i '/\[UV2\]/ r /dev/stdin' "$keilConfig" RUN \ wget "${PACK_URL}" --progress=bar:force:noscroll --no-check-certificate -O InES.pack; \ /usr/bin/entrypoint xvfb-run wine 'C:\Keil_v5\UV4\PackUnzip.exe' --embedded --agree-license InES.pack & \ pid="$!"; \ wait "$pid"; \ rm InES.pack; \ rm -f /tmp/.X*-lock; RUN \ apt-get update && \ ln -s "$(which true)" /usr/bin/depmod && \ wget https://github.com/stlink-org/stlink/releases/download/v1.7.0/stlink_1.7.0-1_amd64.deb --progress=bar:force:noscroll -O stlink.deb && \ dpkg -i stlink.deb; \ apt-get install --fix-broken -y && \ rm -rf /var/lib/apt/lists/ && \ rm stlink.deb RUN ln -s /usr/bin/gdb-multiarch /usr/bin/arm-none-eabi-gdb RUN echo "${USER_NAME} ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/keil COPY ./compile.sh /bin/st-compile RUN chmod a+x /bin/st-compile ENV USER_NAME=${USER_NAME}