Skip to content

Commit 09b725e

Browse files
committed
feat: add port name shortening functionality to connection resolver and emitter
Signed-off-by: Taekjin LEE <taekjin.lee@tier4.jp>
1 parent 81e6490 commit 09b725e

3 files changed

Lines changed: 66 additions & 2 deletions

File tree

tools/system-config-generator/pipeline/connection_resolver.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from .launch_parser import RemapEntry # noqa: F401 — used by callers via star-import
99
from .namespace_tree import NamespaceNode
10+
from .port_utils import shorten_port_names
1011

1112
# Topics that carry no domain-level information
1213
_INFRA_EXACT = {
@@ -103,6 +104,25 @@ def resolve_connections(top_nodes: list[NamespaceNode]) -> list[TopicConnection]
103104
ref = PortRef(component=ns_node.name, port=canonical, node_path=node.full_path)
104105
subscribers[topic].append(ref)
105106

107+
# Build per-component shortening maps from cross-component ports only.
108+
# Internal-only ports are excluded so they can't cause false collisions.
109+
comp_pub_raw: dict[str, set[str]] = defaultdict(set)
110+
comp_sub_raw: dict[str, set[str]] = defaultdict(set)
111+
for topic, pubs in publishers.items():
112+
subs_for_topic = subscribers.get(topic, [])
113+
for pub in pubs:
114+
for sub in subs_for_topic:
115+
if pub.component != sub.component:
116+
comp_pub_raw[pub.component].add(pub.port)
117+
comp_sub_raw[sub.component].add(sub.port)
118+
119+
comp_pub_short: dict[str, dict[str, str]] = {
120+
c: shorten_port_names(list(ports)) for c, ports in comp_pub_raw.items()
121+
}
122+
comp_sub_short: dict[str, dict[str, str]] = {
123+
c: shorten_port_names(list(ports)) for c, ports in comp_sub_raw.items()
124+
}
125+
106126
connections: list[TopicConnection] = []
107127
seen: set[tuple] = set()
108128

@@ -112,11 +132,19 @@ def resolve_connections(top_nodes: list[NamespaceNode]) -> list[TopicConnection]
112132
for sub in subs:
113133
if pub.component == sub.component:
114134
continue # internal – handled in module.yaml
115-
key = (pub.component, pub.port, sub.component, sub.port)
135+
pub_port = comp_pub_short.get(pub.component, {}).get(pub.port, pub.port)
136+
sub_port = comp_sub_short.get(sub.component, {}).get(sub.port, sub.port)
137+
key = (pub.component, pub_port, sub.component, sub_port)
116138
if key in seen:
117139
continue
118140
seen.add(key)
119-
connections.append(TopicConnection(publisher=pub, subscriber=sub, topic=topic))
141+
connections.append(
142+
TopicConnection(
143+
publisher=PortRef(pub.component, pub_port, pub.node_path),
144+
subscriber=PortRef(sub.component, sub_port, sub.node_path),
145+
topic=topic,
146+
)
147+
)
120148

121149
return connections
122150

tools/system-config-generator/pipeline/emitter/module.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
)
1313
from ..launch_parser import NodeRecord
1414
from ..namespace_tree import NamespaceNode
15+
from ..port_utils import shorten_port_names
1516

1617
DESIGN_FORMAT = "0.3.1"
1718

@@ -162,6 +163,14 @@ def _extract_ns_module_interface(
162163
)
163164
)
164165

166+
if external_pub:
167+
pub_short = shorten_port_names([p for p, _ in external_pub])
168+
external_pub = [(pub_short[p], t) for p, t in external_pub]
169+
170+
if external_sub:
171+
sub_short = shorten_port_names([p for p, _ in external_sub])
172+
external_sub = [(sub_short[p], t) for p, t in external_sub]
173+
165174
return ModuleInterface(
166175
publishers=external_pub,
167176
subscribers=external_sub,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Port name utilities shared across emitters and connection resolver."""
2+
3+
from __future__ import annotations
4+
5+
6+
def shorten_port_names(names: list[str]) -> dict[str, str]:
7+
"""Return {original: shortest_unique_suffix} split by '/' segments.
8+
9+
Each name is shortened to the minimum number of trailing slash-separated
10+
segments that uniquely identifies it within the list.
11+
"""
12+
segments_map = {name: name.split("/") for name in names}
13+
result: dict[str, str] = {}
14+
for name in names:
15+
segs = segments_map[name]
16+
for k in range(1, len(segs) + 1):
17+
suffix = "/".join(segs[-k:])
18+
if not any(
19+
suffix == "/".join(other_segs[-min(k, len(other_segs)) :])
20+
for other, other_segs in segments_map.items()
21+
if other != name
22+
):
23+
result[name] = suffix
24+
break
25+
else:
26+
result[name] = name
27+
return result

0 commit comments

Comments
 (0)