1
2 from zope.interface import implements
3 from twisted.python import components
4 from twisted.spread import pb
5 from twisted.web import html, server
6 from twisted.web.resource import Resource
7 from twisted.web.error import NoResource
8
9 from buildbot import interfaces
10 from buildbot.status import builder
11 from buildbot.status.web.base import IHTMLLog, HtmlResource
12
13
14 textlog_stylesheet = """
15 <style type="text/css">
16 div.data {
17 font-family: "Courier New", courier, monotype;
18 }
19 span.stdout {
20 font-family: "Courier New", courier, monotype;
21 }
22 span.stderr {
23 font-family: "Courier New", courier, monotype;
24 color: red;
25 }
26 span.header {
27 font-family: "Courier New", courier, monotype;
28 color: blue;
29 }
30 </style>
31 """
32
34 implements(interfaces.IStatusLogConsumer)
35
37 self.original = original
38 self.textlog = textlog
40 self.producer = producer
41 self.original.registerProducer(producer, streaming)
45 formatted = self.textlog.content([chunk])
46 try:
47 self.original.write(formatted)
48 except pb.DeadReferenceError:
49 self.producing.stopProducing()
52
53
54
55 -class TextLog(Resource):
56
57
58 implements(IHTMLLog)
59
60 asText = False
61 subscribed = False
62
63 - def __init__(self, original):
64 Resource.__init__(self)
65 self.original = original
66
67 - def getChild(self, path, req):
68 if path == "text":
69 self.asText = True
70 return self
71 return HtmlResource.getChild(self, path, req)
72
74 title = "Log File contents"
75 data = "<html>\n<head><title>" + title + "</title>\n"
76 data += textlog_stylesheet
77 data += "</head>\n"
78 data += "<body vlink=\"#800080\">\n"
79 texturl = request.childLink("text")
80 data += '<a href="%s">(view as text)</a><br />\n' % texturl
81 data += "<pre>\n"
82 return data
83
84 - def content(self, entries):
85 spanfmt = '<span class="%s">%s</span>'
86 data = ""
87 for type, entry in entries:
88 if type >= len(builder.ChunkTypes) or type < 0:
89
90 continue
91 if self.asText:
92 if type != builder.HEADER:
93 data += entry
94 else:
95 data += spanfmt % (builder.ChunkTypes[type],
96 html.escape(entry))
97 return data
98
100 data = "</pre>\n"
101 data += "</body></html>\n"
102 return data
103
104 - def render_HEAD(self, request):
105 if self.asText:
106 request.setHeader("content-type", "text/plain")
107 else:
108 request.setHeader("content-type", "text/html")
109
110
111 request.setHeader("content-length", self.original.length)
112 return ''
113
114 - def render_GET(self, req):
115 self.req = req
116
117 if self.asText:
118 req.setHeader("content-type", "text/plain")
119 else:
120 req.setHeader("content-type", "text/html")
121
122 if not self.asText:
123 req.write(self.htmlHeader(req))
124
125 self.original.subscribeConsumer(ChunkConsumer(req, self))
126 return server.NOT_DONE_YET
127
128 - def finished(self):
129 if not self.req:
130 return
131 try:
132 if not self.asText:
133 self.req.write(self.htmlFooter())
134 self.req.finish()
135 except pb.DeadReferenceError:
136 pass
137
138
139 self.req = None
140
141 components.registerAdapter(TextLog, interfaces.IStatusLog, IHTMLLog)
142
143
145 implements(IHTMLLog)
146
148 Resource.__init__(self)
149 self.original = original
150
152 request.setHeader("content-type", "text/html")
153 return self.original.html
154
155 components.registerAdapter(HTMLLog, builder.HTMLLogFile, IHTMLLog)
156
157
172