Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # This file is part of Buildbot. Buildbot is free software: you can | 1 # This file is part of Buildbot. Buildbot is free software: you can |
| 2 # redistribute it and/or modify it under the terms of the GNU General Public | 2 # redistribute it and/or modify it under the terms of the GNU General Public |
| 3 # License as published by the Free Software Foundation, version 2. | 3 # License as published by the Free Software Foundation, version 2. |
| 4 # | 4 # |
| 5 # This program is distributed in the hope that it will be useful, but WITHOUT | 5 # This program is distributed in the hope that it will be useful, but WITHOUT |
| 6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 7 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | 7 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| 8 # details. | 8 # details. |
| 9 # | 9 # |
| 10 # You should have received a copy of the GNU General Public License along with | 10 # You should have received a copy of the GNU General Public License along with |
| 11 # this program; if not, write to the Free Software Foundation, Inc., 51 | 11 # this program; if not, write to the Free Software Foundation, Inc., 51 |
| 12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 13 # | 13 # |
| 14 # Portions Copyright Buildbot Team Members | 14 # Portions Copyright Buildbot Team Members |
| 15 # Original Copyright (c) 2010 The Chromium Authors. | 15 # Original Copyright (c) 2010 The Chromium Authors. |
| 16 | 16 |
| 17 """Simple JSON exporter.""" | 17 """Simple JSON exporter.""" |
| 18 | 18 |
| 19 import collections | |
| 19 import datetime | 20 import datetime |
| 20 import os | 21 import os |
| 21 import re | 22 import re |
| 22 | 23 |
| 23 from twisted.internet import defer | 24 from twisted.internet import defer |
| 24 from twisted.web import html, resource, server | 25 from twisted.web import html, resource, server |
| 25 | 26 |
| 26 from buildbot.status.web.base import HtmlResource | 27 from buildbot.status.web.base import HtmlResource |
| 27 from buildbot.util import json | 28 from buildbot.util import json |
| 28 | 29 |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 407 BuilderJsonResource(status, | 408 BuilderJsonResource(status, |
| 408 status.getBuilder(builder_name))) | 409 status.getBuilder(builder_name))) |
| 409 | 410 |
| 410 | 411 |
| 411 class BuilderSlavesJsonResources(JsonResource): | 412 class BuilderSlavesJsonResources(JsonResource): |
| 412 help = """Describe the slaves attached to a single builder. | 413 help = """Describe the slaves attached to a single builder. |
| 413 """ | 414 """ |
| 414 pageTitle = 'BuilderSlaves' | 415 pageTitle = 'BuilderSlaves' |
| 415 | 416 |
| 416 def __init__(self, status, builder_status): | 417 def __init__(self, status, builder_status): |
| 418 buildcache = collections.defaultdict(dict) | |
|
M-A Ruel
2013/04/06 01:23:46
Why not create a single global instance? It'd be s
Mike Stip (use stip instead)
2013/04/06 01:30:28
Because this is per-request. It's only a cache whi
| |
| 417 JsonResource.__init__(self, status) | 419 JsonResource.__init__(self, status) |
| 418 self.builder_status = builder_status | 420 self.builder_status = builder_status |
| 419 for slave_name in self.builder_status.slavenames: | 421 for slave_name in self.builder_status.slavenames: |
| 420 self.putChild(slave_name, | 422 self.putChild(slave_name, |
| 421 SlaveJsonResource(status, | 423 SlaveJsonResource(status, |
| 422 self.status.getSlave(slave_name))) | 424 self.status.getSlave(slave_name), |
| 425 buildcache=buildcache)) | |
| 423 | 426 |
| 424 | 427 |
| 425 class BuildJsonResource(JsonResource): | 428 class BuildJsonResource(JsonResource): |
| 426 help = """Describe a single build. | 429 help = """Describe a single build. |
| 427 """ | 430 """ |
| 428 pageTitle = 'Build' | 431 pageTitle = 'Build' |
| 429 | 432 |
| 430 def __init__(self, status, build_status): | 433 def __init__(self, status, build_status): |
| 431 JsonResource.__init__(self, status) | 434 JsonResource.__init__(self, status) |
| 432 self.build_status = build_status | 435 self.build_status = build_status |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 613 | 616 |
| 614 def asDict(self, request): | 617 def asDict(self, request): |
| 615 return self.status.asDict() | 618 return self.status.asDict() |
| 616 | 619 |
| 617 | 620 |
| 618 class SlaveJsonResource(JsonResource): | 621 class SlaveJsonResource(JsonResource): |
| 619 help = """Describe a slave. | 622 help = """Describe a slave. |
| 620 """ | 623 """ |
| 621 pageTitle = 'Slave' | 624 pageTitle = 'Slave' |
| 622 | 625 |
| 623 def __init__(self, status, slave_status): | 626 def __init__(self, status, slave_status, buildcache=None): |
| 624 JsonResource.__init__(self, status) | 627 JsonResource.__init__(self, status) |
| 625 self.slave_status = slave_status | 628 self.slave_status = slave_status |
| 626 self.name = self.slave_status.getName() | 629 self.name = self.slave_status.getName() |
| 627 self.builders = None | 630 self.builders = None |
| 628 | 631 |
| 632 # buildcache is used to cache build information across multiple | |
| 633 # invocations of SlaveJsonResource. It should be set to an empty | |
| 634 # collections.defaultdict(dict). Without it, each invocation will | |
| 635 # do a full build scan. | |
| 636 self.buildcache = buildcache or collections.defaultdict(dict) | |
| 637 | |
| 629 def getBuilders(self): | 638 def getBuilders(self): |
| 630 if self.builders is None: | 639 if self.builders is None: |
| 631 # Figure out all the builders to which it's attached | 640 # Figure out all the builders to which it's attached |
| 632 self.builders = [] | 641 self.builders = [] |
| 633 for builderName in self.status.getBuilderNames(): | 642 for builderName in self.status.getBuilderNames(): |
| 634 if self.name in self.status.getBuilder(builderName).slavenames: | 643 if self.name in self.status.getBuilder(builderName).slavenames: |
| 635 self.builders.append(builderName) | 644 self.builders.append(builderName) |
| 636 return self.builders | 645 return self.builders |
| 637 | 646 |
| 638 def asDict(self, request): | 647 def mapSlavesToBuilds(self): |
|
Isaac (away)
2013/04/05 23:45:01
delete this method and inline to line 662
Mike Stip (use stip instead)
2013/04/06 01:30:28
Done.
| |
| 639 results = self.slave_status.asDict() | |
| 640 # Enhance it by adding more informations. | |
| 641 results['builders'] = {} | |
| 642 for builderName in self.getBuilders(): | 648 for builderName in self.getBuilders(): |
| 643 builds = [] | 649 builds = [] |
| 644 builder_status = self.status.getBuilder(builderName) | 650 builder_status = self.status.getBuilder(builderName) |
| 645 for i in range(1, builder_status.buildCacheSize - 1): | 651 for i in range(1, builder_status.buildCacheSize - 1): |
| 646 build_status = builder_status.getBuild(-i) | 652 build_status = builder_status.getBuild(-i) |
| 647 if not build_status or not build_status.isFinished(): | 653 if not build_status or not build_status.isFinished(): |
| 648 # If not finished, it will appear in runningBuilds. | 654 # If not finished, it will appear in runningBuilds. |
| 649 break | 655 break |
| 650 if build_status.getSlavename() == self.name: | 656 slave = self.buildcache[build_status.getSlavename()] |
| 651 builds.append(build_status.getNumber()) | 657 slave.setdefault(builderName, []).append( |
|
M-A Ruel
2013/04/06 01:23:46
Note that it is effectively a memory leak, not a b
Mike Stip (use stip instead)
2013/04/06 01:30:28
buildcache gets thrown away after every request.
| |
| 652 results['builders'][builderName] = builds | 658 build_status.getNumber()) |
| 659 | |
| 660 def getSlaveBuildMap(self): | |
| 661 if not self.buildcache: | |
| 662 self.mapSlavesToBuilds() | |
| 663 return self.buildcache[self.name] | |
| 664 | |
| 665 def asDict(self, request): | |
| 666 results = self.slave_status.asDict() | |
| 667 # Enhance it by adding more informations. | |
| 668 results['builders'] = self.getSlaveBuildMap() | |
| 653 return results | 669 return results |
| 654 | 670 |
| 655 | 671 |
| 656 class SlavesJsonResource(JsonResource): | 672 class SlavesJsonResource(JsonResource): |
| 657 help = """List the registered slaves. | 673 help = """List the registered slaves. |
| 658 """ | 674 """ |
| 659 pageTitle = 'Slaves' | 675 pageTitle = 'Slaves' |
| 660 | 676 |
| 661 def __init__(self, status): | 677 def __init__(self, status): |
| 678 buildcache = collections.defaultdict(dict) | |
| 662 JsonResource.__init__(self, status) | 679 JsonResource.__init__(self, status) |
| 663 for slave_name in status.getSlaveNames(): | 680 for slave_name in status.getSlaveNames(): |
| 664 self.putChild(slave_name, | 681 self.putChild(slave_name, |
| 665 SlaveJsonResource(status, | 682 SlaveJsonResource(status, |
| 666 status.getSlave(slave_name))) | 683 status.getSlave(slave_name), |
| 684 buildcache=buildcache)) | |
| 667 | 685 |
| 668 | 686 |
| 669 class SourceStampJsonResource(JsonResource): | 687 class SourceStampJsonResource(JsonResource): |
| 670 help = """Describe the sources for a SourceStamp. | 688 help = """Describe the sources for a SourceStamp. |
| 671 """ | 689 """ |
| 672 pageTitle = 'SourceStamp' | 690 pageTitle = 'SourceStamp' |
| 673 | 691 |
| 674 def __init__(self, status, source_stamp): | 692 def __init__(self, status, source_stamp): |
| 675 # buildbot.sourcestamp.SourceStamp | 693 # buildbot.sourcestamp.SourceStamp |
| 676 JsonResource.__init__(self, status) | 694 JsonResource.__init__(self, status) |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 738 if not builder: | 756 if not builder: |
| 739 return | 757 return |
| 740 EXAMPLES = EXAMPLES.replace('<A_BUILDER>', builder.getName()) | 758 EXAMPLES = EXAMPLES.replace('<A_BUILDER>', builder.getName()) |
| 741 build = builder.getBuild(-1) | 759 build = builder.getBuild(-1) |
| 742 if build: | 760 if build: |
| 743 EXAMPLES = EXAMPLES.replace('<A_BUILD>', str(build.getNumber())) | 761 EXAMPLES = EXAMPLES.replace('<A_BUILD>', str(build.getNumber())) |
| 744 if builder.slavenames: | 762 if builder.slavenames: |
| 745 EXAMPLES = EXAMPLES.replace('<A_SLAVE>', builder.slavenames[0]) | 763 EXAMPLES = EXAMPLES.replace('<A_SLAVE>', builder.slavenames[0]) |
| 746 | 764 |
| 747 # vim: set ts=4 sts=4 sw=4 et: | 765 # vim: set ts=4 sts=4 sw=4 et: |
| OLD | NEW |