version: 2.1

parameters:
  vc-commit:
    type: string
    default: "HEAD"
  pkg-commit:
    type: string
    default: "master"
  dist-url:
    type: string
    default: ""
  dist-url-sha256:
    type: string
    default: ""
  configure_args:
    type: string
    default: |
        --with-contrib \
        --with-unwind \
        --enable-developer-warnings \
        --enable-debugging-symbols \
        --disable-stack-protector \
        --with-persistent-storage \
  build-pkgs:
    type: string
    default: ""

jobs:
  dist:
    description: Build or download vinyl-x.y.z.tar.gz that is used later for the packaging jobs
    docker:
      - image: fedora:latest
    steps:
      - run:
          name: Install deps
          command: |
            dnf -y install \
                awk \
                automake \
                jemalloc-devel \
                git \
                libedit-devel \
                libtool \
                libunwind-devel \
                make \
                pcre2-devel \
                python3 \
                python3-sphinx
      - checkout
      - when:
          condition: << pipeline.parameters.dist-url >>
          steps:
            - run:
                name: Download the dist tarball
                command: |
                  curl -Ls '<< pipeline.parameters.dist-url >>' -o vinyl-dist.tar.gz
            - when:
                condition: << pipeline.parameters.dist-url-sha256 >>
                steps:
                  - run:
                      name: Verify downloaded tarball
                      command: |
                        echo "<< pipeline.parameters.dist-url-sha256 >> vinyl-dist.tar.gz" | sha256sum -c
            - run:
                name: Rename the dist tarball by parsed version
                command: |
                  mkdir parse-version-tmp
                  cd parse-version-tmp
                  tar xzf ../vinyl-dist.tar.gz
                  VERSION=$(vinyl-*/configure --version | awk 'NR == 1 {print $NF}')
                  cd ..
                  mv -v vinyl-dist.tar.gz vinyl-${VERSION}.tar.gz
      - unless:
          condition: << pipeline.parameters.dist-url >>
          steps:
            - run:
                name: Create the dist tarball
                command: |
                  git checkout << pipeline.parameters.vc-commit >>
                  git submodule update --init
                  # Locally built tarballs are always built with weekly in package name
                  touch .is_weekly
                  # If version is "trunk", override version to add date
                  if grep 'AC_INIT.*trunk.*' ./configure.ac; then
                      sed -i -e "s/AC_INIT(\[\(.*\)\],\s*\[\(.*\)\],\s*\[\(.*\)\])/AC_INIT([\1],[$(date +%Y%m%d)],[\3])/" ./configure.ac
                  else
                      sed -i -e "s/AC_INIT(\[\(.*\)\],\s*\[\(.*\)\],\s*\[\(.*\)\])/AC_INIT([\1],[\2.$(date +%Y%m%d)],[\3])/" ./configure.ac
                  fi
                  ./autogen.des
                  make dist -j 16
      - persist_to_workspace:
          root: .
          paths:
            - .is_weekly
            - vinyl*.tar.gz
            - tools/*.suppr
            - .circleci
  tar_pkg_tools:
    description: Builds archives with the packaging tools from https://code.vinyl-cache.org/vinyl-cache/pkg-vinyl-cache
    docker:
      - image: fedora:latest
    steps:
      - add_ssh_keys:
          fingerprints:
            - "11:ed:57:75:32:81:9d:d0:a4:5e:af:15:4b:d8:74:27"
      - run:
          name: Grab the pkg repo
          command: |
            dnf -y install git
            mkdir -p ~/.ssh
            ssh-keyscan -H github.com >> ~/.ssh/known_hosts
            echo ${CIRCLE_REPOSITORY_URL}
            git clone --recursive https://code.vinyl-cache.org/vinyl-cache/pkg-vinyl-cache.git .
            git checkout << pipeline.parameters.pkg-commit >>
            tar cvzf debian.tar.gz debian --dereference
            tar cvzf redhat.tar.gz redhat --dereference
            tar cvzf alpine.tar.gz alpine --dereference
      - persist_to_workspace:
          root: .
          paths:
            - debian.tar.gz
            - redhat.tar.gz
            - alpine.tar.gz
  package:
    parameters:
      platform:
        description: the Linux distribution, with release, e.g. debian:bookworm, fedora:latest
        type: string
      rclass:
        description: the resource class to use, usually arm.medium or medium
        type: string
    machine:
      image: ubuntu-2004:202111-02
    resource_class: << parameters.rclass >>
    steps:
      - attach_workspace:
          at: ~/project

      - when:
          condition:
            matches:
              pattern: ^alpine.*
              value: << parameters.platform >>
          steps:
            - run:
                # https://wiki.alpinelinux.org/wiki/Release_Notes_for_Alpine_3.14.0#faccessat2
                name: grab the latest docker version
                command: |
                  # using https://docs.docker.com/engine/install/ubuntu/
                  sudo apt-get update
                  sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
                  curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
                  case "<< parameters.rclass >>" in
                      arm.*)  ARCH=arm64;;
                      *)      ARCH=amd64;;
                  esac
                  echo \
                    "deb [signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
                      $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
                  sudo apt-get update
                  sudo apt-get install docker-ce docker-ce-cli containerd.io
      - run:
          name: Build for << parameters.platform >> on << parameters.rclass >>
          command: |
            mkdir -p packages
            case "<< parameters.platform >>" in
                debian:*|ubuntu:*)    EXT=deb ;;
                almalinux:*|fedora:*) EXT=rpm ;;
                alpine:*)             EXT=apk ;;
                *)
                    echo "unrecognized platform: << parameters.platform >>"
                    exit 1
            esac

            case "<< parameters.rclass >>" in
                arm.*)              ARCH=arm64 ;;
                *)                  ARCH=amd64 ;;
            esac

            docker run \
              --rm \
              -it \
              --security-opt seccomp=unconfined \
              -e PARAM_DIST=$(echo "<< parameters.platform >>" | cut -d: -f1) \
              -e PARAM_RELEASE=$(echo "<< parameters.platform >>" | cut -d: -f2) \
              -v$(pwd):/vinyl-cache \
              --platform linux/$ARCH \
              << parameters.platform >> \
              /vinyl-cache/.circleci/make-$EXT-packages.sh
      - run:
          name: List created packages
          command: find ./packages -type f
      - persist_to_workspace:
          root: .
          paths:
            - "packages"
  build:
    parameters:
      prefix:
        description: the container image prefix (repository or architecture)
        type: string
        default: ""
      dist:
        description: the Linux distribution (debian|ubuntu)
        type: string
      release:
        description: the release name (bookworm|focal|jammy|noble)
        type: string
      make_target:
        description: the make target to execute during the build
        default: distcheck
        type: string
      extra_conf:
        description: platform-specific configure arguments
        default: ""
        type: string
      rclass:
        description: job-specific resource class
        default: medium
        type: string
    docker:
      - image: << parameters.prefix >><< parameters.dist >>:<< parameters.release >>
    resource_class: << parameters.rclass >>
    working_directory: /workspace
    steps:
      - checkout
      - run:
          name: Extract and build
          command: |
            case "<< parameters.dist >>" in
            almalinux|fedora)
                case "<< parameters.dist >>:<< parameters.release >>" in
                    almalinux:9)
                        dnf -y install "dnf-command(config-manager)"
                        dnf config-manager --set-enabled crb
                        dnf -y install diffutils
                        dnf -y install epel-release
                        dnf -y groupinstall "Development Tools"
                        ;;
                    almalinux:8)
                        dnf -y install "dnf-command(config-manager)"
                        dnf config-manager --set-enabled powertools
                        dnf -y install diffutils
                        dnf -y install epel-release
                        dnf -y groupinstall "Development Tools"
                        ;;
                    fedora:*)
                        dnf -y group install development-tools
                        dnf -y install awk
                        ;;
                esac
                dnf -y install \
                    cpio \
                    automake \
                    git \
                    jemalloc-devel \
                    libedit-devel \
                    libtool \
                    libunwind-devel \
                    make \
                    pcre2-devel \
                    python3 \
                    /usr/bin/sphinx-build \
                    sudo
                ;;
            debian|ubuntu)
                export DEBIAN_FRONTEND=noninteractive
                export DEBCONF_NONINTERACTIVE_SEEN=true
                apt-get update
                apt-get install -y \
                    autoconf \
                    automake \
                    build-essential \
                    ca-certificates \
                    cpio \
                    git \
                    graphviz \
                    libedit-dev \
                    libjemalloc-dev \
                    libncurses-dev \
                    libpcre2-dev \
                    libtool \
                    libunwind-dev \
                    pkg-config \
                    python3-sphinx \
                    sudo
                ;;
            alpine)
                apk update
                apk add -q \
                    autoconf \
                    automake \
                    build-base \
                    ca-certificates \
                    cpio \
                    git \
                    gzip \
                    libedit-dev \
                    libtool \
                    libunwind-dev \
                    linux-headers \
                    pcre2-dev \
                    py-docutils \
                    py3-sphinx \
                    tar \
                    sudo
                ;;
            archlinux)
                pacman -Syu --noconfirm \
                    ca-certificates \
                    cpio \
                    git \
                    libedit \
                    libtool \
                    libunwind \
                    linux-headers \
                    pcre2 \
                    python-docutils \
                    python-sphinx \
                    tar
                ;;
            esac

            git submodule update --init

            case "<< parameters.dist >>" in
            archlinux)
                useradd vinyl
                ;;
            almalinux|fedora)
                adduser vinyl
                ;;
            *)
                adduser --disabled-password --gecos "" vinyl
                ;;
            esac

            chown -R vinyl:vinyl .

            sudo -u vinyl sh -c '
                export ASAN_OPTIONS=abort_on_error=1,detect_odr_violation=1,detect_leaks=1,detect_stack_use_after_return=1,detect_invalid_pointer_pairs=1,handle_segv=0,handle_sigbus=0,use_sigaltstack=0,disable_coredump=0
                export LSAN_OPTIONS=abort_on_error=1,use_sigaltstack=0,suppressions=$(pwd)/tools/lsan.suppr
                export TSAN_OPTIONS=abort_on_error=1,halt_on_error=1,use_sigaltstack=0,suppressions=$(pwd)/tools/tsan.suppr
                export UBSAN_OPTIONS=halt_on_error=1,print_stacktrace=1,use_sigaltstack=0,suppressions=$(pwd)/tools/ubsan.suppr
                autoreconf -i -v
                ./configure \
                    << pipeline.parameters.configure_args >> \
                    << parameters.extra_conf >>
                make -j 4 -k << parameters.make_target >> VERBOSE=1 \
                    DISTCHECK_CONFIGURE_FLAGS="<< pipeline.parameters.configure_args >> \
                << parameters.extra_conf >>"
            '

  collect_packages:
    docker:
      - image: fedora:latest
    steps:
      - attach_workspace:
          at: ~/project
      - run: ls -la ~/project/
      - run:
          name: Tar the packages
          command: |
              tar cvzf packages.tar.gz packages
      - store_artifacts:
          destination: packages.tar.gz
          path: packages.tar.gz


workflows:
  version: 2
  commit:
    unless: &packaging_cond
      or:
        - << pipeline.parameters.build-pkgs >>
        - << pipeline.parameters.dist-url >>
    jobs:
      - build:
          name: build_almalinux_8
          dist: almalinux
          release: "8"
      - build:
          name: build_almalinux_9
          dist: almalinux
          release: "9"
      # fedora is our witness
      - build:
          name: build_fedora_latest
          dist: fedora
          release: latest
          make_target: witness.dot
      - build:
          name: build_debian_bookworm
          dist: debian
          release: bookworm
      # latest ubuntu uses sanitizers
      - build:
          name: build_ubuntu_focal
          dist: ubuntu
          release: focal
      - build:
          name: build_ubuntu_jammy
          dist: ubuntu
          release: jammy
      - build:
          name: build_ubuntu_noble
          dist: ubuntu
          release: noble
          rclass: large
          extra_conf: --enable-asan --enable-ubsan --enable-workspace-emulator
          make_target: check
      - build:
          name: build_alpine
          dist: alpine
          release: latest
          extra_conf: --without-contrib
          make_target: check
      - build:
          name: build_archlinux
          dist: archlinux
          release: base-devel
  packaging:
    when: *packaging_cond
    jobs: &packaging_jobs
      - dist
      - tar_pkg_tools
      - package:
          name: << matrix.platform >> packages (<< matrix.rclass >>)
          requires:
            - dist
            - tar_pkg_tools
          matrix:
            parameters:
              platform:
                - ubuntu:focal
                - ubuntu:jammy
                - ubuntu:noble
                - debian:bookworm
                - almalinux:8
                - almalinux:9
                - fedora:latest
                - alpine:latest
              rclass:
                - arm.medium
                - medium
      - collect_packages:
          requires:
            - package
  nightly:
    triggers:
      - schedule:
          cron: "0 4 * * *"
          filters:
            branches:
              only:
                - master
    jobs: *packaging_jobs
