File indexing completed on 2024-04-14 05:35:11

0001 #!/usr/bin/python
0002 # -*- coding: utf-8 -*-
0003 
0004 # Copyright (C) 2017 Sandro Knauß <sknauss@kde.org>
0005 #
0006 # This program is free software: you can redistribute it and/or modify
0007 # it under the terms of the GNU General Public License as published by
0008 # the Free Software Foundation, either version 3 of the License, or
0009 # (at your option) any later version.
0010 
0011 """Graph the dependencies of all pim packages.
0012 
0013 The dependencies are minimized, so that only direct dependencies are shown.
0014 The green dots are packages without depdencies inside the set.
0015 The lightblue dots are one end of the build chain.
0016 
0017 If you have something like this:
0018 
0019     a -> b -> c
0020     a -> c
0021 the second depdency is not shown.
0022 
0023 You can enable the full dependency if you replace sgraph -> graph in the last for loop.
0024 
0025 The tier graph shows you a tier based view to pim packages.
0026 One tier is defined as a maximum set of packages, that do not depend on each other and only
0027 depend on lower tiers. Only dependecies from one tier to the next one are shown. Ellipsed shape
0028 packages without arrows are indicating, that they could be built in a higher tier. Diamond shape
0029 indicate that nothing depends on this anymore.
0030 
0031 usage:
0032 git clone kde:kde-build-metadata
0033 <pathto>/pim-build-deps-graphs.py > pim-graphs.dot
0034 dot -T png -o kde-build-metadata-17.12-deps.png  pim-graphs.dot > kde-build-metadata-17.12-tier.png
0035 """
0036 
0037 from __future__ import print_function
0038 
0039 import re
0040 import copy
0041 
0042 __fresh_id = 0
0043 
0044 def main():
0045     def get_id():
0046         global __fresh_id
0047         __fresh_id += 1
0048         return ("NODE_%d" % __fresh_id)
0049 
0050     def emit_arc(node1, node2):
0051         print('  "%s" -> "%s" ;' % (node1, node2))
0052     def emit_node(node, dsc=None):
0053         if dsc is None:
0054               print('  "%s";' % (node))
0055         else:
0056               print('  "%s" [label="%s"];' % (node, dsc))
0057     def emit_nodecolor(node, color):
0058         print('  "%s" [fillcolor="%s", style="filled"] ;' % (node, color))
0059 
0060 
0061     line = re.compile(r"^([^#^:]+):\s*([^#]+)\s*(#.*)?$")
0062     graph = {}
0063     for i in open('kde-build-metadata/dependency-data-kf5-qt5').readlines():
0064          if not i.strip():
0065              continue
0066          m = line.match(i)
0067          if not m:
0068              continue
0069          pkg = m.group(1).strip()
0070          dep = m.group(2).strip()
0071          if not pkg.startswith("kde/pim/"):
0072              continue
0073          else:
0074              pkg = pkg[len("kde/pim/"):]
0075 
0076          if not pkg in graph:
0077              graph[pkg] = set()
0078 
0079          if not dep.startswith("kde/pim/"):
0080              continue
0081          else:
0082              dep = dep[len("kde/pim/"):]
0083 
0084          if not dep in graph:
0085              graph[dep] = set()
0086 
0087          graph[pkg].add(dep)
0088 
0089     sgraph = {}     # minimized graph
0090     fgraph = graph  # full dependency graph
0091 
0092     for i in range(10):
0093         changed = False
0094         ograph = fgraph
0095         for pkg in ograph:
0096             deps = copy.copy(ograph[pkg])
0097             for dep in ograph[pkg]:
0098                 deps |= ograph[dep]
0099             if deps != ograph[pkg]:
0100                 changed = True
0101             fgraph[pkg] = deps
0102 
0103         if not changed:
0104             break
0105 
0106     for pkg in fgraph:
0107         deps = copy.copy(graph[pkg])
0108         for dep in graph[pkg]:
0109             deps -= fgraph[dep]
0110         sgraph[pkg] = deps
0111 
0112     pkgs = set(graph.keys())     # packages to order into tiers
0113     tiers = []                   # each tier will be one entry
0114     deps = set()                 # All deps from lower tiers
0115 
0116     while pkgs:
0117         tD = set()
0118         if tiers:
0119             deps |= tiers[-1]
0120         tiers.append(set())
0121         for pkg in pkgs:
0122             if not (sgraph[pkg] - deps):
0123                 tiers[-1].add(pkg)
0124                 tD.add(pkg)
0125         pkgs -= tD
0126 
0127     ends = set()
0128 
0129     for pkg in graph:
0130         name = pkg
0131         sDeps = sgraph[pkg]
0132         if sDeps:
0133             for p in sgraph:
0134                 if p == pkg:
0135                     continue
0136                 if pkg in sgraph[p]:
0137                     break
0138             else:
0139                 ends.add(name)
0140 
0141     print("digraph pim {")
0142     for pkg in graph:
0143         name = pkg
0144         sDeps = sgraph[pkg]
0145         if sDeps == set():
0146             emit_nodecolor(name, 'darkgreen')
0147         else:
0148             for p in sgraph:
0149                 if p == pkg:
0150                     continue
0151                 if pkg in sgraph[p]:
0152                     break
0153             else:
0154                 emit_nodecolor(name, 'lightblue')
0155 
0156     for pkg in graph:
0157         name = pkg
0158         sDeps = sgraph[pkg]
0159         for dep in sDeps:
0160             emit_arc(dep, name)
0161     print("}")
0162 
0163     print("digraph pimTier {")
0164     print("    node [shape=diamond,fillcolor=lightblue,style=filled];")
0165     for pkg in ends:    # all end notes
0166         emit_node(pkg)
0167     print("    node [shape=ellipse,fillcolor=darkgreen];")
0168     for pkg in tiers[0]:    #   all dependency free packages - aka tier 0
0169         emit_node(pkg)
0170     print("    node [shape=ellipse,fillcolor=white];")
0171     for index, tier in enumerate(tiers):
0172         print("  subgraph cluster_{} {{".format(index))
0173         print("     style=filled;")
0174         print("     color=lightgrey;")
0175         print('     label = "Tier {}";'.format(index))
0176         for pkg in tier:
0177             emit_node(pkg)
0178         print("  }")
0179         if index > 0:
0180             subTier = tiers[index-1]
0181             for pkg in tier:
0182                 for dep in (sgraph[pkg] & subTier):
0183                     emit_arc(dep, pkg)
0184     print("}")
0185 
0186 
0187 
0188 if __name__ == '__main__':
0189     main()
0190