Ctrl K
ComunidadGuías…

Dockerfile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# The release image: the API, the worker and the built frontend in one, for the desktop app and the two-command install.
# Build context: the repository root (see .dockerignore). Development keeps backend/Dockerfile and frontend/Dockerfile.

# Stage 1: the frontend, from the committed src/api/schema.d.ts. Not npm's own build script: its prebuild regenerates
# the types from a running API, which a build doesn't have.
FROM node:24-alpine AS web
WORKDIR /web
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
COPY frontend/ ./
RUN npx tsc -b && npx vite build

# Stage 2: the Python environment, as backend/Dockerfile builds it. Rebuilt only when pyproject.toml or uv.lock change.
FROM python:3.12-slim AS deps
COPY --from=ghcr.io/astral-sh/uv:0.11.19 /uv /usr/local/bin/uv
ENV UV_PROJECT_ENVIRONMENT=/venv UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
WORKDIR /src
COPY backend/pyproject.toml backend/uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-dev --no-install-project

# Tectonic, pinned and checked, with its package cache warmed by compiling main.tex of every template folder in
# manuscript_templates (twice: the second time with warm-results.tex inserted, so each class fetches the font sizes its
# own tables and charts use), warm-packages.tex and warm-diagram.tex (common packages and the TikZ libraries a
# diagram may load; not templates). Compiles only ever read this cache
# (TECTONIC_ONLY_CACHED), so acmart's ~20 s cold start is already paid and nothing is downloaded at compile time.
FROM python:3.12-slim AS tex
ARG TARGETARCH
ENV TECTONIC_CACHE_DIR=/tectonic-cache
RUN python - <<'PY'
import hashlib, os, tarfile, urllib.request
VERSION = "0.17.0"
SHA256 = {
    "x86_64": "8533d07f9ccbd7a65824b9e0459041bca34af1eb33daba48f59215593753a3b7",
    "aarch64": "b10954a95404f3ab2328d2fa59a5ebab8e657f893fab096f98be8db7c0c979b8",
}
arch = {"amd64": "x86_64", "arm64": "aarch64"}[os.environ["TARGETARCH"]]
asset = f"tectonic-{VERSION}-{arch}-unknown-linux-musl.tar.gz"
data = urllib.request.urlopen(
    f"https://github.com/tectonic-typesetting/tectonic/releases/download/tectonic%40{VERSION}/{asset}", timeout=120
).read()
assert hashlib.sha256(data).hexdigest() == SHA256[arch], "tectonic archive checksum mismatch"
open("/tmp/tectonic.tgz", "wb").write(data)
with tarfile.open("/tmp/tectonic.tgz") as tar:
    tar.extract("tectonic", "/usr/local/bin")
PY
COPY backend/app/manuscript_templates /templates
RUN for t in /templates/*/; do \
      d=$(mktemp -d) && cp -R "$t". "$d" && cp /templates/warm.bib "$d/paperlab.bib" \
      && (cd "$d" && tectonic -X compile main.tex) \
      && cp /templates/warm-results.tex /templates/warm-figure.png "$d" \
      && awk '/^\\begin\{document\}/ && !d { print "\\usepackage{booktabs,pgfplots,graphicx}"; print "\\pgfplotsset{compat=1.18}"; print; print "\\input{warm-results}"; d = 1; next } { print }' "$d/main.tex" > "$d/results.tex" \
      && (cd "$d" && tectonic -X compile results.tex) || exit 1; \
    done \
    && d=$(mktemp -d) && cd "$d" && cp /templates/warm-packages.tex main.tex && tectonic -X compile main.tex \
    && cp /templates/warm-diagram.tex main.tex && tectonic -X compile main.tex \
    && printf '\\documentclass{article}\\usepackage{verbatim}\\begin{document}\n\\begin{verbatim}\nx\n\\end{verbatim}\n\\end{document}\n' > main.tex \
    && tectonic -X compile main.tex && rm -rf /tmp/* \
    && chmod -R u=rwX,go=rX /tectonic-cache

# Runtime: the environment first, then the code, so an update that changes only code downloads only the last layers.
# No search model: it is downloaded into the models volume when the user chooses it.
FROM python:3.12-slim
LABEL org.opencontainers.image.source="https://github.com/khannoussi-malek/PaperLab" \
      org.opencontainers.image.description="PaperLab, a local-first research reader" \
      org.opencontainers.image.licenses="Apache-2.0"
COPY --from=deps /venv /venv
COPY --from=tex /usr/local/bin/tectonic /usr/local/bin/tectonic
# Manuscripts compile as `tex` (TECTONIC_USER), an account with no home and no write access to anything of ours.
RUN groupadd --system --gid 999 tex \
    && useradd --system --uid 999 --gid 999 --no-create-home --shell /usr/sbin/nologin tex
# The package cache is root's and read-only to tex (dirs 755, files 644): a project's \openout can't rewrite a package
# another project then loads. No volume: the cache lives in the image, so an update brings its warm set.
COPY --from=tex /tectonic-cache /tectonic-cache
ENV TECTONIC_CACHE_DIR=/tectonic-cache
ENV TECTONIC_ONLY_CACHED=1
ENV PATH=/venv/bin:$PATH PYTHONUNBUFFERED=1 FRONTEND_DIST=/app/web
WORKDIR /src
COPY backend/ ./
COPY --from=web /web/dist /app/web
# Tectonic runs as `tex`, which must not read the app's code (an `\input` of a relative path reads anything its user can).
RUN chmod 750 /src