name: Build (and publish) Python Packages

on:
  workflow_dispatch:
      inputs:
        publish-TestPyPI:
          description: 'Publish packages to TestPyPI'
          required: false
          default: false
          type: boolean
        publish-PyPI:
          description: 'Publish packages to PyPI'
          required: false
          default: false
          type: boolean
  release:
    types: [published]

jobs:
  build_sdist:
    name: Build sdist
    runs-on: ubuntu-latest

    outputs:
      vrna_sdist_file: ${{ steps.create_sdist.outputs.file }}

    steps:
      - uses: actions/checkout@v3
      - name: install prerequisites
        run:  |
          sudo apt-get update
          sudo apt-get -y install build-essential autoconf automake swig doxygen gengetopt help2man libtool check graphviz python3-sphinx 
      - name: autotools setup
        run:  |
          autoreconf -i
          tar -xjf src/dlib-19.24.tar.bz2 -C src
          tar -xzf src/libsvm-3.31.tar.gz -C src
      - name: configure
        run: ./configure --without-kinfold --without-forester --without-rnalocmin --without-rnaxplorer --without-perl --without-gsl --disable-mpfr
      - name: prepare source files
        run:  |
          cd src/ViennaRNA/static
          make
      - name: prepare doxygen XML
        run: |
          cd doc/doxygen
          make doxygen-xml
      - name: prepare Python wrapper
        run: |
          cd interfaces/Python
          make RNA/RNA.py
      - id: create_sdist
        name: build Python source distribution
        run:  |
          python -m pip install --upgrade build
          python -m build --sdist
          echo "file=$(cd dist && ls ViennaRNA-*.tar.gz)" >> "$GITHUB_OUTPUT"
      - name: Archive production artifacts
        uses: actions/upload-artifact@v3
        with:
          name: sdist
          path: dist/

  build_wheels:
    name: Build wheels on ${{ matrix.os }}
    needs: build_sdist
    runs-on: ${{ matrix.os }}

    strategy:
      # Ensure that a wheel builder finishes even if another fails
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            cibw_archs: "x86_64"
          - os: ubuntu-latest
            cibw_archs: "aarch64"
          - os: windows-latest
            cibw_archs: "AMD64"
          - os: macos-latest
            cibw_archs: "x86_64 universal2 arm64"

    steps:
      - name: Set up QEMU
        if: matrix.cibw_archs == 'aarch64'
        uses: docker/setup-qemu-action@v3
        with:
          platforms: arm64
      - uses: actions/download-artifact@v3
        with:
          name: sdist
      - name: Set sdist environment variable
        run:  |
          echo "VRNA_SDIST_FILE=${{needs.build_sdist.outputs.vrna_sdist_file}}" >> "$GITHUB_ENV"
      - name: Set sdist environment variable for Windows
        if: runner.os == 'Windows'
        run:  |
          echo "VRNA_SDIST_FILE=${{needs.build_sdist.outputs.vrna_sdist_file}}" >> "$env:GITHUB_ENV"
      - name: Build wheels
        if: runner.os != 'Windows'
        uses: pypa/cibuildwheel@v2.13.1
        with:
          package-dir: "$VRNA_SDIST_FILE"
          output-dir: dist
        env:
          CIBW_BUILD_VERBOSITY: 3
          CIBW_SKIP: cp37-* pp*
          CIBW_ENVIRONMENT: VRNA_SDIST_FILE=$VRNA_SDIST_FILE
          CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.14 CC=clang CXX=clang++
          CIBW_ARCHS: ${{ matrix.cibw_archs }}
          CIBW_TEST_REQUIRES: pytest
          CIBW_TEST_COMMAND: pytest --datadir {package}/tests/data {package}/tests/python
      - name: Build wheels - Windows
        if: runner.os == 'Windows'
        uses: pypa/cibuildwheel@v2.13.1
        with:
          package-dir: "$env:VRNA_SDIST_FILE"
          output-dir: dist
        # to supply options, put them in 'env', like:
        # env:
        #   CIBW_SOME_OPTION: value
        env:
          CIBW_ARCHS_WINDOWS: ${{ matrix.cibw_archs }}
          CIBW_ENVIRONMENT_WINDOWS: VRNA_SDIST_FILE=$env:VRNA_SDIST_FILE
          CIBW_TEST_REQUIRES: pytest
          CIBW_TEST_COMMAND_WINDOWS: pytest --datadir {package}\tests\data {package}\tests\python
          CIBW_SKIP: cp37-* pp*
      - uses: actions/upload-artifact@v3
        with:
          path: ./dist/*.whl

  upload_test_pypi:
    needs: [build_wheels, build_sdist]
    runs-on: ubuntu-latest
    environment: production
    if: (github.event_name == 'workflow_dispatch' && inputs.publish-TestPyPI) || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v'))
    steps:
      - uses: actions/download-artifact@v3
        with:
          # unpacks default artifact into dist/
          # if `name: artifact` is omitted, the action will create extra parent dir
          name: artifact
          path: dist

      - uses: actions/download-artifact@v3
        with:
          # unpacks sdist into dist/
          name: sdist
          path: dist

      - name: Publish package to TestPyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.TEST_PYPI_API_TOKEN }}
          repository-url: https://test.pypi.org/legacy/

  upload_to_pypi:
    needs: [build_wheels, build_sdist]
    runs-on: ubuntu-latest
    if: (github.event_name == 'workflow_dispatch' && inputs.publish-PyPI) || (github.event_name == 'release' && github.event.action == 'published')
    steps:
      - uses: actions/download-artifact@v3
        with:
          # unpacks default artifact into dist/
          # if `name: artifact` is omitted, the action will create extra parent dir
          name: artifact
          path: dist

      - uses: actions/download-artifact@v3
        with:
          # unpacks sdist into dist/
          name: sdist
          path: dist

      - name: Publish package to TestPyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}
