Skip to content

Commit 2282fe3

Browse files
authored
docs: update architecture (eclipse-score#807)
- Include Module View - Adapt Plotting Scripts - Adapt Example
1 parent ef8da32 commit 2282fe3

File tree

10 files changed

+865
-511
lines changed

10 files changed

+865
-511
lines changed

.vscode/restructuredtext.code-snippets

+373-332
Large diffs are not rendered by default.

docs/_tooling/extensions/score_draw_uml_funcs/__init__.py

+188-80
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@
4040
gen_link_text,
4141
gen_struct_element,
4242
get_impl_comp_from_real_iface,
43-
get_interface,
43+
get_interface_from_component,
44+
get_interface_from_int,
4445
get_logical_interface_real,
46+
get_module,
4547
get_real_interface_logical,
4648
)
4749

@@ -81,12 +83,83 @@ def scripts_directory_hash():
8183
# ╰──────────────────────────────────────────────────────────────────────────────╯
8284

8385

84-
def draw_component(
85-
need: dict,
86-
all_needs: dict,
87-
proc_real_interfaces: dict[str, str] | None = None,
88-
proc_logical_interfaces: dict[str, str] | None = None,
89-
) -> tuple[str, str, dict[str, str], dict[str, str]]:
86+
def draw_comp_incl_impl_int(
87+
need: dict[str, str],
88+
all_needs: dict[str, dict],
89+
proc_impl_interfaces: dict[str, str],
90+
proc_used_interfaces: dict[str, list],
91+
) -> tuple[str, str, dict[str, str], dict[str, list]]:
92+
# Draw outer component
93+
structure_text = f"{gen_struct_element('component', need)} {{\n"
94+
linkage_text = ""
95+
96+
# Draw inner (sub)components recursively
97+
for need_inc in need.get("includes", []):
98+
curr_need = all_needs.get(need_inc, {})
99+
100+
# check for misspelled include
101+
if not curr_need:
102+
logger.info(f"{need}: include {need_inc} could not be found")
103+
continue
104+
105+
if curr_need["type"] != "comp_arc_sta":
106+
continue
107+
108+
sub_structure, sub_linkage, proc_impl_interfaces, proc_used_interfaces = (
109+
draw_comp_incl_impl_int(
110+
curr_need, all_needs, proc_impl_interfaces, proc_used_interfaces
111+
)
112+
)
113+
114+
structure_text += sub_structure
115+
linkage_text += sub_linkage
116+
117+
# close outer component
118+
structure_text += f"}} /' {need['title']} '/ \n\n"
119+
120+
# Find implemented real interfaces inside the module/component
121+
local_impl_interfaces = get_interface_from_component(need, "implements", all_needs)
122+
local_used_interfaces = get_interface_from_component(need, "uses", all_needs)
123+
124+
# Add all interfaces which are implemented by component to global list
125+
# and provide implementation
126+
for iface in local_impl_interfaces:
127+
# check for misspelled implements
128+
if not all_needs.get(iface, []):
129+
logger.info(f"{need}: implements {iface} could not be found")
130+
continue
131+
132+
if not (interface := proc_impl_interfaces.get(iface, [])):
133+
structure_text += gen_interface_element(iface, all_needs, True)
134+
linkage_text += f"{
135+
gen_link_text(
136+
need,
137+
'-u->',
138+
all_needs[iface],
139+
'implements',
140+
)
141+
} \n"
142+
proc_impl_interfaces[iface] = need["id"]
143+
144+
# Add all elements which are used by component to global list
145+
for iface in local_used_interfaces:
146+
# check for misspelled used
147+
if not all_needs.get(iface, []):
148+
logger.info(f"{need}: uses {iface} could not be found")
149+
continue
150+
151+
if not (interface := proc_used_interfaces.get(iface, [])):
152+
proc_used_interfaces[iface] = [need["id"]]
153+
else:
154+
proc_used_interfaces[iface].append(need["id"])
155+
156+
return structure_text, linkage_text, proc_impl_interfaces, proc_used_interfaces
157+
158+
159+
def draw_module(
160+
need: dict[str, str],
161+
all_needs: dict[str, dict],
162+
) -> tuple[str, str]:
90163
"""
91164
Drawing and parsing function of a component.
92165
@@ -139,76 +212,99 @@ def draw_component(
139212
(Structure Text, Linkage Text, Processed (Real Interfaces),
140213
Processed Logical Interfaces)
141214
"""
142-
proc_real_interfaces = proc_real_interfaces or dict()
143-
proc_logical_interfaces = proc_logical_interfaces or dict()
215+
# Store all Elements which have already been processed
216+
proc_impl_interfaces = dict()
217+
proc_used_interfaces = dict()
218+
proc_logical_interfaces = dict()
219+
144220
linkage_text = ""
145221

146-
# Draw outer component
147-
structure_text = f"{gen_struct_element('component', need)} {{\n"
222+
# Draw outer module
223+
structure_text = f"{gen_struct_element('package', need)} {{\n"
148224

149-
# Process includes: Draw inner (sub)components recursively
225+
# Draw inner components recursively
150226
for need_inc in need.get("includes", []):
151-
curr_need = all_needs[need_inc]
227+
curr_need = all_needs.get(need_inc, {})
152228

153-
if "comp_arc_sta" in curr_need["type"]:
154-
sub_structure, sub_links, proc_real_interfaces, proc_logical_interfaces = (
155-
draw_component(
156-
curr_need, all_needs, proc_real_interfaces, proc_logical_interfaces
157-
)
158-
)
159-
else:
229+
# check for misspelled include
230+
if not curr_need:
231+
logger.info(f"{need}: include {need_inc} could not be found")
160232
continue
161233

234+
if curr_need["type"] not in ["comp_arc_sta", "mod_view_sta"]:
235+
continue
236+
237+
sub_structure, sub_linkage, proc_impl_interfaces, proc_used_interfaces = (
238+
draw_comp_incl_impl_int(
239+
curr_need, all_needs, proc_impl_interfaces, proc_used_interfaces
240+
)
241+
)
242+
162243
structure_text += sub_structure
163-
linkage_text += sub_links
244+
linkage_text += sub_linkage
164245

165-
# close component
246+
# close outer component
166247
structure_text += f"}} /' {need['title']} '/ \n\n"
167248

168-
local_interfaces = dict()
169-
# Fill proc_real_interfaces with relation to implements and uses
170-
for interface in need.get("implements", []):
171-
iface = get_interface(interface, all_needs)
172-
if iface not in local_interfaces:
173-
local_interfaces[iface] = "implements"
174-
175-
for interface in need.get("uses", []):
176-
iface = get_interface(interface, all_needs)
177-
if iface not in local_interfaces:
178-
local_interfaces[iface] = "uses"
179-
180-
for iface in local_interfaces:
181-
# Draw interfaces
182-
if iface not in proc_real_interfaces:
183-
structure_text += gen_interface_element(iface, all_needs, True)
184-
proc_logical_interfaces[iface] = get_logical_interface_real(
185-
iface, all_needs
186-
)
187-
proc_real_interfaces[iface] = local_interfaces[iface]
249+
# Add logical interfaces only to implemented interfaces
250+
for iface, component in proc_impl_interfaces.items():
251+
if not (proc_logical_interfaces.get(iface, [])):
252+
# Currently only one Logical Interface per Real Interface supported
253+
logical_iface_tmp = get_logical_interface_real(iface, all_needs)
254+
assert (
255+
len(logical_iface_tmp) == 1
256+
), "only one logical interface per real interface supported"
257+
if logical_iface_tmp:
258+
logical_iface = logical_iface_tmp[0]
259+
proc_logical_interfaces[logical_iface] = iface
260+
261+
structure_text += gen_interface_element(logical_iface, all_needs, True)
262+
263+
linkage_text += f"{
264+
gen_link_text(
265+
all_needs[iface],
266+
'-u->',
267+
all_needs[logical_iface],
268+
'implements',
269+
)
270+
} \n"
271+
else:
272+
print(f"{iface}: Not connected to any virtual interface")
188273

189-
# Draw connection between real components and interfaces
190-
linkage_text += f"{
191-
gen_link_text(
192-
need['title'], '-->', all_needs[iface]['title'], local_interfaces[iface]
193-
)
194-
} \n"
274+
# Add all interfaces which are used by component
275+
for iface, comps in proc_used_interfaces.items():
276+
if iface not in proc_impl_interfaces:
277+
# Add implementing components and modules
278+
impl_comp_str = get_impl_comp_from_real_iface(iface, all_needs)
195279

196-
# Draw connection between real interfaces and logical interfaces
197-
# if link exists
198-
if interfaces := proc_logical_interfaces[iface]:
199-
linkage_text += f"{
200-
gen_link_text(
201-
all_needs[iface]['title'],
202-
'-->',
203-
all_needs[interfaces]['title'],
204-
'implements',
205-
)
206-
} \n"
280+
impl_comp = all_needs.get(impl_comp_str, {}) if impl_comp_str else ""
281+
282+
if impl_comp:
283+
retval = get_module(impl_comp_str, all_needs)
284+
structure_text += retval[2] # module open
285+
structure_text += retval[0] # rest open
286+
287+
structure_text += retval[1] # rest close
288+
structure_text += gen_interface_element(iface, all_needs, True)
289+
structure_text += retval[3] # module close
290+
291+
# Draw connection between implementing components and interface
292+
linkage_text += f"{gen_link_text(impl_comp, '-u->', all_needs[iface], 'implements')} \n"
293+
294+
else:
295+
# Add only interface if component not defined
296+
print(f"{iface}: No implementing component defined")
297+
structure_text += gen_interface_element(iface, all_needs, True)
298+
299+
# Interface can be used by multiple components
300+
for comp in comps:
301+
# Draw connection between used interfaces and components
302+
linkage_text += f"{gen_link_text(all_needs[comp], '-d[#green]->', all_needs[iface], 'uses')} \n"
207303

208304
# Remove duplicate links
209305
linkage_text = "\n".join(set(linkage_text.split("\n"))) + "\n"
210306

211-
return structure_text, linkage_text, proc_real_interfaces, proc_logical_interfaces
307+
return structure_text, linkage_text
212308

213309

214310
# ╭──────────────────────────────────────────────────────────────────────────────╮
@@ -224,49 +320,55 @@ def __call__(self, need, all_needs: dict) -> str:
224320
interfacelist = []
225321
impl_comp = dict()
226322

227-
structure_text = "allowmixing\n"
228-
structure_text += f'actor "Feature User" as {gen_alias("Feature User")} \n'
323+
structure_text = (
324+
f'actor "Feature User" as {gen_alias({"id": "Feature_User"})} \n'
325+
)
229326

230327
# Define Feature as a package
231-
structure_text += f"{gen_struct_element('package', need)} {{\n"
328+
# structure_text += f"{gen_struct_element('package', need)} {{\n"
232329

233330
# Add logical Interfaces / Interface Operations (aka includes)
234331
for need_inc in need.get("includes", []):
235332
# Generate list of interfaces since both interfaces
236333
# and interface operations can be included
237-
iface = get_interface(need_inc, all_needs)
238-
interfacelist.append(iface) if iface not in interfacelist else None
334+
iface = get_interface_from_int(need_inc, all_needs)
335+
if iface not in interfacelist:
336+
interfacelist.append(iface)
239337

240338
for iface in interfacelist:
241339
structure_text += gen_interface_element(iface, all_needs, True)
242340

243341
# Determine Components which implement the interfaces
244342
real_iface = get_real_interface_logical(iface, all_needs)
245-
impl_comp[iface] = get_impl_comp_from_real_iface(real_iface[0], all_needs)
343+
if real_iface:
344+
comps = get_impl_comp_from_real_iface(real_iface[0], all_needs)
246345

247-
if imcomp := impl_comp[iface]:
346+
if comps:
347+
impl_comp[iface] = comps
348+
349+
if imcomp := impl_comp.get(iface):
248350
structure_text += (
249-
f"{gen_struct_element('component', all_needs[imcomp[0]])}\n"
351+
f"{gen_struct_element('component', all_needs[imcomp])}\n"
250352
)
251353

252354
# Close Package
253-
structure_text += f"}} /' {need['title']} '/ \n\n"
355+
# structure_text += f"}} /' {need['title']} '/ \n\n"
254356

255357
link_text = ""
256358

257359
for iface in interfacelist:
258360
# Add relation between Actor and Interfaces
259361
link_text += f"{
260-
gen_link_text('Feature User', '-d->', all_needs[iface]['title'], 'use')
362+
gen_link_text({'id': 'Feature_User'}, '-d->', all_needs[iface], 'use')
261363
} \n"
262364

263365
# Add relation between interface and component
264-
if imcomp := impl_comp[iface]:
366+
if imcomp := impl_comp.get(iface):
265367
link_text += f"{
266368
gen_link_text(
267-
all_needs[imcomp[0]]['title'],
268-
'-->',
269-
all_needs[iface]['title'],
369+
all_needs[imcomp],
370+
'-u->',
371+
all_needs[iface],
270372
'implements',
271373
)
272374
} \n"
@@ -276,20 +378,25 @@ def __call__(self, need, all_needs: dict) -> str:
276378
return gen_header() + structure_text + link_text
277379

278380

381+
class draw_full_module:
382+
def __repr__(self):
383+
return "draw_full_module" + " in " + scripts_directory_hash()
384+
385+
def __call__(self, need, all_needs) -> str:
386+
structure_text, linkage_text = draw_module(need, all_needs)
387+
388+
return gen_header() + structure_text + linkage_text
389+
390+
279391
class draw_full_component:
280392
def __repr__(self):
281393
return "draw_full_component" + " in " + scripts_directory_hash()
282394

283395
def __call__(self, need, all_needs) -> str:
284396
structure_text, linkage_text, processed_interfaces, logical_interfacelist = (
285-
draw_component(need, all_needs, dict(), dict())
397+
draw_comp_incl_impl_int(need, all_needs, dict(), dict())
286398
)
287399

288-
# Draw Logical Interfaces
289-
for iface in logical_interfacelist:
290-
if log_int := logical_interfacelist[iface]:
291-
structure_text += gen_interface_element(log_int, all_needs, True)
292-
293400
return gen_header() + structure_text + linkage_text
294401

295402

@@ -305,6 +412,7 @@ def __call__(self, need, all_needs) -> str:
305412

306413
draw_uml_function_context = {
307414
"draw_interface": draw_full_interface(),
415+
"draw_module": draw_full_module(),
308416
"draw_component": draw_full_component(),
309417
"draw_feature": draw_full_feature(),
310418
}

0 commit comments

Comments
 (0)