add source code and readme

This commit is contained in:
2025-12-24 14:35:17 +01:00
parent 7c92e1e610
commit 74324d5a1b
331 changed files with 39272 additions and 1 deletions

View File

@@ -0,0 +1,95 @@
# Multi-stage build for smaller final image
FROM python:3.11-alpine AS builder
# Use HTTP repositories to avoid SSL issues, then install dependencies
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.22/main" > /etc/apk/repositories \
&& echo "http://dl-cdn.alpinelinux.org/alpine/v3.22/community" >> /etc/apk/repositories \
&& apk update \
&& apk add --no-cache \
pkgconfig \
gcc \
python3-dev \
musl-dev \
postgresql-dev \
linux-headers \
bash \
git \
curl
# Set working directory
WORKDIR /app
# v1.3.x
ARG PIEFED_VERSION=main
RUN git clone https://codeberg.org/rimu/pyfedi.git /app \
&& cd /app \
&& git checkout ${PIEFED_VERSION} \
&& rm -rf .git
# Install Python dependencies to /app/venv
RUN python -m venv /app/venv \
&& source /app/venv/bin/activate \
&& pip install --no-cache-dir -r requirements.txt \
&& pip install --no-cache-dir uwsgi
# Runtime stage - much smaller
FROM python:3.11-alpine AS runtime
# Set environment variables
ENV TZ=UTC
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV PATH="/app/venv/bin:$PATH"
# Install only runtime dependencies
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.22/main" > /etc/apk/repositories \
&& echo "http://dl-cdn.alpinelinux.org/alpine/v3.22/community" >> /etc/apk/repositories \
&& apk update \
&& apk add --no-cache \
ca-certificates \
curl \
su-exec \
dcron \
libpq \
jpeg \
freetype \
lcms2 \
openjpeg \
tiff \
nginx \
supervisor \
redis \
bash \
tesseract-ocr \
tesseract-ocr-data-eng
# Create piefed user
RUN addgroup -g 1000 piefed \
&& adduser -u 1000 -G piefed -s /bin/sh -D piefed
# Set working directory
WORKDIR /app
# Copy application and virtual environment from builder
COPY --from=builder /app /app
COPY --from=builder /app/venv /app/venv
# Compile translations (matching official Dockerfile)
RUN source /app/venv/bin/activate && \
(pybabel compile -d app/translations || true)
# Set proper permissions - ensure logs directory is writable for dual logging
RUN chown -R piefed:piefed /app \
&& mkdir -p /app/logs /app/app/static/tmp /app/app/static/media \
&& chown -R piefed:piefed /app/logs /app/app/static/tmp /app/app/static/media \
&& chmod -R 755 /app/logs /app/app/static/tmp /app/app/static/media \
&& chmod 777 /app/logs
# Copy shared entrypoint utilities
COPY entrypoint-common.sh /usr/local/bin/entrypoint-common.sh
COPY entrypoint-init.sh /usr/local/bin/entrypoint-init.sh
RUN chmod +x /usr/local/bin/entrypoint-common.sh /usr/local/bin/entrypoint-init.sh
# Create directories for logs and runtime
RUN mkdir -p /var/log/piefed /var/run/piefed \
&& chown -R piefed:piefed /var/log/piefed /var/run/piefed

View File

@@ -0,0 +1,83 @@
#!/bin/sh
set -e
# Common initialization functions for PieFed containers
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
# Wait for database to be available
wait_for_db() {
log "Waiting for database connection..."
until python -c "
import psycopg2
import os
from urllib.parse import urlparse
try:
# Parse DATABASE_URL
database_url = os.environ.get('DATABASE_URL', '')
if not database_url:
raise Exception('DATABASE_URL not set')
# Parse the URL to extract connection details
parsed = urlparse(database_url)
conn = psycopg2.connect(
host=parsed.hostname,
port=parsed.port or 5432,
database=parsed.path[1:], # Remove leading slash
user=parsed.username,
password=parsed.password
)
conn.close()
print('Database connection successful')
except Exception as e:
print(f'Database connection failed: {e}')
exit(1)
" 2>/dev/null; do
log "Database not ready, waiting 2 seconds..."
sleep 2
done
log "Database connection established"
}
# Wait for Redis to be available
wait_for_redis() {
log "Waiting for Redis connection..."
until python -c "
import redis
import os
try:
cache_redis_url = os.environ.get('CACHE_REDIS_URL', '')
if cache_redis_url:
r = redis.from_url(cache_redis_url)
else:
# Fallback to separate host/port for backwards compatibility
r = redis.Redis(host='redis', port=6379, password=os.environ.get('REDIS_PASSWORD', ''))
r.ping()
print('Redis connection successful')
except Exception as e:
print(f'Redis connection failed: {e}')
exit(1)
" 2>/dev/null; do
log "Redis not ready, waiting 2 seconds..."
sleep 2
done
log "Redis connection established"
}
# Common startup sequence
common_startup() {
log "Starting PieFed common initialization..."
# Change to application directory
cd /app
# Wait for dependencies
wait_for_db
wait_for_redis
log "Common initialization completed"
}

View File

@@ -0,0 +1,108 @@
#!/bin/sh
set -e
# Database initialization entrypoint for PieFed
# This script runs as a Kubernetes Job before web/worker pods start
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
log "Starting PieFed database initialization..."
# Wait for database to be available
wait_for_db() {
log "Waiting for database connection..."
until python -c "
import psycopg2
import os
from urllib.parse import urlparse
try:
# Parse DATABASE_URL
database_url = os.environ.get('DATABASE_URL', '')
if not database_url:
raise Exception('DATABASE_URL not set')
# Parse the URL to extract connection details
parsed = urlparse(database_url)
conn = psycopg2.connect(
host=parsed.hostname,
port=parsed.port or 5432,
database=parsed.path[1:], # Remove leading slash
user=parsed.username,
password=parsed.password
)
conn.close()
print('Database connection successful')
except Exception as e:
print(f'Database connection failed: {e}')
exit(1)
" 2>/dev/null; do
log "Database not ready, waiting 2 seconds..."
sleep 2
done
log "Database connection established"
}
# Wait for Redis to be available
wait_for_redis() {
log "Waiting for Redis connection..."
until python -c "
import redis
import os
try:
cache_redis_url = os.environ.get('CACHE_REDIS_URL', '')
if cache_redis_url:
r = redis.from_url(cache_redis_url)
else:
# Fallback to separate host/port for backwards compatibility
r = redis.Redis(host='redis', port=6379, password=os.environ.get('REDIS_PASSWORD', ''))
r.ping()
print('Redis connection successful')
except Exception as e:
print(f'Redis connection failed: {e}')
exit(1)
" 2>/dev/null; do
log "Redis not ready, waiting 2 seconds..."
sleep 2
done
log "Redis connection established"
}
# Main initialization sequence
main() {
# Change to application directory
cd /app
# Wait for dependencies
wait_for_db
wait_for_redis
# Run database migrations
log "Running database migrations..."
export FLASK_APP=pyfedi.py
# Run Flask database migrations
flask db upgrade
log "Database migrations completed"
# Populate community search index
log "Populating community search..."
flask populate_community_search
log "Community search populated"
# Ensure log files have correct ownership for dual logging (file + stdout)
if [ -f /app/logs/pyfedi.log ]; then
chown piefed:piefed /app/logs/pyfedi.log
chmod 664 /app/logs/pyfedi.log
log "Fixed log file ownership for piefed user"
fi
log "Database initialization completed successfully!"
}
# Run the main function
main