# syntax=docker/dockerfile:1.6
#
# Pre-built runtime base image for the Elixir app. Contains:
#   * Debian trixie-slim with locale set to en_US.UTF-8
#   * Runtime apt deps for the BEAM + Erlang ssl + snmp
#   * `cdo` + `gdal-bin` (~1 GB dep tree, the slowest install)
#   * `wgrib2` (compiled here from source against NCEPLIBS-g2c v2.3.0)
#
# Built by `.forgejo/workflows/build-base.yaml` only when this file or
# the workflow changes. The app `Dockerfile` does `FROM prop-base` so
# everyday code pushes skip the wgrib2 compile and apt-install entirely.
#
# Bumping wgrib2 or g2c: change the ARGs below and push — the base
# workflow rebuilds and re-tags `:latest`. The app Dockerfile follows
# `:latest`, so the next app push picks it up automatically.

ARG DEBIAN_VERSION=trixie-20260316-slim
ARG RUNNER_IMAGE="docker.io/debian:${DEBIAN_VERSION}"

# ---- wgrib2 build stage (cached independently inside this image) ----
FROM ${RUNNER_IMAGE} AS wgrib2-builder

ARG WGRIB2_VERSION=3.8.0
# wgrib2 3.6.0 has a memory-corruption bug exposed by HRDPS rotated
# lat/lon GRIB2 files plus -lon point extraction (denormal garbage
# values, then `free(): invalid size`). Reproduced in the production
# pod against an HRDPS sample on 2026-04-30; 3.8.0 fixes it.
# g2c v2.3.0 is the minimum wgrib2 3.8.0's CMakeLists demands via
# find_package, and the first release where BUILD_G2C defaults ON.
ARG G2C_VERSION=2.3.0

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    rm -f /etc/apt/apt.conf.d/docker-clean \
    && apt-get update \
    && apt-get install -y --no-install-recommends \
       build-essential gfortran cmake wget ca-certificates pkg-config \
       zlib1g-dev libaec-dev libpng-dev libopenjp2-7-dev

# NCEPLIBS-g2c carries the actual JPEG2000 / PNG / AEC GRIB2 decoders
# that wgrib2 dispatches to via USE_G2CLIB_LOW. Jasper is disabled
# (CVE-laden, dropped from Debian).
WORKDIR /tmp/g2c
RUN wget -q --content-disposition "https://github.com/NOAA-EMC/NCEPLIBS-g2c/archive/refs/tags/v${G2C_VERSION}.tar.gz" \
      -O g2c.tar.gz \
  && tar xzf g2c.tar.gz \
  && cd NCEPLIBS-g2c-${G2C_VERSION} \
  && mkdir build && cd build \
  && cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
              -DCMAKE_BUILD_TYPE=Release \
              -DUSE_PNG=ON \
              -DUSE_AEC=ON \
              -DUSE_OpenJPEG=ON \
              -DUSE_Jasper=OFF \
  && make -j$(nproc) \
  && make install

WORKDIR /tmp/wgrib2
RUN wget -q --content-disposition "https://github.com/NOAA-EMC/wgrib2/archive/refs/tags/v${WGRIB2_VERSION}.tar.gz" \
      -O wgrib2.tar.gz \
  && tar xzf wgrib2.tar.gz \
  && cd wgrib2-${WGRIB2_VERSION} \
  && mkdir build && cd build \
  && cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release \
       -DUSE_AEC=ON -DUSE_G2CLIB_LOW=ON \
  && make -j$(nproc) \
  && make install \
  && strip /usr/local/bin/wgrib2

# ---- Final runtime base ----
FROM ${RUNNER_IMAGE} AS base

# Weekly cron passes CACHE_BUST=<iso year+week> so the apt layers below
# re-execute and pick up Debian security patches. Source-controlled
# pushes leave the value at its `none` default, so day-to-day base
# rebuilds (Dockerfile.base edits) don't pay the apt-update cost
# unless the week has rolled over.
#
# Note: the registry occasionally GCs base-image blobs that the
# manifest still references (saw this 2026-05-04 — `final 1/5 FROM
# prop-base:latest` failed with "could not fetch content descriptor
# … not found"). When that happens, push any change to this file to
# re-trigger the build-base workflow and re-upload the layers.
ARG CACHE_BUST=none

# Runtime apt deps. cdo + gdal-bin are split into a second RUN so a
# transient cdo install failure doesn't invalidate the smaller base
# layer above. Referencing `${CACHE_BUST}` in the RUN line changes the
# layer hash week-to-week without altering the install set.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    echo "cache-bust=${CACHE_BUST}" \
    && rm -f /etc/apt/apt.conf.d/docker-clean \
    && apt-get update \
    && apt-get install -y --no-install-recommends \
       libstdc++6 openssl libncurses6 locales ca-certificates snmp \
       libgfortran5 libaec0 zlib1g libpng16-16t64 libopenjp2-7

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    echo "cache-bust=${CACHE_BUST}" \
    && rm -f /etc/apt/apt.conf.d/docker-clean \
    && apt-get update \
    && apt-get install -y --no-install-recommends cdo gdal-bin

RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen

ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

# wgrib2 binary + dynamic g2c lib. ldconfig refreshes the loader cache
# so /usr/local/lib is searched at exec time without LD_LIBRARY_PATH.
COPY --from=wgrib2-builder /usr/local/bin/wgrib2 /usr/local/bin/wgrib2
COPY --from=wgrib2-builder /usr/local/lib/libg2c.so* /usr/local/lib/
RUN ldconfig
