Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: third_party/buildbot_7_12/buildbot/status/web/grid.py

Issue 12207158: Bye bye buildbot 0.7.12. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 from __future__ import generators
2
3 import sys, time, os.path
4 import urllib
5
6 from twisted.web import html, resource
7
8 from buildbot import util
9 from buildbot import version
10 from buildbot.status.web.base import HtmlResource
11 #from buildbot.status.web.base import Box, HtmlResource, IBox, ICurrentBox, \
12 # ITopBox, td, build_get_class, path_to_build, path_to_step, map_branches
13 from buildbot.status.web.base import build_get_class
14
15 # set grid_css to the full pathname of the css file
16 if hasattr(sys, "frozen"):
17 # all 'data' files are in the directory of our executable
18 here = os.path.dirname(sys.executable)
19 grid_css = os.path.abspath(os.path.join(here, "grid.css"))
20 else:
21 # running from source; look for a sibling to __file__
22 up = os.path.dirname
23 grid_css = os.path.abspath(os.path.join(up(__file__), "grid.css"))
24
25 class ANYBRANCH: pass # a flag value, used below
26
27 class GridStatusMixin(object):
28 def getTitle(self, request):
29 status = self.getStatus(request)
30 p = status.getProjectName()
31 if p:
32 return "BuildBot: %s" % p
33 else:
34 return "BuildBot"
35
36 def getChangemaster(self, request):
37 # TODO: this wants to go away, access it through IStatus
38 return request.site.buildbot_service.getChangeSvc()
39
40 # handle reloads through an http header
41 # TODO: send this as a real header, rather than a tag
42 def get_reload_time(self, request):
43 if "reload" in request.args:
44 try:
45 reload_time = int(request.args["reload"][0])
46 return max(reload_time, 15)
47 except ValueError:
48 pass
49 return None
50
51 def head(self, request):
52 head = ''
53 reload_time = self.get_reload_time(request)
54 if reload_time is not None:
55 head += '<meta http-equiv="refresh" content="%d">\n' % reload_time
56 return head
57
58 # def setBuildmaster(self, buildmaster):
59 # self.status = buildmaster.getStatus()
60 # if self.allowForce:
61 # self.control = interfaces.IControl(buildmaster)
62 # else:
63 # self.control = None
64 # self.changemaster = buildmaster.change_svc
65 #
66 # # try to set the page title
67 # p = self.status.getProjectName()
68 # if p:
69 # self.title = "BuildBot: %s" % p
70 #
71 def build_td(self, request, build):
72 if not build:
73 return '<td class="build">&nbsp;</td>\n'
74
75 if build.isFinished():
76 # get the text and annotate the first line with a link
77 text = build.getText()
78 if not text: text = [ "(no information)" ]
79 if text == [ "build", "successful" ]: text = [ "OK" ]
80 else:
81 text = [ 'building' ]
82
83 name = build.getBuilder().getName()
84 number = build.getNumber()
85 url = "builders/%s/builds/%d" % (name, number)
86 text[0] = '<a href="%s">%s</a>' % (url, text[0])
87 text = '<br />\n'.join(text)
88 class_ = build_get_class(build)
89
90 return '<td class="build %s">%s</td>\n' % (class_, text)
91
92 def builder_td(self, request, builder):
93 state, builds = builder.getState()
94
95 # look for upcoming builds. We say the state is "waiting" if the
96 # builder is otherwise idle and there is a scheduler which tells us a
97 # build will be performed some time in the near future. TODO: this
98 # functionality used to be in BuilderStatus.. maybe this code should
99 # be merged back into it.
100 upcoming = []
101 builderName = builder.getName()
102 for s in self.getStatus(request).getSchedulers():
103 if builderName in s.listBuilderNames():
104 upcoming.extend(s.getPendingBuildTimes())
105 if state == "idle" and upcoming:
106 state = "waiting"
107
108 # TODO: for now, this pending/upcoming stuff is in the "current
109 # activity" box, but really it should go into a "next activity" row
110 # instead. The only times it should show up in "current activity" is
111 # when the builder is otherwise idle.
112
113 # are any builds pending? (waiting for a slave to be free)
114 url = 'builders/%s/' % urllib.quote(builder.getName(), safe='')
115 text = '<a href="%s">%s</a>' % (url, builder.getName())
116 pbs = builder.getPendingBuilds()
117 if state != 'idle' or pbs:
118 if pbs:
119 text += "<br />(%s with %d pending)" % (state, len(pbs))
120 else:
121 text += "<br />(%s)" % state
122
123 return '<td valign="center" class="builder %s">%s</td>\n' % \
124 (state, text)
125
126 def stamp_td(self, stamp):
127 text = stamp.getText()
128 return '<td valign="bottom" class="sourcestamp">%s</td>\n' % \
129 "<br />".join(text)
130
131 def getSourceStampKey(self, ss):
132 """Given two source stamps, we want to assign them to the same row if
133 they are the same version of code, even if they differ in minor detail.
134
135 This function returns an appropriate comparison key for that.
136 """
137 return (ss.branch, ss.revision, ss.patch)
138
139 def getRecentSourcestamps(self, status, numBuilds, categories, branch):
140 """
141 get a list of the most recent NUMBUILDS SourceStamp tuples, sorted
142 by the earliest start we've seen for them
143 """
144 # TODO: use baseweb's getLastNBuilds?
145 sourcestamps = { } # { ss-tuple : earliest time }
146 for bn in status.getBuilderNames():
147 builder = status.getBuilder(bn)
148 if categories and builder.category not in categories:
149 continue
150 build = builder.getBuild(-1)
151 while build:
152 ss = build.getSourceStamp(absolute=True)
153 start = build.getTimes()[0]
154 build = build.getPreviousBuild()
155
156 # skip un-started builds
157 if not start: continue
158
159 # skip non-matching branches
160 if branch != ANYBRANCH and ss.branch != branch: continue
161
162 key= self.getSourceStampKey(ss)
163 if key not in sourcestamps or sourcestamps[key][1] > start:
164 sourcestamps[key] = (ss, start)
165
166 # now sort those and take the NUMBUILDS most recent
167 sourcestamps = sourcestamps.values()
168 sourcestamps.sort(lambda x, y: cmp(x[1], y[1]))
169 sourcestamps = map(lambda tup : tup[0], sourcestamps)
170 sourcestamps = sourcestamps[-numBuilds:]
171
172 return sourcestamps
173
174 class GridStatusResource(HtmlResource, GridStatusMixin):
175 # TODO: docs
176 status = None
177 control = None
178 changemaster = None
179
180 def __init__(self, allowForce=True, css=None):
181 HtmlResource.__init__(self)
182
183 self.allowForce = allowForce
184 self.css = css or grid_css
185
186
187 def body(self, request):
188 """This method builds the regular grid display.
189 That is, build stamps across the top, build hosts down the left side
190 """
191
192 # get url parameters
193 numBuilds = int(request.args.get("width", [5])[0])
194 categories = request.args.get("category", [])
195 branch = request.args.get("branch", [ANYBRANCH])[0]
196 if branch == 'trunk': branch = None
197
198 # and the data we want to render
199 status = self.getStatus(request)
200 stamps = self.getRecentSourcestamps(status, numBuilds, categories, branc h)
201
202 projectURL = status.getProjectURL()
203 projectName = status.getProjectName()
204
205 data = '<table class="Grid" border="0" cellspacing="0">\n'
206 data += '<tr>\n'
207 data += '<td class="title"><a href="%s">%s</a>' % (projectURL, projectNa me)
208 if categories:
209 html_categories = map(html.escape, categories)
210 if len(categories) > 1:
211 data += '\n<br /><b>Categories:</b><br/>%s' % ('<br/>'.join(html _categories))
212 else:
213 data += '\n<br /><b>Category:</b> %s' % html_categories[0]
214 if branch != ANYBRANCH:
215 data += '\n<br /><b>Branch:</b> %s' % (html.escape(branch or 'trunk' ))
216 data += '</td>\n'
217 for stamp in stamps:
218 data += self.stamp_td(stamp)
219 data += '</tr>\n'
220
221 sortedBuilderNames = status.getBuilderNames()[:]
222 sortedBuilderNames.sort()
223 for bn in sortedBuilderNames:
224 builds = [None] * len(stamps)
225
226 builder = status.getBuilder(bn)
227 if categories and builder.category not in categories:
228 continue
229
230 build = builder.getBuild(-1)
231 while build and None in builds:
232 ss = build.getSourceStamp(absolute=True)
233 key= self.getSourceStampKey(ss)
234 for i in range(len(stamps)):
235 if key == self.getSourceStampKey(stamps[i]) and builds[i] is None:
236 builds[i] = build
237 build = build.getPreviousBuild()
238
239 data += '<tr>\n'
240 data += self.builder_td(request, builder)
241 for build in builds:
242 data += self.build_td(request, build)
243 data += '</tr>\n'
244
245 data += '</table>\n'
246
247 data += self.footer(status, request)
248 return data
249
250 class TransposedGridStatusResource(HtmlResource, GridStatusMixin):
251 # TODO: docs
252 status = None
253 control = None
254 changemaster = None
255
256 def __init__(self, allowForce=True, css=None):
257 HtmlResource.__init__(self)
258
259 self.allowForce = allowForce
260 self.css = css or grid_css
261
262
263 def body(self, request):
264 """This method builds the transposed grid display.
265 That is, build hosts across the top, ebuild stamps down the left side
266 """
267
268 # get url parameters
269 numBuilds = int(request.args.get("length", [5])[0])
270 categories = request.args.get("category", [])
271 branch = request.args.get("branch", [ANYBRANCH])[0]
272 if branch == 'trunk': branch = None
273
274 # and the data we want to render
275 status = self.getStatus(request)
276 stamps = self.getRecentSourcestamps(status, numBuilds, categories, branc h)
277
278 projectURL = status.getProjectURL()
279 projectName = status.getProjectName()
280
281 data = '<table class="Grid" border="0" cellspacing="0">\n'
282 data += '<tr>\n'
283 data += '<td class="title"><a href="%s">%s</a>' % (projectURL, projectNa me)
284 if categories:
285 html_categories = map(html.escape, categories)
286 if len(categories) > 1:
287 data += '\n<br /><b>Categories:</b><br/>%s' % ('<br/>'.join(html _categories))
288 else:
289 data += '\n<br /><b>Category:</b> %s' % html_categories[0]
290 if branch != ANYBRANCH:
291 data += '\n<br /><b>Branch:</b> %s' % (html.escape(branch or 'trunk' ))
292 data += '</td>\n'
293
294 sortedBuilderNames = status.getBuilderNames()[:]
295 sortedBuilderNames.sort()
296
297 builder_builds = []
298
299 for bn in sortedBuilderNames:
300 builds = [None] * len(stamps)
301
302 builder = status.getBuilder(bn)
303 if categories and builder.category not in categories:
304 continue
305
306 build = builder.getBuild(-1)
307 while build and None in builds:
308 ss = build.getSourceStamp(absolute=True)
309 key = self.getSourceStampKey(ss)
310 for i in range(len(stamps)):
311 if key == self.getSourceStampKey(stamps[i]) and builds[i] is None:
312 builds[i] = build
313 build = build.getPreviousBuild()
314
315 data += self.builder_td(request, builder)
316 builder_builds.append(builds)
317
318 data += '</tr>\n'
319
320 for i in range(len(stamps)):
321 data += '<tr>\n'
322 data += self.stamp_td(stamps[i])
323 for builds in builder_builds:
324 data += self.build_td(request, builds[i])
325 data += '</tr>\n'
326
327 data += '</table>\n'
328
329 data += self.footer(status, request)
330 return data
331
OLDNEW
« no previous file with comments | « third_party/buildbot_7_12/buildbot/status/web/feeds.py ('k') | third_party/buildbot_7_12/buildbot/status/web/index.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698