Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.git
**/node_modules
**/build
**/coverage
venv
*.pyc
__pycache__
*.egg-info
config.ini
config.development.ini
web.log
web.sock
21 changes: 7 additions & 14 deletions Dockerfile-counter
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y python3-pip

RUN pip3 install --upgrade pip

ENV APP_DIR /deploy

RUN mkdir -p ${APP_DIR}

COPY . ${APP_DIR}
FROM python:3.11-slim

ENV APP_DIR=/deploy
WORKDIR ${APP_DIR}

RUN pip3 install -r ${APP_DIR}/requirements.txt
COPY requirements.txt ${APP_DIR}/requirements.txt
RUN pip3 install --no-cache-dir --upgrade pip \
&& pip3 install --no-cache-dir -r ${APP_DIR}/requirements.txt

CMD ["python3", "counter/main.py"]
COPY . ${APP_DIR}

CMD ["python3", "counter/main.py"]
39 changes: 20 additions & 19 deletions Dockerfile-web
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
FROM node:8
# --- Stage 1: build the React SPA ---
FROM node:20-bookworm-slim AS web-build

RUN apt-get update
RUN apt-get install -y python3-pip
WORKDIR /app/react_app

RUN pip3 install --upgrade pip
# Install dependencies against the committed lockfile first (better layer caching).
# node:20 already ships yarn 1.22.x.
COPY react_app/package.json react_app/yarn.lock ./
RUN yarn install --frozen-lockfile --non-interactive

ENV APP_DIR /deploy
# Build the static bundle into /app/react_app/build
COPY react_app/ ./
RUN yarn build

RUN mkdir -p ${APP_DIR}

COPY . ${APP_DIR}
# --- Stage 2: Python runtime (Flask + gunicorn) ---
FROM python:3.11-slim

ENV APP_DIR=/deploy
WORKDIR ${APP_DIR}

RUN pip3 install -r ${APP_DIR}/requirements.txt

WORKDIR ${APP_DIR}/react_app

RUN npm rebuild node-sass
COPY requirements.txt ${APP_DIR}/requirements.txt
RUN pip3 install --no-cache-dir --upgrade pip \
&& pip3 install --no-cache-dir -r ${APP_DIR}/requirements.txt

RUN yarn

RUN yarn run build
COPY . ${APP_DIR}

WORKDIR ${APP_DIR}
# Bring in the built SPA from the build stage (app.py serves react_app/build)
COPY --from=web-build /app/react_app/build ${APP_DIR}/react_app/build

EXPOSE 5001

CMD ["gunicorn", "app:app", "-b", "0.0.0.0:5001"]

CMD ["gunicorn", "app:app", "-b", "0.0.0.0:5001"]
2 changes: 1 addition & 1 deletion app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from flask import request, jsonify, abort
from flask_cors import CORS
from werkzeug.middleware.proxy_fix import ProxyFix
from xonfig import get_option
from appconfig import get_option

REDIS_HOST = get_option('REDIS', 'HOST')
REDIS_PORT = get_option('REDIS', 'PORT')
Expand Down
86 changes: 86 additions & 0 deletions appconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Minimal stdlib-based config reader.
#
# Replaces the `xonfig` package, which is unmaintained and crashes on
# Python 3.10+ (its custom interpolation no longer satisfies configparser's
# isinstance check). Behaviour kept compatible with how app.py used xonfig:
# - reads config.ini (then an env-specific overlay) from the working dir or a
# parent directory,
# - coerces values with ast.literal_eval so ints/floats/bools come back typed,
# - supports __ENV__SECTION_OPTION environment variable overrides,
# - keeps option keys case-sensitive.
import ast
import configparser
import os


def _literal_eval(val):
try:
return ast.literal_eval(val)
except (SyntaxError, ValueError):
return val


class _Interpolation(configparser.Interpolation):
def before_get(self, parser, section, option, value, defaults):
return _literal_eval(value)


_config = configparser.ConfigParser(interpolation=_Interpolation())
_config.optionxform = str


def _lookup_dirs():
cwd = os.path.abspath(os.getcwd())
return [
cwd,
os.path.abspath(os.path.join(cwd, '..')),
os.path.abspath(os.path.join(cwd, '..', '..')),
]


def _read_files():
env = (os.environ.get('__ENV__') or '').lower()
env_file = 'config.{}.ini'.format(env) if env in ('testing', 'production') else 'config.development.ini'

for name in ('config.ini', env_file):
for directory in _lookup_dirs():
path = os.path.join(directory, name)
if os.path.isfile(path):
_config.read(path)
break


def _split_section_option(rest):
# Prefer the longest already-known section that prefixes the key, so a
# section name containing underscores (e.g. ESEARCH_API) is matched as a
# whole instead of being split at its first underscore. Falls back to the
# first underscore when no defined section matches.
for section in sorted(_config.sections(), key=len, reverse=True):
if rest == section:
return None
if rest.startswith(section + '_'):
return section, rest[len(section) + 1:]
if '_' in rest:
return tuple(rest.split('_', 1))
return None


def _read_env():
for key, value in os.environ.items():
if not key.startswith('__ENV__') or len(key) == len('__ENV__'):
continue
parsed = _split_section_option(key[len('__ENV__'):])
if not parsed:
continue
section, option = parsed
if not _config.has_section(section):
_config.add_section(section)
_config.set(section, option, value)


_read_files()
_read_env()


def get_option(section, option):
return _config.get(section, option)
2 changes: 1 addition & 1 deletion counter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

os.sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))

from xonfig import get_option
from appconfig import get_option

API_URL = get_option('ESEARCH_API', 'URL')
API_TOKEN = get_option('ESEARCH_API', 'TOKEN')
Expand Down
93 changes: 0 additions & 93 deletions react_app/config/env.js

This file was deleted.

14 changes: 0 additions & 14 deletions react_app/config/jest/cssTransform.js

This file was deleted.

12 changes: 0 additions & 12 deletions react_app/config/jest/fileTransform.js

This file was deleted.

55 changes: 0 additions & 55 deletions react_app/config/paths.js

This file was deleted.

24 changes: 0 additions & 24 deletions react_app/config/polyfills.js

This file was deleted.

Loading