Files: bfad9d94f6fd6b6ee044e8305e9ce1f7bc1dc32b / depeject.py
3879 bytesRaw
1 | #!/usr/bin/env python3 |
2 | |
3 | from pprint import pprint |
4 | import re |
5 | import json |
6 | import subprocess as sp |
7 | from collections import defaultdict |
8 | from graphviz import Digraph |
9 | import pickle |
10 | |
11 | NEEDS_CALL = "rg --json -t js --multiline exports.needs[^\)]*\)" |
12 | GIVES_CALL = "rg --json -t js --multiline exports.gives[^\)]*\)" |
13 | |
14 | PARENTHESIS_EXTRACTION_RE = re.compile(r'\(([^)]+)') |
15 | |
16 | def parse_ripgrep(lines): |
17 | for line in lines: |
18 | if not line.strip(): |
19 | continue |
20 | line = json.loads(line) |
21 | if line['type'] != 'match': |
22 | continue |
23 | file_name = line['data']['path']['text'] |
24 | matched_text = line['data']['lines']['text'] |
25 | assert len(line['data']['submatches']) == 1, json.dumps(line, indent=2) |
26 | yield file_name, matched_text |
27 | |
28 | |
29 | JS_TEMPLATE = ''' |
30 | const nest = require('depnest') |
31 | |
32 | console.log(JSON.stringify(nest({obj_str}))) |
33 | ''' |
34 | |
35 | def flatten(d): |
36 | for k, v in d.items(): |
37 | if type(v) == bool: |
38 | assert v, d |
39 | yield k |
40 | continue |
41 | if type(v) == str: |
42 | # print(v) |
43 | yield k |
44 | continue |
45 | v_postfixes = flatten(v) |
46 | for postfix in v_postfixes: |
47 | yield f'{k}.{postfix}' |
48 | |
49 | def edges(rg_matches): |
50 | rg_matches = list(parse_ripgrep(rg_matches.split('\n'))) |
51 | # print(len(rg_matches)) |
52 | result = dict() |
53 | for fn, text in rg_matches: |
54 | # print('='*80) |
55 | # print(f'{fn}\n{text}') |
56 | # print() |
57 | if 'nest(' in text: |
58 | obj_str = text[text.find('(')+1:text.find(')')] |
59 | else: |
60 | obj_str = text[text.find('{'):text.rfind('}')+1] |
61 | obj_str = sp.check_output(['node', '-e', JS_TEMPLATE.format(obj_str=obj_str)]) |
62 | obj_str = obj_str.decode() |
63 | obj = json.loads(obj_str) |
64 | # print(json.dumps(obj, indent=2)) |
65 | # print() |
66 | # print('\n'.join(list(flatten(obj)))) |
67 | result[fn] = list(flatten(obj)) |
68 | return result |
69 | |
70 | if __name__ == '__main__': |
71 | gives_rg = sp.check_output(GIVES_CALL.split()).decode() |
72 | gives = edges(gives_rg) |
73 | |
74 | needs_rg = sp.check_output(NEEDS_CALL.split()).decode() |
75 | needs = edges(needs_rg) |
76 | |
77 | # for every method: which files provide this method? |
78 | providers = defaultdict(list) |
79 | for filename, methods in gives.items(): |
80 | for method in methods: |
81 | providers[method].append(filename) |
82 | providers = dict(providers) |
83 | |
84 | pprint(providers) |
85 | |
86 | # for every file: which other files does this depend on, and for which method? |
87 | dependencies = defaultdict(list) |
88 | # for every file: which other files depend on this, and for which method? |
89 | dependents = defaultdict(list) |
90 | for filename, methods in needs.items(): |
91 | for method in methods: |
92 | method_providers = providers.get(method, ['UNKNOWN']) |
93 | dependencies[filename] += [(mp, method) for mp in method_providers] |
94 | for mp in method_providers: |
95 | dependents[mp].append((filename, method)) |
96 | dependencies = dict(dependencies) |
97 | |
98 | # for p in providers.keys(): |
99 | # _ = dependents[p] |
100 | dependents = dict(dependents) |
101 | print('='*80) |
102 | pprint(dependencies) |
103 | print('='*80) |
104 | pprint(dependents) |
105 | print('='*80) |
106 | |
107 | sortedProviders = list(sorted(dependents.keys(), key=lambda k: len(dependents[k]))) |
108 | counts = {k: len(dependents[k]) for k in sortedProviders} |
109 | |
110 | max_count = len(str(max(*counts.values()))) |
111 | max_len = len(max(*counts.keys(), key=len)) |
112 | print(max_count, max_len) |
113 | |
114 | print('-'*80) |
115 | for k in sortedProviders: |
116 | print(f'{counts[k]:{max_count}}\t{k:{max_len}}') |
117 | |
118 | with open('results.pickle', 'wb') as f: |
119 | pickle.dump({ |
120 | 'gives': gives, |
121 | 'needs': needs, |
122 | 'counts': counts, |
123 | 'providers': providers, |
124 | 'dependents': dependents, |
125 | 'dependencies': dependencies, |
126 | }, f) |
127 | |
128 | # dot = Digraph(comment='Dependencies') |
129 | # |
130 | # for filename in dependencies.keys(): |
131 | # dot.node(filename) |
132 | # |
133 | # for filename, deps in dependencies.items(): |
134 | # for dep, api in deps: |
135 | # dot.edge(filename, dep, label=api) |
136 | # |
137 | # print(dot.source) |
138 | # |
139 | # with open('dependencies.dot', 'w') as f: |
140 | # f.write(dot.source) |
141 | # |
142 | |
143 |
Built with git-ssb-web