# Global arguments
ARG PYTHON_VERSION=3.10.12
ARG APP_HOME="/app"
ARG VENV_PATH="/opt/.venv"
 
##############################################################################################
# ______       _ _     _ 
# | ___ \     (_) |   | |
# | |_/ /_   _ _| | __| |
# | ___ \ | | | | |/ _` |
# | |_/ / |_| | | | (_| |
# \____/ \__,_|_|_|\__,_|
# 
# ASCII font used https://patorjk.com/software/taag/#p=display&f=Doom&t=Build
#---------------------------------------------------------------------------------------------
# Build stage
##############################################################################################
FROM python:${PYTHON_VERSION} as build
 
# Install Poetry
ENV POETRY_VERSION=1.5.1
ENV POETRY_NO_INTERACTION=1
ENV POETRY_HOME="/opt/poetry"
ENV PATH="${POETRY_HOME}/bin:${PATH}"
ENV POETRY_CACHE_DIR=/tmp/poetry_cache
 
RUN curl -sSL https://install.python-poetry.org | python3 -
 
# Set a directory for virtual environment. Setting `VIRTUAL_ENV` and `PATH` environment 
# variables has the effect of activating the virtual environment for all subsequent
# poetry and python commands.
# More on this here: https://github.com/python-poetry/poetry/issues/263#issuecomment-1404129650
ARG VENV_PATH
RUN python -m venv ${VENV_PATH}
ENV VIRTUAL_ENV=${VENV_PATH}
ENV PATH="${VENV_PATH}/bin:${PATH}"
 
# Install dependencies. Also, it's safe to remove poetry cache.
COPY poetry.lock pyproject.toml ./
# `--without dev` is preferred for production, but production still needs dev dependencies (debug-toolbar for example)
RUN poetry install --no-root && rm -rf ${POETRY_CACHE_DIR}
 
 
##############################################################################################
# ______                
# | ___ \               
# | |_/ / __ _ ___  ___ 
# | ___ \/ _` / __|/ _ \
# | |_/ / (_| \__ \  __/
# \____/ \__,_|___/\___|
#---------------------------------------------------------------------------------------------
#
# Base
#
##############################################################################################
 
FROM ubuntu:23.04 as base
ARG PYTHON_VERSION
 
ENV PYTHONUNBUFFERED=1 \
  # Prevents Python from creating .pyc files
  PYTHONDONTWRITEBYTECODE=1
 
RUN apt-get update && apt-get install --no-install-recommends -y \
  build-essential \
  zlib1g-dev \
  libncurses5-dev \
  libgdbm-dev \
  libnss3-dev \
  libssl-dev \
  libreadline-dev \
  libffi-dev \
  libsqlite3-dev \
  wget \
  libbz2-dev \
  ca-certificates \
  sudo \
  adduser \
  && apt-get clean && rm -rf /var/lib/apt/lists/*
 
RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz \
  && tar -xf Python-${PYTHON_VERSION}.tgz \
  && cd /Python-${PYTHON_VERSION} \
  && chmod +x ./configure \
  && ./configure --enable-optimizations \
  && sudo make -j ${nproc} \
  && sudo make install \
  && rm -rf /Python-${PYTHON_VERSION} \
  && rm -rf /Python-${PYTHON_VERSION}.tgz
 
# Create a symlink to python3 as python
RUN ln -s /usr/local/bin/python3 /usr/local/bin/python
 
##############################################################################################
# ______               _                                  _   
# |  _  \             | |                                | |  
# | | | |_____   _____| | ___  _ __  _ __ ___   ___ _ __ | |_ 
# | | | / _ \ \ / / _ \ |/ _ \| '_ \| '_ ` _ \ / _ \ '_ \| __|
# | |/ /  __/\ V /  __/ | (_) | |_) | | | | | |  __/ | | | |_ 
# |___/ \___| \_/ \___|_|\___/| .__/|_| |_| |_|\___|_| |_|\__|
#                             | |                             
#                             |_|                             
#---------------------------------------------------------------------------------------------
#
# Development stage
#
##############################################################################################
 
FROM base as development
ARG VENV_PATH
ARG APP_HOME
 
ENV PYTHONUNBUFFERED=1 \
  # Prevents Python from creating .pyc files
  PYTHONDONTWRITEBYTECODE=1
 
# Install required system dependencies
RUN apt-get update && apt-get install --no-install-recommends -y \
  gettext \
  vim \
  htop \
  libpq-dev \
  libxml2-dev \
  # Cleaning up unused files
  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
  && rm -rf /var/lib/apt/lists/*
 
# Create django user, will own the Django app
RUN adduser --disabled-login --group --system django
 
# Copy virtual environment from the build stage and add to it PATH, activate venv
COPY --from=build --chown=django:django ${VENV_PATH} ${VENV_PATH}
ENV VIRTUAL_ENV=${VENV_PATH}
ENV PATH="${VENV_PATH}/bin:${PATH}"
 
# Copy application code. It's important to select WORKDIR here for code to work.
WORKDIR $APP_HOME
COPY --chown=django:django . ${APP_HOME}
 
COPY --chown=django:django ./docker/local/django/entrypoint /entrypoint
RUN sed -i 's/\r$//g' /entrypoint
RUN chmod +x /entrypoint
 
COPY --chown=django:django ./docker/local/django/start /start-webapp
RUN sed -i 's/\r$//g' /start-webapp
RUN chmod +x /start-webapp
 
COPY --chown=django:django ./docker/local/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r$//g' /start-celeryworker
RUN chmod +x /start-celeryworker
 
COPY --chown=django:django ./docker/local/django/celery/beat/start /start-celerybeat
RUN sed -i 's/\r$//g' /start-celerybeat
RUN chmod +x /start-celerybeat
 
# Create media folder for file uploads.
RUN mkdir -p ${APP_HOME}/apex/media
 
# Make django owner of the WORKDIR directory as well.
RUN chown -R django:django ${APP_HOME}
 
ENTRYPOINT ["/entrypoint"]
 
EXPOSE 8000
 
##############################################################################################
# ______              _            _   _             
# | ___ \            | |          | | (_)            
# | |_/ / __ ___   __| |_   _  ___| |_ _  ___  _ __  
# |  __/ '__/ _ \ / _` | | | |/ __| __| |/ _ \| '_ \ 
# | |  | | | (_) | (_| | |_| | (__| |_| | (_) | | | |
# \_|  |_|  \___/ \__,_|\__,_|\___|\__|_|\___/|_| |_|
#---------------------------------------------------------------------------------------------
#
# Production stage. It uses Python image and runtime dependencies build on the `build` stage.
#
##############################################################################################
 
FROM base as production
ARG VENV_PATH
ARG APP_HOME
 
ENV PYTHONUNBUFFERED=1 \
  # Prevents Python from creating .pyc files
  PYTHONDONTWRITEBYTECODE=1
 
USER root
 
RUN apt-get update && apt-get install --no-install-recommends -y \
  gnupg \
  libmemcached-dev \
  graphviz \
  libpq-dev \
  libxml2-dev \
  mime-support \
  # Cleaning up unused files
  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
  && rm -rf /var/lib/apt/lists/*
 
# Create an unprivilaged user to run celery as advised in the docs. Celery should never run as root on production.
# Additionally, the user must have access to a shell and must be created with a home directory.
RUN groupadd celery
RUN useradd -N -M --system -s /bin/bash -G celery celery
 
# Create django user, will own the Django app
RUN adduser --disabled-login --group --system django
 
COPY --chown=django:django ./docker/production/django/sysctl.conf /etc/sysctl.conf
COPY --chown=django:django ./docker/production/django/custom.conf /etc/security/limits.d/custom.conf
 
# Copy virtual environment from the build stage and add to it PATH, activate venv
COPY --from=build --chown=django:django ${VENV_PATH} ${VENV_PATH}
ENV VIRTUAL_ENV=${VENV_PATH}
ENV PATH="${VENV_PATH}/bin:${PATH}"
 
# Copy application code. It's important to select WORKDIR here for code to work.
WORKDIR $APP_HOME
COPY --chown=django:django . ${APP_HOME}
 
# Make django an owner of the WORKDIR directory as well.
RUN chown -R django:django ${APP_HOME}
 
COPY --chown=django:django ./docker/production/django/start /start-webapp
RUN sed -i 's/\r$//g' /start-webapp
RUN chmod +x /start-webapp
 
COPY --chown=django:django ./docker/production/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r$//g' /start-celeryworker
RUN chmod +x /start-celeryworker
 
COPY --chown=django:django ./docker/production/django/celery/beat/start /start-celerybeat
RUN sed -i 's/\r$//g' /start-celerybeat
RUN chmod +x /start-celerybeat
 
COPY --chown=django:django ./docker/production/django/uwsgi.ini uwsgi.ini
 
EXPOSE 8080