1
2
3 from warnings import warn
4 from email.Utils import formatdate
5 from twisted.python import log
6 from buildbot.process.buildstep import LoggingBuildStep, LoggedRemoteCommand
7 from buildbot.interfaces import BuildSlaveTooOldError
8 from buildbot.status.builder import SKIPPED
9
10
11 -class Source(LoggingBuildStep):
12 """This is a base class to generate a source tree in the buildslave.
13 Each version control system has a specialized subclass, and is expected
14 to override __init__ and implement computeSourceRevision() and
15 startVC(). The class as a whole builds up the self.args dictionary, then
16 starts a LoggedRemoteCommand with those arguments.
17 """
18
19
20 haltOnFailure = True
21 flunkOnFailure = True
22 notReally = False
23
24 branch = None
25
26 - def __init__(self, workdir=None, mode='update', alwaysUseLatest=False,
27 timeout=20*60, retry=None, **kwargs):
28 """
29 @type workdir: string
30 @param workdir: local directory (relative to the Builder's root)
31 where the tree should be placed
32
33 @type mode: string
34 @param mode: the kind of VC operation that is desired:
35 - 'update': specifies that the checkout/update should be
36 performed directly into the workdir. Each build is performed
37 in the same directory, allowing for incremental builds. This
38 minimizes disk space, bandwidth, and CPU time. However, it
39 may encounter problems if the build process does not handle
40 dependencies properly (if you must sometimes do a 'clean
41 build' to make sure everything gets compiled), or if source
42 files are deleted but generated files can influence test
43 behavior (e.g. python's .pyc files), or when source
44 directories are deleted but generated files prevent CVS from
45 removing them. When used with a patched checkout, from a
46 previous buildbot try for instance, it will try to "revert"
47 the changes first and will do a clobber if it is unable to
48 get a clean checkout. The behavior is SCM-dependent.
49
50 - 'copy': specifies that the source-controlled workspace
51 should be maintained in a separate directory (called the
52 'copydir'), using checkout or update as necessary. For each
53 build, a new workdir is created with a copy of the source
54 tree (rm -rf workdir; cp -R -P -p copydir workdir). This
55 doubles the disk space required, but keeps the bandwidth low
56 (update instead of a full checkout). A full 'clean' build
57 is performed each time. This avoids any generated-file
58 build problems, but is still occasionally vulnerable to
59 problems such as a CVS repository being manually rearranged
60 (causing CVS errors on update) which are not an issue with
61 a full checkout.
62
63 - 'clobber': specifies that the working directory should be
64 deleted each time, necessitating a full checkout for each
65 build. This insures a clean build off a complete checkout,
66 avoiding any of the problems described above, but is
67 bandwidth intensive, as the whole source tree must be
68 pulled down for each build.
69
70 - 'export': is like 'clobber', except that e.g. the 'cvs
71 export' command is used to create the working directory.
72 This command removes all VC metadata files (the
73 CVS/.svn/{arch} directories) from the tree, which is
74 sometimes useful for creating source tarballs (to avoid
75 including the metadata in the tar file). Not all VC systems
76 support export.
77
78 @type alwaysUseLatest: boolean
79 @param alwaysUseLatest: whether to always update to the most
80 recent available sources for this build.
81
82 Normally the Source step asks its Build for a list of all
83 Changes that are supposed to go into the build, then computes a
84 'source stamp' (revision number or timestamp) that will cause
85 exactly that set of changes to be present in the checked out
86 tree. This is turned into, e.g., 'cvs update -D timestamp', or
87 'svn update -r revnum'. If alwaysUseLatest=True, bypass this
88 computation and always update to the latest available sources
89 for each build.
90
91 The source stamp helps avoid a race condition in which someone
92 commits a change after the master has decided to start a build
93 but before the slave finishes checking out the sources. At best
94 this results in a build which contains more changes than the
95 buildmaster thinks it has (possibly resulting in the wrong
96 person taking the blame for any problems that result), at worst
97 is can result in an incoherent set of sources (splitting a
98 non-atomic commit) which may not build at all.
99
100 @type retry: tuple of ints (delay, repeats) (or None)
101 @param retry: if provided, VC update failures are re-attempted up
102 to REPEATS times, with DELAY seconds between each
103 attempt. Some users have slaves with poor connectivity
104 to their VC repository, and they say that up to 80% of
105 their build failures are due to transient network
106 failures that could be handled by simply retrying a
107 couple times.
108
109 """
110
111 LoggingBuildStep.__init__(self, **kwargs)
112 self.addFactoryArguments(workdir=workdir,
113 mode=mode,
114 alwaysUseLatest=alwaysUseLatest,
115 timeout=timeout,
116 retry=retry,
117 )
118
119 assert mode in ("update", "copy", "clobber", "export")
120 if retry:
121 delay, repeats = retry
122 assert isinstance(repeats, int)
123 assert repeats > 0
124 self.args = {'mode': mode,
125 'workdir': workdir,
126 'timeout': timeout,
127 'retry': retry,
128 'patch': None,
129 }
130 self.alwaysUseLatest = alwaysUseLatest
131
132
133 description = ["updating"]
134 descriptionDone = ["update"]
135 if mode == "clobber":
136 description = ["checkout"]
137
138 descriptionDone = ["checkout"]
139 elif mode == "export":
140 description = ["exporting"]
141 descriptionDone = ["export"]
142 self.description = description
143 self.descriptionDone = descriptionDone
144
146 self.args['workdir'] = self.args['workdir'] or workdir
147
152
154 """Each subclass must implement this method to do something more
155 precise than -rHEAD every time. For version control systems that use
156 repository-wide change numbers (SVN, P4), this can simply take the
157 maximum such number from all the changes involved in this build. For
158 systems that do not (CVS), it needs to create a timestamp based upon
159 the latest Change, the Build's treeStableTimer, and an optional
160 self.checkoutDelay value."""
161 return None
162
191
193 if cmd.updates.has_key("got_revision"):
194 got_revision = cmd.updates["got_revision"][-1]
195 if got_revision is not None:
196 self.setProperty("got_revision", str(got_revision), "Source")
197
198
199
201 """I do CVS checkout/update operations.
202
203 Note: if you are doing anonymous/pserver CVS operations, you will need
204 to manually do a 'cvs login' on each buildslave before the slave has any
205 hope of success. XXX: fix then, take a cvs password as an argument and
206 figure out how to do a 'cvs login' on each build
207 """
208
209 name = "cvs"
210
211
212
213
214
215
216
217
218
219
220
221 - def __init__(self, cvsroot, cvsmodule,
222 global_options=[], branch=None, checkoutDelay=None,
223 checkout_options=[],
224 login=None,
225 **kwargs):
226
227 """
228 @type cvsroot: string
229 @param cvsroot: CVS Repository from which the source tree should
230 be obtained. '/home/warner/Repository' for local
231 or NFS-reachable repositories,
232 ':pserver:anon@foo.com:/cvs' for anonymous CVS,
233 'user@host.com:/cvs' for non-anonymous CVS or
234 CVS over ssh. Lots of possibilities, check the
235 CVS documentation for more.
236
237 @type cvsmodule: string
238 @param cvsmodule: subdirectory of CVS repository that should be
239 retrieved
240
241 @type login: string or None
242 @param login: if not None, a string which will be provided as a
243 password to the 'cvs login' command, used when a
244 :pserver: method is used to access the repository.
245 This login is only needed once, but must be run
246 each time (just before the CVS operation) because
247 there is no way for the buildslave to tell whether
248 it was previously performed or not.
249
250 @type branch: string
251 @param branch: the default branch name, will be used in a '-r'
252 argument to specify which branch of the source tree
253 should be used for this checkout. Defaults to None,
254 which means to use 'HEAD'.
255
256 @type checkoutDelay: int or None
257 @param checkoutDelay: if not None, the number of seconds to put
258 between the last known Change and the
259 timestamp given to the -D argument. This
260 defaults to exactly half of the parent
261 Build's .treeStableTimer, but it could be
262 set to something else if your CVS change
263 notification has particularly weird
264 latency characteristics.
265
266 @type global_options: list of strings
267 @param global_options: these arguments are inserted in the cvs
268 command line, before the
269 'checkout'/'update' command word. See
270 'cvs --help-options' for a list of what
271 may be accepted here. ['-r'] will make
272 the checked out files read only. ['-r',
273 '-R'] will also assume the repository is
274 read-only (I assume this means it won't
275 use locks to insure atomic access to the
276 ,v files).
277
278 @type checkout_options: list of strings
279 @param checkout_options: these arguments are inserted in the cvs
280 command line, after 'checkout' but before
281 branch or revision specifiers.
282 """
283
284 self.checkoutDelay = checkoutDelay
285 self.branch = branch
286
287 Source.__init__(self, **kwargs)
288 self.addFactoryArguments(cvsroot=cvsroot,
289 cvsmodule=cvsmodule,
290 global_options=global_options,
291 checkout_options=checkout_options,
292 branch=branch,
293 checkoutDelay=checkoutDelay,
294 login=login,
295 )
296
297 self.args.update({'cvsroot': cvsroot,
298 'cvsmodule': cvsmodule,
299 'global_options': global_options,
300 'checkout_options':checkout_options,
301 'login': login,
302 })
303
305 if not changes:
306 return None
307 lastChange = max([c.when for c in changes])
308 if self.checkoutDelay is not None:
309 when = lastChange + self.checkoutDelay
310 else:
311 lastSubmit = max([r.submittedAt for r in self.build.requests])
312 when = (lastChange + lastSubmit) / 2
313 return formatdate(when)
314
315 - def startVC(self, branch, revision, patch):
316 if self.slaveVersionIsOlderThan("cvs", "1.39"):
317
318
319
320
321
322 if (branch != self.branch
323 and self.args['mode'] in ("update", "copy")):
324 m = ("This buildslave (%s) does not know about multiple "
325 "branches, and using mode=%s would probably build the "
326 "wrong tree. "
327 "Refusing to build. Please upgrade the buildslave to "
328 "buildbot-0.7.0 or newer." % (self.build.slavename,
329 self.args['mode']))
330 log.msg(m)
331 raise BuildSlaveTooOldError(m)
332
333 if branch is None:
334 branch = "HEAD"
335 self.args['branch'] = branch
336 self.args['revision'] = revision
337 self.args['patch'] = patch
338
339 if self.args['branch'] == "HEAD" and self.args['revision']:
340
341
342 self.args['branch'] = None
343
344
345 warnings = []
346 slavever = self.slaveVersion("cvs", "old")
347
348 if slavever == "old":
349
350 if self.args['mode'] == "export":
351 self.args['export'] = 1
352 elif self.args['mode'] == "clobber":
353 self.args['clobber'] = 1
354 elif self.args['mode'] == "copy":
355 self.args['copydir'] = "source"
356 self.args['tag'] = self.args['branch']
357 assert not self.args['patch']
358
359 cmd = LoggedRemoteCommand("cvs", self.args)
360 self.startCommand(cmd, warnings)
361
362
364 """I perform Subversion checkout/update operations."""
365
366 name = 'svn'
367
368 - def __init__(self, svnurl=None, baseURL=None, defaultBranch=None,
369 directory=None, username=None, password=None,
370 extra_args=None, keep_on_purge=None, ignore_ignores=None,
371 always_purge=None, depth=None, **kwargs):
372 """
373 @type svnurl: string
374 @param svnurl: the URL which points to the Subversion server,
375 combining the access method (HTTP, ssh, local file),
376 the repository host/port, the repository path, the
377 sub-tree within the repository, and the branch to
378 check out. Using C{svnurl} does not enable builds of
379 alternate branches: use C{baseURL} to enable this.
380 Use exactly one of C{svnurl} and C{baseURL}.
381
382 @param baseURL: if branches are enabled, this is the base URL to
383 which a branch name will be appended. It should
384 probably end in a slash. Use exactly one of
385 C{svnurl} and C{baseURL}.
386
387 @param defaultBranch: if branches are enabled, this is the branch
388 to use if the Build does not specify one
389 explicitly. It will simply be appended
390 to C{baseURL} and the result handed to
391 the SVN command.
392
393 @param username: username to pass to svn's --username
394 @param password: username to pass to svn's --password
395 """
396
397 if not kwargs.has_key('workdir') and directory is not None:
398
399 warn("Please use workdir=, not directory=", DeprecationWarning)
400 kwargs['workdir'] = directory
401
402 self.svnurl = svnurl
403 self.baseURL = baseURL
404 self.branch = defaultBranch
405 self.username = username
406 self.password = password
407 self.extra_args = extra_args
408 self.keep_on_purge = keep_on_purge
409 self.ignore_ignores = ignore_ignores
410 self.always_purge = always_purge
411 self.depth = depth
412
413 Source.__init__(self, **kwargs)
414 self.addFactoryArguments(svnurl=svnurl,
415 baseURL=baseURL,
416 defaultBranch=defaultBranch,
417 directory=directory,
418 username=username,
419 password=password,
420 extra_args=extra_args,
421 keep_on_purge=keep_on_purge,
422 ignore_ignores=ignore_ignores,
423 always_purge=always_purge,
424 depth=depth,
425 )
426
427 if not svnurl and not baseURL:
428 raise ValueError("you must use exactly one of svnurl and baseURL")
429
430
436
437 - def startVC(self, branch, revision, patch):
438
439
440 warnings = []
441 slavever = self.slaveVersion("svn", "old")
442 if not slavever:
443 m = "slave does not have the 'svn' command"
444 raise BuildSlaveTooOldError(m)
445
446 if self.slaveVersionIsOlderThan("svn", "1.39"):
447
448
449
450
451
452 if (branch != self.branch
453 and self.args['mode'] in ("update", "copy")):
454 m = ("This buildslave (%s) does not know about multiple "
455 "branches, and using mode=%s would probably build the "
456 "wrong tree. "
457 "Refusing to build. Please upgrade the buildslave to "
458 "buildbot-0.7.0 or newer." % (self.build.slavename,
459 self.args['mode']))
460 raise BuildSlaveTooOldError(m)
461
462 if slavever == "old":
463
464 if self.args['mode'] in ("clobber", "copy"):
465
466
467
468 warnings.append("WARNING: this slave can only do SVN updates"
469 ", not mode=%s\n" % self.args['mode'])
470 log.msg("WARNING: this slave only does mode=update")
471 if self.args['mode'] == "export":
472 raise BuildSlaveTooOldError("old slave does not have "
473 "mode=export")
474 self.args['directory'] = self.args['workdir']
475 if revision is not None:
476
477
478
479
480 m = ("WARNING: old slave can only update to HEAD, not "
481 "revision=%s" % revision)
482 log.msg(m)
483 warnings.append(m + "\n")
484 revision = "HEAD"
485 if patch:
486 raise BuildSlaveTooOldError("old slave can't do patch")
487
488 if self.svnurl:
489 assert not branch
490 self.args['svnurl'] = self.svnurl
491 else:
492 self.args['svnurl'] = self.baseURL + branch
493 self.args['revision'] = revision
494 self.args['patch'] = patch
495
496
497 if self.depth is not None:
498 if self.slaveVersionIsOlderThan("svn","2.9"):
499 m = ("This buildslave (%s) does not support svn depth "
500 "arguments. "
501 "Refusing to build. "
502 "Please upgrade the buildslave." % (self.build.slavename))
503 raise BuildSlaveTooOldError(m)
504 else:
505 self.args['depth'] = self.depth
506
507 if self.username is not None or self.password is not None:
508 if self.slaveVersionIsOlderThan("svn", "2.8"):
509 m = ("This buildslave (%s) does not support svn usernames "
510 "and passwords. "
511 "Refusing to build. Please upgrade the buildslave to "
512 "buildbot-0.7.10 or newer." % (self.build.slavename,))
513 raise BuildSlaveTooOldError(m)
514 if self.username is not None: self.args['username'] = self.username
515 if self.password is not None: self.args['password'] = self.password
516
517 if self.extra_args is not None:
518 self.args['extra_args'] = self.extra_args
519
520 revstuff = []
521 if branch is not None and branch != self.branch:
522 revstuff.append("[branch]")
523 if revision is not None:
524 revstuff.append("r%s" % revision)
525 if patch is not None:
526 revstuff.append("[patch]")
527 self.description.extend(revstuff)
528 self.descriptionDone.extend(revstuff)
529
530 cmd = LoggedRemoteCommand("svn", self.args)
531 self.startCommand(cmd, warnings)
532
533
535 """Check out a source tree from a Darcs repository at 'repourl'.
536
537 Darcs has no concept of file modes. This means the eXecute-bit will be
538 cleared on all source files. As a result, you may need to invoke
539 configuration scripts with something like:
540
541 C{s(step.Configure, command=['/bin/sh', './configure'])}
542 """
543
544 name = "darcs"
545
546 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
547 **kwargs):
548 """
549 @type repourl: string
550 @param repourl: the URL which points at the Darcs repository. This
551 is used as the default branch. Using C{repourl} does
552 not enable builds of alternate branches: use
553 C{baseURL} to enable this. Use either C{repourl} or
554 C{baseURL}, not both.
555
556 @param baseURL: if branches are enabled, this is the base URL to
557 which a branch name will be appended. It should
558 probably end in a slash. Use exactly one of
559 C{repourl} and C{baseURL}.
560
561 @param defaultBranch: if branches are enabled, this is the branch
562 to use if the Build does not specify one
563 explicitly. It will simply be appended to
564 C{baseURL} and the result handed to the
565 'darcs pull' command.
566 """
567 self.repourl = repourl
568 self.baseURL = baseURL
569 self.branch = defaultBranch
570 Source.__init__(self, **kwargs)
571 self.addFactoryArguments(repourl=repourl,
572 baseURL=baseURL,
573 defaultBranch=defaultBranch,
574 )
575 assert self.args['mode'] != "export", \
576 "Darcs does not have an 'export' mode"
577 if (not repourl and not baseURL) or (repourl and baseURL):
578 raise ValueError("you must provide exactly one of repourl and"
579 " baseURL")
580
581 - def startVC(self, branch, revision, patch):
582 slavever = self.slaveVersion("darcs")
583 if not slavever:
584 m = "slave is too old, does not know about darcs"
585 raise BuildSlaveTooOldError(m)
586
587 if self.slaveVersionIsOlderThan("darcs", "1.39"):
588 if revision:
589
590 m = "0.6.6 slaves can't handle args['revision']"
591 raise BuildSlaveTooOldError(m)
592
593
594
595
596
597
598 if (branch != self.branch
599 and self.args['mode'] in ("update", "copy")):
600 m = ("This buildslave (%s) does not know about multiple "
601 "branches, and using mode=%s would probably build the "
602 "wrong tree. "
603 "Refusing to build. Please upgrade the buildslave to "
604 "buildbot-0.7.0 or newer." % (self.build.slavename,
605 self.args['mode']))
606 raise BuildSlaveTooOldError(m)
607
608 if self.repourl:
609 assert not branch
610 self.args['repourl'] = self.repourl
611 else:
612 self.args['repourl'] = self.baseURL + branch
613 self.args['revision'] = revision
614 self.args['patch'] = patch
615
616 revstuff = []
617 if branch is not None and branch != self.branch:
618 revstuff.append("[branch]")
619 self.description.extend(revstuff)
620 self.descriptionDone.extend(revstuff)
621
622 cmd = LoggedRemoteCommand("darcs", self.args)
623 self.startCommand(cmd)
624
625
627 """Check out a source tree from a git repository 'repourl'."""
628
629 name = "git"
630
631 - def __init__(self, repourl,
632 branch="master",
633 submodules=False,
634 ignore_ignores=None,
635 **kwargs):
636 """
637 @type repourl: string
638 @param repourl: the URL which points at the git repository
639
640 @type branch: string
641 @param branch: The branch or tag to check out by default. If
642 a build specifies a different branch, it will
643 be used instead of this.
644
645 @type submodules: boolean
646 @param submodules: Whether or not to update (and initialize)
647 git submodules.
648
649 """
650 Source.__init__(self, **kwargs)
651 self.addFactoryArguments(repourl=repourl,
652 branch=branch,
653 submodules=submodules,
654 ignore_ignores=ignore_ignores,
655 )
656 self.args.update({'repourl': repourl,
657 'branch': branch,
658 'submodules': submodules,
659 'ignore_ignores': ignore_ignores,
660 })
661
666
667 - def startVC(self, branch, revision, patch):
679
680
682 """Check out a source tree from an Arch repository named 'archive'
683 available at 'url'. 'version' specifies which version number (development
684 line) will be used for the checkout: this is mostly equivalent to a
685 branch name. This version uses the 'tla' tool to do the checkout, to use
686 'baz' see L{Bazaar} instead.
687 """
688
689 name = "arch"
690
691
692 - def __init__(self, url, version, archive=None, **kwargs):
693 """
694 @type url: string
695 @param url: the Arch coordinates of the repository. This is
696 typically an http:// URL, but could also be the absolute
697 pathname of a local directory instead.
698
699 @type version: string
700 @param version: the category--branch--version to check out. This is
701 the default branch. If a build specifies a different
702 branch, it will be used instead of this.
703
704 @type archive: string
705 @param archive: The archive name. If provided, it must match the one
706 that comes from the repository. If not, the
707 repository's default will be used.
708 """
709 self.branch = version
710 Source.__init__(self, **kwargs)
711 self.addFactoryArguments(url=url,
712 version=version,
713 archive=archive,
714 )
715 self.args.update({'url': url,
716 'archive': archive,
717 })
718
720
721
722
723
724
725 if not changes:
726 return None
727 lastChange = None
728 for c in changes:
729 if not c.revision:
730 continue
731 if c.revision.endswith("--base-0"):
732 rev = 0
733 else:
734 i = c.revision.rindex("patch")
735 rev = int(c.revision[i+len("patch-"):])
736 lastChange = max(lastChange, rev)
737 if lastChange is None:
738 return None
739 if lastChange == 0:
740 return "base-0"
741 return "patch-%d" % lastChange
742
744 warnings = []
745 slavever = self.slaveVersion(cmd)
746 if not slavever:
747 m = "slave is too old, does not know about %s" % cmd
748 raise BuildSlaveTooOldError(m)
749
750
751 if self.slaveVersionIsOlderThan(cmd, "1.28"):
752 if not self.alwaysUseLatest:
753
754
755
756
757 m = "WARNING, buildslave is too old to use a revision"
758 log.msg(m)
759 warnings.append(m + "\n")
760
761 if self.slaveVersionIsOlderThan(cmd, "1.39"):
762
763
764
765
766
767 if (branch != self.branch
768 and self.args['mode'] in ("update", "copy")):
769 m = ("This buildslave (%s) does not know about multiple "
770 "branches, and using mode=%s would probably build the "
771 "wrong tree. "
772 "Refusing to build. Please upgrade the buildslave to "
773 "buildbot-0.7.0 or newer." % (self.build.slavename,
774 self.args['mode']))
775 log.msg(m)
776 raise BuildSlaveTooOldError(m)
777
778 return warnings
779
780 - def startVC(self, branch, revision, patch):
796
797
799 """Bazaar is an alternative client for Arch repositories. baz is mostly
800 compatible with tla, but archive registration is slightly different."""
801
802
803
804 - def __init__(self, url, version, archive, **kwargs):
805 """
806 @type url: string
807 @param url: the Arch coordinates of the repository. This is
808 typically an http:// URL, but could also be the absolute
809 pathname of a local directory instead.
810
811 @type version: string
812 @param version: the category--branch--version to check out
813
814 @type archive: string
815 @param archive: The archive name (required). This must always match
816 the one that comes from the repository, otherwise the
817 buildslave will attempt to get sources from the wrong
818 archive.
819 """
820 self.branch = version
821 Source.__init__(self, **kwargs)
822 self.addFactoryArguments(url=url,
823 version=version,
824 archive=archive,
825 )
826 self.args.update({'url': url,
827 'archive': archive,
828 })
829
830 - def startVC(self, branch, revision, patch):
846
848 """Check out a source tree from a bzr (Bazaar) repository at 'repourl'.
849
850 """
851
852 name = "bzr"
853
854 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
855 forceSharedRepo=None,
856 **kwargs):
857 """
858 @type repourl: string
859 @param repourl: the URL which points at the bzr repository. This
860 is used as the default branch. Using C{repourl} does
861 not enable builds of alternate branches: use
862 C{baseURL} to enable this. Use either C{repourl} or
863 C{baseURL}, not both.
864
865 @param baseURL: if branches are enabled, this is the base URL to
866 which a branch name will be appended. It should
867 probably end in a slash. Use exactly one of
868 C{repourl} and C{baseURL}.
869
870 @param defaultBranch: if branches are enabled, this is the branch
871 to use if the Build does not specify one
872 explicitly. It will simply be appended to
873 C{baseURL} and the result handed to the
874 'bzr checkout pull' command.
875
876
877 @param forceSharedRepo: Boolean, defaults to False. If set to True,
878 the working directory will be made into a
879 bzr shared repository if it is not already.
880 Shared repository greatly reduces the amount
881 of history data that needs to be downloaded
882 if not using update/copy mode, or if using
883 update/copy mode with multiple branches.
884 """
885 self.repourl = repourl
886 self.baseURL = baseURL
887 self.branch = defaultBranch
888 Source.__init__(self, **kwargs)
889 self.addFactoryArguments(repourl=repourl,
890 baseURL=baseURL,
891 defaultBranch=defaultBranch,
892 forceSharedRepo=forceSharedRepo
893 )
894 self.args.update({'forceSharedRepo': forceSharedRepo})
895 if (not repourl and not baseURL) or (repourl and baseURL):
896 raise ValueError("you must provide exactly one of repourl and"
897 " baseURL")
898
900 if not changes:
901 return None
902 lastChange = max([int(c.revision) for c in changes])
903 return lastChange
904
905 - def startVC(self, branch, revision, patch):
929
930
932 """Check out a source tree from a mercurial repository 'repourl'."""
933
934 name = "hg"
935
936 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
937 branchType='dirname', clobberOnBranchChange=True, **kwargs):
938 """
939 @type repourl: string
940 @param repourl: the URL which points at the Mercurial repository.
941 This uses the 'default' branch unless defaultBranch is
942 specified below and the C{branchType} is set to
943 'inrepo'. It is an error to specify a branch without
944 setting the C{branchType} to 'inrepo'.
945
946 @param baseURL: if 'dirname' branches are enabled, this is the base URL
947 to which a branch name will be appended. It should
948 probably end in a slash. Use exactly one of C{repourl}
949 and C{baseURL}.
950
951 @param defaultBranch: if branches are enabled, this is the branch
952 to use if the Build does not specify one
953 explicitly.
954 For 'dirname' branches, It will simply be
955 appended to C{baseURL} and the result handed to
956 the 'hg update' command.
957 For 'inrepo' branches, this specifies the named
958 revision to which the tree will update after a
959 clone.
960
961 @param branchType: either 'dirname' or 'inrepo' depending on whether
962 the branch name should be appended to the C{baseURL}
963 or the branch is a mercurial named branch and can be
964 found within the C{repourl}
965
966 @param clobberOnBranchChange: boolean, defaults to True. If set and
967 using inrepos branches, clobber the tree
968 at each branch change. Otherwise, just
969 update to the branch.
970 """
971 self.repourl = repourl
972 self.baseURL = baseURL
973 self.branch = defaultBranch
974 self.branchType = branchType
975 self.clobberOnBranchChange = clobberOnBranchChange
976 Source.__init__(self, **kwargs)
977 self.addFactoryArguments(repourl=repourl,
978 baseURL=baseURL,
979 defaultBranch=defaultBranch,
980 branchType=branchType,
981 clobberOnBranchChange=clobberOnBranchChange,
982 )
983 if (not repourl and not baseURL) or (repourl and baseURL):
984 raise ValueError("you must provide exactly one of repourl and"
985 " baseURL")
986
987 - def startVC(self, branch, revision, patch):
988 slavever = self.slaveVersion("hg")
989 if not slavever:
990 raise BuildSlaveTooOldError("slave is too old, does not know "
991 "about hg")
992
993 if self.repourl:
994
995 assert self.branchType == 'inrepo' or not branch
996 self.args['repourl'] = self.repourl
997 if branch:
998 self.args['branch'] = branch
999 else:
1000 self.args['repourl'] = self.baseURL + (branch or '')
1001 self.args['revision'] = revision
1002 self.args['patch'] = patch
1003 self.args['clobberOnBranchChange'] = self.clobberOnBranchChange
1004 self.args['branchType'] = self.branchType
1005
1006 revstuff = []
1007 if branch is not None and branch != self.branch:
1008 revstuff.append("[branch]")
1009 self.description.extend(revstuff)
1010 self.descriptionDone.extend(revstuff)
1011
1012 cmd = LoggedRemoteCommand("hg", self.args)
1013 self.startCommand(cmd)
1014
1016 if not changes:
1017 return None
1018
1019
1020
1021
1022 if len(changes) > 1:
1023 log.msg("Mercurial.computeSourceRevision: warning: "
1024 "there are %d changes here, assuming the last one is "
1025 "the most recent" % len(changes))
1026 return changes[-1].revision
1027
1028
1030 """ P4 is a class for accessing perforce revision control"""
1031 name = "p4"
1032
1033 - def __init__(self, p4base, defaultBranch=None, p4port=None, p4user=None,
1034 p4passwd=None, p4extra_views=[],
1035 p4client='buildbot_%(slave)s_%(builder)s', **kwargs):
1036 """
1037 @type p4base: string
1038 @param p4base: A view into a perforce depot, typically
1039 "//depot/proj/"
1040
1041 @type defaultBranch: string
1042 @param defaultBranch: Identify a branch to build by default. Perforce
1043 is a view based branching system. So, the branch
1044 is normally the name after the base. For example,
1045 branch=1.0 is view=//depot/proj/1.0/...
1046 branch=1.1 is view=//depot/proj/1.1/...
1047
1048 @type p4port: string
1049 @param p4port: Specify the perforce server to connection in the format
1050 <host>:<port>. Example "perforce.example.com:1666"
1051
1052 @type p4user: string
1053 @param p4user: The perforce user to run the command as.
1054
1055 @type p4passwd: string
1056 @param p4passwd: The password for the perforce user.
1057
1058 @type p4extra_views: list of tuples
1059 @param p4extra_views: Extra views to be added to
1060 the client that is being used.
1061
1062 @type p4client: string
1063 @param p4client: The perforce client to use for this buildslave.
1064 """
1065
1066 self.branch = defaultBranch
1067 Source.__init__(self, **kwargs)
1068 self.addFactoryArguments(p4base=p4base,
1069 defaultBranch=defaultBranch,
1070 p4port=p4port,
1071 p4user=p4user,
1072 p4passwd=p4passwd,
1073 p4extra_views=p4extra_views,
1074 p4client=p4client,
1075 )
1076 self.args['p4port'] = p4port
1077 self.args['p4user'] = p4user
1078 self.args['p4passwd'] = p4passwd
1079 self.args['p4base'] = p4base
1080 self.args['p4extra_views'] = p4extra_views
1081 self.p4client = p4client
1082
1089
1091 if not changes:
1092 return None
1093 lastChange = max([int(c.revision) for c in changes])
1094 return lastChange
1095
1096 - def startVC(self, branch, revision, patch):
1105
1107 """This is a partial solution for using a P4 source repository. You are
1108 required to manually set up each build slave with a useful P4
1109 environment, which means setting various per-slave environment variables,
1110 and creating a P4 client specification which maps the right files into
1111 the slave's working directory. Once you have done that, this step merely
1112 performs a 'p4 sync' to update that workspace with the newest files.
1113
1114 Each slave needs the following environment:
1115
1116 - PATH: the 'p4' binary must be on the slave's PATH
1117 - P4USER: each slave needs a distinct user account
1118 - P4CLIENT: each slave needs a distinct client specification
1119
1120 You should use 'p4 client' (?) to set up a client view spec which maps
1121 the desired files into $SLAVEBASE/$BUILDERBASE/source .
1122 """
1123
1124 name = "p4sync"
1125
1126 - def __init__(self, p4port, p4user, p4passwd, p4client, **kwargs):
1127 assert kwargs['mode'] == "copy", "P4Sync can only be used in mode=copy"
1128 self.branch = None
1129 Source.__init__(self, **kwargs)
1130 self.addFactoryArguments(p4port=p4port,
1131 p4user=p4user,
1132 p4passwd=p4passwd,
1133 p4client=p4client,
1134 )
1135 self.args['p4port'] = p4port
1136 self.args['p4user'] = p4user
1137 self.args['p4passwd'] = p4passwd
1138 self.args['p4client'] = p4client
1139
1141 if not changes:
1142 return None
1143 lastChange = max([int(c.revision) for c in changes])
1144 return lastChange
1145
1146 - def startVC(self, branch, revision, patch):
1151
1153 """Check out a revision from a monotone server at 'server_addr',
1154 branch 'branch'. 'revision' specifies which revision id to check
1155 out.
1156
1157 This step will first create a local database, if necessary, and then pull
1158 the contents of the server into the database. Then it will do the
1159 checkout/update from this database."""
1160
1161 name = "monotone"
1162
1163 - def __init__(self, server_addr, branch, db_path="monotone.db",
1164 monotone="monotone",
1165 **kwargs):
1176
1181
1187