Package buildbot :: Package steps :: Package source :: Module oldsource
[frames] | no frames]

Source Code for Module buildbot.steps.source.oldsource

   1  # This file is part of Buildbot.  Buildbot is free software: you can 
   2  # redistribute it and/or modify it under the terms of the GNU General Public 
   3  # License as published by the Free Software Foundation, version 2. 
   4  # 
   5  # This program is distributed in the hope that it will be useful, but WITHOUT 
   6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
   7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
   8  # details. 
   9  # 
  10  # You should have received a copy of the GNU General Public License along with 
  11  # this program; if not, write to the Free Software Foundation, Inc., 51 
  12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
  13  # 
  14  # Copyright Buildbot Team Members 
  15   
  16   
  17  from warnings import warn 
  18  from email.Utils import formatdate 
  19  from twisted.python import log 
  20  from twisted.internet import defer 
  21  from zope.interface import implements 
  22  from buildbot.process.buildstep import LoggingBuildStep, RemoteCommand 
  23  from buildbot.interfaces import BuildSlaveTooOldError, IRenderable 
  24  from buildbot.status.builder import SKIPPED 
  25   
26 -class _ComputeRepositoryURL(object):
27 implements(IRenderable) 28
29 - def __init__(self, repository):
31
32 - def getRenderingFor(self, props):
33 ''' 34 Helper function that the repository URL based on the parameter the 35 source step took and the Change 'repository' property 36 ''' 37 38 build = props.getBuild() 39 assert build is not None, "Build should be available *during* a build?" 40 s = build.getSourceStamp() 41 42 repository = self.repository 43 44 if not repository: 45 return str(s.repository) 46 else: 47 if callable(repository): 48 return str(props.render(repository(s.repository))) 49 elif isinstance(repository, dict): 50 return str(props.render(repository.get(s.repository))) 51 elif isinstance(repository, str) or isinstance(repository, unicode): 52 try: 53 return str(repository % s.repository) 54 except TypeError: 55 # that's the backward compatibility case 56 return props.render(repository) 57 else: 58 return str(props.render(repository))
59
60 -class Source(LoggingBuildStep):
61 """This is a base class to generate a source tree in the buildslave. 62 Each version control system has a specialized subclass, and is expected 63 to override __init__ and implement computeSourceRevision() and 64 startVC(). The class as a whole builds up the self.args dictionary, then 65 starts a RemoteCommand with those arguments. 66 """ 67 68 renderables = [ 'workdir', 'description', 'descriptionDone' ] 69 description = None # set this to a list of short strings to override 70 descriptionDone = None # alternate description when the step is complete 71 72 # if the checkout fails, there's no point in doing anything else 73 haltOnFailure = True 74 flunkOnFailure = True 75 notReally = False 76 77 branch = None # the default branch, should be set in __init__ 78
79 - def __init__(self, workdir=None, mode='update', alwaysUseLatest=False, 80 timeout=20*60, retry=None, env=None, logEnviron=True, 81 description=None, descriptionDone=None, **kwargs):
82 """ 83 @type workdir: string 84 @param workdir: local directory (relative to the Builder's root) 85 where the tree should be placed 86 87 @type mode: string 88 @param mode: the kind of VC operation that is desired: 89 - 'update': specifies that the checkout/update should be 90 performed directly into the workdir. Each build is performed 91 in the same directory, allowing for incremental builds. This 92 minimizes disk space, bandwidth, and CPU time. However, it 93 may encounter problems if the build process does not handle 94 dependencies properly (if you must sometimes do a 'clean 95 build' to make sure everything gets compiled), or if source 96 files are deleted but generated files can influence test 97 behavior (e.g. python's .pyc files), or when source 98 directories are deleted but generated files prevent CVS from 99 removing them. When used with a patched checkout, from a 100 previous buildbot try for instance, it will try to "revert" 101 the changes first and will do a clobber if it is unable to 102 get a clean checkout. The behavior is SCM-dependent. 103 104 - 'copy': specifies that the source-controlled workspace 105 should be maintained in a separate directory (called the 106 'copydir'), using checkout or update as necessary. For each 107 build, a new workdir is created with a copy of the source 108 tree (rm -rf workdir; cp -R -P -p copydir workdir). This 109 doubles the disk space required, but keeps the bandwidth low 110 (update instead of a full checkout). A full 'clean' build 111 is performed each time. This avoids any generated-file 112 build problems, but is still occasionally vulnerable to 113 problems such as a CVS repository being manually rearranged 114 (causing CVS errors on update) which are not an issue with 115 a full checkout. 116 117 - 'clobber': specifies that the working directory should be 118 deleted each time, necessitating a full checkout for each 119 build. This insures a clean build off a complete checkout, 120 avoiding any of the problems described above, but is 121 bandwidth intensive, as the whole source tree must be 122 pulled down for each build. 123 124 - 'export': is like 'clobber', except that e.g. the 'cvs 125 export' command is used to create the working directory. 126 This command removes all VC metadata files (the 127 CVS/.svn/{arch} directories) from the tree, which is 128 sometimes useful for creating source tarballs (to avoid 129 including the metadata in the tar file). Not all VC systems 130 support export. 131 132 @type alwaysUseLatest: boolean 133 @param alwaysUseLatest: whether to always update to the most 134 recent available sources for this build. 135 136 Normally the Source step asks its Build for a list of all 137 Changes that are supposed to go into the build, then computes a 138 'source stamp' (revision number or timestamp) that will cause 139 exactly that set of changes to be present in the checked out 140 tree. This is turned into, e.g., 'cvs update -D timestamp', or 141 'svn update -r revnum'. If alwaysUseLatest=True, bypass this 142 computation and always update to the latest available sources 143 for each build. 144 145 The source stamp helps avoid a race condition in which someone 146 commits a change after the master has decided to start a build 147 but before the slave finishes checking out the sources. At best 148 this results in a build which contains more changes than the 149 buildmaster thinks it has (possibly resulting in the wrong 150 person taking the blame for any problems that result), at worst 151 is can result in an incoherent set of sources (splitting a 152 non-atomic commit) which may not build at all. 153 154 @type retry: tuple of ints (delay, repeats) (or None) 155 @param retry: if provided, VC update failures are re-attempted up 156 to REPEATS times, with DELAY seconds between each 157 attempt. Some users have slaves with poor connectivity 158 to their VC repository, and they say that up to 80% of 159 their build failures are due to transient network 160 failures that could be handled by simply retrying a 161 couple times. 162 163 @type logEnviron: boolean 164 @param logEnviron: If this option is true (the default), then the 165 step's logfile will describe the environment 166 variables on the slave. In situations where the 167 environment is not relevant and is long, it may 168 be easier to set logEnviron=False. 169 170 """ 171 172 LoggingBuildStep.__init__(self, **kwargs) 173 self.addFactoryArguments(workdir=workdir, 174 mode=mode, 175 alwaysUseLatest=alwaysUseLatest, 176 timeout=timeout, 177 retry=retry, 178 logEnviron=logEnviron, 179 env=env, 180 description=description, 181 descriptionDone=descriptionDone 182 ) 183 184 assert mode in ("update", "copy", "clobber", "export") 185 if retry: 186 delay, repeats = retry 187 assert isinstance(repeats, int) 188 assert repeats > 0 189 self.args = {'mode': mode, 190 'timeout': timeout, 191 'retry': retry, 192 'patch': None, # set during .start 193 } 194 # This will get added to args later, after properties are rendered 195 self.workdir = workdir 196 197 self.alwaysUseLatest = alwaysUseLatest 198 199 self.logEnviron = logEnviron 200 self.env = env 201 202 descriptions_for_mode = { 203 "clobber": "checkout", 204 "export": "exporting"} 205 descriptionDones_for_mode = { 206 "clobber": "checkout", 207 "export": "export"} 208 if description: 209 self.description = description 210 else: 211 self.description = [ 212 descriptions_for_mode.get(mode, "updating")] 213 if isinstance(self.description, str): 214 self.description = [self.description] 215 216 if descriptionDone: 217 self.descriptionDone = descriptionDone 218 else: 219 self.descriptionDone = [ 220 descriptionDones_for_mode.get(mode, "update")] 221 if isinstance(self.descriptionDone, str): 222 self.descriptionDone = [self.descriptionDone]
223
224 - def setStepStatus(self, step_status):
226
227 - def setDefaultWorkdir(self, workdir):
228 self.workdir = self.workdir or workdir
229
230 - def describe(self, done=False):
231 if done: 232 return self.descriptionDone 233 return self.description
234
235 - def computeSourceRevision(self, changes):
236 """Each subclass must implement this method to do something more 237 precise than -rHEAD every time. For version control systems that use 238 repository-wide change numbers (SVN, P4), this can simply take the 239 maximum such number from all the changes involved in this build. For 240 systems that do not (CVS), it needs to create a timestamp based upon 241 the latest Change, the Build's treeStableTimer, and an optional 242 self.checkoutDelay value.""" 243 return None
244
245 - def getRepository(self):
246 """ Identify the unique repository for this step """ 247 return None
248
249 - def start(self):
250 if self.notReally: 251 log.msg("faking %s checkout/update" % self.name) 252 self.step_status.setText(["fake", self.name, "successful"]) 253 self.addCompleteLog("log", 254 "Faked %s checkout/update 'successful'\n" \ 255 % self.name) 256 return SKIPPED 257 258 # Allow workdir to be WithProperties 259 self.args['workdir'] = self.workdir 260 261 if not self.alwaysUseLatest: 262 # what source stamp would this build like to use? 263 id = self.getRepository() 264 s = self.build.getSourceStamp(id) 265 266 # if branch is None, then use the Step's "default" branch 267 branch = s.branch or self.branch 268 # if revision is None, use the latest sources (-rHEAD) 269 revision = s.revision 270 if not revision: 271 revision = self.computeSourceRevision(s.changes) 272 # the revision property is currently None, so set it to something 273 # more interesting 274 if revision is not None: 275 self.setProperty('revision', str(revision), "Source") 276 277 # if patch is None, then do not patch the tree after checkout 278 279 # 'patch' is None or a tuple of (patchlevel, diff, root) 280 # root is optional. 281 patch = s.patch 282 if patch: 283 self.addCompleteLog("patch", patch[1]) 284 else: 285 revision = None 286 branch = self.branch 287 patch = None 288 289 self.args['logEnviron'] = self.logEnviron 290 self.args['env'] = self.env 291 self.startVC(branch, revision, patch)
292
293 - def commandComplete(self, cmd):
294 if cmd.updates.has_key("got_revision"): 295 got_revision = cmd.updates["got_revision"][-1] 296 if got_revision is not None: 297 self.setProperty("got_revision", str(got_revision), "Source")
298 299 300
301 -class BK(Source):
302 """I perform BitKeeper checkout/update operations.""" 303 304 name = 'bk' 305 306 renderables = [ 'bkurl', 'baseURL' ] 307
308 - def __init__(self, bkurl=None, baseURL=None, 309 directory=None, extra_args=None, **kwargs):
310 """ 311 @type bkurl: string 312 @param bkurl: the URL which points to the BitKeeper server. 313 314 @type baseURL: string 315 @param baseURL: if branches are enabled, this is the base URL to 316 which a branch name will be appended. It should 317 probably end in a slash. Use exactly one of 318 C{bkurl} and C{baseURL}. 319 """ 320 321 self.bkurl = _ComputeRepositoryURL(bkurl) 322 self.baseURL = _ComputeRepositoryURL(baseURL) 323 self.extra_args = extra_args 324 325 Source.__init__(self, **kwargs) 326 self.addFactoryArguments(bkurl=bkurl, 327 baseURL=baseURL, 328 directory=directory, 329 extra_args=extra_args, 330 ) 331 332 if bkurl and baseURL: 333 raise ValueError("you must use exactly one of bkurl and baseURL")
334 335
336 - def computeSourceRevision(self, changes):
337 return changes.revision
338 339
340 - def startVC(self, branch, revision, patch):
341 342 warnings = [] 343 slavever = self.slaveVersion("bk") 344 if not slavever: 345 m = "slave does not have the 'bk' command" 346 raise BuildSlaveTooOldError(m) 347 348 if self.bkurl: 349 assert not branch # we need baseURL= to use branches 350 self.args['bkurl'] = self.bkurl 351 else: 352 self.args['bkurl'] = self.baseURL + branch 353 self.args['revision'] = revision 354 self.args['patch'] = patch 355 self.args['branch'] = branch 356 if self.extra_args is not None: 357 self.args['extra_args'] = self.extra_args 358 359 revstuff = [] 360 revstuff.append("[branch]") 361 if revision is not None: 362 revstuff.append("r%s" % revision) 363 if patch is not None: 364 revstuff.append("[patch]") 365 self.description.extend(revstuff) 366 self.descriptionDone.extend(revstuff) 367 368 cmd = RemoteCommand("bk", self.args) 369 self.startCommand(cmd, warnings)
370 371 372
373 -class CVS(Source):
374 """I do CVS checkout/update operations. 375 376 Note: if you are doing anonymous/pserver CVS operations, you will need 377 to manually do a 'cvs login' on each buildslave before the slave has any 378 hope of success. XXX: fix then, take a cvs password as an argument and 379 figure out how to do a 'cvs login' on each build 380 """ 381 382 name = "cvs" 383 384 renderables = [ "cvsroot" ] 385 386 #progressMetrics = ('output',) 387 # 388 # additional things to track: update gives one stderr line per directory 389 # (starting with 'cvs server: Updating ') (and is fairly stable if files 390 # is empty), export gives one line per directory (starting with 'cvs 391 # export: Updating ') and another line per file (starting with U). Would 392 # be nice to track these, requires grepping LogFile data for lines, 393 # parsing each line. Might be handy to have a hook in LogFile that gets 394 # called with each complete line. 395
396 - def __init__(self, cvsroot=None, cvsmodule="", 397 global_options=[], branch=None, checkoutDelay=None, 398 checkout_options=[], export_options=[], extra_options=[], 399 login=None, 400 **kwargs):
401 402 """ 403 @type cvsroot: string 404 @param cvsroot: CVS Repository from which the source tree should 405 be obtained. '/home/warner/Repository' for local 406 or NFS-reachable repositories, 407 ':pserver:anon@foo.com:/cvs' for anonymous CVS, 408 'user@host.com:/cvs' for non-anonymous CVS or 409 CVS over ssh. Lots of possibilities, check the 410 CVS documentation for more. 411 412 @type cvsmodule: string 413 @param cvsmodule: subdirectory of CVS repository that should be 414 retrieved 415 416 @type login: string or None 417 @param login: if not None, a string which will be provided as a 418 password to the 'cvs login' command, used when a 419 :pserver: method is used to access the repository. 420 This login is only needed once, but must be run 421 each time (just before the CVS operation) because 422 there is no way for the buildslave to tell whether 423 it was previously performed or not. 424 425 @type branch: string 426 @param branch: the default branch name, will be used in a '-r' 427 argument to specify which branch of the source tree 428 should be used for this checkout. Defaults to None, 429 which means to use 'HEAD'. 430 431 @type checkoutDelay: int or None 432 @param checkoutDelay: if not None, the number of seconds to put 433 between the last known Change and the 434 timestamp given to the -D argument. This 435 defaults to exactly half of the parent 436 Build's .treeStableTimer, but it could be 437 set to something else if your CVS change 438 notification has particularly weird 439 latency characteristics. 440 441 @type global_options: list of strings 442 @param global_options: these arguments are inserted in the cvs 443 command line, before the 444 'checkout'/'update' command word. See 445 'cvs --help-options' for a list of what 446 may be accepted here. ['-r'] will make 447 the checked out files read only. ['-r', 448 '-R'] will also assume the repository is 449 read-only (I assume this means it won't 450 use locks to insure atomic access to the 451 ,v files). 452 453 @type checkout_options: list of strings 454 @param checkout_options: these arguments are inserted in the cvs 455 command line, after 'checkout' but before 456 branch or revision specifiers. 457 458 @type export_options: list of strings 459 @param export_options: these arguments are inserted in the cvs 460 command line, after 'export' but before 461 branch or revision specifiers. 462 463 @type extra_options: list of strings 464 @param extra_options: these arguments are inserted in the cvs 465 command line, after 'checkout' or 'export' but before 466 branch or revision specifiers. 467 """ 468 469 self.checkoutDelay = checkoutDelay 470 self.branch = branch 471 self.cvsroot = _ComputeRepositoryURL(cvsroot) 472 473 Source.__init__(self, **kwargs) 474 self.addFactoryArguments(cvsroot=cvsroot, 475 cvsmodule=cvsmodule, 476 global_options=global_options, 477 checkout_options=checkout_options, 478 export_options=export_options, 479 extra_options=extra_options, 480 branch=branch, 481 checkoutDelay=checkoutDelay, 482 login=login, 483 ) 484 485 self.args.update({'cvsmodule': cvsmodule, 486 'global_options': global_options, 487 'checkout_options':checkout_options, 488 'export_options':export_options, 489 'extra_options':extra_options, 490 'login': login, 491 })
492
493 - def computeSourceRevision(self, changes):
494 if not changes: 495 return None 496 lastChange = max([c.when for c in changes]) 497 if self.checkoutDelay is not None: 498 when = lastChange + self.checkoutDelay 499 else: 500 lastSubmit = max([br.submittedAt for br in self.build.requests]) 501 when = (lastChange + lastSubmit) / 2 502 return formatdate(when)
503
504 - def startVC(self, branch, revision, patch):
505 if self.slaveVersionIsOlderThan("cvs", "1.39"): 506 # the slave doesn't know to avoid re-using the same sourcedir 507 # when the branch changes. We have no way of knowing which branch 508 # the last build used, so if we're using a non-default branch and 509 # either 'update' or 'copy' modes, it is safer to refuse to 510 # build, and tell the user they need to upgrade the buildslave. 511 if (branch != self.branch 512 and self.args['mode'] in ("update", "copy")): 513 m = ("This buildslave (%s) does not know about multiple " 514 "branches, and using mode=%s would probably build the " 515 "wrong tree. " 516 "Refusing to build. Please upgrade the buildslave to " 517 "buildbot-0.7.0 or newer." % (self.build.slavename, 518 self.args['mode'])) 519 log.msg(m) 520 raise BuildSlaveTooOldError(m) 521 522 if self.slaveVersionIsOlderThan("cvs", "2.10"): 523 if self.args['extra_options'] or self.args['export_options']: 524 m = ("This buildslave (%s) does not support export_options " 525 "or extra_options arguments to the CVS step." 526 % (self.build.slavename)) 527 log.msg(m) 528 raise BuildSlaveTooOldError(m) 529 # the unwanted args are empty, and will probably be ignored by 530 # the slave, but delete them just to be safe 531 del self.args['export_options'] 532 del self.args['extra_options'] 533 534 if branch is None: 535 branch = "HEAD" 536 self.args['cvsroot'] = self.cvsroot 537 self.args['branch'] = branch 538 self.args['revision'] = revision 539 self.args['patch'] = patch 540 541 if self.args['branch'] == "HEAD" and self.args['revision']: 542 # special case. 'cvs update -r HEAD -D today' gives no files 543 # TODO: figure out why, see if it applies to -r BRANCH 544 self.args['branch'] = None 545 546 # deal with old slaves 547 warnings = [] 548 slavever = self.slaveVersion("cvs", "old") 549 550 if slavever == "old": 551 # 0.5.0 552 if self.args['mode'] == "export": 553 self.args['export'] = 1 554 elif self.args['mode'] == "clobber": 555 self.args['clobber'] = 1 556 elif self.args['mode'] == "copy": 557 self.args['copydir'] = "source" 558 self.args['tag'] = self.args['branch'] 559 assert not self.args['patch'] # 0.5.0 slave can't do patch 560 561 cmd = RemoteCommand("cvs", self.args) 562 self.startCommand(cmd, warnings)
563 564
565 -class SVN(Source):
566 """I perform Subversion checkout/update operations.""" 567 568 name = 'svn' 569 branch_placeholder = '%%BRANCH%%' 570 571 renderables = [ 'svnurl', 'baseURL' ] 572
573 - def __init__(self, svnurl=None, baseURL=None, defaultBranch=None, 574 directory=None, username=None, password=None, 575 extra_args=None, keep_on_purge=None, ignore_ignores=None, 576 always_purge=None, depth=None, **kwargs):
577 """ 578 @type svnurl: string 579 @param svnurl: the URL which points to the Subversion server, 580 combining the access method (HTTP, ssh, local file), 581 the repository host/port, the repository path, the 582 sub-tree within the repository, and the branch to 583 check out. Use exactly one of C{svnurl} and C{baseURL}. 584 585 @param baseURL: if branches are enabled, this is the base URL to 586 which a branch name will be appended. It should 587 probably end in a slash. Use exactly one of 588 C{svnurl} and C{baseURL}. 589 590 @param defaultBranch: if branches are enabled, this is the branch 591 to use if the Build does not specify one 592 explicitly. It will simply be appended 593 to C{baseURL} and the result handed to 594 the SVN command. 595 596 @type username: string 597 @param username: username to pass to svn's --username 598 599 @type password: string 600 @param password: password to pass to svn's --password 601 """ 602 603 if not 'workdir' in kwargs and directory is not None: 604 # deal with old configs 605 warn("Please use workdir=, not directory=", DeprecationWarning) 606 kwargs['workdir'] = directory 607 608 self.svnurl = svnurl and _ComputeRepositoryURL(svnurl) 609 self.baseURL = _ComputeRepositoryURL(baseURL) 610 self.branch = defaultBranch 611 self.username = username 612 self.password = password 613 self.extra_args = extra_args 614 self.keep_on_purge = keep_on_purge 615 self.ignore_ignores = ignore_ignores 616 self.always_purge = always_purge 617 self.depth = depth 618 619 Source.__init__(self, **kwargs) 620 self.addFactoryArguments(svnurl=svnurl, 621 baseURL=baseURL, 622 defaultBranch=defaultBranch, 623 directory=directory, 624 username=username, 625 password=password, 626 extra_args=extra_args, 627 keep_on_purge=keep_on_purge, 628 ignore_ignores=ignore_ignores, 629 always_purge=always_purge, 630 depth=depth, 631 ) 632 633 if svnurl and baseURL: 634 raise ValueError("you must use either svnurl OR baseURL")
635
636 - def computeSourceRevision(self, changes):
637 if not changes or None in [c.revision for c in changes]: 638 return None 639 lastChange = max([int(c.revision) for c in changes]) 640 return lastChange
641
642 - def checkCompatibility(self):
643 ''' Handle compatibility between old slaves/svn clients ''' 644 645 slavever = self.slaveVersion("svn", "old") 646 647 if not slavever: 648 m = "slave does not have the 'svn' command" 649 raise BuildSlaveTooOldError(m) 650 651 if self.slaveVersionIsOlderThan("svn", "1.39"): 652 # the slave doesn't know to avoid re-using the same sourcedir 653 # when the branch changes. We have no way of knowing which branch 654 # the last build used, so if we're using a non-default branch and 655 # either 'update' or 'copy' modes, it is safer to refuse to 656 # build, and tell the user they need to upgrade the buildslave. 657 if (self.args['branch'] != self.branch 658 and self.args['mode'] in ("update", "copy")): 659 m = ("This buildslave (%s) does not know about multiple " 660 "branches, and using mode=%s would probably build the " 661 "wrong tree. " 662 "Refusing to build. Please upgrade the buildslave to " 663 "buildbot-0.7.0 or newer." % (self.build.slavename, 664 self.args['mode'])) 665 raise BuildSlaveTooOldError(m) 666 667 if (self.depth is not None) and self.slaveVersionIsOlderThan("svn","2.9"): 668 m = ("This buildslave (%s) does not support svn depth " 669 "arguments. Refusing to build. " 670 "Please upgrade the buildslave." % (self.build.slavename)) 671 raise BuildSlaveTooOldError(m) 672 673 if (self.username is not None or self.password is not None) \ 674 and self.slaveVersionIsOlderThan("svn", "2.8"): 675 m = ("This buildslave (%s) does not support svn usernames " 676 "and passwords. " 677 "Refusing to build. Please upgrade the buildslave to " 678 "buildbot-0.7.10 or newer." % (self.build.slavename,)) 679 raise BuildSlaveTooOldError(m)
680
681 - def getSvnUrl(self, branch):
682 ''' Compute the svn url that will be passed to the svn remote command ''' 683 if self.svnurl: 684 return self.svnurl 685 else: 686 if branch is None: 687 m = ("The SVN source step belonging to builder '%s' does not know " 688 "which branch to work with. This means that the change source " 689 "did not specify a branch and that defaultBranch is None." \ 690 % self.build.builder.name) 691 raise RuntimeError(m) 692 693 computed = self.baseURL 694 695 if self.branch_placeholder in self.baseURL: 696 return computed.replace(self.branch_placeholder, branch) 697 else: 698 return computed + branch
699
700 - def startVC(self, branch, revision, patch):
701 warnings = [] 702 703 self.checkCompatibility() 704 705 self.args['svnurl'] = self.getSvnUrl(branch) 706 self.args['revision'] = revision 707 self.args['patch'] = patch 708 self.args['always_purge'] = self.always_purge 709 710 #Set up depth if specified 711 if self.depth is not None: 712 self.args['depth'] = self.depth 713 714 if self.username is not None: 715 self.args['username'] = self.username 716 if self.password is not None: 717 self.args['password'] = self.password 718 719 if self.extra_args is not None: 720 self.args['extra_args'] = self.extra_args 721 722 revstuff = [] 723 #revstuff.append(self.args['svnurl']) 724 if self.args['svnurl'].find('trunk') == -1: 725 revstuff.append("[branch]") 726 if revision is not None: 727 revstuff.append("r%s" % revision) 728 if patch is not None: 729 revstuff.append("[patch]") 730 self.description.extend(revstuff) 731 self.descriptionDone.extend(revstuff) 732 733 cmd = RemoteCommand("svn", self.args) 734 self.startCommand(cmd, warnings)
735 736
737 -class Darcs(Source):
738 """Check out a source tree from a Darcs repository at 'repourl'. 739 740 Darcs has no concept of file modes. This means the eXecute-bit will be 741 cleared on all source files. As a result, you may need to invoke 742 configuration scripts with something like: 743 744 C{s(step.Configure, command=['/bin/sh', './configure'])} 745 """ 746 747 name = "darcs" 748 749 renderables = [ 'repourl', 'baseURL' ] 750
751 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None, 752 **kwargs):
753 """ 754 @type repourl: string 755 @param repourl: the URL which points at the Darcs repository. This 756 is used as the default branch. Using C{repourl} does 757 not enable builds of alternate branches: use 758 C{baseURL} to enable this. Use either C{repourl} or 759 C{baseURL}, not both. 760 761 @param baseURL: if branches are enabled, this is the base URL to 762 which a branch name will be appended. It should 763 probably end in a slash. Use exactly one of 764 C{repourl} and C{baseURL}. 765 766 @param defaultBranch: if branches are enabled, this is the branch 767 to use if the Build does not specify one 768 explicitly. It will simply be appended to 769 C{baseURL} and the result handed to the 770 'darcs pull' command. 771 """ 772 self.repourl = _ComputeRepositoryURL(repourl) 773 self.baseURL = _ComputeRepositoryURL(baseURL) 774 self.branch = defaultBranch 775 Source.__init__(self, **kwargs) 776 self.addFactoryArguments(repourl=repourl, 777 baseURL=baseURL, 778 defaultBranch=defaultBranch, 779 ) 780 assert self.args['mode'] != "export", \ 781 "Darcs does not have an 'export' mode" 782 if repourl and baseURL: 783 raise ValueError("you must provide exactly one of repourl and" 784 " baseURL")
785
786 - def startVC(self, branch, revision, patch):
787 slavever = self.slaveVersion("darcs") 788 if not slavever: 789 m = "slave is too old, does not know about darcs" 790 raise BuildSlaveTooOldError(m) 791 792 if self.slaveVersionIsOlderThan("darcs", "1.39"): 793 if revision: 794 # TODO: revisit this once we implement computeSourceRevision 795 m = "0.6.6 slaves can't handle args['revision']" 796 raise BuildSlaveTooOldError(m) 797 798 # the slave doesn't know to avoid re-using the same sourcedir 799 # when the branch changes. We have no way of knowing which branch 800 # the last build used, so if we're using a non-default branch and 801 # either 'update' or 'copy' modes, it is safer to refuse to 802 # build, and tell the user they need to upgrade the buildslave. 803 if (branch != self.branch 804 and self.args['mode'] in ("update", "copy")): 805 m = ("This buildslave (%s) does not know about multiple " 806 "branches, and using mode=%s would probably build the " 807 "wrong tree. " 808 "Refusing to build. Please upgrade the buildslave to " 809 "buildbot-0.7.0 or newer." % (self.build.slavename, 810 self.args['mode'])) 811 raise BuildSlaveTooOldError(m) 812 813 if self.repourl: 814 assert not branch # we need baseURL= to use branches 815 self.args['repourl'] = self.repourl 816 else: 817 self.args['repourl'] = self.baseURL + branch 818 self.args['revision'] = revision 819 self.args['patch'] = patch 820 821 revstuff = [] 822 if branch is not None and branch != self.branch: 823 revstuff.append("[branch]") 824 self.description.extend(revstuff) 825 self.descriptionDone.extend(revstuff) 826 827 cmd = RemoteCommand("darcs", self.args) 828 self.startCommand(cmd)
829 830
831 -class Git(Source):
832 """Check out a source tree from a git repository 'repourl'.""" 833 834 name = "git" 835 836 renderables = [ 'repourl' ] 837
838 - def __init__(self, repourl=None, 839 branch="master", 840 submodules=False, 841 ignore_ignores=None, 842 reference=None, 843 shallow=False, 844 progress=False, 845 **kwargs):
846 """ 847 @type repourl: string 848 @param repourl: the URL which points at the git repository 849 850 @type branch: string 851 @param branch: The branch or tag to check out by default. If 852 a build specifies a different branch, it will 853 be used instead of this. 854 855 @type submodules: boolean 856 @param submodules: Whether or not to update (and initialize) 857 git submodules. 858 859 @type reference: string 860 @param reference: The path to a reference repository to obtain 861 objects from, if any. 862 863 @type shallow: boolean 864 @param shallow: Use a shallow or clone, if possible 865 866 @type progress: boolean 867 @param progress: Pass the --progress option when fetching. This 868 can solve long fetches getting killed due to 869 lack of output, but requires Git 1.7.2+. 870 """ 871 Source.__init__(self, **kwargs) 872 self.repourl = _ComputeRepositoryURL(repourl) 873 self.branch = branch 874 self.addFactoryArguments(repourl=repourl, 875 branch=branch, 876 submodules=submodules, 877 ignore_ignores=ignore_ignores, 878 reference=reference, 879 shallow=shallow, 880 progress=progress, 881 ) 882 self.args.update({'submodules': submodules, 883 'ignore_ignores': ignore_ignores, 884 'reference': reference, 885 'shallow': shallow, 886 'progress': progress, 887 })
888
889 - def computeSourceRevision(self, changes):
890 if not changes: 891 return None 892 return changes[-1].revision
893
894 - def startVC(self, branch, revision, patch):
895 self.args['branch'] = branch 896 self.args['repourl'] = self.repourl 897 self.args['revision'] = revision 898 self.args['patch'] = patch 899 900 # check if there is any patchset we should fetch from Gerrit 901 if self.build.hasProperty("event.patchSet.ref"): 902 # GerritChangeSource 903 self.args['gerrit_branch'] = self.build.getProperty("event.patchSet.ref") 904 self.setProperty("gerrit_branch", self.args['gerrit_branch']) 905 else: 906 try: 907 # forced build 908 change = self.build.getProperty("gerrit_change", '').split('/') 909 if len(change) == 2: 910 self.args['gerrit_branch'] = "refs/changes/%2.2d/%d/%d" \ 911 % (int(change[0]) % 100, int(change[0]), int(change[1])) 912 self.setProperty("gerrit_branch", self.args['gerrit_branch']) 913 except: 914 pass 915 916 slavever = self.slaveVersion("git") 917 if not slavever: 918 raise BuildSlaveTooOldError("slave is too old, does not know " 919 "about git") 920 cmd = RemoteCommand("git", self.args) 921 self.startCommand(cmd)
922 923
924 -class Repo(Source):
925 """Check out a source tree from a repo repository described by manifest.""" 926 927 name = "repo" 928 929 renderables = [ "manifest_url" ] 930
931 - def __init__(self, 932 manifest_url=None, 933 manifest_branch="master", 934 manifest_file="default.xml", 935 tarball=None, 936 **kwargs):
937 """ 938 @type manifest_url: string 939 @param manifest_url: The URL which points at the repo manifests repository. 940 941 @type manifest_branch: string 942 @param manifest_branch: The manifest branch to check out by default. 943 944 @type manifest_file: string 945 @param manifest_file: The manifest to use for sync. 946 947 """ 948 Source.__init__(self, **kwargs) 949 self.manifest_url = _ComputeRepositoryURL(manifest_url) 950 self.addFactoryArguments(manifest_url=manifest_url, 951 manifest_branch=manifest_branch, 952 manifest_file=manifest_file, 953 tarball=tarball, 954 ) 955 self.args.update({'manifest_branch': manifest_branch, 956 'manifest_file': manifest_file, 957 'tarball': tarball, 958 'manifest_override_url': None 959 })
960
961 - def computeSourceRevision(self, changes):
962 if not changes: 963 return None 964 return changes[-1].revision
965
966 - def parseDownloadProperty(self, s):
967 """ 968 lets try to be nice in the format we want 969 can support several instances of "repo download proj number/patch" (direct copy paste from gerrit web site) 970 or several instances of "proj number/patch" (simpler version) 971 This feature allows integrator to build with several pending interdependant changes. 972 returns list of repo downloads sent to the buildslave 973 """ 974 import re 975 if s == None: 976 return [] 977 re1 = re.compile("repo download ([^ ]+) ([0-9]+/[0-9]+)") 978 re2 = re.compile("([^ ]+) ([0-9]+/[0-9]+)") 979 re3 = re.compile("([^ ]+)/([0-9]+/[0-9]+)") 980 ret = [] 981 for cur_re in [re1, re2, re3]: 982 res = cur_re.search(s) 983 while res: 984 ret.append("%s %s" % (res.group(1), res.group(2))) 985 s = s[:res.start(0)] + s[res.end(0):] 986 res = cur_re.search(s) 987 return ret
988
989 - def buildDownloadList(self):
990 """taken the changesource and forcebuild property, 991 build the repo download command to send to the slave 992 making this a defereable allow config to tweak this 993 in order to e.g. manage dependancies 994 """ 995 downloads = self.build.getProperty("repo_downloads", []) 996 997 # download patches based on GerritChangeSource events 998 for change in self.build.allChanges(): 999 if (change.properties.has_key("event.type") and 1000 change.properties["event.type"] == "patchset-created"): 1001 downloads.append("%s %s/%s"% (change.properties["event.change.project"], 1002 change.properties["event.change.number"], 1003 change.properties["event.patchSet.number"])) 1004 1005 # download patches based on web site forced build properties: 1006 # "repo_d", "repo_d0", .., "repo_d9" 1007 # "repo_download", "repo_download0", .., "repo_download9" 1008 for propName in ["repo_d"] + ["repo_d%d" % i for i in xrange(0,10)] + \ 1009 ["repo_download"] + ["repo_download%d" % i for i in xrange(0,10)]: 1010 s = self.build.getProperty(propName) 1011 if s is not None: 1012 downloads.extend(self.parseDownloadProperty(s)) 1013 1014 if downloads: 1015 self.args["repo_downloads"] = downloads 1016 self.setProperty("repo_downloads", downloads) 1017 return defer.succeed(None)
1018
1019 - def startVC(self, branch, revision, patch):
1020 self.args['manifest_url'] = self.manifest_url 1021 1022 # manifest override 1023 self.args['manifest_override_url'] = None 1024 try: 1025 self.args['manifest_override_url'] = self.build.getProperty("manifest_override_url") 1026 except KeyError: 1027 pass 1028 # only master has access to properties, so we must implement this here. 1029 d = self.buildDownloadList() 1030 d.addCallback(self.continueStartVC, branch, revision, patch) 1031 d.addErrback(self.failed)
1032
1033 - def continueStartVC(self, ignored, branch, revision, patch):
1034 slavever = self.slaveVersion("repo") 1035 if not slavever: 1036 raise BuildSlaveTooOldError("slave is too old, does not know " 1037 "about repo") 1038 cmd = RemoteCommand("repo", self.args) 1039 self.startCommand(cmd)
1040
1041 - def commandComplete(self, cmd):
1042 repo_downloaded = [] 1043 if cmd.updates.has_key("repo_downloaded"): 1044 repo_downloaded = cmd.updates["repo_downloaded"][-1] 1045 if repo_downloaded: 1046 self.setProperty("repo_downloaded", str(repo_downloaded), "Source") 1047 else: 1048 repo_downloaded = [] 1049 orig_downloads = self.getProperty("repo_downloads") or [] 1050 if len(orig_downloads) != len(repo_downloaded): 1051 self.step_status.setText(["repo download issues"])
1052 1053
1054 -class Bzr(Source):
1055 """Check out a source tree from a bzr (Bazaar) repository at 'repourl'. 1056 1057 """ 1058 1059 name = "bzr" 1060 1061 renderables = [ 'repourl', 'baseURL' ] 1062
1063 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None, 1064 forceSharedRepo=None, 1065 **kwargs):
1066 """ 1067 @type repourl: string 1068 @param repourl: the URL which points at the bzr repository. This 1069 is used as the default branch. Using C{repourl} does 1070 not enable builds of alternate branches: use 1071 C{baseURL} to enable this. Use either C{repourl} or 1072 C{baseURL}, not both. 1073 1074 @param baseURL: if branches are enabled, this is the base URL to 1075 which a branch name will be appended. It should 1076 probably end in a slash. Use exactly one of 1077 C{repourl} and C{baseURL}. 1078 1079 @param defaultBranch: if branches are enabled, this is the branch 1080 to use if the Build does not specify one 1081 explicitly. It will simply be appended to 1082 C{baseURL} and the result handed to the 1083 'bzr checkout pull' command. 1084 1085 1086 @param forceSharedRepo: Boolean, defaults to False. If set to True, 1087 the working directory will be made into a 1088 bzr shared repository if it is not already. 1089 Shared repository greatly reduces the amount 1090 of history data that needs to be downloaded 1091 if not using update/copy mode, or if using 1092 update/copy mode with multiple branches. 1093 """ 1094 self.repourl = _ComputeRepositoryURL(repourl) 1095 self.baseURL = _ComputeRepositoryURL(baseURL) 1096 self.branch = defaultBranch 1097 Source.__init__(self, **kwargs) 1098 self.addFactoryArguments(repourl=repourl, 1099 baseURL=baseURL, 1100 defaultBranch=defaultBranch, 1101 forceSharedRepo=forceSharedRepo 1102 ) 1103 self.args.update({'forceSharedRepo': forceSharedRepo}) 1104 if repourl and baseURL: 1105 raise ValueError("you must provide exactly one of repourl and" 1106 " baseURL")
1107
1108 - def computeSourceRevision(self, changes):
1109 if not changes: 1110 return None 1111 lastChange = max([int(c.revision) for c in changes]) 1112 return lastChange
1113
1114 - def startVC(self, branch, revision, patch):
1115 slavever = self.slaveVersion("bzr") 1116 if not slavever: 1117 m = "slave is too old, does not know about bzr" 1118 raise BuildSlaveTooOldError(m) 1119 1120 if self.repourl: 1121 assert not branch # we need baseURL= to use branches 1122 self.args['repourl'] = self.repourl 1123 else: 1124 self.args['repourl'] = self.baseURL + branch 1125 self.args['revision'] = revision 1126 self.args['patch'] = patch 1127 1128 revstuff = [] 1129 if branch is not None and branch != self.branch: 1130 revstuff.append("[" + branch + "]") 1131 if revision is not None: 1132 revstuff.append("r%s" % revision) 1133 self.description.extend(revstuff) 1134 self.descriptionDone.extend(revstuff) 1135 1136 cmd = RemoteCommand("bzr", self.args) 1137 self.startCommand(cmd)
1138 1139
1140 -class Mercurial(Source):
1141 """Check out a source tree from a mercurial repository 'repourl'.""" 1142 1143 name = "hg" 1144 1145 renderables = [ 'repourl', 'baseURL' ] 1146
1147 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None, 1148 branchType='dirname', clobberOnBranchChange=True, **kwargs):
1149 """ 1150 @type repourl: string 1151 @param repourl: the URL which points at the Mercurial repository. 1152 This uses the 'default' branch unless defaultBranch is 1153 specified below and the C{branchType} is set to 1154 'inrepo'. It is an error to specify a branch without 1155 setting the C{branchType} to 'inrepo'. 1156 1157 @param baseURL: if 'dirname' branches are enabled, this is the base URL 1158 to which a branch name will be appended. It should 1159 probably end in a slash. Use exactly one of C{repourl} 1160 and C{baseURL}. 1161 1162 @param defaultBranch: if branches are enabled, this is the branch 1163 to use if the Build does not specify one 1164 explicitly. 1165 For 'dirname' branches, It will simply be 1166 appended to C{baseURL} and the result handed to 1167 the 'hg update' command. 1168 For 'inrepo' branches, this specifies the named 1169 revision to which the tree will update after a 1170 clone. 1171 1172 @param branchType: either 'dirname' or 'inrepo' depending on whether 1173 the branch name should be appended to the C{baseURL} 1174 or the branch is a mercurial named branch and can be 1175 found within the C{repourl} 1176 1177 @param clobberOnBranchChange: boolean, defaults to True. If set and 1178 using inrepos branches, clobber the tree 1179 at each branch change. Otherwise, just 1180 update to the branch. 1181 """ 1182 self.repourl = _ComputeRepositoryURL(repourl) 1183 self.baseURL = _ComputeRepositoryURL(baseURL) 1184 self.branch = defaultBranch 1185 self.branchType = branchType 1186 self.clobberOnBranchChange = clobberOnBranchChange 1187 Source.__init__(self, **kwargs) 1188 self.addFactoryArguments(repourl=repourl, 1189 baseURL=baseURL, 1190 defaultBranch=defaultBranch, 1191 branchType=branchType, 1192 clobberOnBranchChange=clobberOnBranchChange, 1193 ) 1194 if repourl and baseURL: 1195 raise ValueError("you must provide exactly one of repourl and" 1196 " baseURL")
1197
1198 - def startVC(self, branch, revision, patch):
1199 slavever = self.slaveVersion("hg") 1200 if not slavever: 1201 raise BuildSlaveTooOldError("slave is too old, does not know " 1202 "about hg") 1203 1204 if self.repourl: 1205 # we need baseURL= to use dirname branches 1206 assert self.branchType == 'inrepo' or not branch 1207 self.args['repourl'] = self.repourl 1208 if branch: 1209 self.args['branch'] = branch 1210 else: 1211 self.args['repourl'] = self.baseURL + (branch or '') 1212 self.args['revision'] = revision 1213 self.args['patch'] = patch 1214 self.args['clobberOnBranchChange'] = self.clobberOnBranchChange 1215 self.args['branchType'] = self.branchType 1216 1217 revstuff = [] 1218 if branch is not None and branch != self.branch: 1219 revstuff.append("[branch]") 1220 self.description.extend(revstuff) 1221 self.descriptionDone.extend(revstuff) 1222 1223 cmd = RemoteCommand("hg", self.args) 1224 self.startCommand(cmd)
1225
1226 - def computeSourceRevision(self, changes):
1227 if not changes: 1228 return None 1229 # without knowing the revision ancestry graph, we can't sort the 1230 # changes at all. So for now, assume they were given to us in sorted 1231 # order, and just pay attention to the last one. See ticket #103 for 1232 # more details. 1233 if len(changes) > 1: 1234 log.msg("Mercurial.computeSourceRevision: warning: " 1235 "there are %d changes here, assuming the last one is " 1236 "the most recent" % len(changes)) 1237 return changes[-1].revision
1238 1239
1240 -class P4(Source):
1241 """ P4 is a class for accessing perforce revision control""" 1242 name = "p4" 1243 1244 renderables = [ 'p4base' ] 1245
1246 - def __init__(self, p4base=None, defaultBranch=None, p4port=None, p4user=None, 1247 p4passwd=None, p4extra_views=[], p4line_end='local', 1248 p4client='buildbot_%(slave)s_%(builder)s', **kwargs):
1249 """ 1250 @type p4base: string 1251 @param p4base: A view into a perforce depot, typically 1252 "//depot/proj/" 1253 1254 @type defaultBranch: string 1255 @param defaultBranch: Identify a branch to build by default. Perforce 1256 is a view based branching system. So, the branch 1257 is normally the name after the base. For example, 1258 branch=1.0 is view=//depot/proj/1.0/... 1259 branch=1.1 is view=//depot/proj/1.1/... 1260 1261 @type p4port: string 1262 @param p4port: Specify the perforce server to connection in the format 1263 <host>:<port>. Example "perforce.example.com:1666" 1264 1265 @type p4user: string 1266 @param p4user: The perforce user to run the command as. 1267 1268 @type p4passwd: string 1269 @param p4passwd: The password for the perforce user. 1270 1271 @type p4extra_views: list of tuples 1272 @param p4extra_views: Extra views to be added to 1273 the client that is being used. 1274 1275 @type p4line_end: string 1276 @param p4line_end: value of the LineEnd client specification property 1277 1278 @type p4client: string 1279 @param p4client: The perforce client to use for this buildslave. 1280 """ 1281 1282 self.p4base = _ComputeRepositoryURL(p4base) 1283 self.branch = defaultBranch 1284 Source.__init__(self, **kwargs) 1285 self.addFactoryArguments(p4base=p4base, 1286 defaultBranch=defaultBranch, 1287 p4port=p4port, 1288 p4user=p4user, 1289 p4passwd=p4passwd, 1290 p4extra_views=p4extra_views, 1291 p4line_end=p4line_end, 1292 p4client=p4client, 1293 ) 1294 self.args['p4port'] = p4port 1295 self.args['p4user'] = p4user 1296 self.args['p4passwd'] = p4passwd 1297 self.args['p4extra_views'] = p4extra_views 1298 self.args['p4line_end'] = p4line_end 1299 self.p4client = p4client
1300
1301 - def setBuild(self, build):
1302 Source.setBuild(self, build) 1303 self.args['p4client'] = self.p4client % { 1304 'slave': build.slavename, 1305 'builder': build.builder.name, 1306 }
1307
1308 - def computeSourceRevision(self, changes):
1309 if not changes: 1310 return None 1311 lastChange = max([int(c.revision) for c in changes]) 1312 return lastChange
1313
1314 - def startVC(self, branch, revision, patch):
1315 slavever = self.slaveVersion("p4") 1316 assert slavever, "slave is too old, does not know about p4" 1317 args = dict(self.args) 1318 args['p4base'] = self.p4base 1319 args['branch'] = branch or self.branch 1320 args['revision'] = revision 1321 args['patch'] = patch 1322 cmd = RemoteCommand("p4", args) 1323 self.startCommand(cmd)
1324
1325 -class P4Sync(Source):
1326 """ 1327 DEPRECATED - will be removed in 0.8.5. 1328 1329 This is a partial solution for using a P4 source repository. You are 1330 required to manually set up each build slave with a useful P4 1331 environment, which means setting various per-slave environment variables, 1332 and creating a P4 client specification which maps the right files into 1333 the slave's working directory. Once you have done that, this step merely 1334 performs a 'p4 sync' to update that workspace with the newest files. 1335 1336 Each slave needs the following environment: 1337 1338 - PATH: the 'p4' binary must be on the slave's PATH 1339 - P4USER: each slave needs a distinct user account 1340 - P4CLIENT: each slave needs a distinct client specification 1341 1342 You should use 'p4 client' (?) to set up a client view spec which maps 1343 the desired files into $SLAVEBASE/$BUILDERBASE/source . 1344 """ 1345 1346 name = "p4sync" 1347
1348 - def __init__(self, p4port, p4user, p4passwd, p4client, **kwargs):
1349 assert kwargs['mode'] == "copy", "P4Sync can only be used in mode=copy" 1350 self.branch = None 1351 Source.__init__(self, **kwargs) 1352 self.addFactoryArguments(p4port=p4port, 1353 p4user=p4user, 1354 p4passwd=p4passwd, 1355 p4client=p4client, 1356 ) 1357 self.args['p4port'] = p4port 1358 self.args['p4user'] = p4user 1359 self.args['p4passwd'] = p4passwd 1360 self.args['p4client'] = p4client
1361
1362 - def computeSourceRevision(self, changes):
1363 if not changes: 1364 return None 1365 lastChange = max([int(c.revision) for c in changes]) 1366 return lastChange
1367
1368 - def startVC(self, branch, revision, patch):
1369 slavever = self.slaveVersion("p4sync") 1370 assert slavever, "slave is too old, does not know about p4" 1371 cmd = RemoteCommand("p4sync", self.args) 1372 self.startCommand(cmd)
1373 1374
1375 -class Monotone(Source):
1376 """Check out a source tree from a monotone repository 'repourl'.""" 1377 1378 name = "mtn" 1379 1380 renderables = [ 'repourl' ] 1381
1382 - def __init__(self, repourl=None, branch=None, progress=False, **kwargs):
1383 """ 1384 @type repourl: string 1385 @param repourl: the URI which points at the monotone repository. 1386 1387 @type branch: string 1388 @param branch: The branch or tag to check out by default. If 1389 a build specifies a different branch, it will 1390 be used instead of this. 1391 1392 @type progress: boolean 1393 @param progress: Pass the --ticker=dot option when pulling. This 1394 can solve long fetches getting killed due to 1395 lack of output. 1396 """ 1397 Source.__init__(self, **kwargs) 1398 self.repourl = _ComputeRepositoryURL(repourl) 1399 if (not repourl): 1400 raise ValueError("you must provide a repository uri in 'repourl'") 1401 if (not branch): 1402 raise ValueError("you must provide a default branch in 'branch'") 1403 self.addFactoryArguments(repourl=repourl, 1404 branch=branch, 1405 progress=progress, 1406 ) 1407 self.args.update({'branch': branch, 1408 'progress': progress, 1409 })
1410
1411 - def startVC(self, branch, revision, patch):
1412 slavever = self.slaveVersion("mtn") 1413 if not slavever: 1414 raise BuildSlaveTooOldError("slave is too old, does not know " 1415 "about mtn") 1416 1417 self.args['repourl'] = self.repourl 1418 if branch: 1419 self.args['branch'] = branch 1420 self.args['revision'] = revision 1421 self.args['patch'] = patch 1422 1423 cmd = RemoteCommand("mtn", self.args) 1424 self.startCommand(cmd)
1425
1426 - def computeSourceRevision(self, changes):
1427 if not changes: 1428 return None 1429 # without knowing the revision ancestry graph, we can't sort the 1430 # changes at all. So for now, assume they were given to us in sorted 1431 # order, and just pay attention to the last one. See ticket #103 for 1432 # more details. 1433 if len(changes) > 1: 1434 log.msg("Monotone.computeSourceRevision: warning: " 1435 "there are %d changes here, assuming the last one is " 1436 "the most recent" % len(changes)) 1437 return changes[-1].revision
1438