waterfall: fix DST calculation. Closes #137.
[buildbot.git] / buildbot / interfaces.py
blob0f5cac954fe89b094f5257605a2d2770c1db68ef
2 """Interface documentation.
4 Define the interfaces that are implemented by various buildbot classes.
5 """
7 from zope.interface import Interface
9 # exceptions that can be raised while trying to start a build
10 class NoSlaveError(Exception):
11 pass
12 class BuilderInUseError(Exception):
13 pass
14 class BuildSlaveTooOldError(Exception):
15 pass
17 class IChangeSource(Interface):
18 """Object which feeds Change objects to the changemaster. When files or
19 directories are changed and the version control system provides some
20 kind of notification, this object should turn it into a Change object
21 and pass it through::
23 self.changemaster.addChange(change)
24 """
26 def start():
27 """Called when the buildmaster starts. Can be used to establish
28 connections to VC daemons or begin polling."""
30 def stop():
31 """Called when the buildmaster shuts down. Connections should be
32 terminated, polling timers should be canceled."""
34 def describe():
35 """Should return a string which briefly describes this source. This
36 string will be displayed in an HTML status page."""
38 class IScheduler(Interface):
39 """I watch for Changes in the source tree and decide when to trigger
40 Builds. I create BuildSet objects and submit them to the BuildMaster. I
41 am a service, and the BuildMaster is always my parent."""
43 def addChange(change):
44 """A Change has just been dispatched by one of the ChangeSources.
45 Each Scheduler will receive this Change. I may decide to start a
46 build as a result, or I might choose to ignore it."""
48 def listBuilderNames():
49 """Return a list of strings indicating the Builders that this
50 Scheduler might feed."""
52 def getPendingBuildTimes():
53 """Return a list of timestamps for any builds that are waiting in the
54 tree-stable-timer queue. This is only relevant for Change-based
55 schedulers, all others can just return an empty list."""
56 # TODO: it might be nice to make this into getPendingBuildSets, which
57 # would let someone subscribe to the buildset being finished.
58 # However, the Scheduler doesn't actually create the buildset until
59 # it gets submitted, so doing this would require some major rework.
61 class IUpstreamScheduler(Interface):
62 """This marks an IScheduler as being eligible for use as the 'upstream='
63 argument to a buildbot.scheduler.Dependent instance."""
65 def subscribeToSuccessfulBuilds(target):
66 """Request that the target callbable be invoked after every
67 successful buildset. The target will be called with a single
68 argument: the SourceStamp used by the successful builds."""
70 def listBuilderNames():
71 """Return a list of strings indicating the Builders that this
72 Scheduler might feed."""
74 class ISourceStamp(Interface):
75 """
76 @cvar branch: branch from which source was drawn
77 @type branch: string or None
79 @cvar revision: revision of the source, or None to use CHANGES
80 @type revision: varies depending on VC
82 @cvar patch: patch applied to the source, or None if no patch
83 @type patch: None or tuple (level diff)
85 @cvar changes: the source step should check out hte latest revision
86 in the given changes
87 @type changes: tuple of L{buildbot.changes.changes.Change} instances,
88 all of which are on the same branch
89 """
91 def canBeMergedWith(self, other):
92 """
93 Can this SourceStamp be merged with OTHER?
94 """
96 def mergeWith(self, others):
97 """Generate a SourceStamp for the merger of me and all the other
98 BuildRequests. This is called by a Build when it starts, to figure
99 out what its sourceStamp should be."""
101 def getText(self):
102 """Returns a list of strings to describe the stamp. These are
103 intended to be displayed in a narrow column. If more space is
104 available, the caller should join them together with spaces before
105 presenting them to the user."""
107 class IEmailSender(Interface):
108 """I know how to send email, and can be used by other parts of the
109 Buildbot to contact developers."""
110 pass
112 class IEmailLookup(Interface):
113 def getAddress(user):
114 """Turn a User-name string into a valid email address. Either return
115 a string (with an @ in it), None (to indicate that the user cannot
116 be reached by email), or a Deferred which will fire with the same."""
118 class IStatus(Interface):
119 """I am an object, obtainable from the buildmaster, which can provide
120 status information."""
122 def getProjectName():
123 """Return the name of the project that this Buildbot is working
124 for."""
125 def getProjectURL():
126 """Return the URL of this Buildbot's project."""
127 def getBuildbotURL():
128 """Return the URL of the top-most Buildbot status page, or None if
129 this Buildbot does not provide a web status page."""
130 def getURLForThing(thing):
131 """Return the URL of a page which provides information on 'thing',
132 which should be an object that implements one of the status
133 interfaces defined in L{buildbot.interfaces}. Returns None if no
134 suitable page is available (or if no Waterfall is running)."""
136 def getChangeSources():
137 """Return a list of IChangeSource objects."""
139 def getChange(number):
140 """Return an IChange object."""
142 def getSchedulers():
143 """Return a list of ISchedulerStatus objects for all
144 currently-registered Schedulers."""
146 def getBuilderNames(categories=None):
147 """Return a list of the names of all current Builders."""
148 def getBuilder(name):
149 """Return the IBuilderStatus object for a given named Builder. Raises
150 KeyError if there is no Builder by that name."""
152 def getSlaveNames():
153 """Return a list of buildslave names, suitable for passing to
154 getSlave()."""
155 def getSlave(name):
156 """Return the ISlaveStatus object for a given named buildslave."""
158 def getBuildSets():
159 """Return a list of active (non-finished) IBuildSetStatus objects."""
161 def generateFinishedBuilds(builders=[], branches=[],
162 num_builds=None, finished_before=None,
163 max_search=200):
164 """Return a generator that will produce IBuildStatus objects each
165 time you invoke its .next() method, starting with the most recent
166 finished build and working backwards.
168 @param builders: this is a list of Builder names, and the generator
169 will only produce builds that ran on the given
170 Builders. If the list is empty, produce builds from
171 all Builders.
173 @param branches: this is a list of branch names, and the generator
174 will only produce builds that used the given
175 branches. If the list is empty, produce builds from
176 all branches.
178 @param num_builds: the generator will stop after providing this many
179 builds. The default of None means to produce as
180 many builds as possible.
182 @type finished_before: int: a timestamp, seconds since the epoch
183 @param finished_before: if provided, do not produce any builds that
184 finished after the given timestamp.
186 @type max_search: int
187 @param max_search: this method may have to examine a lot of builds
188 to find some that match the search parameters,
189 especially if there aren't any matching builds.
190 This argument imposes a hard limit on the number
191 of builds that will be examined within any given
192 Builder.
195 def subscribe(receiver):
196 """Register an IStatusReceiver to receive new status events. The
197 receiver will immediately be sent a set of 'builderAdded' messages
198 for all current builders. It will receive further 'builderAdded' and
199 'builderRemoved' messages as the config file is reloaded and builders
200 come and go. It will also receive 'buildsetSubmitted' messages for
201 all outstanding BuildSets (and each new BuildSet that gets
202 submitted). No additional messages will be sent unless the receiver
203 asks for them by calling .subscribe on the IBuilderStatus objects
204 which accompany the addedBuilder message."""
206 def unsubscribe(receiver):
207 """Unregister an IStatusReceiver. No further status messgaes will be
208 delivered."""
210 class IBuildSetStatus(Interface):
211 """I represent a set of Builds, each run on a separate Builder but all
212 using the same source tree."""
214 def getSourceStamp():
215 """Return a SourceStamp object which can be used to re-create
216 the source tree that this build used.
218 This method will return None if the source information is no longer
219 available."""
220 pass
221 def getReason():
222 pass
223 def getID():
224 """Return the BuildSet's ID string, if any. The 'try' feature uses a
225 random string as a BuildSetID to relate submitted jobs with the
226 resulting BuildSet."""
227 def getResponsibleUsers():
228 pass # not implemented
229 def getInterestedUsers():
230 pass # not implemented
231 def getBuilderNames():
232 """Return a list of the names of all Builders on which this set will
233 do builds."""
234 def getBuildRequests():
235 """Return a list of IBuildRequestStatus objects that represent my
236 component Builds. This list might correspond to the Builders named by
237 getBuilderNames(), but if builder categories are used, or 'Builder
238 Aliases' are implemented, then they may not."""
239 def isFinished():
240 pass
241 def waitUntilSuccess():
242 """Return a Deferred that fires (with this IBuildSetStatus object)
243 when the outcome of the BuildSet is known, i.e., upon the first
244 failure, or after all builds complete successfully."""
245 def waitUntilFinished():
246 """Return a Deferred that fires (with this IBuildSetStatus object)
247 when all builds have finished."""
248 def getResults():
249 pass
251 class IBuildRequestStatus(Interface):
252 """I represent a request to build a particular set of source code on a
253 particular Builder. These requests may be merged by the time they are
254 finally turned into a Build."""
256 def getSourceStamp():
257 """Return a SourceStamp object which can be used to re-create
258 the source tree that this build used.
260 This method will return None if the source information is no longer
261 available."""
262 pass
263 def getBuilderName():
264 pass
265 def getBuilds():
266 """Return a list of IBuildStatus objects for each Build that has been
267 started in an attempt to satify this BuildRequest."""
269 def subscribe(observer):
270 """Register a callable that will be invoked (with a single
271 IBuildStatus object) for each Build that is created to satisfy this
272 request. There may be multiple Builds created in an attempt to handle
273 the request: they may be interrupted by the user or abandoned due to
274 a lost slave. The last Build (the one which actually gets to run to
275 completion) is said to 'satisfy' the BuildRequest. The observer will
276 be called once for each of these Builds, both old and new."""
277 def unsubscribe(observer):
278 """Unregister the callable that was registered with subscribe()."""
281 class ISlaveStatus(Interface):
282 def getName():
283 """Return the name of the build slave."""
285 def getAdmin():
286 """Return a string with the slave admin's contact data."""
288 def getHost():
289 """Return a string with the slave host info."""
291 def isConnected():
292 """Return True if the slave is currently online, False if not."""
294 def lastMessageReceived():
295 """Return a timestamp (seconds since epoch) indicating when the most
296 recent message was received from the buildslave."""
298 class ISchedulerStatus(Interface):
299 def getName():
300 """Return the name of this Scheduler (a string)."""
302 def getPendingBuildsets():
303 """Return an IBuildSet for all BuildSets that are pending. These
304 BuildSets are waiting for their tree-stable-timers to expire."""
305 # TODO: this is not implemented anywhere
308 class IBuilderStatus(Interface):
309 def getName():
310 """Return the name of this Builder (a string)."""
312 def getState():
313 # TODO: this isn't nearly as meaningful as it used to be
314 """Return a tuple (state, builds) for this Builder. 'state' is the
315 so-called 'big-status', indicating overall status (as opposed to
316 which step is currently running). It is a string, one of 'offline',
317 'idle', or 'building'. 'builds' is a list of IBuildStatus objects
318 (possibly empty) representing the currently active builds."""
320 def getSlaves():
321 """Return a list of ISlaveStatus objects for the buildslaves that are
322 used by this builder."""
324 def getPendingBuilds():
325 """Return an IBuildRequestStatus object for all upcoming builds
326 (those which are ready to go but which are waiting for a buildslave
327 to be available."""
329 def getCurrentBuilds():
330 """Return a list containing an IBuildStatus object for each build
331 currently in progress."""
332 # again, we could probably provide an object for 'waiting' and
333 # 'interlocked' too, but things like the Change list might still be
334 # subject to change
336 def getLastFinishedBuild():
337 """Return the IBuildStatus object representing the last finished
338 build, which may be None if the builder has not yet finished any
339 builds."""
341 def getBuild(number):
342 """Return an IBuildStatus object for a historical build. Each build
343 is numbered (starting at 0 when the Builder is first added),
344 getBuild(n) will retrieve the Nth such build. getBuild(-n) will
345 retrieve a recent build, with -1 being the most recent build
346 started. If the Builder is idle, this will be the same as
347 getLastFinishedBuild(). If the Builder is active, it will be an
348 unfinished build. This method will return None if the build is no
349 longer available. Older builds are likely to have less information
350 stored: Logs are the first to go, then Steps."""
352 def getEvent(number):
353 """Return an IStatusEvent object for a recent Event. Builders
354 connecting and disconnecting are events, as are ping attempts.
355 getEvent(-1) will return the most recent event. Events are numbered,
356 but it probably doesn't make sense to ever do getEvent(+n)."""
358 def generateFinishedBuilds(branches=[],
359 num_builds=None,
360 max_buildnum=None, finished_before=None,
361 max_search=200,
363 """Return a generator that will produce IBuildStatus objects each
364 time you invoke its .next() method, starting with the most recent
365 finished build, then the previous build, and so on back to the oldest
366 build available.
368 @param branches: this is a list of branch names, and the generator
369 will only produce builds that involve the given
370 branches. If the list is empty, the generator will
371 produce all builds regardless of what branch they
372 used.
374 @param num_builds: if provided, the generator will stop after
375 providing this many builds. The default of None
376 means to produce as many builds as possible.
378 @param max_buildnum: if provided, the generator will start by
379 providing the build with this number, or the
380 highest-numbered preceding build (i.e. the
381 generator will not produce any build numbered
382 *higher* than max_buildnum). The default of None
383 means to start with the most recent finished
384 build. -1 means the same as None. -2 means to
385 start with the next-most-recent completed build,
386 etc.
388 @type finished_before: int: a timestamp, seconds since the epoch
389 @param finished_before: if provided, do not produce any builds that
390 finished after the given timestamp.
392 @type max_search: int
393 @param max_search: this method may have to examine a lot of builds
394 to find some that match the search parameters,
395 especially if there aren't any matching builds.
396 This argument imposes a hard limit on the number
397 of builds that will be examined.
400 def subscribe(receiver):
401 """Register an IStatusReceiver to receive new status events. The
402 receiver will be given builderChangedState, buildStarted, and
403 buildFinished messages."""
405 def unsubscribe(receiver):
406 """Unregister an IStatusReceiver. No further status messgaes will be
407 delivered."""
409 class IEventSource(Interface):
410 def eventGenerator(branches=[]):
411 """This function creates a generator which will yield all of this
412 object's status events, starting with the most recent and progressing
413 backwards in time. These events provide the IStatusEvent interface.
414 At the moment they are all instances of buildbot.status.builder.Event
415 or buildbot.status.builder.BuildStepStatus .
417 @param branches: a list of branch names. The generator should only
418 return events that are associated with these branches. If the list is
419 empty, events for all branches should be returned (i.e. an empty list
420 means 'accept all' rather than 'accept none').
423 class IBuildStatus(Interface):
424 """I represent the status of a single Build/BuildRequest. It could be
425 in-progress or finished."""
427 def getBuilder():
429 Return the BuilderStatus that owns this build.
431 @rtype: implementor of L{IBuilderStatus}
434 def isFinished():
435 """Return a boolean. True means the build has finished, False means
436 it is still running."""
438 def waitUntilFinished():
439 """Return a Deferred that will fire when the build finishes. If the
440 build has already finished, this deferred will fire right away. The
441 callback is given this IBuildStatus instance as an argument."""
443 def getProperty(propname):
444 """Return the value of the build property with the given name. Raises
445 KeyError if there is no such property on this build."""
447 def getReason():
448 """Return a string that indicates why the build was run. 'changes',
449 'forced', and 'periodic' are the most likely values. 'try' will be
450 added in the future."""
452 def getSourceStamp():
453 """Return a SourceStamp object which can be used to re-create
454 the source tree that this build used.
456 This method will return None if the source information is no longer
457 available."""
458 # TODO: it should be possible to expire the patch but still remember
459 # that the build was r123+something.
461 def getChanges():
462 """Return a list of Change objects which represent which source
463 changes went into the build."""
465 def getResponsibleUsers():
466 """Return a list of Users who are to blame for the changes that went
467 into this build. If anything breaks (at least anything that wasn't
468 already broken), blame them. Specifically, this is the set of users
469 who were responsible for the Changes that went into this build. Each
470 User is a string, corresponding to their name as known by the VC
471 repository."""
473 def getInterestedUsers():
474 """Return a list of Users who will want to know about the results of
475 this build. This is a superset of getResponsibleUsers(): it adds
476 people who are interested in this build but who did not actually
477 make the Changes that went into it (build sheriffs, code-domain
478 owners)."""
480 def getNumber():
481 """Within each builder, each Build has a number. Return it."""
483 def getPreviousBuild():
484 """Convenience method. Returns None if the previous build is
485 unavailable."""
487 def getSteps():
488 """Return a list of IBuildStepStatus objects. For invariant builds
489 (those which always use the same set of Steps), this should always
490 return the complete list, however some of the steps may not have
491 started yet (step.getTimes()[0] will be None). For variant builds,
492 this may not be complete (asking again later may give you more of
493 them)."""
495 def getTimes():
496 """Returns a tuple of (start, end). 'start' and 'end' are the times
497 (seconds since the epoch) when the Build started and finished. If
498 the build is still running, 'end' will be None."""
500 # while the build is running, the following methods make sense.
501 # Afterwards they return None
503 def getETA():
504 """Returns the number of seconds from now in which the build is
505 expected to finish, or None if we can't make a guess. This guess will
506 be refined over time."""
508 def getCurrentStep():
509 """Return an IBuildStepStatus object representing the currently
510 active step."""
512 # Once you know the build has finished, the following methods are legal.
513 # Before ths build has finished, they all return None.
515 def getSlavename():
516 """Return the name of the buildslave which handled this build."""
518 def getText():
519 """Returns a list of strings to describe the build. These are
520 intended to be displayed in a narrow column. If more space is
521 available, the caller should join them together with spaces before
522 presenting them to the user."""
524 def getColor():
525 """Returns a single string with the color that should be used to
526 display the build. 'green', 'orange', or 'red' are the most likely
527 ones."""
529 def getResults():
530 """Return a constant describing the results of the build: one of the
531 constants in buildbot.status.builder: SUCCESS, WARNINGS, or
532 FAILURE."""
534 def getLogs():
535 """Return a list of logs that describe the build as a whole. Some
536 steps will contribute their logs, while others are are less important
537 and will only be accessible through the IBuildStepStatus objects.
538 Each log is an object which implements the IStatusLog interface."""
540 def getTestResults():
541 """Return a dictionary that maps test-name tuples to ITestResult
542 objects. This may return an empty or partially-filled dictionary
543 until the build has completed."""
545 # subscription interface
547 def subscribe(receiver, updateInterval=None):
548 """Register an IStatusReceiver to receive new status events. The
549 receiver will be given stepStarted and stepFinished messages. If
550 'updateInterval' is non-None, buildETAUpdate messages will be sent
551 every 'updateInterval' seconds."""
553 def unsubscribe(receiver):
554 """Unregister an IStatusReceiver. No further status messgaes will be
555 delivered."""
557 class ITestResult(Interface):
558 """I describe the results of a single unit test."""
560 def getName():
561 """Returns a tuple of strings which make up the test name. Tests may
562 be arranged in a hierarchy, so looking for common prefixes may be
563 useful."""
565 def getResults():
566 """Returns a constant describing the results of the test: SUCCESS,
567 WARNINGS, FAILURE."""
569 def getText():
570 """Returns a list of short strings which describe the results of the
571 test in slightly more detail. Suggested components include
572 'failure', 'error', 'passed', 'timeout'."""
574 def getLogs():
575 # in flux, it may be possible to provide more structured information
576 # like python Failure instances
577 """Returns a dictionary of test logs. The keys are strings like
578 'stdout', 'log', 'exceptions'. The values are strings."""
581 class IBuildStepStatus(Interface):
582 """I hold status for a single BuildStep."""
584 def getName():
585 """Returns a short string with the name of this step. This string
586 may have spaces in it."""
588 def getBuild():
589 """Returns the IBuildStatus object which contains this step."""
591 def getTimes():
592 """Returns a tuple of (start, end). 'start' and 'end' are the times
593 (seconds since the epoch) when the Step started and finished. If the
594 step has not yet started, 'start' will be None. If the step is still
595 running, 'end' will be None."""
597 def getExpectations():
598 """Returns a list of tuples (name, current, target). Each tuple
599 describes a single axis along which the step's progress can be
600 measured. 'name' is a string which describes the axis itself, like
601 'filesCompiled' or 'tests run' or 'bytes of output'. 'current' is a
602 number with the progress made so far, while 'target' is the value
603 that we expect (based upon past experience) to get to when the build
604 is finished.
606 'current' will change over time until the step is finished. It is
607 'None' until the step starts. When the build is finished, 'current'
608 may or may not equal 'target' (which is merely the expectation based
609 upon previous builds)."""
611 def getURLs():
612 """Returns a dictionary of URLs. Each key is a link name (a short
613 string, like 'results' or 'coverage'), and each value is a URL. These
614 links will be displayed along with the LogFiles.
617 def getLogs():
618 """Returns a list of IStatusLog objects. If the step has not yet
619 finished, this list may be incomplete (asking again later may give
620 you more of them)."""
623 def isFinished():
624 """Return a boolean. True means the step has finished, False means it
625 is still running."""
627 def waitUntilFinished():
628 """Return a Deferred that will fire when the step finishes. If the
629 step has already finished, this deferred will fire right away. The
630 callback is given this IBuildStepStatus instance as an argument."""
632 # while the step is running, the following methods make sense.
633 # Afterwards they return None
635 def getETA():
636 """Returns the number of seconds from now in which the step is
637 expected to finish, or None if we can't make a guess. This guess will
638 be refined over time."""
640 # Once you know the step has finished, the following methods are legal.
641 # Before ths step has finished, they all return None.
643 def getText():
644 """Returns a list of strings which describe the step. These are
645 intended to be displayed in a narrow column. If more space is
646 available, the caller should join them together with spaces before
647 presenting them to the user."""
649 def getColor():
650 """Returns a single string with the color that should be used to
651 display this step. 'green', 'orange', 'red' and 'yellow' are the
652 most likely ones."""
654 def getResults():
655 """Return a tuple describing the results of the step: (result,
656 strings). 'result' is one of the constants in
657 buildbot.status.builder: SUCCESS, WARNINGS, FAILURE, or SKIPPED.
658 'strings' is an optional list of strings that the step wants to
659 append to the overall build's results. These strings are usually
660 more terse than the ones returned by getText(): in particular,
661 successful Steps do not usually contribute any text to the overall
662 build."""
664 # subscription interface
666 def subscribe(receiver, updateInterval=10):
667 """Register an IStatusReceiver to receive new status events. The
668 receiver will be given logStarted and logFinished messages. It will
669 also be given a ETAUpdate message every 'updateInterval' seconds."""
671 def unsubscribe(receiver):
672 """Unregister an IStatusReceiver. No further status messgaes will be
673 delivered."""
675 class IStatusEvent(Interface):
676 """I represent a Builder Event, something non-Build related that can
677 happen to a Builder."""
679 def getTimes():
680 """Returns a tuple of (start, end) like IBuildStepStatus, but end==0
681 indicates that this is a 'point event', which has no duration.
682 SlaveConnect/Disconnect are point events. Ping is not: it starts
683 when requested and ends when the response (positive or negative) is
684 returned"""
686 def getText():
687 """Returns a list of strings which describe the event. These are
688 intended to be displayed in a narrow column. If more space is
689 available, the caller should join them together with spaces before
690 presenting them to the user."""
692 def getColor():
693 """Returns a single string with the color that should be used to
694 display this event. 'red' and 'yellow' are the most likely ones."""
697 LOG_CHANNEL_STDOUT = 0
698 LOG_CHANNEL_STDERR = 1
699 LOG_CHANNEL_HEADER = 2
701 class IStatusLog(Interface):
702 """I represent a single Log, which is a growing list of text items that
703 contains some kind of output for a single BuildStep. I might be finished,
704 in which case this list has stopped growing.
706 Each Log has a name, usually something boring like 'log' or 'output'.
707 These names are not guaranteed to be unique, however they are usually
708 chosen to be useful within the scope of a single step (i.e. the Compile
709 step might produce both 'log' and 'warnings'). The name may also have
710 spaces. If you want something more globally meaningful, at least within a
711 given Build, try::
713 '%s.%s' % (log.getStep.getName(), log.getName())
715 The Log can be presented as plain text, or it can be accessed as a list
716 of items, each of which has a channel indicator (header, stdout, stderr)
717 and a text chunk. An HTML display might represent the interleaved
718 channels with different styles, while a straight download-the-text
719 interface would just want to retrieve a big string.
721 The 'header' channel is used by ShellCommands to prepend a note about
722 which command is about to be run ('running command FOO in directory
723 DIR'), and append another note giving the exit code of the process.
725 Logs can be streaming: if the Log has not yet finished, you can
726 subscribe to receive new chunks as they are added.
728 A ShellCommand will have a Log associated with it that gathers stdout
729 and stderr. Logs may also be created by parsing command output or
730 through other synthetic means (grepping for all the warnings in a
731 compile log, or listing all the test cases that are going to be run).
732 Such synthetic Logs are usually finished as soon as they are created."""
735 def getName():
736 """Returns a short string with the name of this log, probably 'log'.
739 def getStep():
740 """Returns the IBuildStepStatus which owns this log."""
741 # TODO: can there be non-Step logs?
743 def isFinished():
744 """Return a boolean. True means the log has finished and is closed,
745 False means it is still open and new chunks may be added to it."""
747 def waitUntilFinished():
748 """Return a Deferred that will fire when the log is closed. If the
749 log has already finished, this deferred will fire right away. The
750 callback is given this IStatusLog instance as an argument."""
752 def subscribe(receiver, catchup):
753 """Register an IStatusReceiver to receive chunks (with logChunk) as
754 data is added to the Log. If you use this, you will also want to use
755 waitUntilFinished to find out when the listener can be retired.
756 Subscribing to a closed Log is a no-op.
758 If 'catchup' is True, the receiver will immediately be sent a series
759 of logChunk messages to bring it up to date with the partially-filled
760 log. This allows a status client to join a Log already in progress
761 without missing any data. If the Log has already finished, it is too
762 late to catch up: just do getText() instead.
764 If the Log is very large, the receiver will be called many times with
765 a lot of data. There is no way to throttle this data. If the receiver
766 is planning on sending the data on to somewhere else, over a narrow
767 connection, you can get a throttleable subscription by using
768 C{subscribeConsumer} instead."""
770 def unsubscribe(receiver):
771 """Remove a receiver previously registered with subscribe(). Attempts
772 to remove a receiver which was not previously registered is a no-op.
775 def subscribeConsumer(consumer):
776 """Register an L{IStatusLogConsumer} to receive all chunks of the
777 logfile, including all the old entries and any that will arrive in
778 the future. The consumer will first have their C{registerProducer}
779 method invoked with a reference to an object that can be told
780 C{pauseProducing}, C{resumeProducing}, and C{stopProducing}. Then the
781 consumer's C{writeChunk} method will be called repeatedly with each
782 (channel, text) tuple in the log, starting with the very first. The
783 consumer will be notified with C{finish} when the log has been
784 exhausted (which can only happen when the log is finished). Note that
785 a small amount of data could be written via C{writeChunk} even after
786 C{pauseProducing} has been called.
788 To unsubscribe the consumer, use C{producer.stopProducing}."""
790 # once the log has finished, the following methods make sense. They can
791 # be called earlier, but they will only return the contents of the log up
792 # to the point at which they were called. You will lose items that are
793 # added later. Use C{subscribe} or C{subscribeConsumer} to avoid missing
794 # anything.
796 def hasContents():
797 """Returns True if the LogFile still has contents available. Returns
798 False for logs that have been pruned. Clients should test this before
799 offering to show the contents of any log."""
801 def getText():
802 """Return one big string with the contents of the Log. This merges
803 all non-header chunks together."""
805 def readlines(channel=LOG_CHANNEL_STDOUT):
806 """Read lines from one channel of the logfile. This returns an
807 iterator that will provide single lines of text (including the
808 trailing newline).
811 def getTextWithHeaders():
812 """Return one big string with the contents of the Log. This merges
813 all chunks (including headers) together."""
815 def getChunks():
816 """Generate a list of (channel, text) tuples. 'channel' is a number,
817 0 for stdout, 1 for stderr, 2 for header. (note that stderr is merged
818 into stdout if PTYs are in use)."""
820 class IStatusLogConsumer(Interface):
821 """I am an object which can be passed to IStatusLog.subscribeConsumer().
822 I represent a target for writing the contents of an IStatusLog. This
823 differs from a regular IStatusReceiver in that it can pause the producer.
824 This makes it more suitable for use in streaming data over network
825 sockets, such as an HTTP request. Note that the consumer can only pause
826 the producer until it has caught up with all the old data. After that
827 point, C{pauseProducing} is ignored and all new output from the log is
828 sent directoy to the consumer."""
830 def registerProducer(producer, streaming):
831 """A producer is being hooked up to this consumer. The consumer only
832 has to handle a single producer. It should send .pauseProducing and
833 .resumeProducing messages to the producer when it wants to stop or
834 resume the flow of data. 'streaming' will be set to True because the
835 producer is always a PushProducer.
838 def unregisterProducer():
839 """The previously-registered producer has been removed. No further
840 pauseProducing or resumeProducing calls should be made. The consumer
841 should delete its reference to the Producer so it can be released."""
843 def writeChunk(chunk):
844 """A chunk (i.e. a tuple of (channel, text)) is being written to the
845 consumer."""
847 def finish():
848 """The log has finished sending chunks to the consumer."""
850 class IStatusReceiver(Interface):
851 """I am an object which can receive build status updates. I may be
852 subscribed to an IStatus, an IBuilderStatus, or an IBuildStatus."""
854 def buildsetSubmitted(buildset):
855 """A new BuildSet has been submitted to the buildmaster.
857 @type buildset: implementor of L{IBuildSetStatus}
860 def builderAdded(builderName, builder):
862 A new Builder has just been added. This method may return an
863 IStatusReceiver (probably 'self') which will be subscribed to receive
864 builderChangedState and buildStarted/Finished events.
866 @type builderName: string
867 @type builder: L{buildbot.status.builder.BuilderStatus}
868 @rtype: implementor of L{IStatusReceiver}
871 def builderChangedState(builderName, state):
872 """Builder 'builderName' has changed state. The possible values for
873 'state' are 'offline', 'idle', and 'building'."""
875 def buildStarted(builderName, build):
876 """Builder 'builderName' has just started a build. The build is an
877 object which implements IBuildStatus, and can be queried for more
878 information.
880 This method may return an IStatusReceiver (it could even return
881 'self'). If it does so, stepStarted and stepFinished methods will be
882 invoked on the object for the steps of this one build. This is a
883 convenient way to subscribe to all build steps without missing any.
884 This receiver will automatically be unsubscribed when the build
885 finishes.
887 It can also return a tuple of (IStatusReceiver, interval), in which
888 case buildETAUpdate messages are sent ever 'interval' seconds, in
889 addition to the stepStarted and stepFinished messages."""
891 def buildETAUpdate(build, ETA):
892 """This is a periodic update on the progress this Build has made
893 towards completion."""
895 def stepStarted(build, step):
896 """A step has just started. 'step' is the IBuildStepStatus which
897 represents the step: it can be queried for more information.
899 This method may return an IStatusReceiver (it could even return
900 'self'). If it does so, logStarted and logFinished methods will be
901 invoked on the object for logs created by this one step. This
902 receiver will be automatically unsubscribed when the step finishes.
904 Alternatively, the method may return a tuple of an IStatusReceiver
905 and an integer named 'updateInterval'. In addition to
906 logStarted/logFinished messages, it will also receive stepETAUpdate
907 messages about every updateInterval seconds."""
909 def stepETAUpdate(build, step, ETA, expectations):
910 """This is a periodic update on the progress this Step has made
911 towards completion. It gets an ETA (in seconds from the present) of
912 when the step ought to be complete, and a list of expectation tuples
913 (as returned by IBuildStepStatus.getExpectations) with more detailed
914 information."""
916 def logStarted(build, step, log):
917 """A new Log has been started, probably because a step has just
918 started running a shell command. 'log' is the IStatusLog object
919 which can be queried for more information.
921 This method may return an IStatusReceiver (such as 'self'), in which
922 case the target's logChunk method will be invoked as text is added to
923 the logfile. This receiver will automatically be unsubsribed when the
924 log finishes."""
926 def logChunk(build, step, log, channel, text):
927 """Some text has been added to this log. 'channel' is one of
928 LOG_CHANNEL_STDOUT, LOG_CHANNEL_STDERR, or LOG_CHANNEL_HEADER, as
929 defined in IStatusLog.getChunks."""
931 def logFinished(build, step, log):
932 """A Log has been closed."""
934 def stepFinished(build, step, results):
935 """A step has just finished. 'results' is the result tuple described
936 in IBuildStepStatus.getResults."""
938 def buildFinished(builderName, build, results):
940 A build has just finished. 'results' is the result tuple described
941 in L{IBuildStatus.getResults}.
943 @type builderName: string
944 @type build: L{buildbot.status.builder.BuildStatus}
945 @type results: tuple
948 def builderRemoved(builderName):
949 """The Builder has been removed."""
951 class IControl(Interface):
952 def addChange(change):
953 """Add a change to all builders. Each Builder will decide for
954 themselves whether the change is interesting or not, and may initiate
955 a build as a result."""
957 def submitBuildSet(buildset):
958 """Submit a BuildSet object, which will eventually be run on all of
959 the builders listed therein."""
961 def getBuilder(name):
962 """Retrieve the IBuilderControl object for the given Builder."""
964 class IBuilderControl(Interface):
965 def requestBuild(request):
966 """Queue a L{buildbot.process.base.BuildRequest} object for later
967 building."""
969 def requestBuildSoon(request):
970 """Submit a BuildRequest like requestBuild, but raise a
971 L{buildbot.interfaces.NoSlaveError} if no slaves are currently
972 available, so it cannot be used to queue a BuildRequest in the hopes
973 that a slave will eventually connect. This method is appropriate for
974 use by things like the web-page 'Force Build' button."""
976 def resubmitBuild(buildStatus, reason="<rebuild, no reason given>"):
977 """Rebuild something we've already built before. This submits a
978 BuildRequest to our Builder using the same SourceStamp as the earlier
979 build. This has no effect (but may eventually raise an exception) if
980 this Build has not yet finished."""
982 def getPendingBuilds():
983 """Return a list of L{IBuildRequestControl} objects for this Builder.
984 Each one corresponds to a pending build that has not yet started (due
985 to a scarcity of build slaves). These upcoming builds can be canceled
986 through the control object."""
988 def getBuild(number):
989 """Attempt to return an IBuildControl object for the given build.
990 Returns None if no such object is available. This will only work for
991 the build that is currently in progress: once the build finishes,
992 there is nothing to control anymore."""
994 def ping(timeout=30):
995 """Attempt to contact the slave and see if it is still alive. This
996 returns a Deferred which fires with either True (the slave is still
997 alive) or False (the slave did not respond). As a side effect, adds
998 an event to this builder's column in the waterfall display
999 containing the results of the ping."""
1000 # TODO: this ought to live in ISlaveControl, maybe with disconnect()
1001 # or something. However the event that is emitted is most useful in
1002 # the Builder column, so it kinda fits here too.
1004 class IBuildRequestControl(Interface):
1005 def subscribe(observer):
1006 """Register a callable that will be invoked (with a single
1007 IBuildControl object) for each Build that is created to satisfy this
1008 request. There may be multiple Builds created in an attempt to handle
1009 the request: they may be interrupted by the user or abandoned due to
1010 a lost slave. The last Build (the one which actually gets to run to
1011 completion) is said to 'satisfy' the BuildRequest. The observer will
1012 be called once for each of these Builds, both old and new."""
1013 def unsubscribe(observer):
1014 """Unregister the callable that was registered with subscribe()."""
1015 def cancel():
1016 """Remove the build from the pending queue. Has no effect if the
1017 build has already been started."""
1019 class IBuildControl(Interface):
1020 def getStatus():
1021 """Return an IBuildStatus object for the Build that I control."""
1022 def stopBuild(reason="<no reason given>"):
1023 """Halt the build. This has no effect if the build has already
1024 finished."""
1026 class ILogFile(Interface):
1027 """This is the internal interface to a LogFile, used by the BuildStep to
1028 write data into the log.
1030 def addStdout(data):
1031 pass
1032 def addStderr(data):
1033 pass
1034 def addHeader(data):
1035 pass
1036 def finish():
1037 """The process that is feeding the log file has finished, and no
1038 further data will be added. This closes the logfile."""
1040 class ILogObserver(Interface):
1041 """Objects which provide this interface can be used in a BuildStep to
1042 watch the output of a LogFile and parse it incrementally.
1045 # internal methods
1046 def setStep(step):
1047 pass
1048 def setLog(log):
1049 pass
1051 # methods called by the LogFile
1052 def logChunk(build, step, log, channel, text):
1053 pass
1055 class IBuildSlave(Interface):
1056 # this is a marker interface for the BuildSlave class
1057 pass