* log2xml -> nix-log2xml.
This commit is contained in:
parent
d47e03fccd
commit
0e38578433
8 changed files with 2 additions and 2 deletions
17
src/nix-log2xml/Makefile.am
Normal file
17
src/nix-log2xml/Makefile.am
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
bin_PROGRAMS = nix-log2xml
|
||||
|
||||
nix_log2xml_SOURCES = log2xml.cc
|
||||
|
||||
%.xml: %.log nix-log2xml
|
||||
./nix-log2xml < $< > $@
|
||||
|
||||
%.html: %.xml mark-errors.xsl log2html.xsl
|
||||
$(xsltproc) mark-errors.xsl $< | $(xsltproc) log2html.xsl - > $@
|
||||
|
||||
LOG2HTML = mark-errors.xsl log2html.xsl treebits.js
|
||||
|
||||
EXTRA_DIST = $(LOG2HTML)
|
||||
|
||||
install-data-local:
|
||||
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/log2html
|
||||
$(INSTALL_DATA) $(LOG2HTML) $(DESTDIR)$(datadir)/nix/log2html
|
||||
76
src/nix-log2xml/log2html.xsl
Normal file
76
src/nix-log2xml/log2html.xsl
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<xsl:output method='html' />
|
||||
|
||||
<xsl:template match="logfile">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="treebits.js" />
|
||||
<link rel="stylesheet" href="logfile.css" type="text/css" />
|
||||
<title>Log File</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul class='toplevel'>
|
||||
<xsl:for-each select='line|nest'>
|
||||
<li>
|
||||
<xsl:apply-templates select='.'/>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="nest">
|
||||
|
||||
<!-- The tree should be collapsed by default if all children are
|
||||
unimportant or if the header is unimportant. -->
|
||||
<!-- <xsl:variable name="collapsed"
|
||||
select="count(.//line[not(@priority = 3)]) = 0 or ./head[@priority = 3]" /> -->
|
||||
<xsl:variable name="collapsed" select="count(.//*[@error]) = 0"/>
|
||||
|
||||
<xsl:variable name="style"><xsl:if test="$collapsed">display: none;</xsl:if></xsl:variable>
|
||||
<xsl:variable name="arg"><xsl:choose><xsl:when test="$collapsed">true</xsl:when><xsl:otherwise>false</xsl:otherwise></xsl:choose></xsl:variable>
|
||||
|
||||
<script type='text/javascript'>showTreeToggle(<xsl:value-of select="$collapsed"/>)</script>
|
||||
<xsl:apply-templates select='head'/>
|
||||
|
||||
<ul class='nesting' style="{$style}">
|
||||
<xsl:for-each select='line|nest'>
|
||||
|
||||
<!-- Is this the last line? If so, mark it as such so that it
|
||||
can be rendered differently. -->
|
||||
<xsl:variable name="class"><xsl:choose><xsl:when test="position() != last()">line</xsl:when><xsl:otherwise>lastline</xsl:otherwise></xsl:choose></xsl:variable>
|
||||
|
||||
<li class='{$class}'>
|
||||
<span class='lineconn' />
|
||||
<span class='linebody'>
|
||||
<xsl:apply-templates select='.'/>
|
||||
</span>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="head|line">
|
||||
<code>
|
||||
<xsl:if test="@error">
|
||||
<xsl:attribute name="class">error</xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:apply-templates/>
|
||||
</code>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="storeref">
|
||||
<em class='storeref'>
|
||||
<span class='popup'><xsl:apply-templates/></span>
|
||||
<span class='elided'>/...</span><xsl:apply-templates select='name'/><xsl:apply-templates select='path'/>
|
||||
</em>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
172
src/nix-log2xml/log2xml.cc
Normal file
172
src/nix-log2xml/log2xml.cc
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Decoder
|
||||
{
|
||||
enum { stTop, stEscape, stCSI } state;
|
||||
string line;
|
||||
bool inHeader;
|
||||
int level;
|
||||
vector<int> args;
|
||||
bool newNumber;
|
||||
int priority;
|
||||
bool ignoreLF;
|
||||
int lineNo, charNo;
|
||||
|
||||
Decoder()
|
||||
{
|
||||
state = stTop;
|
||||
line = "";
|
||||
inHeader = false;
|
||||
level = 0;
|
||||
priority = 1;
|
||||
ignoreLF = false;
|
||||
lineNo = 1;
|
||||
charNo = 0;
|
||||
}
|
||||
|
||||
void pushChar(char c);
|
||||
|
||||
void finishLine();
|
||||
};
|
||||
|
||||
|
||||
void Decoder::pushChar(char c)
|
||||
{
|
||||
if (c == '\n') {
|
||||
lineNo++;
|
||||
charNo = 0;
|
||||
} else charNo++;
|
||||
|
||||
switch (state) {
|
||||
|
||||
case stTop:
|
||||
if (c == '\e') {
|
||||
state = stEscape;
|
||||
} else if (c == '\n' && !ignoreLF) {
|
||||
finishLine();
|
||||
} else line += c;
|
||||
break;
|
||||
|
||||
case stEscape:
|
||||
if (c == '[') {
|
||||
state = stCSI;
|
||||
args.clear();
|
||||
newNumber = true;
|
||||
} else
|
||||
state = stTop; /* !!! wrong */
|
||||
break;
|
||||
|
||||
case stCSI:
|
||||
if (c >= 0x40 && c != 0x7e) {
|
||||
state = stTop;
|
||||
switch (c) {
|
||||
case 'p':
|
||||
if (line.size()) finishLine();
|
||||
level++;
|
||||
inHeader = true;
|
||||
cout << "<nest>" << endl;
|
||||
priority = args.size() >= 1 ? args[0] : 1;
|
||||
break;
|
||||
case 'q':
|
||||
if (line.size()) finishLine();
|
||||
if (level > 0) {
|
||||
level--;
|
||||
cout << "</nest>" << endl;
|
||||
} else
|
||||
cerr << "not enough nesting levels at line "
|
||||
<< lineNo << ", character " << charNo << endl;
|
||||
break;
|
||||
case 's':
|
||||
if (line.size()) finishLine();
|
||||
priority = args.size() >= 1 ? args[0] : 1;
|
||||
break;
|
||||
case 'a':
|
||||
ignoreLF = true;
|
||||
break;
|
||||
case 'b':
|
||||
ignoreLF = false;
|
||||
break;
|
||||
}
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
int n = 0;
|
||||
if (!newNumber) {
|
||||
n = args.back() * 10;
|
||||
args.pop_back();
|
||||
}
|
||||
n += c - '0';
|
||||
args.push_back(n);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Decoder::finishLine()
|
||||
{
|
||||
string storeDir = "/nix/store/";
|
||||
int sz = storeDir.size();
|
||||
string tag = inHeader ? "head" : "line";
|
||||
cout << "<" << tag;
|
||||
if (priority != 1) cout << " priority='" << priority << "'";
|
||||
cout << ">";
|
||||
|
||||
for (unsigned int i = 0; i < line.size(); i++) {
|
||||
|
||||
if (line[i] == '<') cout << "<";
|
||||
else if (line[i] == '&') cout << "&";
|
||||
else if (line[i] < 32 && line[i] != 9) cout << "�";
|
||||
else if (i + sz + 33 < line.size() &&
|
||||
string(line, i, sz) == storeDir &&
|
||||
line[i + sz + 32] == '-')
|
||||
{
|
||||
int j = i + sz + 32;
|
||||
/* skip name */
|
||||
while (!strchr("/\n\r\t ()[]:;?<>", line[j])) j++;
|
||||
int k = j;
|
||||
while (!strchr("\n\r\t ()[]:;?<>", line[k])) k++;
|
||||
// !!! escaping
|
||||
cout << "<storeref>"
|
||||
<< "<storedir>"
|
||||
<< string(line, i, sz)
|
||||
<< "</storedir>"
|
||||
<< "<hash>"
|
||||
<< string(line, i + sz, 32)
|
||||
<< "</hash>"
|
||||
<< "<name>"
|
||||
<< string(line, i + sz + 32, j - (i + sz + 32))
|
||||
<< "</name>"
|
||||
<< "<path>"
|
||||
<< string(line, j, k - j)
|
||||
<< "</path>"
|
||||
<< "</storeref>";
|
||||
i = k - 1;
|
||||
} else cout << line[i];
|
||||
}
|
||||
|
||||
cout << "</" << tag << ">" << endl;
|
||||
line = "";
|
||||
inHeader = false;
|
||||
priority = 1;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
Decoder dec;
|
||||
int c;
|
||||
|
||||
cout << "<logfile>" << endl;
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
dec.pushChar(c);
|
||||
}
|
||||
|
||||
cout << "</logfile>" << endl;
|
||||
}
|
||||
86
src/nix-log2xml/logfile.css
Normal file
86
src/nix-log2xml/logfile.css
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
body {
|
||||
font-family: sans-serif;
|
||||
background: white;
|
||||
}
|
||||
|
||||
|
||||
ul.nesting, ul.toplevel {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul.toplevel {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
ul.nesting li.line, ul.nesting li.lastline {
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
ul.nesting li.line {
|
||||
padding-left: 1.1em;
|
||||
}
|
||||
|
||||
ul.nesting li.lastline {
|
||||
padding-left: 1.2em; // for the 0.1em border-left in .lastline > .lineconn
|
||||
}
|
||||
|
||||
li.line {
|
||||
border-left: 0.1em solid #6185a0;
|
||||
}
|
||||
|
||||
li.line > span.lineconn, li.lastline > span.lineconn {
|
||||
position: absolute;
|
||||
height: 0.65em;
|
||||
left: 0em;
|
||||
width: 1em;
|
||||
border-bottom: 0.1em solid #6185a0;
|
||||
}
|
||||
|
||||
li.lastline > span.lineconn {
|
||||
border-left: 0.1em solid #6185a0;
|
||||
}
|
||||
|
||||
|
||||
em.storeref {
|
||||
color: #500000;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
em.storeref:hover {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
*.popup {
|
||||
display: none;
|
||||
/* background: url('http://losser.st-lab.cs.uu.nl/~mbravenb/menuback.png') repeat; */
|
||||
background: #ffffcd;
|
||||
border: solid #555555 1px;
|
||||
position: absolute;
|
||||
top: 0em;
|
||||
left: 0em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
em.storeref:hover span.popup {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
.toggle {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.showTree, .hideTree {
|
||||
font-family: monospace;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #ff0000;
|
||||
font-weight: bold;
|
||||
}
|
||||
24
src/nix-log2xml/mark-errors.xsl
Normal file
24
src/nix-log2xml/mark-errors.xsl
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<xsl:template match="@*|node()">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="line">
|
||||
<line>
|
||||
<xsl:if test="contains(text(), ' *** ') or
|
||||
contains(text(), 'LaTeX Error') or
|
||||
contains(text(), 'FAIL:') or
|
||||
contains(text(), ' error: ') or
|
||||
true">
|
||||
<xsl:attribute name="error"></xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</line>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
50
src/nix-log2xml/treebits.js
Normal file
50
src/nix-log2xml/treebits.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* Acknowledgement: this is based on the Wikipedia table-of-contents
|
||||
* toggle. */
|
||||
|
||||
|
||||
var idCounter = 0;
|
||||
|
||||
|
||||
function showTreeToggle(isHidden) {
|
||||
if (document.getElementById) {
|
||||
var id = "toggle_" + idCounter;
|
||||
document.writeln(
|
||||
'<a href="javascript:toggleTree(\'' + id + '\')" class="toggle" id="' + id + '">' +
|
||||
'<span class="showTree" ' + (isHidden ? '' : 'style="display: none;"') + '>+</span>' +
|
||||
'<span class="hideTree" ' + (isHidden ? 'style="display: none;"' : '') + '>-</span>' +
|
||||
'</a>');
|
||||
idCounter = idCounter + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function toggleTree(id) {
|
||||
|
||||
var href = document.getElementById(id);
|
||||
|
||||
var node = href;
|
||||
var tree = null;
|
||||
while (node != null) {
|
||||
if (node.className == "nesting") tree = node;
|
||||
node = node.nextSibling;
|
||||
}
|
||||
|
||||
node = href.firstChild;
|
||||
var hideTree = null;
|
||||
var showTree = null;
|
||||
while (node != null) {
|
||||
if (node.className == "showTree") showTree = node;
|
||||
else if (node.className == "hideTree") hideTree = node;
|
||||
node = node.nextSibling;
|
||||
}
|
||||
|
||||
if (tree.style.display == 'none') {
|
||||
tree.style.display = '';
|
||||
hideTree.style.display = '';
|
||||
showTree.style.display = 'none';
|
||||
} else {
|
||||
tree.style.display = 'none';
|
||||
hideTree.style.display = 'none';
|
||||
showTree.style.display = '';
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue