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 \ 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; \ output=$( \ sed \ # Handle exit hints -e "s/^exit \([[:digit:]]\+\)$/\1/; t end;" \ # Handle multiple occurrences of $pattern -e "/$pattern/{ x; s/^x\{$(expr $patternCount - 1)\}$/\0/; t stuck; s/^\(x*\)$/\1x/; x; };" \ # Delete output and return to start -e "d; b;" \ # Branch "stuck": delete output and exit with code 42 -e ":stuck s/.*//; 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; \ # Use `sed`s output otherwise [ $exitCode -eq 0 ] && exit $output; \ }; \ # Run actual MDK537 installer install_keil() { \ echo "Starting ARM Keil installation"; \ try=$1; \ # Run installer asynchronously { \ { /usr/bin/entrypoint wine MDK537.exe --batch-install 2>&1 || echo "exit $?"; } \ # Write output to `log.txt` | { [ $DEBUG -eq 1 ] && tee log.txt || cat; } \ # Pipe stdout and stderr to `handle_output` function | handle_output & \ }; \ 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/pit$try-$x.png; \ import -window root $fileName; \ tiv -w 10000 -h 10000 $fileName; \ x=$(bash -c "declare -i x=$x+1; echo "'$x'); \ echo $x; \ sleep 1; \ done; \ # Kill installer after timeout indicated by `maxCount` [ $x -eq $maxCount ] && { pkill -9 MDK537.exe; mv log.txt logs/timeout-$try.txt; }; \ } & \ }; \ wait $pid; \ exitCode=$?; \ # Rename log file according to the state of the installer [ $DEBUG -eq 1 ] \ && [ -f log.txt ] \ && { \ # Move logs to location based on exit code [ $exitCode -eq 0 ] && mv log.txt logs/success-$try.txt; \ [ $exitCode -eq 42 ] && mv log.txt logs/timeout-prevented-$try.txt; \ [ $exitCode -ne 0 ] && mv log.txt logs/fail-$try.txt; \ }; \ [ $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"; \ bash -c "exit $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 \ echo "Restarting Installation"; \ # Increase counter y=$(bash -c "declare -i y=$y+1; echo "'$y'); \ 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; \ pkill -P -9 $pid > /dev/null 2>&1; \ kill -9 $pid > /dev/null 2>&1; \ kill -9 $displayPID > /dev/null 2>&1; \ 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}