Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1a4373e
Added commands to setup Oxigraph
tanmay-9 Apr 17, 2025
956a59d
Fix host_name bug in example_querie and add util stop_with_regex comm…
tanmay-9 May 19, 2025
b1310ad
Update branch code and have only qoxigraph latest code
tanmay-9 Mar 27, 2026
36aebef
Merge remote-tracking branch 'origin/main' into add-qoxigraph-commands
tanmay-9 Apr 1, 2026
833e06f
Removed extract_queries.py
tanmay-9 Apr 1, 2026
8ae4b7e
Merge branch 'qlever-dev:main' into add-qoxigraph-commands
tanmay-9 Apr 7, 2026
274fff9
Add memory monitor to qoxigraph along with separate time log for load…
tanmay-9 Apr 8, 2026
d59abe6
Merge branch 'qlever-dev:main' into add-qoxigraph-commands
tanmay-9 Apr 8, 2026
17e66ca
Take new memory monitor changes
tanmay-9 Apr 8, 2026
bb59bc9
Remove redundant example_queries and change symlinked get-data to a s…
tanmay-9 Apr 8, 2026
977e47b
Use index and server resource monitoring args provided by qlever-inde…
tanmay-9 Jul 7, 2026
4510cfa
Merge remote-tracking branch 'origin/main' into remove-resource-monit…
tanmay-9 Jul 9, 2026
b0dd86c
Enforce resource monitor interval and plot max_points to be a positiv…
tanmay-9 Jul 13, 2026
6bb76f3
Merge remote-tracking branch 'origin/main' into add-qoxigraph-commands
tanmay-9 Jul 13, 2026
f8eebc9
Remove old memory_monitor
tanmay-9 Jul 13, 2026
fceaca4
Merge remote-tracking branch 'origin/remove-resource-monitoring' into…
tanmay-9 Jul 13, 2026
b443f5e
Add resource monitoring to qoxigraph and refactor usage_plot to be us…
tanmay-9 Jul 13, 2026
949e463
Add qoxigraph native & container imdb workflow
tanmay-9 Jul 13, 2026
656bcfc
Fix --system in qoxigraph github workflow
tanmay-9 Jul 13, 2026
4045674
Merge remote-tracking branch 'origin/main' into remove-resource-monit…
tanmay-9 Jul 15, 2026
3f76379
Add some tests and minor fixes
tanmay-9 Jul 15, 2026
69a198f
Merge remote-tracking branch 'origin/remove-resource-monitoring' into…
tanmay-9 Jul 15, 2026
82bc15a
Fix failing test and remove duplication between usage_plot and index_…
tanmay-9 Jul 15, 2026
94fa500
Add cross-platform python-specific way to add/modify/remove ini value…
tanmay-9 Jul 19, 2026
79808bf
Merge remote-tracking branch 'origin/main' into add-qoxigraph-commands
tanmay-9 Jul 19, 2026
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
71 changes: 71 additions & 0 deletions .github/workflows/end-to-end-test-qoxigraph.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: End-to-end test for qoxigraph

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
merge_group:

permissions:
contents: read

jobs:
qoxigraph-end-to-end-test:
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
system: [native, docker, podman]

steps:
- name: Checkout the repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install qoxigraph (qlever-control) with the plot extra
run: |
python -m pip install --upgrade pip
pip install -e ".[plot]"

- name: Install the latest oxigraph release binary on PATH
if: matrix.system == 'native'
run: |
url=$(curl -sL https://api.github.com/repos/oxigraph/oxigraph/releases/latest \
| grep -oE 'https://[^"]+x86_64_linux_gnu' | head -1)
echo "Downloading oxigraph binary from $url"
curl -sL "$url" -o oxigraph
chmod +x oxigraph
sudo mv oxigraph /usr/local/bin/oxigraph
oxigraph --version

- name: Make sure the container runtime is available and pull the image
if: matrix.system != 'native'
run: |
command -v ${{matrix.system}} || (sudo apt-get update && sudo apt-get install -y ${{matrix.system}})
${{matrix.system}} --version
${{matrix.system}} pull ghcr.io/oxigraph/oxigraph

- name: End-to-end test on the imdb dataset (${{matrix.system}})
run: |
export QLEVER_ARGCOMPLETE_ENABLED=1
mkdir -p qoxigraph-e2e && cd qoxigraph-e2e
qoxigraph setup-config imdb --system ${{matrix.system}}
qoxigraph get-data
qoxigraph index

echo "Checking that the resource-usage log and plot were produced"
test -s imdb.index.resource-usage-log.tsv
test -f imdb.resource-usage-plot.png

qoxigraph index-stats
qoxigraph start
qoxigraph status
qoxigraph query "SELECT * WHERE { ?s ?p ?o } LIMIT 1"
qoxigraph stop
ls -lh
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ bugtracker = "https://github.com/ad-freiburg/qlever/issues"

[project.scripts]
"qlever" = "qlever.qlever_main:main"
"qoxigraph" = "qlever.qlever_main:main"

[tool.setuptools]
package-data = { "qlever" = ["Qleverfiles/*", "evaluation/www/*", "monitor_queries/*.tcss"] }
Expand Down
35 changes: 7 additions & 28 deletions src/qlever/commands/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,15 @@
)


def render_usage_plot(
dataset: str,
stxxl_memory: str,
settings_json: str,
plot_max_points: int,
plot_only: bool,
) -> Path | None:
def render_usage_plot(args, plot_only: bool) -> Path | None:
"""Render the resource-usage plot.

When the plotting libraries are missing, this is an error if the
user asked for the plot directly via `plot_only`, otherwise it notes
how to get the plot at info level since the index build succeeded.
"""
try:
from qlever.resource_usage import usage_plot
from qlever.resource_usage.usage_plot import UsagePlot
except ImportError:
if plot_only:
log.error(
Expand All @@ -46,12 +40,9 @@ def render_usage_plot(
"`qlever index --resource-usage-plot-only`."
)
return None
return usage_plot.render_usage_plot(
dataset,
stxxl_memory=stxxl_memory,
settings_json=settings_json,
plot_max_points=plot_max_points,
)
return UsagePlot(
args.name, args, plot_max_points=args.resource_usage_plot_max_points
).render()


class IndexCommand(QleverCommand):
Expand Down Expand Up @@ -233,13 +224,7 @@ def execute(self, args) -> bool:
# Render the resource-usage plot from the existing log without
# rebuilding the index.
if args.resource_usage_plot_only:
plot_path = render_usage_plot(
args.name,
stxxl_memory=args.stxxl_memory or "",
settings_json=args.settings_json,
plot_max_points=args.resource_usage_plot_max_points,
plot_only=True,
)
plot_path = render_usage_plot(args, plot_only=True)
if plot_path is None:
return False
log.info(f"Resource-usage plot saved to `{plot_path.name}`")
Expand Down Expand Up @@ -407,13 +392,7 @@ def execute(self, args) -> bool:
Path(f"{args.name}.index.resource-usage-log.tsv").exists()
or Path(f"{args.name}.resource-usage-log.tsv").exists()
):
plot_path = render_usage_plot(
args.name,
stxxl_memory=args.stxxl_memory or "",
settings_json=args.settings_json,
plot_max_points=args.resource_usage_plot_max_points,
plot_only=False,
)
plot_path = render_usage_plot(args, plot_only=False)
if plot_path is not None:
log.info(f"Resource-usage plot saved to `{plot_path.name}`")

Expand Down
49 changes: 32 additions & 17 deletions src/qlever/commands/setup_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import subprocess
from os import environ
from pathlib import Path

Expand Down Expand Up @@ -49,6 +48,10 @@ def additional_arguments(self, subparser) -> None:
choices=self.qleverfile_names,
help="The name of the pre-configured Qleverfile to create",
)
# Override defaults to None so that arguments explicitly passed
# by the user can be told apart from plain defaults.
for section, arg_name in self.override_args:
subparser.set_defaults(**{arg_name: None})

def check_qleverfile_exists(self) -> bool:
"""Return True if a Qleverfile already exists (and log an error)."""
Expand All @@ -75,37 +78,49 @@ def execute(self, args) -> bool:
"(since inside the container, QLever should run natively)"
)
log.info("")
# Construct the command line and show it.
# Build the updates for the copied Qleverfile.
qleverfile_path = (
self.qleverfiles_path / f"Qleverfile.{args.config_name}"
)
setup_config_cmd = f"cat {qleverfile_path} | {util.get_ini_sed_cmd('server', 'ACCESS_TOKEN', util.get_random_string(12), True)}"
updates = {
"server": {
"ACCESS_TOKEN": (util.get_random_string(12), True),
},
}
if qlever_is_running_in_container:
setup_config_cmd += (
f" | {util.get_ini_sed_cmd('runtime', 'SYSTEM', 'native')}"
)
updates.setdefault("runtime", {})["SYSTEM"] = ("native", False)
else:
for section, arg_name in self.override_args:
if arg_value := getattr(args, arg_name, None):
setup_config_cmd += f" | {util.get_ini_sed_cmd(section, arg_name.upper(), arg_value)}"
updates.setdefault(section, {})[arg_name.upper()] = (
str(arg_value),
False,
)

setup_config_cmd += "> Qleverfile"
self.show(setup_config_cmd, only_show=args.show)
# Show the changes that will be applied to the copied template.
show_lines = [
f"Copy {qleverfile_path} to Qleverfile with the following changes:"
]
for section, option_dict in updates.items():
show_lines.append(f"\n[{section}]")
for option, (value, is_suffix) in option_dict.items():
shown_value = (
"*" * len(value) if option == "ACCESS_TOKEN" else value
)
show_lines.append(f"{option} = {shown_value}")
self.show("\n".join(show_lines), only_show=args.show)
if args.show:
return True

if self.check_qleverfile_exists():
return False

# Copy the Qleverfile to the current directory.
# Copy the Qleverfile to the current directory, with the updates
# applied.
try:
subprocess.run(
setup_config_cmd,
shell=True,
check=True,
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
)
lines = qleverfile_path.read_text().splitlines()
result = util.update_ini_values(lines, updates)
Path("Qleverfile").write_text("\n".join(result) + "\n")
except Exception as e:
log.error(
f'Could not copy "{qleverfile_path}" to current directory: {e}'
Expand Down
Loading
Loading