fm-weck 1.4.6__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 CHANGED
@@ -8,4 +8,4 @@
8
8
  from .config import Config # noqa: F401
9
9
  from .image_mgr import ImageMgr # noqa: F401
10
10
 
11
- __version__ = "1.4.6"
11
+ __version__ = "1.4.7"
fm_weck/cli.py CHANGED
@@ -13,23 +13,25 @@ from argparse import Namespace
13
13
  from dataclasses import dataclass
14
14
  from functools import cache
15
15
  from pathlib import Path
16
- from typing import Any, Callable, Optional, Tuple, Union
16
+ from typing import TYPE_CHECKING, Any, Callable, Optional, Tuple, Union
17
17
 
18
18
  try:
19
19
  from fm_tools.benchexec_helper import DataModel
20
20
  except ImportError:
21
21
  from enum import Enum
22
22
 
23
- class DataModel(Enum):
24
- """
25
- Enum representing the data model of the tool.
26
- """
23
+ if not TYPE_CHECKING:
27
24
 
28
- LP64 = "LP64"
29
- ILP32 = "ILP32"
25
+ class DataModel(Enum):
26
+ """
27
+ Enum representing the data model of the tool.
28
+ """
30
29
 
31
- def __str__(self):
32
- return self.value
30
+ LP64 = "LP64"
31
+ ILP32 = "ILP32"
32
+
33
+ def __str__(self):
34
+ return self.value
33
35
 
34
36
 
35
37
  import contextlib
@@ -107,7 +109,7 @@ class ShellCompletion:
107
109
  return selected_tools
108
110
 
109
111
 
110
- def add_tool_arg(parser, nargs="?"):
112
+ def add_tool_arg(parser, nargs: str | None = "?"):
111
113
  parser.add_argument(
112
114
  "TOOL",
113
115
  help="The tool to obtain the container from. Can be the form <tool>:<version>. "
@@ -196,7 +198,7 @@ def parse(raw_args: list[str]) -> Tuple[Callable[[], None], Namespace]:
196
198
  ),
197
199
  required=False,
198
200
  default=None,
199
- ).completer = ShellCompletion.properties_completer
201
+ ).completer = ShellCompletion.properties_completer # type: ignore[assignment]
200
202
 
201
203
  run.add_argument(
202
204
  "-d",
@@ -313,7 +315,7 @@ def parse(raw_args: list[str]) -> Tuple[Callable[[], None], Namespace]:
313
315
  help="The tool(s) for which to print the versions.",
314
316
  type=ToolQualifier,
315
317
  nargs="+",
316
- ).completer = ShellCompletion.versions_completer
318
+ ).completer = ShellCompletion.versions_completer # type: ignore[assignment]
317
319
  versions.set_defaults(main=main_versions)
318
320
 
319
321
  with contextlib.suppress(ImportError):
@@ -368,7 +370,7 @@ def resolve_tool(tool: ToolQualifier) -> Path:
368
370
  if (as_path := Path(tool_name)).exists() and as_path.is_file():
369
371
  return as_path
370
372
 
371
- return fm_tools_choice_map()[tool_name]
373
+ return fm_tools_choice_map()[str(tool_name)]
372
374
 
373
375
 
374
376
  def resolve_property(prop_name: str) -> Path:
@@ -459,10 +461,7 @@ def main_manual(args: argparse.Namespace):
459
461
 
460
462
 
461
463
  def main_install(args: argparse.Namespace):
462
- from .serve import setup_fm_tool
463
-
464
- if args.destination:
465
- Config()._config["defaults"]["cache_location"] = args.destination.resolve()
464
+ from .serve import install_fm_tool
466
465
 
467
466
  for tool in args.TOOL:
468
467
  try:
@@ -471,10 +470,11 @@ def main_install(args: argparse.Namespace):
471
470
  logger.error("Unknown tool %s. Skipping installation...", tool)
472
471
  continue
473
472
 
474
- setup_fm_tool(
473
+ install_fm_tool(
475
474
  fm_tool=fm_data,
476
475
  version=tool.version,
477
476
  configuration=Config(),
477
+ install_path=args.destination
478
478
  )
479
479
 
480
480
  return 0
@@ -499,9 +499,9 @@ def main_shell(args: argparse.Namespace):
499
499
 
500
500
  def main_clear_cache(args: argparse.Namespace):
501
501
  if args.yes:
502
- clear_cache(Config().get("defaults").get("cache_location"))
502
+ clear_cache(Config().get("defaults", {}).get("cache_location")) # type: ignore
503
503
  else:
504
- ask_and_clear(Config().get("defaults").get("cache_location"))
504
+ ask_and_clear(Config().get("defaults", {}).get("cache_location")) # type: ignore
505
505
  return
506
506
 
507
507
 
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.fmdata import FmData
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
- class FmData:
23
- def __init__(self, data, version):
24
- raise ImportError("fm_tools is not imported.")
30
+ class FmToolVersion:
31
+ def __init__(self, data: FmTool, version: str):
32
+ raise ImportError("fm_tools is not imported.")
25
33
 
26
- def get_actor_name(self):
27
- raise ImportError("fm_tools is not imported.")
34
+ def get_actor_name(self):
35
+ raise ImportError("fm_tools is not imported.")
28
36
 
29
- def get_version(self):
30
- raise ImportError("fm_tools is not imported.")
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[[Any], Path]) -> Callable[[Any], Path]:
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: FmData) -> Path:
170
+ def get_shelve_space_for(self, fm_data: FmToolVersion) -> Path:
163
171
  shelve = self.cache_location
164
- tool_name = fm_data.get_actor_name() # safe to use in filesystem
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: Optional[str]) -> FmData:
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 FmData(data, version)
250
+ return FmToolVersion(data, version)
fm_weck/engine.py CHANGED
@@ -15,20 +15,25 @@ from abc import ABC, abstractmethod
15
15
  from functools import cached_property, singledispatchmethod
16
16
  from pathlib import Path
17
17
  from tempfile import mkdtemp
18
- from typing import Callable, List, Optional, Union
18
+ from typing import TYPE_CHECKING, Callable, Iterable, List, Optional, Union
19
19
 
20
20
  from fm_weck.run_result import RunResult
21
21
 
22
22
  try:
23
- from fm_tools.fmdata import FmData, FmImageConfig
23
+ from fm_tools.fmtoolversion import (
24
+ FmImageConfig, # type: ignore
25
+ FmToolVersion, # type: ignore
26
+ )
24
27
  except ImportError:
25
- # Mock the FmData and FmImageConfig class for type checking
26
- class FmData:
27
- def get_images(self):
28
- pass
28
+ # Mock the FmToolVersion and FmImageConfig class for type checking
29
+ if not TYPE_CHECKING:
29
30
 
30
- class FmImageConfig:
31
- pass
31
+ class FmImageConfig:
32
+ with_fallback: Callable[[str], "FmImageConfig"] # type: ignore
33
+
34
+ class FmToolVersion:
35
+ def get_images(self) -> "FmImageConfig": # type: ignore
36
+ pass
32
37
 
33
38
 
34
39
  from fm_weck.config import Config, parse_fm_data
@@ -157,7 +162,7 @@ class Engine(ABC):
157
162
  except shutil.Error as e:
158
163
  logger.warning(f"Error while copying the output {file} directory: {e}")
159
164
 
160
- def assemble_command(self, command: tuple[str, ...]) -> list[str]:
165
+ def assemble_command(self, command: Iterable[str]) -> list[str]:
161
166
  base = self.base_command()
162
167
  if self.add_benchexec_capabilities:
163
168
  base += self.benchexec_capabilities()
@@ -180,7 +185,7 @@ class Engine(ABC):
180
185
  _command = self._prep_command(command)
181
186
  return base + [self.image, *_command]
182
187
 
183
- def _prep_command(self, command: tuple[str, ...]) -> tuple[str, ...]:
188
+ def _prep_command(self, command: Iterable[str]) -> tuple[str | Path, ...]:
184
189
  """We want to map absolute paths of the current working directory to the
185
190
  working directory of the container."""
186
191
 
@@ -218,7 +223,7 @@ class Engine(ABC):
218
223
  def extract_image(fm: Union[str, Path], version: str, config: dict) -> str:
219
224
  image = config.get("defaults", {}).get("image", None)
220
225
 
221
- return parse_fm_data(fm, version).get_images().with_fallback(image)
226
+ return parse_fm_data(fm, version).get_images().with_fallback(image) # type: ignore
222
227
 
223
228
  @staticmethod
224
229
  def _base_engine_class(config: Config):
@@ -241,7 +246,7 @@ class Engine(ABC):
241
246
  @from_config.register
242
247
  @staticmethod
243
248
  def _(fm: Path, version: str, config: Config):
244
- image = Engine.extract_image(fm, version, config)
249
+ image = Engine.extract_image(fm, version, config) # type: ignore
245
250
  Base = Engine._base_engine_class(config)
246
251
  engine = Base(image)
247
252
  return Engine._prepare_engine(engine, config)
@@ -249,14 +254,14 @@ class Engine(ABC):
249
254
  @from_config.register
250
255
  @staticmethod
251
256
  def _(fm: str, version: str, config: Config):
252
- image = Engine.extract_image(fm, version, config)
257
+ image = Engine.extract_image(fm, version, config) # type: ignore
253
258
  Base = Engine._base_engine_class(config)
254
259
  engine = Base(image)
255
260
  return Engine._prepare_engine(engine, config)
256
261
 
257
262
  @from_config.register
258
263
  @staticmethod
259
- def _(fm: FmData, config: Config):
264
+ def _(fm: FmToolVersion, config: Config):
260
265
  image = fm.get_images().with_fallback(config.from_defaults_or_none("image"))
261
266
  Base = Engine._base_engine_class(config)
262
267
  engine = Base(image)
@@ -281,6 +286,8 @@ class Engine(ABC):
281
286
 
282
287
  class BuildCommand(ABC):
283
288
  build_args: List[str] = []
289
+ containerfile: Path
290
+ _engine: str
284
291
 
285
292
  @abstractmethod
286
293
  def __init__(self, containerfile: Path, **kwargs):
@@ -290,7 +297,7 @@ class Engine(ABC):
290
297
  self.build_args += ["--build-arg", f"BASE_IMAGE={image}"]
291
298
  return self
292
299
 
293
- def packages(self, packages: list[str]):
300
+ def packages(self, packages: Iterable[str]):
294
301
  self.build_args += ["--build-arg", f"REQUIRED_PACKAGES={' '.join(packages)}"]
295
302
  return self
296
303
 
@@ -342,7 +349,7 @@ class Engine(ABC):
342
349
  process.terminate()
343
350
  process.wait()
344
351
 
345
- return RunResult(command, process.returncode, io.StringIO())
352
+ return RunResult(command, process.returncode, "")
346
353
 
347
354
  def _run_process(self, command: tuple[str, ...] | list[str], timeout_sec: Optional[float] = None) -> RunResult:
348
355
  process = None # To make sure process is defined if a signal is caught early
@@ -363,16 +370,18 @@ class Engine(ABC):
363
370
 
364
371
  def run_and_poll(writer: Callable[[str], None]):
365
372
  while process.poll() is None:
373
+ if process.stdout is None:
374
+ continue
366
375
  line = process.stdout.readline().decode("utf-8")
367
376
  writer(line)
368
377
  if self.print_output_to_stdout:
369
378
  sys.stdout.write(line)
370
379
 
371
380
  if self.log_file is None:
372
- run_and_poll(full_stdout.write)
381
+ run_and_poll(full_stdout.write) # type: ignore
373
382
  else:
374
383
  with self.log_file.open("w") as log:
375
- run_and_poll(log.write)
384
+ run_and_poll(log.write) # type: ignore
376
385
 
377
386
  assert process is not None, "Process should be defined at this point."
378
387
  try:
@@ -391,12 +400,12 @@ class Engine(ABC):
391
400
  if self.image is None:
392
401
  raise NoImageError("No image set for engine.")
393
402
 
394
- command = self.assemble_command(command)
403
+ command = self.assemble_command(command) # type: ignore
395
404
  logger.debug("Running: %s", command)
396
405
  if self.dry_run:
397
406
  print("Command to be executed:")
398
407
  print(" ".join(map(str, command)))
399
- return 0, ""
408
+ return RunResult(command, 0, "Dry run: no command executed.")
400
409
 
401
410
  if self.interactive or not self.handle_io:
402
411
  return self._run_process_without_attaching_io(command, timeout_sec=timeout_sec)
fm_weck/image_mgr.py CHANGED
@@ -10,12 +10,13 @@ from pathlib import Path
10
10
  from typing import TYPE_CHECKING
11
11
 
12
12
  try:
13
- from fm_tools.fmdata import FmImageConfig
13
+ from fm_tools.fmtoolversion import FmImageConfig
14
14
  except ImportError:
15
+ if not TYPE_CHECKING:
15
16
 
16
- class FmImageConfig:
17
- def __init__(self, full_images, base_images, required_packages):
18
- raise ImportError("fm_tools is not imported.")
17
+ class FmImageConfig:
18
+ def __init__(self, full_images, base_images, required_packages):
19
+ raise ImportError("fm_tools is not imported.")
19
20
 
20
21
 
21
22
  from fm_weck.exceptions import NoImageError
@@ -5,28 +5,30 @@
5
5
  #
6
6
  # SPDX-License-Identifier: Apache-2.0
7
7
 
8
+ import importlib.resources as pkg_resources
8
9
  from pathlib import Path
9
10
 
10
- resource_dir = Path(__file__).parent
11
-
12
- CONTAINERFILE = resource_dir / "Containerfile"
11
+ from . import fm_tools, properties
13
12
 
14
13
  # During the build of the wheel file, the fm-tools/data directory is copied
15
14
  # to the wheel file under fm_weck/resources/fm_tools
16
- FM_DATA_LOCATION = resource_dir / "fm_tools"
17
- PROPERTY_LOCATION = resource_dir / "properties"
15
+
18
16
  RUN_WITH_OVERLAY = "run_with_overlay.sh"
19
- BENCHEXEC_WHL = resource_dir / "BenchExec-3.27-py3-none-any.whl"
17
+ BENCHEXEC_WHL = "BenchExec-3.25-py3-none-any.whl"
20
18
  RUNEXEC_SCRIPT = "runexec"
21
19
 
22
20
 
23
21
  def iter_fm_data():
24
- for fm_data in FM_DATA_LOCATION.iterdir():
25
- if fm_data.is_file() and (fm_data.name.endswith(".yml") or fm_data.name.endswith(".yaml")):
26
- yield fm_data
22
+ for fm_data in pkg_resources.contents(fm_tools):
23
+ with pkg_resources.path(fm_tools, fm_data) as fake_context_path:
24
+ fm_data_path = Path(fake_context_path)
25
+ if fm_data_path.is_file() and (fm_data_path.name.endswith(".yml") or fm_data_path.name.endswith(".yaml")):
26
+ yield fm_data_path
27
27
 
28
28
 
29
29
  def iter_properties():
30
- for prop in PROPERTY_LOCATION.iterdir():
31
- if prop.is_file():
32
- yield prop
30
+ for prop in pkg_resources.contents(properties):
31
+ with pkg_resources.path(properties, prop) as fake_context_path:
32
+ prop_path = Path(fake_context_path)
33
+ if prop_path.is_file():
34
+ yield prop_path
@@ -17,7 +17,7 @@ fmtools_entry_maintainers:
17
17
  - dbeyer
18
18
 
19
19
  maintainers:
20
- - orcid: 0000-0000-0000-0000
20
+ - orcid: 0009-0000-5304-8081
21
21
  name: Hubert Garavel
22
22
  institution: INRIA
23
23
  country: France
@@ -2,7 +2,7 @@ id: hybridtiger
2
2
  name: HybridTiger
3
3
  input_languages:
4
4
  - C
5
- project_url: https://www.es.tu-darmstadt.de/es/team/sebastian-ruland/testcomp20
5
+ project_url: https://gitlab.com/sosy-lab/software/cpachecker
6
6
  repository_url: https://gitlab.com/sosy-lab/software/cpachecker
7
7
  spdx_license_identifier: Apache-2.0
8
8
  benchexec_toolinfo_module: "https://gitlab.com/sosy-lab/software/benchexec/-/raw/main/benchexec/tools/cpachecker.py"
@@ -0,0 +1,40 @@
1
+ id: ltsmin
2
+ name: LTSmin
3
+ description: |
4
+ LTSmin is a language-independent model-checking toolset supporting
5
+ multiple input languages and advanced state-space generation techniques via a unified PINS interface.
6
+ It features modular architecture, symbolic/distributed/multi-core reachability,
7
+ and easy extensibility for new languages.
8
+ input_languages:
9
+ - PNML
10
+ project_url: https://ltsmin.utwente.nl/
11
+ repository_url: https://github.com/utwente-fmt/ltsmin
12
+ spdx_license_identifier: BSD-3-Clause
13
+ benchexec_toolinfo_module: "https://www.cip.ifi.lmu.de/~wachowitz/ltsmin.py"
14
+ fmtools_format_version: "2.0"
15
+ fmtools_entry_maintainers:
16
+ - dbeyer
17
+ - ricffb
18
+
19
+ maintainers:
20
+ - orcid: 0000-0002-2433-4174
21
+ name: Alfons Laarman
22
+ institution: Leiden Institute for Advanced Computer Science
23
+ country: Netherlands
24
+ url: https://alfons.laarman.com/
25
+
26
+ versions:
27
+ - version: "pnml2lts-sym-3.0.2"
28
+ url: "https://github.com/utwente-fmt/ltsmin/releases/download/v3.0.2/ltsmin-v3.0.2-linux.tgz"
29
+ benchexec_toolinfo_options: ["pnml2lts-sym"]
30
+ required_ubuntu_packages: []
31
+ base_container_image: ["ubuntu:24.04"]
32
+
33
+ competition_participations: []
34
+
35
+ techniques: []
36
+
37
+ frameworks_solvers: []
38
+
39
+ literature: []
40
+
@@ -1,5 +1,7 @@
1
1
  id: sv-sanitizers
2
- name: sv-sanitizers
2
+ name: SV-sanitizers
3
+ description: |
4
+ SV-COMP wrapper for sanitizers (ThreadSanitizer, AddressSanitizer, LeakSanitizer, UndefinedBehaviorSanitizer).
3
5
  input_languages:
4
6
  - C
5
7
  project_url: https://github.com/sim642/sv-sanitizers
fm_weck/run_result.py CHANGED
@@ -10,13 +10,13 @@ from functools import singledispatchmethod
10
10
 
11
11
  from benchexec.tools.template import BaseTool2
12
12
  from benchexec.util import ProcessExitCode
13
- from fm_tools import FmData
13
+ from fm_tools.fmtoolversion import FmToolVersion
14
14
  from fm_tools.run import get_tool_info
15
15
 
16
16
 
17
17
  @dataclass(frozen=True)
18
18
  class RunResult:
19
- command: tuple[str, ...]
19
+ command: tuple[str, ...] | list[str]
20
20
  exit_code: int
21
21
  raw_output: str
22
22
 
@@ -33,6 +33,6 @@ class RunResult:
33
33
  return tool.determine_result(self.as_benchexec_run())
34
34
 
35
35
  @determine_result.register
36
- def _(self, tool: FmData) -> str:
37
- tool = get_tool_info(tool)
38
- return self.determine_result(tool)
36
+ def _(self, tool: FmToolVersion) -> str:
37
+ tool_ = get_tool_info(tool)
38
+ return self.determine_result(tool_)
fm_weck/runexec_mode.py CHANGED
@@ -5,6 +5,7 @@
5
5
  #
6
6
  # SPDX-License-Identifier: Apache-2.0
7
7
 
8
+ import importlib.resources as pkg_resources
8
9
  import logging
9
10
  import shutil
10
11
  from pathlib import Path
@@ -42,8 +43,13 @@ def run_runexec(
42
43
  else:
43
44
  # Default to the bundled benchexec package
44
45
  benchexec_package = configuration.get_shelve_path_for_benchexec()
45
- shutil.copyfile(BENCHEXEC_WHL, benchexec_package)
46
- engine.env["PYTHONPATH"] = f"{CACHE_MOUNT_LOCATION}/.lib/benchexec.whl"
46
+ try:
47
+ with pkg_resources.path("fm_weck.resources", BENCHEXEC_WHL) as source_path:
48
+ shutil.copy(source_path, benchexec_package)
49
+ engine.env["PYTHONPATH"] = f"{CACHE_MOUNT_LOCATION}/.lib/benchexec.whl"
50
+ except FileNotFoundError:
51
+ logging.error(f"Resource {BENCHEXEC_WHL} not found in package.")
52
+ return None
47
53
 
48
54
  for path in mountable_absolute_paths_of_command(Path.cwd().absolute(), command):
49
55
  engine.mount(path, str(path) + ":ro")
fm_weck/serve.py CHANGED
@@ -6,6 +6,7 @@
6
6
  # SPDX-License-Identifier: Apache-2.0
7
7
 
8
8
  import dbm
9
+ import json
9
10
  import logging
10
11
  import os
11
12
  import shutil
@@ -13,8 +14,8 @@ import sys
13
14
  from pathlib import Path
14
15
  from typing import Optional, Tuple, Union
15
16
 
16
- from fm_tools import FmData
17
17
  from fm_tools.benchexec_helper import DataModel
18
+ from fm_tools.fmtoolversion import FmToolVersion
18
19
 
19
20
  from fm_weck.run_result import RunResult
20
21
 
@@ -60,12 +61,12 @@ def update_checksum(shelve_space: Path, checksum: str, config: Config):
60
61
 
61
62
 
62
63
  def setup_fm_tool(
63
- fm_tool: Union[Path, FmData],
64
+ fm_tool: Union[Path, FmToolVersion],
64
65
  version: Optional[str],
65
66
  configuration: Config,
66
67
  offline_mode: bool = False,
67
- ) -> Tuple[FmData, Path]:
68
- # Don't explicitly disallow non-FmData here; Pythonic Users might want to exchange the FmData object
68
+ ) -> Tuple[FmToolVersion, Path]:
69
+ # Don't explicitly disallow non-FmToolVersion here; Pythonic Users might want to exchange the FmToolVersion object
69
70
  # by a class with the same interface
70
71
  fm_data = parse_fm_data(fm_tool, version) if isinstance(fm_tool, (Path, str)) else fm_tool
71
72
 
@@ -75,14 +76,23 @@ def setup_fm_tool(
75
76
 
76
77
  if (not offline_mode) and shelve_space.exists() and shelve_space.is_dir():
77
78
  logger.debug("Shelve space already exists, testing checksum")
78
- checksum = fm_data.archive_location.checksum()
79
- skip_download = check_cache_entry(shelve_space, checksum, configuration)
79
+ checksum = fm_data.get_archive_location().resolve().checksum
80
+ if checksum is None:
81
+ logger.warning("No checksum available for %s, skipping cache check", fm_data.get_tool_name_with_version())
82
+ skip_download = False
83
+ else:
84
+ skip_download = check_cache_entry(shelve_space, checksum, configuration)
80
85
 
81
86
  if not skip_download:
82
87
  fm_data.download_and_install_into(shelve_space)
83
- checksum = fm_data.archive_location.checksum()
84
- update_checksum(shelve_space, checksum, configuration)
85
-
88
+ checksum = fm_data.get_archive_location().resolve().checksum
89
+ if checksum is None:
90
+ logger.warning(
91
+ "No checksum available for %s, skipping checksum update", fm_data.get_tool_name_with_version()
92
+ )
93
+ else:
94
+ update_checksum(shelve_space, checksum, configuration)
95
+ map_doi(fm_data, shelve_space)
86
96
  tool_info_module = fm_data.get_toolinfo_module()
87
97
 
88
98
  if (not offline_mode) or tool_info_module._trivially_resolved():
@@ -98,8 +108,18 @@ def setup_fm_tool(
98
108
  return fm_data, shelve_space
99
109
 
100
110
 
111
+ def install_fm_tool(
112
+ fm_tool: Union[Path, FmToolVersion], version: Optional[str], configuration: Config, install_path: Path
113
+ ) -> None:
114
+ fm_data = parse_fm_data(fm_tool, version) if isinstance(fm_tool, (Path, str)) else fm_tool
115
+ shelve_space = install_path.resolve() if install_path else configuration.get_shelve_space_for(fm_data)
116
+
117
+ logger.debug("Installing tool into %s", shelve_space)
118
+ fm_data.download_and_install_into(shelve_space)
119
+
120
+
101
121
  def run_guided(
102
- fm_tool: Union[Path, FmData],
122
+ fm_tool: Union[Path, FmToolVersion],
103
123
  version: Optional[str],
104
124
  configuration: Config,
105
125
  prop: Optional[Path],
@@ -123,7 +143,7 @@ def run_guided(
123
143
  shutil.copyfile(source_property_path, property_path)
124
144
  except KeyError:
125
145
  logger.error("Unknown property %s", prop)
126
- return 1, None
146
+ return RunResult(command=[], exit_code=1, raw_output="Unknown property")
127
147
 
128
148
  configuration.make_script_available()
129
149
 
@@ -157,7 +177,7 @@ def run_guided(
157
177
  # We are using the second approach here, in order to avoid modifying FM-Data
158
178
  if witness is not None:
159
179
  assert any(c == "${witness}" for c in command), "The version given does not support witness files"
160
- command = [witness if c == "${witness}" else c for c in command]
180
+ command = [str(witness) if c == "${witness}" else c for c in command]
161
181
 
162
182
  logger.debug("Assembled command from fm-tools: %s", command)
163
183
 
@@ -169,7 +189,7 @@ def run_guided(
169
189
 
170
190
 
171
191
  def run_manual(
172
- fm_tool: Union[Path, FmData],
192
+ fm_tool: Union[Path, FmToolVersion],
173
193
  version: Optional[str],
174
194
  configuration: Config,
175
195
  command: list[str],
@@ -200,6 +220,29 @@ def run_manual(
200
220
 
201
221
  engine.print_output_to_stdout = print_tool_output_to_console
202
222
 
203
- execution_result = engine.run(executable, *command, timeout_sec=timeout_sec)
223
+ execution_result = engine.run(str(executable), *command, timeout_sec=timeout_sec)
204
224
 
205
225
  return execution_result
226
+
227
+
228
+ ### Move to cache_mgr.py after merge to main ###
229
+ def map_doi(fm_data: FmToolVersion, tool_path: Path):
230
+ doi_map = tool_path.parent / "doi_map.json"
231
+
232
+ if os.path.exists(doi_map):
233
+ with open(doi_map, "r") as file:
234
+ data = json.load(file)
235
+ else:
236
+ data = {}
237
+
238
+ doi = str(tool_path).split("/")[-1]
239
+ if doi not in data:
240
+ data[doi] = []
241
+ if fm_data.get_tool_name_with_version() not in data[doi]:
242
+ data[doi].append(fm_data.get_tool_name_with_version())
243
+
244
+ with open(doi_map, "w") as file:
245
+ json.dump(data, file, indent=2)
246
+
247
+
248
+ ### Move to cache_mgr.py after merge to main ###
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fm-weck
3
- Version: 1.4.6
3
+ Version: 1.4.7
4
4
  Author-email: Henrik Wachowitz <henrik.wachowitz@ifi.lmu.de>
5
5
  Maintainer-email: Henrik Wachowitz <henrik.wachowitz@ifi.lmu.de>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Requires-Python: >=3.10
13
13
  Requires-Dist: argcomplete
14
- Requires-Dist: fm-tools>=0.3.3
14
+ Requires-Dist: fm-tools>=1.0.0
15
15
  Requires-Dist: pyyaml>=6.0
16
16
  Requires-Dist: tabulate
17
17
  Requires-Dist: tomli>=2.0; python_version <= '3.10'
@@ -1,20 +1,20 @@
1
- fm_weck/__init__.py,sha256=DV5C4Bm7M37AnsKAzMOPeyxn9kt_BMFQM69KKWhiOos,351
1
+ fm_weck/__init__.py,sha256=qVPurJ_oj0SwP8asFRG0x8Qh7KDzNBLJf5jHKxcyDMc,351
2
2
  fm_weck/__main__.py,sha256=IfNDAqM6MK6P7KsQoW3wOHPOscB8evdVlS9C7R4wd_0,391
3
3
  fm_weck/cache_mgr.py,sha256=3-OQFmCeswazXmX08ND4oEHFOR07ZDCwWzjmFTDkOSE,1373
4
- fm_weck/cli.py,sha256=3XfzaMqh2Bl_Es3n_7Kv80LScJmQdI6et0tcEI_Z2W4,17069
5
- fm_weck/config.py,sha256=AAp5qPZfx2Gh-43jySzfHzHOEmbduHJalA7guV9SIzI,7340
6
- fm_weck/engine.py,sha256=PfcjtN-szlpinSFtv1uE0zs_w__GvR8BSlqbz0u6lII,16742
4
+ fm_weck/cli.py,sha256=k2-rHURw_w0yy5L97FofJ0jYVxqpNP79_XTtirYbyjY,17194
5
+ fm_weck/config.py,sha256=72HfwKJlLnyrBUmLyjEebgPerGMq0CdnQnugz1SIWis,8017
6
+ fm_weck/engine.py,sha256=1EhfL0tzgVyBNf4b40yt2w1netv2Elyop9aRpwzCvm0,17262
7
7
  fm_weck/exceptions.py,sha256=xXxbYK-FZW6YksBtaN79KaA4fGnFCBO-wc0QMqtq3Og,282
8
- fm_weck/image_mgr.py,sha256=f1RlmQPBiMrsqPyH1Rtfb8WMp2YBq-7z-Rto_kCfS7U,1861
9
- fm_weck/run_result.py,sha256=b7t_g6qN2GFGPW6cCoLX_BWMSQ_Q-1cca3Fw3lmIB9M,1207
10
- fm_weck/runexec_mode.py,sha256=vV90CfxwvoR1ApwL4BXq2q_7f8wjSFsS5XQyugDFWMQ,1909
8
+ fm_weck/image_mgr.py,sha256=mDqP-YD6AEOW2xldYJ4D-wxYKF0Ta5SgoJiX2CrhyQg,1906
9
+ fm_weck/run_result.py,sha256=0d8G3py1VCPP4jLxPCVzL8Vljvrwt9IHlmvCkW0pwx8,1249
10
+ fm_weck/runexec_mode.py,sha256=UamxVvYm0XErPjR2sRJaLMX8uHBzRcgCTWbQIZjdju0,2195
11
11
  fm_weck/runexec_util.py,sha256=YBvVIPpmEousZVxbZ5NS8jzpKPLyws31kIFE2z3Ki2E,1370
12
- fm_weck/serve.py,sha256=JaaOi2ipJbPiATHVcpjXOoE8XyuoWXSFlrKtdfkqjU8,7342
12
+ fm_weck/serve.py,sha256=RL6LOnK0RMhFRWehwFdoydc0A619FqSaph7H0JFDYlo,9037
13
13
  fm_weck/version_listing.py,sha256=caaoC3n9R-Ao2sEQ_ngOVO3bnKr7cNVeH6EiA8jO5Sc,864
14
14
  fm_weck/resources/BenchExec-3.27-py3-none-any.whl,sha256=g-db8LM8HfqLhbnl7n5lvUbMnF2tZ4MHAVOxTGxqO8w,732849
15
15
  fm_weck/resources/BenchExec-3.27-py3-none-any.whl.license,sha256=Nq2Mwgn_pyr6ZZrTT095QPtFP3hr15ZeIRIaY0B7eC8,201
16
16
  fm_weck/resources/Containerfile,sha256=MltxP1of9klsQFNR8WyngRTJrPwxQTF4C9ennRxVqSo,391
17
- fm_weck/resources/__init__.py,sha256=XRQiBOncbVvTqZkJ6vSuvu5SUYd3zEV-dGHZTmmLsEM,1023
17
+ fm_weck/resources/__init__.py,sha256=-YLqFTF2Gu4RA9ye3SdvBk1rjhlYxk_f1TgPsix3SAk,1213
18
18
  fm_weck/resources/run_with_overlay.sh,sha256=v1gV_6kMQ0v9BQ3chgDqI1MAOLHbPWeeTC52aCqVpEM,1162
19
19
  fm_weck/resources/runexec,sha256=ogIBO38HLu9C9kDTTANBgAqVnH-UIF1bSJ9d3DSjyF4,462
20
20
  fm_weck/resources/properties/coverage-branches.prp,sha256=Gl2r1cgBFoh4M2laa8dVGhteHkL04oiBRLzxz_hbkEU,56
@@ -46,7 +46,7 @@ fm_weck/resources/fm_tools/blast.yml,sha256=zwPhJN0PfNJo_ZM4a5DNTxKCqc_b0CDaADRf
46
46
  fm_weck/resources/fm_tools/brick.yml,sha256=7mWXlRdc-XiFR2c2wohhuoWHCznmEcnr1i1aLCtcZTk,2007
47
47
  fm_weck/resources/fm_tools/bubaak-split.yml,sha256=7hmY5CYgIdQJAXYrpcGwR-3tqDFnQNTemFUforrDojQ,1886
48
48
  fm_weck/resources/fm_tools/bubaak.yml,sha256=pcJCljIHYmgEMOdeMp8YQxAURO0WlLQ-FpYlYktQHLw,2171
49
- fm_weck/resources/fm_tools/cadp.yml,sha256=nJsmaBl4qwLsP_ZKujCY7Gbjc0qWV6FbmErpPPw1f2c,3352
49
+ fm_weck/resources/fm_tools/cadp.yml,sha256=xkXVGEn4PYMK7ItnaleVLOvbmAU8_9VDlqKjaln5C-k,3352
50
50
  fm_weck/resources/fm_tools/cbmc.yml,sha256=QfgJxq7aBhRcuQpR1_26wKvumM0H4JH7u3SQ_oXYyBM,2095
51
51
  fm_weck/resources/fm_tools/cetfuzz.yml,sha256=4JULcR2E0rM_RhgaFv9x8J34loMwB1uiluIKKcQninw,1808
52
52
  fm_weck/resources/fm_tools/coastal.yml,sha256=ebKhmUoTdlCTw6W4jIllpAJ-CSoFfGvaB004fDg17nY,1650
@@ -84,7 +84,7 @@ fm_weck/resources/fm_tools/graves-par.yml,sha256=GLoBUwv16gQBzrtg5dota5-wbls8Dd_
84
84
  fm_weck/resources/fm_tools/graves.yml,sha256=adyp-k_7moQ9pgSeCtEauPOGFIufWoRlQydIRjn0yi0,2269
85
85
  fm_weck/resources/fm_tools/gwit.yml,sha256=31k4Js4d3nCqW2uJDQnnfuqJcqfK77C0PuGBhdKMC98,1848
86
86
  fm_weck/resources/fm_tools/hornix.yml,sha256=zfJZg09qiueTtyDcZLpWEQDK8GhwfvjfbLI1G_tzUUM,1532
87
- fm_weck/resources/fm_tools/hybridtiger.yml,sha256=Zh9z-CQwB0tjF94_s4Yw9wnTblYAvumiwPk30-qfe_I,1833
87
+ fm_weck/resources/fm_tools/hybridtiger.yml,sha256=4ieXZSbm5qdmW3hK5vSfIwOPW6ZI7rSmecE5Ql0xPpI,1814
88
88
  fm_weck/resources/fm_tools/infer.yml,sha256=sRIzRShUOhY_Y624Oiwdk5MR-c1ligXJdAgLdt-20qk,1884
89
89
  fm_weck/resources/fm_tools/java-ranger.yml,sha256=3T1Vq3v_7dBZl3oIgjZjoZVkPK-OGeFzoaxzpn8h4sE,1989
90
90
  fm_weck/resources/fm_tools/jayhorn.yml,sha256=4-R_2eBD_RvbY2f6Wsrp0ObssHdEsJT29aYCngYnozY,1994
@@ -101,6 +101,7 @@ fm_weck/resources/fm_tools/legion.yml,sha256=ClD8_UEJq8wHIEp9_ifhTNKJuNmzvekaQx1
101
101
  fm_weck/resources/fm_tools/lf-checker.yml,sha256=lV4-GzzNvzWW505FFtYAUHlSG4gxOn-LL4xT8Tpyvq0,1386
102
102
  fm_weck/resources/fm_tools/liv.yml,sha256=t0-Rfs0Ot3VPn7DD_pt3VAbyfpUOP8kdYV3E7uN3qGI,3260
103
103
  fm_weck/resources/fm_tools/locksmith.yml,sha256=c3wNvIzQ_PZaYv6Mm15QH-Rm4oTuNzILNJs1fssESYQ,1397
104
+ fm_weck/resources/fm_tools/ltsmin.yml,sha256=vpfL4mBGlnxPtqoqaqUnR-Ph0kibaOd-h6FYuWHn91M,1206
104
105
  fm_weck/resources/fm_tools/metaval++.yml,sha256=KAOcvftDNLvuHzIKaUoebekeOxBE6DVS2Acq2VbL1Dg,2006
105
106
  fm_weck/resources/fm_tools/metaval.yml,sha256=aclr5cfGDuCduSrlk9kLOcK8GaUQAzPtDAxIJHgHs44,4668
106
107
  fm_weck/resources/fm_tools/mlb.yml,sha256=S_ykc9ThLHBbMSXOgYIvk81r96cEwXbAXI5lPRDxJ4s,1907
@@ -121,7 +122,7 @@ fm_weck/resources/fm_tools/rizzer.yml,sha256=ZmVL72-mBTzmMY29I3x5HmSCtQTMbJ0vw2U
121
122
  fm_weck/resources/fm_tools/schema.yml,sha256=_SqJzwFGxM0EuuLgcMF-S_hUtoGxaFKraGTfQDUyILY,22945
122
123
  fm_weck/resources/fm_tools/sikraken.yml,sha256=WnLxKyl-4zZ8rvXWqLuuqaC8b9GGQDg-jB3798SeK6M,1067
123
124
  fm_weck/resources/fm_tools/spf.yml,sha256=6-7306izjPHKcLZ1veQRmGWOVQcsFJbNyL_55JYVQXA,1692
124
- fm_weck/resources/fm_tools/sv-sanitizers.yml,sha256=tisvbuYRXutJuk-rsqzRJ-3NSMBL29hHjym3eqE4MAI,1431
125
+ fm_weck/resources/fm_tools/sv-sanitizers.yml,sha256=bLG5MoLK95KruF5WCH0Yz2pJPAikPfkNgZRfbP5a2j0,1559
125
126
  fm_weck/resources/fm_tools/svf-svc.yml,sha256=gQ12F7_7uis7fVgsTiNdleKBgydi-BOgS4ne-dRyHvk,1591
126
127
  fm_weck/resources/fm_tools/swat.yml,sha256=gsvsFBeItbspzdXVVQ8TFWulbdYHzIHSmcKlWkWxGk0,1684
127
128
  fm_weck/resources/fm_tools/symbiotic-witch.yml,sha256=6ND-WISFvJEeyEB3Q-Xu71dZrc_ayr1kAnEzfV3TA84,2421
@@ -147,7 +148,7 @@ fm_weck/resources/fm_tools/wit4java.yml,sha256=ylfze2XbV4zKkVUH57Veqn7G49gW0Byxd
147
148
  fm_weck/resources/fm_tools/witch.yml,sha256=wwe6lrI2sxGKVZbLeipa38rPhB2pcSUFi9uVngtXGUQ,1795
148
149
  fm_weck/resources/fm_tools/witnesslint.yml,sha256=EvMBcm5fx6lgSLRmHSKXSxXIJKZ-BrxLwTXI4GQ6FMs,6812
149
150
  fm_weck/resources/fm_tools/witnessmap.yml,sha256=FyZtEloxpWBBjLn9kyqoen2kPjOkH2r4fxAj5gfV8Bg,1692
150
- fm_weck-1.4.6.dist-info/METADATA,sha256=lZPOGSSc4OeZvJ0m5VGGbo25DdX0twG-9rCEfYGE2A0,2822
151
- fm_weck-1.4.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
152
- fm_weck-1.4.6.dist-info/entry_points.txt,sha256=toWpKCSY1u593MPnI_xW5gnwlnkerP4AvmPQ1s2nPgY,50
153
- fm_weck-1.4.6.dist-info/RECORD,,
151
+ fm_weck-1.4.7.dist-info/METADATA,sha256=WnQnKmjvJ6HQouE2-s1Mil4cw9NJW0Sp3d9E43upkhk,2822
152
+ fm_weck-1.4.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
153
+ fm_weck-1.4.7.dist-info/entry_points.txt,sha256=toWpKCSY1u593MPnI_xW5gnwlnkerP4AvmPQ1s2nPgY,50
154
+ fm_weck-1.4.7.dist-info/RECORD,,