From 3bd7191e44d62a97213d9bbddeffa094ca14a702 Mon Sep 17 00:00:00 2001 From: George Dadunashvili Date: Tue, 14 Apr 2026 15:51:59 +0200 Subject: [PATCH] lobster_bazel: bazel plugin for lobster --- BUILD | 1 + MODULE.bazel | 9 + lobster_bazel/BUILD | 32 ++ lobster_bazel/README.md | 131 ++++++ lobster_bazel/lobster_bazel.bzl | 19 + lobster_bazel/parse_source_files.py | 261 +++++++++++ lobster_bazel/private/BUILD | 31 ++ lobster_bazel/private/lobster_linker.bzl | 166 +++++++ lobster_bazel/requirements.in | 1 + lobster_bazel/requirements.txt | 425 ++++++++++++++++++ lobster_bazel/test/BUILD | 58 +++ lobster_bazel/test/__init__.py | 0 lobster_bazel/test/data/BUILD.bazel | 59 +++ .../test/data/dependency_with_tags.py | 17 + lobster_bazel/test/data/file_list.txt | 1 + lobster_bazel/test/data/source_with_tags.cpp | 36 ++ lobster_bazel/test/data/source_with_tags.h | 20 + lobster_bazel/test/data/source_with_tags.py | 34 ++ .../data/transitive_dependency_with_tags.py | 17 + .../lobster_bazel_system_test_case_base.py | 34 ++ lobster_bazel/test/test_basic_tracing.py | 121 +++++ lobster_bazel/test/test_bazel_rule.py | 53 +++ lobster_bazel/test/test_runner.py | 107 +++++ 23 files changed, 1633 insertions(+) create mode 100644 lobster_bazel/BUILD create mode 100644 lobster_bazel/README.md create mode 100644 lobster_bazel/lobster_bazel.bzl create mode 100644 lobster_bazel/parse_source_files.py create mode 100644 lobster_bazel/private/BUILD create mode 100644 lobster_bazel/private/lobster_linker.bzl create mode 100644 lobster_bazel/requirements.in create mode 100644 lobster_bazel/requirements.txt create mode 100644 lobster_bazel/test/BUILD create mode 100644 lobster_bazel/test/__init__.py create mode 100644 lobster_bazel/test/data/BUILD.bazel create mode 100644 lobster_bazel/test/data/dependency_with_tags.py create mode 100644 lobster_bazel/test/data/file_list.txt create mode 100644 lobster_bazel/test/data/source_with_tags.cpp create mode 100644 lobster_bazel/test/data/source_with_tags.h create mode 100644 lobster_bazel/test/data/source_with_tags.py create mode 100644 lobster_bazel/test/data/transitive_dependency_with_tags.py create mode 100644 lobster_bazel/test/lobster_bazel_system_test_case_base.py create mode 100644 lobster_bazel/test/test_basic_tracing.py create mode 100644 lobster_bazel/test/test_bazel_rule.py create mode 100644 lobster_bazel/test/test_runner.py diff --git a/BUILD b/BUILD index 34e97d2d..d1490afb 100644 --- a/BUILD +++ b/BUILD @@ -29,6 +29,7 @@ copyright_checker( "starpls", "tools", "plantuml", + "lobster_bazel", # Add other directories/files you want to check ], diff --git a/MODULE.bazel b/MODULE.bazel index 87aac87a..cd160a28 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -151,6 +151,15 @@ pip.parse( ) use_repo(pip, "pip_tooling") +pip.parse( + envsubst = ["PIP_INDEX_URL"], + extra_pip_args = ["--index-url=${PIP_INDEX_URL:-https://pypi.org/simple/}"], + hub_name = "pip_lobster_bazel", + python_version = PYTHON_VERSION, + requirements_lock = "//lobster_bazel:requirements.txt", +) +use_repo(pip, "pip_lobster_bazel") + ############################################################################### # Multitool Hub (for ruff, pyright, actionlint, etc.) ############################################################################### diff --git a/lobster_bazel/BUILD b/lobster_bazel/BUILD new file mode 100644 index 00000000..132a2a95 --- /dev/null +++ b/lobster_bazel/BUILD @@ -0,0 +1,32 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("@rules_python//python:defs.bzl", "py_binary", "py_library") + +py_binary( + name = "lobster-bazel", + srcs = [ + "parse_source_files.py", + ], + main = "parse_source_files.py", + visibility = [ + "//visibility:public", + ], + deps = [ + "@pip_lobster_bazel//bmw_lobster", + ], +) + +exports_files([ + "requirements.in", + "requirements.txt", +]) diff --git a/lobster_bazel/README.md b/lobster_bazel/README.md new file mode 100644 index 00000000..4e8cb6ee --- /dev/null +++ b/lobster_bazel/README.md @@ -0,0 +1,131 @@ +# Tracing to Source Files (Bazel / Source Code Linker) + +## Overview + +`lobster-bazel` scans source files for inline tracing tags and produces a +`.lobster` file in the `lobster-imp-trace` format. It is designed for use in +Bazel-based projects where the build system can provide lists of source files to +scan, but the tool itself is not Bazel-specific and can be used with any build +system that can produce file-list inputs. + +Supported file types (automatically detected by extension): + +| Extension | Language | Comment sign | +|----------------------|-----------|--------------| +| `.c`, `.cc`, `.cpp`, `.cxx`, `.h`, `.hh`, `.hpp`, `.hxx` | C/C++ | `//` | +| `.rs` | Rust | `//` | +| `.py` | Python | `#` | +| `.bzl` | Starlark | `#` | +| `.trlc`, `.rsl` | TRLC | `#` | + +Files with unsupported extensions are silently skipped; the run continues and +reports the number of items extracted from the remaining files. + +## Adding tracing tags to source files + +Add a single-line comment **at the start of the line** with the tracing tag +attribute and the requirement ID: + +```python +# Python example +def process(): + # req-traceability: COMP_REQ_001 + pass +``` + +```cpp +// C++ example +void process() { + // req-traceability: COMP_REQ_001 +} +``` + +```rust +// Rust example +fn process() { + // req-traceability: COMP_REQ_001 +} +``` + +> **Note:** The tag pattern must appear at the start of the (stripped) line. +> Inline comments at the end of a code statement are intentionally **not** +> matched to avoid false positives. + +The tag attribute (e.g. `req-traceability`) is configurable via `--tag`. +The default tag used by the `lobster_linker` Bazel rule is `lobster-trace`. + +## Creating lobster files + +The tool reads **file-list files** as positional arguments. Each file-list file +contains one source file path per line. This design integrates naturally with +Bazel's `$(locations ...)` expansion or any tool that can dump a list of files. + +```sh +$ lobster-bazel --output impl.lobster \ + --tag req-traceability \ + source_files.txt +``` + +Where `source_files.txt` contains: + +``` +src/module_a.py +src/module_b.rs +include/module_c.hpp +``` + +Multiple file-list files and multiple `--tag` values are supported: + +```sh +$ lobster-bazel --output impl.lobster \ + --tag req-traceability \ + --tag req-Id \ + sources_a.txt sources_b.txt +``` + +An optional `--namespace` argument controls the namespace prefix for the +generated tags (default: `source`): + +```sh +$ lobster-bazel --output impl.lobster \ + --tag req-traceability \ + --namespace impl \ + source_files.txt +``` + +### Error behaviour + +- **Unsupported file extension**: the file is skipped with a warning; the run + continues. +- **Unreadable or missing source file**: an error is logged and the file is + skipped; the run continues and exits with code 0. +- **Unreadable file-list file**: a fatal error is logged and the tool exits + with code 1. + +## Bazel integration + +When using Bazel, use the `lobster_linker` rule from `lobster.bzl`: + +```starlark +load("@lobster//:lobster.bzl", "lobster_linker", "lobster_test") + +lobster_linker( + name = "impl_trace", + srcs = [ + "//src:my_library", + "//src:my_binary", + ], + tracing_tags = ["req-traceability"], +) +``` + +The `lobster_linker` rule automatically collects all source files from the +listed targets and passes them to `lobster-bazel`. The output is exposed as a +`LobsterProvider` so it can be consumed by `lobster_test`. + +The `subrule_lobster_linker` subrule is also exported for composing the linker +into other custom Bazel rules: + +```starlark +load("@lobster//:lobster.bzl", "subrule_lobster_linker") +``` diff --git a/lobster_bazel/lobster_bazel.bzl b/lobster_bazel/lobster_bazel.bzl new file mode 100644 index 00000000..3e890e85 --- /dev/null +++ b/lobster_bazel/lobster_bazel.bzl @@ -0,0 +1,19 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("//lobster_bazel/private:lobster_linker.bzl", _lobster_linker = "lobster_linker", _subrule_lobster_linker = "subrule_lobster_linker") + +# Re-export LobsterProvider so it can be loaded from this file +def lobster_linker(**kwargs): + _lobster_linker(**kwargs) + +subrule_lobster_linker = _subrule_lobster_linker diff --git a/lobster_bazel/parse_source_files.py b/lobster_bazel/parse_source_files.py new file mode 100644 index 00000000..11297e11 --- /dev/null +++ b/lobster_bazel/parse_source_files.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python3 +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +# +# Carry over from Eclipse S-Core including slight modifications: +# https://github.com/eclipse-score/docs-as-code/tree/v0.4.0/src/extensions/score_source_code_linker + +""" +Lobster source code linker -- scans source files for tracing tags and produces +a ``.lobster`` file in ``lobster-imp-trace`` format. + +Tracing tags in source files follow the pattern:: + + : + +The comment sign is automatically derived from the file extension. +Tracing attributes (e.g. ``req-traceability``, ``req-Id``) are configurable +via the ``--tag`` argument. +""" + +import argparse +import logging +import sys +from pathlib import Path +from typing import Optional, Sequence, Union + +from lobster.common.items import Implementation, Tracing_Tag +from lobster.common.location import File_Reference +from lobster.common.io import lobster_write + +logger = logging.getLogger(__name__) + +# --------------------------------------------------------------------------- +# Comment-sign mapping (file extension → single-line comment prefix) +# --------------------------------------------------------------------------- + +COMMENT_SIGNS: dict[str, str] = { + # C-family + ".c": "//", + ".cc": "//", + ".cpp": "//", + ".cxx": "//", + ".h": "//", + ".hh": "//", + ".hpp": "//", + ".hxx": "//", + # Rust + ".rs": "//", + # Python + ".py": "#", + # Starlark / Bazel + ".bzl": "#", + # TRLC + ".trlc": "#", + ".rsl": "#", +} + +LANGUAGE_MAP: dict[str, str] = { + ".c": "C/C++", + ".cc": "C/C++", + ".cpp": "C/C++", + ".cxx": "C/C++", + ".h": "C/C++", + ".hh": "C/C++", + ".hpp": "C/C++", + ".hxx": "C/C++", + ".rs": "Rust", + ".py": "Python", + ".bzl": "Starlark", + ".trlc": "TRLC", + ".rsl": "TRLC", +} + +LOBSTER_GENERATOR = "lobster_linker" + + +# --------------------------------------------------------------------------- +# Public helpers +# --------------------------------------------------------------------------- + + +def get_comment_sign(file_path: str) -> Union[str, None]: + """Derive the single-line comment sign from a file's extension. + + Args: + file_path: Path to the source file. + + Returns: + The comment prefix string, or ``None`` if the extension is unknown. + """ + ext = Path(file_path).suffix.lower() + return COMMENT_SIGNS.get(ext) + + +def get_language(file_path: str) -> str: + """Derive the language name from a file's extension. + + Args: + file_path: Path to the source file. + + Returns: + A human-readable language string (e.g. ``"Rust"``, ``"Python"``). + Falls back to the uppercased extension if not in LANGUAGE_MAP. + """ + ext = Path(file_path).suffix.lower() + return LANGUAGE_MAP.get(ext, ext.lstrip(".").upper() or "Unknown") + + +def build_tag_patterns(tracing_tags: list[str], comment_sign: str) -> list[str]: + """Construct the full tag patterns to search for in source lines. + + Each pattern is: `` :`` + + Args: + tracing_tags: List of tracing attribute names + (e.g. ``["req-traceability", "req-Id"]``). + comment_sign: The comment prefix for the file type. + + Returns: + List of tag pattern strings. + """ + return [f"{comment_sign} {tag}:" for tag in tracing_tags] + + +def extract_lobster_items( + source_file: str, + tracing_tags: list[str], + namespace: str = "source", +) -> list[Implementation]: + """Scan a source file for tracing tags and produce lobster trace items. + + For every matching line the function creates a lobster ``Implementation`` + item with a ``refs`` entry pointing at ``req `` so that the lobster + report can link implementations back to requirements. + + Tags are matched only when the pattern appears at the start of the + (stripped) line, preventing false positives from mid-line occurrences. + + Args: + source_file: Path to the source file to scan. + tracing_tags: List of tracing attribute names to look for. + namespace: Namespace prefix for lobster tags (default: ``"source"``). + + Returns: + List of ``Implementation`` objects in ``lobster-imp-trace`` format. + """ + comment_sign = get_comment_sign(source_file) + if comment_sign is None: + logger.warning("Unknown file extension for '%s', skipping.", source_file) + return [] + tag_patterns = build_tag_patterns(tracing_tags, comment_sign) + items: list[Implementation] = [] + try: + with open(source_file, encoding="utf-8", errors="replace") as fh: + for line_number, line in enumerate(fh, start=1): + stripped = line.strip() + for pattern in tag_patterns: + if stripped.startswith(pattern): + after_pattern = stripped[len(pattern) :].strip() + req_id = ( + after_pattern.replace("'", "") + .replace('"', "") + .replace(",", "") + .strip() + ) + if not req_id: + continue + item = Implementation( + tag=Tracing_Tag(namespace, req_id), + location=File_Reference(source_file, line_number), + language=get_language(source_file), + kind="Implementation", + name=req_id, + ) + item.add_tracing_target(Tracing_Tag("req", req_id)) + items.append(item) + break # One match per line is enough + except OSError: + logger.exception("Cannot read file '%s'", source_file) + raise + return items + + +# --------------------------------------------------------------------------- +# CLI entry-point +# --------------------------------------------------------------------------- + + +def main(args: Optional[Sequence[str]] = None) -> int: + parser = argparse.ArgumentParser( + description="Scan source files for tracing tags and produce a .lobster file.", + ) + parser.add_argument( + "-o", + "--output", + required=True, + help="Output .lobster file path.", + ) + parser.add_argument( + "--tag", + action="append", + dest="tags", + required=True, + help=( + "Tracing tag attribute to scan for " + "(can be specified multiple times, e.g. --tag req-Id --tag req-traceability)." + ), + ) + parser.add_argument( + "--namespace", + default="source", + help="Namespace prefix for lobster tags (default: 'source').", + ) + parser.add_argument( + "inputs", + nargs="*", + help="File-list files (each line contains a source file path to scan).", + ) + + options = parser.parse_args(args) + + all_items: list[Implementation] = [] + for input_list_file in options.inputs: + try: + with open(input_list_file) as fh: + for source_file_line in fh: + source_file = source_file_line.strip() + if not source_file: + continue + try: + items = extract_lobster_items( + source_file, + tracing_tags=options.tags, + namespace=options.namespace, + ) + all_items.extend(items) + except OSError as exc: + logger.error("Skipping '%s': %s", source_file, exc) + except OSError as exc: + logger.error("Cannot read file list '%s': %s", input_list_file, exc) + return 1 + + with open(options.output, "w", encoding="utf-8") as fh: + lobster_write(fh, Implementation, LOBSTER_GENERATOR, all_items) + + print(f"lobster-bazel: wrote {len(all_items)} items to {options.output}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/lobster_bazel/private/BUILD b/lobster_bazel/private/BUILD new file mode 100644 index 00000000..11d70914 --- /dev/null +++ b/lobster_bazel/private/BUILD @@ -0,0 +1,31 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("@rules_python//python:pip.bzl", "compile_pip_requirements") + +compile_pip_requirements( + name = "requirements", + src = "//lobster_bazel:requirements.in", + requirements_txt = "//lobster_bazel:requirements.txt", + tags = [ + "manual", + ], +) + +build_test( + name = "ensure_all_private_targets_work", + targets = [ + ":requirements.update", + ], +) diff --git a/lobster_bazel/private/lobster_linker.bzl b/lobster_bazel/private/lobster_linker.bzl new file mode 100644 index 00000000..d1586f47 --- /dev/null +++ b/lobster_bazel/private/lobster_linker.bzl @@ -0,0 +1,166 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("@lobster//:lobster.bzl", "LobsterProvider") + +# --------------------------------------------------------------------------- +# Aspect – transitively collect source files from deps +# --------------------------------------------------------------------------- + +_CollectedFilesInfo = provider( + doc = "Internal provider for collecting all source files.", + fields = { + "files": "depset of source files", + }, +) + +def _extract_files_from_attr(attr, attr_name): + """Extracts source files from a given attribute, if the attribute exists.""" + return [ + f + for src in getattr(attr, attr_name, []) + for f in src.files.to_list() + if not f.path.startswith("external") + ] + +def _get_transitive_deps(attr, attr_name): + """Extracts previously collected transitive dependencies.""" + return [ + dep[_CollectedFilesInfo].files + for dep in getattr(attr, attr_name, []) + if _CollectedFilesInfo in dep + ] + +def _collect_source_files_aspect_impl(_target, ctx): + """Aspect implementation to collect source files from rules and dependencies.""" + return [ + _CollectedFilesInfo( + files = depset( + _extract_files_from_attr(ctx.rule.attr, "srcs") + + _extract_files_from_attr(ctx.rule.attr, "hdrs"), + transitive = _get_transitive_deps(ctx.rule.attr, "deps"), + ), + ), + ] + +_collect_source_files_aspect = aspect( + implementation = _collect_source_files_aspect_impl, + attr_aspects = ["deps"], + doc = "Aspect that collects source files from a rule and its dependencies.", +) + +# --------------------------------------------------------------------------- +# Subrule implementation +# --------------------------------------------------------------------------- + +def _lobster_linker_subrule_impl(ctx, files, tracing_tags, namespace, _parser): + """Subrule implementation: takes file list, tags and namespace, emits .lobster.""" + + # 1. Write the file list to a temporary text file ------------------- + sources_file = ctx.actions.declare_file("%s_sources.txt" % ctx.label.name) + + ctx.actions.write(sources_file, "\n".join([f.path for f in files])) + + # 2. Declare output .lobster file ----------------------------------- + lobster_file = ctx.actions.declare_file("%s.lobster" % ctx.label.name) + + # 3. Build command-line arguments ----------------------------------- + args = ctx.actions.args() + args.add(sources_file) + args.add("--output", lobster_file) + for tag in tracing_tags: + args.add("--tag", tag) + if namespace: + args.add("--namespace", namespace) + + # 4. Run the parser ------------------------------------------------- + ctx.actions.run( + arguments = [args], + executable = _parser, + inputs = depset( + [sources_file] + files, + ), + outputs = [lobster_file], + mnemonic = "LobsterLinker", + progress_message = "Scanning source files for tracing tags: %s" % ctx.label, + ) + + return [ + lobster_file, + LobsterProvider(lobster_input = {lobster_file.basename: lobster_file.path}), + ] + +subrule_lobster_linker = subrule( + implementation = _lobster_linker_subrule_impl, + attrs = { + "_parser": attr.label( + default = Label("//lobster_bazel:lobster-bazel"), + executable = True, + cfg = "exec", + ), + }, +) + +# --------------------------------------------------------------------------- +# Rule implementation +# --------------------------------------------------------------------------- + +def _lobster_linker_impl(ctx): + """Implementation of the lobster_linker rule.""" + all_files = depset( + direct = ctx.files.srcs, + transitive = _get_transitive_deps(ctx.attr, "srcs"), + ).to_list() + + # gToDo: what is going on here? + lobster_file, lobster_provider = subrule_lobster_linker( + all_files, + ctx.attr.tracing_tags, + ctx.attr.namespace, + ) + + return [ + DefaultInfo( + files = depset([lobster_file]), + runfiles = ctx.runfiles([lobster_file]), + ), + lobster_provider, + ] + +# --------------------------------------------------------------------------- +# Rule definition +# --------------------------------------------------------------------------- + +lobster_linker = rule( + implementation = _lobster_linker_impl, + attrs = { + "srcs": attr.label_list( + aspects = [_collect_source_files_aspect], + allow_files = True, + doc = "Source file targets (filegroups, libraries, etc.) to scan for tracing tags.", + ), + "tracing_tags": attr.string_list( + default = ["lobster-trace"], + doc = "List of tracing tag attribute names to search for in source files. The tool will construct the full pattern as: : where the comment sign is auto-derived from the file extension. Defaults to ['lobster-trace'].", + ), + "namespace": attr.string( + default = "source", + doc = "Namespace prefix for lobster tags (default: 'source').", + ), + }, + subrules = [subrule_lobster_linker], + provides = [ + DefaultInfo, + LobsterProvider, + ], + doc = "Scans source files for tracing tags and produces a .lobster file. Provides a LobsterProvider for integration with lobster_test traceability reports.", +) diff --git a/lobster_bazel/requirements.in b/lobster_bazel/requirements.in new file mode 100644 index 00000000..b8465745 --- /dev/null +++ b/lobster_bazel/requirements.in @@ -0,0 +1 @@ +bmw-lobster diff --git a/lobster_bazel/requirements.txt b/lobster_bazel/requirements.txt new file mode 100644 index 00000000..9e11bfe2 --- /dev/null +++ b/lobster_bazel/requirements.txt @@ -0,0 +1,425 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# bazel run //lobster_bazel/private:requirements.update +# +bmw-lobster==1.0.2 \ + --hash=sha256:74125e835a3e913935693517795fd819282796bb12bfc32a63a97ca39abfaf60 + # via -r lobster_bazel/requirements.in +bmw-lobster-core==1.0.2 \ + --hash=sha256:fbbc359e6e46f5e9bbbef32844bd2aed42ec6180c9f4c636350393f96c48da43 + # via + # bmw-lobster + # bmw-lobster-tool-codebeamer + # bmw-lobster-tool-cpp + # bmw-lobster-tool-cpptest + # bmw-lobster-tool-gtest + # bmw-lobster-tool-json + # bmw-lobster-tool-python + # bmw-lobster-tool-trlc +bmw-lobster-tool-codebeamer==1.0.2 \ + --hash=sha256:864ae2d04f78f6f6750c5adff39c965dd48c369eefcb18b39cabf8acb125f3a7 + # via bmw-lobster +bmw-lobster-tool-cpp==1.0.2 \ + --hash=sha256:cc3acc929f8cc45ec909885d4fa95218cc9ca8022d30d7bfe7214fb28210f644 + # via bmw-lobster +bmw-lobster-tool-cpptest==1.0.2 \ + --hash=sha256:8d405d647768668a25be0bdeeaeff7300bb95a5cfdc1fa9c2039edb2259842c9 + # via bmw-lobster +bmw-lobster-tool-gtest==1.0.2 \ + --hash=sha256:aac8f38cfea1290fa1eed596a4ebaf6db4571a3f67435824e27843513b0e05a6 + # via bmw-lobster +bmw-lobster-tool-json==1.0.2 \ + --hash=sha256:99019a8ec986f1cd3f92190f2572e41578f973b1563dc104e25e89b1dd7b832f + # via bmw-lobster +bmw-lobster-tool-python==1.0.2 \ + --hash=sha256:3b85c5b2142ddbae79d16ac2464f005d5f4baba2a94397301ac60e3a3af7e460 + # via bmw-lobster +bmw-lobster-tool-trlc==1.0.2 \ + --hash=sha256:4c5f0c52a3b395e3a2923455e16066217ebbcca60f2ce34cb77c1c90152b2363 + # via bmw-lobster +certifi==2026.2.25 \ + --hash=sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa \ + --hash=sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7 + # via requests +charset-normalizer==3.4.7 \ + --hash=sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc \ + --hash=sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c \ + --hash=sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67 \ + --hash=sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4 \ + --hash=sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0 \ + --hash=sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c \ + --hash=sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5 \ + --hash=sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444 \ + --hash=sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153 \ + --hash=sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9 \ + --hash=sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01 \ + --hash=sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217 \ + --hash=sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b \ + --hash=sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c \ + --hash=sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a \ + --hash=sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83 \ + --hash=sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5 \ + --hash=sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7 \ + --hash=sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb \ + --hash=sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c \ + --hash=sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1 \ + --hash=sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42 \ + --hash=sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab \ + --hash=sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df \ + --hash=sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e \ + --hash=sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207 \ + --hash=sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18 \ + --hash=sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734 \ + --hash=sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38 \ + --hash=sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110 \ + --hash=sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18 \ + --hash=sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44 \ + --hash=sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d \ + --hash=sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48 \ + --hash=sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e \ + --hash=sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5 \ + --hash=sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d \ + --hash=sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53 \ + --hash=sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790 \ + --hash=sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c \ + --hash=sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b \ + --hash=sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116 \ + --hash=sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d \ + --hash=sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10 \ + --hash=sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6 \ + --hash=sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2 \ + --hash=sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776 \ + --hash=sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a \ + --hash=sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265 \ + --hash=sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008 \ + --hash=sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943 \ + --hash=sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374 \ + --hash=sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246 \ + --hash=sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e \ + --hash=sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5 \ + --hash=sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616 \ + --hash=sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15 \ + --hash=sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41 \ + --hash=sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960 \ + --hash=sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752 \ + --hash=sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e \ + --hash=sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72 \ + --hash=sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7 \ + --hash=sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8 \ + --hash=sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b \ + --hash=sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4 \ + --hash=sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545 \ + --hash=sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706 \ + --hash=sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366 \ + --hash=sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb \ + --hash=sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a \ + --hash=sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e \ + --hash=sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00 \ + --hash=sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f \ + --hash=sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a \ + --hash=sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1 \ + --hash=sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66 \ + --hash=sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356 \ + --hash=sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319 \ + --hash=sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4 \ + --hash=sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad \ + --hash=sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d \ + --hash=sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5 \ + --hash=sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7 \ + --hash=sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0 \ + --hash=sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686 \ + --hash=sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34 \ + --hash=sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49 \ + --hash=sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c \ + --hash=sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1 \ + --hash=sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e \ + --hash=sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60 \ + --hash=sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0 \ + --hash=sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274 \ + --hash=sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d \ + --hash=sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0 \ + --hash=sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae \ + --hash=sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f \ + --hash=sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d \ + --hash=sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe \ + --hash=sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3 \ + --hash=sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393 \ + --hash=sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1 \ + --hash=sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af \ + --hash=sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44 \ + --hash=sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00 \ + --hash=sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c \ + --hash=sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3 \ + --hash=sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7 \ + --hash=sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd \ + --hash=sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e \ + --hash=sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b \ + --hash=sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8 \ + --hash=sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259 \ + --hash=sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859 \ + --hash=sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46 \ + --hash=sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30 \ + --hash=sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b \ + --hash=sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46 \ + --hash=sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24 \ + --hash=sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a \ + --hash=sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24 \ + --hash=sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc \ + --hash=sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215 \ + --hash=sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063 \ + --hash=sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832 \ + --hash=sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6 \ + --hash=sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79 \ + --hash=sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464 + # via requests +cvc5==1.3.0 \ + --hash=sha256:039cdda840e6af8695be90a81df1c7db1655923d56afede305f47deb3dfa9b97 \ + --hash=sha256:04082b95507673e4f747e8601c26b19bd4edf9fec215b1794e3fa0dcb6acb824 \ + --hash=sha256:05d0d3e677b31690536300889f3c7a9e4227a9c995f29a06f7c5b220ac2c3953 \ + --hash=sha256:08b80ed3a7f75a3e1bd6c5e298c2ce018f717447544e0d4b7180b744959ada02 \ + --hash=sha256:0cac786b1b5c5ec33121dbd79e7f49dd4da9ae643f94b5b468d376ba9cd9eb40 \ + --hash=sha256:0cc4095a51d18d935b1e0830ab450c93dc2bf7d4038aa98389b4c53c8c46df36 \ + --hash=sha256:15b194b6a7bd18d7b0d32b9b28bbfb72d294330ec5be0191ee0c864e0570fdc2 \ + --hash=sha256:1864ff530c8bad896d609cf28a5427705ec360e7dcc79a578ff8e8ada16a6e6e \ + --hash=sha256:19f988325064115f80c4a1eb01536436bca6d79e73de67bad3f3a0eb6f04220f \ + --hash=sha256:1a7836d8acfda443722aad3d6f766e7e42c4342bcc352a16e9f77c29efe261be \ + --hash=sha256:256a72acdb3d0b77e0f3a8ffcf73513c3a5c18a6570a31fbde56bc90fd42a96b \ + --hash=sha256:2b796f54f0ebe2d18e1ee1d0f3c368c8dc52596c6756b259f9e2d3f092b3e28f \ + --hash=sha256:31f5687ecadddb02c158f0f7510332b7d95c0200c3a238f3d6d8b0ecadffcfca \ + --hash=sha256:34a0f47ebb6aa083260e70b03616a0f8ed1bd9c3bc25bf1a790f50adcff29df6 \ + --hash=sha256:3cec83e3166992dab9ca97149a5484ed6ada344264759a97d39539a33d78d3b3 \ + --hash=sha256:3d0ceb1108e7a2eea63ad0abf45aa2432af35ab4a9cf0821401acce1bc5e79d6 \ + --hash=sha256:4194ada6b3a9e88a4b444b9242ce910c2f938f6839f7d4512af6fc7b7b18f578 \ + --hash=sha256:44d1e3778d30b7ef57041e24ae35451877fc7b77515863a25b10cfb6995ee00e \ + --hash=sha256:4713d356285bc902cfb23cb03d263f546772548a3432786fa11fdb723364d626 \ + --hash=sha256:495185bb29045c71c94d16c17ace476f63669ef65be7543124c42185f72ab80b \ + --hash=sha256:52421c4a4e8af0db9c40fe66182f46b3fb7e4c108861cf3de4debd65469a5ab6 \ + --hash=sha256:5daa8b20161bb0da41d64f5721a048b4bdee0e5488a0a3562756162222c7e239 \ + --hash=sha256:78257e815aa524bb9f2ab44e7bc94ecb0aa063df2bff26a92dac419b50742b40 \ + --hash=sha256:79a64ea8a8c2c967414b43a946b0cb3eb03cdcab6b42f0318e45d06d9089455c \ + --hash=sha256:7f153d9a2438e4a1dd8ba0387004ab3bd1006d8edbd24c6317ec9ac8fc23def4 \ + --hash=sha256:81acf63ac8eb5f16cb0f9fd9876819f1ac23e12a0fb452f57fb9a383a21b79b8 \ + --hash=sha256:89238d35dd05c2fac8f397f524d1d85f5ae302bb8d17d061c7bdb48da918a0b5 \ + --hash=sha256:8b91c56a3af83ef97a8cdbd26ff5947c3f6011f3ba8ee5bb0b2c967303b9939f \ + --hash=sha256:92777475076f394a3089bcff651ff46be90fef6bab14fd4c7c9fc6ebe7e64f9d \ + --hash=sha256:92c51bf7bd5218a6c82ac2b898c2bf477a93245b027200672701ba6ebdf42b3d \ + --hash=sha256:934aafde6e7060ae7960afa234014186274fd8e8ddb0dbe88652216e05739fa4 \ + --hash=sha256:97a6f57b0c9ab6bbbca06d08241630ae4eb192a5e5a2d80f431fb29dc38d5a5e \ + --hash=sha256:9b1015fddb5bf89dc3c9eabd8885bd31b47903207e25f3f021e0dd84313ce854 \ + --hash=sha256:9efa29e314a41441b91e82822ed7558cad2629e20620ac5fde00fe3d182165c5 \ + --hash=sha256:a455e10e30ef05a76dfc4f4fbe01684ecb3c9fd9e329c9419be6d8a60cb7a730 \ + --hash=sha256:ad21ce105d9e3eba2a220815b59be9a95575be3a79fa11b271773d96c90b1ea0 \ + --hash=sha256:ae1407a4202af525f44444878dfc8fac29b7f2ae9b77f4a582342805d85326a1 \ + --hash=sha256:aee88274f35cfef81f815fa6d1a956ad522cb789505f9911021eea20e396bda8 \ + --hash=sha256:bbb93e21283e15e5dcb18f78afe05864384e7b651d24e85fac5ff1fe0da08721 \ + --hash=sha256:bef5c64e5474634d68e880104e6dc838996b68fe45906c49e591d376236bf0ec \ + --hash=sha256:c4827b28fd8e398824a003edac93eecc0c933fc51d0c8c36e0ce7839e38ace8c \ + --hash=sha256:c516f766cc0f74ea79a4eee83e87201e51bc80e770d3227c559e609e25b36daf \ + --hash=sha256:c563a3f27ed5d26d0a042f218f186b936c175088377d65180ed4da5975b63265 \ + --hash=sha256:c80967c23a492ae7b6dae30ac1cdaf099672a9c88a4c7b2620ebf6e9d093f8b9 \ + --hash=sha256:ce0b06e58cb3b18635a2c712e368502ca421be02158ad8ca4ce38dda5de9d3b5 \ + --hash=sha256:cfea2163054c883992f3b596a561b46aa644ec6c75e50e81e21f77445d897474 \ + --hash=sha256:d2ea103f9cd512c09f118e66cee9f7b50863ab4352e6cfe1ab145c5ad998fab1 \ + --hash=sha256:dacaecf7e2e94339d2458fa490c68cf2894ab4b7bff9c0ad4cc0f3a3eafac76b \ + --hash=sha256:dd800445fb86f8f5623754f14dd1d5ce013339936c54391f275df4a50a4610a6 \ + --hash=sha256:e33e21fc5e5ae5f1c6182c413ea6a2b90890d29f80ca61d4b7cbd4753c763772 \ + --hash=sha256:f4a3ed8cd2a56d69d4a0f097e50677032fcedc13701d1d5b0c63b899738b6ac4 \ + --hash=sha256:f63322af039263ec52ca86cfb301cab24da2e5782c9ebab5f05dd02d2859470e \ + --hash=sha256:f77ccde33fd5745db9d637787ed191aa359066efc73bc19e82f1c82e14ceecc1 + # via pyvcg +gitdb==4.0.12 \ + --hash=sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571 \ + --hash=sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf + # via gitpython +gitpython==3.1.46 \ + --hash=sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f \ + --hash=sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058 + # via bmw-lobster-core +idna==3.11 \ + --hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \ + --hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902 + # via requests +libcst==1.8.6 \ + --hash=sha256:04030ea4d39d69a65873b1d4d877def1c3951a7ada1824242539e399b8763d30 \ + --hash=sha256:06fc56335a45d61b7c1b856bfab4587b84cfe31e9d6368f60bb3c9129d900f58 \ + --hash=sha256:089c58e75cb142ec33738a1a4ea7760a28b40c078ab2fd26b270dac7d2633a4d \ + --hash=sha256:08bd63a8ce674be431260649e70fca1d43f1554f1591eac657f403ff8ef82c7a \ + --hash=sha256:0c13d5bd3d8414a129e9dccaf0e5785108a4441e9b266e1e5e9d1f82d1b943c9 \ + --hash=sha256:0cbe17067055829607c5ba4afa46bfa4d0dd554c0b5a583546e690b7367a29b6 \ + --hash=sha256:16cfe0cfca5fd840e1fb2c30afb628b023d3085b30c3484a79b61eae9d6fe7ba \ + --hash=sha256:1a3a5e4ee870907aa85a4076c914ae69066715a2741b821d9bf16f9579de1105 \ + --hash=sha256:1dc3b897c8b0f7323412da3f4ad12b16b909150efc42238e19cbf19b561cc330 \ + --hash=sha256:203ec2a83f259baf686b9526268cd23d048d38be5589594ef143aee50a4faf7e \ + --hash=sha256:207481197afd328aa91d02670c15b48d0256e676ce1ad4bafb6dc2b593cc58f1 \ + --hash=sha256:25eaeae6567091443b5374b4c7d33a33636a2d58f5eda02135e96fc6c8807786 \ + --hash=sha256:25fc7a1303cad7639ad45ec38c06789b4540b7258e9a108924aaa2c132af4aca \ + --hash=sha256:2f04d3672bde1704f383a19e8f8331521abdbc1ed13abb349325a02ac56e5012 \ + --hash=sha256:351ab879c2fd20d9cb2844ed1ea3e617ed72854d3d1e2b0880ede9c3eea43ba8 \ + --hash=sha256:36473e47cb199b7e6531d653ee6ffed057de1d179301e6c67f651f3af0b499d6 \ + --hash=sha256:3649a813660fbffd7bc24d3f810b1f75ac98bd40d9d6f56d1f0ee38579021073 \ + --hash=sha256:375965f34cc6f09f5f809244d3ff9bd4f6cb6699f571121cebce53622e7e0b86 \ + --hash=sha256:3a926a4b42015ee24ddfc8ae940c97bd99483d286b315b3ce82f3bafd9f53474 \ + --hash=sha256:3f4fbb7f569e69fd9e89d9d9caa57ca42c577c28ed05062f96a8c207594e75b8 \ + --hash=sha256:42a4f68121e2e9c29f49c97f6154e8527cd31021809cc4a941c7270aa64f41aa \ + --hash=sha256:44f38139fa95e488db0f8976f9c7ca39a64d6bc09f2eceef260aa1f6da6a2e42 \ + --hash=sha256:455f49a93aea4070132c30ebb6c07c2dea0ba6c1fde5ffde59fc45dbb9cfbe4b \ + --hash=sha256:4d7bbdd35f3abdfb5ac5d1a674923572dab892b126a58da81ff2726102d6ec2e \ + --hash=sha256:4fc3fef8a2c983e7abf5d633e1884c5dd6fa0dcb8f6e32035abd3d3803a3a196 \ + --hash=sha256:536567441182a62fb706e7aa954aca034827b19746832205953b2c725d254a93 \ + --hash=sha256:5432e785322aba3170352f6e72b32bea58d28abd141ac37cc9b0bf6b7c778f58 \ + --hash=sha256:55ec021a296960c92e5a33b8d93e8ad4182b0eab657021f45262510a58223de1 \ + --hash=sha256:59a7e388c57d21d63722018978a8ddba7b176e3a99bd34b9b84a576ed53f2978 \ + --hash=sha256:5dcaaebc835dfe5755bc85f9b186fb7e2895dda78e805e577fef1011d51d5a5c \ + --hash=sha256:6366ab2107425bf934b0c83311177f2a371bfc757ee8c6ad4a602d7cbcc2f363 \ + --hash=sha256:6421a930b028c5ef4a943b32a5a78b7f1bf15138214525a2088f11acbb7d3d64 \ + --hash=sha256:6609291c41f7ad0bac570bfca5af8fea1f4a27987d30a1fa8b67fe5e67e6c78d \ + --hash=sha256:6a65f844d813ab4ef351443badffa0ae358f98821561d19e18b3190f59e71996 \ + --hash=sha256:6aa11df6c58812f731172b593fcb485d7ba09ccc3b52fea6c7f26a43377dc748 \ + --hash=sha256:6b23d14a7fc0addd9795795763af26b185deb7c456b1e7cc4d5228e69dab5ce8 \ + --hash=sha256:6cad63e3a26556b020b634d25a8703b605c0e0b491426b3e6b9e12ed20f09100 \ + --hash=sha256:6d8b67874f2188399a71a71731e1ba2d1a2c3173b7565d1cc7ffb32e8fbaba5b \ + --hash=sha256:72cca15800ffc00ba25788e4626189fe0bc5fe2a0c1cb4294bce2e4df21cc073 \ + --hash=sha256:7445479ebe7d1aff0ee094ab5a1c7718e1ad78d33e3241e1a1ec65dcdbc22ffb \ + --hash=sha256:7f04febcd70e1e67917be7de513c8d4749d2e09206798558d7fe632134426ea4 \ + --hash=sha256:8066f1b70f21a2961e96bedf48649f27dfd5ea68be5cd1bed3742b047f14acde \ + --hash=sha256:819c8081e2948635cab60c603e1bbdceccdfe19104a242530ad38a36222cb88f \ + --hash=sha256:85b7025795b796dea5284d290ff69de5089fc8e989b25d6f6f15b6800be7167f \ + --hash=sha256:87e74f7d7dfcba9efa91127081e22331d7c42515f0a0ac6e81d4cf2c3ed14661 \ + --hash=sha256:8a434c521fadaf9680788b50d5c21f4048fa85ed19d7d70bd40549fbaeeecab1 \ + --hash=sha256:98fa1ca321c81fb1f02e5c43f956ca543968cc1a30b264fd8e0a2e1b0b0bf106 \ + --hash=sha256:a20c5182af04332cc94d8520792befda06d73daf2865e6dddc5161c72ea92cb9 \ + --hash=sha256:b0d8c364c44ae343937f474b2e492c1040df96d94530377c2f9263fb77096e4f \ + --hash=sha256:b188e626ce61de5ad1f95161b8557beb39253de4ec74fc9b1f25593324a0279c \ + --hash=sha256:b6c1248cc62952a3a005792b10cdef2a4e130847be9c74f33a7d617486f7e532 \ + --hash=sha256:ba9ab2b012fbd53b36cafd8f4440a6b60e7e487cd8b87428e57336b7f38409a4 \ + --hash=sha256:bb9b4077bdf8857b2483879cbbf70f1073bc255b057ec5aac8a70d901bb838e9 \ + --hash=sha256:bdb14bc4d4d83a57062fed2c5da93ecb426ff65b0dc02ddf3481040f5f074a82 \ + --hash=sha256:bff00e1c766658adbd09a175267f8b2f7616e5ee70ce45db3d7c4ce6d9f6bec7 \ + --hash=sha256:c0a0cc80aebd8aa15609dd4d330611cbc05e9b4216bcaeabba7189f99ef07c28 \ + --hash=sha256:c188d06b583900e662cd791a3f962a8c96d3dfc9b36ea315be39e0a4c4792ebf \ + --hash=sha256:c41c76e034a1094afed7057023b1d8967f968782433f7299cd170eaa01ec033e \ + --hash=sha256:c9d7aeafb1b07d25a964b148c0dda9451efb47bbbf67756e16eeae65004b0eb5 \ + --hash=sha256:cb2679ef532f9fa5be5c5a283b6357cb6e9888a8dd889c4bb2b01845a29d8c0b \ + --hash=sha256:da95b38693b989eaa8d32e452e8261cfa77fe5babfef1d8d2ac25af8c4aa7e6d \ + --hash=sha256:e00e275d4ba95d4963431ea3e409aa407566a74ee2bf309a402f84fc744abe47 \ + --hash=sha256:f1472eeafd67cdb22544e59cf3bfc25d23dc94058a68cf41f6654ff4fcb92e09 \ + --hash=sha256:f729c37c9317126da9475bdd06a7208eb52fcbd180a6341648b45a56b4ba708b \ + --hash=sha256:fea5c7fa26556eedf277d4f72779c5ede45ac3018650721edd77fd37ccd4a2d4 + # via bmw-lobster-tool-python +markdown==3.10.2 \ + --hash=sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950 \ + --hash=sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36 + # via bmw-lobster-core +miss-hit==0.9.44 \ + --hash=sha256:8416c42123960fad515f40b6129104ed09a84688e3efd07839d0fbfc2052bdde \ + --hash=sha256:c0705b07bc4bdb54f803889c721058871cadfe20c7dc650867818b2d45e7a4ae + # via bmw-lobster +miss-hit-core==0.9.44 \ + --hash=sha256:1c91601ff1dbf7ef217c46028fedbb940b15501d5e52fa393e91e81fc7f1b2b9 \ + --hash=sha256:899f0b1a7d6d7a11d5435ffd5c528aa2fb9483c881cdf5ede3fcd9ea20fb8f9c + # via miss-hit +pyvcg[api]==1.0.8 \ + --hash=sha256:1a91e1fa296b5895ebc55deb49a402e706900386f9459ce9140f136243e6d130 \ + --hash=sha256:93541fd57b99ee013b8da06ccf65a6ae00988b5c496f533c2bea1804ae90f4d3 + # via + # pyvcg + # trlc +pyyaml==6.0.3 \ + --hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \ + --hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \ + --hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \ + --hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \ + --hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \ + --hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \ + --hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \ + --hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \ + --hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \ + --hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \ + --hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \ + --hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \ + --hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \ + --hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \ + --hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \ + --hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \ + --hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \ + --hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \ + --hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \ + --hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \ + --hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \ + --hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \ + --hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \ + --hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \ + --hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \ + --hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \ + --hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \ + --hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \ + --hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \ + --hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \ + --hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \ + --hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \ + --hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \ + --hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \ + --hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \ + --hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \ + --hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \ + --hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \ + --hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \ + --hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \ + --hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \ + --hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \ + --hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \ + --hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \ + --hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \ + --hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \ + --hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \ + --hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \ + --hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \ + --hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \ + --hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \ + --hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \ + --hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \ + --hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \ + --hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \ + --hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \ + --hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \ + --hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \ + --hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \ + --hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \ + --hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \ + --hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \ + --hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \ + --hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \ + --hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \ + --hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \ + --hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \ + --hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \ + --hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \ + --hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \ + --hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \ + --hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \ + --hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0 + # via + # bmw-lobster-core + # libcst + # yamale +requests==2.33.1 \ + --hash=sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517 \ + --hash=sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a + # via bmw-lobster-tool-codebeamer +smmap==5.0.3 \ + --hash=sha256:4d9debb8b99007ae47165abc08670bd74cb74b5227dda7f643eccc4e9eb5642c \ + --hash=sha256:c106e05d5a61449cf6ba9a1e650227ecfb141590d2a98412103ff35d89fc7b2f + # via gitdb +trlc==2.0.3 \ + --hash=sha256:86b4c8690239f7b993259b316b8d6079633e32dff8f8ddbae5ad61503ac9362d + # via bmw-lobster-tool-trlc +urllib3==2.6.3 \ + --hash=sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed \ + --hash=sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4 + # via requests +yamale==6.1.0 \ + --hash=sha256:7e109c9d83e3a7e42703516cb2b70b9c7aa5b7a738019c4a6c202b6b0b9096c5 \ + --hash=sha256:fd435aa7b830c73e89a9ef548c0ace2d3d8dc3e5e180e6b57ff70b31495672fd + # via bmw-lobster-core diff --git a/lobster_bazel/test/BUILD b/lobster_bazel/test/BUILD new file mode 100644 index 00000000..baa60c96 --- /dev/null +++ b/lobster_bazel/test/BUILD @@ -0,0 +1,58 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("@rules_python//python:defs.bzl", "py_library", "py_test") +load("//lobster_bazel:lobster_bazel.bzl", "lobster_linker") + +# BUILD.bazel +# gazelle:exclude __init__.py + +py_library( + name = "test_runner", + srcs = [ + "__init__.py", + "test_runner.py", + ], + imports = ["."], +) + +py_test( + name = "test_basic_tracing", + srcs = ["test_basic_tracing.py"], + data = [ + "//lobster_bazel:lobster-bazel", + "//lobster_bazel/test/data:bazel_data_system", + ], + deps = [ + ":test_runner", + ], +) + +lobster_linker( + name = "impl_trace", + srcs = [ + "//lobster_bazel/test/data:cpp_source_with_tags", + "//lobster_bazel/test/data:py_source_with_tags", + ], + tracing_tags = ["req-traceability"], +) + +py_test( + name = "test_bazel_rule", + srcs = ["test_bazel_rule.py"], + data = [ + ":impl_trace", + ], + deps = [ + ":test_runner", + ], +) diff --git a/lobster_bazel/test/__init__.py b/lobster_bazel/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lobster_bazel/test/data/BUILD.bazel b/lobster_bazel/test/data/BUILD.bazel new file mode 100644 index 00000000..a6606855 --- /dev/null +++ b/lobster_bazel/test/data/BUILD.bazel @@ -0,0 +1,59 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +filegroup( + name = "bazel_data_system", + srcs = glob( + [ + "*.py", + "*.lobster", + "*.txt", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) + +cc_library( + name = "cpp_source_with_tags", + srcs = ["source_with_tags.cpp"], + hdrs = ["source_with_tags.h"], + visibility = [ + "//lobster_bazel/test:__pkg__", + ], +) + +py_binary( + name = "py_source_with_tags", + srcs = [ + "dependency_with_tags.py", + "source_with_tags.py", + ], + main = "source_with_tags.py", + visibility = [ + "//lobster_bazel/test:__pkg__", + ], + deps = [ + ":source_with_tags_lib", + ], +) + +py_library( + name = "source_with_tags_lib", + srcs = [ + "transitive_dependency_with_tags.py", + ], + imports = ["."], + visibility = [ + "//lobster_bazel/test:__pkg__", + ], +) diff --git a/lobster_bazel/test/data/dependency_with_tags.py b/lobster_bazel/test/data/dependency_with_tags.py new file mode 100644 index 00000000..d681338e --- /dev/null +++ b/lobster_bazel/test/data/dependency_with_tags.py @@ -0,0 +1,17 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +def module_function(): + # req-traceability: FEAT_REQ_024 + pass diff --git a/lobster_bazel/test/data/file_list.txt b/lobster_bazel/test/data/file_list.txt new file mode 100644 index 00000000..ca957b6e --- /dev/null +++ b/lobster_bazel/test/data/file_list.txt @@ -0,0 +1 @@ +source_with_tags.py diff --git a/lobster_bazel/test/data/source_with_tags.cpp b/lobster_bazel/test/data/source_with_tags.cpp new file mode 100644 index 00000000..1fdcbb7e --- /dev/null +++ b/lobster_bazel/test/data/source_with_tags.cpp @@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "lobster_bazel/test/data/source_with_tags.h" + +namespace { + +void validate_input_imp() { + // req-traceability: FEAT_REQ_012 +} +} // namespace + +void validate_input() { validate_input_imp(); }; diff --git a/lobster_bazel/test/data/source_with_tags.h b/lobster_bazel/test/data/source_with_tags.h new file mode 100644 index 00000000..34b0fac5 --- /dev/null +++ b/lobster_bazel/test/data/source_with_tags.h @@ -0,0 +1,20 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef LOBSTER_BAZEL_TEST_DATA_SOURCE_WITH_TAGS_H +#define LOBSTER_BAZEL_TEST_DATA_SOURCE_WITH_TAGS_H + +// req-traceability: FEAT_REQ_011 +void validate_input(); + +#endif // LOBSTER_BAZEL_TEST_DATA_SOURCE_WITH_TAGS_H diff --git a/lobster_bazel/test/data/source_with_tags.py b/lobster_bazel/test/data/source_with_tags.py new file mode 100644 index 00000000..aeb79ce8 --- /dev/null +++ b/lobster_bazel/test/data/source_with_tags.py @@ -0,0 +1,34 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +from dependency_with_tags import module_function +from trandependency_with_tags import library_function + + +def process_safety_function(): + # req-traceability: COMP_REQ_001 + pass + + +def validate_input(): + # req-traceability: FEAT_REQ_042 + pass + + +def validate_output(): + # req-traceability: FEAT_REQ_042 + module_function() + + +# req-traceability: FEAT_REQ_043 +def another_safety_function(): + library_function() diff --git a/lobster_bazel/test/data/transitive_dependency_with_tags.py b/lobster_bazel/test/data/transitive_dependency_with_tags.py new file mode 100644 index 00000000..e3d5e933 --- /dev/null +++ b/lobster_bazel/test/data/transitive_dependency_with_tags.py @@ -0,0 +1,17 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +def library_function(): + # req-traceability: FEAT_REQ_034 + pass diff --git a/lobster_bazel/test/lobster_bazel_system_test_case_base.py b/lobster_bazel/test/lobster_bazel_system_test_case_base.py new file mode 100644 index 00000000..2fb5d94a --- /dev/null +++ b/lobster_bazel/test/lobster_bazel_system_test_case_base.py @@ -0,0 +1,34 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +from pathlib import Path + +from lobster.test.lobster_bazel.lobster_bazel_test_runner import LobsterBazelTestRunner +from tests_system.system_test_case_base import SystemTestCaseBase + + +class TestRunner: + def __init__(self, working_dir: Path): + self._working_dir = working_dir + + +class LobsterBazelSystemTestCaseBase(SystemTestCaseBase): + def __init__(self, methodName): + super().__init__(methodName) + self._data_directory = Path(__file__).parents[0] / "data" + + def create_test_runner(self) -> LobsterBazelTestRunner: + tool_name = Path(__file__).parents[0].name + test_runner = LobsterBazelTestRunner( + self.create_temp_dir(prefix=f"test-{tool_name}-"), + ) + return test_runner diff --git a/lobster_bazel/test/test_basic_tracing.py b/lobster_bazel/test/test_basic_tracing.py new file mode 100644 index 00000000..ae8a9380 --- /dev/null +++ b/lobster_bazel/test/test_basic_tracing.py @@ -0,0 +1,121 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +from typing import List, Optional, Set +import unittest +from pathlib import Path + +from test_runner import TestRunner + + +class BasicTracingTest(unittest.TestCase): + """Tests for basic tracing tag extraction from source files.""" + + def setUp(self): + cwd = Path(__file__).parent + # Resolve lobster_bazel binary from runfiles + tool_path = Path(__file__).parent.parent / "lobster-bazel" + self._test_runner = TestRunner(cwd, tool_path) + self._data_directory: Path = cwd / "data" + + self._test_runner.copy_file_to_working_directory( + self._data_directory / "source_with_tags.py" + ) + self._test_runner.copy_file_to_working_directory( + self._data_directory / "file_list.txt" + ) + + def _configure_cmd_args( + self, + output_file: str, + namespace: Optional[str] = None, + inputs: List[str] = ["file_list.txt"], + ): + output_file_path: Path = self._test_runner.working_dir / output_file + + self._test_runner.cmd_args.output = output_file_path.as_posix() + self._test_runner.cmd_args.tags = ["req-traceability"] + self._test_runner.cmd_args.inputs = inputs + + if namespace: + self._test_runner.cmd_args.namespace = namespace + + return output_file_path + + # gToDo: delete this helper function + def load_output_file(self, output_file: Path): + """Declares an output file that should be generated by the tool.""" + print(f"Declaring output file: {output_file}") + with open(output_file, "r") as f: + content = f.read() + return content + + def test_python_file_with_tracing_tags(self): + """ + Test that tracing tags are correctly extracted from a Python source file. + """ + + output_file_path = self._configure_cmd_args( + output_file="source_with_tags.lobster" + ) + + completed_process = self._test_runner.run_tool_test() + + self.assertEqual(completed_process.returncode, 0) + + missing: Set[str] = self._test_runner.verify_lobster_tags( + output_file_path, + ["source COMP_REQ_001", "source FEAT_REQ_042", "source FEAT_REQ_043"], + ) + + self.assertFalse(missing, f"Missing tags in output: {missing}") + + def test_custom_namespace(self): + """ + Test that the custom namespace is applied to extracted tracing tags. + """ + + output_file_path = self._configure_cmd_args( + output_file="source_ns.lobster", namespace="impl" + ) + + completed_process = self._test_runner.run_tool_test() + + self.assertEqual(completed_process.returncode, 0) + + missing: Set[str] = self._test_runner.verify_lobster_tags( + output_file_path, + ["impl COMP_REQ_001", "impl FEAT_REQ_042", "impl FEAT_REQ_043"], + ) + + self.assertFalse(missing, f"Missing tags in output: {missing}") + + def test_no_file_list_inputs(self): + """ + Test that an empty output is produced when no file-list inputs are given. + """ + out_file_path = self._configure_cmd_args( + output_file="empty.lobster", + inputs=[], # No file list inputs + ) + + completed_process = self._test_runner.run_tool_test() + + self.assertEqual(completed_process.returncode, 0) + self.assertEqual( + completed_process.stdout, + f"lobster-bazel: wrote 0 items to {out_file_path}\n", + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/lobster_bazel/test/test_bazel_rule.py b/lobster_bazel/test/test_bazel_rule.py new file mode 100644 index 00000000..fef123f0 --- /dev/null +++ b/lobster_bazel/test/test_bazel_rule.py @@ -0,0 +1,53 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +import unittest +from pathlib import Path + +from test_runner import TestRunner + + +class BazelRuleTest(unittest.TestCase): + """Tests for basic tracing tag extraction from source files.""" + + def setUp(self): + cwd = Path(__file__).parent + # Resolve lobster_bazel binary from runfiles + self._output_lobster: Path = cwd / "impl_trace.lobster" + self._test_runner = TestRunner(cwd, cwd) + + def test_correct_source_generation(self): + """ + Read source file and configrm that it contains expected file names. + """ + + expected_file_names = { + "source_with_tags.py", + "dependency_with_tags.py", + "transitive_dependency_with_tags.py", + "source_with_tags.h", + "source_with_tags.cpp", + } + + file_names = self._test_runner.extract_lobster_file_names(self._output_lobster) + + required_file_names = expected_file_names - file_names + + self.assertTrue( + expected_file_names <= file_names, + f"""Not all dependencies were extracted from the +targets. Required but not extracted file names: {required_file_names}""", + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/lobster_bazel/test/test_runner.py b/lobster_bazel/test/test_runner.py new file mode 100644 index 00000000..c57cec51 --- /dev/null +++ b/lobster_bazel/test/test_runner.py @@ -0,0 +1,107 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +from dataclasses import dataclass, field +from pathlib import Path +from typing import Optional, List, Set +import json +import subprocess + + +@dataclass +class CmdArgs: + output: Optional[str] = None + tags: List[str] = field(default_factory=list) + namespace: Optional[str] = None + inputs: List[str] = field(default_factory=list) + + def as_list(self) -> List[str]: + """Returns the command line arguments as a list for lobster-bazel""" + cmd_args: List[str] = [] + + if self.output is not None: + cmd_args.append(f"--output={self.output}") + for tag in self.tags: + cmd_args.extend(["--tag", tag]) + if self.namespace is not None: + cmd_args.append(f"--namespace={self.namespace}") + cmd_args.extend(self.inputs) + + return cmd_args + + +class TestRunner: + def __init__(self, working_dir: Path, tool_path: Path): + self.working_dir = working_dir + self.tool_path = tool_path + self.cmd_args = CmdArgs() + + def get_tool_args(self) -> List[str]: + """Returns the command line arguments for 'lobster-bazel'""" + return self.cmd_args.as_list() + + def run_tool_test(self): + """Runs the tool with the specified command line arguments and returns + the completed process.""" + + cmd = [str(self.tool_path)] + self.get_tool_args() + completed_process = subprocess.run( + cmd, + cwd=self.working_dir, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + return completed_process + + def copy_file_to_working_directory(self, source: Path): + """Copies a file from the source path to the working directory.""" + destination = self.working_dir / source.name + destination.write_bytes(source.read_bytes()) + + def _read_lobster_file(self, lobster_file: Path) -> dict: + try: + content = json.loads(lobster_file.read_text(encoding="utf-8")) + except json.JSONDecodeError as e: + raise ValueError(f"Failed to parse {lobster_file} as JSON: {e}") from e + + if "data" not in content: + raise ValueError( + f"{lobster_file} invalid .lobster file: missing 'data' key" + ) + return content + + def verify_lobster_tags( + self, lobster_file: Path, expected_tags: List[str] + ) -> Set[str]: + """ + Parse a .lobster file and verify it contains all expected tag names. + """ + + content = self._read_lobster_file(lobster_file) + + found_tags: Set[str] = { + item["tag"] for item in content["data"] if "tag" in item + } + return set(expected_tags) - found_tags + + def extract_lobster_file_names(self, lobster_file: Path) -> Set[str]: + """ + Parse a .lobster file and verify it contains all expected file names. + """ + + content = self._read_lobster_file(lobster_file) + + found_file_names: Set[str] = { + Path(item["location"]["file"]).name for item in content["data"] + } + return found_file_names