Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No tests for starlark changes

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def assumed_system_requirements(
spec = Label("//bazel/rules/rules_score/trlc/config:score_requirements_model"),
lobster_config = Label("//bazel/rules/rules_score/lobster/config:assumed_system_requirement"),
ref_package = "",
package = "",
image_srcs = [],
**kwargs):
"""Define Assumed System Requirements following S-CORE process guidelines.
Expand Down Expand Up @@ -87,6 +88,7 @@ def assumed_system_requirements(
lobster_config = lobster_config,
spec = spec,
ref_package = ref_package,
package = package,
image_srcs = image_srcs,
**kwargs
)
Expand Down
2 changes: 2 additions & 0 deletions bazel/rules/rules_score/private/assumptions_of_use.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def assumptions_of_use(
srcs,
deps = [],
ref_package = None,
package = "",
lobster_config = Label("//bazel/rules/rules_score/lobster/config:aou_config"),
**kwargs):
"""Define Assumptions of Use following S-CORE process guidelines.
Expand Down Expand Up @@ -92,6 +93,7 @@ def assumptions_of_use(
req_kind = "aou",
lobster_config = lobster_config,
ref_package = ref_package or "",
package = package,
**kwargs
)
trlc_requirements_test(
Expand Down
2 changes: 2 additions & 0 deletions bazel/rules/rules_score/private/component_requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def component_requirements(
spec = Label("//bazel/rules/rules_score/trlc/config:score_requirements_model"),
lobster_config = Label("//bazel/rules/rules_score/lobster/config:component_requirement"),
ref_package = "",
package = "",
image_srcs = [],
**kwargs):
"""Define component requirements following S-CORE process guidelines.
Expand Down Expand Up @@ -86,6 +87,7 @@ def component_requirements(
lobster_config = lobster_config,
spec = spec,
ref_package = ref_package,
package = package,
image_srcs = image_srcs,
**kwargs
)
Expand Down
2 changes: 2 additions & 0 deletions bazel/rules/rules_score/private/feature_requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def feature_requirements(
spec = Label("//bazel/rules/rules_score/trlc/config:score_requirements_model"),
lobster_config = Label("//bazel/rules/rules_score/lobster/config:feature_requirement"),
ref_package = "",
package = "",
image_srcs = [],
**kwargs):
"""Define feature requirements following S-CORE process guidelines.
Expand Down Expand Up @@ -86,6 +87,7 @@ def feature_requirements(
lobster_config = lobster_config,
spec = spec,
ref_package = ref_package,
package = package,
image_srcs = image_srcs,
**kwargs
)
Expand Down
5 changes: 5 additions & 0 deletions bazel/rules/rules_score/private/requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ def score_requirements_rule(
deps = [],
spec = [],
ref_package = "",
package = "",
**kwargs):
"""Macro wrapper around _score_requirements_rule with RST support.

Expand All @@ -226,6 +227,9 @@ def score_requirements_rule(
ref_package: TRLC package prefix used for derived_from cross-references
when converting RST sources (e.g. "AssumedSystemRequirements" for
feature requirements that derive from ASR).
package: TRLC package name to use for any generated .trlc file(s) when
converting RST sources. Defaults to the input file's stem (e.g.
"index.rst" -> "Index") if left empty.

Returns:
List of resolved labels corresponding to srcs (after any .rst-to-.trlc
Expand All @@ -244,6 +248,7 @@ def score_requirements_rule(
name = gen_name,
srcs = [src],
ref_package = ref_package,
package = package,
)
trlc_srcs.append(":" + gen_name)
resolved_srcs.append(":" + gen_name)
Expand Down
4 changes: 2 additions & 2 deletions bazel/rules/rules_score/private/rst_to_trlc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ def rst_srcs_to_trlc(name, srcs, deps = [], ref_package = ""):
def _rst_to_trlc_impl(ctx):
"""Convert each .rst source file to a .trlc file via the Python converter."""
outs = []
for src in ctx.files.srcs:
out = ctx.actions.declare_file(src.basename[:-4] + ".trlc", sibling = src)
for i, src in enumerate(ctx.files.srcs):
out = ctx.actions.declare_file(ctx.label.name + "/" + str(i) + "/" + src.basename.removesuffix(".rst") + ".trlc")
outs.append(out)

args = ctx.actions.args()
Expand Down
44 changes: 42 additions & 2 deletions bazel/rules/rules_score/src/rst_to_trlc.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
_RE_MARKUP = re.compile(r"\*\*?(.*?)\*\*?")
_RE_DIRECTIVE = re.compile(r"^\.\.\s+([\w]+)::\s*(.*)")
_RE_FIELD = re.compile(r"^\s+:([\w]+):\s*(.*)") # noqa: E501
_RE_NEEDS_FILTER = re.compile(r"(\s*\[[^\[\]]*\])+\s*$")

_TRLC_HEADER = """\
/********************************************************************************
Expand Down Expand Up @@ -135,9 +136,40 @@ def _escape(text: str) -> str:
return text.replace("\\", "\\\\").replace('"', '\\"')


def _split_top_level(value: str, sep: str = ",") -> list[str]:
"""Split on ``sep``, ignoring occurrences nested inside ``[...]`` brackets."""
parts: list[str] = []
current: list[str] = []
depth = 0
for ch in value:
if ch == "[":
depth += 1
elif ch == "]":
depth = max(depth - 1, 0)
if ch == sep and depth == 0:
parts.append("".join(current))
current = []
else:
current.append(ch)
parts.append("".join(current))
return parts


def _collect_refs(fields: dict[str, str]) -> list[str]:
"""Extract all cross-reference IDs from relationship fields."""
return [r.strip() for k in _REF_FIELDS if k in fields for r in fields[k].split(",") if r.strip()]
"""Extract cross-reference IDs from relationship fields.

Strips trailing sphinx-needs filter expressions (E.g. [version==1]),
which aren't valid TRLC reference syntax.
"""
refs: list[str] = []
for k in _REF_FIELDS:
if k not in fields:
continue
for r in _split_top_level(fields[k]):
ref = _RE_NEEDS_FILTER.sub("", r.strip()).strip()
if ref:
refs.append(ref)
return refs


def parse_directives(content: str) -> list[dict[str, Any]]:
Expand All @@ -154,6 +186,14 @@ def parse_directives(content: str) -> list[dict[str, Any]]:
directive, title = m.group(1), m.group(2).strip()
i += 1

# RST directive arguments may wrap onto continuation lines (docutils
# allows this); consume any such lines here before the field list,
# otherwise they get mis-parsed as body text and the real :id: (and
# other fields) on the following lines are missed entirely.
while i < len(lines) and lines[i].strip() and lines[i][0].isspace() and not _RE_FIELD.match(lines[i]):
title += " " + lines[i].strip()
i += 1

fields, i = _collect_fields(lines, i)
raw_body, i = _collect_body(lines, i)
body = _RE_MARKUP.sub(r"\1", raw_body).strip()
Expand Down
40 changes: 40 additions & 0 deletions bazel/rules/rules_score/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ load(
"unit_design",
)
load("@score_tooling//bazel/rules/rules_score:sphinx_toolchain.bzl", "score_sphinx_toolchain")
load("@score_tooling//bazel/rules/rules_score/private:rst_to_trlc.bzl", "rst_to_trlc")
load("@score_tooling//cpp/libclang:libclang_toolchain.bzl", "libclang_toolchain")
load("@trlc//:trlc.bzl", "trlc_requirements", "trlc_requirements_test", "trlc_specification")
load(
Expand Down Expand Up @@ -71,6 +72,12 @@ load(
"feat_req_multi_spec_provider_test",
"requirements_multi_spec_test_suite",
)
load(
":requirements_package_test.bzl",
"asr_package_forwarded_test",
"requirements_package_test_suite",
"rst_to_trlc_no_collision_test",
)
load(
":requirements_rst_test.bzl",
"aous_rst_provider_test",
Expand Down Expand Up @@ -1723,6 +1730,38 @@ aous_rst_sphinx_test(

requirements_rst_test_suite(name = "requirements_rst_tests")

# ============================================================================
# package attr forwarding / rst_to_trlc output-path collision tests
# ============================================================================

# Fixture: package attr must forward to the generated rst_to_trlc target.
assumed_system_requirements(
name = "asr_custom_package",
srcs = ["fixtures/rst_requirements/assumed_system_requirements.rst"],
package = "CustomAsrPackage",
)

asr_package_forwarded_test(
name = "asr_package_forwarded_test",
target_under_test = ":_asr_custom_package_rst_gen_0",
)

# Fixture: same-basename .rst srcs in one target must not collide.
rst_to_trlc(
name = "rst_collision_fixture",
srcs = [
"fixtures/rst_collision/a/req.rst",
"fixtures/rst_collision/b/req.rst",
],
)

rst_to_trlc_no_collision_test(
name = "rst_to_trlc_no_collision_test",
target_under_test = ":rst_collision_fixture",
)

requirements_package_test_suite(name = "requirements_package_tests")

# ============================================================================
# Multi-spec Requirements Tests
# ============================================================================
Expand Down Expand Up @@ -1884,6 +1923,7 @@ test_suite(
tests = [
":lobster_config_tests",
":requirements_multi_spec_tests",
":requirements_package_tests",
":requirements_rst_tests",
":seooc_tests",
":sphinx_module_tests",
Expand Down
22 changes: 22 additions & 0 deletions bazel/rules/rules_score/test/fixtures/rst_collision/a/req.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
..
# *******************************************************************************
# 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
# *******************************************************************************

Collision Fixture A
====================

.. comp_req:: From A
:id: comp_req__collision_test__a
:safety: QM

Requirement sourced from a/req.rst.
22 changes: 22 additions & 0 deletions bazel/rules/rules_score/test/fixtures/rst_collision/b/req.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
..
# *******************************************************************************
# 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
# *******************************************************************************

Collision Fixture B
====================

.. comp_req:: From B
:id: comp_req__collision_test__b
:safety: QM

Requirement sourced from b/req.rst.
64 changes: 64 additions & 0 deletions bazel/rules/rules_score/test/requirements_package_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# *******************************************************************************
# 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
# *******************************************************************************
"""Tests for the ``package`` attr and the rst_to_trlc output-path fix."""

load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")

# ============================================================================
# assumed_system_requirements(package = ...) forwards to rst_to_trlc
# ============================================================================

def _asr_package_forwarded_test_impl(ctx):
env = analysistest.begin(ctx)
actions = analysistest.target_actions(env)
rst_actions = [a for a in actions if a.mnemonic == "RstToTrlc"]

asserts.true(env, len(rst_actions) == 1, "expected exactly one RstToTrlc action")
if rst_actions:
argv = rst_actions[0].argv
asserts.true(env, "--package" in argv, "expected --package in RstToTrlc argv")
asserts.equals(env, "CustomAsrPackage", argv[argv.index("--package") + 1])

return analysistest.end(env)

asr_package_forwarded_test = analysistest.make(_asr_package_forwarded_test_impl)

# ============================================================================
# rst_to_trlc: same-basename srcs in one target must not collide
# ============================================================================

def _rst_to_trlc_no_collision_test_impl(ctx):
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)
outs = target_under_test[DefaultInfo].files.to_list()

asserts.equals(env, 2, len(outs))
asserts.true(env, outs[0].path != outs[1].path, "same-basename srcs must produce distinct output paths")

return analysistest.end(env)

rst_to_trlc_no_collision_test = analysistest.make(_rst_to_trlc_no_collision_test_impl)

# ============================================================================
# Test Suite
# ============================================================================

def requirements_package_test_suite(name):
"""Register the package-forwarding and output-collision tests."""
native.test_suite(
name = name,
tests = [
":asr_package_forwarded_test",
":rst_to_trlc_no_collision_test",
],
)
Loading
Loading