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

Side by Side Diff: master/public_html/skia_tools.js

Issue 648353002: Remove Skia's forked buildbot code (Closed) Base URL: https://skia.googlesource.com/buildbot.git@master
Patch Set: Address comment Created 6 years, 2 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
« no previous file with comments | « master/public_html/robots.txt ('k') | master/skia_master_scripts/__init__.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /**
2 * @license Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 /**
9 * @fileoverview Tools used by the Skia buildbot dashboards, including
10 * facilities for retrieving data from the buildbot master.
11 */
12
13 "use strict";
14
15 var skiaTools = {
16
17 globalVariables: null,
18 googlesourceURL: "https://skia.googlesource.com",
19
20 masterHostSuffix: "_master_host",
21 masterPortSuffix: "_external_port",
22
23
24 /**
25 * Retrieve the Git log for the Skia repository.
26 *
27 * @param {string} startHash
28 * @param {string} endHash
29 * @param {function(Array.<Object>)} callback Call this function with the
30 * decoded JSON from the Git log when the data has loaded.
31 */
32 gitLog: function(startHash, endHash, callback) {
33 var url = this.googlesourceURL + "/skia/+log/" + startHash + ".." + endHash +
34 "?format=JSON";
35 try {
36 var request = new XMLHttpRequest();
37 } catch (error) {
38 alert(error);
39 }
40 request.open("GET", url, true);
41 request.onreadystatechange = function() {
42 if (request.readyState != 4) { return; }
43 // Remove the first line, which is garbage.
44 var responseLines = request.responseText.split('\n');
45 responseLines.splice(0, 1);
46
47 callback(JSON.parse(responseLines.join('\n'))["log"]);
48 };
49 request.send();
50 },
51
52 /**
53 * Object used for managing Git history.
54 */
55 GitHistory: function() {
56 this.gotRev = {};
57 this.allRevisions = [];
58 this.lastFetchedRev = "HEAD";
59
60 /**
61 * loadCommits
62 *
63 * @param {string} oldestCommit Load this commit and all newer commits.
64 * @param {function} callback Call this function when finished.
65 */
66 this.loadCommits = function(oldestCommit, callback) {
67 var thisInstance = this;
68 skiaTools.gitLog(oldestCommit + "~1", this.lastFetchedRev, function(newCommi ts) {
69 for (var i = 0; i < newCommits.length; ++i) {
70 var commitHash = newCommits[i].commit;
71 thisInstance.allRevisions.push(commitHash);
72 thisInstance.gotRev[commitHash] = true;
73 }
74 thisInstance.lastFetchedRev = newCommits[newCommits.length - 1].commit;
75 callback();
76 });
77 }
78
79 /**
80 * getRevList
81 *
82 * @return {Array.<string>} Array of commit hashes in chronological order.
83 */
84 this.getRevList = function() {
85 var revList = Array.prototype.slice.call(this.allRevisions);
86 revList.reverse(); // Sort newest to oldest.
87 return revList;
88 }
89
90 /**
91 * ensureLoaded
92 *
93 * @param {Array.<string>} commitList Load commits from history until all
94 * commits in commitList have been loaded. This will be significantly
95 * faster if the list is in chronological order.
96 * @param {function} callback Call this function when finished.
97 */
98 this.ensureLoaded = function(commitList, callback) {
99 var thisInstance = this;
100 var areAllLoaded = function() {
101 for (var i = 0; i < commitList.length; i++) {
102 var commit = commitList[i];
103 if (!thisInstance.gotRev[commit]) {
104 thisInstance.loadCommits(commit, areAllLoaded);
105 return;
106 }
107 }
108 callback();
109 };
110 areAllLoaded();
111 }
112 },
113
114 /**
115 * Convenience function for populating a ComboBox or ListBox with a list of
116 * items. Existing items will be cleared.
117 *
118 * @param {string} menuId ID of the menu to populate.
119 * @param {Array.<string>} items A list of strings to insert into the menu.
120 */
121 populateMenu: function(menuId, items) {
122 var menu = document.getElementById(menuId);
123 menu.options.length = 0;
124 for (var itemIdx = 0; itemIdx < items.length; itemIdx++) {
125 var item = items[itemIdx];
126 var newOption = document.createElement("option");
127 newOption.text = item;
128 newOption.value = item;
129 menu.options.add(newOption);
130 }
131 },
132
133 /**
134 * Load the global_variables.json file.
135 *
136 * @param {function} callback Call this function when finished.
137 */
138 loadGlobalVariables: function(callback) {
139 var thisInstance = this;
140 var url = this.googlesourceURL + "/buildbot/+/master/site_config/" +
141 "global_variables.json?format=TEXT";
142 try {
143 var request = new XMLHttpRequest();
144 } catch (error) {
145 alert(error);
146 }
147 request.open("GET", url, true);
148 request.onreadystatechange = function() {
149 if (request.readyState != 4) { return; }
150 thisInstance.globalVariables = JSON.parse(atob(request.responseText));
151 callback();
152 }
153 request.send();
154 },
155
156 /**
157 * Retrieve the given variable.
158 *
159 * @param {function(string)} callback Call this function with the value of the
160 * requested variable, as defined in the global variables file, or
161 * undefined if it is not found.
162 */
163 getVariable: function(varName, callback) {
164 var thisInstance = this;
165 var readGlobalVariable = function() {
166 if (!thisInstance.globalVariables[varName]) {
167 callback(undefined);
168 }
169 callback(thisInstance.globalVariables[varName].value);
170 };
171 if (!this.globalVariables) {
172 this.loadGlobalVariables(readGlobalVariable);
173 } else {
174 readGlobalVariable();
175 }
176 },
177
178 /**
179 * Information about a single build.
180 */
181 Build: function(builder, number, revision, result, startTime, endTime, steps) {
182 this.builder = builder;
183 this.number = number;
184 this.revision = revision;
185 this.result = result;
186 this.startTime = startTime;
187 this.endTime = endTime;
188 this.elapsedTime = endTime - startTime;
189 this.steps = steps;
190
191 /**
192 * getBuilder
193 *
194 * @return {string} The name of the builder who owns this build.
195 */
196 this.getBuilder = function() { return this.builder; }
197
198 /**
199 * getNumber
200 *
201 * @return {number} The build number.
202 */
203 this.getNumber = function() { return this.number; }
204
205 /**
206 * getResult
207 *
208 * @return {number} The result of the build. Will be 0 iff the build
209 * succeeded.
210 */
211 this.getResult = function() { return this.result; }
212
213 /**
214 * getRevision
215 *
216 * @return {number} The revision number of this build.
217 */
218 this.getRevision = function() { return this.revision; }
219
220 /**
221 * getStartTime
222 *
223 * @return {number} Start time of the build in UNIX seconds from epoch.
224 */
225 this.getStartTime = function() { return this.startTime; }
226
227 /**
228 * getEndTime
229 *
230 * @return {number} End time of the build in UNIX seconds from epoch.
231 */
232 this.getEndTime = function() { return this.endTime; }
233
234 /**
235 * getElapsedTime
236 *
237 * @return {number} Elapsed time of the build in seconds.
238 */
239 this.getElapsedTime = function() { return this.elapsedTime; }
240
241 /**
242 * getStartTime
243 *
244 * @return {Array.<BuildStep>} Information about the steps of this build.
245 */
246 this.getSteps = function() { return this.steps; }
247 },
248
249 /**
250 * Information about a single build step.
251 */
252 BuildStep: function(name, elapsedTime, result, stdio) {
253 this.name = name;
254 this.elapsedTime = elapsedTime;
255 this.result = result;
256 this.stdio = stdio;
257
258 /**
259 * getName
260 *
261 * @return {string} The name of the build step.
262 */
263 this.getName = function() { return this.name; }
264
265 /**
266 * getElapsedTime
267 *
268 * @return {number} Elapsed time of the build step in seconds.
269 */
270 this.getElapsedTime = function() { return this.elapsedTime; }
271
272 /**
273 * getResult
274 *
275 * @return {number} The result of the build. Will be 0 iff the build step
276 * succeeded.
277 */
278 this.getResult = function() { return this.result; }
279
280 /**
281 * getStdio
282 *
283 * @return {string} URL to the log output for this build step.
284 */
285 this.getStdio = function() { return this.stdio; }
286 },
287
288 /**
289 * Information about a builder.
290 */
291 Builder: function(name, master, basedir, cachedBuilds, category, currentBuilds,
292 slaves, state) {
293 this.name = name;
294 this.master = master;
295 this.basedir = basedir;
296 // alreadyLoadedBuilds differs from the passed-in cachedBuilds; the passed-in
297 // parameter refers to the builds which the build master has cached. This
298 // property is a set of builds which have been loaded from the build master
299 // and stored here for future use.
300 this.alreadyLoadedBuilds = {};
301 this.category = category;
302 this.currentBuilds = currentBuilds;
303 this.lastBuild = cachedBuilds[cachedBuilds.length - 1];
304 this.slaves = slaves;
305 this.state = state;
306
307 /**
308 * getName
309 *
310 * @return {string} The name of the builder.
311 */
312 this.getName = function() { return this.name; }
313
314 /**
315 * getBaseDir
316 *
317 * @return {string} Directory on the build slave machine in which build
318 * information is stored. This is typically the same as the builder name.
319 */
320 this.getBaseDir = function() { return this.basedir; }
321
322 /**
323 * getCategory
324 *
325 * @return {string} Category of this builder. This is the heading under
326 * which the builder is placed on the buildbot web page.
327 */
328 this.getCategory = function() { return this.category; }
329
330 /**
331 * getCurrentBuilds
332 *
333 * @return {Array.<number>} List of currently-running builds for this
334 * builder.
335 */
336 this.getCurrentBuilds = function() { return this.currentBuilds; }
337
338 /**
339 * getLastBuild
340 *
341 * @return {number} The build number of the last completed build for this
342 * builder.
343 */
344 this.getLastBuild = function() { return this.lastBuild; }
345
346 /**
347 * getSlaves
348 *
349 * @return {Array.<string>} List of known build slaves which are capable of
350 * running builds for this builder.
351 */
352 this.getSlaves = function() { return this.slaves; }
353
354 /**
355 * getState
356 *
357 * @return {string} Current status of the builder. Either "building" or
358 * "idle."
359 */
360 this.getState = function() { return this.state; }
361
362 /**
363 * Obtain information about a single build from the buildbot master.
364 *
365 * @param {number} build The number of the build which should be retrieved.
366 * @param {boolean} loadUnfinished Whether or not to load data for unfinished
367 * builds.
368 * @param {boolean} loadUnknownRevs Whether or not to load data for builds
369 * which do not have an associated revision number. This occurs when the
370 * source checkout step fails.
371 * @param {function(string, number, Build|null)} callback Call this function
372 * with a builder name, build number, and a Build instance containing
373 * information about the requested build when loaded.
374 */
375 this.loadDataForBuild = function(build, loadUnfinished, loadUnknownRevs,
376 callback) {
377 var thisInstance = this;
378 var buildURL = "builders/" + this.getName() + "/builds/" + build + "/steps";
379 this.master.loadData(buildURL, function(buildData) {
380 // Build step results.
381 var SUCCESS = 0;
382 var FAILURE = 2;
383 var SKIPPED = 3;
384
385 var steps = [];
386 var result = 0;
387 var startTime = 0;
388 var endTime = 0;
389 var revision = undefined;
390 var gotRevisionStr = "got_revision: ";
391 for (var step in buildData) {
392 var stepData = buildData[step];
393 if (stepData["isStarted"] && !stepData["isFinished"] &&
394 !loadUnfinished) {
395 // If the build isn't finished, ignore it
396 callback(thisInstance.getName(), build, null);
397 }
398 if (!stepData["isStarted"]) {
399 continue;
400 }
401 if (stepData["name"] == "Update") {
402 // The buildbot's JSON interface stores results as an array in which
403 // the first element is an integer indicating success or failure.
404 if (stepData["isStarted"] && stepData["isFinished"] &&
405 stepData["results"][0] == 0) {
406 // The "text" field is an array containing extra information about
407 // the build step. In the case of the Update step, its second
408 // element is a string indicating the revision obtained for the
409 // current build.
410 revision = stepData["text"][1].substring(gotRevisionStr.length);
411 } else if (!loadUnknownRevs) {
412 // If the Update step failed, we can't attach a revision, so we have
413 // to ignore this build.
414 console.log("Warning: Can't get a revision for build #" + build +
415 ". Skipping.");
416 callback(thisInstance.getName(), build, null);
417 }
418 }
419 var times = stepData["times"];
420 var stepTime = times[1] - times[0];
421 if (startTime == 0) {
422 startTime = times[0];
423 }
424 endTime = times[1];
425 var stdout = null;
426 try {
427 stdout = stepData["logs"][0][1];
428 } catch(e) {
429 stdout = "None";
430 }
431
432 var buildStep = new skiaTools.BuildStep(stepData["name"], stepTime,
433 stepData["results"][0], stdout);
434 steps.push(buildStep);
435
436 if (buildStep.getResult() != SUCCESS &&
437 buildStep.getResult() != SKIPPED) {
438 result = FAILURE;
439 }
440 }
441 if (revision == undefined) {
442 console.log("Warning: could not find a revision for build #" + build);
443 }
444
445 callback(thisInstance.getName(), build, new skiaTools.Build(
446 thisInstance.getName(), build, revision, result, startTime, endTime,
447 steps));
448 });
449 }
450
451 /**
452 * Obtain information about the builds for a single builder. Works backward
453 * from the last known build, loading builds until the requested number of
454 * builds has been fulfilled or all of the builder's builds have been loaded.
455 *
456 * @param {number} numBuilds The number of builds to load.
457 * @param {function(string, Object)} callback Call this function with the
458 * builder name and a dictionary of instances of Build for the builder,
459 * indexed by revision.
460 */
461 this.loadBuilds = function(numBuilds, callback) {
462 var lastBuild = this.getLastBuild();
463 var loading = [];
464 var thisInstance = this;
465 var doneLoading = function() {
466 var data = {};
467 for (var buildNum = lastBuild; buildNum >= lastBuild - numBuilds && buildN um >= 0; buildNum--) {
468 var build = thisInstance.alreadyLoadedBuilds[buildNum];
469 if (build) {
470 data[buildNum] = build;
471 }
472 }
473 callback(thisInstance.getName(), data);
474 };
475 for (var buildNum = lastBuild; buildNum >= lastBuild - numBuilds && buildNum >= 0; buildNum--) {
476 var build = this.alreadyLoadedBuilds[buildNum];
477 if (!build) {
478 loading.push(buildNum);
479 this.loadDataForBuild(buildNum, false, false, function(builder, buildNum , build) {
480 loading.splice(loading.indexOf(buildNum), 1);
481 thisInstance.alreadyLoadedBuilds[buildNum] = build;
482 if (loading.length == 0) {
483 doneLoading();
484 }
485 });
486 } else {
487 data[buildNum] = build;
488 if (loading.length == 0) {
489 doneLoading();
490 }
491 }
492 }
493 }
494 },
495
496 /**
497 * Information about a build slave.
498 */
499 BuildSlave: function(admin, builders, connected, currentBuilds, host, name,
500 master, version) {
501 this.admin = admin;
502 this.builders = builders;
503 this.connected = connected;
504 this.currentBuilds = currentBuilds;
505 this.host = host;
506 this.name = name;
507 this.master = master;
508 this.version = version;
509
510 /**
511 * getAdmin
512 *
513 * @return {string} Usernames of buildbot maintainers.
514 */
515 this.getAdmin = function() { return this.admin; }
516
517 /**
518 * getBuilders
519 *
520 * @return {Object} Dictionary whose keys are builder names and values are
521 * lists of build numbers indicating which builds for which builders this
522 * slave has performed.
523 */
524 this.getBuilders = function() { return this.builders; }
525
526 /**
527 * isConnected
528 *
529 * @return {boolean} Whether or not the build slave is currently connected
530 * to the build master.
531 */
532 this.isConnected = function() { return this.connected; }
533
534 /**
535 * getCurrentBuilds
536 *
537 * @return {Array.<Object>} List of dictionaries containing information about
538 * currently-running builds on this slave.
539 */
540 this.getCurrentBuilds = function() { return this.currentBuilds; }
541
542 /**
543 * getHost
544 *
545 * @return {string} Hostname of this build slave.
546 */
547 this.getHost = function() { return this.host; }
548
549 /**
550 * getName
551 *
552 * @return {string} The name of this build slave.
553 */
554 this.getName = function() { return this.name; }
555
556 /**
557 * getVersion
558 *
559 * @return {string} Version of BuildBot which this build slave is running.
560 */
561 this.getVersion = function() { return this.version; }
562
563 /**
564 * Obtain information about recent builds for a build slave.
565 *
566 * @param {number} rangeMin Builds before this time will not be loaded.
567 * @param {number} currentTime The time at which {@code slaveDict} was
568 * obtained from the build master. This value is passed in rather than
569 * obtaining the current time at the call of this function in case the
570 * state of the build slave has changed since {@code slaveDict} was
571 * obtained.
572 * @param {function(Array.<Build>)} callback Call this function with a list
573 * of Build objects when loaded.
574 */
575 this.loadBuilds = function(rangeMin, currentTime, callback) {
576 var builders = this.getBuilders();
577 var buildList = [];
578 var thisInstance = this;
579 var getRunningBuilds = function() {
580 var runningBuilds = thisInstance.getCurrentBuilds();
581 for (var buildIdx = 0; buildIdx < runningBuilds.length; buildIdx++) {
582 var buildData = runningBuilds[buildIdx];
583 buildList.push(new thisInstance.Build(buildData["builderName"],
584 buildData["number"],
585 -1, 0, buildData["times"][0],
586 currentTime + 1, []));
587 }
588 buildList.sort(function(a, b) {
589 return a.getStartTime() - b.getStartTime();
590 });
591 callback(buildList);
592 };
593
594 var loadingBuilders = {};
595
596 var gotBuild = function(builder, buildNum, build) {
597 buildList.push(build);
598 if (build != null &&
599 (build.getEndTime() < rangeMin ||
600 build.getStartTime() < rangeMin ||
601 build.getNumber() == 0)) {
602 delete loadingBuilders[builder];
603 if (Object.keys(loadingBuilders).length == 0) {
604 getRunningBuilds();
605 }
606 } else {
607 var builderObj = loadingBuilders[builder];
608 builderObj.loadDataForBuild(buildNum - 1, true, true, gotBuild);
609 }
610 }
611
612 for (var builder in builders) {
613 var builderObj = new skiaTools.Builder(builder,
614 this.master,
615 null,
616 [-1],
617 null,
618 null,
619 null,
620 null);
621 var builds = builders[builder];
622 if (builds.length > 0) {
623 loadingBuilders[builder] = builderObj;
624 builderObj.loadDataForBuild(builds[0], true, true, gotBuild);
625 }
626 }
627 }
628 },
629
630 loadMasterList: function(callback) {
631 var masters = [];
632 var thisInstance = this;
633 var gotVariables = function() {
634 for (var key in thisInstance.globalVariables) {
635 var suffixIndex = key.indexOf(
636 skiaTools.masterHostSuffix,
637 key.length - skiaTools.masterHostSuffix.length);
638 if (suffixIndex !== -1) {
639 masters.push(key.substring(0, suffixIndex));
640 }
641 }
642 callback(masters);
643 }
644 if (!thisInstance.globalVariables) {
645 this.loadGlobalVariables(gotVariables);
646 } else {
647 gotVariables();
648 }
649 },
650
651 Master: function(name) {
652 this.name = name;
653
654 var thisInstance = this;
655 skiaTools.getVariable(name + skiaTools.masterHostSuffix, function(host) {
656 thisInstance.host = host;
657 });
658 skiaTools.getVariable(name + skiaTools.masterPortSuffix, function(port) {
659 thisInstance.port = port;
660 });
661
662 /**
663 * getName
664 *
665 * @return {string} Name of this build master.
666 */
667 this.getName = function() { return this.name; }
668
669 /**
670 * getHost
671 *
672 * @return {string} Hostname of this build master.
673 */
674 this.getHost = function() { return this.host; }
675
676 /**
677 * getPort
678 *
679 * @return {string} Port number of this build master.
680 */
681 this.getPort = function() { return this.port; }
682
683 /**
684 * loadData
685 *
686 * Sends an {@code XMLHttpRequest} to the buildbot master, parses the JSON in
687 * the response, and returns a dictionary.
688 *
689 * @param {string} subdir Subdirectory of the buildbot master's JSON
690 * interface to query.
691 * @param {function(Object)} callback Call this function with the decoded
692 * JSON data when loaded.
693 */
694 this.loadData = function(subdir, callback) {
695 try {
696 var request = new XMLHttpRequest();
697 } catch (error) {
698 alert(error);
699 }
700 var url = "http://" + this.getHost() + ":" + this.getPort() + "/json/" +
701 subdir;
702 request.open("GET", url, true);
703 request.onreadystatechange = function() {
704 if (request.readyState != 4) { return; }
705 callback(JSON.parse(request.responseText));
706 }
707 request.send(null);
708 }
709
710 /**
711 * Obtain high-level information about known builders.
712 *
713 * @param {Array.<Builder>} callback Call this function with a list of
714 * Builder objects when loaded.
715 */
716 this.loadBuilders = function(callback) {
717 var thisInstance = this;
718 this.loadData("builders", function(buildersData) {
719 var builders = [];
720 for (var builderName in buildersData) {
721 var builderData = buildersData[builderName];
722 var builder = new skiaTools.Builder(builderName,
723 thisInstance,
724 builderData["basedir"],
725 builderData["cachedBuilds"],
726 builderData["category"],
727 builderData["currentBuilds"],
728 builderData["slaves"],
729 builderData["state"]);
730 builders.push(builder);
731 }
732 callback(builders);
733 });
734 }
735
736 /**
737 * Obtain high-level information about known build slaves.
738 *
739 * @param {function(Array.<BuildSlave>)} callback Call this function with a
740 * list of BuildSlave objects when loaded.
741 */
742 this.loadSlaves = function(callback) {
743 var slaves = [];
744 var thisInstance = this;
745 this.loadData("slaves", function(slavesData) {
746 for (var slave in slavesData) {
747 var slaveData = slavesData[slave];
748 var currentBuilds = slaveData["currentBuilds"];
749 if (currentBuilds == undefined) {
750 currentBuilds = [];
751 }
752 slaves.push(new skiaTools.BuildSlave(slaveData["admin"],
753 slaveData["builders"],
754 slaveData["connected"],
755 currentBuilds,
756 slaveData["host"],
757 slaveData["name"],
758 thisInstance,
759 slaveData["version"]));
760 }
761 callback(slaves);
762 });
763 }
764
765 },
766
767 };
OLDNEW
« no previous file with comments | « master/public_html/robots.txt ('k') | master/skia_master_scripts/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698