3 from os
import makedirs
4 from os.path
import isdir
5 from argparse
import ArgumentParser
6 from typing
import Mapping, Union, TextIO
8 from DQDefects
import DefectsDB
9 from DQDefects.virtual_logic
import DefectLogic
11 DEPENDSON_DIR =
"dependson"
32 return any(c.primary
for c
in self.
children)
39 return (f
'<Node {self.name} parents="{[n.name for n in self.parents]}" '
40 f
'children="{[n.name for n in self.children]}">')
42 def dot(self, current_node=False, tooltip: str =
"", viewing_dependents: bool =
False) -> str:
44 color =
"grey" if self.
primary else "white"
46 color =
"darkslategray2" if viewing_dependents
else "gold"
48 tooltip = (
"[Virtual]" if self.
virtual else "[Primary]") +
" " + html.escape(tooltip,
True)
54 if viewing_dependents:
55 url = f
"../{self.name}.svg"
56 label +=
r"\n[Deep dependants]"
58 url = f
"{DEPENDSON_DIR}/{self.name}.svg"
59 label +=
r"\n[Dependencies]"
61 url =
"%s.svg" % self.
name
63 return f
'{self.name} [fillcolor={color}, style=filled, URL="{url}", tooltip="{tooltip}", label="{label}"];'
65 def build_tree(all_logic: Mapping[str, DefectLogic]) -> dict[str, Node]:
67 all_nodes: dict[str, Node] = {}
69 def make_primary(current_logic: str) -> Node:
70 if current_logic
in all_nodes:
71 return all_nodes[current_logic]
72 all_nodes[current_logic] = node =
Node(current_logic)
75 def explore_virtual(current_logic: str) -> Node:
76 if current_logic
in all_nodes:
77 return all_nodes[current_logic]
79 this_logic = all_logic[current_logic]
80 all_nodes[current_logic] = node =
Node(current_logic)
82 for name
in this_logic.clauses:
84 child = explore_virtual(name)
86 child = make_primary(name)
88 child.parents.add(node)
89 node.children.add(child)
93 for name
in all_logic:
98 def walk(node: Node, visited: set[Node], visit_primary: bool, fd: TextIO):
101 for subnode
in sorted(node.children, key=Node.get_name):
102 if subnode.virtual
or (subnode.primary
and visit_primary):
103 print(f
"{node.name} -> {subnode.name}", file=fd)
104 walk(subnode, visited, visit_primary, fd)
107 descs: Mapping[Union[str, int], str], parents: bool):
108 for node
in sorted(nodes, key=Node.get_name):
109 at_current_node = node.name == current_node.name
110 description = descs.get(node.name, node.name)
112 description = description.replace(
'\n',
' ')
113 print(node.dot(at_current_node, description, parents), file=fd)
117 with open(
"%s/%s.dot" % (output_dir, node.name),
"w")
as fd:
118 print(f
"strict digraph {node.name} {{", file=fd)
119 print(
"rankdir=LR;\n", file=fd)
123 for parent
in sorted(node.parents, key=Node.get_name):
124 print(f
"{parent.name} -> {node.name}", file=fd)
127 walk(node, visited, node.has_primary_children, fd)
135 visited =
set([node])
137 with open(f
"{output_dir}/{DEPENDSON_DIR}/{node.name}.dot",
"w")
as fd:
138 def walk_parents(node):
140 for parent
in node.parents:
141 print(f
"{parent.name} -> {node.name}", file=fd)
144 print(f
"strict digraph {node.name} {{", file=fd)
145 print(
"rankdir=LR;\n", file=fd)
153 def render_all_flags(output_dir: str, all_nodes: dict[str, Node], descs: Mapping[Union[str, int], str]):
155 path =
"%s/%s" % (output_dir, DEPENDSON_DIR)
159 for _, node
in sorted(all_nodes.items()):
165 parser = ArgumentParser(description=
"Dump defect viewer information")
167 parser.add_argument(
"-t",
"--tag", default=
"HEAD", help=
"Defect tag")
168 parser.add_argument(
"-o",
"--output", default=
".", help=
"Directory to dump files")
170 args = parser.parse_args()
173 db = DefectsDB(tag=args.tag)
175 descs = db.all_defect_descriptions
178 all_nodes =
build_tree(db.virtual_defect_logics)
181 output_dir =
"%s/%s" % (args.output, args.tag)
184 if __name__ ==
"__main__":