name: Analysis and Ports

on:
  workflow_dispatch:
    inputs:
      start:
        description: 'Start analysis and port workflow'
        default: 'yes'
        required: true

jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          - name: GCC on Linux
            os: ubuntu-latest
            config: "--enable-debug --disable-flto"
            make_test: "yes"
          - name: Clang-analyzer
            os: ubuntu-latest
            config: "CC=clang --enable-debug --disable-flto --disable-static"
            make_test: "yes"
            clang_analysis: "yes"
          - name: libevent
            os: ubuntu-latest
            install_libevent: "yes"
            config: "CC=clang --enable-debug --disable-flto --with-libevent --disable-static"
            make_test: "yes"
            clang_analysis: "yes"
          - name: OS X
            os: macos-latest
            install_expat: "yes"
            config: "--enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat"
            make_test: "yes"
          - name: Clang on OS X
            os: macos-latest
            install_expat: "yes"
            config: "CC=clang --enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat --disable-static"
            make_test: "yes"
            clang_analysis: "yes"
          - name: ubsan (gcc undefined behaviour sanitizer)
            os: ubuntu-latest
            config: 'CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=undefined -fno-sanitize-recover=all" --disable-flto --disable-static'
            make_test: "yes"
          - name: asan (gcc address sanitizer)
            os: ubuntu-latest
            config: 'CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address" --disable-flto --disable-static'
            make_test: "yes"
          - name: Apple iPhone on iOS, armv7
            os: macos-latest
            AUTOTOOLS_HOST: armv7-apple-ios
            OPENSSL_HOST: ios-cross
            IOS_SDK: iPhoneOS
            IOS_CPU: armv7s
            test_ios: "yes"
            config: "no"
            make: "no"
          - name: Apple iPhone on iOS, arm64
            os: macos-latest
            AUTOTOOLS_HOST: aarch64-apple-ios
            OPENSSL_HOST: ios64-cross
            IOS_SDK: iPhoneOS
            IOS_CPU: arm64
            test_ios: "yes"
            config: "no"
            make: "no"
          - name: Apple TV on iOS, arm64
            os: macos-latest
            AUTOTOOLS_HOST: aarch64-apple-ios
            OPENSSL_HOST: ios64-cross
            IOS_SDK: AppleTVOS
            IOS_CPU: arm64
            test_ios: "yes"
            config: "no"
            make: "no"
          - name: Apple Watch on iOS, armv7
            os: macos-latest
            AUTOTOOLS_HOST: armv7-apple-ios
            OPENSSL_HOST: ios-cross
            IOS_SDK: WatchOS
            IOS_CPU: armv7k
            test_ios: "yes"
            config: "no"
            make: "no"
          - name: iPhoneSimulator on OS X, i386
            os: macos-latest
            AUTOTOOLS_HOST: i386-apple-ios
            OPENSSL_HOST: iphoneos-cross
            IOS_SDK: iPhoneSimulator
            IOS_CPU: i386
            test_ios: "yes"
            config: "no"
            make: "no"
          - name: iPhoneSimulator on OS X, x86_64
            os: macos-latest
            AUTOTOOLS_HOST: x86_64-apple-ios
            OPENSSL_HOST: iphoneos-cross
            IOS_SDK: iPhoneSimulator
            IOS_CPU: x86_64
            test_ios: "yes"
            config: "no"
            make: "no"
          - name: AppleTVSimulator on OS X, x86_64
            os: macos-latest
            AUTOTOOLS_HOST: x86_64-apple-ios
            OPENSSL_HOST: iphoneos-cross
            IOS_SDK: AppleTVSimulator
            IOS_CPU: x86_64
            test_ios: "yes"
            config: "no"
            make: "no"
          - name: WatchSimulator on OS X, i386
            os: macos-latest
            AUTOTOOLS_HOST: i386-apple-ios
            OPENSSL_HOST: iphoneos-cross
            IOS_SDK: WatchSimulator
            IOS_CPU: i386
            test_ios: "yes"
            config: "no"
            make: "no"
          - name: Android armv7a
            os: ubuntu-latest
            AUTOTOOLS_HOST: armv7a-linux-androidabi
            OPENSSL_HOST: android-arm
            ANDROID_CPU: armv7a
            ANDROID_API: 23
            test_android: "yes"
            config: "no"
            make: "no"
          - name: Android aarch64
            os: ubuntu-latest
            AUTOTOOLS_HOST: aarch64-linux-android
            OPENSSL_HOST: android-arm64
            ANDROID_CPU: aarch64
            ANDROID_API: 23
            test_android: "yes"
            config: "no"
            make: "no"
          - name: Android x86
            os: ubuntu-latest
            AUTOTOOLS_HOST: i686-linux-android
            OPENSSL_HOST: android-x86
            ANDROID_CPU: x86
            ANDROID_API: 23
            test_android: "yes"
            config: "no"
            make: "no"
          - name: Android x86_64
            os: ubuntu-latest
            AUTOTOOLS_HOST: x86_64-linux-android
            OPENSSL_HOST: android-x86_64
            ANDROID_CPU: x86_64
            ANDROID_API: 23
            test_android: "yes"
            config: "no"
            make: "no"
          - name: Windows
            os: windows-latest
            test_windows: "yes"
            config: "no"
            make: "no"
 
    steps:
      - uses: actions/checkout@v2
        with:
          submodules: false
      - name: test_windows
        if: ${{ matrix.test_windows == 'yes' }}
        shell: bash
        run: |
          export unboundpath=`pwd`
          echo unboundpath=${unboundpath}
          cd ..
          export prepath=`pwd`
          echo prepath=${prepath}
          #echo "curl cpanm"
          #curl -L -k -s -S -o cpanm https://cpanmin.us/
          #echo "perl cpanm Pod::Usage"
          #perl cpanm Pod::Usage
          mkdir openssl
          echo "curl openssl"
          curl -L -k -s -S -o openssl-1.1.1j.tar.gz https://www.openssl.org/source/openssl-1.1.1j.tar.gz
          tar xzf openssl-1.1.1j.tar.gz
          cd openssl-1.1.1j
          # remove pod::Usage because we do not need -help or -man output
          # from the Configure script
          echo "Fixup ./Configure by removing use Pod::Usage require"
          sed -e 's/use Pod::Usage//' < Configure > Configure.fix
          echo "./Configure.fix no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix=\""$prepath/openssl\"""
          ./Configure.fix no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix="$prepath/openssl"
          # make the libs only, build faster
          echo "make build_libs"
          #make
          make build_libs
          mv Makefile Makefile.orig
          # fixup \\ in the installtop to /.
          echo "fixup INSTALLTOP"
          sed -e 's?^INSTALLTOP=.*$?INSTALLTOP='"$prepath"'/openssl?' < Makefile.orig > Makefile
          # install the includes and libs only, build faster
          echo "make install_dev"
          #make install_sw
          make install_dev
          cd ..
          mkdir expat
          echo "curl expat"
          curl -L -k -s -S -o expat-2.2.10.tar.gz https://github.com/libexpat/libexpat/releases/download/R_2_2_10/expat-2.2.10.tar.gz
          tar xzf expat-2.2.10.tar.gz
          cd expat-2.2.10
          echo "./configure SHELL=/usr/bin/bash CONFIG_SHELL=/usr/bin/bash --prefix=\"$prepath/expat\" --exec-prefix=\"$prepath/expat\" --bindir=\"$prepath/expat/bin\" --includedir=\"$prepath/expat/include\" --mandir=\"$prepath/expat/man\" --libdir=\"$prepath/expat/lib\""
          ./configure SHELL=/usr/bin/bash CONFIG_SHELL=/usr/bin/bash --prefix="$prepath/expat" --exec-prefix="$prepath/expat" --bindir="$prepath/expat/bin" --includedir="$prepath/expat/include" --mandir="$prepath/expat/man" --libdir="$prepath/expat/lib"
          # fixup SHELL is treated specially, but SHELZZ is not by make.
          echo "Fixup Makefiles by renaming SHELL to SHELLZZ"
          mv Makefile Makefile.orig
          sed -e 's/SHELL/SHELLZZ/g' < Makefile.orig > Makefile
          mv lib/Makefile lib/Makefile.orig
          sed -e 's/SHELL/SHELLZZ/g' < lib/Makefile.orig > lib/Makefile
          mv doc/Makefile doc/Makefile.orig
          sed -e 's/SHELL/SHELLZZ/g' < doc/Makefile.orig > doc/Makefile
          mv examples/Makefile examples/Makefile.orig
          sed -e 's/SHELL/SHELLZZ/g' < examples/Makefile.orig > examples/Makefile
          mv tests/Makefile tests/Makefile.orig
          sed -e 's/SHELL/SHELLZZ/g' < tests/Makefile.orig > tests/Makefile
          mv xmlwf/Makefile xmlwf/Makefile.orig
          sed -e 's/SHELL/SHELLZZ/g' < xmlwf/Makefile.orig > xmlwf/Makefile
          echo "make"
          make
          echo "make install"
          make install
          cd ..
          echo "unbound"
          cd unbound
          echo "./configure --enable-debug --enable-static-exe --disable-flto \"--with-ssl=$prepath/openssl\" --with-libexpat=\"$prepath/expat\" --disable-shared"
          ./configure --enable-debug --enable-static-exe --disable-flto "--with-ssl=$prepath/openssl" --with-libexpat="$prepath/expat" --disable-shared
          make
          # specific test output
          #make testbound.exe; ./testbound.exe -s
          #make testbound; ./testbound.exe -p testdata/acl.rpl -o -vvvv
          make test
      - name: test_android
        if: ${{ matrix.test_android == 'yes' }}
        env:
          AUTOTOOLS_HOST: ${{ matrix.AUTOTOOLS_HOST }}
          OPENSSL_HOST: ${{ matrix.OPENSSL_HOST }}
          ANDROID_API: ${{ matrix.ANDROID_API }}
          ANDROID_CPU: ${{ matrix.ANDROID_CPU }}
        run: |
          #(already installed) ./contrib/android/install_tools.sh
          export ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
          echo ANDROID_PREFIX=${ANDROID_PREFIX}
          export ANDROID_SDK_ROOT="$HOME/android-sdk"
          echo ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}
          export ANDROID_NDK_ROOT="$HOME/android-ndk"
          echo ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}
          export AUTOTOOLS_BUILD="$(./config.guess)"
          echo AUTOTOOLS_BUILD=${AUTOTOOLS_BUILD}
          export PKG_CONFIG_PATH="$ANDROID_PREFIX/lib/pkgconfig"
          echo PKG_CONFIG_PATH=${PKG_CONFIG_PATH}
          export CONFIG_OPTS="--build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST --prefix=$ANDROID_PREFIX --with-ssl=$ANDROID_PREFIX --disable-gost --with-libexpat=$ANDROID_PREFIX"
          echo CONFIG_OPTS=${CONFIG_OPTS}
          echo "::group::install_ndk"
          echo "./contrib/android/install_ndk.sh"
          ./contrib/android/install_ndk.sh
          echo "::endgroup::"
          echo "::group::setenv_android.sh"
          echo "./contrib/android/setenv_android.sh"
          source ./contrib/android/setenv_android.sh
          echo "::endgroup::"
          echo "::group::install_openssl"
          echo "./contrib/android/install_openssl.sh"
          ./contrib/android/install_openssl.sh
          echo "::endgroup::"
          echo "::group::install_expat"
          echo "./contrib/android/install_expat.sh"
          ./contrib/android/install_expat.sh
          echo "::endgroup::"
          echo "::group::configure"
          echo "./configure ${CONFIG_OPTS}"
          ./configure ${CONFIG_OPTS}
          echo "::endgroup::"
          echo "::group::make"
          # make is here to preserve environment variables
          make
          echo "::endgroup::"
          echo "::group::make install"
          make install
          echo "::endgroup::"
      - name: test ios
        if: ${{ matrix.test_ios == 'yes' }}
        env:
          AUTOTOOLS_HOST: ${{ matrix.AUTOTOOLS_HOST }}
          OPENSSL_HOST: ${{ matrix.OPENSSL_HOST }}
          IOS_SDK: ${{ matrix.IOS_SDK }}
          IOS_CPU: ${{ matrix.IOS_CPU }}
        run: |
          #(already installed) ./contrib/ios/install_tools.sh
          export AUTOTOOLS_BUILD="$(./config.guess)"
          echo AUTOTOOLS_BUILD=${AUTOTOOLS_BUILD}
          export IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
          echo IOS_PREFIX=${IOS_PREFIX}
          export PKG_CONFIG_PATH="$IOS_PREFIX/lib/pkgconfig"
          echo PKG_CONFIG_PATH=${PKG_CONFIG_PATH}
          export CONFIG_OPTS="--build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST --prefix=$IOS_PREFIX --with-ssl=$IOS_PREFIX --disable-gost --with-libexpat=$IOS_PREFIX"
          echo CONFIG_OPTS=${CONFIG_OPTS}
          echo "::group::setenv_ios.sh"
          echo "./contrib/ios/setenv_ios.sh"
          source ./contrib/ios/setenv_ios.sh
          echo "::endgroup::"
          echo "::group::install_openssl"
          echo "./contrib/ios/install_openssl.sh"
          ./contrib/ios/install_openssl.sh
          echo "::endgroup::"
          echo "::group::install_expat"
          echo "./contrib/ios/install_expat.sh"
          ./contrib/ios/install_expat.sh
          echo "::endgroup::"
          echo "::group::configure"
          echo "./configure ${CONFIG_OPTS}"
          ./configure ${CONFIG_OPTS}
          echo "::endgroup::"
          echo "::group::make"
          # make is here to preserve environment variables
          make
          echo "::endgroup::"
          echo "::group::make install"
          make install
          echo "::endgroup::"
      - name: install libevent
        if: ${{ matrix.install_libevent == 'yes' }}
        run: sudo apt-get install libevent-dev
      - name: install expat
        if: ${{ matrix.install_expat == 'yes' }}
        run: brew install expat
      - name: configure
        if: ${{ matrix.config != 'no' }}
        run: ./configure ${{ matrix.config }}
      - name: make
        if: ${{ matrix.make != 'no' }}
        run: make
      - name: make test
        if: ${{ matrix.make_test == 'yes' }}
        run: make test
      - name: clang-analysis
        if: ${{ matrix.clang_analysis == 'yes' }}
        run: (cd testdata/clang-analysis.tdir; bash clang-analysis.test)
