1   
  2  from twisted.web import html 
  3  from twisted.web.util import Redirect, DeferredResource 
  4  from twisted.internet import defer, reactor 
  5   
  6  import urllib, time 
  7  from twisted.python import log 
  8  from buildbot.status.web.base import HtmlResource, make_row, make_stop_form, \ 
  9       make_extra_property_row, css_classes, path_to_builder, path_to_slave, \ 
 10       make_name_user_passwd_form, getAndCheckProperties 
 11   
 12   
 13  from buildbot.status.web.tests import TestsResource 
 14  from buildbot.status.web.step import StepsResource 
 15  from buildbot import version, util 
 16   
 17   
 19      addSlash = True 
 20   
 21 -    def __init__(self, build_status, build_control, builder_control): 
  26   
 31   
 32 -    def body(self, req): 
  33          b = self.build_status 
 34          status = self.getStatus(req) 
 35          projectName = status.getProjectName() 
 36          projectURL = status.getProjectURL() 
 37          data = ('<div class="title"><a href="%s">%s</a></div>\n' 
 38                  % (self.path_to_root(req), projectName)) 
 39          builder_name = b.getBuilder().getName() 
 40          data += ("<h1><a href=\"%s\">Builder %s</a>: Build #%d</h1>\n" 
 41                   % (path_to_builder(req, b.getBuilder()), 
 42                      builder_name, b.getNumber())) 
 43   
 44          if not b.isFinished(): 
 45              data += "<h2>Build In Progress</h2>" 
 46              when = b.getETA() 
 47              if when is not None: 
 48                  when_time = time.strftime("%H:%M:%S", 
 49                                            time.localtime(time.time() + when)) 
 50                  data += "<div>ETA %ds (%s)</div>\n" % (when, when_time) 
 51   
 52              if self.build_control is not None: 
 53                  stopURL = urllib.quote(req.childLink("stop")) 
 54                  data += make_stop_form(stopURL, self.isUsingUserPasswd(req)) 
 55   
 56          if b.isFinished(): 
 57               
 58              results = b.getResults() 
 59              data += "<h2>Results:</h2>\n" 
 60              text = " ".join(b.getText()) 
 61              data += '<span class="%s">%s</span>\n' % (css_classes[results], 
 62                                                        text) 
 63              if b.getTestResults(): 
 64                  url = req.childLink("tests") 
 65                  data += "<h3><a href=\"%s\">test results</a></h3>\n" % url 
 66   
 67          ss = b.getSourceStamp() 
 68          data += "<h2>SourceStamp:</h2>\n" 
 69          data += " <ul>\n" 
 70          if ss.branch: 
 71              data += "  <li>Branch: %s</li>\n" % html.escape(ss.branch) 
 72          if ss.revision: 
 73              data += "  <li>Revision: %s</li>\n" % html.escape(str(ss.revision)) 
 74          if ss.patch: 
 75              data += "  <li>Patch: YES</li>\n"  
 76          if ss.changes: 
 77              data += "  <li>Changes: see below</li>\n" 
 78          if (ss.branch is None and ss.revision is None and ss.patch is None 
 79              and not ss.changes): 
 80              data += "  <li>build of most recent revision</li>\n" 
 81          got_revision = None 
 82          try: 
 83              got_revision = b.getProperty("got_revision") 
 84          except KeyError: 
 85              pass 
 86          if got_revision: 
 87              got_revision = str(got_revision) 
 88              if len(got_revision) > 40: 
 89                  got_revision = "[revision string too long]" 
 90              data += "  <li>Got Revision: %s</li>\n" % got_revision 
 91          data += " </ul>\n" 
 92   
 93           
 94           
 95          try: 
 96              slaveurl = path_to_slave(req, status.getSlave(b.getSlavename())) 
 97              data += "<h2>Buildslave:</h2>\n <a href=\"%s\">%s</a>\n" % (html.escape(slaveurl), html.escape(b.getSlavename())) 
 98          except KeyError: 
 99              data += "<h2>Buildslave:</h2>\n %s\n" % html.escape(b.getSlavename()) 
100          data += "<h2>Reason:</h2>\n%s\n" % html.escape(b.getReason()) 
101   
102          data += "<h2>Steps and Logfiles:</h2>\n" 
103           
104   
105   
106   
107   
108   
109          data += "<ol>\n" 
110          for s in b.getSteps(): 
111              name = s.getName() 
112              time_to_run = 0 
113              (start, end) = s.getTimes() 
114              if start and end: 
115                time_to_run = end - start 
116              if s.isFinished(): 
117                  css_class = css_classes[s.getResults()[0]] 
118              elif s.isStarted(): 
119                  css_class = "running" 
120              else: 
121                  css_class = "" 
122              data += (' <li><span class="%s"><a href=\"%s\">%s</a> [%s] [%d seconds]</span>\n' 
123                       % (css_class,  
124                          req.childLink("steps/%s" % urllib.quote(name)), 
125                          name, 
126                          " ".join(s.getText()), 
127                          time_to_run)) 
128              data += "  <ol>\n" 
129              if s.getLogs(): 
130                  for logfile in s.getLogs(): 
131                      logname = logfile.getName() 
132                      logurl = req.childLink("steps/%s/logs/%s" % 
133                                             (urllib.quote(name), 
134                                              urllib.quote(logname))) 
135                      data += ("   <li><a href=\"%s\">%s</a></li>\n" % 
136                               (logurl, logfile.getName())) 
137              if s.getURLs(): 
138                  for url in s.getURLs().items(): 
139                      logname = url[0] 
140                      logurl = url[1] 
141                      data += ('   <li><a href="%s">%s</a></li>\n' % 
142                               (logurl, html.escape(logname))) 
143              data += "</ol>\n" 
144              data += " </li>\n" 
145   
146          data += "</ol>\n" 
147   
148          data += "<h2>Build Properties:</h2>\n" 
149          data += "<table><tr><th valign=\"left\">Name</th><th valign=\"left\">Value</th><th valign=\"left\">Source</th></tr>\n" 
150          for name, value, source in b.getProperties().asList(): 
151              value = str(value) 
152              if len(value) > 500: 
153                  value = value[:500] + " .. [property value too long]" 
154              data += "<tr>" 
155              data += "<td>%s</td>" % html.escape(name) 
156              data += "<td>%s</td>" % html.escape(value) 
157              data += "<td>%s</td>" % html.escape(source) 
158              data += "</tr>\n" 
159          data += "</table>" 
160   
161          data += "<h2>Blamelist:</h2>\n" 
162          if list(b.getResponsibleUsers()): 
163              data += " <ol>\n" 
164              for who in b.getResponsibleUsers(): 
165                  data += "  <li>%s</li>\n" % html.escape(who) 
166              data += " </ol>\n" 
167          else: 
168              data += "<div>no responsible users</div>\n" 
169   
170   
171          (start, end) = b.getTimes() 
172          data += "<h2>Timing</h2>\n" 
173          data += "<table>\n" 
174          data += "<tr><td>Start</td><td>%s</td></tr>\n" % time.ctime(start) 
175          if end: 
176              data += "<tr><td>End</td><td>%s</td></tr>\n" % time.ctime(end) 
177              data += "<tr><td>Elapsed</td><td>%s</td></tr>\n" % util.formatInterval(end - start) 
178          else: 
179              now = util.now() 
180              data += "<tr><td>Elapsed</td><td>%s</td></tr>\n" % util.formatInterval(now - start) 
181          data += "</table>\n" 
182   
183          if ss.changes: 
184              data += "<h2>All Changes</h2>\n" 
185              data += "<ol>\n" 
186              for c in ss.changes: 
187                  data += "<li>" + c.asHTML() + "</li>\n" 
188              data += "</ol>\n" 
189               
190   
191          if b.isFinished() and self.builder_control is not None: 
192              data += "<h3>Resubmit Build:</h3>\n" 
193               
194              exactly = (ss.revision is not None) or b.getChanges() 
195              if exactly: 
196                  data += ("<p>This tree was built from a specific set of \n" 
197                           "source files, and can be rebuilt exactly</p>\n") 
198              else: 
199                  data += ("<p>This tree was built from the most recent " 
200                           "revision") 
201                  if ss.branch: 
202                      data += " (along some branch)" 
203                  data += (" and thus it might not be possible to rebuild it \n" 
204                           "exactly. Any changes that have been committed \n" 
205                           "after this build was started <b>will</b> be \n" 
206                           "included in a rebuild.</p>\n") 
207              rebuildURL = urllib.quote(req.childLink("rebuild")) 
208              data += ('<form method="post" action="%s" class="command rebuild">\n' 
209                       % rebuildURL) 
210              data += make_name_user_passwd_form(self.isUsingUserPasswd(req)) 
211              data += make_extra_property_row(1) 
212              data += make_extra_property_row(2) 
213              data += make_extra_property_row(3) 
214              data += make_row("Reason for re-running build:", 
215                               "<input type='text' name='comments' />") 
216              data += '<input type="submit" value="Rebuild" />\n' 
217              data += '</form>\n' 
218   
219          data += self.footer(status, req) 
220   
221          return data 
 222   
223 -    def stop(self, req): 
 224          if self.isUsingUserPasswd(req): 
225              if not self.authUser(req): 
226                  return Redirect("../../../authfailed") 
227          b = self.build_status 
228          c = self.build_control 
229          log.msg("web stopBuild of build %s:%s" % \ 
230                  (b.getBuilder().getName(), b.getNumber())) 
231          name = req.args.get("username", ["<unknown>"])[0] 
232          comments = req.args.get("comments", ["<no reason specified>"])[0] 
233           
234          reason = ("The web-page 'stop build' button was pressed by " 
235                    "'%s': %s\n" % (html.escape(name), html.escape(comments))) 
236          if c: 
237              c.stopBuild(reason) 
238           
239           
240          r = Redirect("../..") 
241          d = defer.Deferred() 
242          reactor.callLater(1, d.callback, r) 
243          return DeferredResource(d) 
 244   
246          if self.isUsingUserPasswd(req): 
247              if not self.authUser(req): 
248                  return Redirect("../../../authfailed") 
249          b = self.build_status 
250          bc = self.builder_control 
251          builder_name = b.getBuilder().getName() 
252          log.msg("web rebuild of build %s:%s" % (builder_name, b.getNumber())) 
253          name = req.args.get("username", ["<unknown>"])[0] 
254          comments = req.args.get("comments", ["<no reason specified>"])[0] 
255          reason = ("The web-page 'rebuild' button was pressed by " 
256                    "'%s': %s\n" % (html.escape(name), html.escape(comments))) 
257          extraProperties = getAndCheckProperties(req) 
258          if not bc or not b.isFinished() or extraProperties is None: 
259              log.msg("could not rebuild: bc=%s, isFinished=%s" 
260                      % (bc, b.isFinished())) 
261               
262          else: 
263              bc.resubmitBuild(b, reason, extraProperties) 
264           
265           
266           
267           
268           
269           
270           
271           
272           
273           
274          r = Redirect("../..")  
275          d = defer.Deferred() 
276          reactor.callLater(1, d.callback, r) 
277          return DeferredResource(d) 
 278   
 290   
291   
293      addSlash = True 
294   
295 -    def __init__(self, builder_status, builder_control): 
 296          HtmlResource.__init__(self) 
297          self.builder_status = builder_status 
298          self.builder_control = builder_control 
 299   
 316