fm-weck 1.4.5__py3-none-any.whl → 1.4.7__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.
- fm_weck/__init__.py +1 -1
- fm_weck/__main__.py +1 -0
- fm_weck/cache_mgr.py +47 -0
- fm_weck/cli.py +136 -27
- fm_weck/config.py +31 -17
- fm_weck/engine.py +110 -32
- fm_weck/exceptions.py +1 -0
- fm_weck/image_mgr.py +5 -4
- fm_weck/resources/{BenchExec-3.25-py3-none-any.whl → BenchExec-3.27-py3-none-any.whl} +0 -0
- fm_weck/resources/__init__.py +14 -12
- fm_weck/resources/fm_tools/2ls.yml +32 -7
- fm_weck/resources/fm_tools/aise.yml +6 -1
- fm_weck/resources/fm_tools/aprove.yml +73 -72
- fm_weck/resources/fm_tools/blast.yml +58 -0
- fm_weck/resources/fm_tools/brick.yml +4 -4
- fm_weck/resources/fm_tools/bubaak-split.yml +3 -3
- fm_weck/resources/fm_tools/bubaak.yml +4 -4
- fm_weck/resources/fm_tools/cadp.yml +95 -0
- fm_weck/resources/fm_tools/cbmc.yml +8 -4
- fm_weck/resources/fm_tools/cetfuzz.yml +4 -3
- fm_weck/resources/fm_tools/coastal.yml +13 -8
- fm_weck/resources/fm_tools/concurrentwitness2test.yml +4 -1
- fm_weck/resources/fm_tools/cooperace.yml +7 -6
- fm_weck/resources/fm_tools/coveriteam-verifier-algo-selection.yml +9 -20
- fm_weck/resources/fm_tools/coveriteam-verifier-parallel-portfolio.yml +9 -20
- fm_weck/resources/fm_tools/coveritest.yml +27 -6
- fm_weck/resources/fm_tools/cpa-bam-bnb.yml +13 -9
- fm_weck/resources/fm_tools/cpa-bam-smg.yml +12 -7
- fm_weck/resources/fm_tools/cpa-lockator.yml +13 -9
- fm_weck/resources/fm_tools/cpa-witness2test.yml +13 -3
- fm_weck/resources/fm_tools/cpachecker.yml +3 -3
- fm_weck/resources/fm_tools/cpv.yml +2 -0
- fm_weck/resources/fm_tools/crux.yml +20 -8
- fm_weck/resources/fm_tools/cseq.yml +9 -4
- fm_weck/resources/fm_tools/dartagnan.yml +12 -1
- fm_weck/resources/fm_tools/deagle.yml +5 -0
- fm_weck/resources/fm_tools/divine.yml +20 -11
- fm_weck/resources/fm_tools/ebf.yml +8 -5
- fm_weck/resources/fm_tools/emergentheta.yml +9 -2
- fm_weck/resources/fm_tools/esbmc-incr.yml +13 -10
- fm_weck/resources/fm_tools/esbmc-kind.yml +12 -11
- fm_weck/resources/fm_tools/fdse.yml +1 -1
- fm_weck/resources/fm_tools/fizzer.yml +15 -24
- fm_weck/resources/fm_tools/frama-c-sv.yml +3 -2
- fm_weck/resources/fm_tools/fshell-witness2test.yml +9 -6
- fm_weck/resources/fm_tools/fusebmc-ia.yml +6 -3
- fm_weck/resources/fm_tools/fusebmc.yml +26 -6
- fm_weck/resources/fm_tools/gazer-theta.yml +10 -7
- fm_weck/resources/fm_tools/gdart-llvm.yml +8 -4
- fm_weck/resources/fm_tools/gdart.yml +3 -0
- fm_weck/resources/fm_tools/goblint.yml +7 -2
- fm_weck/resources/fm_tools/graves-par.yml +9 -14
- fm_weck/resources/fm_tools/graves.yml +10 -4
- fm_weck/resources/fm_tools/gwit.yml +10 -4
- fm_weck/resources/fm_tools/hornix.yml +12 -7
- fm_weck/resources/fm_tools/hybridtiger.yml +13 -8
- fm_weck/resources/fm_tools/infer.yml +12 -7
- fm_weck/resources/fm_tools/java-ranger.yml +6 -3
- fm_weck/resources/fm_tools/jayhorn.yml +6 -4
- fm_weck/resources/fm_tools/jbmc.yml +11 -2
- fm_weck/resources/fm_tools/jcwit.yml +9 -5
- fm_weck/resources/fm_tools/jdart.yml +12 -7
- fm_weck/resources/fm_tools/klee.yml +13 -8
- fm_weck/resources/fm_tools/kleef.yml +3 -3
- fm_weck/resources/fm_tools/korn.yml +11 -1
- fm_weck/resources/fm_tools/lazycseq.yml +10 -7
- fm_weck/resources/fm_tools/legion-symcc.yml +6 -12
- fm_weck/resources/fm_tools/legion.yml +9 -14
- fm_weck/resources/fm_tools/lf-checker.yml +10 -6
- fm_weck/resources/fm_tools/liv.yml +19 -4
- fm_weck/resources/fm_tools/locksmith.yml +10 -6
- fm_weck/resources/fm_tools/ltsmin.yml +40 -0
- fm_weck/resources/fm_tools/metaval++.yml +19 -3
- fm_weck/resources/fm_tools/metaval.yml +21 -3
- fm_weck/resources/fm_tools/mlb.yml +5 -5
- fm_weck/resources/fm_tools/mopsa.yml +9 -7
- fm_weck/resources/fm_tools/nacpa.yml +7 -1
- fm_weck/resources/fm_tools/nitwit.yml +5 -3
- fm_weck/resources/fm_tools/owic.yml +4 -3
- fm_weck/resources/fm_tools/pesco.yml +10 -4
- fm_weck/resources/fm_tools/pichecker.yml +10 -6
- fm_weck/resources/fm_tools/pinaka.yml +13 -8
- fm_weck/resources/fm_tools/predatorhp.yml +6 -4
- fm_weck/resources/fm_tools/prism.yml +67 -0
- fm_weck/resources/fm_tools/proton.yml +6 -6
- fm_weck/resources/fm_tools/prtest.yml +22 -6
- fm_weck/resources/fm_tools/racerf.yml +14 -5
- fm_weck/resources/fm_tools/relay-sv.yml +8 -13
- fm_weck/resources/fm_tools/rizzer.yml +8 -12
- fm_weck/resources/fm_tools/schema.yml +56 -3
- fm_weck/resources/fm_tools/sikraken.yml +3 -3
- fm_weck/resources/fm_tools/spf.yml +13 -8
- fm_weck/resources/fm_tools/sv-sanitizers.yml +3 -1
- fm_weck/resources/fm_tools/svf-svc.yml +15 -6
- fm_weck/resources/fm_tools/symbiotic-witch.yml +9 -5
- fm_weck/resources/fm_tools/symbiotic.yml +6 -2
- fm_weck/resources/fm_tools/testcov.yml +8 -8
- fm_weck/resources/fm_tools/theta.yml +8 -4
- fm_weck/resources/fm_tools/thorn.yml +3 -1
- fm_weck/resources/fm_tools/tracerx-wp.yml +11 -2
- fm_weck/resources/fm_tools/tracerx.yml +5 -1
- fm_weck/resources/fm_tools/uautomizer.yml +7 -12
- fm_weck/resources/fm_tools/ugemcutter.yml +8 -2
- fm_weck/resources/fm_tools/ukojak.yml +5 -2
- fm_weck/resources/fm_tools/ureferee.yml +3 -4
- fm_weck/resources/fm_tools/utaipan.yml +8 -2
- fm_weck/resources/fm_tools/utestgen.yml +11 -3
- fm_weck/resources/fm_tools/vercors.yml +94 -0
- fm_weck/resources/fm_tools/veriabs.yml +11 -9
- fm_weck/resources/fm_tools/veriabsl.yml +10 -8
- fm_weck/resources/fm_tools/verifuzz.yml +16 -266
- fm_weck/resources/fm_tools/verioover.yml +10 -6
- fm_weck/resources/fm_tools/wasp-c.yml +6 -4
- fm_weck/resources/fm_tools/wit4java.yml +20 -13
- fm_weck/resources/fm_tools/witch.yml +8 -4
- fm_weck/resources/fm_tools/witnesslint.yml +37 -9
- fm_weck/resources/fm_tools/witnessmap.yml +16 -1
- fm_weck/run_result.py +38 -0
- fm_weck/runexec_mode.py +15 -4
- fm_weck/serve.py +119 -22
- fm_weck/version_listing.py +25 -0
- {fm_weck-1.4.5.dist-info → fm_weck-1.4.7.dist-info}/METADATA +5 -3
- fm_weck-1.4.7.dist-info/RECORD +154 -0
- {fm_weck-1.4.5.dist-info → fm_weck-1.4.7.dist-info}/WHEEL +1 -1
- fm_weck-1.4.5.dist-info/RECORD +0 -146
- /fm_weck/resources/{BenchExec-3.25-py3-none-any.whl.license → BenchExec-3.27-py3-none-any.whl.license} +0 -0
- {fm_weck-1.4.5.dist-info → fm_weck-1.4.7.dist-info}/entry_points.txt +0 -0
fm_weck/__init__.py
CHANGED
fm_weck/__main__.py
CHANGED
fm_weck/cache_mgr.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# This file is part of fm-weck: executing fm-tools in containerized environments.
|
|
2
|
+
# https://gitlab.com/sosy-lab/software/fm-weck
|
|
3
|
+
#
|
|
4
|
+
# SPDX-FileCopyrightText: 2024 Dirk Beyer <https://www.sosy-lab.org>
|
|
5
|
+
#
|
|
6
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
import shutil
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def ask_and_clear(cache_location: str):
|
|
16
|
+
response = (
|
|
17
|
+
input(f"The following cache location will be deleted: {cache_location}\nDo you want to proceed? (Y/n): ")
|
|
18
|
+
.strip()
|
|
19
|
+
.lower()
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
if response == "y":
|
|
23
|
+
clear_cache(cache_location)
|
|
24
|
+
elif response == "n":
|
|
25
|
+
return
|
|
26
|
+
else:
|
|
27
|
+
logger.error(f"Unknown command '{response}'\n")
|
|
28
|
+
ask_and_clear(cache_location)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def clear_cache(cache_location: str):
|
|
32
|
+
if not cache_location:
|
|
33
|
+
logger.error("Cache location is unknown.")
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
if os.path.isdir(cache_location):
|
|
37
|
+
for item in os.listdir(cache_location):
|
|
38
|
+
item_path = os.path.join(cache_location, item)
|
|
39
|
+
try:
|
|
40
|
+
if os.path.isdir(item_path):
|
|
41
|
+
shutil.rmtree(item_path)
|
|
42
|
+
else:
|
|
43
|
+
os.remove(item_path)
|
|
44
|
+
except Exception as e:
|
|
45
|
+
logger.error(f"Error removing {item_path}: {e}")
|
|
46
|
+
else:
|
|
47
|
+
logger.error(f"The path {cache_location} is not a valid directory.")
|
fm_weck/cli.py
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#
|
|
6
6
|
# SPDX-License-Identifier: Apache-2.0
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
import argparse
|
|
9
10
|
import logging
|
|
10
11
|
import os
|
|
@@ -12,26 +13,31 @@ from argparse import Namespace
|
|
|
12
13
|
from dataclasses import dataclass
|
|
13
14
|
from functools import cache
|
|
14
15
|
from pathlib import Path
|
|
15
|
-
from typing import Any, Callable, Optional, Tuple, Union
|
|
16
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional, Tuple, Union
|
|
16
17
|
|
|
17
18
|
try:
|
|
18
19
|
from fm_tools.benchexec_helper import DataModel
|
|
19
20
|
except ImportError:
|
|
20
21
|
from enum import Enum
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
"""
|
|
24
|
-
Enum representing the data model of the tool.
|
|
25
|
-
"""
|
|
23
|
+
if not TYPE_CHECKING:
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
class DataModel(Enum):
|
|
26
|
+
"""
|
|
27
|
+
Enum representing the data model of the tool.
|
|
28
|
+
"""
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
LP64 = "LP64"
|
|
31
|
+
ILP32 = "ILP32"
|
|
32
32
|
|
|
33
|
+
def __str__(self):
|
|
34
|
+
return self.value
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
import contextlib
|
|
33
38
|
|
|
34
39
|
from fm_weck import Config
|
|
40
|
+
from fm_weck.cache_mgr import ask_and_clear, clear_cache
|
|
35
41
|
from fm_weck.config import _SEARCH_ORDER
|
|
36
42
|
from fm_weck.resources import iter_fm_data, iter_properties
|
|
37
43
|
|
|
@@ -61,7 +67,49 @@ class ToolQualifier:
|
|
|
61
67
|
return
|
|
62
68
|
|
|
63
69
|
|
|
64
|
-
|
|
70
|
+
class ShellCompletion:
|
|
71
|
+
@staticmethod
|
|
72
|
+
def properties_completer(prefix, parsed_args, **kwargs):
|
|
73
|
+
return list_known_properties()
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def versions_completer(prefix, parsed_args, **kwargs):
|
|
77
|
+
return list_known_tools()
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def tool_completer(prefix, parsed_args, **kwargs):
|
|
81
|
+
try:
|
|
82
|
+
import yaml
|
|
83
|
+
except ImportError:
|
|
84
|
+
logger.error("PyYAML is not installed. Cannot complete tool names.")
|
|
85
|
+
return []
|
|
86
|
+
|
|
87
|
+
tools_and_versions: dict[str, list] = {}
|
|
88
|
+
|
|
89
|
+
for tool_path in iter_fm_data():
|
|
90
|
+
with open(tool_path) as stream:
|
|
91
|
+
tool_data = yaml.safe_load(stream)
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
versions = [version_data["version"] for version_data in tool_data["versions"]]
|
|
95
|
+
except KeyError:
|
|
96
|
+
continue
|
|
97
|
+
tools_and_versions[tool_data["name"]] = versions
|
|
98
|
+
|
|
99
|
+
tools_and_versions_list = [
|
|
100
|
+
f"{tool.lower()}:{version}" for tool, versions in tools_and_versions.items() for version in versions
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
selected_tools = set([tool.split(":")[0] for tool in tools_and_versions_list if tool.startswith(prefix)])
|
|
104
|
+
if len(selected_tools) == 1:
|
|
105
|
+
# If exactly one tool has been selected, suggest versions
|
|
106
|
+
return [tool for tool in tools_and_versions_list if tool.startswith(prefix)]
|
|
107
|
+
|
|
108
|
+
# If no tool has been selected, suggest tool names
|
|
109
|
+
return selected_tools
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def add_tool_arg(parser, nargs: str | None = "?"):
|
|
65
113
|
parser.add_argument(
|
|
66
114
|
"TOOL",
|
|
67
115
|
help="The tool to obtain the container from. Can be the form <tool>:<version>. "
|
|
@@ -69,14 +117,15 @@ def add_tool_arg(parser, nargs="?"):
|
|
|
69
117
|
"the path to a fm-tools yaml file.",
|
|
70
118
|
type=ToolQualifier,
|
|
71
119
|
nargs=nargs,
|
|
72
|
-
)
|
|
120
|
+
).completer = ShellCompletion.tool_completer
|
|
73
121
|
|
|
74
122
|
|
|
75
123
|
def add_shared_args_for_run_modes(parser):
|
|
76
124
|
parser.add_argument(
|
|
77
|
-
"--
|
|
125
|
+
"--offline",
|
|
78
126
|
action="store_true",
|
|
79
|
-
help="
|
|
127
|
+
help="Run the tools offline. The offline mode assumes that both the tool and its info-module are located "
|
|
128
|
+
"at the location specified by the config's 'cache_location' field.",
|
|
80
129
|
)
|
|
81
130
|
|
|
82
131
|
add_tool_arg(parser, nargs=None)
|
|
@@ -149,7 +198,7 @@ def parse(raw_args: list[str]) -> Tuple[Callable[[], None], Namespace]:
|
|
|
149
198
|
),
|
|
150
199
|
required=False,
|
|
151
200
|
default=None,
|
|
152
|
-
)
|
|
201
|
+
).completer = ShellCompletion.properties_completer # type: ignore[assignment]
|
|
153
202
|
|
|
154
203
|
run.add_argument(
|
|
155
204
|
"-d",
|
|
@@ -178,7 +227,7 @@ def parse(raw_args: list[str]) -> Tuple[Callable[[], None], Namespace]:
|
|
|
178
227
|
"argument_list",
|
|
179
228
|
metavar="args",
|
|
180
229
|
nargs="*",
|
|
181
|
-
help="Additional arguments for the fm-tool.
|
|
230
|
+
help="Additional arguments for the fm-tool. To add them, separate them with '--' from the files.",
|
|
182
231
|
)
|
|
183
232
|
run.set_defaults(main=main_run)
|
|
184
233
|
|
|
@@ -248,6 +297,32 @@ def parse(raw_args: list[str]) -> Tuple[Callable[[], None], Namespace]:
|
|
|
248
297
|
runexec.add_argument("argument_list", metavar="args", nargs="*", help="Arguments for runexec.")
|
|
249
298
|
runexec.set_defaults(main=main_runexec)
|
|
250
299
|
|
|
300
|
+
clear_cache = subparsers.add_parser("clear-cache", help="Clear the cache directory.")
|
|
301
|
+
clear_cache.add_argument(
|
|
302
|
+
"--yes",
|
|
303
|
+
"-y",
|
|
304
|
+
"-Y",
|
|
305
|
+
action="store_true",
|
|
306
|
+
help="Add automatic approval for clearing the cache.",
|
|
307
|
+
required=False,
|
|
308
|
+
default=False,
|
|
309
|
+
)
|
|
310
|
+
clear_cache.set_defaults(main=main_clear_cache)
|
|
311
|
+
|
|
312
|
+
versions = subparsers.add_parser("versions", help="Show the versions of the chosen tool(s).")
|
|
313
|
+
versions.add_argument(
|
|
314
|
+
"TOOL",
|
|
315
|
+
help="The tool(s) for which to print the versions.",
|
|
316
|
+
type=ToolQualifier,
|
|
317
|
+
nargs="+",
|
|
318
|
+
).completer = ShellCompletion.versions_completer # type: ignore[assignment]
|
|
319
|
+
versions.set_defaults(main=main_versions)
|
|
320
|
+
|
|
321
|
+
with contextlib.suppress(ImportError):
|
|
322
|
+
import argcomplete
|
|
323
|
+
|
|
324
|
+
argcomplete.autocomplete(parser)
|
|
325
|
+
|
|
251
326
|
def help_callback():
|
|
252
327
|
parser.print_help()
|
|
253
328
|
|
|
@@ -295,7 +370,7 @@ def resolve_tool(tool: ToolQualifier) -> Path:
|
|
|
295
370
|
if (as_path := Path(tool_name)).exists() and as_path.is_file():
|
|
296
371
|
return as_path
|
|
297
372
|
|
|
298
|
-
return fm_tools_choice_map()[tool_name]
|
|
373
|
+
return fm_tools_choice_map()[str(tool_name)]
|
|
299
374
|
|
|
300
375
|
|
|
301
376
|
def resolve_property(prop_name: str) -> Path:
|
|
@@ -333,22 +408,25 @@ def main_run(args: argparse.Namespace):
|
|
|
333
408
|
logger.error("Unknown property %s", args.property)
|
|
334
409
|
return 1
|
|
335
410
|
|
|
336
|
-
|
|
411
|
+
result = run_guided(
|
|
337
412
|
fm_tool=fm_data,
|
|
338
413
|
version=args.TOOL.version,
|
|
339
414
|
configuration=Config(),
|
|
340
415
|
prop=property_path,
|
|
416
|
+
witness=Path(args.witness) if args.witness else None,
|
|
341
417
|
program_files=args.files,
|
|
342
418
|
additional_args=args.argument_list,
|
|
343
419
|
data_model=args.data_model,
|
|
344
|
-
|
|
420
|
+
offline_mode=args.offline,
|
|
345
421
|
)
|
|
346
422
|
|
|
423
|
+
return result.exit_code
|
|
424
|
+
|
|
347
425
|
|
|
348
426
|
def main_runexec(args: argparse.Namespace):
|
|
349
427
|
from .runexec_mode import run_runexec
|
|
350
428
|
|
|
351
|
-
|
|
429
|
+
result = run_runexec(
|
|
352
430
|
benchexec_package=args.benchexec_package,
|
|
353
431
|
use_image=args.use_image,
|
|
354
432
|
configuration=Config(),
|
|
@@ -356,6 +434,8 @@ def main_runexec(args: argparse.Namespace):
|
|
|
356
434
|
command=args.argument_list,
|
|
357
435
|
)
|
|
358
436
|
|
|
437
|
+
return result.exit_code
|
|
438
|
+
|
|
359
439
|
|
|
360
440
|
def main_manual(args: argparse.Namespace):
|
|
361
441
|
from .serve import run_manual
|
|
@@ -369,20 +449,19 @@ def main_manual(args: argparse.Namespace):
|
|
|
369
449
|
logger.error("Unknown tool %s", args.TOOL)
|
|
370
450
|
return 1
|
|
371
451
|
|
|
372
|
-
|
|
452
|
+
result = run_manual(
|
|
373
453
|
fm_tool=fm_data,
|
|
374
454
|
version=args.TOOL.version,
|
|
375
455
|
configuration=Config(),
|
|
376
456
|
command=args.argument_list,
|
|
377
|
-
|
|
457
|
+
offline_mode=args.offline,
|
|
378
458
|
)
|
|
379
459
|
|
|
460
|
+
return result.exit_code
|
|
380
461
|
|
|
381
|
-
def main_install(args: argparse.Namespace):
|
|
382
|
-
from .serve import setup_fm_tool
|
|
383
462
|
|
|
384
|
-
|
|
385
|
-
|
|
463
|
+
def main_install(args: argparse.Namespace):
|
|
464
|
+
from .serve import install_fm_tool
|
|
386
465
|
|
|
387
466
|
for tool in args.TOOL:
|
|
388
467
|
try:
|
|
@@ -391,10 +470,11 @@ def main_install(args: argparse.Namespace):
|
|
|
391
470
|
logger.error("Unknown tool %s. Skipping installation...", tool)
|
|
392
471
|
continue
|
|
393
472
|
|
|
394
|
-
|
|
473
|
+
install_fm_tool(
|
|
395
474
|
fm_tool=fm_data,
|
|
396
475
|
version=tool.version,
|
|
397
476
|
configuration=Config(),
|
|
477
|
+
install_path=args.destination
|
|
398
478
|
)
|
|
399
479
|
|
|
400
480
|
return 0
|
|
@@ -413,7 +493,35 @@ def main_shell(args: argparse.Namespace):
|
|
|
413
493
|
return 1
|
|
414
494
|
engine = Engine.from_config(fm_data, args.TOOL.version, Config())
|
|
415
495
|
engine.interactive = True
|
|
416
|
-
|
|
496
|
+
result = engine.run(args.entry)
|
|
497
|
+
return result.exit_code
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def main_clear_cache(args: argparse.Namespace):
|
|
501
|
+
if args.yes:
|
|
502
|
+
clear_cache(Config().get("defaults", {}).get("cache_location")) # type: ignore
|
|
503
|
+
else:
|
|
504
|
+
ask_and_clear(Config().get("defaults", {}).get("cache_location")) # type: ignore
|
|
505
|
+
return
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def main_versions(args: argparse.Namespace):
|
|
509
|
+
from .version_listing import VersionListing
|
|
510
|
+
|
|
511
|
+
tools = args.TOOL
|
|
512
|
+
tool_paths = []
|
|
513
|
+
if not args.TOOL:
|
|
514
|
+
logger.error("No fm-tool given. Aborting...")
|
|
515
|
+
return 1
|
|
516
|
+
|
|
517
|
+
for tool in tools:
|
|
518
|
+
try:
|
|
519
|
+
tool_paths.append(resolve_tool(tool))
|
|
520
|
+
except KeyError:
|
|
521
|
+
logger.error("Unknown tool %s", tool)
|
|
522
|
+
return 1
|
|
523
|
+
|
|
524
|
+
VersionListing(tool_paths).print_versions()
|
|
417
525
|
|
|
418
526
|
|
|
419
527
|
def log_no_image_error(tool, config):
|
|
@@ -462,6 +570,7 @@ to your .fm-weck file.
|
|
|
462
570
|
def cli(raw_args: list[str]):
|
|
463
571
|
help_callback, args = parse(raw_args)
|
|
464
572
|
configuration = Config().load(args.config)
|
|
573
|
+
|
|
465
574
|
set_log_options(args.loglevel, args.logfile, configuration)
|
|
466
575
|
if args.dry_run:
|
|
467
576
|
Config().set_dry_run(True)
|
fm_weck/config.py
CHANGED
|
@@ -13,21 +13,29 @@ import stat
|
|
|
13
13
|
import sys
|
|
14
14
|
from functools import cache
|
|
15
15
|
from pathlib import Path
|
|
16
|
-
from typing import Any, Callable, Iterable, Optional, Tuple, TypeVar
|
|
16
|
+
from typing import TYPE_CHECKING, Any, Callable, Iterable, Optional, Tuple, TypeVar
|
|
17
|
+
|
|
18
|
+
from werkzeug.utils import secure_filename
|
|
17
19
|
|
|
18
20
|
try:
|
|
19
|
-
from fm_tools.
|
|
21
|
+
from fm_tools.fmtool import FmTool
|
|
22
|
+
from fm_tools.fmtoolversion import FmToolVersion
|
|
20
23
|
except ImportError:
|
|
24
|
+
if not TYPE_CHECKING:
|
|
25
|
+
|
|
26
|
+
class FmTool:
|
|
27
|
+
def __init__(self, data):
|
|
28
|
+
raise ImportError("fm_tools is not imported.")
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
class FmToolVersion:
|
|
31
|
+
def __init__(self, data: FmTool, version: str):
|
|
32
|
+
raise ImportError("fm_tools is not imported.")
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
def get_actor_name(self):
|
|
35
|
+
raise ImportError("fm_tools is not imported.")
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
def get_version(self):
|
|
38
|
+
raise ImportError("fm_tools is not imported.")
|
|
31
39
|
|
|
32
40
|
|
|
33
41
|
from fm_weck.resources import RUN_WITH_OVERLAY, RUNEXEC_SCRIPT
|
|
@@ -35,7 +43,7 @@ from fm_weck.resources import RUN_WITH_OVERLAY, RUNEXEC_SCRIPT
|
|
|
35
43
|
try:
|
|
36
44
|
import tomllib as toml
|
|
37
45
|
except ImportError:
|
|
38
|
-
import tomli as toml
|
|
46
|
+
import tomli as toml # type: ignore
|
|
39
47
|
|
|
40
48
|
_SEARCH_ORDER: tuple[Path, ...] = (
|
|
41
49
|
Path.cwd() / ".fm-weck",
|
|
@@ -121,7 +129,7 @@ class Config(object):
|
|
|
121
129
|
return self.defaults().get(key, None)
|
|
122
130
|
|
|
123
131
|
@staticmethod
|
|
124
|
-
def _handle_relative_paths(fn: Callable[
|
|
132
|
+
def _handle_relative_paths(fn: Callable[..., Path]) -> Callable[..., Path]:
|
|
125
133
|
def wrapper(self, *args, **kwargs) -> Path:
|
|
126
134
|
"""Makes sure relative Paths in the config are relative to the config file."""
|
|
127
135
|
|
|
@@ -159,9 +167,15 @@ class Config(object):
|
|
|
159
167
|
def get_checksum_db(self) -> Path:
|
|
160
168
|
return self.cache_location / ".checksums.dbm"
|
|
161
169
|
|
|
162
|
-
def get_shelve_space_for(self, fm_data:
|
|
170
|
+
def get_shelve_space_for(self, fm_data: FmToolVersion) -> Path:
|
|
163
171
|
shelve = self.cache_location
|
|
164
|
-
|
|
172
|
+
# Remove leading http:// or https:// from the raw archive location
|
|
173
|
+
raw_location = fm_data.get_archive_location().raw
|
|
174
|
+
if raw_location.startswith("http://"):
|
|
175
|
+
raw_location = raw_location[len("http://") :]
|
|
176
|
+
elif raw_location.startswith("https://"):
|
|
177
|
+
raw_location = raw_location[len("https://") :]
|
|
178
|
+
tool_name = secure_filename(raw_location)
|
|
165
179
|
return shelve / tool_name
|
|
166
180
|
|
|
167
181
|
def get_shelve_path_for_property(self, path: Path) -> Path:
|
|
@@ -179,10 +193,10 @@ class Config(object):
|
|
|
179
193
|
def _system_is_not_posix():
|
|
180
194
|
return not (sys.platform.startswith("linux") or sys.platform == "darwin")
|
|
181
195
|
|
|
182
|
-
def make_runexec_script_available(self) -> Path:
|
|
196
|
+
def make_runexec_script_available(self) -> Path | None:
|
|
183
197
|
return self.make_script_available(RUNEXEC_SCRIPT)
|
|
184
198
|
|
|
185
|
-
def make_script_available(self, target_name: str = RUN_WITH_OVERLAY) -> Path:
|
|
199
|
+
def make_script_available(self, target_name: str = RUN_WITH_OVERLAY) -> Path | None:
|
|
186
200
|
script_dir = self.cache_location / ".scripts"
|
|
187
201
|
target = script_dir / target_name
|
|
188
202
|
|
|
@@ -224,7 +238,7 @@ class Config(object):
|
|
|
224
238
|
|
|
225
239
|
|
|
226
240
|
@cache
|
|
227
|
-
def parse_fm_data(fm_data: Path, version:
|
|
241
|
+
def parse_fm_data(fm_data: Path, version: str | None) -> FmToolVersion:
|
|
228
242
|
import yaml
|
|
229
243
|
|
|
230
244
|
if not fm_data.exists() or not fm_data.is_file():
|
|
@@ -233,4 +247,4 @@ def parse_fm_data(fm_data: Path, version: Optional[str]) -> FmData:
|
|
|
233
247
|
with fm_data.open("rb") as f:
|
|
234
248
|
data = yaml.safe_load(f)
|
|
235
249
|
|
|
236
|
-
return
|
|
250
|
+
return FmToolVersion(data, version)
|