diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6f27c72 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,186 @@ +ARG USER_NAME=keil +FROM scottyhardy/docker-wine:devel-8.2 +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() { \ + pattern="fixme:win:NtUserLockWindowUpdate ((nil))"; \ + output=$( \ + sed \ + # Handle exit hints + -e "s/^exit \([[:digit:]]\+\)$/\1/; t end;" \ + # Handle multiple occurrences of $pattern + -e "/$pattern/{ x; s/^x\{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 + { inotifywait -e create /tmp/.X11-unix/ 2>&1 > /dev/null & }; \ + resolver=$!; \ + { \ + # 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 + +ENV USER_NAME=${USER_NAME}