# This is a base dockerfile for UTBot. It's image can be used as a development environment and as a first step in building UTBot, it's release build and integration tests.
# This dockerfile installs grpc, cmake, llvm, uclibc, z3. Also it installs such packages as ssh, git, openssh-server, nodejs, python and others.
# You need to build this dockerfile inside UnitTestBot/UTBotCpp/docker directory.

ARG OPERATING_SYSTEM_TAG
FROM ubuntu:$OPERATING_SYSTEM_TAG as base_env
LABEL maintainer="UnitTestBot"
SHELL ["/bin/bash", "--login", "-c"]

ENV UTBOT_ALL=/utbot_distr
ENV WORKSPACE=/github/workspace/

USER root

# Handle sudo annoying bug https://bugzilla.redhat.com/show_bug.cgi?id=1773148
RUN echo "Set disable_coredump false" >> /etc/sudo.conf

WORKDIR docker

# Install required system packages
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends sudo file python3-dateutil wget fakeroot libssl-dev build-essential \
      software-properties-common
RUN echo "check_certificate = off" > /etc/wgetrc

# We use C++ 17 for UnitTestBot, it is available in gcc-9; default gcc for ubuntu:18.04 is gcc-7
RUN if [[ "$OPERATING_SYSTEM_TAG" = "18.04" ]] ; then RUN add-apt-repository ppa:ubuntu-toolchain-r/test ; fi
RUN apt update && apt install -y --no-install-recommends gcc-9 g++-9 gcc-multilib g++-multilib gcc-9-multilib g++-9-multilib

# Set gcc-9 as default gcc version
RUN sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 100
RUN sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 100
RUN sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-9 100

# install git
RUN apt install -y software-properties-common git libcurl4-openssl-dev

# install others apt
RUN apt install -y --no-install-recommends ninja-build python3-setuptools curl libcap-dev libncurses5-dev unzip \
      libtcmalloc-minimal4 libgoogle-perftools-dev libsqlite3-dev doxygen python3-pip autoconf libtool

# install vscode dependencies
RUN apt install -y libxshmfence1 libglu1 libgconf-2-4 libatk1.0-0 libatk-bridge2.0-0 libgdk-pixbuf2.0-0 libgtk-3-0 \
      libgbm-dev libnss3-dev libxss-dev libasound2 xvfb

RUN mkdir $UTBOT_ALL && cd $UTBOT_ALL

# Install latest CMake
ENV UTBOT_INSTALL_DIR=$UTBOT_ALL/install
ENV UTBOT_CMAKE_BINARY=$UTBOT_INSTALL_DIR/bin/cmake
RUN wget https://github.com/Kitware/CMake/releases/download/v3.17.2/cmake-3.17.2.tar.gz -O /tmp/cmake_src.tar.gz
RUN tar xfz /tmp/cmake_src.tar.gz -C $UTBOT_ALL
RUN cd $UTBOT_ALL/cmake-3.17.2/ && ./bootstrap --prefix=$UTBOT_INSTALL_DIR --parallel=`nproc` && make -j`nproc` && make install && cd $UTBOT_ALL && rm -rf $UTBOT_ALL/cmake-3.17.2

# Create user
RUN useradd -m utbot && \
    echo utbot:utbot | chpasswd && \
    cp /etc/sudoers /etc/sudoers.bak && \
    echo 'utbot  ALL=(root) NOPASSWD: ALL' >> /etc/sudoers

USER utbot
WORKDIR /home/utbot

# Install llvm
USER root
ARG LLVM_VERSION_MAJOR
RUN mkdir $UTBOT_ALL/llvm_gold_plugin
RUN wget -P $UTBOT_ALL/llvm_gold_plugin https://raw.githubusercontent.com/bminor/binutils-gdb/fd67aa1129fd006ad49ed5ecb2b063705211553a/include/plugin-api.h
RUN git clone --single-branch --branch "release/${LLVM_VERSION_MAJOR}.x" --depth 1 "https://github.com/llvm/llvm-project.git" $UTBOT_ALL/llvm-project
WORKDIR $UTBOT_ALL/llvm-project
RUN mkdir build && cd build \
    && $UTBOT_CMAKE_BINARY \
    -DCMAKE_BUILD_TYPE=MinSizeRel \
    -DCMAKE_INSTALL_PREFIX=$UTBOT_INSTALL_DIR \
    -DLLVM_INCLUDE_TESTS=OFF \
    -DLLVM_BINUTILS_INCDIR=$UTBOT_ALL/llvm_gold_plugin \
    -DLLVM_ENABLE_RTTI=ON \
    -DLLVM_ENABLE_EH=ON \
    -DLLVM_TARGETS_TO_BUILD="host" \
    -DLLVM_INSTALL_UTILS=ON \
    -DLLVM_ENABLE_PROJECTS="clang;libclc;lld" \
    -DLLVM_ENABLE_RUNTIMES="compiler-rt;libc;libcxx;libcxxabi" \
    -G "Ninja" ../llvm \
    && $UTBOT_CMAKE_BINARY --build . --target install

# Install KLEE dependencies
ENV CURL_CA_BUNDLE=""
RUN sudo -E pip3 install tabulate==0.8.7 \
                         typing==3.7.4.3 \
                         lit==0.11.0.post1 \
                         wllvm==1.3.1

ENV CFLAGS="-gdwarf-4"
ENV CXXFLAGS="-gdwarf-4"

WORKDIR $UTBOT_ALL/llvm-project
RUN mkdir libcxx_build && cd libcxx_build \
    && export CC=wllvm \
    && export CXX=wllvm++ \
    && export LLVM_COMPILER=clang \
    && export LLVM_COMPILER_PATH=$UTBOT_INSTALL_DIR/bin \
    && $UTBOT_CMAKE_BINARY \
    -DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi" \
    -DLLVM_ENABLE_THREADS:BOOL=OFF \
    -DLIBCXX_ENABLE_THREADS:BOOL=OFF \
    -DLIBCXX_ENABLE_SHARED:BOOL=ON \
    -DLIBCXXABI_ENABLE_THREADS:BOOL=OFF \
    -DCMAKE_BUILD_TYPE=MinSizeRel \
    -DLLVM_TARGETS_TO_BUILD=host \
    -DCMAKE_INSTALL_PREFIX=$UTBOT_ALL/libcxx/install \
    -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY:BOOL=ON ../llvm \
    && make cxx -j`nproc` && cd projects && make install \
    && find $UTBOT_ALL/libcxx/install/lib/lib*.so -print0 | xargs -0 --max-args=1 extract-bc \
    && find $UTBOT_ALL/libcxx/install/lib/lib*.a -print0 | xargs -0 --max-args=1 extract-bc \
    && cp -R $UTBOT_ALL/llvm-project/libcxxabi $UTBOT_ALL/libcxx \
    && export CC=$UTBOT_INSTALL_DIR/bin/clang \
    && export CXX=$UTBOT_INSTALL_DIR/bin/clang++

# Delete llvm src
RUN cd $UTBOT_ALL && rm -rf $UTBOT_ALL/llvm-project && rm -rf $UTBOT_ALL/llvm_gold_plugin

# Install GRPC
FROM base_env
RUN git clone --single-branch -b v1.49.0 --depth=1 https://github.com/grpc/grpc $UTBOT_ALL/grpc
RUN cd $UTBOT_ALL/grpc && git submodule update --init
RUN cd $UTBOT_ALL/grpc \
  && mkdir -p cmake/build \
  && cd cmake/build \
  && $UTBOT_CMAKE_BINARY -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=$UTBOT_INSTALL_DIR ../.. \
  && make -j`nproc` \
  && make install \
  && cd $UTBOT_ALL \
  && rm -rf $UTBOT_ALL/grpc

# Get gtest
USER root
RUN git clone --single-branch -b release-1.10.0 https://github.com/google/googletest.git $UTBOT_ALL/gtest
RUN cd $UTBOT_ALL/gtest && mkdir build && cd build && \
    $UTBOT_CMAKE_BINARY -G "Ninja" -DCMAKE_INSTALL_PREFIX=$UTBOT_INSTALL_DIR .. && \
    $UTBOT_CMAKE_BINARY --build . --target install && \
    cd $UTBOT_ALL
USER utbot

# Install z3
USER root
RUN git clone --single-branch -b z3-4.8.17 --depth=1 https://github.com/Z3Prover/z3.git $UTBOT_ALL/z3-src
RUN cd $UTBOT_ALL/z3-src && mkdir build && cd build && \
    $UTBOT_CMAKE_BINARY -G "Ninja" -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=$UTBOT_INSTALL_DIR .. && \
    $UTBOT_CMAKE_BINARY --build . --target install && \
    cd $UTBOT_ALL && \
    rm -rf $UTBOT_ALL/z3-src
USER utbot

# Add ssh authorization key
RUN mkdir -p /home/utbot/.ssh/
RUN echo "StrictHostKeyChecking no" >> /home/utbot/.ssh/config

USER root
ARG OPERATING_SYSTEM_TAG

# When we switch to Ubuntu 20 container, we may still need old libssl if we support Ubuntu < 18
# RUN "deb http://security.ubuntu.com/ubuntu bionic-security main" | sudo tee -a /etc/apt/sources.list
# RUN apt update && apt-cache policy libssl1.0-dev
# RUN apt install -y --no-install-recommends libssl1.0-dev

RUN if [[ "$OPERATING_SYSTEM_TAG" = "18.04" ]] ; then apt update && apt install -y --no-install-recommends nodejs-dev node-gyp libssl1.0-dev ; fi
RUN apt update && apt install -y --no-install-recommends nodejs npm openssh-server net-tools gdb vim-nox rsync
RUN pip3 install git+https://chromium.googlesource.com/external/gyp

# Update node and npm
RUN npm cache clean -f
RUN sudo -E npm install -g n
RUN sudo -E n 16
RUN sudo -E apt remove -y --purge nodejs npm

# Install cmake which can generate link_commands.json. Installing cmake the second time in order to build base image faster since this cmake may be changed frequently.
RUN git clone --single-branch -b utbot-0.1.2b --depth=1 https://github.com/Software-Analysis-Team/CMake.git $UTBOT_ALL/cmake
RUN cd $UTBOT_ALL/cmake && $UTBOT_CMAKE_BINARY  -DCMAKE_INSTALL_PREFIX=$UTBOT_INSTALL_DIR . && \
    make -j`nproc` && make install && cd $UTBOT_ALL && rm -rf $UTBOT_ALL/cmake

## Setup ssh
RUN mkdir -p /var/run/sshd
# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

# Append installation paths
RUN mkdir $UTBOT_ALL/klee && chown utbot: $UTBOT_ALL/klee/
RUN mkdir $UTBOT_ALL/server-install && chown utbot: $UTBOT_ALL/server-install/

# Installing patched version of lit to handle Klee unit-test execution properly
USER root
COPY building_dependencies/patches/lit.py /usr/local/bin/lit
RUN chmod +x /usr/local/bin/lit

RUN sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 100

# Download CLI11 and Rang libs for nice CLI
RUN wget https://github.com/CLIUtils/CLI11/releases/download/v1.9.1/CLI11.hpp -P $UTBOT_ALL/cli
RUN wget https://github.com/agauniyal/rang/releases/download/v3.1.0/rang.hpp -P $UTBOT_ALL/cli

# Applying environment variables to all users
COPY building_dependencies/runtime_env.sh /home/utbot/.bashrc
COPY building_dependencies/runtime_env.sh /root/.bashrc

# We need to install version 32 and 64 for klee.
# Install uclibc-32
RUN git clone -b klee_uclibc_v1.2 https://github.com/klee/klee-uclibc.git $UTBOT_ALL/klee-uclibc-32
WORKDIR $UTBOT_ALL/klee-uclibc-32
RUN ./configure --make-llvm-lib && make KLEE_CFLAGS="-m32" -j`nproc`

# Install uclibc-64
RUN git clone -b klee_uclibc_v1.2 https://github.com/klee/klee-uclibc.git $UTBOT_ALL/klee-uclibc-64
WORKDIR $UTBOT_ALL/klee-uclibc-64
RUN ./configure --make-llvm-lib && make -j`nproc`

# Download library for access private members
RUN git clone https://github.com/martong/access_private.git $UTBOT_ALL/access_private

RUN apt autoclean

RUN chsh -s /bin/bash utbot
EXPOSE 2020
CMD ["/usr/sbin/sshd", "-D", "-p 2020"]
