name: Build furnace

on:
  push:
    branches: master
  pull_request:
    branches: master

defaults:
  run:
    shell: bash

env:
  BUILD_TYPE: RelWithDebInfo

jobs:
  build:
    strategy:
      matrix:
        config:
          - { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 }
          - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 }
          #- { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 }
          #- { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 }
          - { name: 'macOS x86_64', os: macos-latest, arch: x86_64 }
          - { name: 'macOS ARM', os: macos-latest, arch: arm64 }
          - { name: 'Linux x86_64', os: ubuntu-20.04, arch: x86_64 }
          #- { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf }
      fail-fast: false

    name: ${{ matrix.config.name }}
    runs-on: ${{ matrix.config.os }}

    steps:
    - name: Checkout
      uses: actions/checkout@v3.1.0
      with:
        submodules: recursive

    - name: Set Windows arch identifiers
      id: windows-identify
      if: ${{ matrix.config.compiler == 'msvc' || matrix.config.compiler == 'mingw' }}
      run: |
        vswhere_target="${{ matrix.config.arch }}"
        msvc_target="${{ matrix.config.arch }}"
        mingw_target="${{ matrix.config.arch }}"

        if [ '${{ matrix.config.arch }}' == 'x86' ]; then
          msvc_target="Win32"
        elif [ '${{ matrix.config.arch }}' == 'x86_64' ]; then
          vswhere_target="amd64"
          msvc_target="x64"
        fi

        if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
          echo "vswhere target: ${vswhere_target}"
          echo "MSVC target: ${msvc_target}"
        else
          echo "MinGW cross target: ${mingw_target}"
        fi

        echo "vswhere-target=${vswhere_target}" >> $GITHUB_OUTPUT
        echo "msvc-target=${msvc_target}" >> $GITHUB_OUTPUT
        echo "mingw-target=${mingw_target}" >> $GITHUB_OUTPUT

    - name: Set package identifier
      id: package-identify
      run: |
        package_name="furnace-${GITHUB_SHA}"
        package_ext=""
        if [ '${{ runner.os }}' == 'Windows' ] || [ '${{ matrix.config.compiler }}' == 'mingw' ]; then
          package_name="${package_name}-Windows"
          if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then
            package_name="${package_name}-MinGW"
          else
            package_name="${package_name}-MSVC"
          fi
          package_name="${package_name}-${{ matrix.config.arch }}"
          package_ext="" # Directory, uploading will automatically zip it
        elif [ '${{ runner.os }}' == 'macOS' ]; then
          package_name="${package_name}-macOS-${{ matrix.config.arch }}"
          package_ext=".dmg"
        else
          package_name="${package_name}-Linux-${{ matrix.config.arch }}"
          package_ext=".tar.gz"
        fi

        echo "Package identifier: ${package_name}"
        echo "Package file: ${package_name}${package_ext}"

        echo "id=${package_name}" >> $GITHUB_OUTPUT
        echo "filename=${package_name}${package_ext}" >> $GITHUB_OUTPUT

    - name: Set build cores amount
      id: build-cores
      run: |
        # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
        amount=2
        if [ '${{ runner.os }}' == 'macOS' ]; then
          amount=3
        fi

        echo "Amount of cores we can build with: ${amount}"

        echo "amount=${amount}" >> $GITHUB_OUTPUT

    - name: Setup Toolchain [Windows MSVC]
      if: ${{ matrix.config.compiler == 'msvc' }}
      uses: vadz/gha-setup-vsdevenv@avoid-deprecation-warnings
      with:
        arch: ${{ steps.windows-identify.outputs.vswhere-target }}

    - name: Setup Toolchain [Windows MinGW]
      if: ${{ matrix.config.compiler == 'mingw' }}
      run: |
        sudo apt update
        sudo apt install \
          mingw-w64 \
          mingw-w64-tools

    - name: Install Dependencies [Linux x86_64]
      if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }}
      run: |
        sudo apt update
        sudo apt install \
          libsdl2-dev \
          libfmt-dev \
          librtmidi-dev \
          libsndfile1-dev \
          zlib1g-dev \
          libjack-jackd2-dev

    - name: Install Dependencies [Linux armhf]
      if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'armhf' }}
      run: |
        sudo sed -ri "s/^deb /deb [arch=amd64] /" /etc/apt/sources.list
        echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ bionic main universe" | sudo tee -a /etc/apt/sources.list
        echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main universe" | sudo tee -a /etc/apt/sources.list
        sudo dpkg --add-architecture armhf
        sudo apt update
        sudo apt install \
          crossbuild-essential-armhf \
          appstream
        sudo apt install \
          libsdl2-dev:armhf \
          libfmt-dev:armhf \
          librtmidi-dev:armhf \
          libsndfile1-dev:armhf \
          zlib1g-dev:armhf \
          libjack-jackd2-dev:armhf
        ls /usr/arm-linux-gnueabihf/lib

    - name: Configure (System Libraries)
      if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }}
      run: |
        export USE_WAE=ON
        export CMAKE_EXTRA_ARGS=()
        if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
          CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}')
        elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then
          CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake')
        else
          # Test with system libs
          CMAKE_EXTRA_ARGS+=(
            '-DSYSTEM_FMT=OFF'
            '-DSYSTEM_LIBSNDFILE=ON'
            '-DSYSTEM_RTMIDI=ON'
            '-DSYSTEM_ZLIB=ON'
            '-DWITH_JACK=ON'
          )
          # Too old on Ubuntu
          if [ '${{ runner.os }}' == 'macOS' ]; then
            CMAKE_EXTRA_ARGS+=('-DSYSTEM_SDL2=ON')
          fi
        fi

        cmake \
          -B ${PWD}/build \
          -DCMAKE_INSTALL_PREFIX=${PWD}/target \
          -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
          -DWARNINGS_ARE_ERRORS=${USE_WAE} \
          "${CMAKE_EXTRA_ARGS[@]}"

    - name: Build (System Libraries)
      if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }}
      run: |
        cmake \
          --build ${PWD}/build \
          --config ${{ env.BUILD_TYPE }} \
          --parallel ${{ steps.build-cores.outputs.amount }}

    - name: Install (System Libraries)
      if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }}
      run: |
        cmake \
          --install ${PWD}/build \
          --config ${{ env.BUILD_TYPE }}

    - name: Cleanup (System Libraries)
      if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }}
      run: |
        rm -rf build/ target/

    - name: Configure
      run: |
        export USE_WAE=ON
        export CMAKE_EXTRA_ARGS=()
        if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
          CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}')

          # Force static linking
          # 1. Make MSVC runtime configurable
          CMAKE_EXTRA_ARGS+=('-DCMAKE_POLICY_DEFAULT_CMP0091=NEW')
          # 2. Use static (debug) runtime
          if [ '${{ env.BUILD_TYPE }}' == 'Debug' ]; then
            CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug')
          else
            CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded')
          fi
        elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then
          CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake')
          if [ '${{ matrix.config.arch }}' == 'x86' ]; then
            CMAKE_EXTRA_ARGS+=('-DSUPPORT_XP=ON')
          fi
        elif [ '${{ runner.os }}' == 'macOS' ]; then
          if [ '${{ matrix.config.arch }}' == 'arm64' ]; then
            CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="11.0"' '-DCMAKE_OSX_ARCHITECTURES=arm64')
          else
            CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"')
          fi
        elif [ '${{ runner.os }}' == 'Linux' ] && [ '${{ matrix.config.arch }}' == 'armhf' ]; then
          CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-Linux-armhf.cmake')
        fi

        cmake \
          -B ${PWD}/build \
          -DCMAKE_INSTALL_PREFIX=/usr \
          -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
          -DWARNINGS_ARE_ERRORS=${USE_WAE} \
          -DWITH_DEMOS=OFF -DWITH_INSTRUMENTS=OFF -DWITH_WAVETABLES=OFF \
          "${CMAKE_EXTRA_ARGS[@]}"

    - name: Build
      run: |
        cmake \
          --build ${PWD}/build \
          --config ${{ env.BUILD_TYPE }} \
          --parallel ${{ steps.build-cores.outputs.amount }}

    - name: Package [Windows]
      if: ${{ runner.os == 'Windows' || matrix.config.compiler == 'mingw' }}
      run: |
        binPath=build
        if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
          binPath="${binPath}/${{ env.BUILD_TYPE }}"
        fi
        # always strip on MinGW as it generate massive artifacts
        #if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then
        #  # arch-specific strip prefix
        #  # TODO maybe extract from cross toolchain files?
        #  toolPrefix="-w64-mingw32-"
        #  if [ '${{ matrix.config.arch }}' == 'x86_64' ]; then
        #    toolPrefix="x86_64${toolPrefix}"
        #  else
        #    toolPrefix="i686${toolPrefix}"
        #  fi
        #  ${toolPrefix}strip -s "${binPath}/furnace.exe"
        #fi

        mkdir ${{ steps.package-identify.outputs.filename }}
        pushd ${{ steps.package-identify.outputs.filename }}

        cp -v ../LICENSE LICENSE.txt
        cp -v ../README.md README.txt
        cp -vr ../papers ../${binPath}/furnace.exe ./
        if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
          cp -v ../${binPath}/furnace.pdb ./
        fi
        sha256sum ../${binPath}/furnace.exe > checksum.txt

        popd

    - name: Package [macOS]
      if: ${{ runner.os == 'macOS' }}
      run: |
        pushd build
        cpack
        mv Furnace-*-Darwin.dmg ../${{ steps.package-identify.outputs.filename }}
        popd

    - name: Package [Linux]
      if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }}
      run: |
        #if [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then
        #  strip -s build/furnace
        #fi

        mkdir -p target/furnace
        make -C ${PWD}/build DESTDIR=${PWD}/target/furnace install
        pushd target/furnace

        cp -v ../../res/logo.png .DirIcon

        cd usr

        mv bin/furnace ..
        rmdir bin

        rm -r share/applications
        rm -r share/doc
        rm -r share/icons
        rm -r share/licenses
        rm -r share/metainfo

        rmdir share

        cd ..

        cp ../../LICENSE .
        cp ../../README.md .
        cp -r ../../papers papers
        rmdir usr

        popd

        cd target

        tar -zcv -f ../${{ steps.package-identify.outputs.filename }} furnace

    - name: Upload artifact
      if: ${{ github.repository == 'tildearrow/furnace' && github.ref_name == 'master' }}
      uses: actions/upload-artifact@v3.1.1
      with:
        name: ${{ steps.package-identify.outputs.id }}
        path: ${{ steps.package-identify.outputs.filename }}
