~ubuntu-branches/debian/sid/botan/sid

« back to all changes in this revision

Viewing changes to src/scripts/show_dependencies.py

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2018-03-01 22:23:25 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20180301222325-7p7vc45gu3hta34d
Tags: 2.4.0-2
* Don't remove .doctrees from the manual if it doesn't exist.
* Don't specify parallel to debhelper.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
"""
 
4
Show Botan module dependencies as a list or graph.
 
5
 
 
6
Requires graphviz from pip when graphical output is selected:
 
7
https://pypi.python.org/pypi/graphviz
 
8
 
 
9
(C) 2015 Simon Warta (Kullo GmbH)
 
10
 
 
11
Botan is released under the Simplified BSD License (see license.txt)
 
12
"""
 
13
 
 
14
# global
 
15
import argparse
 
16
import copy
 
17
import sys
 
18
import subprocess
 
19
from collections import OrderedDict
 
20
import glob
 
21
import os
 
22
 
 
23
# Assume this script is in botan/src/scripts
 
24
botan_root = os.path.join(os.path.dirname(sys.argv[0]), "..", "..")
 
25
 
 
26
# locale
 
27
sys.path.append(botan_root)
 
28
from configure import ModuleInfo
 
29
 
 
30
parser = argparse.ArgumentParser(description=
 
31
    'Show Botan module dependencies. '
 
32
    'The output is reduced by indirect dependencies, '
 
33
    'i.e. you must look at the result recursively to get all dependencies.')
 
34
 
 
35
parser.add_argument('mode',
 
36
                    choices=["list", "draw"],
 
37
                    help='The output mode')
 
38
parser.add_argument('--format',
 
39
                    nargs='?',
 
40
                    choices=["pdf", "png"],
 
41
                    default="pdf",
 
42
                    help='The file format (drawing mode only)')
 
43
parser.add_argument('--engine',
 
44
                    nargs='?',
 
45
                    choices=["fdp", "dot"],
 
46
                    default="fdp",
 
47
                    help='The graph engine (drawing mode only)')
 
48
parser.add_argument('--all', dest='all', action='store_const',
 
49
                    const=True, default=False,
 
50
                    help='Show all dependencies. Default: direct dependencies only. (list mode only)')
 
51
parser.add_argument('--verbose', dest='verbose', action='store_const',
 
52
                    const=True, default=False,
 
53
                    help='Verbose output (default: false)')
 
54
args = parser.parse_args()
 
55
 
 
56
files = []
 
57
files += glob.glob(botan_root + '/src/lib/*/*/*/*/*/*/info.txt')
 
58
files += glob.glob(botan_root + '/src/lib/*/*/*/*/*/info.txt')
 
59
files += glob.glob(botan_root + '/src/lib/*/*/*/*/info.txt')
 
60
files += glob.glob(botan_root + '/src/lib/*/*/*/info.txt')
 
61
files += glob.glob(botan_root + '/src/lib/*/*/info.txt')
 
62
files += glob.glob(botan_root + '/src/lib/*/info.txt')
 
63
files += glob.glob(botan_root + '/src/lib/info.txt')
 
64
files.sort()
 
65
 
 
66
if len(files) == 0:
 
67
    print("No info.txt files found.")
 
68
    sys.exit(1)
 
69
 
 
70
modules = []
 
71
 
 
72
def dicts(t): return {k: dicts(t[k]) for k in t}
 
73
 
 
74
def paths(t, path = [], level=0):
 
75
    ret =  []
 
76
    for key in t:
 
77
        ret.append(path + [key])
 
78
        ret += paths(t[key], path + [key], level+1)
 
79
    return ret
 
80
 
 
81
if args.verbose:
 
82
    print("Getting dependencies from into.txt files ...")
 
83
 
 
84
for filename in files:
 
85
    (rest, info_txt) = os.path.split(filename)
 
86
    (rest, modname) = os.path.split(rest)
 
87
    module = ModuleInfo(filename)
 
88
    modules.append(module)
 
89
    if args.verbose:
 
90
        print(module.basename)
 
91
        print("\t" + str(set(module.dependencies())))
 
92
 
 
93
if args.verbose:
 
94
    print(str(len(modules)) + " modules:")
 
95
    names=[m.basename for m in modules]
 
96
    names.sort()
 
97
    print(names)
 
98
    print("")
 
99
 
 
100
if args.verbose:
 
101
    print("resolving dependencies ...")
 
102
 
 
103
def cartinality(depdict):
 
104
    return sum([len(depdict[k]) for k in depdict])
 
105
 
 
106
registered_dependencies = dict()
 
107
all_dependencies = dict()
 
108
direct_dependencies = dict()
 
109
 
 
110
for module in modules:
 
111
    lst = module.dependencies()
 
112
    registered_dependencies[module.basename] = set(lst) - set([module.basename])
 
113
 
 
114
# Get all_dependencies from registered_dependencies
 
115
def add_dependency():
 
116
    for key in all_dependencies:
 
117
        potentially_new_modules_for_key = None
 
118
        new_modules_for_key = None
 
119
        for currently_in in all_dependencies[key]:
 
120
            if currently_in in all_dependencies:
 
121
                potentially_new_modules_for_key = all_dependencies[currently_in] - set([key])
 
122
                if not potentially_new_modules_for_key <= all_dependencies[key]:
 
123
                    new_modules_for_key = potentially_new_modules_for_key.copy()
 
124
                    break
 
125
        if new_modules_for_key:
 
126
            all_dependencies[key] |= new_modules_for_key
 
127
            return
 
128
 
 
129
 
 
130
all_dependencies = copy.deepcopy(registered_dependencies)
 
131
direct_dependencies = copy.deepcopy(registered_dependencies)
 
132
 
 
133
# Sort
 
134
all_dependencies = OrderedDict(sorted(all_dependencies.items()))
 
135
direct_dependencies = OrderedDict(sorted(direct_dependencies.items()))
 
136
 
 
137
#print(direct_dependencies)
 
138
 
 
139
last_card = -1
 
140
while True:
 
141
    card = cartinality(all_dependencies)
 
142
    # print(card)
 
143
    if card == last_card:
 
144
        break;
 
145
    last_card = card
 
146
    add_dependency()
 
147
 
 
148
# Return true iff a depends on b,
 
149
# i.e. b is in the dependencies of a
 
150
def depends_on(a, b):
 
151
    if not a in direct_dependencies:
 
152
        return False
 
153
    else:
 
154
        return b in direct_dependencies[a]
 
155
 
 
156
def remove_indirect_dependencies():
 
157
    for mod in direct_dependencies:
 
158
        for one in direct_dependencies[mod]:
 
159
            others = direct_dependencies[mod] - set([one])
 
160
            for other in others:
 
161
                if depends_on(other, one):
 
162
                    direct_dependencies[mod].remove(one)
 
163
                    return
 
164
                    # Go to next mod
 
165
 
 
166
last_card = -1
 
167
while True:
 
168
    card = cartinality(direct_dependencies)
 
169
    # print(card)
 
170
    if card == last_card:
 
171
        break;
 
172
    last_card = card
 
173
    remove_indirect_dependencies()
 
174
 
 
175
def openfile(f):
 
176
    if sys.platform.startswith('linux'):
 
177
        subprocess.call(["xdg-open", f])
 
178
    else:
 
179
        os.startfile(f)
 
180
 
 
181
if args.verbose:
 
182
    print("Done resolving dependencies.")
 
183
 
 
184
if args.mode == "list":
 
185
    if args.all:
 
186
        for key in all_dependencies:
 
187
            print(key.ljust(17) + " : " + ", ".join(sorted(all_dependencies[key])))
 
188
    else:
 
189
        for key in direct_dependencies:
 
190
            print(key.ljust(17) + " : " + ", ".join(sorted(direct_dependencies[key])))
 
191
 
 
192
if args.mode == "draw":
 
193
    import graphviz as gv
 
194
    import tempfile
 
195
 
 
196
    tmpdir = tempfile.mkdtemp(prefix="botan-")
 
197
 
 
198
    g2 = gv.Digraph(format=args.format, engine=args.engine)
 
199
    for key in direct_dependencies:
 
200
        g2.node(key)
 
201
        for dep in direct_dependencies[key]:
 
202
            g2.edge(key, dep)
 
203
 
 
204
    if args.verbose:
 
205
        print("Rendering graph ...")
 
206
    filename = g2.render(filename='graph', directory=tmpdir)
 
207
 
 
208
    if args.verbose:
 
209
        print("Opening " + filename + " ...")
 
210
    openfile(filename)
 
211