Skip to content

Instantly share code, notes, and snippets.

@yurenju
Created August 7, 2013 14:25
Show Gist options
  • Save yurenju/6174536 to your computer and use it in GitHub Desktop.
Save yurenju/6174536 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Created on Sep 29, 2010
@author: vak
'''
from sys import stdin, stdout, stderr
import unittest
import sys
prev_target = None
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] == '#' or line.find('=') > 0 or line.find('?') > 0:
continue
if line[0] == '\t' and '@$(call run-js-command, ' not in line:
continue
if line[0] == '\t' and '@$(call run-js-command, ' in line:
yield tuple([line.split(',')[1].strip()[:-1] + '.js', prev_target])
parts = _pat_colon.split(line)
if len(parts) == 1:
continue
elif len(parts) == 2:
if len(parts[1]) == 0 or parts[1][0] != '=':
prev_target = parts[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()):
if out[-3:] != '.js':
yield '\t"%s"\n' % out
else:
yield '\t"%s" [color=red]\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="LR"\n\tnode [shape=record]\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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment