KApiDox

generate.py
1 # -*- coding: utf-8 -*-
2 #
3 # SPDX-FileCopyrightText: 2014 Aurélien Gâteau <[email protected]>
4 #
5 # SPDX-License-Identifier: BSD-2-Clause
6 
7 import logging
8 import itertools
9 from functools import cmp_to_key
10 
11 from kapidox.depdiagram.block import Block, quote
12 from kapidox.depdiagram.framework import Framework
13 from kapidox.depdiagram.frameworkdb import FrameworkDb
14 
15 __all__ = ('generate',)
16 
17 ROOT_NODE_ATTRS = dict(fontsize=12, shape="box")
18 
19 GROUP_ATTRS = dict(style="filled", fillcolor="grey95", color="grey85")
20 
21 # Blocks within groups
22 OTHER_ATTRS = dict(style="filled", fillcolor="cornsilk", color="black")
23 
24 QT_ATTRS = dict(style="filled", fillcolor="darkseagreen1", color="black")
25 
26 FW_ATTRS = dict(style="filled", fillcolor="azure", color="black")
27 
28 # Target blocks, used with --detailed
29 FW_TARGET_ATTRS = dict(style="filled", fillcolor="paleturquoise")
30 
31 # Highlight the wanted framework, used with --framework
32 WANTED_FW_ATTRS = dict(penwidth=2)
33 
34 class FrameworkCmp(object):
35  def __init__(self, db):
36  self.db = db
37  self.src = set(db)
38  self.dst = []
39 
40  def __call__(self, fw1, fw2):
41  if self.depends_on(fw1, fw2):
42  return 1
43  if self.depends_on(fw2, fw1):
44  return -1
45  return 0
46 
47  def depends_on(self, depender_fw, provider_fw):
48  for dep_target in depender_fw.get_all_target_dependencies():
49  if provider_fw.has_target(dep_target):
50  return True
51 
52  try:
53  dep_fw = self.db.get_framework_for_target(dep_target)
54  except KeyError:
55  # No framework for this target, must be an external dependency,
56  # carry on
57  continue
58  if dep_fw != depender_fw and self.depends_on(dep_fw, provider_fw):
59  return True
60 
61  return False
62 
63 
64 class DotWriter(Block):
65  def __init__(self, db, out, wanted_fw=None, detailed=False):
66  Block.__init__(self, out)
67  self.db = db
68  self.detailed = detailed
69  self.wanted_fw = wanted_fw
70 
71  def write(self):
72  with self.curly_block("digraph Root") as root:
73  root.write_list_attrs("node", **ROOT_NODE_ATTRS)
74 
75  other_targets = self.db.find_external_targets()
76  qt_targets = set([x for x in other_targets if x.startswith("Qt")])
77  other_targets.difference_update(qt_targets)
78 
79  if qt_targets:
80  with root.cluster_block("Qt", **GROUP_ATTRS) as b:
81  b.write_list_attrs("node", **QT_ATTRS)
82  b.write_nodes(qt_targets)
83 
84  if other_targets:
85  with root.cluster_block("Others", **GROUP_ATTRS) as b:
86  b.write_list_attrs("node", **OTHER_ATTRS)
87  b.write_nodes(other_targets)
88 
89  lst = sorted([x for x in self.db], key=lambda x: x.tier)
90  for tier, frameworks in itertools.groupby(lst, lambda x: x.tier):
91  cluster_title = "Tier {}".format(tier)
92  with root.cluster_block(cluster_title, **GROUP_ATTRS) as tier_block:
93  tier_block.write_list_attrs("node", **FW_ATTRS)
94  # Sort frameworks within the tier to ensure frameworks which
95  # depend on other frameworks from that tier are listed after
96  # their dependees.
97  frameworks = list(frameworks)
98  for fw in sorted(frameworks, key=cmp_to_key(FrameworkCmp(self.db))):
99  if self.detailed:
100  self.write_detailed_framework(tier_block, fw)
101  else:
102  self.write_framework(tier_block, fw)
103 
104  def write_framework(self, tier_block, fw):
105  if fw == self.wanted_fw:
106  tier_block.write_list_attrs(quote(fw.name), **WANTED_FW_ATTRS)
107  else:
108  tier_block.write_nodes([fw.name])
109  edges = set([])
110  for target in fw.get_all_target_dependencies():
111  try:
112  target_fw = self.db.get_framework_for_target(target)
113  if fw == target_fw:
114  continue
115  dep = target_fw.name
116  except KeyError:
117  dep = target
118  edges.add((fw.name, dep))
119  for dep_fw in fw.get_extra_frameworks():
120  edges.add((fw.name, dep_fw))
121  for edge in edges:
122  tier_block.writeln('"{}" -> "{}";'.format(*edge))
123 
124  def write_detailed_framework(self, tier_block, fw):
125  with tier_block.cluster_block(fw.name, **FW_ATTRS) as fw_block:
126  if fw == self.wanted_fw:
127  fw_block.write_attrs(**WANTED_FW_ATTRS)
128  fw_block.write_list_attrs("node", **FW_TARGET_ATTRS)
129  targets = sorted(fw.get_targets())
130  fw_block.write_nodes(targets)
131  for target in targets:
132  deps = fw.get_dependencies_for_target(target)
133  for dep in sorted(deps):
134  fw_block.writeln('"{}" -> "{}";'.format(target, dep))
135 
136 
137 def generate(out, dot_files, framework=None, with_qt=False, detailed=False):
138  db = FrameworkDb()
139  db.populate(dot_files, with_qt=with_qt)
140 
141  if framework:
142  wanted_fw = db.find_by_name(framework)
143  if wanted_fw is None:
144  logging.error("No framework named {}.".format(framework))
145  return False
146  db.remove_unused_frameworks(wanted_fw)
147  else:
148  wanted_fw = None
149 
150  writer = DotWriter(db, out, wanted_fw=wanted_fw, detailed=detailed)
151  writer.write()
152 
153  return True
154 
155 # vi: ts=4 sw=4 et
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Nov 30 2020 22:54:36 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.