208def _structuredPrint(conf, start, args):
209 showClasses = args.classes or args.uniqueClasses
210 def _oneCompPrint(d, comp, cl, done={}, depth=0, indent = "") -> list:
211 show = ((not showClasses or cl is not None) and
212 (depth>0 and any([re.match(f"({regex})$",cl) for regex in args.includeClassesSub])) or
213 ((not args.includeClasses or any([re.match(f"({regex})$",cl) for regex in args.includeClasses])) and
214 not any([re.match(f"({regex})$",cl) for regex in args.excludeClasses]) and
215 not any([re.match(f"({regex})$",comp) for regex in args.excludeComponents])))
216 if show:
217 if not args.uniqueClasses:
218 if args.classes:
219 cc = cl if (not args.showComponentName) else f"{cl}/{comp}"
220 print(f
"{indent}{cc}")
221 else:
222 print(f
"{indent}{comp}")
223 newindent = indent + " - "
224 depth += 1
225 elif args.includeSequences and ((len(d) == 1 and "Members" in d) or (comp == "ApplicationMgr" and "TopAlg" in d)):
226 newindent = indent
227 else:
228 return []
229 if showClasses and args.maxDepth is not None and depth > args.maxDepth:
230 return []
231
232 sub = []
233 for prop,val in sorted(d.items()):
234 if not showClasses and show:
235 print(f
"{indent} {prop} = {val}")
236 if args.maxDepth is not None and depth > args.maxDepth:
237 continue
238 if not args.includeSequences and (prop == "Members" or prop == "TopAlg"):
239 continue
240 for ref,c in isReference(val, comp, conf):
241 if showClasses and not c:
242 continue
243 if ref in conf and ref not in done:
244 r = _oneCompPrint(conf[ref], ref, c or ref, {**done, ref:True}, depth, newindent)
245 if args.uniqueClasses:
246 sub += r
247 if show:
248 return [[cl, comp, sub]]
249 else:
250 return sub
251
252 sub = []
253 for comp in start:
254 for ref,cl in isReference(start, None, conf) or [(None,None)]:
255 if ref and ref in conf:
256 settings = conf.get(ref)
257 if isinstance(settings, dict):
258 r = _oneCompPrint(settings, ref, cl or ref)
259 sub += r
260 elif not showClasses:
262 else:
263 print(f
"{comp} is absent in the config, unfortunately the name has to be exact")
264
265 if not args.uniqueClasses:
266 return
267
268 def _nocomp(top):
269 """copy structure without the component names, so equality tests for the same class names."""
270 new = []
271 for cl,_,sub in top:
272 r = _nocomp(sub)
273 new.append([cl,r])
274 return new
275
276 from collections import defaultdict
277 cls = defaultdict(list)
278 def _oneCompPrune(top):
279 """Duplicate classes (with identical structure below) are listed, without substructure
280 - or not listed at all if they already showed up at this level.
281 Classes with the same name are grouped next to each other and shown with their component name."""
282
283
284 ord = defaultdict(list)
285 for cl,comp,sub in top:
286 ord[cl].append([cl,comp,sub])
287
288
289 new = []
290 dupcls = defaultdict(int)
291 for o in ord.values():
292 for cl,comp,sub in o:
293 comp = comp.split('.')[-1]
294 nsub = _nocomp(sub)
295 if cl in cls and nsub in cls[cl]:
296 if cl in dupcls:
297 continue
298 r = []
299 else:
300 cls[cl].append(nsub)
301 r = _oneCompPrune(sub)
302 dupcls[cl] += 1
303 new.append([cl,comp,r])
304
305
306 if not args.showComponentName:
307 for e in new:
308 if dupcls[e[0]] < 2:
309 e[1] = None
310 return new
311
312 def _structPrint(top, indent = ""):
313 for cl,comp,sub in top:
314 cc = f"{cl}/{comp}" if args.showComponentName else \
315 f"{cl} ({comp})" if comp is not None else cl
316 print(f
"{indent}{cc}")
317 if sub:
318 _structPrint(sub, indent + " - ")
319
320 _structPrint(_oneCompPrune(sub))
321
322