name: C/C++ CI

on:
  pull_request:
  push:
    branches:
      - master
    tags:
      - v[0-9]+.*
    paths:
      - '.github/scripts/**'
      - '.github/workflows/ccpp.yml'
      - '**.c'
      - '**.cpp'
      - '**.cu'
      - '**.h'
      - '**.hpp'
      - '**.m'
      - '**.mm'
      - 'autogen.sh'
      - 'configure.ac'
      - 'data/**'
      - 'Makefile.in'
  workflow_dispatch:

jobs:
  prepare:
    runs-on: ubuntu-latest
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, we do not need to create own token.
    steps:
    - uses: actions/checkout@v4
      id: checkout
      with:
        persist-credentials: true
    - name: Init environment variables
      run: . .github/scripts/environment.sh
    - name: Retag continuous
      if: github.repository == 'CESNET/UltraGrid' && github.ref == 'refs/heads/master'
      run: |
        git fetch --prune --unshallow --tags
        git tag -f $TAG
        git push -f origin refs/tags/$TAG:refs/tags/$TAG
    - name: Update Release
      if: (github.repository == 'CESNET/UltraGrid' && github.ref == 'refs/heads/master') || startsWith(github.ref, 'refs/tags/')
      run: .github/scripts/create_release.sh
    - name: Create continuous release # ensure continuous release is present for AppImage zsync
      if: startsWith(github.ref, 'refs/tags/')
      run: .github/scripts/create_continuous_release.sh

  Ubuntu:
    name: run Ubuntu
    needs: prepare
    runs-on: ubuntu-22.04
    env:
      appimage_key: ${{ secrets.appimage_key }}
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      SDK_URL: ${{ secrets.SDK_URL }}

    steps:
    - uses: actions/checkout@v4
    - name: Fetch SDKs ETags
      id: etags
      run: |
        $GITHUB_WORKSPACE/.github/scripts/get-etag.sh ndi\
         https://downloads.ndi.tv/SDK/NDI_SDK_Linux/\
        Install_NDI_SDK_v6_Linux.tar.gz >> $GITHUB_OUTPUT
    - name: Run actions/cache for NDI
      id: cache-ndi
      uses: actions/cache@main
      with:
        path: /var/tmp/Install_NDI_SDK_Linux.tar.gz
        key: cache-ndi-${{ runner.os }}-${{ steps.etags.outputs.ndi }}
    - name: Download NDI
      if: steps.cache-ndi.outputs.cache-hit != 'true'
      run: "curl -Lf https://downloads.ndi.tv/SDK/NDI_SDK_Linux/\
       Install_NDI_SDK_v6_Linux.tar.gz -o /var/tmp/Install_NDI_SDK_Linux.tar.gz"
    - name: Cache FFmpeg
      uses: actions/cache@main
      with:
        path: '/var/tmp/ffmpeg'
        key: cache-ffmpeg-${{ runner.os }}-${{ hashFiles( '.github/scripts/Linux/install_ffmpeg.sh', '.github/scripts/Linux/install_other.sh', '.github/scripts/Linux/ffmpeg-patches/*') }}
    - name: Cache SDL
      uses: actions/cache@main
      with:
        path: '/var/tmp/sdl'
        key: cache-sdl-${{ runner.os }}-${{ hashFiles( '.github/scripts/Linux/install_sdl.sh' ) }}
    - name: Cache GLFW
      uses: actions/cache@main
      with:
        path: '/var/tmp/glfw'
        key: cache-glfw-${{ runner.os }}-${{ hashFiles( '.github/scripts/Linux/install_glfw.sh' ) }}
    - name: bootstrap
      run: |
           . .github/scripts/environment.sh
           .github/scripts/Linux/prepare.sh
    - name: configure
      run: "./autogen.sh $FEATURES || { RC=$?; cat config.log; exit $RC; }"
    - name: make
      run: make -j4
    - name: make check
      run: make check
    - name: make distcheck
      run: make distcheck
    - name: check libc/libstdc++ ABI
      run: .github/scripts/Linux/check_abi.sh 2.35 3.4.30 1.3.13 bin/* lib/ultragrid/*
    - name: Create AppImage
      run: data/scripts/Linux-AppImage/create-appimage.sh https://github.com/$GITHUB_REPOSITORY/releases/download/continuous/UltraGrid-$CHANNEL-x86_64.AppImage.zsync
    - name: Check AppImage
      run: |
        .github/scripts/Linux/docker_appimage_tests.sh
        curl -LSf -O https://raw.githubusercontent.com/AppImage/pkg2appimage/\
        master/appdir-lint.sh -O https://raw.githubusercontent.com/probonopd/\
        AppImages/master/excludelist
        sudo apt install desktop-file-utils libfile-mimeinfo-perl # desktop-file-validate, mimetype
        bash appdir-lint.sh squashfs-root
    - name: Compute checksum
      run: sha256sum UltraGrid-$VERSION-x86_64.AppImage
    - name: Upload Release Asset
      id: upload-release
      if: (github.repository == 'CESNET/UltraGrid' && github.ref == 'refs/heads/master') || startsWith(github.ref, 'refs/tags/')
      run: |
        sudo apt install jq zsync
        zsyncmake -C -u https://github.com/$GITHUB_REPOSITORY/releases/download/$TAG/UltraGrid-$VERSION-x86_64.AppImage -o UltraGrid-$CHANNEL-x86_64.AppImage.zsync UltraGrid-$VERSION-x86_64.AppImage
        .github/scripts/replace-asset.sh continuous UltraGrid-$CHANNEL-x86_64.AppImage.zsync application/x-zsync AppImage%20${CHANNEL}%20zsync
        .github/scripts/replace-asset.sh $TAG UltraGrid-$VERSION-x86_64.AppImage application/x-appimage Linux%20build
    - name: Upload Build
      if: steps.upload-release.conclusion == 'skipped'
      uses: actions/upload-artifact@main
      with:
        name: UltraGrid-Linux
        path: UltraGrid-${{ env.VERSION }}-x86_64.AppImage

  macOS:
    name: run macOS
    needs: prepare
    strategy:
      matrix:
        os: [macos-15-intel, macos-14]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      SDK_NONFREE_PATH: /private/var/tmp/sdks-nonfree
      notarytool_credentials: ${{ secrets.notarytool_credentials }}
      apple_key_p12_b64: ${{ secrets.apple_key_p12_b64 }}
      SDK_URL: ${{ secrets.SDK_URL }}

    steps:
    - uses: actions/checkout@v4
    - name: Set environment
      run: . .github/scripts/environment.sh
    - name: Fetch SDKs ETags
      id: etags
      run: |
        $GITHUB_WORKSPACE/.github/scripts/get-etag.sh nonfree\
         "$SDK_URL/$DELTA_MAC_ARCHIVE" optional >> $GITHUB_OUTPUT
        $GITHUB_WORKSPACE/.github/scripts/get-etag.sh ndi\
         https://downloads.ndi.tv/SDK/NDI_SDK_Mac/Install_NDI_SDK_v6_Apple.pkg\
         >> $GITHUB_OUTPUT
        $GITHUB_WORKSPACE/.github/scripts/get-etag.sh ximea\
         "$XIMEA_DOWNLOAD_URL" >> $GITHUB_OUTPUT
    - name: Run actions/cache for Non-Free SDKs
      id: cache-macos-nonfree-sdks
      uses: actions/cache@main
      with:
        path: ${{ env.SDK_NONFREE_PATH }}
        key: cache-nonfree-sdks-${{ runner.os }}-${{ steps.etags.outputs.nonfree }}
    - name: Download Non-Free SDKs
      if: steps.cache-macos-nonfree-sdks.outputs.cache-hit != 'true' && env.SDK_URL != null
      run: |
        rm -rf ${{ env.SDK_NONFREE_PATH }}
        mkdir -p ${{ env.SDK_NONFREE_PATH }}
        cd ${{ env.SDK_NONFREE_PATH }}
        curl -S -f "$SDK_URL/$DELTA_MAC_ARCHIVE" -o "$DELTA_MAC_ARCHIVE"
    - name: Run actions/cache for XIMEA
      id: cache-macos-ximea
      uses: actions/cache@main
      with:
        path: /var/tmp/XIMEA_OSX_SP.dmg
        key: cache-ximea-${{ matrix.os }}-${{ steps.etags.outputs.ximea }}
    - name: Download XIMEA
      if: steps.cache-macos-ximea.outputs.cache-hit != 'true'
      run: curl -LSf "$XIMEA_DOWNLOAD_URL" -o /private/var/tmp/XIMEA_OSX_SP.dmg
    - name: Run actions/cache for NDI
      id: cache-ndi
      uses: actions/cache@main
      with:
        path: /private/var/tmp/Install_NDI_SDK_Apple.pkg
        key: cache-ndi-${{ runner.os }}-${{ steps.etags.outputs.ndi }}
    - name: Download NDI
      if: steps.cache-ndi.outputs.cache-hit != 'true'
      run: "curl -Lf https://downloads.ndi.tv/SDK/NDI_SDK_Mac/Install_\
       NDI_SDK_v6_Apple.pkg -o /private/var/tmp/Install_NDI_SDK_Apple.pkg"
    - name: bootstrap
      run: .github/scripts/macOS/prepare.sh
    - name: configure
      run: "ARCH=$UG_ARCH ./autogen.sh $FEATURES || { RC=$?; cat config.log; exit $RC; }"
    - name: make bundle
      run: make -j4 gui-bundle
    - name: make check
      run: make check
    - name: make distcheck
      run: |
        local_lib_list="/opt/homebrew /usr/local/lib /usr/local/opt \
         $(xcrun --show-sdk-path)/System/Library/Frameworks"
        for n in $local_lib_list; do if [ -d "$n" ]
         then sudo mv -- "$n" "$n-"; fi; done # hide local libs
        make distcheck TARGET=uv-qt.app/Contents/MacOS/uv REFLECTOR_TARGET=uv-qt.app/Contents/MacOS/hd-rum-transcode GUI_EXE=uv-qt.app/Contents/MacOS/uv-qt
        for n in $local_lib_list; do if [ -d "$n-" ]
         then sudo mv -- "$n-" "$n"; fi; done # return back
    - name: sign+notarize
      if: env.KEY_CHAIN != null
      run: .github/scripts/macOS/sign.sh uv-qt.app
    - name: make dmg
      run: |
        for n in `seq 5`; do # do more attempts
          if make osx-gui-dmg; then break; fi
          if [ $n -eq 5 ]; then false; fi
          sleep $((n * 10))
        done
        mv UltraGrid.dmg UltraGrid-$VERSION.dmg
    - name: Compute checksum
      run: sha2 -256 UltraGrid-$VERSION.dmg || true
    - name: Upload Release Asset
      id: upload-release
      if: (github.repository == 'CESNET/UltraGrid' && github.ref == 'refs/heads/master') || startsWith(github.ref, 'refs/tags/')
      run: |
        brew list jq >/dev/null 2>&1 || brew install jq
        .github/scripts/replace-asset.sh $TAG UltraGrid-$VERSION.dmg application/x-apple-diskimage macOS%20$(uname -m)%20build
    - name: Upload Build
      if: steps.upload-release.conclusion == 'skipped'
      uses: actions/upload-artifact@main
      with:
        name: UltraGrid-${{ env.VERSION }}-macOS
        path: UltraGrid-${{ env.VERSION }}.dmg

  Windows:
    name: run Windows
    needs: prepare
    runs-on: windows-latest
    defaults:
      run:
        shell: C:\shells\msys2bash.cmd {0}
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      MSYS2_PATH_TYPE: inherit
      SDK_URL: ${{ secrets.SDK_URL }}
    
    steps:
    - uses: actions/checkout@v4
    - name: Set environment
      run: .github/scripts/environment.sh
    - name: Fetch SDKs ETags
      id: etags
      run: |
        $GITHUB_WORKSPACE/.github/scripts/get-etag.sh ndi\
         https://downloads.ndi.tv/SDK/NDI_SDK/NDI%206%20SDK.exe\
         >> $GITHUB_OUTPUT
        $GITHUB_WORKSPACE/.github/scripts/get-etag.sh ximea\
         "$XIMEA_DOWNLOAD_URL" >> $GITHUB_OUTPUT
    - name: Find MSVC
      run: .github/scripts/Windows/find_msvc.ps1
      shell: pwsh -command ". '{0}'"
    - name: Run actions/cache for NDI
      id: cache-ndi
      uses: actions/cache@main
      with:
        path: 'C:\ndi.exe'
        key: cache-ndi-${{ runner.os }}-${{ steps.etags.outputs.ndi }}
    - name: Download NDI
      if: steps.cache-ndi.outputs.cache-hit != 'true'
      run: curl -f 'https://downloads.ndi.tv/SDK/NDI_SDK/NDI%206%20SDK.exe'
       -o 'C:\ndi.exe'
    - name: Cache XIMEA
      id: cache-macos-ximea
      uses: actions/cache@main
      with:
        path: 'C:\XIMEA_API_Installer.exe'
        key: cache-ximea-${{ runner.os }}-${{ steps.etags.outputs.ximea }}
    - name: Download XIMEA
      if: steps.cache-macos-ximea.outputs.cache-hit != 'true'
      run: curl -f "$XIMEA_DOWNLOAD_URL" -o 'C:\XIMEA_API_Installer.exe'

    - name: Run actions/cache for libajantv2 build
      id: cache-aja
      uses: actions/cache@main
      with:
        path: 'libajantv2'
        key: cache-aja-${{ runner.os }}-${{ hashFiles('.github/scripts/install-common-deps.sh') }}
    - name: Cache live555
      id: cache-live555
      uses: actions/cache@main
      with:
        path: 'live555'
        key: cache-live555-${{ runner.os }}-${{ hashFiles('.github/scripts/install-common-deps.sh') }}

    - name: bootsrap
      run: .github/scripts/Windows/prepare.ps1
      shell: pwsh -command ". '{0}'"
    - name: Run actions/cache for JACK
      id: cache-jack
      uses: actions/cache@main
      with:
        path: 'C:\Program Files\JACK2'
        key: cache-jack-${{ runner.os }}-${{ hashFiles('.github/scripts/Windows/install_jack.ps1') }}
    - name: Install JACK
      if: steps.cache-jack.outputs.cache-hit != 'true'
      run: .github/scripts/Windows/install_jack.ps1
      shell: pwsh -command ". '{0}'"
    - name: bootsrap MSYS2
      run: $GITHUB_WORKSPACE/.github/scripts/Windows/prepare_msys.sh

    - name: Install Spout
      run: $GITHUB_WORKSPACE/.github/scripts/Windows/install_spout.sh

    - name: Run actions/cache for CineForm build
      id: cache-cineform
      uses: actions/cache@main
      with:
        path: 'C:\cineform-sdk'
        key: cache-cineform-${{ runner.os }}-${{ hashFiles('.github/scripts/Windows/install_cineform.sh') }}
    - name: Build CineForm
      if: steps.cache-cineform.outputs.cache-hit != 'true'
      run: $GITHUB_WORKSPACE/.github/scripts/Windows/install_cineform.sh build
    - name: Install CineForm
      run: $GITHUB_WORKSPACE/.github/scripts/Windows/install_cineform.sh install

    - name: configure
      run: ./autogen.sh --prefix=/ --bindir=/ --docdir=/doc $FEATURES || { RC=$?; cat config.log; exit $RC; }
    - name: make
      run: make -j4
    - name: make check
      run: make check
    - name: make bundle
      run: |
        export DESTDIR=build/UltraGrid-$VERSION-win64
        make install
        for exe in "$DESTDIR"/*.exe; do
            data/scripts/get_dll_depends.sh "$exe" |
                while read -r n; do cp "$n" "$DESTDIR"; done
        done
        if command -v windeployqt-qt6 >/dev/null; then
            windeployqt-qt6 "$DESTDIR/uv-qt.exe"
        else
            windeployqt "$DESTDIR/uv-qt.exe"
        fi
        cp -r data/Windows/* "$DESTDIR"
        data/scripts/get_dll_depends.sh\
         "$DESTDIR/screen-capture-recorder-x64.dll" |
            while read -r n; do cp "$n" "$DESTDIR"; done
    - name: make dist-check
      run: PATH= /usr/bin/make distcheck
        TARGET=build/UltraGrid-$VERSION-win64/uv.exe
        REFLECTOR_TARGET=build/UltraGrid-$VERSION-win64/hd-rum-transcode.exe
        GUI_EXE=build/UltraGrid-$VERSION-win64/uv-qt.exe
    - name: Upload Release Asset
      id: upload-release
      if: (github.repository == 'CESNET/UltraGrid' && github.ref == 'refs/heads/master') || startsWith(github.ref, 'refs/tags/')
      run: |
        cd build; zip -9 -r UltraGrid-$VERSION-win64.zip UltraGrid-$VERSION-win64
        $GITHUB_WORKSPACE/.github/scripts/replace-asset.sh $TAG UltraGrid-$VERSION-win64.zip application/zip Windows%20build
    - name: Compute checksum
      if: steps.upload-release.conclusion != 'skipped'
      run: sha256sum build/UltraGrid-$VERSION-win64.zip
    - name: Upload Build
      if: steps.upload-release.conclusion == 'skipped'
      uses: actions/upload-artifact@main
      with:
        name: UltraGrid-Windows
        path: build

# vi: set expandtab sw=2:
