From b7cb29991df1b26010f4c255634f7eaa8aff326f Mon Sep 17 00:00:00 2001 From: Okiki Ojo Date: Tue, 9 Dec 2025 01:10:34 -0500 Subject: [PATCH] refactor: refactor QLever Docker setup and add initial dataset - Split Dockerfile into multiple stages for better organization and clarity. - Introduced a new init container to handle permissions for the data volume. - Added a new environment file (`qlever.env`) for configuration management. - Created a new entrypoint script to manage QLever server startup and indexing logic. - Added a script to generate a Qleverfile based on environment variables. - Included a sample dataset (`data.nt`) for testing purposes. - Updated `docker-compose.yaml` to reflect changes in service structure and dependencies. Signed-off-by: Okiki Ojo --- infra/qlever/Dockerfile | 177 +++++++++++++------- infra/qlever/data/data.nt | 163 ++++++++++++++++++ infra/qlever/docker-compose.yaml | 54 +++--- infra/qlever/qlever.env | 34 ++++ infra/qlever/scripts/entrypoint.sh | 137 +++++++++++++++ infra/qlever/scripts/generate-qleverfile.sh | 93 ++++++++++ 6 files changed, 566 insertions(+), 92 deletions(-) create mode 100644 infra/qlever/data/data.nt create mode 100644 infra/qlever/qlever.env create mode 100644 infra/qlever/scripts/entrypoint.sh create mode 100644 infra/qlever/scripts/generate-qleverfile.sh diff --git a/infra/qlever/Dockerfile b/infra/qlever/Dockerfile index 6527118..ce429b3 100644 --- a/infra/qlever/Dockerfile +++ b/infra/qlever/Dockerfile @@ -1,71 +1,128 @@ -FROM ubuntu:24.04 AS builder +# docker/server.Dockerfile + +# ----------------------------- +# Stage 1: Build QLever from source +# ----------------------------- +FROM ubuntu:24.04 AS qlever-build + +ARG QLEVER_GIT_REF="master" # You can pin to a tag/commit if you want ENV DEBIAN_FRONTEND=noninteractive -# Basic tools + git -RUN apt-get update && apt-get install -y wget git +RUN apt-get update \ + && apt-get install -y \ + git \ + cmake \ + ninja-build \ + build-essential \ + libzstd-dev \ + libjemalloc-dev \ + libboost-all-dev \ + && rm -rf /var/lib/apt/lists/* -# Newer CMake from Kitware (as you had) -RUN wget https://apt.kitware.com/kitware-archive.sh \ - && chmod +x kitware-archive.sh \ - && ./kitware-archive.sh \ - && apt-get update +WORKDIR /src -# Build dependencies (mostly copied from your file) -RUN apt-get install -y \ - build-essential cmake libicu-dev tzdata pkg-config uuid-runtime uuid-dev \ - libjemalloc-dev ninja-build libzstd-dev libssl-dev \ - libboost1.83-dev libboost-program-options1.83-dev \ - libboost-iostreams1.83-dev libboost-url1.83-dev \ - libboost-container1.83-dev +# Clone QLever and checkout the requested ref +RUN git clone https://github.com/ad-freiburg/qlever.git . \ + && git checkout "${QLEVER_GIT_REF}" -# Fetch QLever source (repo has src/, test/, CMakeLists.txt, CompilationInfo.cmake, docker-entrypoint.sh) -WORKDIR /qlever -RUN git clone --recursive https://github.com/ad-freiburg/qlever.git . +# Configure with conservative CPU flags so we don't hit Illegal Instruction +RUN cmake -S . -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_FLAGS="-march=x86-64 -mtune=generic" \ + -DUSE_PARALLEL=true -# Configure + build binaries -WORKDIR /qlever/build -RUN cmake -DCMAKE_BUILD_TYPE=Release \ - -DLOGLEVEL=INFO \ - -DUSE_PARALLEL=true \ - -DNATIVE_ARCH=OFF \ - -GNinja .. -RUN cmake --build . --target IndexBuilderMain ServerMain +# Build only the two main binaries we need +RUN cmake --build build --target IndexBuilderMain ServerMain -j4 +# ----------------------------- +# Stage 2: Stop-on-call helper +# ----------------------------- +FROM ghcr.io/ludovicm67/stop-on-call:v0.1.0 AS soc + +# ----------------------------- +# Stage 3: Final QLever runtime image +# ----------------------------- FROM ubuntu:24.04 + +# Match the CLI version to something recent / stable +# Check PyPI for latest: https://pypi.org/project/qlever/ +ARG QLEVER_VERSION="0.5.35" +ARG PIPX_VERSION="1.8.0" + ENV DEBIAN_FRONTEND=noninteractive + +# Core runtime deps for QLever binaries + Python CLI +RUN apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y \ + bash-completion \ + bzip2 \ + curl \ + libboost-iostreams1.83.0 \ + libboost-program-options1.83.0 \ + libboost-url1.83.0 \ + libgomp1 \ + libicu74 \ + libjemalloc2 \ + libzstd1 \ + pipx \ + python3 \ + unzip \ + uuid-runtime \ + vim \ + wget \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && apt-get clean + +# Create dirs and relax permissions so the `nobody`-like user can write +RUN mkdir -p /qlever /data \ + && chmod -R a+rw /data \ + && chmod -R a+rw /qlever + +# Shell convenience for interactive use (optional, but nice) +RUN echo 'eval "$(register-python-argcomplete qlever)"' >> /etc/bash.bashrc \ + && echo 'PATH="/qlever:${PATH}"' >> /etc/bash.bashrc + +ENV QLEVER_ARGCOMPLETE_ENABLED="1" +ENV QLEVER_IS_RUNNING_IN_CONTAINER="1" + +# Upgrade pipx to the pyz version with --global support +RUN curl -L -o /usr/local/bin/pipx "https://github.com/pypa/pipx/releases/download/${PIPX_VERSION}/pipx.pyz" \ + && chmod +x /usr/local/bin/pipx + +# Install the QLever CLI (Python wrapper); this will invoke our compiled binaries +RUN pipx install --global "qlever==${QLEVER_VERSION}" + +# Copy compiled binaries from the build stage +# NOTE: CMake by default puts executables directly in build/, not under apps/ +COPY --from=qlever-build /src/build/IndexBuilderMain /qlever/ +COPY --from=qlever-build /src/build/ServerMain /qlever/ + +ENV PATH="/qlever:${PATH}" + +# Copy your helper scripts +RUN mkdir -p /qlever/scripts +COPY ./scripts/generate-qleverfile.sh /qlever/scripts/ +COPY ./scripts/entrypoint.sh /qlever/scripts/ +RUN chmod +x /qlever/scripts/*.sh + +# Configure Stop On Call +ENV STOP_ON_CALL_ENABLED="false" +COPY --from=soc /app/stop_on_call /usr/bin/stop_on_call + +# Use the nobody user by default (65534) +USER 65534 + WORKDIR /qlever -RUN apt-get update && apt-get install -y \ - python3-yaml unzip curl bzip2 pkg-config libicu74 python3-icu \ - libgomp1 uuid-runtime make lbzip2 libjemalloc2 libzstd1 \ - libboost-program-options1.83.0 libboost-iostreams1.83.0 \ - libboost-url1.83.0 pipx bash-completion vim sudo && \ - rm -rf /var/lib/apt/lists/* - -RUN groupadd -r qlever && useradd --no-log-init -d /qlever -r -g qlever qlever && \ - chown qlever:qlever /qlever && \ - echo "qlever ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers - -ENV QLEVER_PROFILE=/etc/profile.d/qlever.sh -RUN echo 'eval "$(register-python-argcomplete qlever)"' >> $QLEVER_PROFILE && \ - echo "export QLEVER_ARGCOMPLETE_ENABLED=1" >> $QLEVER_PROFILE && \ - echo "export QLEVER_IS_RUNNING_IN_CONTAINER=1" >> $QLEVER_PROFILE && \ - echo 'PATH=/qlever:/qlever/.local/bin:$PATH && PS1="\u@docker:\W\$ "' >> $QLEVER_PROFILE && \ - echo 'alias ll="ls -l"' >> $QLEVER_PROFILE && \ - echo "if [ -d /data ]; then cd /data; fi" >> $QLEVER_PROFILE && \ - cp $QLEVER_PROFILE /qlever/.bashrc - -USER qlever -ENV PATH=/qlever:/qlever/.local/bin:$PATH -RUN pipx install qlever -ENV QLEVER_ARGCOMPLETE_ENABLED=1 -ENV QLEVER_IS_RUNNING_IN_CONTAINER=1 - -# Copy the freshly built binaries from the builder stage -COPY --from=builder /qlever/build/*Main /qlever/ - -# Copy the entrypoint script from the source checkout (also in the builder stage) -COPY --from=builder /qlever/docker-entrypoint.sh /qlever/ -RUN sudo chmod +x /qlever/docker-entrypoint.sh - -ENTRYPOINT ["/qlever/docker-entrypoint.sh"] +EXPOSE 7001 + +# Default envs (these are also used by generate-qleverfile.sh) +ENV QLEVER_SERVER_HOST_NAME="127.0.0.1" +ENV QLEVER_SERVER_PORT="7001" +ENV QLEVER_RUNTIME_SYSTEM="native" + +# We let the script be the main process; keep ENTRYPOINT empty for compatibility +ENTRYPOINT [ "" ] +CMD [ "/qlever/scripts/entrypoint.sh" ] diff --git a/infra/qlever/data/data.nt b/infra/qlever/data/data.nt new file mode 100644 index 0000000..5f5f5fa --- /dev/null +++ b/infra/qlever/data/data.nt @@ -0,0 +1,163 @@ +# TBBT (The Big Bang Theory) dataset + . + "Farrah" . + "Fowler" . + "Amy" . + "neurobiologist" . + . + . + . + . + . + . + . + . + "Maryann" . + "Rostenkowski-Wolowitz" . + "Bernadette" . + "microbiologist" . + . + . + . + . + . + . + . + . + . + "Joel" . + "Wolowitz" . + "Howard" . + "aerospace engineer" . + . + . + . + . + . + . + . + . + . + "Leakey" . +_:b1 "US" . +_:b1 "Pasadena" . +_:b1 "CA" . +_:b1 "91104" . +_:b1 "2311 North Los Robles Avenue, Apartment 4A" . + _:b1 . + "Hofstadter" . + "Leonard" . + "experimental physicist" . + . + . + . + . + . + . + . + . + . +_:b2 "US" . +_:b2 "TX" . + _:b2 . + . + "Cooper" . + "Mary" . + . + . + . + . + . +_:b3 "US" . +_:b3 "Pasadena" . +_:b3 "CA" . +_:b3 "91104" . +_:b3 "2311 North Los Robles Avenue, Apartment 4B" . + _:b3 . + "Penny" . + "pharmaceutical sales representative" . + . + . + . + . + . + . + . + . + "Ramayan Raj" . + "Koothrappali" . + "Rajesh" . + "astrophysicist" . + . + . + . + . + . + . + . + . + "Lee" . +_:b4 "US" . +_:b4 "Pasadena" . +_:b4 "CA" . +_:b4 "91104" . +_:b4 "2311 North Los Robles Avenue, Apartment 4A" . + _:b4 . + "Cooper" . + "Sheldon" . + "theoretical physicist" . + . + . + . + . + . + . + . + . + . + "Bloom" . + "Stuart" . + "comic book store owner" . + . + . + . + . + . + . + . + + +# France (polygon) + +## Feature + . + "France" . + . + +## Geometry + . + "POLYGON((8.24127303627454 48.97794887560541,5.231019130024541 49.750647190315945,2.440491786274541 51.14961841626458,1.5176402237745412 50.87313049536895,1.5011607315870412 50.21336829946772,0.9133921768995412 49.99845644178497,0.21576034096204122 49.82512350296763,-0.2621449324754588 49.33718921868228,-1.8881214949754588 49.82157960827845,-2.085875401225459 49.394425976491604,-1.5365589949754588 48.73217609928656,-3.140562901225459 48.891343313415014,-4.942320713725459 48.630624713300485,-4.766539463725459 48.07577006394907,-4.371031651225459 47.75177459783237,-3.096617588725459 47.21722096602976,-1.5805043074754588 45.61162012205615,-1.7782582137254588 43.60971468750438,-1.8881214949754588 43.290685000073935,0.19928084877454122 42.61524836026427,0.8145152237745412 42.7928648459883,2.704163661274541 42.24222710444366,3.253480067524541 42.420905523667386,3.561097255024541 43.14657273329965,4.659730067524541 43.08241351640007,6.549378505024541 42.501955158864604,7.208558192524541 42.95389331205366,8.65875350502454 41.324731196577005,9.66949569252454 41.423662015262664,10.02105819252454 42.88953234551158,9.31793319252454 43.46635957827632,7.911683192524541 43.08241351640007,7.516175380024541 43.784463573801766,7.735901942524541 44.16396575789822,7.054749598774541 44.22698031120467,6.944886317524541 44.61929440132649,7.098694911274541 44.75988294318899,6.791077723774541 44.97789792588031,6.725159755024541 45.164110654364634,7.142640223774541 45.2724545718037,7.208558192524541 45.45770672352913,6.835023036274541 45.74978203327899,7.054749598774541 45.94874696966964,6.791077723774541 46.37487002615409,6.285706630024541 46.40518111104491,6.175843348774541 46.20785813977869,6.044007411274541 46.480885182821844,6.527405848774541 46.9178949511633,7.054749598774541 47.30669106481971,6.835023036274541 47.366253803971325,7.076722255024541 47.529704967777825,7.252503505024541 47.45547195118154,7.604066005024541 47.48517774971194,7.538148036274541 47.67785626638349,7.604066005024541 48.090448939567736,7.845765223774541 48.58704000495766,8.24127303627454 48.97794887560541))"^^ . + + +# Strasbourg (point) + +## Feature + . + "Strasbourg" . + . + +## Geometry + . + "POINT(7.7510315861075085 48.581903974563204)"^^ . + + +# Bern (point) + +## Feature + . + "Bern" . + . + +## Geometry + . + "POINT(7.448102905878211 46.945410623891554)"^^ . \ No newline at end of file diff --git a/infra/qlever/docker-compose.yaml b/infra/qlever/docker-compose.yaml index 8d590a4..a75af82 100644 --- a/infra/qlever/docker-compose.yaml +++ b/infra/qlever/docker-compose.yaml @@ -1,38 +1,28 @@ services: - qlever: + # One-shot init container to fix permissions on the data volume + qlever-init: + image: busybox:latest + container_name: qlever-init + command: ["sh", "-c", "chown -R 65534:0 /data"] + volumes: + - ./qlever-data:/data + restart: "no" + + qlever-server: build: context: . - dockerfile: Dockerfile - container_name: qlever - environment: - - UID=${QLEVER_UID:-1234} - - GID=${QLEVER_GID:-1234} + dockerfile: ./Dockerfile + image: local/qlever-server:latest + container_name: qlever-server + user: "65534:0" # run as 'nobody' (uid 65534), group root + depends_on: + - qlever-init # make sure perms are fixed first + env_file: + - ./qlever.env # QLever + indexing config (see below) volumes: - - qlever-data:/data - working_dir: /data + - ./qlever-data:/data # QLever index + Qleverfile live here + - ./data/data.nt:/data/data.nt:ro # your RDF data file ports: - - "7001:7001" - command: - - -c - - | - sudo groupadd sharedgroup || true # avoid error if it already exists - sudo usermod -aG sharedgroup qlever # add qlever user to sharedgroup - sudo usermod -aG sharedgroup $(whoami) # add your current user by name - sudo chown -R qlever:sharedgroup /data - sudo chmod -R 770 /data - if [ ! -f /data/Qleverfile ]; then - qlever setup-config olympics && - qlever get-data && - qlever index - fi && - echo "Starting QLever server..." - qlever start --name olympics --description "Olympics Dataset" + - "7001:7001" # SPARQL endpoint + stop_grace_period: 0s restart: unless-stopped - - deploy: - resources: - limits: - memory: 8g - -volumes: - qlever-data: diff --git a/infra/qlever/qlever.env b/infra/qlever/qlever.env new file mode 100644 index 0000000..d195ef5 --- /dev/null +++ b/infra/qlever/qlever.env @@ -0,0 +1,34 @@ +# Force a fresh Qleverfile at least once +QLEVER_GENERATE_CONFIG_FILE=true + +# [data] +QLEVER_DATA_NAME=local +QLEVER_DATA_DESCRIPTION=Local NT dataset for QLever + +# [index] +QLEVER_INDEX_INPUT_FILES=data.nt +QLEVER_INDEX_CAT_INPUT_FILES=cat data.nt +# QLEVER_INDEX_SETTINGS_JSON={ "ascii-prefixes-only": false, "num-triples-per-batch": 100000 } + +# [server] +QLEVER_SERVER_PORT=7001 +QLEVER_SERVER_MEMORY_FOR_QUERIES=8G +QLEVER_SERVER_CACHE_MAX_SIZE=4G +QLEVER_SERVER_TIMEOUT=300s + +# [runtime] +QLEVER_RUNTIME_SYSTEM=native + +# [ui] +QLEVER_UI_UI_CONFIG=default +QLEVER_UI_UI_PORT=7002 + +# Entrypoint behavior +SHOULD_DOWNLOAD=false +FORCE_DOWNLOAD=false + +SHOULD_INDEX=true +FORCE_INDEXING=false + +STOP_ON_CALL_ENABLED=false +START_ADDITIONAL_ARGS= diff --git a/infra/qlever/scripts/entrypoint.sh b/infra/qlever/scripts/entrypoint.sh new file mode 100644 index 0000000..da33689 --- /dev/null +++ b/infra/qlever/scripts/entrypoint.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +set -euo pipefail + +# Tweak indexing +SHOULD_INDEX="${SHOULD_INDEX:-false}" +FORCE_INDEXING="${FORCE_INDEXING:-false}" + +# Tweak data download +SHOULD_DOWNLOAD="${SHOULD_DOWNLOAD:-true}" +FORCE_DOWNLOAD="${FORCE_DOWNLOAD:-false}" + +# Additional parameters to qlever start (e.g. --kill-existing-with-same-port) +START_ADDITIONAL_ARGS="${START_ADDITIONAL_ARGS:-}" + +# Display some debug information +echo "INFO: Indexing : should index = ${SHOULD_INDEX} ; force indexing = ${FORCE_INDEXING}" +echo "INFO: Data download : should download = ${SHOULD_DOWNLOAD} ; force download = ${FORCE_DOWNLOAD}" + +# Generate Qleverfile (or skip, depending on QLEVER_GENERATE_CONFIG_FILE) + /qlever/scripts/generate-qleverfile.sh + +# Go to the data directory +cd /data + +QLEVER_FILE_PATH="${QLEVER_FILE_PATH:-/data/Qleverfile}" + +# Check if the Qleverfile exists +if [ ! -f "${QLEVER_FILE_PATH}" ]; then + echo "ERROR: Qleverfile not found at '${QLEVER_FILE_PATH}'" + exit 1 +fi + +# Display the Qleverfile for debugging +echo "INFO: Qleverfile found at '${QLEVER_FILE_PATH}'" +cat "${QLEVER_FILE_PATH}" + +# Extract INPUT_FILES from the Qleverfile (if any) +INPUT_FILES=$(grep "^INPUT_FILES[[:space:]]*=" "${QLEVER_FILE_PATH}" | head -n1 | sed 's/.*=[[:space:]]*//') +HAS_INPUT_FILES=$(echo "${INPUT_FILES}" | sed '/^[[:space:]]*$/d' | wc -l) + +if [ "${HAS_INPUT_FILES}" -ne 0 ]; then + echo "INFO: Found 'INPUT_FILES' in the Qleverfile" + + # Check if the input files already exist + HAS_MISSING_INPUT_FILES="false" + for INPUT_FILE in ${INPUT_FILES}; do + if [ -f "${INPUT_FILE}" ]; then + echo "INFO: Input file found at '${INPUT_FILE}'" + else + echo "INFO: Input file not found at '${INPUT_FILE}'" + HAS_MISSING_INPUT_FILES="true" + fi + done + + # If all files are present, skip the download + if [ "${HAS_MISSING_INPUT_FILES}" = "false" ]; then + SHOULD_DOWNLOAD="false" # As the input files are already present, no need to download them + fi + + # Display the info in the logs only if the download is enabled + if [ "${SHOULD_DOWNLOAD}" = "true" ]; then + echo "INFO: Trigger download of input files…" + fi +fi + +# If the download of the input files is forced, then download them in all cases +if [ "${FORCE_DOWNLOAD}" = "true" ]; then + echo "INFO: Forcing download of input files…" + SHOULD_DOWNLOAD="true" +fi + +# Check if there is a line that starts with `GET_DATA_CMD` in the Qleverfile +if grep -q "^GET_DATA_CMD" "${QLEVER_FILE_PATH}"; then + echo "INFO: Found 'GET_DATA_CMD' in the Qleverfile" + if [ "${SHOULD_DOWNLOAD}" = "true" ]; then + echo "INFO: Trigger download of data…" + qlever get-data + SHOULD_INDEX="true" # As the data is downloaded, we should index it + else + echo "INFO: Skipping download of data…" + fi +fi + +# Indexing logic +if [ "${SHOULD_INDEX}" = "true" ]; then + echo "INFO: Indexing is enabled" + qlever index --overwrite-existing +elif [ "${FORCE_INDEXING}" = "true" ]; then + echo "INFO: Forcing indexing" + qlever index --overwrite-existing +else + echo "INFO: Indexing is disabled" +fi + +# Start the QLever server +echo "INFO: Starting QLever server..." +if [ "${STOP_ON_CALL_ENABLED}" = "true" ]; then + + # Start QLever in the background + qlever start --run-in-foreground $START_ADDITIONAL_ARGS & + QLEVER_PID=$! + + # Start stop_on_call in the background + stop_on_call & + STOP_ON_CALL_PID=$! + + # Wait for either QLever or stop_on_call to exit + wait -n $QLEVER_PID $STOP_ON_CALL_PID + EXITED_PID=$? + + # Check which one exited + if ! kill -0 $QLEVER_PID 2>/dev/null; then + # QLever exited + wait $QLEVER_PID + QLEVER_EXIT_CODE=$? + echo "qlever exited with code $QLEVER_EXIT_CODE" + kill $STOP_ON_CALL_PID 2>/dev/null + exit $QLEVER_EXIT_CODE + else + # stop_on_call was called, so we stop QLever + echo "" + echo "" + echo "" + echo "[INFO] Stopped using stop_on_call" + qlever stop + + # Stop QLever manually, in case it is still running (it should not be, but just in case) + kill $QLEVER_PID 2>/dev/null || true + wait $QLEVER_PID || true + exit 0 + fi + +else + # Normal case: keep QLever in the foreground, container stays alive + exec qlever start --run-in-foreground $START_ADDITIONAL_ARGS +fi diff --git a/infra/qlever/scripts/generate-qleverfile.sh b/infra/qlever/scripts/generate-qleverfile.sh new file mode 100644 index 0000000..35b7dcc --- /dev/null +++ b/infra/qlever/scripts/generate-qleverfile.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +set -eu + +################################################################################## +# This script generates a Qleverfile that can be used to start a QLever instance # +################################################################################## + +QLEVER_FILE_PATH="${QLEVER_FILE_PATH:-/data/Qleverfile}" + +# Have a way to opt-out of generating the Qleverfile +QLEVER_GENERATE_CONFIG_FILE="${QLEVER_GENERATE_CONFIG_FILE:-true}" +if [ "${QLEVER_GENERATE_CONFIG_FILE}" = "auto" ]; then + # Check if the Qleverfile already exists + if [ -f "${QLEVER_FILE_PATH}" ]; then + echo "INFO: Skipping Qleverfile generation, as 'QLEVER_GENERATE_CONFIG_FILE' is set to 'auto' and the file already exists at '${QLEVER_FILE_PATH}'" + exit 0 + else + echo "INFO: Generating Qleverfile, as 'QLEVER_GENERATE_CONFIG_FILE' is set to 'auto' and the file does not exist at '${QLEVER_FILE_PATH}'" + QLEVER_GENERATE_CONFIG_FILE="true" + fi +fi + +if [ "${QLEVER_GENERATE_CONFIG_FILE}" != "true" ]; then + echo "INFO: Skipping Qleverfile generation, as 'QLEVER_GENERATE_CONFIG_FILE' is not set to 'true'" + exit 0 +fi + +dirname "${QLEVER_FILE_PATH}" | xargs mkdir -p + +# Set default values for some configuration fields (could be overridden by other environment variables) +export QLEVER_DATA_NAME="${QLEVER_DATA_NAME:-default}" +export QLEVER_DATA_DESCRIPTION="${QLEVER_DATA_DESCRIPTION:-Default dataset}" + +export QLEVER_INDEX_SETTINGS_JSON="${QLEVER_INDEX_SETTINGS_JSON:-{ \"ascii-prefixes-only\": false, \"num-triples-per-batch\": 100000 }}" + +export QLEVER_SERVER_ACCESS_TOKEN="${QLEVER_SERVER_ACCESS_TOKEN:-${QLEVER_DATA_NAME}_7643543846_Zs6nw7yi3Z9m}" +export QLEVER_SERVER_HOST_NAME="${QLEVER_SERVER_HOST_NAME:-127.0.0.1}" +export QLEVER_SERVER_PORT="${QLEVER_SERVER_PORT:-7001}" +export QLEVER_SERVER_MEMORY_FOR_QUERIES="${QLEVER_SERVER_MEMORY_FOR_QUERIES:-5G}" +export QLEVER_SERVER_CACHE_MAX_SIZE="${QLEVER_SERVER_CACHE_MAX_SIZE:-2G}" +export QLEVER_SERVER_TIMEOUT="${QLEVER_SERVER_TIMEOUT:-30s}" + +export QLEVER_RUNTIME_SYSTEM="${QLEVER_RUNTIME_SYSTEM:-native}" + +export QLEVER_UI_UI_CONFIG="${QLEVER_UI_UI_CONFIG:-default}" +export QLEVER_UI_UI_PORT="${QLEVER_UI_UI_PORT:-7002}" + +# Extract all environment variables that start with 'QLEVER_', as we ignore all other variables +QLEVER_ENV_VARS="$(env | grep '^QLEVER_' | sort -u)" + +# Generate a specific section for the Qleverfile +generate_config_section () { + local section="$1" + local section_upper="$(echo "${section}" | tr '[:lower:]' '[:upper:]')" + + # Extract all environment variables for the given section + local section_env_vars="$(echo "${QLEVER_ENV_VARS}" | grep "^QLEVER_${section_upper}_" | sed "s/^QLEVER_${section_UPPER}_//")" +} + +# Generate a specific section for the Qleverfile (corrected, POSIX-safe) +generate_config_section () { + section="$1" + section_upper="$(echo "${section}" | tr '[:lower:]' '[:upper:]')" + + # Extract all environment variables for the given section + section_env_vars="$(echo "${QLEVER_ENV_VARS}" | grep "^QLEVER_${section_upper}_" | sed "s/^QLEVER_${section_upper}_//")" + + # Skip empty sections + if [ -z "${section_env_vars}" ]; then + return + fi + + echo "[$section]" + echo "${section_env_vars}" + echo "" +} + +# Generate the Qleverfile, with the different sections +{ + echo "# Qleverfile auto-generated using environment variables at $(date), while starting the container" + echo "" + + generate_config_section "data" + generate_config_section "index" + generate_config_section "server" + generate_config_section "runtime" + generate_config_section "ui" +} > "${QLEVER_FILE_PATH}" || exit 1 + +echo "INFO: Generated Qleverfile at '${QLEVER_FILE_PATH}'" + +exit 0 -- 2.51.2