Add bonsai query support; add bonsaibouncer helper script; add marker support to graphs; disable test select dropdown while the data is loading after a tinderbox switch

This commit is contained in:
vladimir%pobox.com 2006-06-20 19:41:05 +00:00
parent e325e8c6f1
commit 673cb0b446
4 changed files with 229 additions and 7 deletions

View File

@ -0,0 +1,59 @@
#!/usr/bin/python
#
# bonsaibouncer
#
# Bounce a request to bonsai.mozilla.org, getting around silly
# cross-domain XMLHTTPRequest deficiencies.
#
import cgitb; cgitb.enable()
import os
import sys
import cgi
import gzip
import urllib
from urllib import quote
import cStringIO
bonsai = "http://bonsai.mozilla.org/cvsquery.cgi";
def main():
#doGzip = 0
#try:
# if string.find(os.environ["HTTP_ACCEPT_ENCODING"], "gzip") != -1:
# doGzip = 1
#except:
# pass
form = cgi.FieldStorage()
treeid = form.getfirst("treeid")
module = form.getfirst("module")
branch = form.getfirst("branch")
mindate = form.getfirst("mindate")
maxdate = form.getfirst("maxdate")
xml_nofiles = form.getfirst("xml_nofiles")
if not treeid or not module or not branch or not mindate or not maxdate:
print "Content-type: text/plain\n\n"
print "ERROR"
return
url = bonsai + "?" + "branchtype=match&sortby=Date&date=explicit&cvsroot=%2Fcvsroot&xml=1"
url += "&treeid=%s&module=%s&branch=%s&mindate=%s&maxdate=%s" % (quote(treeid), quote(module), quote(branch), quote(mindate), quote(maxdate))
if (xml_nofiles):
url += "&xml_nofiles=1"
urlstream = urllib.urlopen(url)
sys.stdout.write("Content-type: text/xml\n\n")
for s in urlstream:
sys.stdout.write(s)
urlstream.close()
main()

View File

@ -94,6 +94,8 @@ def doSendResults(fo, tbox, test, starttime, endtime, raw):
cur = db.cursor()
cur.execute(stmt)
for row in cur:
if row[1] == 'nan':
continue
if raw:
fo.write ("%s,%s,'%s'," % (row[0], row[1], row[2]))
else:

View File

@ -16,7 +16,7 @@
<script type="text/javascript" src="js/yui/container.js"></script>
<!-- Core -->
<script type="text/javascript" src="js/graph.js"></script>
<script type="text/javascript; e4x=1" src="js/graph.js"></script>
</head>
<body onload="loadingDone()">
@ -32,6 +32,11 @@
<input id="load-days-radio" type="radio" name="dataload" onclick="onDataLoadChanged()" checked>
<label>previous</label> <input type="text" value="120" id="load-days-entry" size="3" onchange="onDataLoadChanged()"> <label>days</label>
</td>
<td width="200px">
</td>
<td>
<input id="bonsaibutton" type="button" onclick="onUpdateBonsai()" value="Refresh Bonsai Data">
</td>
</tr>
</table>
@ -43,7 +48,7 @@
</div>
<div id="formend">
<img src="js/plus.png" class="plusminus" onclick="addGraphForm()">
<img src="js/img/plus.png" class="plusminus" onclick="addGraphForm()">
<input type="submit" onclick="onGraph()" value="Graph It!">
<!-- <label for="baseline">No baseline</label><input type="radio" name="baseline" checked onclick="onNoBaseLineClick()"> -->

View File

@ -48,8 +48,15 @@ const MONTH_ABBREV = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "
//const getdatacgi = "http://localhost:9050/getdata.cgi?";
const getdatacgi = "getdata.cgi?";
const bonsaicgi = "bonsaibouncer.cgi";
// more days than this and we'll force user confirmation for the bonsai query
const bonsaiNoForceDays = 90;
// the default average interval
var gAverageInterval = 6*ONE_HOUR_SECONDS;
var gCurrentLoadRange = null;
var gForceBonsai = false;
function checkErrorReturn(obj) {
if (!obj || obj.resultcode != 0) {
@ -147,6 +154,8 @@ TinderboxData.prototype = {
}
},
// arg1 = startTime, arg2 = endTime, arg3 = callback
// arg1 = callback, arg2/arg3 == null
requestValueDataSetFor: function (tbox, testname, arg1, arg2, arg3) {
var self = this;
@ -227,7 +236,7 @@ TinderboxData.prototype = {
self.onDataSetAvailable.fire(tbox, testname, ds, startTime, endTime);
},
function () {alert ("Error talking to getdata.cgi"); });
function (obj) {alert ("Error talking to getdata.cgi (" + obj + ")"); log (obj.stack); });
},
clearValueDataSets: function () {
@ -471,6 +480,80 @@ TimeStringDataSet.prototype = {
},
};
function BonsaiService() {
}
BonsaiService.prototype = {
// this could cache stuff, so that we only have to request the bookend data
// if we want a wider range, but it's probably not worth it for now.
//
// The callback is called with an object argument which contains:
// {
// times: [ t1, t2, t3, .. ],
// who: [ w1, w2, w3, .. ],
// log: [ l1, l2, l3, .. ],
// files: [ [ r11, f11, r12, f12, r13, f13, .. ], [ r21, f21, r22, f22, r23, f23, .. ], .. ]
// }
//
// r = revision number, as a string, e.g. "1.15"
// f = file, e.g. "mozilla/widget/foo.cpp"
//
// arg1 = callback, arg2 = null
// arg1 = includeFiles, arg2 = callback
requestCheckinsBetween: function (startDate, endDate, arg1, arg2) {
var includeFiles = arg1;
var callback = arg2;
if (arg2 == null) {
callback = arg1;
includeFiles = null;
}
var queryargs = {
treeid: "default",
module: "SeaMonkeyAll",
branch: "HEAD",
mindate: startDate,
maxdate: endDate
};
if (!includeFiles)
queryargs.xml_nofiles = "1";
log ("bonsai request: ", queryString(queryargs));
doSimpleXMLHttpRequest (bonsaicgi, queryargs)
.addCallbacks(
function (obj) {
var result = { times: [], who: [], comment: [], files: null };
if (includeFiles)
result.files = [];
// strip out the xml declaration
var s = obj.responseText.replace(/<\?xml version="1.0"\?>/, "");
var bq = new XML(s);
for (var i = 0; i < bq.ci.length(); i++) {
var ci = bq.ci[i];
result.times.push(ci.@date);
result.who.push(ci.@who);
result.comment.push(ci.log.text().toString());
if (includeFiles) {
var files = [];
for (var j = 0; j < ci.files.f.length(); j++) {
var f = ci.files.f[j];
files.push(f.@rev);
files.push(f.text().toString());
}
result.files.push(files);
}
}
callback.call (window, result);
},
function () { alert ("Error talking to bonsai"); });
},
};
function Graph() {
}
@ -518,6 +601,10 @@ Graph.prototype = {
cursorTime: null,
cursorValue: null,
markerColor: "rgba(200,0,0,0.4)",
markersVisible: true,
markers: null,
dirty: true,
valid: false,
@ -538,6 +625,8 @@ Graph.prototype = {
this.dataSetMinMaxes = new Array();
this.dataSetIndices = new Array();
this.markers = new Array();
this.onSelectionChanged = new YAHOO.util.CustomEvent("graphselectionchanged");
this.onCursorMoved = new YAHOO.util.CustomEvent("graphcursormoved");
},
@ -804,6 +893,7 @@ Graph.prototype = {
// yScale = pixels-per-value
with (ctx) {
clearRect (0, 0, cw, ch);
lineWidth = 1.0;
// draw gridlines
var yLabelValues = this.getTimeAxisLabels();
@ -827,7 +917,25 @@ Graph.prototype = {
lineTo(this.frontBuffer.width + 0.5, p);
stroke();
}
// draw markers
strokeStyle = this.markerColor;
for (var i = 0; i < this.markers.length/2; i++) {
var mtime = this.markers[i*2];
//var mlabel = this.markers[i*2+1];
if (mtime < this.startTime || mtime > this.endTime)
continue;
var p = Math.round((mtime - xoffs) * xscale) + 0.5;
beginPath();
moveTo(p, Math.round(this.frontBuffer.height*0.8)-0.5);
lineTo(p, this.frontBuffer.height+0.5);
stroke();
}
// draw actual graph lines
for (var i = 0; i < this.dataSets.length; i++) {
if (this.dataSetIndices[i] == null) {
// there isn't anything in the data set in the given time range
@ -875,8 +983,6 @@ Graph.prototype = {
strokeStyle = colorToRgbString(this.dataSets[i].color);
stroke();
lineWidth = 1.0;
}
}
}
@ -1308,6 +1414,19 @@ Graph.prototype = {
this.redrawOverlayOnly();
},
/*
* marker stuff
*/
deleteAllMarkers: function () {
this.markers = new Array();
},
addMarker: function (mtime, mlabel) {
this.markers.push (mtime);
this.markers.push (mlabel);
},
};
function BigGraph(canvasId) {
@ -1461,6 +1580,7 @@ GraphFormModule.prototype = {
this.tinderbox = this.tinderboxSelect.value;
this.testSelect.disabled = true;
Tinderbox.requestTestListFor(this.tinderbox,
function (tbox, tests) {
var opts = [];
@ -1475,6 +1595,8 @@ GraphFormModule.prototype = {
self.testname = forceTestname;
self.testSelect.value = forceTestname;
}
self.testSelect.disabled = false;
});
},
@ -1503,6 +1625,7 @@ GraphFormModule.prototype = {
var Tinderbox;
var BigPerfGraph;
var SmallPerfGraph;
var Bonsai;
function loadingDone() {
//createLoggingPane(true);
@ -1510,6 +1633,8 @@ function loadingDone() {
Tinderbox = new TinderboxData();
Tinderbox.init();
Bonsai = new BonsaiService();
SmallPerfGraph = new SmallGraph("smallgraph");
SmallPerfGraph.setSelectionType("range");
BigPerfGraph = new BigGraph("graph");
@ -1557,12 +1682,39 @@ function onNoBaseLineClick() {
GraphFormModules.forEach (function (g) { g.baseline = false; });
}
// whether the bonsai data query should redraw the graph or not
var gReadyForRedraw = true;
function onUpdateBonsai() {
BigPerfGraph.deleteAllMarkers();
getElement("bonsaibutton").disabled = true;
if (gCurrentLoadRange) {
if ((gCurrentLoadRange[1] - gCurrentLoadRange[0]) < (bonsaiNoForceDays * ONE_DAY_SECONDS) || gForceBonsai) {
Bonsai.requestCheckinsBetween (gCurrentLoadRange[0], gCurrentLoadRange[1],
function (bdata) {
for (var i = 0; i < bdata.times.length; i++) {
BigPerfGraph.addMarker (bdata.times[i], bdata.who[i] + ": " + bdata.comment[i]);
}
if (gReadyForRedraw)
BigPerfGraph.redraw();
getElement("bonsaibutton").disabled = false;
});
}
}
}
function onGraph() {
for each (var g in [BigPerfGraph, SmallPerfGraph]) {
g.clearDataSets();
g.setTimeRange(null, null);
}
gReadyForRedraw = false;
// do the actual graph data request
var baselineModule = null;
GraphFormModules.forEach (function (g) { if (g.baseline) baselineModule = g; });
if (baselineModule) {
@ -1623,7 +1775,9 @@ function onGraphLoadRemainder(baselineDataSet) {
if (g == SmallPerfGraph || autoExpand)
g.expandTimeRange(ds.firstTime, ds.lastTime);
g.autoScale();
g.redraw();
gReadyForRedraw = true;
}
updateLinkToThis();
@ -1651,8 +1805,10 @@ function onDataLoadChanged() {
log ("drange", d1, d2);
Tinderbox.defaultLoadRange = [d1, d2];
gCurrentLoadRange = [d1, d2];
} else {
Tinderbox.defaultLoadRange = null;
gCurrentLoadRange = null;
}
Tinderbox.clearValueDataSets();