summaryrefslogtreecommitdiffstats
path: root/src/browse.py
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2012-01-24 23:56:15 (GMT)
committerEvan Martin <martine@danga.com>2012-01-24 23:56:15 (GMT)
commit982de2ff79a1d862026763bcff17582ebeef5a5d (patch)
treee63d776ef833ef7f35cd0143aa6e0d3fdc977240 /src/browse.py
parent9101fb077be10d74bc0f165cc2c327a9190e3eb6 (diff)
downloadNinja-982de2ff79a1d862026763bcff17582ebeef5a5d.zip
Ninja-982de2ff79a1d862026763bcff17582ebeef5a5d.tar.gz
Ninja-982de2ff79a1d862026763bcff17582ebeef5a5d.tar.bz2
rearrange query/browse output to be more sensible
Diffstat (limited to 'src/browse.py')
-rwxr-xr-xsrc/browse.py131
1 files changed, 78 insertions, 53 deletions
diff --git a/src/browse.py b/src/browse.py
index ca95197..17e67cf 100755
--- a/src/browse.py
+++ b/src/browse.py
@@ -24,36 +24,66 @@ import BaseHTTPServer
import subprocess
import sys
import webbrowser
+from collections import namedtuple
-def match_strip(prefix, line):
+Node = namedtuple('Node', ['inputs', 'rule', 'target', 'outputs'])
+
+# Ideally we'd allow you to navigate to a build edge or a build node,
+# with appropriate views for each. But there's no way to *name* a build
+# edge so we can only display nodes.
+#
+# For a given node, it has at most one input edge, which has n
+# different inputs. This becomes node.inputs. (We leave out the
+# outputs of the input edge due to what follows.) The node can have
+# multiple dependent output edges. Rather than attempting to display
+# those, they are summarized by taking the union of all their outputs.
+#
+# This means there's no single view that shows you all inputs and outputs
+# of an edge. But I think it's less confusing than alternatives.
+
+def match_strip(line, prefix):
if not line.startswith(prefix):
- print prefix, line
- assert line.startswith(prefix)
- return line[len(prefix):]
+ return (False, line)
+ return (True, line[len(prefix):])
def parse(text):
- lines = text.split('\n')
- node = lines.pop(0)
- node = node[:-1] # strip trailing colon
-
- input = []
- if lines and lines[0].startswith(' input:'):
- input.append(match_strip(' input: ', lines.pop(0)))
- while lines and lines[0].startswith(' '):
- input.append(lines.pop(0).strip())
+ lines = iter(text.split('\n'))
+ target = None
+ rule = None
+ inputs = []
outputs = []
- while lines:
- output = []
- output.append(match_strip(' output: ', lines.pop(0)))
- while lines and lines[0].startswith(' '):
- output.append(lines.pop(0).strip())
- outputs.append(output)
-
- return (node, input, outputs)
-def generate_html(data):
- node, input, outputs = data
+ try:
+ target = lines.next()[:-1] # strip trailing colon
+
+ line = lines.next()
+ (match, rule) = match_strip(line, ' input: ')
+ if match:
+ (match, line) = match_strip(lines.next(), ' ')
+ while match:
+ type = None
+ (match, line) = match_strip(line, '| ')
+ if match:
+ type = 'implicit'
+ (match, line) = match_strip(line, '|| ')
+ if match:
+ type = 'order-only'
+ inputs.append((line, type))
+ (match, line) = match_strip(lines.next(), ' ')
+
+ match, _ = match_strip(line, ' outputs:')
+ if match:
+ (match, line) = match_strip(lines.next(), ' ')
+ while match:
+ outputs.append(line)
+ (match, line) = match_strip(lines.next(), ' ')
+ except StopIteration:
+ pass
+
+ return Node(inputs, rule, target, outputs)
+
+def generate_html(node):
print '''<!DOCTYPE html>
<style>
body {
@@ -63,47 +93,42 @@ body {
}
h1 {
font-weight: normal;
+ font-size: 140%;
text-align: center;
margin: 0;
}
h2 {
font-weight: normal;
+ font-size: 120%;
}
tt {
font-family: WebKitHack, monospace;
+ white-space: nowrap;
}
-ul {
- margin-top: 0;
- padding-left: 20px;
+.filelist {
+ -webkit-columns: auto 2;
}
</style>'''
- print '<table width=500><tr><td colspan=3>'
- print '<h1><tt>%s</tt></h1>' % node
- print '</td></tr>'
-
- print '<tr><td valign=top>'
- if input:
- print '<h2>built by rule: <tt>%s</tt></h2>' % input[0]
- if len(input) > 0:
- print 'inputs:'
- print '<ul>'
- for i in input[1:]:
- print '<li><tt><a href="?%s">%s</a></tt></li>' % (i, i)
- print '</ul>'
- else:
- print '<h2>no input rule</h2>'
- print '</td>'
- print '<td width=50>&nbsp;</td>'
-
- print '<td valign=top>'
- print '<h2>dependents</h2>'
- for output in outputs:
- print '<tt>%s</tt>' % output[0]
- print '<ul>'
- for i in output[1:]:
- print '<li><tt><a href="?%s">%s</a></tt></li>' % (i, i)
- print '</ul>'
- print '</td></tr></table>'
+
+ print '<h1><tt>%s</tt></h1>' % node.target
+
+ if node.inputs:
+ print '<h2>target is built using rule <tt>%s</tt> of</h2>' % node.rule
+ if len(node.inputs) > 0:
+ print '<div class=filelist>'
+ for input, type in sorted(node.inputs):
+ extra = ''
+ if type:
+ extra = ' (%s)' % type
+ print '<tt><a href="?%s">%s</a>%s</tt><br>' % (input, input, extra)
+ print '</div>'
+
+ if node.outputs:
+ print '<h2>dependent edges build:</h2>'
+ print '<div class=filelist>'
+ for output in sorted(node.outputs):
+ print '<tt><a href="?%s">%s</a></tt><br>' % (output, output)
+ print '</div>'
def ninja_dump(target):
proc = subprocess.Popen([sys.argv[1], '-t', 'query', target],