qlever 0.5.21__py3-none-any.whl → 0.5.23__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/__init__.py +17 -10
- qlever/command.py +1 -1
- qlever/commands/cache_stats.py +2 -2
- qlever/commands/clear_cache.py +30 -20
- qlever/commands/example_queries.py +2 -2
- qlever/commands/index.py +2 -10
- qlever/commands/query.py +2 -2
- qlever/commands/settings.py +1 -0
- qlever/commands/start.py +3 -26
- qlever/commands/stop.py +17 -41
- qlever/commands/ui.py +178 -26
- qlever/config.py +13 -6
- qlever/containerize.py +9 -4
- qlever/qlever_main.py +9 -4
- qlever/qleverfile.py +52 -5
- qlever/util.py +89 -4
- {qlever-0.5.21.dist-info → qlever-0.5.23.dist-info}/METADATA +2 -1
- {qlever-0.5.21.dist-info → qlever-0.5.23.dist-info}/RECORD +22 -22
- {qlever-0.5.21.dist-info → qlever-0.5.23.dist-info}/WHEEL +1 -1
- {qlever-0.5.21.dist-info → qlever-0.5.23.dist-info}/entry_points.txt +0 -0
- {qlever-0.5.21.dist-info → qlever-0.5.23.dist-info}/licenses/LICENSE +0 -0
- {qlever-0.5.21.dist-info → qlever-0.5.23.dist-info}/top_level.txt +0 -0
qlever/__init__.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
|
+
from importlib import import_module
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
|
|
@@ -10,9 +11,19 @@ def snake_to_camel(str):
|
|
|
10
11
|
return "".join([w.capitalize() for w in str.replace("-", "_").split("_")])
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
# Get the name of the script (without the path and without the extension).
|
|
15
|
+
script_name = Path(sys.argv[0]).stem
|
|
16
|
+
|
|
17
|
+
ENGINE_NAMES = {
|
|
18
|
+
"qlever": "QLever",
|
|
19
|
+
"qmdb": "MillenniumDB",
|
|
20
|
+
}
|
|
21
|
+
# Default engine_name = script_name without starting 'q' and capitalized
|
|
22
|
+
engine_name = ENGINE_NAMES.get(script_name, script_name[1:].capitalize())
|
|
23
|
+
|
|
13
24
|
# Each module in `qlever/commands` corresponds to a command. The name
|
|
14
25
|
# of the command is the base name of the module file.
|
|
15
|
-
package_path = Path(__file__).parent
|
|
26
|
+
package_path = Path(__file__).parent.parent / script_name
|
|
16
27
|
command_names = [
|
|
17
28
|
Path(p).stem
|
|
18
29
|
for p in package_path.glob("commands/*.py")
|
|
@@ -22,19 +33,15 @@ command_names = [
|
|
|
22
33
|
# Dynamically load all the command classes and create an object for each.
|
|
23
34
|
command_objects = {}
|
|
24
35
|
for command_name in command_names:
|
|
25
|
-
module_path = f"
|
|
26
|
-
class_name = snake_to_camel(command_name) + "Command"
|
|
36
|
+
module_path = f"{script_name}.commands.{command_name}"
|
|
27
37
|
try:
|
|
28
|
-
module =
|
|
38
|
+
module = import_module(module_path)
|
|
29
39
|
except ImportError as e:
|
|
30
40
|
raise Exception(
|
|
31
|
-
f"Could not import
|
|
32
|
-
|
|
33
|
-
)
|
|
41
|
+
f"Could not import module {module_path} for {script_name}: {e}"
|
|
42
|
+
) from e
|
|
34
43
|
# Create an object of the class and store it in the dictionary. For the
|
|
35
44
|
# commands, take - instead of _.
|
|
45
|
+
class_name = snake_to_camel(command_name) + "Command"
|
|
36
46
|
command_class = getattr(module, class_name)
|
|
37
47
|
command_objects[command_name.replace("_", "-")] = command_class()
|
|
38
|
-
|
|
39
|
-
# Get the name of the script (without the path and without the extension).
|
|
40
|
-
script_name = Path(sys.argv[0]).stem
|
qlever/command.py
CHANGED
|
@@ -81,7 +81,7 @@ class QleverCommand(ABC):
|
|
|
81
81
|
log.info("")
|
|
82
82
|
if only_show:
|
|
83
83
|
log.info(
|
|
84
|
-
'You
|
|
84
|
+
'You passed the argument "--show", therefore the command '
|
|
85
85
|
'is only shown, but not executed (omit the "--show" to '
|
|
86
86
|
"execute it)"
|
|
87
87
|
)
|
qlever/commands/cache_stats.py
CHANGED
|
@@ -28,7 +28,7 @@ class CacheStatsCommand(QleverCommand):
|
|
|
28
28
|
def additional_arguments(self, subparser) -> None:
|
|
29
29
|
subparser.add_argument("--server-url",
|
|
30
30
|
help="URL of the QLever server, default is "
|
|
31
|
-
"
|
|
31
|
+
"{host_name}:{port}")
|
|
32
32
|
subparser.add_argument("--detailed",
|
|
33
33
|
action="store_true",
|
|
34
34
|
default=False,
|
|
@@ -37,7 +37,7 @@ class CacheStatsCommand(QleverCommand):
|
|
|
37
37
|
def execute(self, args) -> bool:
|
|
38
38
|
# Construct the two curl commands.
|
|
39
39
|
server_url = (args.server_url if args.server_url
|
|
40
|
-
else f"
|
|
40
|
+
else f"{args.host_name}:{args.port}")
|
|
41
41
|
cache_stats_cmd = (f"curl -s {server_url} "
|
|
42
42
|
f"--data-urlencode \"cmd=cache-stats\"")
|
|
43
43
|
cache_settings_cmd = (f"curl -s {server_url} "
|
qlever/commands/clear_cache.py
CHANGED
|
@@ -17,22 +17,25 @@ class ClearCacheCommand(QleverCommand):
|
|
|
17
17
|
pass
|
|
18
18
|
|
|
19
19
|
def description(self) -> str:
|
|
20
|
-
return
|
|
20
|
+
return "Clear the query processing cache"
|
|
21
21
|
|
|
22
22
|
def should_have_qleverfile(self) -> bool:
|
|
23
23
|
return True
|
|
24
24
|
|
|
25
|
-
def relevant_qleverfile_arguments(self) -> dict[str: list[str]]:
|
|
26
|
-
return {"server": ["port", "access_token"]}
|
|
25
|
+
def relevant_qleverfile_arguments(self) -> dict[str : list[str]]:
|
|
26
|
+
return {"server": ["host_name", "port", "access_token"]}
|
|
27
27
|
|
|
28
28
|
def additional_arguments(self, subparser) -> None:
|
|
29
|
-
subparser.add_argument(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
subparser.add_argument(
|
|
30
|
+
"--server-url",
|
|
31
|
+
help="URL of the QLever server, default is {host_name}:{port}",
|
|
32
|
+
)
|
|
33
|
+
subparser.add_argument(
|
|
34
|
+
"--complete",
|
|
35
|
+
action="store_true",
|
|
36
|
+
default=False,
|
|
37
|
+
help="Clear the cache completely, including the pinned queries",
|
|
38
|
+
)
|
|
36
39
|
|
|
37
40
|
def execute(self, args) -> bool:
|
|
38
41
|
# Construct command line and show it.
|
|
@@ -40,22 +43,27 @@ class ClearCacheCommand(QleverCommand):
|
|
|
40
43
|
if args.server_url:
|
|
41
44
|
clear_cache_cmd += f" {args.server_url}"
|
|
42
45
|
else:
|
|
43
|
-
clear_cache_cmd += f"
|
|
46
|
+
clear_cache_cmd += f" {args.host_name}:{args.port}"
|
|
44
47
|
cmd_val = "clear-cache-complete" if args.complete else "clear-cache"
|
|
45
|
-
clear_cache_cmd += f
|
|
48
|
+
clear_cache_cmd += f' --data-urlencode "cmd={cmd_val}"'
|
|
46
49
|
if args.complete:
|
|
47
|
-
clear_cache_cmd += (
|
|
48
|
-
|
|
50
|
+
clear_cache_cmd += (
|
|
51
|
+
f" --data-urlencode access-token=" f'"{args.access_token}"'
|
|
52
|
+
)
|
|
49
53
|
self.show(clear_cache_cmd, only_show=args.show)
|
|
50
54
|
if args.show:
|
|
51
55
|
return True
|
|
52
56
|
|
|
53
57
|
# Execute the command.
|
|
54
58
|
try:
|
|
55
|
-
clear_cache_cmd +=
|
|
56
|
-
result = subprocess.run(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
clear_cache_cmd += ' -w " %{http_code}"'
|
|
60
|
+
result = subprocess.run(
|
|
61
|
+
clear_cache_cmd,
|
|
62
|
+
shell=True,
|
|
63
|
+
capture_output=True,
|
|
64
|
+
text=True,
|
|
65
|
+
check=True,
|
|
66
|
+
).stdout
|
|
59
67
|
match = re.match(r"^(.*) (\d+)$", result, re.DOTALL)
|
|
60
68
|
if not match:
|
|
61
69
|
raise Exception(f"Unexpected output:\n{result}")
|
|
@@ -77,6 +85,8 @@ class ClearCacheCommand(QleverCommand):
|
|
|
77
85
|
log.info("")
|
|
78
86
|
args.detailed = False
|
|
79
87
|
if not CacheStatsCommand().execute(args):
|
|
80
|
-
log.error(
|
|
81
|
-
|
|
88
|
+
log.error(
|
|
89
|
+
"Clearing the cache was successful, but showing the "
|
|
90
|
+
"cache stats failed {e}"
|
|
91
|
+
)
|
|
82
92
|
return True
|
|
@@ -31,7 +31,7 @@ class ExampleQueriesCommand(QleverCommand):
|
|
|
31
31
|
return False
|
|
32
32
|
|
|
33
33
|
def relevant_qleverfile_arguments(self) -> dict[str : list[str]]:
|
|
34
|
-
return {"server": ["port"], "ui": ["ui_config"]}
|
|
34
|
+
return {"server": ["host_name", "port"], "ui": ["ui_config"]}
|
|
35
35
|
|
|
36
36
|
def additional_arguments(self, subparser) -> None:
|
|
37
37
|
subparser.add_argument(
|
|
@@ -240,7 +240,7 @@ class ExampleQueriesCommand(QleverCommand):
|
|
|
240
240
|
sparql_endpoint = (
|
|
241
241
|
args.sparql_endpoint
|
|
242
242
|
if args.sparql_endpoint
|
|
243
|
-
else f"
|
|
243
|
+
else f"{args.host_name}:{args.port}"
|
|
244
244
|
)
|
|
245
245
|
self.show(
|
|
246
246
|
f"Obtain queries via: {get_queries_cmd}\n"
|
qlever/commands/index.py
CHANGED
|
@@ -9,6 +9,7 @@ from qlever.command import QleverCommand
|
|
|
9
9
|
from qlever.containerize import Containerize
|
|
10
10
|
from qlever.log import log
|
|
11
11
|
from qlever.util import (
|
|
12
|
+
binary_exists,
|
|
12
13
|
get_existing_index_files,
|
|
13
14
|
get_total_file_size,
|
|
14
15
|
run_command,
|
|
@@ -267,16 +268,7 @@ class IndexCommand(QleverCommand):
|
|
|
267
268
|
|
|
268
269
|
# When running natively, check if the binary exists and works.
|
|
269
270
|
if args.system == "native":
|
|
270
|
-
|
|
271
|
-
run_command(f"{args.index_binary} --help")
|
|
272
|
-
except Exception as e:
|
|
273
|
-
log.error(
|
|
274
|
-
f'Running "{args.index_binary}" failed, '
|
|
275
|
-
f"set `--index-binary` to a different binary or "
|
|
276
|
-
f"set `--system to a container system`"
|
|
277
|
-
)
|
|
278
|
-
log.info("")
|
|
279
|
-
log.info(f"The error message was: {e}")
|
|
271
|
+
if not binary_exists(args.index_binary, "index-binary"):
|
|
280
272
|
return False
|
|
281
273
|
|
|
282
274
|
# Check if all of the input files exist.
|
qlever/commands/query.py
CHANGED
|
@@ -38,7 +38,7 @@ class QueryCommand(QleverCommand):
|
|
|
38
38
|
return False
|
|
39
39
|
|
|
40
40
|
def relevant_qleverfile_arguments(self) -> dict[str : list[str]]:
|
|
41
|
-
return {"server": ["port", "access_token"]}
|
|
41
|
+
return {"server": ["host_name", "port", "access_token"]}
|
|
42
42
|
|
|
43
43
|
def additional_arguments(self, subparser) -> None:
|
|
44
44
|
subparser.add_argument(
|
|
@@ -109,7 +109,7 @@ class QueryCommand(QleverCommand):
|
|
|
109
109
|
sparql_endpoint = (
|
|
110
110
|
args.sparql_endpoint
|
|
111
111
|
if args.sparql_endpoint
|
|
112
|
-
else f"
|
|
112
|
+
else f"{args.host_name}:{args.port}"
|
|
113
113
|
)
|
|
114
114
|
curl_cmd = (
|
|
115
115
|
f"curl -s {sparql_endpoint}"
|
qlever/commands/settings.py
CHANGED
qlever/commands/start.py
CHANGED
|
@@ -10,7 +10,7 @@ from qlever.commands.stop import StopCommand
|
|
|
10
10
|
from qlever.commands.warmup import WarmupCommand
|
|
11
11
|
from qlever.containerize import Containerize
|
|
12
12
|
from qlever.log import log
|
|
13
|
-
from qlever.util import is_qlever_server_alive, run_command
|
|
13
|
+
from qlever.util import binary_exists, is_qlever_server_alive, run_command
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
# Construct the command line based on the config file.
|
|
@@ -71,22 +71,6 @@ def wrap_command_in_container(args, start_cmd) -> str:
|
|
|
71
71
|
return start_cmd
|
|
72
72
|
|
|
73
73
|
|
|
74
|
-
# When running natively, check if the binary exists and works.
|
|
75
|
-
def check_binary(binary) -> bool:
|
|
76
|
-
try:
|
|
77
|
-
run_command(f"{binary} --help")
|
|
78
|
-
return True
|
|
79
|
-
except Exception as e:
|
|
80
|
-
log.error(
|
|
81
|
-
f'Running "{binary}" failed, '
|
|
82
|
-
f"set `--server-binary` to a different binary or "
|
|
83
|
-
f"set `--system to a container system`"
|
|
84
|
-
)
|
|
85
|
-
log.info("")
|
|
86
|
-
log.info(f"The error message was: {e}")
|
|
87
|
-
return False
|
|
88
|
-
|
|
89
|
-
|
|
90
74
|
# Set the index description.
|
|
91
75
|
def set_index_description(access_arg, port, desc) -> bool:
|
|
92
76
|
curl_cmd = (
|
|
@@ -160,12 +144,6 @@ class StartCommand(QleverCommand):
|
|
|
160
144
|
}
|
|
161
145
|
|
|
162
146
|
def additional_arguments(self, subparser) -> None:
|
|
163
|
-
# subparser.add_argument("--kill-existing-with-same-name",
|
|
164
|
-
# action="store_true",
|
|
165
|
-
# default=False,
|
|
166
|
-
# help="If a QLever server is already running "
|
|
167
|
-
# "with the same name, kill it before "
|
|
168
|
-
# "starting a new server")
|
|
169
147
|
subparser.add_argument(
|
|
170
148
|
"--kill-existing-with-same-port",
|
|
171
149
|
action="store_true",
|
|
@@ -226,12 +204,11 @@ class StartCommand(QleverCommand):
|
|
|
226
204
|
|
|
227
205
|
# When running natively, check if the binary exists and works.
|
|
228
206
|
if args.system == "native":
|
|
229
|
-
|
|
230
|
-
if not ret:
|
|
207
|
+
if not binary_exists(args.server_binary, "server-binary"):
|
|
231
208
|
return False
|
|
232
209
|
|
|
233
210
|
# Check if a QLever server is already running on this port.
|
|
234
|
-
endpoint_url = f"http://
|
|
211
|
+
endpoint_url = f"http://{args.host_name}:{args.port}"
|
|
235
212
|
if is_qlever_server_alive(endpoint_url):
|
|
236
213
|
log.error(f"QLever server already running on {endpoint_url}")
|
|
237
214
|
log.info("")
|
qlever/commands/stop.py
CHANGED
|
@@ -1,37 +1,25 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import psutil
|
|
2
|
+
|
|
4
3
|
from qlever.command import QleverCommand
|
|
5
4
|
from qlever.commands.status import StatusCommand
|
|
6
5
|
from qlever.containerize import Containerize
|
|
7
6
|
from qlever.log import log
|
|
8
|
-
from qlever.util import
|
|
9
|
-
|
|
10
|
-
# try to kill the given process, return true iff it was killed successfully.
|
|
11
|
-
# the process_info is used for logging.
|
|
12
|
-
def stop_process(proc, pinfo):
|
|
13
|
-
try:
|
|
14
|
-
proc.kill()
|
|
15
|
-
log.info(f"Killed process {pinfo['pid']}")
|
|
16
|
-
return True
|
|
17
|
-
except Exception as e:
|
|
18
|
-
log.error(f"Could not kill process with PID "
|
|
19
|
-
f"{pinfo['pid']} ({e}) ... try to kill it "
|
|
20
|
-
f"manually")
|
|
21
|
-
log.info("")
|
|
22
|
-
show_process_info(proc, "", show_heading=True)
|
|
23
|
-
return False
|
|
7
|
+
from qlever.util import stop_process_with_regex
|
|
24
8
|
|
|
25
9
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
def stop_container(server_container: str) -> bool:
|
|
11
|
+
"""
|
|
12
|
+
Try to stop and remove container. return True iff it was stopped
|
|
13
|
+
successfully. Gives log info accordingly.
|
|
14
|
+
"""
|
|
29
15
|
for container_system in Containerize.supported_systems():
|
|
30
16
|
if Containerize.stop_and_remove_container(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
17
|
+
container_system, server_container
|
|
18
|
+
):
|
|
19
|
+
log.info(
|
|
20
|
+
f"{container_system.capitalize()} container with "
|
|
21
|
+
f'name "{server_container}" stopped and removed'
|
|
22
|
+
)
|
|
35
23
|
return True
|
|
36
24
|
return False
|
|
37
25
|
|
|
@@ -45,7 +33,7 @@ class StopCommand(QleverCommand):
|
|
|
45
33
|
pass
|
|
46
34
|
|
|
47
35
|
def description(self) -> str:
|
|
48
|
-
return "Stop QLever server for a given
|
|
36
|
+
return "Stop QLever server for a given dataset or port"
|
|
49
37
|
|
|
50
38
|
def should_have_qleverfile(self) -> bool:
|
|
51
39
|
return True
|
|
@@ -85,21 +73,9 @@ class StopCommand(QleverCommand):
|
|
|
85
73
|
# Check if there is a process running on the server port using psutil.
|
|
86
74
|
# NOTE: On MacOS, some of the proc's returned by psutil.process_iter()
|
|
87
75
|
# no longer exist when we try to access them, so we just skip them.
|
|
88
|
-
stop_process_results =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
pinfo = proc.as_dict(
|
|
92
|
-
attrs=['pid', 'username', 'create_time',
|
|
93
|
-
'memory_info', 'cmdline'])
|
|
94
|
-
cmdline = " ".join(pinfo['cmdline'])
|
|
95
|
-
except Exception as e:
|
|
96
|
-
log.debug(f"Error getting process info: {e}")
|
|
97
|
-
return False
|
|
98
|
-
if re.search(cmdline_regex, cmdline):
|
|
99
|
-
log.info(f"Found process {pinfo['pid']} from user "
|
|
100
|
-
f"{pinfo['username']} with command line: {cmdline}")
|
|
101
|
-
log.info("")
|
|
102
|
-
stop_process_results.append(stop_process(proc, pinfo))
|
|
76
|
+
stop_process_results = stop_process_with_regex(cmdline_regex)
|
|
77
|
+
if stop_process_results is None:
|
|
78
|
+
return False
|
|
103
79
|
if len(stop_process_results) > 0:
|
|
104
80
|
return all(stop_process_results)
|
|
105
81
|
|
qlever/commands/ui.py
CHANGED
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import subprocess
|
|
4
3
|
from os import environ
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import yaml
|
|
5
7
|
|
|
6
8
|
from qlever.command import QleverCommand
|
|
7
9
|
from qlever.containerize import Containerize
|
|
8
10
|
from qlever.log import log
|
|
9
|
-
from qlever.util import is_port_used
|
|
11
|
+
from qlever.util import is_port_used, run_command
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Return a YAML string for the given dictionary. Format values with
|
|
15
|
+
# newlines using the "|" style.
|
|
16
|
+
def dict_to_yaml(dictionary):
|
|
17
|
+
# Custom representer for yaml, which uses the "|" style only for
|
|
18
|
+
# multiline strings.
|
|
19
|
+
#
|
|
20
|
+
# NOTE: We replace all `\r\n` with `\n` because otherwise the `|` style
|
|
21
|
+
# does not work as expected.
|
|
22
|
+
class MultiLineDumper(yaml.Dumper):
|
|
23
|
+
def represent_scalar(self, tag, value, style=None):
|
|
24
|
+
value = value.replace("\r\n", "\n")
|
|
25
|
+
if isinstance(value, str) and "\n" in value:
|
|
26
|
+
style = "|"
|
|
27
|
+
return super().represent_scalar(tag, value, style)
|
|
28
|
+
|
|
29
|
+
# Dump as yaml.
|
|
30
|
+
return yaml.dump(
|
|
31
|
+
dictionary,
|
|
32
|
+
sort_keys=False,
|
|
33
|
+
Dumper=MultiLineDumper,
|
|
34
|
+
)
|
|
10
35
|
|
|
11
36
|
|
|
12
37
|
class UiCommand(QleverCommand):
|
|
@@ -37,7 +62,30 @@ class UiCommand(QleverCommand):
|
|
|
37
62
|
}
|
|
38
63
|
|
|
39
64
|
def additional_arguments(self, subparser) -> None:
|
|
40
|
-
|
|
65
|
+
subparser.add_argument(
|
|
66
|
+
"--ui-config-file",
|
|
67
|
+
default="Qleverfile-ui.yml",
|
|
68
|
+
help="Name of the config file for the QLever UI "
|
|
69
|
+
"(default: Qleverfile-ui.yml)",
|
|
70
|
+
)
|
|
71
|
+
subparser.add_argument(
|
|
72
|
+
"--ui-db-file",
|
|
73
|
+
help="Name of the database file for the QLever UI "
|
|
74
|
+
"(default: {name}.ui-db.sqlite3)",
|
|
75
|
+
)
|
|
76
|
+
subparser.add_argument(
|
|
77
|
+
"--no-pull-latest",
|
|
78
|
+
action="store_true",
|
|
79
|
+
default=False,
|
|
80
|
+
help="Do not pull the latest image for the QLever UI "
|
|
81
|
+
"(default: pull the latest image if image name contains '/')",
|
|
82
|
+
)
|
|
83
|
+
subparser.add_argument(
|
|
84
|
+
"--stop",
|
|
85
|
+
action="store_true",
|
|
86
|
+
default=False,
|
|
87
|
+
help="Stop the running container",
|
|
88
|
+
)
|
|
41
89
|
|
|
42
90
|
def execute(self, args) -> bool:
|
|
43
91
|
# If QLEVER_OVERRIDE_DISABLE_UI is set, this command is disabled.
|
|
@@ -59,57 +107,161 @@ class UiCommand(QleverCommand):
|
|
|
59
107
|
log.info("")
|
|
60
108
|
|
|
61
109
|
# Construct commands and show them.
|
|
62
|
-
|
|
110
|
+
pull_latest_image = "/" in args.ui_image and not args.no_pull_latest
|
|
111
|
+
ui_config_name = args.ui_config
|
|
112
|
+
ui_db_file = args.ui_db_file or f"{args.name}.ui-db.sqlite3"
|
|
113
|
+
ui_db_file_from_image = "qleverui.sqlite3"
|
|
114
|
+
ui_config_file = args.ui_config_file
|
|
115
|
+
sparql_endpoint = f"http://{args.host_name}:{args.port}"
|
|
63
116
|
ui_url = f"http://{args.host_name}:{args.ui_port}"
|
|
64
117
|
pull_cmd = f"{args.ui_system} pull -q {args.ui_image}"
|
|
65
|
-
|
|
118
|
+
get_db_cmd = (
|
|
119
|
+
f"{args.ui_system} create "
|
|
120
|
+
f"--name {args.ui_container} "
|
|
121
|
+
f"{args.ui_image} "
|
|
122
|
+
f"&& {args.ui_system} cp "
|
|
123
|
+
f"{args.ui_container}:/app/db/{ui_db_file_from_image} {ui_db_file} "
|
|
124
|
+
f"&& {args.ui_system} rm -f {args.ui_container}"
|
|
125
|
+
)
|
|
126
|
+
start_ui_cmd = (
|
|
66
127
|
f"{args.ui_system} run -d "
|
|
128
|
+
f"--volume $(pwd):/app/db "
|
|
129
|
+
f"--env QLEVERUI_DATABASE_URL=sqlite:////app/db/{ui_db_file} "
|
|
67
130
|
f"--publish {args.ui_port}:7000 "
|
|
68
131
|
f"--name {args.ui_container} "
|
|
69
132
|
f"{args.ui_image}"
|
|
70
133
|
)
|
|
71
|
-
|
|
72
|
-
f"{args.ui_system} exec -
|
|
134
|
+
get_config_cmd = (
|
|
135
|
+
f"{args.ui_system} exec -i "
|
|
73
136
|
f"{args.ui_container} "
|
|
74
|
-
f'bash -c "python manage.py
|
|
75
|
-
f'{args.ui_config} {server_url}"'
|
|
137
|
+
f'bash -c "python manage.py config {ui_config_name}"'
|
|
76
138
|
)
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
139
|
+
set_config_cmd = (
|
|
140
|
+
f"{args.ui_system} exec -i "
|
|
141
|
+
f"{args.ui_container} "
|
|
142
|
+
f'bash -c "python manage.py config {ui_config_name} '
|
|
143
|
+
f'/app/db/{ui_config_file} --hide-all-other-backends"'
|
|
82
144
|
)
|
|
145
|
+
commands_to_show = []
|
|
146
|
+
if not args.stop:
|
|
147
|
+
if pull_latest_image:
|
|
148
|
+
commands_to_show.append(pull_cmd)
|
|
149
|
+
if not Path(ui_db_file).exists():
|
|
150
|
+
commands_to_show.append(get_db_cmd)
|
|
151
|
+
commands_to_show.append(start_ui_cmd)
|
|
152
|
+
if not Path(ui_config_file).exists():
|
|
153
|
+
commands_to_show.append(get_config_cmd)
|
|
154
|
+
else:
|
|
155
|
+
commands_to_show.append(set_config_cmd)
|
|
156
|
+
self.show("\n".join(commands_to_show), only_show=args.show)
|
|
83
157
|
if qlever_is_running_in_container:
|
|
84
158
|
return False
|
|
85
159
|
if args.show:
|
|
86
160
|
return True
|
|
87
161
|
|
|
88
162
|
# Stop running containers.
|
|
163
|
+
was_found_and_stopped = False
|
|
89
164
|
for container_system in Containerize.supported_systems():
|
|
90
|
-
Containerize.stop_and_remove_container(
|
|
165
|
+
was_found_and_stopped |= Containerize.stop_and_remove_container(
|
|
91
166
|
container_system, args.ui_container
|
|
92
167
|
)
|
|
168
|
+
if was_found_and_stopped:
|
|
169
|
+
log.debug(f"Stopped and removed container `{args.ui_container}`")
|
|
170
|
+
else:
|
|
171
|
+
log.debug(f"No container with name `{args.ui_container}` found")
|
|
172
|
+
if args.stop:
|
|
173
|
+
return True
|
|
174
|
+
|
|
175
|
+
# Pull the latest image.
|
|
176
|
+
if pull_latest_image:
|
|
177
|
+
log.debug(f"Pulling image `{args.ui_image}` for QLever UI")
|
|
178
|
+
run_command(pull_cmd)
|
|
93
179
|
|
|
94
180
|
# Check if the UI port is already being used.
|
|
95
181
|
if is_port_used(args.ui_port):
|
|
96
182
|
log.warning(
|
|
97
|
-
f"It looks like
|
|
183
|
+
f"It looks like port {args.ui_port} for the QLever UI "
|
|
184
|
+
f"is already in use. You can set another port in the "
|
|
185
|
+
f" Qleverfile in the [ui] section with the UI_PORT variable."
|
|
98
186
|
)
|
|
99
187
|
|
|
100
|
-
#
|
|
188
|
+
# Get the QLever UI database from the image, unless it already exists.
|
|
189
|
+
if Path(ui_db_file).exists():
|
|
190
|
+
log.debug(f"Found QLever UI database `{ui_db_file}`, reusing it")
|
|
191
|
+
else:
|
|
192
|
+
log.debug(f"Getting QLever UI database `{ui_db_file}` from image")
|
|
193
|
+
try:
|
|
194
|
+
run_command(get_db_cmd)
|
|
195
|
+
except Exception as e:
|
|
196
|
+
log.error(
|
|
197
|
+
f"Failed to get {ui_db_file} from {args.ui_image} "
|
|
198
|
+
f"({e})"
|
|
199
|
+
)
|
|
200
|
+
return False
|
|
201
|
+
|
|
202
|
+
# Start the QLever UI.
|
|
203
|
+
try:
|
|
204
|
+
log.debug(
|
|
205
|
+
f"Starting new container with name `{args.ui_container}`"
|
|
206
|
+
)
|
|
207
|
+
run_command(start_ui_cmd)
|
|
208
|
+
except Exception as e:
|
|
209
|
+
log.error(f"Failed to start container `{args.ui_container}` ({e})")
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
# Check if config file with name `ui_config_file` exists. If not, try
|
|
213
|
+
# to obtain it via `get_config_cmd` and set it as default.
|
|
214
|
+
if Path(ui_config_file).exists():
|
|
215
|
+
log.info(f"Found config file `{ui_config_file}` and reusing it")
|
|
216
|
+
else:
|
|
217
|
+
try:
|
|
218
|
+
log.info(
|
|
219
|
+
f"Get default config file `{ui_config_file}` from image "
|
|
220
|
+
f"`{args.ui_image}` and set endpoint to `{sparql_endpoint}`"
|
|
221
|
+
)
|
|
222
|
+
config_yaml = run_command(get_config_cmd, return_output=True)
|
|
223
|
+
config_dict = yaml.safe_load(config_yaml)
|
|
224
|
+
except Exception as e:
|
|
225
|
+
log.error("")
|
|
226
|
+
log.error(
|
|
227
|
+
f"An error occured while getting and parsing the "
|
|
228
|
+
f"config file ({e})"
|
|
229
|
+
)
|
|
230
|
+
return False
|
|
231
|
+
try:
|
|
232
|
+
config_dict["config"]["backend"]["isDefault"] = True
|
|
233
|
+
config_dict["config"]["backend"]["baseUrl"] = sparql_endpoint
|
|
234
|
+
config_dict["config"]["backend"]["sortKey"] = 1
|
|
235
|
+
config_yaml = dict_to_yaml(config_dict)
|
|
236
|
+
with open(ui_config_file, "w") as f:
|
|
237
|
+
f.write(config_yaml)
|
|
238
|
+
except Exception as e:
|
|
239
|
+
log.error("")
|
|
240
|
+
log.error(
|
|
241
|
+
f"An error occured while modifying and writing the "
|
|
242
|
+
f"config file ({e})"
|
|
243
|
+
)
|
|
244
|
+
return False
|
|
245
|
+
|
|
246
|
+
# Configure the QLever UI.
|
|
101
247
|
try:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
except subprocess.CalledProcessError as e:
|
|
106
|
-
log.error(f"Failed to start the QLever UI ({e})")
|
|
248
|
+
run_command(set_config_cmd)
|
|
249
|
+
except Exception as e:
|
|
250
|
+
log.error(f"Failed to configure the QLever UI ({e})")
|
|
107
251
|
return False
|
|
108
252
|
|
|
109
|
-
#
|
|
253
|
+
# If we come this far, everything should work.
|
|
254
|
+
log.info("")
|
|
255
|
+
log.info(
|
|
256
|
+
f"The QLever UI should now be up at {ui_url}/{ui_config_name}"
|
|
257
|
+
)
|
|
258
|
+
log.info("")
|
|
259
|
+
log.debug(
|
|
260
|
+
"If you must, you can log in as QLever UI admin with "
|
|
261
|
+
'username and password "demo"'
|
|
262
|
+
)
|
|
110
263
|
log.info(
|
|
111
|
-
f"
|
|
112
|
-
f"
|
|
113
|
-
f'password "demo"'
|
|
264
|
+
f"You can modify the config file at `{ui_config_file}` "
|
|
265
|
+
f"and then just run `qlever ui` again"
|
|
114
266
|
)
|
|
115
267
|
return True
|
qlever/config.py
CHANGED
|
@@ -9,7 +9,7 @@ from pathlib import Path
|
|
|
9
9
|
import argcomplete
|
|
10
10
|
from termcolor import colored
|
|
11
11
|
|
|
12
|
-
from qlever import command_objects, script_name
|
|
12
|
+
from qlever import command_objects, engine_name, script_name
|
|
13
13
|
from qlever.log import log, log_levels
|
|
14
14
|
from qlever.qleverfile import Qleverfile
|
|
15
15
|
|
|
@@ -176,11 +176,18 @@ class QleverConfig:
|
|
|
176
176
|
# are defined in the modules in `qlever/commands`. In `__init__.py`
|
|
177
177
|
# an object of each class is created and stored in `command_objects`.
|
|
178
178
|
parser = argparse.ArgumentParser(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
description=colored(
|
|
180
|
+
f"This is the {script_name} command line tool, "
|
|
181
|
+
f"it's all you need to work with {engine_name}",
|
|
182
|
+
attrs=["bold"],
|
|
183
|
+
)
|
|
184
|
+
)
|
|
185
|
+
if script_name == "qlever":
|
|
186
|
+
parser.add_argument(
|
|
187
|
+
"--version",
|
|
188
|
+
action="version",
|
|
189
|
+
version=f"%(prog)s {version('qlever')}",
|
|
190
|
+
)
|
|
184
191
|
add_qleverfile_option(parser)
|
|
185
192
|
subparsers = parser.add_subparsers(dest='command')
|
|
186
193
|
subparsers.required = 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
|
|
12
|
+
from qlever.util import get_random_string, run_command
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class ContainerizeException(Exception):
|
|
@@ -40,6 +40,7 @@ class Containerize:
|
|
|
40
40
|
volumes: list[tuple[str, str]] = [],
|
|
41
41
|
ports: list[tuple[int, int]] = [],
|
|
42
42
|
working_directory: Optional[str] = None,
|
|
43
|
+
use_bash: bool = True,
|
|
43
44
|
) -> str:
|
|
44
45
|
"""
|
|
45
46
|
Get the command to run `cmd` with the given `container_system` and the
|
|
@@ -80,11 +81,15 @@ class Containerize:
|
|
|
80
81
|
f"{volume_options}"
|
|
81
82
|
f"{port_options}"
|
|
82
83
|
f"{working_directory_option}"
|
|
84
|
+
f" --name {container_name}"
|
|
83
85
|
f" --init"
|
|
84
|
-
f" --entrypoint bash"
|
|
85
|
-
f" --name {container_name} {image_name}"
|
|
86
|
-
f" -c {shlex.quote(cmd)}"
|
|
87
86
|
)
|
|
87
|
+
if use_bash:
|
|
88
|
+
containerized_cmd += (
|
|
89
|
+
f" --entrypoint bash {image_name} -c {shlex.quote(cmd)}"
|
|
90
|
+
)
|
|
91
|
+
else:
|
|
92
|
+
containerized_cmd += f" {image_name} {cmd}"
|
|
88
93
|
return containerized_cmd
|
|
89
94
|
|
|
90
95
|
@staticmethod
|
qlever/qlever_main.py
CHANGED
|
@@ -12,7 +12,7 @@ import traceback
|
|
|
12
12
|
|
|
13
13
|
from termcolor import colored
|
|
14
14
|
|
|
15
|
-
from qlever import command_objects
|
|
15
|
+
from qlever import command_objects, script_name
|
|
16
16
|
from qlever.config import ConfigException, QleverConfig
|
|
17
17
|
from qlever.log import log, log_levels
|
|
18
18
|
|
|
@@ -35,9 +35,9 @@ def main():
|
|
|
35
35
|
log.info("")
|
|
36
36
|
log.info(colored(f"Command: {args.command}", attrs=["bold"]))
|
|
37
37
|
log.info("")
|
|
38
|
-
|
|
38
|
+
command_successful = command_object.execute(args)
|
|
39
39
|
log.info("")
|
|
40
|
-
if not
|
|
40
|
+
if not command_successful:
|
|
41
41
|
exit(1)
|
|
42
42
|
except KeyboardInterrupt:
|
|
43
43
|
log.info("")
|
|
@@ -47,9 +47,14 @@ def main():
|
|
|
47
47
|
except Exception as e:
|
|
48
48
|
# Check if it's a certain kind of `AttributeError` and give a hint in
|
|
49
49
|
# that case.
|
|
50
|
+
log.debug(
|
|
51
|
+
"Command failed with exception, full traceback: "
|
|
52
|
+
f"{traceback.format_exc()}"
|
|
53
|
+
)
|
|
50
54
|
match_error = re.search(r"object has no attribute '(.+)'", str(e))
|
|
51
55
|
match_trace = re.search(
|
|
52
|
-
|
|
56
|
+
rf"({script_name}/commands/.+\.py)\", line (\d+)",
|
|
57
|
+
traceback.format_exc(),
|
|
53
58
|
)
|
|
54
59
|
if isinstance(e, AttributeError) and match_error and match_trace:
|
|
55
60
|
attribute = match_error.group(1)
|
qlever/qleverfile.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
+
import socket
|
|
4
5
|
import subprocess
|
|
5
|
-
from configparser import ConfigParser, ExtendedInterpolation
|
|
6
|
+
from configparser import ConfigParser, ExtendedInterpolation, RawConfigParser
|
|
7
|
+
from pathlib import Path
|
|
6
8
|
|
|
9
|
+
from qlever import script_name
|
|
7
10
|
from qlever.containerize import Containerize
|
|
8
11
|
from qlever.log import log
|
|
9
12
|
|
|
@@ -298,12 +301,12 @@ class Qleverfile:
|
|
|
298
301
|
runtime_args["index_container"] = arg(
|
|
299
302
|
"--index-container",
|
|
300
303
|
type=str,
|
|
301
|
-
help="The name of the container used by `
|
|
304
|
+
help=f"The name of the container used by `{script_name} index`",
|
|
302
305
|
)
|
|
303
306
|
runtime_args["server_container"] = arg(
|
|
304
307
|
"--server-container",
|
|
305
308
|
type=str,
|
|
306
|
-
help="The name of the container used by `
|
|
309
|
+
help=f"The name of the container used by `{script_name} start`",
|
|
307
310
|
)
|
|
308
311
|
|
|
309
312
|
ui_args["ui_port"] = arg(
|
|
@@ -400,9 +403,9 @@ class Qleverfile:
|
|
|
400
403
|
name = config["data"]["name"]
|
|
401
404
|
runtime = config["runtime"]
|
|
402
405
|
if "server_container" not in runtime:
|
|
403
|
-
runtime["server_container"] = f"
|
|
406
|
+
runtime["server_container"] = f"{script_name}.server.{name}"
|
|
404
407
|
if "index_container" not in runtime:
|
|
405
|
-
runtime["index_container"] = f"
|
|
408
|
+
runtime["index_container"] = f"{script_name}.index.{name}"
|
|
406
409
|
if "ui_container" not in config["ui"]:
|
|
407
410
|
config["ui"]["ui_container"] = f"qlever.ui.{name}"
|
|
408
411
|
index = config["index"]
|
|
@@ -414,5 +417,49 @@ class Qleverfile:
|
|
|
414
417
|
if index.get("text_index", "none") != "none":
|
|
415
418
|
server["use_text_index"] = "yes"
|
|
416
419
|
|
|
420
|
+
# Add other non-trivial default values.
|
|
421
|
+
try:
|
|
422
|
+
config["server"]["host_name"] = socket.gethostname()
|
|
423
|
+
except Exception:
|
|
424
|
+
log.warning(
|
|
425
|
+
"Could not get the hostname, using `localhost` as default"
|
|
426
|
+
)
|
|
427
|
+
pass
|
|
428
|
+
|
|
417
429
|
# Return the parsed Qleverfile with the added inherited values.
|
|
418
430
|
return config
|
|
431
|
+
|
|
432
|
+
@staticmethod
|
|
433
|
+
def filter(
|
|
434
|
+
qleverfile_path: Path, options_included: dict[str, list[str]]
|
|
435
|
+
) -> RawConfigParser:
|
|
436
|
+
"""
|
|
437
|
+
Given a filter criteria (key: section_header, value: list[options]),
|
|
438
|
+
return a RawConfigParser object to create a new filtered Qleverfile
|
|
439
|
+
with only the specified sections and options (selects all options if
|
|
440
|
+
list[options] is empty). Mainly to be used by non-qlever scripts for
|
|
441
|
+
the setup-config command
|
|
442
|
+
"""
|
|
443
|
+
# Read the Qleverfile.
|
|
444
|
+
config = RawConfigParser()
|
|
445
|
+
config.optionxform = str # Preserve case sensitivity of keys
|
|
446
|
+
config.read(qleverfile_path)
|
|
447
|
+
|
|
448
|
+
filtered_config = RawConfigParser()
|
|
449
|
+
filtered_config.optionxform = str
|
|
450
|
+
|
|
451
|
+
for section, desired_fields in options_included.items():
|
|
452
|
+
if config.has_section(section):
|
|
453
|
+
filtered_config.add_section(section)
|
|
454
|
+
|
|
455
|
+
# If the list is empty, copy all fields
|
|
456
|
+
if not desired_fields:
|
|
457
|
+
for field, value in config.items(section):
|
|
458
|
+
filtered_config.set(section, field, value)
|
|
459
|
+
else:
|
|
460
|
+
for desired_field in desired_fields:
|
|
461
|
+
if config.has_option(section, desired_field):
|
|
462
|
+
value = config.get(section, desired_field)
|
|
463
|
+
filtered_config.set(section, desired_field, value)
|
|
464
|
+
|
|
465
|
+
return filtered_config
|
qlever/util.py
CHANGED
|
@@ -10,7 +10,9 @@ import string
|
|
|
10
10
|
import subprocess
|
|
11
11
|
from datetime import date, datetime
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import Optional
|
|
13
|
+
from typing import Any, Optional
|
|
14
|
+
|
|
15
|
+
import psutil
|
|
14
16
|
|
|
15
17
|
from qlever.log import log
|
|
16
18
|
|
|
@@ -33,6 +35,7 @@ def run_command(
|
|
|
33
35
|
cmd: str,
|
|
34
36
|
return_output: bool = False,
|
|
35
37
|
show_output: bool = False,
|
|
38
|
+
show_stderr: bool = False,
|
|
36
39
|
use_popen: bool = False,
|
|
37
40
|
) -> Optional[str | subprocess.Popen]:
|
|
38
41
|
"""
|
|
@@ -50,7 +53,7 @@ def run_command(
|
|
|
50
53
|
"shell": True,
|
|
51
54
|
"text": True,
|
|
52
55
|
"stdout": None if show_output else subprocess.PIPE,
|
|
53
|
-
"stderr": subprocess.PIPE,
|
|
56
|
+
"stderr": None if show_stderr else subprocess.PIPE,
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
# With `Popen`, the command runs in the current shell and a process object
|
|
@@ -72,8 +75,8 @@ def run_command(
|
|
|
72
75
|
raise Exception(result.stderr.replace("\n", " ").strip())
|
|
73
76
|
else:
|
|
74
77
|
raise Exception(
|
|
75
|
-
f"Command failed with exit code {result.returncode}"
|
|
76
|
-
f"
|
|
78
|
+
f"Command failed with exit code {result.returncode}, "
|
|
79
|
+
f" nothing written to stderr"
|
|
77
80
|
)
|
|
78
81
|
# Optionally, return what was written to `stdout`.
|
|
79
82
|
if return_output:
|
|
@@ -242,3 +245,85 @@ def format_size(bytes, suffix="B"):
|
|
|
242
245
|
if bytes < factor:
|
|
243
246
|
return f"{bytes:.2f} {unit}{suffix}"
|
|
244
247
|
bytes /= factor
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def stop_process(proc: psutil.Process, pinfo: dict[str, Any]) -> bool:
|
|
251
|
+
"""
|
|
252
|
+
Try to kill the given process, return True iff it was killed
|
|
253
|
+
successfully. The process_info is used for logging.
|
|
254
|
+
"""
|
|
255
|
+
try:
|
|
256
|
+
proc.kill()
|
|
257
|
+
log.info(f"Killed process {pinfo['pid']}")
|
|
258
|
+
return True
|
|
259
|
+
except Exception as e:
|
|
260
|
+
log.error(
|
|
261
|
+
f"Could not kill process with PID "
|
|
262
|
+
f"{pinfo['pid']} ({e}) ... try to kill it "
|
|
263
|
+
f"manually"
|
|
264
|
+
)
|
|
265
|
+
log.info("")
|
|
266
|
+
show_process_info(proc, "", show_heading=True)
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def stop_process_with_regex(cmdline_regex: str) -> list[bool] | None:
|
|
271
|
+
"""
|
|
272
|
+
Given a cmdline_regex for a native process, try to kill the processes that
|
|
273
|
+
match the regex and return a list of their stopped status (bool).
|
|
274
|
+
Show the matched processes as log info.
|
|
275
|
+
"""
|
|
276
|
+
stop_process_results = []
|
|
277
|
+
for proc in psutil.process_iter():
|
|
278
|
+
try:
|
|
279
|
+
pinfo = proc.as_dict(
|
|
280
|
+
attrs=[
|
|
281
|
+
"pid",
|
|
282
|
+
"username",
|
|
283
|
+
"create_time",
|
|
284
|
+
"memory_info",
|
|
285
|
+
"cmdline",
|
|
286
|
+
]
|
|
287
|
+
)
|
|
288
|
+
cmdline = " ".join(pinfo["cmdline"])
|
|
289
|
+
except Exception as e:
|
|
290
|
+
log.debug(f"Error getting process info: {e}")
|
|
291
|
+
return None
|
|
292
|
+
if re.search(cmdline_regex, cmdline):
|
|
293
|
+
log.info(
|
|
294
|
+
f"Found process {pinfo['pid']} from user "
|
|
295
|
+
f"{pinfo['username']} with command line: {cmdline}"
|
|
296
|
+
)
|
|
297
|
+
log.info("")
|
|
298
|
+
stop_process_results.append(stop_process(proc, pinfo))
|
|
299
|
+
return stop_process_results
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def binary_exists(binary: str, cmd_arg: str) -> bool:
|
|
303
|
+
"""
|
|
304
|
+
When a command is run natively, check if the binary exists on the system
|
|
305
|
+
"""
|
|
306
|
+
try:
|
|
307
|
+
run_command(f"{binary} --help")
|
|
308
|
+
return True
|
|
309
|
+
except Exception as e:
|
|
310
|
+
log.error(
|
|
311
|
+
f'Running "{binary}" failed, '
|
|
312
|
+
f"set `--{cmd_arg}` to a different binary or "
|
|
313
|
+
f"set `--system to a container system`"
|
|
314
|
+
)
|
|
315
|
+
log.info("")
|
|
316
|
+
log.info(f"The error message was: {e}")
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def is_server_alive(url: str) -> bool:
|
|
321
|
+
"""
|
|
322
|
+
Check if the server is already alive at the given endpoint url
|
|
323
|
+
"""
|
|
324
|
+
check_server_cmd = f"curl -s {url}"
|
|
325
|
+
try:
|
|
326
|
+
run_command(check_server_cmd)
|
|
327
|
+
return True
|
|
328
|
+
except Exception:
|
|
329
|
+
return False
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qlever
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.23
|
|
4
4
|
Summary: Command-line tool for using the QLever graph database
|
|
5
5
|
Author-email: Hannah Bast <bast@cs.uni-freiburg.de>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -14,6 +14,7 @@ License-File: LICENSE
|
|
|
14
14
|
Requires-Dist: psutil
|
|
15
15
|
Requires-Dist: termcolor
|
|
16
16
|
Requires-Dist: argcomplete
|
|
17
|
+
Requires-Dist: pyyaml
|
|
17
18
|
Dynamic: license-file
|
|
18
19
|
|
|
19
20
|
# QLever
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
qlever/__init__.py,sha256=
|
|
2
|
-
qlever/command.py,sha256=
|
|
3
|
-
qlever/config.py,sha256=
|
|
4
|
-
qlever/containerize.py,sha256=
|
|
1
|
+
qlever/__init__.py,sha256=ZbzivHALRlzAUoFBBSbbkKFcvATBX7yVR6Q9JyEQ8ig,1631
|
|
2
|
+
qlever/command.py,sha256=nI-UG1GWrZ24DxD0Ly8dvupCpsD9e3n9-eskkCMTx6c,2767
|
|
3
|
+
qlever/config.py,sha256=gNw2_-jj1TjzhzqLOuUI_Dh19q_ViCiArrtrgXL2F4E,10354
|
|
4
|
+
qlever/containerize.py,sha256=G1_ei9nBnYl5-7miiy0eWjb9HMnt06X21P7iU8bm6A0,5369
|
|
5
5
|
qlever/log.py,sha256=WLscWV4fFF_w_uXSOfvWzhyzRM7t_61inE2ks3zf6Gw,1317
|
|
6
|
-
qlever/qlever_main.py,sha256
|
|
7
|
-
qlever/qleverfile.py,sha256=
|
|
8
|
-
qlever/util.py,sha256=
|
|
6
|
+
qlever/qlever_main.py,sha256=mkNeQ6UOX-cIR5dVwwS12qc0gsJh4b6yL0LTdU-8oN4,2612
|
|
7
|
+
qlever/qleverfile.py,sha256=DZ--LJ4TxWqs08bKHmGQlXQW6MPyOB--r7eMKs7E59s,17449
|
|
8
|
+
qlever/util.py,sha256=Gv9fE-SOZSx1Kez5z3pcukniZnDDQEKx7j9LV-iP7LM,10939
|
|
9
9
|
qlever/Qleverfiles/Qleverfile.dblp,sha256=oVVPFMpKX0Lfe0HDYPuL3qYhlC-3Lz18AT2tHmJ32WE,1282
|
|
10
10
|
qlever/Qleverfiles/Qleverfile.dblp-plus,sha256=TJHxp8I1P6JKJjbuAllEpB32-huuY1gH0FlenqPVJ5g,1334
|
|
11
11
|
qlever/Qleverfiles/Qleverfile.dbpedia,sha256=aaNZZayE-zVePGSwPzXemkX__Ns8-kP_E7DNNKZPnqg,1160
|
|
@@ -28,26 +28,26 @@ qlever/Qleverfiles/Qleverfile.wikipathways,sha256=UFEVLrtOBiSQfibBN9xc2wDXrnWcnx
|
|
|
28
28
|
qlever/Qleverfiles/Qleverfile.yago-4,sha256=hAS_2ZmC1zxNsKXip7t1F_iqu3CC-6O7v6HZhuFbnWY,1819
|
|
29
29
|
qlever/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
qlever/commands/add_text_index.py,sha256=xJ49Iq1-CszXjHDvOpllqLw1J1kCxQl7H848XD1vEz0,3820
|
|
31
|
-
qlever/commands/cache_stats.py,sha256=
|
|
32
|
-
qlever/commands/clear_cache.py,sha256=
|
|
33
|
-
qlever/commands/example_queries.py,sha256=
|
|
31
|
+
qlever/commands/cache_stats.py,sha256=15C0iIahwPuxTvMDyB0UDmo45iBk97hWzVZkEMHjMA8,4165
|
|
32
|
+
qlever/commands/clear_cache.py,sha256=kwNayV4qtgqh_Gf5SjS6WzmfgUsJ-9YhPoWYWGoNNn8,2967
|
|
33
|
+
qlever/commands/example_queries.py,sha256=4oKCBYYO_uhBNGrSyAd69UA1--bPPcjp88aULaNaT-o,24051
|
|
34
34
|
qlever/commands/extract_queries.py,sha256=TZBmZLz_NknU1LKbl9nPmxdb82lsPeDhTWjIo81llvA,3942
|
|
35
35
|
qlever/commands/get_data.py,sha256=nHOHMjv0tSLWJDOR0ba_LK-Bk-mcGnphb8hbqcVYFhE,1411
|
|
36
|
-
qlever/commands/index.py,sha256=
|
|
36
|
+
qlever/commands/index.py,sha256=NJ6hdlYEc-4AOANON3Bpl-vhgOs21HiPQnUrAE1Flfk,13055
|
|
37
37
|
qlever/commands/index_stats.py,sha256=9EBo1Oq5PGjajrvWJNafJ-Wg_d90DaO5AGq9a5plSRM,11720
|
|
38
38
|
qlever/commands/log.py,sha256=vLqkgtx1udnQqoUBMWB5G9rwr-l7UKrDpyFYSMuoXWw,1987
|
|
39
|
-
qlever/commands/query.py,sha256=
|
|
40
|
-
qlever/commands/settings.py,sha256=
|
|
39
|
+
qlever/commands/query.py,sha256=IBIi1NT1n9xDobqNIXlV50ap3o958g5KHMiFJqw89z0,4608
|
|
40
|
+
qlever/commands/settings.py,sha256=LpfF0jhttJsqKUh9hO4mdW3SVE3361wvb2SeQWPUB7w,3813
|
|
41
41
|
qlever/commands/setup_config.py,sha256=wEy1LAunpOnqrUCbazMpt1u9HJCKgXJEMxF3zjh0jb0,3344
|
|
42
|
-
qlever/commands/start.py,sha256=
|
|
42
|
+
qlever/commands/start.py,sha256=g_5-BUiSYJjL10ae91jMA5SgI0zk4O4gPMN_BOuERmc,10854
|
|
43
43
|
qlever/commands/status.py,sha256=TtnBqcdkF3zTDKft07zpVcIX7kFu7d_nOy9b6Ohh9vQ,1650
|
|
44
|
-
qlever/commands/stop.py,sha256=
|
|
44
|
+
qlever/commands/stop.py,sha256=5BNKArOzoJ8kYiTVAmtN81w7nQ42fkxISgsxL-qJpO0,3463
|
|
45
45
|
qlever/commands/system_info.py,sha256=I84EKgMO5J8pvsTDhkVKHzsRLtPajNg9KTQN5kWjqLU,4660
|
|
46
|
-
qlever/commands/ui.py,sha256=
|
|
46
|
+
qlever/commands/ui.py,sha256=32DxXXrYEO4Ou9M3azWpPHzwCsPYvWuR9hBfliVJ2WM,9762
|
|
47
47
|
qlever/commands/warmup.py,sha256=kJHzS7HJo8pD2CphJuaXDj_CYP02YDo2DVM-pun3A80,1029
|
|
48
|
-
qlever-0.5.
|
|
49
|
-
qlever-0.5.
|
|
50
|
-
qlever-0.5.
|
|
51
|
-
qlever-0.5.
|
|
52
|
-
qlever-0.5.
|
|
53
|
-
qlever-0.5.
|
|
48
|
+
qlever-0.5.23.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
49
|
+
qlever-0.5.23.dist-info/METADATA,sha256=mLvI_U3eUeLxMSDSjk96eFa8HqH7Gv6grntGeVcDeJM,4652
|
|
50
|
+
qlever-0.5.23.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
|
|
51
|
+
qlever-0.5.23.dist-info/entry_points.txt,sha256=U_1U6SFIEZ-AnNlvk2nzcL0e4jnjEpuSbxYZ_E0XpEg,51
|
|
52
|
+
qlever-0.5.23.dist-info/top_level.txt,sha256=kd3zsYqiFd0--Czh5XTVkfEq6XR-XgRFW35X0v0GT-c,7
|
|
53
|
+
qlever-0.5.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|