mirror of https://gitlab.com/ita1024/waf.git
do not convert to png anymore, and added a templating engine to replace the string appending
This commit is contained in:
parent
4953daf3d4
commit
fb022f4787
|
@ -8,13 +8,11 @@ a file named pdebug.svg in the source directory::
|
|||
|
||||
def options(opt):
|
||||
opt.load('parallel_debug')
|
||||
def configure(conf):
|
||||
conf.load('parallel_debug')
|
||||
def build(bld):
|
||||
...
|
||||
...
|
||||
"""
|
||||
|
||||
import os, time, sys
|
||||
import os, time, sys, re
|
||||
try: from Queue import Queue
|
||||
except: from queue import Queue
|
||||
from waflib import Runner, Options, Utils, Task, Logs, Errors
|
||||
|
@ -22,16 +20,162 @@ from waflib import Runner, Options, Utils, Task, Logs, Errors
|
|||
#import random
|
||||
#random.seed(100)
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--dtitle', action='store', default='Parallel build representation for %r' % ' '.join(sys.argv),
|
||||
help='title for the svg diagram', dest='dtitle')
|
||||
opt.add_option('--dwidth', action='store', type='int', help='diagram width', default=800, dest='dwidth')
|
||||
opt.add_option('--dtime', action='store', type='float', help='recording interval in seconds', default=0.009, dest='dtime')
|
||||
opt.add_option('--dband', action='store', type='int', help='band width', default=22, dest='dband')
|
||||
opt.add_option('--dmaxtime', action='store', type='float', help='maximum time, for drawing fair comparisons', default=0, dest='dmaxtime')
|
||||
SVG_TEMPLATE = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0"
|
||||
x="${project.x}" y="${project.y}" width="${project.width}" height="${project.height}" id="svg602" xml:space="preserve">
|
||||
|
||||
def configure(conf):
|
||||
conf.find_program('convert', var='CONVERT_BIN')
|
||||
<style type='text/css' media='screen'>
|
||||
g.over rect { stroke:#FF0000; fill-opacity:0.4 }
|
||||
</style>
|
||||
|
||||
<script type='text/javascript'><![CDATA[
|
||||
var svg = document.getElementsByTagName('svg')[0];
|
||||
|
||||
svg.addEventListener('mouseover', function(e) {
|
||||
var g = e.target.parentNode;
|
||||
var x = document.getElementById('r_' + g.id);
|
||||
if (x) {
|
||||
g.setAttribute('class', g.getAttribute('class') + ' over');
|
||||
x.setAttribute('class', x.getAttribute('class') + ' over');
|
||||
showInfo(e, g.id);
|
||||
}
|
||||
}, false);
|
||||
|
||||
svg.addEventListener('mouseout', function(e) {
|
||||
var g = e.target.parentNode;
|
||||
var x = document.getElementById('r_' + g.id);
|
||||
if (x) {
|
||||
g.setAttribute('class', g.getAttribute('class').replace(' over', ''));
|
||||
x.setAttribute('class', x.getAttribute('class').replace(' over', ''));
|
||||
hideInfo(e);
|
||||
}
|
||||
}, false);
|
||||
|
||||
function showInfo(evt, txt) {
|
||||
tooltip = document.getElementById('tooltip');
|
||||
|
||||
var t = document.getElementById('tooltiptext');
|
||||
t.firstChild.data = txt;
|
||||
|
||||
var x = evt.clientX + 9;
|
||||
if (x > 250) { x -= t.getComputedTextLength() + 16; }
|
||||
var y = evt.clientY + 20;
|
||||
tooltip.setAttribute("transform", "translate(" + x + "," + y + ")");
|
||||
tooltip.setAttributeNS(null, "visibility", "visible");
|
||||
|
||||
var r = document.getElementById('tooltiprect');
|
||||
r.setAttribute('width', t.getComputedTextLength() + 6);
|
||||
}
|
||||
|
||||
function hideInfo(evt) {
|
||||
var tooltip = document.getElementById('tooltip');
|
||||
tooltip.setAttributeNS(null,"visibility","hidden");
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<!-- inkscape requires a big rectangle or it will not export the pictures properly -->
|
||||
<rect
|
||||
x='${project.x}' y='${project.y}' width='${project.width}' height='${project.height}'
|
||||
style="font-size:10;fill:#ffffff;fill-opacity:0.01;fill-rule:evenodd;stroke:#ffffff;"
|
||||
/>
|
||||
|
||||
${if project.title}
|
||||
<text x="${project.title_x}" y="${project.title_y}"
|
||||
style="font-size:15px; text-anchor:middle; font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans">${project.title}</text>
|
||||
${endif}
|
||||
|
||||
|
||||
${for cls in project.groups}
|
||||
<g id='${cls.classname}'>
|
||||
${for rect in cls.rects}
|
||||
<rect x='${rect.x}' y='${rect.y}' width='${rect.width}' height='${rect.height}' style="font-size:10;fill:${rect.color};fill-rule:evenodd;stroke:#000000;stroke-width:0.4;" />
|
||||
${endfor}
|
||||
</g>
|
||||
${endfor}
|
||||
|
||||
${for info in project.infos}
|
||||
<g id='r_${info.classname}'>
|
||||
<rect x='${info.x}' y='${info.y}' width='${info.width}' height='${info.height}' style="font-size:10;fill:${info.color};fill-rule:evenodd;stroke:#000000;stroke-width:0.4;" />
|
||||
<text x="${info.text_x}" y="${info.text_y}"
|
||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
>${info.text}</text>
|
||||
</g>
|
||||
${endfor}
|
||||
|
||||
<g transform="translate(0,0)" visibility="hidden" id="tooltip">
|
||||
<rect id="tooltiprect" y="-15" x="-3" width="1" height="20" style="stroke:black;fill:#edefc2;stroke-width:1"/>
|
||||
<text id="tooltiptext" style="font-family:Arial; font-size:12;fill:black;" />
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
"""
|
||||
|
||||
COMPILE_TEMPLATE = '''def f(project):
|
||||
lst = []
|
||||
def xml_escape(value):
|
||||
return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")
|
||||
|
||||
%s
|
||||
return ''.join(lst)
|
||||
'''
|
||||
reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re.M)
|
||||
def compile_template(line):
|
||||
|
||||
extr = []
|
||||
def repl(match):
|
||||
g = match.group
|
||||
if g('dollar'): return "$"
|
||||
elif g('backslash'):
|
||||
return "\\"
|
||||
elif g('subst'):
|
||||
extr.append(g('code'))
|
||||
return "<<|@|>>"
|
||||
return None
|
||||
|
||||
line2 = reg_act.sub(repl, line)
|
||||
params = line2.split('<<|@|>>')
|
||||
assert(extr)
|
||||
|
||||
|
||||
indent = 0
|
||||
buf = []
|
||||
app = buf.append
|
||||
|
||||
def app(txt):
|
||||
buf.append(indent * '\t' + txt)
|
||||
|
||||
for x in range(len(extr)):
|
||||
if params[x]:
|
||||
app("lst.append(%r)" % params[x])
|
||||
|
||||
f = extr[x]
|
||||
if f.startswith('if') or f.startswith('for'):
|
||||
app(f + ':')
|
||||
indent += 1
|
||||
elif f.startswith('py:'):
|
||||
app(f[3:])
|
||||
elif f.startswith('endif') or f.startswith('endfor'):
|
||||
indent -= 1
|
||||
elif f.startswith('else') or f.startswith('elif'):
|
||||
indent -= 1
|
||||
app(f + ':')
|
||||
indent += 1
|
||||
elif f.startswith('xml:'):
|
||||
app('lst.append(xml_escape(%s))' % f[4:])
|
||||
else:
|
||||
#app('lst.append((%s) or "cannot find %s")' % (f, f))
|
||||
app('lst.append(str(%s))' % f)
|
||||
|
||||
if extr:
|
||||
if params[-1]:
|
||||
app("lst.append(%r)" % params[-1])
|
||||
|
||||
fun = COMPILE_TEMPLATE % "\n\t".join(buf)
|
||||
# uncomment the following to debug the template
|
||||
#for i, x in enumerate(fun.splitlines()):
|
||||
# print i, x
|
||||
return Task.funex(fun)
|
||||
|
||||
# red #ff4d4d
|
||||
# green #4da74d
|
||||
|
@ -121,7 +265,7 @@ def do_start(self):
|
|||
self.taskinfo = Queue()
|
||||
old_start(self)
|
||||
if self.dirty:
|
||||
process_colors(self)
|
||||
make_picture(self)
|
||||
Runner.Parallel.start = do_start
|
||||
|
||||
def set_running(self, by, i, tsk):
|
||||
|
@ -131,7 +275,7 @@ Runner.Parallel.set_running = set_running
|
|||
def name2class(name):
|
||||
return name.replace(' ', '_').replace('.', '_')
|
||||
|
||||
def process_colors(producer):
|
||||
def make_picture(producer):
|
||||
# first, cast the parameters
|
||||
if not hasattr(producer.bld, 'path'):
|
||||
return
|
||||
|
@ -220,82 +364,22 @@ def process_colors(producer):
|
|||
|
||||
ratio = float(Options.options.dwidth) / gwidth
|
||||
gwidth = Options.options.dwidth
|
||||
|
||||
gheight = BAND * (THREAD_AMOUNT + len(info) + 1.5)
|
||||
|
||||
out = []
|
||||
|
||||
out.append("""<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
|
||||
<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"
|
||||
\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">
|
||||
<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.0\"
|
||||
x=\"%r\" y=\"%r\" width=\"%r\" height=\"%r\"
|
||||
id=\"svg602\" xml:space=\"preserve\">
|
||||
# simple data model for our template
|
||||
class tobject(object):
|
||||
pass
|
||||
|
||||
<style type='text/css' media='screen'>
|
||||
g.over rect { stroke:#FF0000; fill-opacity:0.4 }
|
||||
</style>
|
||||
model = tobject()
|
||||
model.x = 0
|
||||
model.y = 0
|
||||
model.width = gwidth + 4
|
||||
model.height = gheight + 4
|
||||
|
||||
<script type='text/javascript'><![CDATA[
|
||||
var svg = document.getElementsByTagName('svg')[0];
|
||||
|
||||
svg.addEventListener('mouseover', function(e) {
|
||||
var g = e.target.parentNode;
|
||||
var x = document.getElementById('r_' + g.id);
|
||||
if (x) {
|
||||
g.setAttribute('class', g.getAttribute('class') + ' over');
|
||||
x.setAttribute('class', x.getAttribute('class') + ' over');
|
||||
showInfo(e, g.id);
|
||||
}
|
||||
}, false);
|
||||
|
||||
svg.addEventListener('mouseout', function(e) {
|
||||
var g = e.target.parentNode;
|
||||
var x = document.getElementById('r_' + g.id);
|
||||
if (x) {
|
||||
g.setAttribute('class', g.getAttribute('class').replace(' over', ''));
|
||||
x.setAttribute('class', x.getAttribute('class').replace(' over', ''));
|
||||
hideInfo(e);
|
||||
}
|
||||
}, false);
|
||||
|
||||
function showInfo(evt, txt) {
|
||||
tooltip = document.getElementById('tooltip');
|
||||
|
||||
var t = document.getElementById('tooltiptext');
|
||||
t.firstChild.data = txt;
|
||||
|
||||
var x = evt.clientX + 9;
|
||||
if (x > 250) { x -= t.getComputedTextLength() + 16; }
|
||||
var y = evt.clientY + 20;
|
||||
tooltip.setAttribute("transform", "translate(" + x + "," + y + ")");
|
||||
tooltip.setAttributeNS(null, "visibility", "visible");
|
||||
|
||||
var r = document.getElementById('tooltiprect');
|
||||
r.setAttribute('width', t.getComputedTextLength() + 6);
|
||||
}
|
||||
|
||||
function hideInfo(evt) {
|
||||
var tooltip = document.getElementById('tooltip');
|
||||
tooltip.setAttributeNS(null,"visibility","hidden");
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<!-- inkscape requires a big rectangle or it will not export the pictures properly -->
|
||||
<rect
|
||||
x='%r' y='%r'
|
||||
width='%r' height='%r'
|
||||
style=\"font-size:10;fill:#ffffff;fill-opacity:0.01;fill-rule:evenodd;stroke:#ffffff;\"
|
||||
/>\n
|
||||
|
||||
""" % (0, 0, gwidth + 4, gheight + 4, 0, 0, gwidth + 4, gheight + 4))
|
||||
|
||||
# main title
|
||||
if Options.options.dtitle:
|
||||
out.append("""<text x="%d" y="%d" style="font-size:15px; text-anchor:middle; font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans">%s</text>
|
||||
""" % (gwidth/2, gheight - 5, Options.options.dtitle))
|
||||
|
||||
# the rectangles
|
||||
model.title = Options.options.dtitle
|
||||
model.title_x = gwidth / 2
|
||||
model.title_y = gheight + - 5
|
||||
|
||||
groups = {}
|
||||
for (x, y, w, h, clsname) in acc:
|
||||
|
@ -303,47 +387,56 @@ function hideInfo(evt) {
|
|||
groups[clsname].append((x, y, w, h))
|
||||
except:
|
||||
groups[clsname] = [(x, y, w, h)]
|
||||
|
||||
# groups of rectangles (else js highlighting is slow)
|
||||
model.groups = []
|
||||
for cls in groups:
|
||||
out.append("<g id='%s'>\n" % name2class(cls))
|
||||
|
||||
g = tobject()
|
||||
model.groups.append(g)
|
||||
g.classname = name2class(cls)
|
||||
g.rects = []
|
||||
for (x, y, w, h) in groups[cls]:
|
||||
out.append("""<rect
|
||||
x='%r' y='%r'
|
||||
width='%r' height='%r'
|
||||
style=\"font-size:10;fill:%s;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;\"
|
||||
/>\n""" % (2 + x*ratio, 2 + y, w*ratio, h, map_to_color(cls)))
|
||||
out.append("</g>\n")
|
||||
r = tobject()
|
||||
g.rects.append(r)
|
||||
r.x = 2 + x * ratio
|
||||
r.y = 2 + y
|
||||
r.width = w * ratio
|
||||
r.height = h
|
||||
r.color = map_to_color(cls)
|
||||
|
||||
# output the caption
|
||||
cnt = THREAD_AMOUNT
|
||||
|
||||
# caption
|
||||
model.infos = []
|
||||
for (text, color) in info:
|
||||
# caption box
|
||||
b = BAND/2
|
||||
out.append("""<g id='r_%s'><rect
|
||||
x='%r' y='%r'
|
||||
width='%r' height='%r'
|
||||
style=\"font-size:10;fill:%s;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;\"
|
||||
/>\n""" % (name2class(text), 2 + BAND, 5 + (cnt + 0.5) * BAND, b, b, color))
|
||||
inf = tobject()
|
||||
model.infos.append(inf)
|
||||
inf.classname = name2class(text)
|
||||
inf.x = 2 + BAND
|
||||
inf.y = 5 + (cnt + 0.5) * BAND
|
||||
inf.width = BAND/2
|
||||
inf.height = BAND/2
|
||||
inf.color = color
|
||||
|
||||
inf.text = text
|
||||
inf.text_x = 2 + 2 * BAND
|
||||
inf.text_y = 5 + (cnt + 0.5) * BAND + 10
|
||||
|
||||
# caption text
|
||||
out.append("""<text
|
||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
x="%r" y="%d">%s</text></g>\n""" % (2 + 2 * BAND, 5 + (cnt + 0.5) * BAND + 10, text))
|
||||
cnt += 1
|
||||
|
||||
out.append("""
|
||||
<g transform="translate(0,0)" visibility="hidden" id="tooltip">
|
||||
<rect id="tooltiprect" y="-15" x="-3" width="1" height="20" style="stroke:black;fill:#edefc2;stroke-width:1"/>
|
||||
<text id="tooltiptext" style="font-family:Arial; font-size:12;fill:black;"> </text>
|
||||
</g>""")
|
||||
|
||||
out.append("\n</svg>")
|
||||
# write the file...
|
||||
template1 = compile_template(SVG_TEMPLATE)
|
||||
txt = template1(model)
|
||||
|
||||
node = producer.bld.path.make_node('pdebug.svg')
|
||||
node.write("".join(out))
|
||||
node.write(txt)
|
||||
Logs.warn('Created the diagram %r' % node.abspath())
|
||||
|
||||
p = node.parent.abspath()
|
||||
producer.bld.exec_command([producer.bld.env.CONVERT_BIN or 'convert', p + os.sep + 'pdebug.svg', p + os.sep + 'pdebug.png'])
|
||||
def options(opt):
|
||||
opt.add_option('--dtitle', action='store', default='Parallel build representation for %r' % ' '.join(sys.argv),
|
||||
help='title for the svg diagram', dest='dtitle')
|
||||
opt.add_option('--dwidth', action='store', type='int', help='diagram width', default=800, dest='dwidth')
|
||||
opt.add_option('--dtime', action='store', type='float', help='recording interval in seconds', default=0.009, dest='dtime')
|
||||
opt.add_option('--dband', action='store', type='int', help='band width', default=22, dest='dband')
|
||||
opt.add_option('--dmaxtime', action='store', type='float', help='maximum time, for drawing fair comparisons', default=0, dest='dmaxtime')
|
||||
|
||||
|
|
Loading…
Reference in New Issue