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