qlever 0.5.7__py3-none-any.whl → 0.5.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of qlever might be problematic. Click here for more details.
- qlever/Qleverfiles/Qleverfile.dblp +14 -10
- qlever/Qleverfiles/Qleverfile.dblp-plus +2 -2
- qlever/Qleverfiles/Qleverfile.default +1 -1
- qlever/Qleverfiles/Qleverfile.fbeasy +4 -4
- qlever/Qleverfiles/Qleverfile.freebase +2 -2
- qlever/Qleverfiles/Qleverfile.imdb +1 -1
- qlever/Qleverfiles/Qleverfile.orkg +30 -0
- qlever/Qleverfiles/Qleverfile.osm-planet +1 -1
- qlever/Qleverfiles/Qleverfile.vvz +3 -3
- qlever/Qleverfiles/Qleverfile.wikidata +29 -17
- qlever/Qleverfiles/Qleverfile.yago-4 +4 -4
- qlever/commands/example_queries.py +250 -150
- qlever/commands/index.py +96 -8
- qlever/commands/setup_config.py +47 -31
- qlever/commands/system_info.py +126 -0
- qlever/commands/ui.py +50 -23
- qlever/containerize.py +67 -33
- qlever/qleverfile.py +10 -3
- qlever/util.py +55 -30
- {qlever-0.5.7.dist-info → qlever-0.5.9.dist-info}/METADATA +1 -1
- {qlever-0.5.7.dist-info → qlever-0.5.9.dist-info}/RECORD +25 -25
- {qlever-0.5.7.dist-info → qlever-0.5.9.dist-info}/WHEEL +1 -1
- qlever/Qleverfiles/Qleverfile.wikimedia-commons +0 -37
- qlever/__main__.py +0 -1476
- {qlever-0.5.7.dist-info → qlever-0.5.9.dist-info}/LICENSE +0 -0
- {qlever-0.5.7.dist-info → qlever-0.5.9.dist-info}/entry_points.txt +0 -0
- {qlever-0.5.7.dist-info → qlever-0.5.9.dist-info}/top_level.txt +0 -0
qlever/commands/setup_config.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import subprocess
|
|
4
|
+
from os import environ
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
from qlever.command import QleverCommand
|
|
@@ -15,9 +16,9 @@ class SetupConfigCommand(QleverCommand):
|
|
|
15
16
|
|
|
16
17
|
def __init__(self):
|
|
17
18
|
self.qleverfiles_path = Path(__file__).parent.parent / "Qleverfiles"
|
|
18
|
-
self.qleverfile_names =
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
self.qleverfile_names = [
|
|
20
|
+
p.name.split(".")[1] for p in self.qleverfiles_path.glob("Qleverfile.*")
|
|
21
|
+
]
|
|
21
22
|
|
|
22
23
|
def description(self) -> str:
|
|
23
24
|
return "Get a pre-configured Qleverfile"
|
|
@@ -25,23 +26,38 @@ class SetupConfigCommand(QleverCommand):
|
|
|
25
26
|
def should_have_qleverfile(self) -> bool:
|
|
26
27
|
return False
|
|
27
28
|
|
|
28
|
-
def relevant_qleverfile_arguments(self) -> dict[str: list[str]]:
|
|
29
|
+
def relevant_qleverfile_arguments(self) -> dict[str : list[str]]:
|
|
29
30
|
return {}
|
|
30
31
|
|
|
31
32
|
def additional_arguments(self, subparser) -> None:
|
|
32
33
|
subparser.add_argument(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
"config_name",
|
|
35
|
+
type=str,
|
|
36
|
+
choices=self.qleverfile_names,
|
|
37
|
+
help="The name of the pre-configured Qleverfile to create",
|
|
38
|
+
)
|
|
36
39
|
|
|
37
40
|
def execute(self, args) -> bool:
|
|
41
|
+
# Show a warning if `QLEVER_OVERRIDE_SYSTEM_NATIVE` is set.
|
|
42
|
+
qlever_is_running_in_container = environ.get("QLEVER_IS_RUNNING_IN_CONTAINER")
|
|
43
|
+
if qlever_is_running_in_container:
|
|
44
|
+
log.warning(
|
|
45
|
+
"The environment variable `QLEVER_IS_RUNNING_IN_CONTAINER` is set, "
|
|
46
|
+
"therefore the Qleverfile is modified to use `SYSTEM = native` "
|
|
47
|
+
"(since inside the container, QLever should run natively)"
|
|
48
|
+
)
|
|
49
|
+
log.info("")
|
|
38
50
|
# Construct the command line and show it.
|
|
39
|
-
qleverfile_path =
|
|
40
|
-
/ f"Qleverfile.{args.config_name}")
|
|
51
|
+
qleverfile_path = self.qleverfiles_path / f"Qleverfile.{args.config_name}"
|
|
41
52
|
setup_config_cmd = (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
f"cat {qleverfile_path}"
|
|
54
|
+
f" | sed -E 's/(^ACCESS_TOKEN.*)/\\1_{get_random_string(12)}/'"
|
|
55
|
+
)
|
|
56
|
+
if qlever_is_running_in_container:
|
|
57
|
+
setup_config_cmd += (
|
|
58
|
+
" | sed -E 's/(^SYSTEM[[:space:]]*=[[:space:]]*).*/\\1native/'"
|
|
59
|
+
)
|
|
60
|
+
setup_config_cmd += "> Qleverfile"
|
|
45
61
|
self.show(setup_config_cmd, only_show=args.show)
|
|
46
62
|
if args.show:
|
|
47
63
|
return False
|
|
@@ -51,31 +67,31 @@ class SetupConfigCommand(QleverCommand):
|
|
|
51
67
|
if qleverfile_path.exists():
|
|
52
68
|
log.error("`Qleverfile` already exists in current directory")
|
|
53
69
|
log.info("")
|
|
54
|
-
log.info(
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
log.info(
|
|
71
|
+
"If you want to create a new Qleverfile using "
|
|
72
|
+
"`qlever setup-config`, delete the existing Qleverfile "
|
|
73
|
+
"first"
|
|
74
|
+
)
|
|
57
75
|
return False
|
|
58
76
|
|
|
59
77
|
# Copy the Qleverfile to the current directory.
|
|
60
78
|
try:
|
|
61
|
-
subprocess.run(
|
|
62
|
-
|
|
79
|
+
subprocess.run(
|
|
80
|
+
setup_config_cmd,
|
|
81
|
+
shell=True,
|
|
82
|
+
check=True,
|
|
83
|
+
stdin=subprocess.DEVNULL,
|
|
84
|
+
stdout=subprocess.DEVNULL,
|
|
85
|
+
)
|
|
63
86
|
except Exception as e:
|
|
64
|
-
log.error(
|
|
65
|
-
|
|
87
|
+
log.error(
|
|
88
|
+
f'Could not copy "{qleverfile_path}"' f" to current directory: {e}"
|
|
89
|
+
)
|
|
66
90
|
return False
|
|
67
91
|
|
|
68
92
|
# If we get here, everything went well.
|
|
69
|
-
log.info(
|
|
70
|
-
|
|
93
|
+
log.info(
|
|
94
|
+
f'Created Qleverfile for config "{args.config_name}"'
|
|
95
|
+
f" in current directory"
|
|
96
|
+
)
|
|
71
97
|
return True
|
|
72
|
-
|
|
73
|
-
# if config_name == "default":
|
|
74
|
-
# log.info("Since this is the default Qleverfile, you need to "
|
|
75
|
-
# "edit it before you can continue")
|
|
76
|
-
# log.info("")
|
|
77
|
-
# log.info("Afterwards, run `qlever` without arguments to see "
|
|
78
|
-
# "which actions are available")
|
|
79
|
-
# else:
|
|
80
|
-
# show_available_action_names()
|
|
81
|
-
# log.info("")
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import platform
|
|
4
|
+
from importlib.metadata import version
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import psutil
|
|
8
|
+
|
|
9
|
+
from qlever.command import QleverCommand
|
|
10
|
+
from qlever.containerize import Containerize
|
|
11
|
+
from qlever.log import log
|
|
12
|
+
from qlever.util import format_size, run_command
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def show_heading(text: str) -> str:
|
|
16
|
+
log.info(text)
|
|
17
|
+
log.info("-" * len(text))
|
|
18
|
+
log.info("")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_partition(dir: Path):
|
|
22
|
+
"""
|
|
23
|
+
Returns the partition on which `dir` resides. May return None.
|
|
24
|
+
"""
|
|
25
|
+
# The first partition that whose mountpoint is a parent of `dir` is
|
|
26
|
+
# returned. Sort the partitions by the length of the mountpoint to ensure
|
|
27
|
+
# that the result is correct. Assume there are partitions with mountpoint
|
|
28
|
+
# `/` and `/home`. This ensures that `/home/foo` is detected as being in
|
|
29
|
+
# the partition with mountpoint `/home`.
|
|
30
|
+
partitions = sorted(
|
|
31
|
+
psutil.disk_partitions(),
|
|
32
|
+
key=lambda part: len(part.mountpoint),
|
|
33
|
+
reverse=True,
|
|
34
|
+
)
|
|
35
|
+
for partition in partitions:
|
|
36
|
+
if dir.is_relative_to(partition.mountpoint):
|
|
37
|
+
return partition
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SystemInfoCommand(QleverCommand):
|
|
42
|
+
def __init__(self):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
def description(self) -> str:
|
|
46
|
+
return "Gather some system info to help with troubleshooting"
|
|
47
|
+
|
|
48
|
+
def should_have_qleverfile(self) -> bool:
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
def relevant_qleverfile_arguments(self) -> dict[str : list[str]]:
|
|
52
|
+
return {"runtime": ["system", "image", "server_container"]}
|
|
53
|
+
|
|
54
|
+
def additional_arguments(self, subparser) -> None:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
def execute(self, args) -> bool:
|
|
58
|
+
# Say what the command is doing.
|
|
59
|
+
self.show("Show system information and Qleverfile", only_show=args.show)
|
|
60
|
+
if args.show:
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
# Show system information.
|
|
64
|
+
show_heading("System Information")
|
|
65
|
+
system = platform.system()
|
|
66
|
+
is_linux = system == "Linux"
|
|
67
|
+
is_mac = system == "Darwin"
|
|
68
|
+
is_windows = system == "Windows"
|
|
69
|
+
if is_windows:
|
|
70
|
+
log.warn("Only limited information is gathered on Windows.")
|
|
71
|
+
log.info(f"Version: {version('qlever')} (qlever --version)")
|
|
72
|
+
if is_linux:
|
|
73
|
+
info = platform.freedesktop_os_release()
|
|
74
|
+
log.info(f"OS: {platform.system()} ({info['PRETTY_NAME']})")
|
|
75
|
+
else:
|
|
76
|
+
log.info(f"OS: {platform.system()}")
|
|
77
|
+
log.info(f"Arch: {platform.machine()}")
|
|
78
|
+
log.info(f"Host: {platform.node()}")
|
|
79
|
+
psutil.virtual_memory().total / (1000**3)
|
|
80
|
+
memory_total = psutil.virtual_memory().total / (1024.0**3)
|
|
81
|
+
memory_available = psutil.virtual_memory().available / (1024.0**3)
|
|
82
|
+
log.info(
|
|
83
|
+
f"RAM: {memory_total:.1f} GB total, " f"{memory_available:.1f} GB available"
|
|
84
|
+
)
|
|
85
|
+
num_cores = psutil.cpu_count(logical=False)
|
|
86
|
+
num_threads = psutil.cpu_count(logical=True)
|
|
87
|
+
cpu_freq = psutil.cpu_freq().max / 1000
|
|
88
|
+
log.info(
|
|
89
|
+
f"CPU: {num_cores} Cores, " f"{num_threads} Threads @ {cpu_freq:.2f} GHz"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
cwd = Path.cwd()
|
|
93
|
+
log.info(f"CWD: {cwd}")
|
|
94
|
+
# Free and total size of the partition on which the current working
|
|
95
|
+
# directory resides.
|
|
96
|
+
disk_usage = psutil.disk_usage(str(cwd))
|
|
97
|
+
partition = get_partition(cwd)
|
|
98
|
+
partition_description = f"{partition.device} @ {partition.mountpoint}"
|
|
99
|
+
fs_type = partition.fstype
|
|
100
|
+
fs_free = format_size(disk_usage.free)
|
|
101
|
+
fs_total = format_size(disk_usage.total)
|
|
102
|
+
log.info(
|
|
103
|
+
f"Disk space in {partition_description} is "
|
|
104
|
+
f"({fs_type}): {fs_free} free / {fs_total} total"
|
|
105
|
+
)
|
|
106
|
+
# User/Group on host and in container
|
|
107
|
+
if is_linux or is_mac:
|
|
108
|
+
user_info = run_command("id", return_output=True).strip()
|
|
109
|
+
log.info(f"User and group on host: {user_info}")
|
|
110
|
+
elif is_windows:
|
|
111
|
+
user_info = run_command("whoami /all", return_output=True).strip()
|
|
112
|
+
log.info(f"User and group on host: {user_info}")
|
|
113
|
+
if args.system in Containerize.supported_systems():
|
|
114
|
+
user_info = Containerize.run_in_container("id", args).strip()
|
|
115
|
+
log.info(f"User and group in container: {user_info}")
|
|
116
|
+
|
|
117
|
+
# Show Qleverfile.
|
|
118
|
+
log.info("")
|
|
119
|
+
show_heading("Contents of Qleverfile")
|
|
120
|
+
qleverfile = cwd / "Qleverfile"
|
|
121
|
+
if qleverfile.exists():
|
|
122
|
+
# TODO: output the effective qlever file using primites from #57
|
|
123
|
+
log.info(qleverfile.read_text())
|
|
124
|
+
else:
|
|
125
|
+
log.info("No Qleverfile found")
|
|
126
|
+
return True
|
qlever/commands/ui.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import subprocess
|
|
4
|
+
from os import environ
|
|
4
5
|
|
|
5
6
|
from qlever.command import QleverCommand
|
|
6
7
|
from qlever.containerize import Containerize
|
|
@@ -17,46 +18,70 @@ class UiCommand(QleverCommand):
|
|
|
17
18
|
pass
|
|
18
19
|
|
|
19
20
|
def description(self) -> str:
|
|
20
|
-
return
|
|
21
|
+
return "Launch the QLever UI web application"
|
|
21
22
|
|
|
22
23
|
def should_have_qleverfile(self) -> bool:
|
|
23
24
|
return True
|
|
24
25
|
|
|
25
|
-
def relevant_qleverfile_arguments(self) -> dict[str: list[str]]:
|
|
26
|
-
return {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
def relevant_qleverfile_arguments(self) -> dict[str : list[str]]:
|
|
27
|
+
return {
|
|
28
|
+
"data": ["name"],
|
|
29
|
+
"server": ["host_name", "port"],
|
|
30
|
+
"ui": ["ui_port", "ui_config", "ui_system", "ui_image", "ui_container"],
|
|
31
|
+
}
|
|
30
32
|
|
|
31
33
|
def additional_arguments(self, subparser) -> None:
|
|
32
34
|
pass
|
|
33
35
|
|
|
34
36
|
def execute(self, args) -> bool:
|
|
37
|
+
# If QLEVER_OVERRIDE_DISABLE_UI is set, this command is disabled.
|
|
38
|
+
qlever_is_running_in_container = environ.get("QLEVER_IS_RUNNING_IN_CONTAINER")
|
|
39
|
+
if qlever_is_running_in_container:
|
|
40
|
+
log.error(
|
|
41
|
+
"The environment variable `QLEVER_OVERRIDE_DISABLE_UI` is set, "
|
|
42
|
+
"therefore `qlever ui` is not available (it should not be called "
|
|
43
|
+
"from inside a container)"
|
|
44
|
+
)
|
|
45
|
+
log.info("")
|
|
46
|
+
if not args.show:
|
|
47
|
+
log.info(
|
|
48
|
+
"For your information, showing the commands that are "
|
|
49
|
+
"executed when `qlever ui` is available:"
|
|
50
|
+
)
|
|
51
|
+
log.info("")
|
|
52
|
+
|
|
35
53
|
# Construct commands and show them.
|
|
36
54
|
server_url = f"http://{args.host_name}:{args.port}"
|
|
37
55
|
ui_url = f"http://{args.host_name}:{args.ui_port}"
|
|
38
56
|
pull_cmd = f"{args.ui_system} pull -q {args.ui_image}"
|
|
39
|
-
run_cmd =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
run_cmd = (
|
|
58
|
+
f"{args.ui_system} run -d "
|
|
59
|
+
f"--publish {args.ui_port}:7000 "
|
|
60
|
+
f"--name {args.ui_container} "
|
|
61
|
+
f"{args.ui_image}"
|
|
62
|
+
)
|
|
63
|
+
exec_cmd = (
|
|
64
|
+
f"{args.ui_system} exec -it "
|
|
65
|
+
f"{args.ui_container} "
|
|
66
|
+
f'bash -c "python manage.py configure '
|
|
67
|
+
f'{args.ui_config} {server_url}"'
|
|
68
|
+
)
|
|
69
|
+
self.show(
|
|
70
|
+
"\n".join(["Stop running containers", pull_cmd, run_cmd, exec_cmd]),
|
|
71
|
+
only_show=args.show,
|
|
72
|
+
)
|
|
73
|
+
if qlever_is_running_in_container or args.show:
|
|
50
74
|
return False
|
|
51
75
|
|
|
52
76
|
# Stop running containers.
|
|
53
77
|
for container_system in Containerize.supported_systems():
|
|
54
|
-
Containerize.stop_and_remove_container(
|
|
55
|
-
container_system, args.ui_container)
|
|
78
|
+
Containerize.stop_and_remove_container(container_system, args.ui_container)
|
|
56
79
|
|
|
57
80
|
# Check if the UI port is already being used.
|
|
58
81
|
if is_port_used(args.ui_port):
|
|
59
|
-
log.warning(
|
|
82
|
+
log.warning(
|
|
83
|
+
f"It looks like the specified port for the UI ({args.ui_port}) is already in use. You can set another port in the Qleverfile in the [ui] section with the UI_PORT variable."
|
|
84
|
+
)
|
|
60
85
|
|
|
61
86
|
# Try to start the QLever UI.
|
|
62
87
|
try:
|
|
@@ -68,7 +93,9 @@ class UiCommand(QleverCommand):
|
|
|
68
93
|
return False
|
|
69
94
|
|
|
70
95
|
# Success.
|
|
71
|
-
log.info(
|
|
72
|
-
|
|
73
|
-
|
|
96
|
+
log.info(
|
|
97
|
+
f"The QLever UI should now be up at {ui_url} ..."
|
|
98
|
+
f"You can log in as QLever UI admin with username and "
|
|
99
|
+
f'password "demo"'
|
|
100
|
+
)
|
|
74
101
|
return True
|
qlever/containerize.py
CHANGED
|
@@ -9,7 +9,7 @@ import subprocess
|
|
|
9
9
|
from typing import Optional
|
|
10
10
|
|
|
11
11
|
from qlever.log import log
|
|
12
|
-
from qlever.util import run_command
|
|
12
|
+
from qlever.util import run_command, get_random_string
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class ContainerizeException(Exception):
|
|
@@ -31,12 +31,16 @@ class Containerize:
|
|
|
31
31
|
return ["docker", "podman"]
|
|
32
32
|
|
|
33
33
|
@staticmethod
|
|
34
|
-
def containerize_command(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
def containerize_command(
|
|
35
|
+
cmd: str,
|
|
36
|
+
container_system: str,
|
|
37
|
+
run_subcommand: str,
|
|
38
|
+
image_name: str,
|
|
39
|
+
container_name: str,
|
|
40
|
+
volumes: list[tuple[str, str]] = [],
|
|
41
|
+
ports: list[tuple[int, int]] = [],
|
|
42
|
+
working_directory: Optional[str] = None,
|
|
43
|
+
) -> str:
|
|
40
44
|
"""
|
|
41
45
|
Get the command to run `cmd` with the given `container_system` and the
|
|
42
46
|
given options.
|
|
@@ -45,8 +49,9 @@ class Containerize:
|
|
|
45
49
|
# Check that `container_system` is supported.
|
|
46
50
|
if container_system not in Containerize.supported_systems():
|
|
47
51
|
return ContainerizeException(
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
f'Invalid container system "{container_system}"'
|
|
53
|
+
f" (must be one of {Containerize.supported_systems()})"
|
|
54
|
+
)
|
|
50
55
|
|
|
51
56
|
# Set user and group ids. This is important so that the files created
|
|
52
57
|
# by the containerized command are owned by the user running the
|
|
@@ -62,37 +67,40 @@ class Containerize:
|
|
|
62
67
|
# dir.
|
|
63
68
|
volume_options = "".join([f" -v {v1}:{v2}" for v1, v2 in volumes])
|
|
64
69
|
port_options = "".join([f" -p {p1}:{p2}" for p1, p2 in ports])
|
|
65
|
-
working_directory_option = (
|
|
66
|
-
|
|
70
|
+
working_directory_option = (
|
|
71
|
+
f" -w {working_directory}" if working_directory is not None else ""
|
|
72
|
+
)
|
|
67
73
|
|
|
68
74
|
# Construct the command that runs `cmd` with the given container
|
|
69
75
|
# system.
|
|
70
|
-
containerized_cmd = (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
containerized_cmd = (
|
|
77
|
+
f"{container_system} {run_subcommand}"
|
|
78
|
+
f"{user_option}"
|
|
79
|
+
f" -v /etc/localtime:/etc/localtime:ro"
|
|
80
|
+
f"{volume_options}"
|
|
81
|
+
f"{port_options}"
|
|
82
|
+
f"{working_directory_option}"
|
|
83
|
+
f" --init"
|
|
84
|
+
f" --entrypoint bash"
|
|
85
|
+
f" --name {container_name} {image_name}"
|
|
86
|
+
f" -c {shlex.quote(cmd)}"
|
|
87
|
+
)
|
|
80
88
|
return containerized_cmd
|
|
81
89
|
|
|
82
90
|
@staticmethod
|
|
83
91
|
def is_running(container_system: str, container_name: str) -> bool:
|
|
84
92
|
# Note: the `{{{{` and `}}}}` result in `{{` and `}}`, respectively.
|
|
85
93
|
containers = (
|
|
86
|
-
run_command(
|
|
87
|
-
|
|
94
|
+
run_command(
|
|
95
|
+
f'{container_system} ps --format="{{{{.Names}}}}"', return_output=True
|
|
96
|
+
)
|
|
88
97
|
.strip()
|
|
89
98
|
.splitlines()
|
|
90
99
|
)
|
|
91
100
|
return container_name in containers
|
|
92
101
|
|
|
93
102
|
@staticmethod
|
|
94
|
-
def stop_and_remove_container(container_system: str,
|
|
95
|
-
container_name: str) -> bool:
|
|
103
|
+
def stop_and_remove_container(container_system: str, container_name: str) -> bool:
|
|
96
104
|
"""
|
|
97
105
|
Stop the container with the given name using the given system. Return
|
|
98
106
|
`True` if a container with that name was found and stopped, `False`
|
|
@@ -102,19 +110,45 @@ class Containerize:
|
|
|
102
110
|
# Check that `container_system` is supported.
|
|
103
111
|
if container_system not in Containerize.supported_systems():
|
|
104
112
|
return ContainerizeException(
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
f'Invalid container system "{container_system}"'
|
|
114
|
+
f" (must be one of {Containerize.supported_systems()})"
|
|
115
|
+
)
|
|
107
116
|
|
|
108
117
|
# Construct the command that stops the container.
|
|
109
|
-
stop_cmd =
|
|
110
|
-
|
|
118
|
+
stop_cmd = (
|
|
119
|
+
f"{container_system} stop {container_name} && "
|
|
120
|
+
f"{container_system} rm {container_name}"
|
|
121
|
+
)
|
|
111
122
|
|
|
112
123
|
# Run the command.
|
|
113
124
|
try:
|
|
114
|
-
subprocess.run(
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
subprocess.run(
|
|
126
|
+
stop_cmd,
|
|
127
|
+
shell=True,
|
|
128
|
+
check=True,
|
|
129
|
+
stdout=subprocess.DEVNULL,
|
|
130
|
+
stderr=subprocess.DEVNULL,
|
|
131
|
+
)
|
|
117
132
|
return True
|
|
118
133
|
except Exception as e:
|
|
119
|
-
log.debug(f
|
|
134
|
+
log.debug(f'Error running "{stop_cmd}": {e}')
|
|
120
135
|
return False
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def run_in_container(cmd: str, args) -> Optional[str]:
|
|
139
|
+
"""
|
|
140
|
+
Run an arbitrary command in the qlever container and return its output.
|
|
141
|
+
"""
|
|
142
|
+
if args.system in Containerize.supported_systems():
|
|
143
|
+
if not args.server_container:
|
|
144
|
+
args.server_container = get_random_string(20)
|
|
145
|
+
run_cmd = Containerize().containerize_command(
|
|
146
|
+
cmd,
|
|
147
|
+
args.system,
|
|
148
|
+
'run --rm -it --entrypoint "" ',
|
|
149
|
+
args.image,
|
|
150
|
+
args.server_container,
|
|
151
|
+
volumes=[("$(pwd)", "/index")],
|
|
152
|
+
working_directory="/index",
|
|
153
|
+
)
|
|
154
|
+
return run_command(run_cmd, return_output=True)
|
qlever/qleverfile.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
import socket
|
|
5
4
|
import subprocess
|
|
6
5
|
from configparser import ConfigParser, ExtendedInterpolation
|
|
7
6
|
|
|
@@ -63,8 +62,16 @@ class Qleverfile:
|
|
|
63
62
|
help="A space-separated list of patterns that match "
|
|
64
63
|
"all the files of the dataset")
|
|
65
64
|
index_args["cat_input_files"] = arg(
|
|
66
|
-
"--cat-input-files", type=str,
|
|
65
|
+
"--cat-input-files", type=str,
|
|
67
66
|
help="The command that produces the input")
|
|
67
|
+
index_args["multi_input_json"] = arg(
|
|
68
|
+
"--multi-input-json", type=str, default=None,
|
|
69
|
+
help="JSON to specify multiple input files, each with a "
|
|
70
|
+
"`cmd` (command that writes the triples to stdout), "
|
|
71
|
+
"`format` (format like for the `--format` option), "
|
|
72
|
+
"`graph` (name of the graph, use `-` for the default graph), "
|
|
73
|
+
"`parallel` (parallel parsing for large files, where all "
|
|
74
|
+
"prefix declaration are at the beginning)")
|
|
68
75
|
index_args["settings_json"] = arg(
|
|
69
76
|
"--settings-json", type=str, default="{}",
|
|
70
77
|
help="The `.settings.json` file for the index")
|
|
@@ -106,7 +113,7 @@ class Qleverfile:
|
|
|
106
113
|
help="The binary for starting the server (this requires "
|
|
107
114
|
"that you have compiled QLever on your machine)")
|
|
108
115
|
server_args["host_name"] = arg(
|
|
109
|
-
"--host-name", type=str, default=
|
|
116
|
+
"--host-name", type=str, default="localhost",
|
|
110
117
|
help="The name of the host on which the server listens for "
|
|
111
118
|
"requests")
|
|
112
119
|
server_args["port"] = arg(
|