# Support for GitHub Actions -- https://github.com/features/actions

# note: GitHub Actions runner images are frequently updated, and
# unfortunately this sometimes breaks builds in mysterious ways...
# see https://github.com/actions/runner-images.git

name: 'CI'

on: [push, workflow_dispatch]

env:
  DEBIAN_FRONTEND: noninteractive
  UPX_CMAKE_BUILD_FLAGS: --verbose

jobs:
  job-rebuild-and-verify-stubs:
    name: 'Rebuild stubs'
    runs-on: ubuntu-20.04
    steps:
      - name: 'Install extra packages'
        run: |
          uname -a; pwd; id; umask
          mkdir ../deps; cd ../deps; mkdir packages
          # for ubuntu-22.04: install python2-minimal
          ##sudo apt-get update && sudo apt-get install -y --no-install-recommends python2-minimal
          # manually install compat libs from Ubuntu 16.04
          wget -q 'http://archive.kernel.org/ubuntu-archive/ubuntu/pool/main/m/mpfr4/libmpfr4_3.1.6-1_amd64.deb'
          for f in ./*.deb; do dpkg -x $f ./packages; done
          sudo mv -v -n ./packages/usr/lib/x86_64-linux-gnu/lib* /usr/lib/x86_64-linux-gnu/
          rm -rf ./*.deb ./packages
          sudo ldconfig
          wget -q -O - https://github.com/upx/upx-stubtools/releases/download/v20221212/bin-upx-20221212.tar.xz | tar -xJ
      - name: 'Check out code'
        uses: actions/checkout@v3
        with: { submodules: true }
      - name: 'Rebuild and verify stubs'
        run: |
          export PATH="$(readlink -en ../deps/bin-upx-20221212):$PATH"
          make -C src/stub maintainer-clean extra-clean
          git status || true
          make -C src/stub extra-all all
          if ! git diff --quiet; then git diff; exit 1; fi
      - name: 'Check source code formatting'
        run: |
          bash ./misc/scripts/check_whitespace_git.sh
          UPX_CLANG_FORMAT="$PWD/../deps/bin-upx-20221212/clang-format-15.0.6" make -C src clang-format
          if ! git diff --quiet; then git diff; exit 1; fi

  job-linux-cmake:
    needs: [ job-rebuild-and-verify-stubs ]
    name: ${{ format('{0} cmake', matrix.os) }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - { os: ubuntu-22.04, use_m32: true }
          - { os: ubuntu-20.04, use_m32: false }
    steps:
      - name: 'Install extra 32-bit and Windows packages'
        if: ${{ matrix.use_m32 }}
        run: |
          sudo dpkg --add-architecture i386
          sudo apt-get update
          sudo apt-get install -y g++-multilib g++-mingw-w64-i686 g++-mingw-w64-x86-64
      - name: 'Check out code'
        uses: actions/checkout@v3
        with: { submodules: true }
      - name: 'Check out test suite'
        run: 'git clone --depth=1 https://github.com/upx/upx-testsuite ../deps/upx-testsuite'
      - name: 'Build cmake extra/gcc/debug'
        run:   'make build/extra/gcc/debug'
      - name: 'Build cmake extra/gcc/release'
        run:   'make build/extra/gcc/release'
      - name: 'Build cmake extra/clang/debug'
        run:   'make build/extra/clang/debug'
      - name: 'Build cmake extra/clang/release'
        run:   'make build/extra/clang/release'
      - name: 'Build cmake extra/gcc-m32/debug'
        if: ${{ matrix.use_m32 }}
        run:   'make build/extra/gcc-m32/debug'
      - name: 'Build cmake extra/gcc-m32/release'
        if: ${{ matrix.use_m32 }}
        run:   'make build/extra/gcc-m32/release'
      - name: 'Build cmake extra/cross-windows-mingw32/release'
        if: ${{ matrix.use_m32 }}
        run:   'make build/extra/cross-windows-mingw32/release'
      - name: 'Build cmake extra/cross-windows-mingw64/release'
        if: ${{ matrix.use_m32 }}
        run:   'make build/extra/cross-windows-mingw64/release'
      - name: 'Make artifact'
        run: |
          N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-${{ matrix.os }}
          mkdir -p "tmp/artifact/$N"
          (cd build && shopt -s nullglob && cp -ai --parents */upx{,.exe} */*/*/upx{,.exe} "../tmp/artifact/$N")
          (cd tmp/artifact && tar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
          # GitHub Actions magic: set "artifact_name" environment value for use in next step
          echo "artifact_name=$N" >> $GITHUB_ENV
      - name: ${{ format('Upload artifact {0}', env.artifact_name) }}
        uses: actions/upload-artifact@v3
        with:
          name: ${{ env.artifact_name }}
          path: tmp/artifact
      - name: 'Run basic tests'
        run: |
          make -C build/extra/gcc/debug test
          make -C build/extra/gcc/release test
          make -C build/extra/clang/debug test
          make -C build/extra/clang/release test
      - name: 'Run basic tests 32-bit'
        if: ${{ matrix.use_m32 }}
        run: |
          make -C build/extra/gcc-m32/debug test
          make -C build/extra/gcc-m32/release test
      - name: 'Run test suite build/extra/gcc/release'
        run: |
          export upx_testsuite_SRCDIR="$(readlink -en ../deps/upx-testsuite)"
          testsuite_1=$(readlink -en ./.github/travis_testsuite_1.sh)
          env -C build/extra/gcc/release upx_exe=./upx bash "$testsuite_1"

  job-macos-cmake:
    needs: [ job-rebuild-and-verify-stubs ]
    name: ${{ format('{0} cmake', matrix.os) }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - { os: macos-11, gcc: gcc-10, gxx: 'g++-10', testsuite: true }
          - { os: macos-12, gcc: gcc-11, gxx: 'g++-11', testsuite: true }
    steps:
      - name: 'Install brew packages'
        if: ${{ matrix.testsuite }}
        run: |
          brew update
          brew install coreutils
      - name: 'Check out code'
        uses: actions/checkout@v3
        with: { submodules: true }
      - name: 'Check out test suite'
        if: ${{ matrix.testsuite }}
        run: 'git clone --depth=1 https://github.com/upx/upx-testsuite ../deps/upx-testsuite'
      - name: 'Build cmake extra/clang/debug'
        run:   'make build/extra/clang/debug'
      - name: 'Build cmake extra/clang/release'
        run:   'make build/extra/clang/release'
      - name: 'Build cmake extra/gcc/debug'
        if: ${{ matrix.gcc != '' }}
        run:   'make build/extra/gcc/debug CC=${{ matrix.gcc }} CXX=${{ matrix.gxx }}'
      - name: 'Build cmake extra/gcc/release'
        if: ${{ matrix.gcc != '' }}
        run:   'make build/extra/gcc/release CC=${{ matrix.gcc }} CXX=${{ matrix.gxx }}'
      - name: 'Build cmake xtarget/cross-darwin-arm64/debug'
        run: |
          CC="clang -target arm64-apple-darwin" CXX="clang++ -target arm64-apple-darwin" \
          make UPX_XTARGET=cross-darwin-arm64 xtarget/debug
      - name: 'Build cmake xtarget/cross-darwin-arm64/release'
        run: |
          CC="clang -target arm64-apple-darwin" CXX="clang++ -target arm64-apple-darwin" \
          make UPX_XTARGET=cross-darwin-arm64 xtarget/release
      - name: 'Make artifact'
        run: |
          N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-${{ matrix.os }}
          mkdir -p "tmp/artifact/$N"
          (cd build && rsync -R -a */*/*/upx "../tmp/artifact/$N/")
          (cd tmp/artifact && gtar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
          # GitHub Actions magic: set "artifact_name" environment value for use in next step
          echo "artifact_name=$N" >> $GITHUB_ENV
      - name: ${{ format('Upload artifact {0}', env.artifact_name) }}
        uses: actions/upload-artifact@v3
        with:
          name: ${{ env.artifact_name }}
          path: tmp/artifact
      - name: 'Run basic tests'
        run: |
          make -C build/extra/clang/debug test
          make -C build/extra/clang/release test
      - name: 'Run test suite build/extra/clang/release'
        if: ${{ matrix.testsuite }}
        run: |
          export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
          export upx_testsuite_SRCDIR="$(readlink -en ../deps/upx-testsuite)"
          testsuite_1=$(readlink -en ./.github/travis_testsuite_1.sh)
          env -C build/extra/clang/release upx_exe=./upx bash "$testsuite_1"

  job-windows-cmake:
    needs: [ job-rebuild-and-verify-stubs ]
    name: ${{ format('{0} cmake', matrix.os) }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          # windows-2019 used to work but got broken with the 20220821.1 runner-image
          # update; we cannot download that image for inspection, and debugging the
          # remote image is painful, so disable for now
          # see https://github.com/actions/runner-images.git
          ####- { os: windows-2019 }
          - { os: windows-2022 }
    steps:
      - name: 'Check out code'
        uses: actions/checkout@v3
        with: { submodules: true }
      - name: 'Check out test suite'
        run: 'git clone --depth=1 https://github.com/upx/upx-testsuite ../deps/upx-testsuite'
      - name: 'Inspect runner-image settings'
        # debug remote image; also see https://github.com/actions/runner-images.git
        if: ${{ false }}
        run: |
          Get-Command bash; Get-Command cmake; Get-Command make
          bash --version; cmake --version; make --version
          Get-Command cl -ErrorAction SilentlyContinue
      - name: 'Build cmake debug'
        run:   'make build/debug'
      - name: 'Build cmake release'
        run:   'make build/release'
      - name: 'Make artifact'
        shell: bash
        run: |
          N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-${{ matrix.os }}
          mkdir -p "tmp/artifact/$N"
          (cd build && cp -ai --parents */*/upx.exe "../tmp/artifact/$N")
          # GitHub Actions magic: set "artifact_name" environment value for use in next step
          echo "artifact_name=$N" >> $GITHUB_ENV
      - name: ${{ format('Upload artifact {0}', env.artifact_name) }}
        uses: actions/upload-artifact@v3
        with:
          name: ${{ env.artifact_name }}
          path: tmp/artifact
      - name: 'Run basic tests'
        run: |
          cmake --build build/debug   --config Debug   --target RUN_TESTS
          cmake --build build/release --config Release --target RUN_TESTS
      - name: 'Run test suite build/release'
        shell: bash
        run: |
          export upx_testsuite_SRCDIR="$(readlink -en ../deps/upx-testsuite)"
          testsuite_1=$(readlink -en ./.github/travis_testsuite_1.sh)
          env -C build/release/Release upx_exe=./upx bash "$testsuite_1"

  job-windows-toolchains:
    needs: [ job-rebuild-and-verify-stubs ]
    name: ${{ format('windows {0}', matrix.name) }}
    runs-on: ${{ matrix.os }}
    env:
      C: ${{ matrix.C }}
      B: release
      H: 'd:\a\upx\upx'
    strategy:
      fail-fast: false
      matrix:
        include:
          - { name: amd64-win64-vs2019, os: windows-2019, C: msvc-14.2-x64, arch: amd64 }
          - { name: amd64-win64-vs2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64 }
          - { name: arm64-win64-vs2019, os: windows-2019, C: msvc-14.2-x64, arch: amd64_arm64 }
          - { name: arm64-win64-vs2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64_arm64 }
          - { name: i386-win32-vs2019,  os: windows-2019, C: msvc-14.2-x86, arch: amd64_x86 }
          - { name: i386-win32-vs2022,  os: windows-2022, C: msvc-14.3-x86, arch: amd64_x86 }
    steps:
      - name: 'Check out code'
        uses: actions/checkout@v3
        with: { submodules: true }
      - name: 'Prepare sources and Check out test suite'
        shell: bash
        run: |
          git config --global core.autocrlf input
          git --version && bash --version
          git clone --depth=1 https://github.com/upx/upx-testsuite ../deps/upx-testsuite
          mkdir -p -v build/$C/$B/{ucl,upx,zlib,zstd}
      - name: 'Set up Developer Command Prompt'
        uses: ilammy/msvc-dev-cmd@v1
        with:
          arch: ${{ matrix.arch }}
      - name: 'Build'
        shell: cmd
        run: |
          @REM setup directories
          where cl & where link
          set BDIR=%H%\build\%C%\%B%
          set DEFS=-D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS
          git rev-parse --short=12 HEAD > %BDIR%\upx\.GITREV.txt
          @REM ===== build UCL =====
          cd %BDIR%\ucl
          set s=%H%\vendor\ucl
          cl -MT -J -O2 -W4 -WX %DEFS% -I%s%\include -I%s% -c %s%\src\*.c
          link -lib -out:ucl.lib *.obj
          @REM ===== build zlib =====
          cd %BDIR%\zlib
          cl -MT -J -O2 -W3 -WX %DEFS% -c %H%\vendor\zlib\*.c
          link -lib -out:zlib.lib *.obj
          @REM ===== build zstd =====
          @rem cd %BDIR%\zstd
          @rem set s=%H%\vendor\zstd\lib
          @rem cl -MT -J -O2 -W4 -WX -DDYNAMIC_BMI2=0 -DZSTD_DISABLE_ASM %DEFS% -c %s%\common\*.c %s%\compress\*.c %s%\decompress\*.c
          @rem link -lib -out:zstd.lib *.obj
          @REM ===== build UPX =====
          cd %BDIR%\upx
          set s=%H%\src
          cat .GITREV.txt
          set /p GITREV=<.GITREV.txt
          set sources=%s%\*.cpp %s%\check\*.cpp %s%\compress\*.cpp %s%\console\*.cpp %s%\filter\*.cpp %s%\util\*.cpp
          cl -MT -std:c++17 -Zc:__cplusplus -EHsc -J -O2 -W4 -WX -DUPX_VERSION_GITREV="""%GITREV%""" -DWITH_ZSTD=0 %DEFS% -I%H%\vendor -I%H%\vendor\boost-pfr\include -Feupx.exe %sources% %BDIR%\ucl\ucl.lib %BDIR%\zlib\zlib.lib /link setargv.obj
      - name: 'Make artifact'
        shell: bash
        run: |
          N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-windows-${{ matrix.name }}
          mkdir -p "tmp/artifact/$N/$B"
          cp -ai build/$C/$B/upx/upx*.exe "tmp/artifact/$N/$B"
          # GitHub Actions magic: set "artifact_name" environment value for use in next step
          echo "artifact_name=$N" >> $GITHUB_ENV
      - name: ${{ format('Upload artifact {0}', env.artifact_name) }}
        uses: actions/upload-artifact@v3
        with:
          name: ${{ env.artifact_name }}
          path: tmp/artifact
      - name: 'Run basic tests'
        if: ${{ matrix.arch != 'amd64_arm64' }}
        run: |
          $ErrorActionPreference = 'stop'
          $ErrorView = 'NormalView'
          cd $Env:H\build\$Env:C\$Env:B\upx
          $Env:UPX = "--no-color --no-progress"
          .\upx.exe --version
          .\upx.exe upx.exe -o upx_packed.exe
          dir *.exe
          .\upx.exe -l upx_packed.exe
          .\upx.exe -t upx_packed.exe
          .\upx_packed.exe --version
      - name: 'Run test suite'
        if: ${{ matrix.arch != 'amd64_arm64' }}
        shell: bash
        run: |
          export upx_testsuite_SRCDIR="$(readlink -en ../deps/upx-testsuite)"
          testsuite_1=$(readlink -en ./.github/travis_testsuite_1.sh)
          env -C build/$C/$B/upx upx_exe=./upx.exe bash "$testsuite_1"

  job-linux-zigcc:
    if: ${{ true }}
    needs: [ job-rebuild-and-verify-stubs ]
    name: ${{ format('zigcc {0} {1}', matrix.zig_target, matrix.zig_pic) }}
    runs-on: ubuntu-latest
    ##container: alpine:3.17 # older versions such as alpine:3.12 also work; no-container also works
    strategy:
      fail-fast: false
      matrix:
        include:
          - { zig_target: aarch64-linux-musl }
          - { zig_target: aarch64-macos.11-none }
          - { zig_target: aarch64-macos.12-none }
          - { zig_target: aarch64-macos.13-none }
          - { zig_target: aarch64-windows-gnu }
          - { zig_target: i386-linux-musl }
          - { zig_target: i386-windows-gnu }
          - { zig_target: x86_64-linux-musl }
          - { zig_target: x86_64-linux-musl, zig_pic: -fPIE }
          - { zig_target: x86_64-macos.11-none }
          - { zig_target: x86_64-macos.12-none }
          - { zig_target: x86_64-macos.13-none }
          - { zig_target: x86_64-windows-gnu }
    env:
      # 2023-01-30
      ZIG_DIST_VERSION: 0.11.0-dev.1491+2b27bc2c6
      # for zig-cc wrapper scripts (see below):
      ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
      ZIG_FLAGS: ${{ matrix.zig_flags }}
      ZIG_PIC: ${{ matrix.zig_pic }}
      ZIG_TARGET: ${{ matrix.zig_target }}
    steps:
      - name: 'Install Alpine Linux container packages'
        if: ${{ job.container }}
        shell: sh
        run: |
          apk update && apk upgrade && apk add bash cmake file git make tar xz
          # set PATH like in Ubuntu
          echo "PATH=$HOME/.local/bin:$PATH" >> $GITHUB_ENV
          # this seems to be needed when running in a container (beause of UID mismatch??)
          git config --global --add safe.directory '*'
      - name: 'Check out code'
        uses: actions/checkout@v3
        with: { submodules: true }
      - name: ${{ format('Install Zig {0}', env.ZIG_DIST_VERSION) }}
        shell: bash
        run: |
          # GitHub Actions magic: set "UPX_GITREV_SHORT" environment value for use in steps below
          rev=$(git rev-parse --short=7 HEAD)
          echo "UPX_GITREV_SHORT=$rev" >> $GITHUB_ENV
          # update ZIG_TARGET (i386 => x86)
          ZIG_TARGET=${ZIG_TARGET/i386-/x86-}
          echo "ZIG_TARGET=$ZIG_TARGET" >> $GITHUB_ENV
          # install zig; note that ~/.local/bin is included in the default $PATH on Ubuntu
          mkdir -p -v ~/.local/bin
          cd ~/.local/bin
          ZIG_DIST_NAME=zig-linux-x86_64-${ZIG_DIST_VERSION}
          wget -q 'https://ziglang.org/builds/'${ZIG_DIST_NAME}.tar.xz
          ls -l ${ZIG_DIST_NAME}.tar.xz
          tar -xoJf ${ZIG_DIST_NAME}.tar.xz
          rm ${ZIG_DIST_NAME}.tar.xz
          ln -s -v ${ZIG_DIST_NAME}/zig zig
          #echo "PATH=$PATH" && which zig
          echo -n 'zig version: '; zig version
          # create wrapper scripts (needed for CMake)
          echo -e '#!/bin/sh\nexec zig ar "$@"' > zig-ar
          echo -e '#!/bin/sh\nexec zig cc  -target $ZIG_TARGET $ZIG_PIC $ZIG_FLAGS $ZIG_CPPFLAGS $ZIG_CFLAGS   "$@"' > zig-cc
          echo -e '#!/bin/sh\nexec zig c++ -target $ZIG_TARGET $ZIG_PIC $ZIG_FLAGS $ZIG_CPPFLAGS $ZIG_CXXFLAGS "$@"' > zig-cxx
          echo -e '#!/bin/sh\nexec zig ranlib "$@"' > zig-ranlib
          chmod +x zig-ar zig-cc zig-cxx zig-ranlib
          ls -la; head zig-ar zig-cc zig-cxx zig-ranlib
      - name: ${{ format('Build Release with zig-cc -target {0} {1}', env.ZIG_TARGET, env.ZIG_PIC) }}
        run: |
          mkdir -p build/zig/${ZIG_TARGET}${ZIG_PIC}/release
          cd       build/zig/${ZIG_TARGET}${ZIG_PIC}/release
          cmake ../../../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_AR=$HOME/.local/bin/zig-ar -DCMAKE_C_COMPILER=zig-cc -DCMAKE_CXX_COMPILER=zig-cxx -DCMAKE_RANLIB=$HOME/.local/bin/zig-ranlib $EXTRA_CMAKE_CONFIG_FLAGS_RELEASE
          cmake --build . --config Release --parallel --verbose
          file ./upx*
      - name: ${{ format('Build Debug with zig-cc -target {0} {1}', env.ZIG_TARGET, env.ZIG_PIC) }}
        run: |
          mkdir -p build/zig/${ZIG_TARGET}${ZIG_PIC}/debug
          cd       build/zig/${ZIG_TARGET}${ZIG_PIC}/debug
          cmake ../../../.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_AR=$HOME/.local/bin/zig-ar -DCMAKE_C_COMPILER=zig-cc -DCMAKE_CXX_COMPILER=zig-cxx -DCMAKE_RANLIB=$HOME/.local/bin/zig-ranlib $EXTRA_CMAKE_CONFIG_FLAGS_DEBUG
          cmake --build . --config Debug --parallel --verbose
          file ./upx*
      - name: ${{ format('Make artifact from upx-{0}-{1}', github.ref_name, env.UPX_GITREV_SHORT) }}
        shell: bash
        run: |
          N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-zigcc-${{ matrix.zig_target }}${ZIG_PIC}
          mkdir -p "tmp/artifact/$N"
          (cd build && shopt -s nullglob && cp -ai --parents */upx{,.exe} */*/*/upx{,.exe} "../tmp/artifact/$N")
          (cd tmp/artifact && tar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
          # GitHub Actions magic: set "artifact_name" environment value for use in next step
          echo "artifact_name=$N" >> $GITHUB_ENV
      - name: ${{ format('Upload artifact {0}', env.artifact_name) }}
        uses: actions/upload-artifact@v3
        with:
          name: ${{ env.artifact_name }}
          path: tmp/artifact

# vim:set ts=2 sw=2 et:
