33# Excludes JARs listed in jar_exclusions.txt to optimize size
44#
55# REQUIRED BUILD ARGS (passed from build.sh):
6+ # PYTHON_VERSION - Python version for wheel (e.g., 3.11, 3.12, 3.13, 3.14)
67# PACKAGE_NAME - always: arcadedb-embedded
78# PACKAGE_DESCRIPTION - package description
8- # ARCADEDB_TAG - version tag from pom.xml (e.g., 25.10.1-SNAPSHOT)
9- # Default below is fallback; build.sh extracts and passes actual version
109# TARGET_PLATFORM - target platform for JRE (e.g., linux-x64, linux-arm64, darwin-x64)
1110
11+ ARG PYTHON_VERSION=3.12
1212ARG PACKAGE_NAME=arcadedb-embedded
1313ARG PACKAGE_DESCRIPTION="ArcadeDB embedded multi-model database with bundled JRE - no Java installation required"
14- ARG ARCADEDB_TAG=25.10.1-SNAPSHOT
14+ ARG ARCADEDB_TAG
1515ARG TARGET_PLATFORM=linux-x64
16+ # When set to 1, prefer jars provided in bindings/python/local-jars/lib from the build context.
17+ # If no local jars are present, the build fails fast to avoid silently falling back.
18+ ARG USE_LOCAL_JARS=0
1619
1720# Stage 1: Use prebuilt ArcadeDB image to obtain compiled JARs
1821# JARs are filtered based on jar_exclusions.txt in later stages
@@ -21,15 +24,30 @@ FROM arcadedata/arcadedb:${ARCADEDB_TAG} AS java-builder
2124# nothing to do here; jars will be copied from /home/arcadedb/lib in the python-builder stage
2225
2326# Stage 2: Build minimal JRE with jlink
24- FROM eclipse-temurin:21 -jdk-jammy AS jre-builder
27+ FROM eclipse-temurin:25 -jdk-jammy AS jre-builder
2528
2629ARG TARGET_PLATFORM
30+ ARG USE_LOCAL_JARS
2731
2832WORKDIR /build
2933
30- # Copy JARs from ArcadeDB image
31- RUN mkdir -p /build/jars
32- COPY --from=java-builder /home/arcadedb/lib /build/jars/
34+ # Stash upstream jars from the ArcadeDB image
35+ RUN mkdir -p /build/upstream-jars /build/jars /build/local-jars
36+ COPY --from=java-builder /home/arcadedb/lib /build/upstream-jars/
37+
38+ # Optionally bring in locally built jars from the repo (bindings/python/local-jars/lib)
39+ COPY bindings/python/local-jars/lib/ /build/local-jars/
40+
41+ # Select jar source: local when requested and available; otherwise fall back to upstream image
42+ RUN if [ "$USE_LOCAL_JARS" = "1" ]; then \
43+ if [ -d /build/local-jars ] && [ "$(ls -1 /build/local-jars | wc -l)" -gt 0 ]; then \
44+ echo "📦 Using local jars from build context" && cp /build/local-jars/* /build/jars/; \
45+ else \
46+ echo "❌ USE_LOCAL_JARS=1 but no jars found in bindings/python/local-jars/lib" && exit 1; \
47+ fi; \
48+ else \
49+ echo "📦 Using ArcadeDB image jars" && cp /build/upstream-jars/* /build/jars/; \
50+ fi
3351
3452# Copy JAR exclusion list
3553COPY bindings/python/jar_exclusions.txt /build/jar_exclusions.txt
@@ -47,26 +65,43 @@ RUN echo "🗑️ Removing excluded JARs..." && \
4765 done < /build/jar_exclusions.txt && \
4866 echo "📋 JAR count after exclusion: $(ls -1 /build/jars/*.jar | wc -l)"
4967
50- # Build minimal JRE with jlink (21 modules)
51- # Based on analysis of ArcadeDB dependencies
52- # Note: jdk.zipfs is required for JPype JAR filesystem support
53- RUN echo "🔨 Building minimal JRE for platform: ${TARGET_PLATFORM}" && \
54- REQUIRED_MODULES="java.base,java.compiler,java.desktop,java.logging,java.management,java.naming,java.prefs,java.rmi,java.scripting,java.security.jgss,java.security.sasl,java.sql,java.transaction.xa,java.xml,jdk.incubator.vector,jdk.internal.vm.ci,jdk.jfr,jdk.management,jdk.sctp,jdk.unsupported,jdk.zipfs" && \
55- echo "📦 Required modules (21):" && \
68+ # Build minimal JRE with jlink
69+ # Automatically detect modules with jdeps, plus ensure jdk.zipfs (for JPype) and jdk.unsupported are included
70+ # We exclude jboss/wildfly JARs because they have broken module descriptors that fail analysis.
71+ # We also do NOT provide a classpath, forcing jdeps to ignore all missing dependencies (intra-jar or external).
72+ RUN echo "🔍 Analyzing JARs with jdeps..." && \
73+ DETECTED_MODULES=$(find /build/jars -name "*.jar" | grep -v "jboss" | grep -v "wildfly" | grep -v "smallrye" | xargs jdeps --print-module-deps --ignore-missing-deps --multi-release 25 | grep -v "Warning" | tr ',' '\n' | grep -v "Warning" | grep -v ":" | grep -v "/" | sort -u | paste -sd "," -) && \
74+ REQUIRED_MODULES="${DETECTED_MODULES},jdk.zipfs,jdk.unsupported" && \
75+ echo "🔨 Building minimal JRE for platform: ${TARGET_PLATFORM}" && \
76+ echo "📦 Detected modules: ${DETECTED_MODULES}" && \
77+ echo "📦 Final modules list: ${REQUIRED_MODULES}" && \
78+ echo "📦 Required modules:" && \
5679 echo "$REQUIRED_MODULES" | tr ',' '\n' | sed 's/^/ - /' && \
57- echo "" && \
58- echo "🔨 Running jlink..." && \
59- jlink \
60- --module-path "${JAVA_HOME}/jmods" \
61- --add-modules "${REQUIRED_MODULES}" \
62- --ignore-signing-information \
63- --strip-debug \
64- --no-man-pages \
65- --no-header-files \
66- --compress zip-9 \
67- --output /build/jre && \
68- echo "" && \
69- echo "✅ JRE build complete!" && \
80+ JMODS_DIR="${JAVA_HOME}/jmods" && \
81+ if [ ! -d "$JMODS_DIR" ]; then JMODS_DIR="${JAVA_HOME}/lib/jmods"; fi && \
82+ if [ -d "$JMODS_DIR" ]; then \
83+ echo "" ; \
84+ echo "🔨 Running jlink..." ; \
85+ jlink \
86+ --module-path "$JMODS_DIR" \
87+ --add-modules "${REQUIRED_MODULES}" \
88+ --ignore-signing-information \
89+ --strip-debug \
90+ --no-man-pages \
91+ --no-header-files \
92+ --compress zip-9 \
93+ --output /build/jre ; \
94+ echo "" ; \
95+ echo "✅ JRE build complete!" ; \
96+ else \
97+ echo "⚠️ jmods directory not found under ${JAVA_HOME}. Falling back to copying full JDK runtime." ; \
98+ mkdir -p /build/jre ; \
99+ cp -a ${JAVA_HOME}/bin /build/jre/bin ; \
100+ cp -a ${JAVA_HOME}/lib /build/jre/lib ; \
101+ cp -a ${JAVA_HOME}/conf /build/jre/conf || true ; \
102+ cp -a ${JAVA_HOME}/release /build/jre/release || true ; \
103+ echo "✅ Fallback JRE created from full JDK runtime." ; \
104+ fi && \
70105 echo "" && \
71106 JRE_SIZE=$(du -sh /build/jre | cut -f1) && \
72107 echo "📊 JRE size: $JRE_SIZE" && \
@@ -82,16 +117,19 @@ RUN echo "🔨 Building minimal JRE for platform: ${TARGET_PLATFORM}" && \
82117
83118# Stage 3: Build Python wheel
84119
85- FROM python:3.11 -slim AS python-builder
120+ FROM python:${PYTHON_VERSION} -slim AS python-builder
86121
87- # Install system dependencies ( JDK needed for JPype at build/test time )
122+ # Install minimal build tooling (no external JDK needed; we use bundled JRE )
88123RUN apt-get update && apt-get install -y \
89- openjdk-21-jdk \
124+ build-essential \
125+ curl \
126+ file \
127+ patchelf \
90128 && rm -rf /var/lib/apt/lists/*
91129
92- # Set JAVA_HOME
93- ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
94- ENV PATH=$PATH:$JAVA_HOME/bin
130+ # Install uv for faster, deterministic installs
131+ ENV PATH="/root/.cargo/bin:/root/.local/bin:${PATH}"
132+ RUN curl -LsSf https://astral.sh/uv/install.sh | sh && uv --version
95133
96134WORKDIR /build
97135
@@ -117,7 +155,7 @@ COPY bindings/python/README.md ./
117155COPY ../../pom.xml /arcadedb/pom.xml
118156
119157# Install Python build dependencies
120- RUN pip install --no-cache-dir build wheel setuptools jpype1
158+ RUN uv pip install --system build wheel setuptools jpype1 auditwheel
121159
122160# Re-declare build args for this stage (required after FROM)
123161ARG PACKAGE_NAME
@@ -150,7 +188,30 @@ RUN if [ -n "${BUILD_VERSION}" ]; then \
150188 sed -i 's|^name = .*|name = "'"${PACKAGE_NAME}"'"|' pyproject.toml && \
151189 sed -i 's|^version = .*|version = "'"${ARCADEDB_VERSION}"'"|' pyproject.toml && \
152190 sed -i 's|^description = .*|description = "'"${PACKAGE_DESCRIPTION}"'"|' pyproject.toml && \
153- python3 -m build --wheel && \
191+ if echo "${TARGET_PLATFORM}" | grep -q '^linux-'; then \
192+ if [ "${TARGET_PLATFORM}" = "linux-x64" ]; then \
193+ WHEEL_PLAT="manylinux_2_35_x86_64"; \
194+ elif [ "${TARGET_PLATFORM}" = "linux-arm64" ]; then \
195+ WHEEL_PLAT="manylinux_2_35_aarch64"; \
196+ else \
197+ WHEEL_PLAT=""; \
198+ fi; \
199+ if [ -n "${WHEEL_PLAT}" ]; then \
200+ echo "🏷️ Building wheel with platform tag: ${WHEEL_PLAT}"; \
201+ python3 -m build --wheel --config-setting=--build-option=--plat-name=${WHEEL_PLAT}; \
202+ else \
203+ python3 -m build --wheel; \
204+ fi; \
205+ else \
206+ python3 -m build --wheel; \
207+ fi && \
208+ if echo "${TARGET_PLATFORM}" | grep -q '^linux-'; then \
209+ if [ -n "${WHEEL_PLAT}" ] && ! ls /build/dist/*${WHEEL_PLAT}*.whl 1> /dev/null 2>&1; then \
210+ echo "❌ Expected manylinux wheel (${WHEEL_PLAT}) not found"; \
211+ ls -lh /build/dist; \
212+ exit 1; \
213+ fi; \
214+ fi && \
154215 echo "✅ Wheel built successfully!" && \
155216 ls -lh dist/
156217
@@ -160,23 +221,26 @@ FROM python-builder AS export
160221# The dist directory is preserved from python-builder stage
161222
162223# Stage 5: Test the built wheel
163- FROM python:3.11 -slim AS tester
224+ FROM python:${PYTHON_VERSION} -slim AS tester
164225
165- # Install Java runtime for JPype
226+ # No external JRE needed in tester; the wheel includes a bundled JRE
227+ # Keep build-essential in case pytest or wheels need compilation on some platforms
166228RUN apt-get update && apt-get install -y \
167- openjdk-21-jre-headless \
229+ build-essential \
230+ curl \
168231 && rm -rf /var/lib/apt/lists/*
169232
170- ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
171- ENV PATH=$PATH:$JAVA_HOME/bin
233+ # Install uv for faster, deterministic installs
234+ ENV PATH="/root/.cargo/bin:/root/.local/bin:${PATH}"
235+ RUN curl -LsSf https://astral.sh/uv/install.sh | sh && uv --version
172236
173237WORKDIR /test
174238
175239# Copy the wheel from builder
176240COPY --from=python-builder /build/dist/*.whl /tmp/
177241
178242# Install the wheel and test dependencies
179- RUN pip install --no-cache-dir /tmp/*.whl pytest pytest-cov
243+ RUN uv pip install --system /tmp/*.whl pytest pytest-cov
180244
181245# Copy tests
182246COPY --from=python-builder /build/tests ./tests/
@@ -205,7 +269,7 @@ try:\n\
205269 \n\
206270 result = db.query("sql", "SELECT FROM TestDoc")\n\
207271 for record in result:\n\
208- print(f"✅ Query result: {record.get_property ('\''name'\'')} = {record.get_property ('\''value'\'')}")\n\
272+ print(f"✅ Query result: {record.get ('\''name'\'')} = {record.get ('\''value'\'')}")\n\
209273 \n\
210274 print("🎉 All tests passed!")\n\
211275finally:\n\
0 commit comments