name: Build Python 3

on:
  workflow_call:
    inputs:
      cibw_build:
        required: true
        type: string
      cibw_skip:
        required: false
        type: string
      cibw_prerelease_pythons:
        required: false
        type: string
      library_version:
        required: false
        type: string

jobs:
  compute_version:
    name: Compute Library Version
    runs-on: ubuntu-latest
    outputs:
      library_version: ${{ steps.compute-version.outputs.library_version }}
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        # Include all history and tags
        with:
          persist-credentials: false
          fetch-depth: 0
      - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
        name: Install Python
        with:
          python-version: '3.12'
      - name: Compute Version
        id: compute-version
        run: |
          if [ -n "${{ inputs.library_version}}" ]; then
            LIBRARY_VERSION="${{ inputs.library_version}}"
          else
            pip install "setuptools_scm[toml]>=4"
            LIBRARY_VERSION=$(setuptools-scm)
          fi

          echo "${LIBRARY_VERSION}"
          echo "library_version=${LIBRARY_VERSION}" >> $GITHUB_OUTPUT

  build-wheels-matrix:
    runs-on: ubuntu-latest
    outputs:
      include: ${{steps.set-matrix.outputs.include}}
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          persist-credentials: false
      - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
        with:
          python-version: "3.13"
      - run: pip install cibuildwheel==3.1.4
      - id: set-matrix
        env:
          CIBW_BUILD: ${{ inputs.cibw_build }}
          CIBW_SKIP: ${{ inputs.cibw_skip }}
        run: |
          MATRIX_INCLUDE=$(
            {
              cibuildwheel --print-build-identifiers --platform linux --archs x86_64,i686 | jq -cR '{only: ., os: "ubuntu-latest-16-cores"}' \
              && cibuildwheel --print-build-identifiers --platform linux --archs aarch64  | jq -cR '{only: ., os: "arm-8core-linux"}' \
              && cibuildwheel --print-build-identifiers --platform windows --archs AMD64,x86 | jq -cR '{only: ., os: "windows-latest"}' \
              && cibuildwheel --print-build-identifiers --platform windows --archs ARM64    | jq -cR '{only: ., os: "windows-11-arm"}' \
              && cibuildwheel --print-build-identifiers --platform macos --archs x86_64 | jq -cR '{only: ., os: "macos-15-large"}' \
              && cibuildwheel --print-build-identifiers --platform macos --archs arm64 | jq -cR '{only: ., os: "macos-15-xlarge"}'
            } | jq -sc
          )
          echo $MATRIX_INCLUDE
          echo "include=${MATRIX_INCLUDE}" >> $GITHUB_OUTPUT

  build:
    needs: ["compute_version", "build-wheels-matrix" ]
    runs-on: ${{ matrix.os }}
    name: Build ${{ matrix.only }}
    strategy:
      fail-fast: false
      matrix:
        include: ${{ fromJson(needs.build-wheels-matrix.outputs.include) }}
    env:
      SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DDTRACE: ${{ needs.compute_version.outputs.library_version }}
      CIBW_SKIP: ${{ inputs.cibw_skip }}
      CIBW_PRERELEASE_PYTHONS: ${{ inputs.cibw_prerelease_pythons }}
      CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
      CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014
      CIBW_MUSLLINUX_I686_IMAGE: ghcr.io/datadog/dd-trace-py/pypa_musllinux_1_2_i686:latest
      CIBW_BEFORE_ALL_WINDOWS: ${{ matrix.os == 'windows-latest' && 'rustup target add i686-pc-windows-msvc' || (matrix.os == 'windows-11-arm' && 'rustup target add aarch64-pc-windows-msvc') }}
      CIBW_BEFORE_ALL_MACOS: rustup target add aarch64-apple-darwin
      CIBW_BEFORE_ALL_LINUX: |
        if [[ "$(uname -m)-$(uname -i)-$(uname -o | tr '[:upper:]' '[:lower:]')-$(ldd --version 2>&1 | head -n 1 | awk '{print $1}')" != "i686-unknown-linux-musl" ]]; then
          curl -sSf https://sh.rustup.rs | sh -s -- -y;
        fi
      CIBW_ENVIRONMENT_LINUX: PATH=$HOME/.cargo/bin:$PATH CMAKE_BUILD_PARALLEL_LEVEL=24 CMAKE_ARGS="-DNATIVE_TESTING=OFF" SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DDTRACE=${{ needs.compute_version.outputs.library_version }}
      # SYSTEM_VERSION_COMPAT is a workaround for versioning issue, a.k.a.
      # `platform.mac_ver()` reports incorrect MacOS version at 11.0
      # See: https://stackoverflow.com/a/65402241
      CIBW_ENVIRONMENT_MACOS: CMAKE_BUILD_PARALLEL_LEVEL=24 SYSTEM_VERSION_COMPAT=0 CMAKE_ARGS="-DNATIVE_TESTING=OFF" SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DDTRACE=${{ needs.compute_version.outputs.library_version }}
      CIBW_ENVIRONMENT_WINDOWS: SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DDTRACE=${{ needs.compute_version.outputs.library_version }}
      # cibuildwheel repair will copy anything's under /output directory from the
      # build container to the host machine. This is a bit hacky way, but seems
      # to be the only way getting debug symbols out from the container while
      # we don't mess up with RECORD file.
      CIBW_REPAIR_WHEEL_COMMAND_LINUX: |
        mkdir -p /output/debugwheelhouse &&
        python scripts/extract_debug_symbols.py {wheel} --output-dir /output/debugwheelhouse &&
        python scripts/zip_filter.py {wheel} \*.c \*.cpp \*.cc \*.h \*.hpp \*.pyx \*.md &&
        mkdir ./tempwheelhouse &&
        unzip -l {wheel} | grep '\.so' &&
        auditwheel repair -w ./tempwheelhouse {wheel} &&
        mv ./tempwheelhouse/*.whl {dest_dir} &&
        rm -rf ./tempwheelhouse
      CIBW_REPAIR_WHEEL_COMMAND_MACOS: |
        mkdir -p ./debugwheelhouse &&
        python scripts/extract_debug_symbols.py {wheel} --output-dir ./debugwheelhouse &&
        python scripts/zip_filter.py {wheel} \*.c \*.cpp \*.cc \*.h \*.hpp \*.pyx \*.md &&
        MACOSX_DEPLOYMENT_TARGET=12.7 delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}
      CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: python scripts/zip_filter.py "{wheel}" "*.c" "*.cpp" "*.cc" "*.h" "*.hpp" "*.pyx" "*.md" && mv "{wheel}" "{dest_dir}"
      CIBW_TEST_COMMAND: "python {project}/tests/smoke_test.py"

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          persist-credentials: false
          fetch-depth: 0

      - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
        name: Install Python
        with:
          python-version: "3.13"

      - name: Set up QEMU
        if: runner.os == 'Linux' && matrix.os != 'ubuntu-24.04-arm'
        uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
        with:
          platforms: all

      - name: Build wheels
        uses: pypa/cibuildwheel@c923d83ad9c1bc00211c5041d0c3f73294ff88f6 # v3.1.4
        with:
          only: ${{ matrix.only }}

      - name: Validate wheel RECORD files
        shell: bash
        run: |
          for wheel in ./wheelhouse/*.whl; do
            if [ -f "$wheel" ]; then
              echo "Validating $(basename $wheel)..."
              python scripts/validate_wheel.py "$wheel"
            fi
          done

      - if: runner.os != 'Windows'
        run: |
          echo "ARTIFACT_NAME=${{ matrix.only }}" >> $GITHUB_ENV
      - if: runner.os == 'Windows'
        run: |
          chcp 65001 #set code page to utf-8
          echo "ARTIFACT_NAME=${{ matrix.only }}"  >> $env:GITHUB_ENV
      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: wheels-${{ env.ARTIFACT_NAME }}
          path: ./wheelhouse/*.whl

      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        if: runner.os != 'Windows'
        with:
          name: debug-symbols-${{ env.ARTIFACT_NAME }}
          path: |
            ./debugwheelhouse/*.zip
            ./wheelhouse/debugwheelhouse/*.zip
