enhance IStatusLog.readlines to accept a channel= argument
[buildbot.git] / buildbot / interfaces.py
blob58e3104e155439041f4ab553d8f419e3c473dc5e
1 #! /usr/bin/python
3 """Interface documentation.
5 Define the interfaces that are implemented by various buildbot classes.
6 """
8 from buildbot.twcompat import Interface
10 # exceptions that can be raised while trying to start a build
11 class NoSlaveError(Exception):
12 pass
13 class BuilderInUseError(Exception):
14 pass
15 class BuildSlaveTooOldError(Exception):
16 pass
18 class IChangeSource(Interface):
19 """Object which feeds Change objects to the changemaster. When files or
20 directories are changed and the version control system provides some
21 kind of notification, this object should turn it into a Change object
22 and pass it through::
24 self.changemaster.addChange(change)
25 """
27 def start():
28 """Called when the buildmaster starts. Can be used to establish
29 connections to VC daemons or begin polling."""
31 def stop():
32 """Called when the buildmaster shuts down. Connections should be
33 terminated, polling timers should be canceled."""
35 def describe():
36 """Should return a string which briefly describes this source. This
37 string will be displayed in an HTML status page."""
39 class IScheduler(Interface):
40 """I watch for Changes in the source tree and decide when to trigger
41 Builds. I create BuildSet objects and submit them to the BuildMaster. I
42 am a service, and the BuildMaster is always my parent."""
44 def addChange(change):
45 """A Change has just been dispatched by one of the ChangeSources.
46 Each Scheduler will receive this Change. I may decide to start a
47 build as a result, or I might choose to ignore it."""
49 def listBuilderNames():
50 """Return a list of strings indicating the Builders that this
51 Scheduler might feed."""
53 def getPendingBuildTimes():
54 """Return a list of timestamps for any builds that are waiting in the
55 tree-stable-timer queue. This is only relevant for Change-based
56 schedulers, all others can just return an empty list."""
57 # TODO: it might be nice to make this into getPendingBuildSets, which
58 # would let someone subscribe to the buildset being finished.
59 # However, the Scheduler doesn't actually create the buildset until
60 # it gets submitted, so doing this would require some major rework.
62 class IUpstreamScheduler(Interface):
63 """This marks an IScheduler as being eligible for use as the 'upstream='
64 argument to a buildbot.scheduler.Dependent instance."""
66 def subscribeToSuccessfulBuilds(target):
67 """Request that the target callbable be invoked after every
68 successful buildset. The target will be called with a single
69 argument: the SourceStamp used by the successful builds."""
71 def listBuilderNames():
72 """Return a list of strings indicating the Builders that this
73 Scheduler might feed."""
75 class ISourceStamp(Interface):
76 pass
78 class IEmailSender(Interface):
79 """I know how to send email, and can be used by other parts of the
80 Buildbot to contact developers."""
81 pass
83 class IEmailLookup(Interface):
84 def getAddress(user):
85 """Turn a User-name string into a valid email address. Either return
86 a string (with an @ in it), None (to indicate that the user cannot
87 be reached by email), or a Deferred which will fire with the same."""
89 class IStatus(Interface):
90 """I am an object, obtainable from the buildmaster, which can provide
91 status information."""
93 def getProjectName():
94 """Return the name of the project that this Buildbot is working
95 for."""
96 def getProjectURL():
97 """Return the URL of this Buildbot's project."""
98 def getBuildbotURL():
99 """Return the URL of the top-most Buildbot status page, or None if
100 this Buildbot does not provide a web status page."""
101 def getURLFor(thing):
102 """Return the URL of a page which provides information on 'thing',
103 which should be an object that implements one of the status
104 interfaces defined in L{buildbot.interfaces}. Returns None if no
105 suitable page is available (or if no Waterfall is running)."""
107 def getSchedulers():
108 """Return a list of ISchedulerStatus objects for all
109 currently-registered Schedulers."""
111 def getBuilderNames(categories=None):
112 """Return a list of the names of all current Builders."""
113 def getBuilder(name):
114 """Return the IBuilderStatus object for a given named Builder."""
115 def getSlave(name):
116 """Return the ISlaveStatus object for a given named buildslave."""
118 def getBuildSets():
119 """Return a list of active (non-finished) IBuildSetStatus objects."""
121 def subscribe(receiver):
122 """Register an IStatusReceiver to receive new status events. The
123 receiver will immediately be sent a set of 'builderAdded' messages
124 for all current builders. It will receive further 'builderAdded' and
125 'builderRemoved' messages as the config file is reloaded and builders
126 come and go. It will also receive 'buildsetSubmitted' messages for
127 all outstanding BuildSets (and each new BuildSet that gets
128 submitted). No additional messages will be sent unless the receiver
129 asks for them by calling .subscribe on the IBuilderStatus objects
130 which accompany the addedBuilder message."""
132 def unsubscribe(receiver):
133 """Unregister an IStatusReceiver. No further status messgaes will be
134 delivered."""
136 class IBuildSetStatus(Interface):
137 """I represent a set of Builds, each run on a separate Builder but all
138 using the same source tree."""
140 def getSourceStamp():
141 pass
142 def getReason():
143 pass
144 def getID():
145 """Return the BuildSet's ID string, if any. The 'try' feature uses a
146 random string as a BuildSetID to relate submitted jobs with the
147 resulting BuildSet."""
148 def getResponsibleUsers():
149 pass # not implemented
150 def getInterestedUsers():
151 pass # not implemented
152 def getBuilderNames():
153 """Return a list of the names of all Builders on which this set will
154 do builds."""
155 def getBuildRequests():
156 """Return a list of IBuildRequestStatus objects that represent my
157 component Builds. This list might correspond to the Builders named by
158 getBuilderNames(), but if builder categories are used, or 'Builder
159 Aliases' are implemented, then they may not."""
160 def isFinished():
161 pass
162 def waitUntilSuccess():
163 """Return a Deferred that fires (with this IBuildSetStatus object)
164 when the outcome of the BuildSet is known, i.e., upon the first
165 failure, or after all builds complete successfully."""
166 def waitUntilFinished():
167 """Return a Deferred that fires (with this IBuildSetStatus object)
168 when all builds have finished."""
169 def getResults():
170 pass
172 class IBuildRequestStatus(Interface):
173 """I represent a request to build a particular set of source code on a
174 particular Builder. These requests may be merged by the time they are
175 finally turned into a Build."""
177 def getSourceStamp():
178 pass
179 def getBuilderName():
180 pass
181 def getBuilds():
182 """Return a list of IBuildStatus objects for each Build that has been
183 started in an attempt to satify this BuildRequest."""
185 def subscribe(observer):
186 """Register a callable that will be invoked (with a single
187 IBuildStatus object) for each Build that is created to satisfy this
188 request. There may be multiple Builds created in an attempt to handle
189 the request: they may be interrupted by the user or abandoned due to
190 a lost slave. The last Build (the one which actually gets to run to
191 completion) is said to 'satisfy' the BuildRequest. The observer will
192 be called once for each of these Builds, both old and new."""
193 def unsubscribe(observer):
194 """Unregister the callable that was registered with subscribe()."""
197 class ISlaveStatus(Interface):
198 def getName():
199 """Return the name of the build slave."""
201 def getAdmin():
202 """Return a string with the slave admin's contact data."""
204 def getHost():
205 """Return a string with the slave host info."""
207 def isConnected():
208 """Return True if the slave is currently online, False if not."""
210 class ISchedulerStatus(Interface):
211 def getName():
212 """Return the name of this Scheduler (a string)."""
214 def getPendingBuildsets():
215 """Return an IBuildSet for all BuildSets that are pending. These
216 BuildSets are waiting for their tree-stable-timers to expire."""
217 # TODO: this is not implemented anywhere
220 class IBuilderStatus(Interface):
221 def getName():
222 """Return the name of this Builder (a string)."""
224 def getState():
225 # TODO: this isn't nearly as meaningful as it used to be
226 """Return a tuple (state, builds) for this Builder. 'state' is the
227 so-called 'big-status', indicating overall status (as opposed to
228 which step is currently running). It is a string, one of 'offline',
229 'idle', or 'building'. 'builds' is a list of IBuildStatus objects
230 (possibly empty) representing the currently active builds."""
232 def getSlaves():
233 """Return a list of ISlaveStatus objects for the buildslaves that are
234 used by this builder."""
236 def getPendingBuilds():
237 """Return an IBuildRequestStatus object for all upcoming builds
238 (those which are ready to go but which are waiting for a buildslave
239 to be available."""
241 def getCurrentBuilds():
242 """Return a list containing an IBuildStatus object for each build
243 currently in progress."""
244 # again, we could probably provide an object for 'waiting' and
245 # 'interlocked' too, but things like the Change list might still be
246 # subject to change
248 def getLastFinishedBuild():
249 """Return the IBuildStatus object representing the last finished
250 build, which may be None if the builder has not yet finished any
251 builds."""
253 def getBuild(number):
254 """Return an IBuildStatus object for a historical build. Each build
255 is numbered (starting at 0 when the Builder is first added),
256 getBuild(n) will retrieve the Nth such build. getBuild(-n) will
257 retrieve a recent build, with -1 being the most recent build
258 started. If the Builder is idle, this will be the same as
259 getLastFinishedBuild(). If the Builder is active, it will be an
260 unfinished build. This method will return None if the build is no
261 longer available. Older builds are likely to have less information
262 stored: Logs are the first to go, then Steps."""
264 def getEvent(number):
265 """Return an IStatusEvent object for a recent Event. Builders
266 connecting and disconnecting are events, as are ping attempts.
267 getEvent(-1) will return the most recent event. Events are numbered,
268 but it probably doesn't make sense to ever do getEvent(+n)."""
270 def subscribe(receiver):
271 """Register an IStatusReceiver to receive new status events. The
272 receiver will be given builderChangedState, buildStarted, and
273 buildFinished messages."""
275 def unsubscribe(receiver):
276 """Unregister an IStatusReceiver. No further status messgaes will be
277 delivered."""
279 class IBuildStatus(Interface):
280 """I represent the status of a single Build/BuildRequest. It could be
281 in-progress or finished."""
283 def getBuilder():
285 Return the BuilderStatus that owns this build.
287 @rtype: implementor of L{IBuilderStatus}
290 def isFinished():
291 """Return a boolean. True means the build has finished, False means
292 it is still running."""
294 def waitUntilFinished():
295 """Return a Deferred that will fire when the build finishes. If the
296 build has already finished, this deferred will fire right away. The
297 callback is given this IBuildStatus instance as an argument."""
299 def getProperty(propname):
300 """Return the value of the build property with the given name."""
302 def getReason():
303 """Return a string that indicates why the build was run. 'changes',
304 'forced', and 'periodic' are the most likely values. 'try' will be
305 added in the future."""
307 def getSourceStamp():
308 """Return a tuple of (branch, revision, patch) which can be used to
309 re-create the source tree that this build used. 'branch' is a string
310 with a VC-specific meaning, or None to indicate that the checkout
311 step used its default branch. 'revision' is a string, the sort you
312 would pass to 'cvs co -r REVISION'. 'patch' is either None, or a
313 (level, diff) tuple which represents a patch that should be applied
314 with 'patch -pLEVEL < DIFF' from the directory created by the
315 checkout operation.
317 This method will return None if the source information is no longer
318 available."""
319 # TODO: it should be possible to expire the patch but still remember
320 # that the build was r123+something.
322 # TODO: change this to return the actual SourceStamp instance, and
323 # remove getChanges()
325 def getChanges():
326 """Return a list of Change objects which represent which source
327 changes went into the build."""
329 def getResponsibleUsers():
330 """Return a list of Users who are to blame for the changes that went
331 into this build. If anything breaks (at least anything that wasn't
332 already broken), blame them. Specifically, this is the set of users
333 who were responsible for the Changes that went into this build. Each
334 User is a string, corresponding to their name as known by the VC
335 repository."""
337 def getInterestedUsers():
338 """Return a list of Users who will want to know about the results of
339 this build. This is a superset of getResponsibleUsers(): it adds
340 people who are interested in this build but who did not actually
341 make the Changes that went into it (build sheriffs, code-domain
342 owners)."""
344 def getNumber():
345 """Within each builder, each Build has a number. Return it."""
347 def getPreviousBuild():
348 """Convenience method. Returns None if the previous build is
349 unavailable."""
351 def getSteps():
352 """Return a list of IBuildStepStatus objects. For invariant builds
353 (those which always use the same set of Steps), this should always
354 return the complete list, however some of the steps may not have
355 started yet (step.getTimes()[0] will be None). For variant builds,
356 this may not be complete (asking again later may give you more of
357 them)."""
359 def getTimes():
360 """Returns a tuple of (start, end). 'start' and 'end' are the times
361 (seconds since the epoch) when the Build started and finished. If
362 the build is still running, 'end' will be None."""
364 # while the build is running, the following methods make sense.
365 # Afterwards they return None
367 def getETA():
368 """Returns the number of seconds from now in which the build is
369 expected to finish, or None if we can't make a guess. This guess will
370 be refined over time."""
372 def getCurrentStep():
373 """Return an IBuildStepStatus object representing the currently
374 active step."""
376 # Once you know the build has finished, the following methods are legal.
377 # Before ths build has finished, they all return None.
379 def getSlavename():
380 """Return the name of the buildslave which handled this build."""
382 def getText():
383 """Returns a list of strings to describe the build. These are
384 intended to be displayed in a narrow column. If more space is
385 available, the caller should join them together with spaces before
386 presenting them to the user."""
388 def getColor():
389 """Returns a single string with the color that should be used to
390 display the build. 'green', 'orange', or 'red' are the most likely
391 ones."""
393 def getResults():
394 """Return a constant describing the results of the build: one of the
395 constants in buildbot.status.builder: SUCCESS, WARNINGS, or
396 FAILURE."""
398 def getLogs():
399 """Return a list of logs that describe the build as a whole. Some
400 steps will contribute their logs, while others are are less important
401 and will only be accessible through the IBuildStepStatus objects.
402 Each log is an object which implements the IStatusLog interface."""
404 def getTestResults():
405 """Return a dictionary that maps test-name tuples to ITestResult
406 objects. This may return an empty or partially-filled dictionary
407 until the build has completed."""
409 # subscription interface
411 def subscribe(receiver, updateInterval=None):
412 """Register an IStatusReceiver to receive new status events. The
413 receiver will be given stepStarted and stepFinished messages. If
414 'updateInterval' is non-None, buildETAUpdate messages will be sent
415 every 'updateInterval' seconds."""
417 def unsubscribe(receiver):
418 """Unregister an IStatusReceiver. No further status messgaes will be
419 delivered."""
421 class ITestResult(Interface):
422 """I describe the results of a single unit test."""
424 def getName():
425 """Returns a tuple of strings which make up the test name. Tests may
426 be arranged in a hierarchy, so looking for common prefixes may be
427 useful."""
429 def getResults():
430 """Returns a constant describing the results of the test: SUCCESS,
431 WARNINGS, FAILURE."""
433 def getText():
434 """Returns a list of short strings which describe the results of the
435 test in slightly more detail. Suggested components include
436 'failure', 'error', 'passed', 'timeout'."""
438 def getLogs():
439 # in flux, it may be possible to provide more structured information
440 # like python Failure instances
441 """Returns a dictionary of test logs. The keys are strings like
442 'stdout', 'log', 'exceptions'. The values are strings."""
445 class IBuildStepStatus(Interface):
446 """I hold status for a single BuildStep."""
448 def getName():
449 """Returns a short string with the name of this step. This string
450 may have spaces in it."""
452 def getBuild():
453 """Returns the IBuildStatus object which contains this step."""
455 def getTimes():
456 """Returns a tuple of (start, end). 'start' and 'end' are the times
457 (seconds since the epoch) when the Step started and finished. If the
458 step has not yet started, 'start' will be None. If the step is still
459 running, 'end' will be None."""
461 def getExpectations():
462 """Returns a list of tuples (name, current, target). Each tuple
463 describes a single axis along which the step's progress can be
464 measured. 'name' is a string which describes the axis itself, like
465 'filesCompiled' or 'tests run' or 'bytes of output'. 'current' is a
466 number with the progress made so far, while 'target' is the value
467 that we expect (based upon past experience) to get to when the build
468 is finished.
470 'current' will change over time until the step is finished. It is
471 'None' until the step starts. When the build is finished, 'current'
472 may or may not equal 'target' (which is merely the expectation based
473 upon previous builds)."""
475 def getURLs():
476 """Returns a dictionary of URLs. Each key is a link name (a short
477 string, like 'results' or 'coverage'), and each value is a URL. These
478 links will be displayed along with the LogFiles.
481 def getLogs():
482 """Returns a list of IStatusLog objects. If the step has not yet
483 finished, this list may be incomplete (asking again later may give
484 you more of them)."""
487 def isFinished():
488 """Return a boolean. True means the step has finished, False means it
489 is still running."""
491 def waitUntilFinished():
492 """Return a Deferred that will fire when the step finishes. If the
493 step has already finished, this deferred will fire right away. The
494 callback is given this IBuildStepStatus instance as an argument."""
496 # while the step is running, the following methods make sense.
497 # Afterwards they return None
499 def getETA():
500 """Returns the number of seconds from now in which the step is
501 expected to finish, or None if we can't make a guess. This guess will
502 be refined over time."""
504 # Once you know the step has finished, the following methods are legal.
505 # Before ths step has finished, they all return None.
507 def getText():
508 """Returns a list of strings which describe the step. These are
509 intended to be displayed in a narrow column. If more space is
510 available, the caller should join them together with spaces before
511 presenting them to the user."""
513 def getColor():
514 """Returns a single string with the color that should be used to
515 display this step. 'green', 'orange', 'red' and 'yellow' are the
516 most likely ones."""
518 def getResults():
519 """Return a tuple describing the results of the step: (result,
520 strings). 'result' is one of the constants in
521 buildbot.status.builder: SUCCESS, WARNINGS, FAILURE, or SKIPPED.
522 'strings' is an optional list of strings that the step wants to
523 append to the overall build's results. These strings are usually
524 more terse than the ones returned by getText(): in particular,
525 successful Steps do not usually contribute any text to the overall
526 build."""
528 # subscription interface
530 def subscribe(receiver, updateInterval=10):
531 """Register an IStatusReceiver to receive new status events. The
532 receiver will be given logStarted and logFinished messages. It will
533 also be given a ETAUpdate message every 'updateInterval' seconds."""
535 def unsubscribe(receiver):
536 """Unregister an IStatusReceiver. No further status messgaes will be
537 delivered."""
539 class IStatusEvent(Interface):
540 """I represent a Builder Event, something non-Build related that can
541 happen to a Builder."""
543 def getTimes():
544 """Returns a tuple of (start, end) like IBuildStepStatus, but end==0
545 indicates that this is a 'point event', which has no duration.
546 SlaveConnect/Disconnect are point events. Ping is not: it starts
547 when requested and ends when the response (positive or negative) is
548 returned"""
550 def getText():
551 """Returns a list of strings which describe the event. These are
552 intended to be displayed in a narrow column. If more space is
553 available, the caller should join them together with spaces before
554 presenting them to the user."""
556 def getColor():
557 """Returns a single string with the color that should be used to
558 display this event. 'red' and 'yellow' are the most likely ones."""
561 LOG_CHANNEL_STDOUT = 0
562 LOG_CHANNEL_STDERR = 1
563 LOG_CHANNEL_HEADER = 2
565 class IStatusLog(Interface):
566 """I represent a single Log, which is a growing list of text items that
567 contains some kind of output for a single BuildStep. I might be finished,
568 in which case this list has stopped growing.
570 Each Log has a name, usually something boring like 'log' or 'output'.
571 These names are not guaranteed to be unique, however they are usually
572 chosen to be useful within the scope of a single step (i.e. the Compile
573 step might produce both 'log' and 'warnings'). The name may also have
574 spaces. If you want something more globally meaningful, at least within a
575 given Build, try::
577 '%s.%s' % (log.getStep.getName(), log.getName())
579 The Log can be presented as plain text, or it can be accessed as a list
580 of items, each of which has a channel indicator (header, stdout, stderr)
581 and a text chunk. An HTML display might represent the interleaved
582 channels with different styles, while a straight download-the-text
583 interface would just want to retrieve a big string.
585 The 'header' channel is used by ShellCommands to prepend a note about
586 which command is about to be run ('running command FOO in directory
587 DIR'), and append another note giving the exit code of the process.
589 Logs can be streaming: if the Log has not yet finished, you can
590 subscribe to receive new chunks as they are added.
592 A ShellCommand will have a Log associated with it that gathers stdout
593 and stderr. Logs may also be created by parsing command output or
594 through other synthetic means (grepping for all the warnings in a
595 compile log, or listing all the test cases that are going to be run).
596 Such synthetic Logs are usually finished as soon as they are created."""
599 def getName():
600 """Returns a short string with the name of this log, probably 'log'.
603 def getStep():
604 """Returns the IBuildStepStatus which owns this log."""
605 # TODO: can there be non-Step logs?
607 def isFinished():
608 """Return a boolean. True means the log has finished and is closed,
609 False means it is still open and new chunks may be added to it."""
611 def waitUntilFinished():
612 """Return a Deferred that will fire when the log is closed. If the
613 log has already finished, this deferred will fire right away. The
614 callback is given this IStatusLog instance as an argument."""
616 def subscribe(receiver, catchup):
617 """Register an IStatusReceiver to receive chunks (with logChunk) as
618 data is added to the Log. If you use this, you will also want to use
619 waitUntilFinished to find out when the listener can be retired.
620 Subscribing to a closed Log is a no-op.
622 If 'catchup' is True, the receiver will immediately be sent a series
623 of logChunk messages to bring it up to date with the partially-filled
624 log. This allows a status client to join a Log already in progress
625 without missing any data. If the Log has already finished, it is too
626 late to catch up: just do getText() instead.
628 If the Log is very large, the receiver will be called many times with
629 a lot of data. There is no way to throttle this data. If the receiver
630 is planning on sending the data on to somewhere else, over a narrow
631 connection, you can get a throttleable subscription by using
632 C{subscribeConsumer} instead."""
634 def unsubscribe(receiver):
635 """Remove a receiver previously registered with subscribe(). Attempts
636 to remove a receiver which was not previously registered is a no-op.
639 def subscribeConsumer(consumer):
640 """Register an L{IStatusLogConsumer} to receive all chunks of the
641 logfile, including all the old entries and any that will arrive in
642 the future. The consumer will first have their C{registerProducer}
643 method invoked with a reference to an object that can be told
644 C{pauseProducing}, C{resumeProducing}, and C{stopProducing}. Then the
645 consumer's C{writeChunk} method will be called repeatedly with each
646 (channel, text) tuple in the log, starting with the very first. The
647 consumer will be notified with C{finish} when the log has been
648 exhausted (which can only happen when the log is finished). Note that
649 a small amount of data could be written via C{writeChunk} even after
650 C{pauseProducing} has been called.
652 To unsubscribe the consumer, use C{producer.stopProducing}."""
654 # once the log has finished, the following methods make sense. They can
655 # be called earlier, but they will only return the contents of the log up
656 # to the point at which they were called. You will lose items that are
657 # added later. Use C{subscribe} or C{subscribeConsumer} to avoid missing
658 # anything.
660 def hasContents():
661 """Returns True if the LogFile still has contents available. Returns
662 False for logs that have been pruned. Clients should test this before
663 offering to show the contents of any log."""
665 def getText():
666 """Return one big string with the contents of the Log. This merges
667 all non-header chunks together."""
669 def readlines(channel=LOG_CHANNEL_STDOUT):
670 """Read lines from one channel of the logfile. This returns an
671 iterator that will provide single lines of text (including the
672 trailing newline).
675 def getTextWithHeaders():
676 """Return one big string with the contents of the Log. This merges
677 all chunks (including headers) together."""
679 def getChunks():
680 """Generate a list of (channel, text) tuples. 'channel' is a number,
681 0 for stdout, 1 for stderr, 2 for header. (note that stderr is merged
682 into stdout if PTYs are in use)."""
684 class IStatusLogConsumer(Interface):
685 """I am an object which can be passed to IStatusLog.subscribeConsumer().
686 I represent a target for writing the contents of an IStatusLog. This
687 differs from a regular IStatusReceiver in that it can pause the producer.
688 This makes it more suitable for use in streaming data over network
689 sockets, such as an HTTP request. Note that the consumer can only pause
690 the producer until it has caught up with all the old data. After that
691 point, C{pauseProducing} is ignored and all new output from the log is
692 sent directoy to the consumer."""
694 def registerProducer(producer, streaming):
695 """A producer is being hooked up to this consumer. The consumer only
696 has to handle a single producer. It should send .pauseProducing and
697 .resumeProducing messages to the producer when it wants to stop or
698 resume the flow of data. 'streaming' will be set to True because the
699 producer is always a PushProducer.
702 def unregisterProducer():
703 """The previously-registered producer has been removed. No further
704 pauseProducing or resumeProducing calls should be made. The consumer
705 should delete its reference to the Producer so it can be released."""
707 def writeChunk(chunk):
708 """A chunk (i.e. a tuple of (channel, text)) is being written to the
709 consumer."""
711 def finish():
712 """The log has finished sending chunks to the consumer."""
714 class IStatusReceiver(Interface):
715 """I am an object which can receive build status updates. I may be
716 subscribed to an IStatus, an IBuilderStatus, or an IBuildStatus."""
718 def buildsetSubmitted(buildset):
719 """A new BuildSet has been submitted to the buildmaster.
721 @type buildset: implementor of L{IBuildSetStatus}
724 def builderAdded(builderName, builder):
726 A new Builder has just been added. This method may return an
727 IStatusReceiver (probably 'self') which will be subscribed to receive
728 builderChangedState and buildStarted/Finished events.
730 @type builderName: string
731 @type builder: L{buildbot.status.builder.BuilderStatus}
732 @rtype: implementor of L{IStatusReceiver}
735 def builderChangedState(builderName, state):
736 """Builder 'builderName' has changed state. The possible values for
737 'state' are 'offline', 'idle', and 'building'."""
739 def buildStarted(builderName, build):
740 """Builder 'builderName' has just started a build. The build is an
741 object which implements IBuildStatus, and can be queried for more
742 information.
744 This method may return an IStatusReceiver (it could even return
745 'self'). If it does so, stepStarted and stepFinished methods will be
746 invoked on the object for the steps of this one build. This is a
747 convenient way to subscribe to all build steps without missing any.
748 This receiver will automatically be unsubscribed when the build
749 finishes.
751 It can also return a tuple of (IStatusReceiver, interval), in which
752 case buildETAUpdate messages are sent ever 'interval' seconds, in
753 addition to the stepStarted and stepFinished messages."""
755 def buildETAUpdate(build, ETA):
756 """This is a periodic update on the progress this Build has made
757 towards completion."""
759 def stepStarted(build, step):
760 """A step has just started. 'step' is the IBuildStepStatus which
761 represents the step: it can be queried for more information.
763 This method may return an IStatusReceiver (it could even return
764 'self'). If it does so, logStarted and logFinished methods will be
765 invoked on the object for logs created by this one step. This
766 receiver will be automatically unsubscribed when the step finishes.
768 Alternatively, the method may return a tuple of an IStatusReceiver
769 and an integer named 'updateInterval'. In addition to
770 logStarted/logFinished messages, it will also receive stepETAUpdate
771 messages about every updateInterval seconds."""
773 def stepETAUpdate(build, step, ETA, expectations):
774 """This is a periodic update on the progress this Step has made
775 towards completion. It gets an ETA (in seconds from the present) of
776 when the step ought to be complete, and a list of expectation tuples
777 (as returned by IBuildStepStatus.getExpectations) with more detailed
778 information."""
780 def logStarted(build, step, log):
781 """A new Log has been started, probably because a step has just
782 started running a shell command. 'log' is the IStatusLog object
783 which can be queried for more information.
785 This method may return an IStatusReceiver (such as 'self'), in which
786 case the target's logChunk method will be invoked as text is added to
787 the logfile. This receiver will automatically be unsubsribed when the
788 log finishes."""
790 def logChunk(build, step, log, channel, text):
791 """Some text has been added to this log. 'channel' is one of
792 LOG_CHANNEL_STDOUT, LOG_CHANNEL_STDERR, or LOG_CHANNEL_HEADER, as
793 defined in IStatusLog.getChunks."""
795 def logFinished(build, step, log):
796 """A Log has been closed."""
798 def stepFinished(build, step, results):
799 """A step has just finished. 'results' is the result tuple described
800 in IBuildStepStatus.getResults."""
802 def buildFinished(builderName, build, results):
804 A build has just finished. 'results' is the result tuple described
805 in L{IBuildStatus.getResults}.
807 @type builderName: string
808 @type build: L{buildbot.status.builder.BuildStatus}
809 @type results: tuple
812 def builderRemoved(builderName):
813 """The Builder has been removed."""
815 class IControl(Interface):
816 def addChange(change):
817 """Add a change to all builders. Each Builder will decide for
818 themselves whether the change is interesting or not, and may initiate
819 a build as a result."""
821 def submitBuildSet(buildset):
822 """Submit a BuildSet object, which will eventually be run on all of
823 the builders listed therein."""
825 def getBuilder(name):
826 """Retrieve the IBuilderControl object for the given Builder."""
828 class IBuilderControl(Interface):
829 def forceBuild(who, reason):
830 """DEPRECATED, please use L{requestBuild} instead.
832 Start a build of the latest sources. If 'who' is not None, it is
833 string with the name of the user who is responsible for starting the
834 build: they will be added to the 'interested users' list (so they may
835 be notified via email or another Status object when it finishes).
836 'reason' is a string describing why this user requested the build.
838 The results of forced builds are always sent to the Interested Users,
839 even if the Status object would normally only send results upon
840 failures.
842 forceBuild() may raise L{NoSlaveError} or L{BuilderInUseError} if it
843 cannot start the build.
845 forceBuild() returns a Deferred which fires with an L{IBuildControl}
846 object that can be used to further control the new build, or from
847 which an L{IBuildStatus} object can be obtained."""
849 def requestBuild(request):
850 """Queue a L{buildbot.process.base.BuildRequest} object for later
851 building."""
853 def requestBuildSoon(request):
854 """Submit a BuildRequest like requestBuild, but raise a
855 L{buildbot.interfaces.NoSlaveError} if no slaves are currently
856 available, so it cannot be used to queue a BuildRequest in the hopes
857 that a slave will eventually connect. This method is appropriate for
858 use by things like the web-page 'Force Build' button."""
860 def resubmitBuild(buildStatus, reason="<rebuild, no reason given>"):
861 """Rebuild something we've already built before. This submits a
862 BuildRequest to our Builder using the same SourceStamp as the earlier
863 build. This has no effect (but may eventually raise an exception) if
864 this Build has not yet finished."""
866 def getPendingBuilds():
867 """Return a list of L{IBuildRequestControl} objects for this Builder.
868 Each one corresponds to a pending build that has not yet started (due
869 to a scarcity of build slaves). These upcoming builds can be canceled
870 through the control object."""
872 def getBuild(number):
873 """Attempt to return an IBuildControl object for the given build.
874 Returns None if no such object is available. This will only work for
875 the build that is currently in progress: once the build finishes,
876 there is nothing to control anymore."""
878 def ping(timeout=30):
879 """Attempt to contact the slave and see if it is still alive. This
880 returns a Deferred which fires with either True (the slave is still
881 alive) or False (the slave did not respond). As a side effect, adds
882 an event to this builder's column in the waterfall display
883 containing the results of the ping."""
884 # TODO: this ought to live in ISlaveControl, maybe with disconnect()
885 # or something. However the event that is emitted is most useful in
886 # the Builder column, so it kinda fits here too.
888 class IBuildRequestControl(Interface):
889 def subscribe(observer):
890 """Register a callable that will be invoked (with a single
891 IBuildControl object) for each Build that is created to satisfy this
892 request. There may be multiple Builds created in an attempt to handle
893 the request: they may be interrupted by the user or abandoned due to
894 a lost slave. The last Build (the one which actually gets to run to
895 completion) is said to 'satisfy' the BuildRequest. The observer will
896 be called once for each of these Builds, both old and new."""
897 def unsubscribe(observer):
898 """Unregister the callable that was registered with subscribe()."""
899 def cancel():
900 """Remove the build from the pending queue. Has no effect if the
901 build has already been started."""
903 class IBuildControl(Interface):
904 def getStatus():
905 """Return an IBuildStatus object for the Build that I control."""
906 def stopBuild(reason="<no reason given>"):
907 """Halt the build. This has no effect if the build has already
908 finished."""
910 class ILogFile(Interface):
911 """This is the internal interface to a LogFile, used by the BuildStep to
912 write data into the log.
914 def addStdout(data):
915 pass
916 def addStderr(data):
917 pass
918 def addHeader(data):
919 pass
920 def finish():
921 """The process that is feeding the log file has finished, and no
922 further data will be added. This closes the logfile."""
924 class ILogObserver(Interface):
925 """Objects which provide this interface can be used in a BuildStep to
926 watch the output of a LogFile and parse it incrementally.
929 # internal methods
930 def setStep(step):
931 pass
932 def setLog(log):
933 pass
935 # methods called by the LogFile
936 def logChunk(build, step, log, channel, text):
937 pass