Mercurial > fife-parpg
comparison tests/analyzers/dep_analyzer.py @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children | 81641655bc38 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4a0efb7baf70 |
---|---|
1 #!/usr/bin/python | |
2 import sys, re, os | |
3 | |
4 try: | |
5 from os.shutil import copyfile | |
6 | |
7 except ImportError: | |
8 def copyfile(src,dest): | |
9 srcf = open(src) | |
10 destf = open(dest,"w") | |
11 destf.write( srcf.read() ) | |
12 destf.close() | |
13 srcf.close() | |
14 | |
15 | |
16 if '.' not in sys.path: | |
17 sys.path.append('.') | |
18 from utils.util_scripts.path import path | |
19 from _allowed_dependencies import ALLOWED_MODULE_DEPS | |
20 | |
21 _S = os.path.sep | |
22 ROOTDIRNAME = 'engine%score' % _S | |
23 FILE_DEPS_OUT = 'doc%sdependencies%sfiledeps' % (_S, _S) | |
24 DIR_DEPS_OUT = 'doc%sdependencies%sdirdeps' % (_S, _S) | |
25 MODULE_DEPS_OUT = 'doc%sdependencies%smoduledeps' % (_S, _S) | |
26 SKIPPED_PROVIDERS = [] | |
27 SKIPPED_USERS = [] | |
28 | |
29 reInc = re.compile('#include "(.*?)"') | |
30 | |
31 def add_to_dictset(d, key, val): | |
32 try: | |
33 d[key].add(val) | |
34 except KeyError: | |
35 d[key] = set([val]) | |
36 | |
37 # return error string in case of possible error | |
38 unknown_modules = [] | |
39 def check_dep_error(allowed_deps, user, provider): | |
40 global unknown_modules | |
41 | |
42 msg = '' | |
43 try: | |
44 if not provider in allowed_deps[user]: | |
45 msg = 'Illegal dependency between %s -> %s, % s can use only:\n' % (user, provider, user) | |
46 for d in allowed_deps[user]: | |
47 msg += ' %s\n' % d | |
48 except KeyError: | |
49 print unknown_modules | |
50 if user not in unknown_modules: | |
51 msg = 'Unknown module %s found in static check\n' % user | |
52 msg += ' please adjust dep_analyzer script to match new structure' | |
53 unknown_modules.append(user) | |
54 return msg | |
55 | |
56 def get_file2inc(sources): | |
57 file2inc = {} | |
58 for f in sources: | |
59 inComment = False | |
60 for line in open(f): | |
61 if not inComment and line.find('/*') != -1: | |
62 inComment = True | |
63 continue | |
64 elif inComment: | |
65 if line.find('*/') != -1: | |
66 inComment = False | |
67 continue | |
68 elif line.strip().startswith('//'): | |
69 continue | |
70 m = reInc.search(line) | |
71 if m: | |
72 add_to_dictset(file2inc, f, m.group(1).replace( '/', _S )) | |
73 | |
74 return file2inc | |
75 | |
76 def fill_dep_infos(file2inc, fileUser2provider, dirUser2provider, moduleUser2provider, unknownIncludes, dirclusters): | |
77 for f, incs in file2inc.items(): | |
78 #if f.find('engine.cpp') != -1: | |
79 # import pdb; pdb.set_trace() | |
80 skip = False | |
81 for user in SKIPPED_USERS: | |
82 if f.find(user) != -1: | |
83 skip = True | |
84 break | |
85 if skip: | |
86 continue | |
87 | |
88 for i in incs: | |
89 user = str(f.dirname()).replace(ROOTDIRNAME + _S, '') | |
90 header = path((f.dirname() / path(i)).abspath().split(ROOTDIRNAME + _S)[1]) | |
91 if not header.isfile(): | |
92 header = path(ROOTDIRNAME) + _S + path(i) | |
93 if not header.isfile(): | |
94 add_to_dictset(unknownIncludes, str(f), str(i)) | |
95 continue | |
96 provider = str(header.dirname()).replace(ROOTDIRNAME + _S, '') | |
97 skip = False | |
98 for skipped in SKIPPED_PROVIDERS: | |
99 if header.find(skipped) != -1: | |
100 skip = True | |
101 break | |
102 if skip: | |
103 continue | |
104 add_to_dictset(dirUser2provider, user, provider) | |
105 usermodule = user.split(_S)[0] | |
106 providermodule = provider.split(_S)[0] | |
107 userfile = user.split(_S)[-1].split('.')[0] | |
108 providerfile = provider.split(_S)[-1].split('.')[0] | |
109 | |
110 add_to_dictset(dirclusters, usermodule, user) | |
111 add_to_dictset(dirclusters, providermodule, provider) | |
112 add_to_dictset(moduleUser2provider, usermodule, providermodule) | |
113 add_to_dictset(fileUser2provider, userfile, providerfile) | |
114 | |
115 def write_dot_file(fname, contents): | |
116 lines = [] | |
117 a = lines.append | |
118 a('digraph "source tree" {') | |
119 a(' overlap=scale;') | |
120 a(' size="8,10";') | |
121 a(' ratio="fill";') | |
122 a(' fontsize="16";') | |
123 a(' fontname="Helvetica";') | |
124 a(' clusterrank="local";') | |
125 if type(contents) in (list, tuple): | |
126 lines += contents | |
127 else: | |
128 lines.append(contents) | |
129 a('}') | |
130 open(fname, 'w').write('\n'.join(lines)) | |
131 | |
132 def get_cluster_str(ind, elements, label): | |
133 lines = [] | |
134 a = lines.append | |
135 a('subgraph cluster_%d {' % ind) | |
136 a(' style=filled;') | |
137 a(' color=lightgrey;') | |
138 a(' node [style=filled,color=white];') | |
139 a(' %s' % '; '.join('"%s"' % d for d in elements)) | |
140 a(' label = "%s";' % label) | |
141 a('}') | |
142 return '\n'.join(lines) | |
143 | |
144 def run_dot(basename,type): | |
145 dotname = basename + ".dot" | |
146 outname = basename + "." + type | |
147 | |
148 dotchanged = True | |
149 | |
150 try: | |
151 olddot = open(dotname + "~").read() | |
152 dotchanged = olddot != open(dotname).read() | |
153 dotchanged = dotchanged or not os.path.exists(outname) | |
154 except IOError: pass | |
155 if not dotchanged: | |
156 return | |
157 print "Generating: ",outname | |
158 cmd = 'dot -T%(type)s %(dotname)s > %(outname)s' % locals() | |
159 os.system(cmd) | |
160 copyfile(dotname,dotname + "~") | |
161 | |
162 def analyze(write_postscript=False): | |
163 root = path(ROOTDIRNAME) | |
164 headers = list(root.walkfiles('*.h')) | |
165 sources = headers + list(root.walkfiles('*.cpp')) | |
166 file2inc = get_file2inc(sources) | |
167 | |
168 moduleUser2provider = {} | |
169 dirUser2provider = {} | |
170 fileUser2provider = {} | |
171 unknownIncludes = {} | |
172 dirclusters = {} | |
173 fill_dep_infos(file2inc, fileUser2provider, dirUser2provider, moduleUser2provider, unknownIncludes, dirclusters) | |
174 | |
175 # write module dep graph | |
176 out = [] | |
177 illegalModuleDeps = [] | |
178 for user, providers in sorted(moduleUser2provider.items()): | |
179 for provider in sorted(providers): | |
180 if user != provider: | |
181 out.append(' "' + user + '" -> "' + provider + '"') | |
182 msg = check_dep_error(ALLOWED_MODULE_DEPS, user, provider) | |
183 if msg: | |
184 illegalModuleDeps.append(msg) | |
185 write_dot_file('%s.dot' % MODULE_DEPS_OUT, out) | |
186 if write_postscript: | |
187 run_dot(MODULE_DEPS_OUT, "ps") | |
188 run_dot(MODULE_DEPS_OUT,"png") | |
189 | |
190 # write dir dep graph | |
191 out = [] | |
192 for cluster, subdirs in sorted(dirclusters.items()): | |
193 out.append(get_cluster_str(len(out), sorted(subdirs), cluster)) | |
194 for user, providers in sorted(dirUser2provider.items()): | |
195 for provider in sorted(providers): | |
196 if user != provider: | |
197 out.append(' "' + user + '" -> "' + provider + '"') | |
198 write_dot_file('%s.dot' % DIR_DEPS_OUT, out) | |
199 if write_postscript: | |
200 run_dot(DIR_DEPS_OUT, "ps") | |
201 | |
202 # write file dep graph | |
203 out = [] | |
204 for user, providers in sorted(file2inc.items()): | |
205 for provider in sorted(providers): | |
206 if user != provider: | |
207 out.append(' "' + user + '" -> "' + provider + '"') | |
208 write_dot_file('%s.dot' % FILE_DEPS_OUT, out) | |
209 # os.system('dot -Tps %s.dot > %s.ps' % (MODULE_DEPS_OUT, MODULE_DEPS_OUT)) | |
210 | |
211 # write raw dep info | |
212 #out = [] | |
213 #for f, file2inc | |
214 result = '\n'.join(illegalModuleDeps) | |
215 if result: | |
216 print result | |
217 else: | |
218 print "no dependency analyzer errors found" | |
219 return result | |
220 | |
221 | |
222 _ANALYZE_FN_ = analyze | |
223 | |
224 if __name__ == '__main__': | |
225 analyze(True) |