-
Notifications
You must be signed in to change notification settings - Fork 19
/
makefile2dot.py
executable file
·99 lines (77 loc) · 3.49 KB
/
makefile2dot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Created on Sep 29, 2010
@author: vak
'''
from sys import stdin, stdout, stderr
import unittest
import sys
def _line_emitter(input):
line_to_emit = ''
for line in input:
if line.endswith('\\'):
line_to_emit += line[:-1]
#print >>stderr, "line_to_emit=<%s>" % line_to_emit
else:
line_to_emit += line
yield line_to_emit
line_to_emit = ''
import re
_pat_colon = re.compile(':')
def _dependency_emitter(lines):
for line in lines:
if len(line) == 0 or line[0] in ['\t', '#'] or line.find('=') > 0 or line.find('?') > 0:
continue
parts = _pat_colon.split(line)
if len(parts) == 1:
continue
elif len(parts) == 2:
if len(parts[1]) == 0 or parts[1][0] != '=':
yield tuple(parts)
else:
print >> stderr, 'more then one ":" not yet implemented ;)\n got the following:\n%s' % parts
_pat_whitespacing = re.compile('[ \t]+')
def _single_dot_dep_emitter(out_deps_pairs):
for outs_str, deps_str in out_deps_pairs:
for out in _pat_whitespacing.split(outs_str.strip()):
yield '\t"%s"\n' % out
deps = _pat_whitespacing.split(deps_str.strip())
for dep in deps:
if dep:
if dep[0] == '#':
break
yield '\t"%s" -> "%s"\n' % (dep, out)
def makefile2dot():
'''
Visalizer of Makefiles.
Don't even think we use a grammar parser.
'''
stdout.write('digraph G {\n\trankdir="BT"\n')
for line in _single_dot_dep_emitter(_dependency_emitter(_line_emitter(''.join(stdin).split('\n')))):
stdout.write(line)
stdout.write('}\n')
class Test(unittest.TestCase):
def test_emitters(self):
self.assertEqual(list(_line_emitter([''])), [''])
self.assertEqual(list(_line_emitter(['', ''])), ['', ''])
self.assertEqual(list(_line_emitter(['a', 'b'])), ['a', 'b'])
self.assertEqual(list(_line_emitter(['a\\', 'b', 'c'])), ['ab', 'c'])
self.assertEqual(list(_dependency_emitter(_line_emitter(['']))), [])
self.assertEqual(list(_dependency_emitter(_line_emitter(['macro', 'out:dep1\\', ' dep2', '\tcommand']))), [('out', 'dep1 dep2')])
self.assertEqual(list(_dependency_emitter(_line_emitter(['macro', 'out:dep1\\', ' dep2', '\tcommand', 'out2:dep3\\', ' dep4', '\tcommand2']))),
[('out', 'dep1 dep2'), ('out2', 'dep3 dep4')])
self.assertEqual(list(_dependency_emitter(_line_emitter(['default:', '', '']))), [('default','')])
inp = ['macro', 'out:dep1\\', ' dep2', '\tcommand', '', 'out2:dep3\\', ' dep4', '\tcommand2']
self.assertEqual(list(_single_dot_dep_emitter(_dependency_emitter(_line_emitter(inp)))),
['\t"out"\n', '\t"dep1" -> "out"\n', '\t"dep2" -> "out"\n', '\t"out2"\n', '\t"dep3" -> "out2"\n', '\t"dep4" -> "out2"\n'])
inp = ['default:', '\techo']
self.assertEqual(list(_single_dot_dep_emitter(_dependency_emitter(_line_emitter(inp)))),
['\t"default"\n'])
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
# unittest.main()
if len(sys.argv) > 1:
print >> stderr, 'Usage:\n\tmakefile2dot <Makefile >out.dot\nor\n\tmakefile2dot <Makefile |dot -Tpng > out.png'
else:
makefile2dot()