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 'timeout': timeout,
126 'retry': retry,
127 'patch': None,
128 }
129
130 self.workdir = workdir
131
132 self.alwaysUseLatest = alwaysUseLatest
133
134
135 description = ["updating"]
136 descriptionDone = ["update"]
137 if mode == "clobber":
138 description = ["checkout"]
139
140 descriptionDone = ["checkout"]
141 elif mode == "export":
142 description = ["exporting"]
143 descriptionDone = ["export"]
144 self.description = description
145 self.descriptionDone = descriptionDone
146
149
152
157
159 """Each subclass must implement this method to do something more
160 precise than -rHEAD every time. For version control systems that use
161 repository-wide change numbers (SVN, P4), this can simply take the
162 maximum such number from all the changes involved in this build. For
163 systems that do not (CVS), it needs to create a timestamp based upon
164 the latest Change, the Build's treeStableTimer, and an optional
165 self.checkoutDelay value."""
166 return None
167
195
232
234 if cmd.updates.has_key("got_revision"):
235 got_revision = cmd.updates["got_revision"][-1]
236 if got_revision is not None:
237 self.setProperty("got_revision", str(got_revision), "Source")
238
239
240
242 """I perform BitKeeper checkout/update operations."""
243
244 name = 'bk'
245
246 - def __init__(self, bkurl=None, baseURL=None,
247 directory=None, extra_args=None, **kwargs):
248 """
249 @type bkurl: string
250 @param bkurl: the URL which points to the BitKeeper server.
251
252 @type baseURL: string
253 @param baseURL: if branches are enabled, this is the base URL to
254 which a branch name will be appended. It should
255 probably end in a slash. Use exactly one of
256 C{bkurl} and C{baseURL}.
257 """
258
259 self.bkurl = bkurl
260 self.baseURL = baseURL
261 self.extra_args = extra_args
262
263 Source.__init__(self, **kwargs)
264 self.addFactoryArguments(bkurl=bkurl,
265 baseURL=baseURL,
266 directory=directory,
267 extra_args=extra_args,
268 )
269
270 if bkurl and baseURL:
271 raise ValueError("you must use exactly one of bkurl and baseURL")
272
273
276
277
278 - def startVC(self, branch, revision, patch):
308
309
310
312 """I do CVS checkout/update operations.
313
314 Note: if you are doing anonymous/pserver CVS operations, you will need
315 to manually do a 'cvs login' on each buildslave before the slave has any
316 hope of success. XXX: fix then, take a cvs password as an argument and
317 figure out how to do a 'cvs login' on each build
318 """
319
320 name = "cvs"
321
322
323
324
325
326
327
328
329
330
331
332 - def __init__(self, cvsroot=None, cvsmodule="",
333 global_options=[], branch=None, checkoutDelay=None,
334 checkout_options=[], export_options=[], extra_options=[],
335 login=None,
336 **kwargs):
337
338 """
339 @type cvsroot: string
340 @param cvsroot: CVS Repository from which the source tree should
341 be obtained. '/home/warner/Repository' for local
342 or NFS-reachable repositories,
343 ':pserver:anon@foo.com:/cvs' for anonymous CVS,
344 'user@host.com:/cvs' for non-anonymous CVS or
345 CVS over ssh. Lots of possibilities, check the
346 CVS documentation for more.
347
348 @type cvsmodule: string
349 @param cvsmodule: subdirectory of CVS repository that should be
350 retrieved
351
352 @type login: string or None
353 @param login: if not None, a string which will be provided as a
354 password to the 'cvs login' command, used when a
355 :pserver: method is used to access the repository.
356 This login is only needed once, but must be run
357 each time (just before the CVS operation) because
358 there is no way for the buildslave to tell whether
359 it was previously performed or not.
360
361 @type branch: string
362 @param branch: the default branch name, will be used in a '-r'
363 argument to specify which branch of the source tree
364 should be used for this checkout. Defaults to None,
365 which means to use 'HEAD'.
366
367 @type checkoutDelay: int or None
368 @param checkoutDelay: if not None, the number of seconds to put
369 between the last known Change and the
370 timestamp given to the -D argument. This
371 defaults to exactly half of the parent
372 Build's .treeStableTimer, but it could be
373 set to something else if your CVS change
374 notification has particularly weird
375 latency characteristics.
376
377 @type global_options: list of strings
378 @param global_options: these arguments are inserted in the cvs
379 command line, before the
380 'checkout'/'update' command word. See
381 'cvs --help-options' for a list of what
382 may be accepted here. ['-r'] will make
383 the checked out files read only. ['-r',
384 '-R'] will also assume the repository is
385 read-only (I assume this means it won't
386 use locks to insure atomic access to the
387 ,v files).
388
389 @type checkout_options: list of strings
390 @param checkout_options: these arguments are inserted in the cvs
391 command line, after 'checkout' but before
392 branch or revision specifiers.
393
394 @type export_options: list of strings
395 @param export_options: these arguments are inserted in the cvs
396 command line, after 'export' but before
397 branch or revision specifiers.
398
399 @type extra_options: list of strings
400 @param extra_options: these arguments are inserted in the cvs
401 command line, after 'checkout' or 'export' but before
402 branch or revision specifiers.
403 """
404
405 self.checkoutDelay = checkoutDelay
406 self.branch = branch
407 self.cvsroot = cvsroot
408
409 Source.__init__(self, **kwargs)
410 self.addFactoryArguments(cvsroot=cvsroot,
411 cvsmodule=cvsmodule,
412 global_options=global_options,
413 checkout_options=checkout_options,
414 export_options=export_options,
415 extra_options=extra_options,
416 branch=branch,
417 checkoutDelay=checkoutDelay,
418 login=login,
419 )
420
421 self.args.update({'cvsmodule': cvsmodule,
422 'global_options': global_options,
423 'checkout_options':checkout_options,
424 'export_options':export_options,
425 'extra_options':extra_options,
426 'login': login,
427 })
428
430 if not changes:
431 return None
432 lastChange = max([c.when for c in changes])
433 if self.checkoutDelay is not None:
434 when = lastChange + self.checkoutDelay
435 else:
436 lastSubmit = max([r.submittedAt for r in self.build.requests])
437 when = (lastChange + lastSubmit) / 2
438 return formatdate(when)
439
440 - def startVC(self, branch, revision, patch):
441 if self.slaveVersionIsOlderThan("cvs", "1.39"):
442
443
444
445
446
447 if (branch != self.branch
448 and self.args['mode'] in ("update", "copy")):
449 m = ("This buildslave (%s) does not know about multiple "
450 "branches, and using mode=%s would probably build the "
451 "wrong tree. "
452 "Refusing to build. Please upgrade the buildslave to "
453 "buildbot-0.7.0 or newer." % (self.build.slavename,
454 self.args['mode']))
455 log.msg(m)
456 raise BuildSlaveTooOldError(m)
457
458 if self.slaveVersionIsOlderThan("cvs", "2.10"):
459 if self.args['extra_options'] or self.args['export_options']:
460 m = ("This buildslave (%s) does not support export_options "
461 "or extra_options arguments to the CVS step."
462 % (self.build.slavename))
463 log.msg(m)
464 raise BuildSlaveTooOldError(m)
465
466
467 del self.args['export_options']
468 del self.args['extra_options']
469
470 if branch is None:
471 branch = "HEAD"
472 self.args['cvsroot'] = self.computeRepositoryURL(self.cvsroot)
473 self.args['branch'] = branch
474 self.args['revision'] = revision
475 self.args['patch'] = patch
476
477 if self.args['branch'] == "HEAD" and self.args['revision']:
478
479
480 self.args['branch'] = None
481
482
483 warnings = []
484 slavever = self.slaveVersion("cvs", "old")
485
486 if slavever == "old":
487
488 if self.args['mode'] == "export":
489 self.args['export'] = 1
490 elif self.args['mode'] == "clobber":
491 self.args['clobber'] = 1
492 elif self.args['mode'] == "copy":
493 self.args['copydir'] = "source"
494 self.args['tag'] = self.args['branch']
495 assert not self.args['patch']
496
497 cmd = LoggedRemoteCommand("cvs", self.args)
498 self.startCommand(cmd, warnings)
499
500
502 """I perform Subversion checkout/update operations."""
503
504 name = 'svn'
505 branch_placeholder = '%%BRANCH%%'
506
507 - def __init__(self, svnurl=None, baseURL=None, defaultBranch=None,
508 directory=None, username=None, password=None,
509 extra_args=None, keep_on_purge=None, ignore_ignores=None,
510 always_purge=None, depth=None, **kwargs):
511 """
512 @type svnurl: string
513 @param svnurl: the URL which points to the Subversion server,
514 combining the access method (HTTP, ssh, local file),
515 the repository host/port, the repository path, the
516 sub-tree within the repository, and the branch to
517 check out. Use exactly one of C{svnurl} and C{baseURL}.
518
519 @param baseURL: if branches are enabled, this is the base URL to
520 which a branch name will be appended. It should
521 probably end in a slash. Use exactly one of
522 C{svnurl} and C{baseURL}.
523
524 @param defaultBranch: if branches are enabled, this is the branch
525 to use if the Build does not specify one
526 explicitly. It will simply be appended
527 to C{baseURL} and the result handed to
528 the SVN command.
529
530 @type username: string
531 @param username: username to pass to svn's --username
532
533 @type password: string
534 @param password: password to pass to svn's --password
535 """
536
537 if not 'workdir' in kwargs and directory is not None:
538
539 warn("Please use workdir=, not directory=", DeprecationWarning)
540 kwargs['workdir'] = directory
541
542 self.svnurl = svnurl
543 self.baseURL = baseURL
544 self.branch = defaultBranch
545 self.username = username
546 self.password = password
547 self.extra_args = extra_args
548 self.keep_on_purge = keep_on_purge
549 self.ignore_ignores = ignore_ignores
550 self.always_purge = always_purge
551 self.depth = depth
552
553 Source.__init__(self, **kwargs)
554 self.addFactoryArguments(svnurl=svnurl,
555 baseURL=baseURL,
556 defaultBranch=defaultBranch,
557 directory=directory,
558 username=username,
559 password=password,
560 extra_args=extra_args,
561 keep_on_purge=keep_on_purge,
562 ignore_ignores=ignore_ignores,
563 always_purge=always_purge,
564 depth=depth,
565 )
566
567 if svnurl and baseURL:
568 raise ValueError("you must use either svnurl OR baseURL")
569
575
577 ''' Handle compatibility between old slaves/svn clients '''
578
579 slavever = self.slaveVersion("svn", "old")
580
581 if not slavever:
582 m = "slave does not have the 'svn' command"
583 raise BuildSlaveTooOldError(m)
584
585 if self.slaveVersionIsOlderThan("svn", "1.39"):
586
587
588
589
590
591 if (self.args['branch'] != self.branch
592 and self.args['mode'] in ("update", "copy")):
593 m = ("This buildslave (%s) does not know about multiple "
594 "branches, and using mode=%s would probably build the "
595 "wrong tree. "
596 "Refusing to build. Please upgrade the buildslave to "
597 "buildbot-0.7.0 or newer." % (self.build.slavename,
598 self.args['mode']))
599 raise BuildSlaveTooOldError(m)
600
601 if (self.depth is not None) and self.slaveVersionIsOlderThan("svn","2.9"):
602 m = ("This buildslave (%s) does not support svn depth "
603 "arguments. Refusing to build. "
604 "Please upgrade the buildslave." % (self.build.slavename))
605 raise BuildSlaveTooOldError(m)
606
607 if (self.username is not None or self.password is not None) \
608 and self.slaveVersionIsOlderThan("svn", "2.8"):
609 m = ("This buildslave (%s) does not support svn usernames "
610 "and passwords. "
611 "Refusing to build. Please upgrade the buildslave to "
612 "buildbot-0.7.10 or newer." % (self.build.slavename,))
613 raise BuildSlaveTooOldError(m)
614
615 - def getSvnUrl(self, branch, revision, patch):
616 ''' Compute the svn url that will be passed to the svn remote command '''
617 if self.svnurl:
618 return self.computeRepositoryURL(self.svnurl)
619 else:
620 if branch is None:
621 m = ("The SVN source step belonging to builder '%s' does not know "
622 "which branch to work with. This means that the change source "
623 "did not specify a branch and that defaultBranch is None." \
624 % self.build.builder.name)
625 raise RuntimeError(m)
626
627 computed = self.computeRepositoryURL(self.baseURL)
628
629 if self.branch_placeholder in self.baseURL:
630 return computed.replace(self.branch_placeholder, branch)
631 else:
632 return computed + branch
633
634 - def startVC(self, branch, revision, patch):
635 warnings = []
636
637 self.checkCompatibility()
638
639 self.args['svnurl'] = self.getSvnUrl(branch, revision, patch)
640 self.args['revision'] = revision
641 self.args['patch'] = patch
642 self.args['always_purge'] = self.always_purge
643
644
645 if self.depth is not None:
646 self.args['depth'] = self.depth
647
648 if self.username is not None:
649 self.args['username'] = self.username
650 if self.password is not None:
651 self.args['password'] = self.password
652
653 if self.extra_args is not None:
654 self.args['extra_args'] = self.extra_args
655
656 revstuff = []
657
658 if self.args['svnurl'].find('trunk') == -1:
659 revstuff.append("[branch]")
660 if revision is not None:
661 revstuff.append("r%s" % revision)
662 if patch is not None:
663 revstuff.append("[patch]")
664 self.description.extend(revstuff)
665 self.descriptionDone.extend(revstuff)
666
667 cmd = LoggedRemoteCommand("svn", self.args)
668 self.startCommand(cmd, warnings)
669
670
672 """Check out a source tree from a Darcs repository at 'repourl'.
673
674 Darcs has no concept of file modes. This means the eXecute-bit will be
675 cleared on all source files. As a result, you may need to invoke
676 configuration scripts with something like:
677
678 C{s(step.Configure, command=['/bin/sh', './configure'])}
679 """
680
681 name = "darcs"
682
683 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
684 **kwargs):
685 """
686 @type repourl: string
687 @param repourl: the URL which points at the Darcs repository. This
688 is used as the default branch. Using C{repourl} does
689 not enable builds of alternate branches: use
690 C{baseURL} to enable this. Use either C{repourl} or
691 C{baseURL}, not both.
692
693 @param baseURL: if branches are enabled, this is the base URL to
694 which a branch name will be appended. It should
695 probably end in a slash. Use exactly one of
696 C{repourl} and C{baseURL}.
697
698 @param defaultBranch: if branches are enabled, this is the branch
699 to use if the Build does not specify one
700 explicitly. It will simply be appended to
701 C{baseURL} and the result handed to the
702 'darcs pull' command.
703 """
704 self.repourl = repourl
705 self.baseURL = baseURL
706 self.branch = defaultBranch
707 Source.__init__(self, **kwargs)
708 self.addFactoryArguments(repourl=repourl,
709 baseURL=baseURL,
710 defaultBranch=defaultBranch,
711 )
712 assert self.args['mode'] != "export", \
713 "Darcs does not have an 'export' mode"
714 if repourl and baseURL:
715 raise ValueError("you must provide exactly one of repourl and"
716 " baseURL")
717
718 - def startVC(self, branch, revision, patch):
761
762
764 """Check out a source tree from a git repository 'repourl'."""
765
766 name = "git"
767
768 - def __init__(self, repourl=None,
769 branch="master",
770 submodules=False,
771 ignore_ignores=None,
772 reference=None,
773 shallow=False,
774 progress=False,
775 **kwargs):
776 """
777 @type repourl: string
778 @param repourl: the URL which points at the git repository
779
780 @type branch: string
781 @param branch: The branch or tag to check out by default. If
782 a build specifies a different branch, it will
783 be used instead of this.
784
785 @type submodules: boolean
786 @param submodules: Whether or not to update (and initialize)
787 git submodules.
788
789 @type reference: string
790 @param reference: The path to a reference repository to obtain
791 objects from, if any.
792
793 @type shallow: boolean
794 @param shallow: Use a shallow or clone, if possible
795
796 @type progress: boolean
797 @param progress: Pass the --progress option when fetching. This
798 can solve long fetches getting killed due to
799 lack of output, but requires Git 1.7.2+.
800 """
801 Source.__init__(self, **kwargs)
802 self.repourl = repourl
803 self.addFactoryArguments(repourl=repourl,
804 branch=branch,
805 submodules=submodules,
806 ignore_ignores=ignore_ignores,
807 reference=reference,
808 shallow=shallow,
809 progress=progress,
810 )
811 self.args.update({'branch': branch,
812 'submodules': submodules,
813 'ignore_ignores': ignore_ignores,
814 'reference': reference,
815 'shallow': shallow,
816 'progress': progress,
817 })
818
823
824 - def startVC(self, branch, revision, patch):
837
838
840 """Check out a source tree from a bzr (Bazaar) repository at 'repourl'.
841
842 """
843
844 name = "bzr"
845
846 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
847 forceSharedRepo=None,
848 **kwargs):
849 """
850 @type repourl: string
851 @param repourl: the URL which points at the bzr repository. This
852 is used as the default branch. Using C{repourl} does
853 not enable builds of alternate branches: use
854 C{baseURL} to enable this. Use either C{repourl} or
855 C{baseURL}, not both.
856
857 @param baseURL: if branches are enabled, this is the base URL to
858 which a branch name will be appended. It should
859 probably end in a slash. Use exactly one of
860 C{repourl} and C{baseURL}.
861
862 @param defaultBranch: if branches are enabled, this is the branch
863 to use if the Build does not specify one
864 explicitly. It will simply be appended to
865 C{baseURL} and the result handed to the
866 'bzr checkout pull' command.
867
868
869 @param forceSharedRepo: Boolean, defaults to False. If set to True,
870 the working directory will be made into a
871 bzr shared repository if it is not already.
872 Shared repository greatly reduces the amount
873 of history data that needs to be downloaded
874 if not using update/copy mode, or if using
875 update/copy mode with multiple branches.
876 """
877 self.repourl = repourl
878 self.baseURL = baseURL
879 self.branch = defaultBranch
880 Source.__init__(self, **kwargs)
881 self.addFactoryArguments(repourl=repourl,
882 baseURL=baseURL,
883 defaultBranch=defaultBranch,
884 forceSharedRepo=forceSharedRepo
885 )
886 self.args.update({'forceSharedRepo': forceSharedRepo})
887 if repourl and baseURL:
888 raise ValueError("you must provide exactly one of repourl and"
889 " baseURL")
890
892 if not changes:
893 return None
894 lastChange = max([int(c.revision) for c in changes])
895 return lastChange
896
897 - def startVC(self, branch, revision, patch):
921
922
924 """Check out a source tree from a mercurial repository 'repourl'."""
925
926 name = "hg"
927
928 - def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
929 branchType='dirname', clobberOnBranchChange=True, **kwargs):
930 """
931 @type repourl: string
932 @param repourl: the URL which points at the Mercurial repository.
933 This uses the 'default' branch unless defaultBranch is
934 specified below and the C{branchType} is set to
935 'inrepo'. It is an error to specify a branch without
936 setting the C{branchType} to 'inrepo'.
937
938 @param baseURL: if 'dirname' branches are enabled, this is the base URL
939 to which a branch name will be appended. It should
940 probably end in a slash. Use exactly one of C{repourl}
941 and C{baseURL}.
942
943 @param defaultBranch: if branches are enabled, this is the branch
944 to use if the Build does not specify one
945 explicitly.
946 For 'dirname' branches, It will simply be
947 appended to C{baseURL} and the result handed to
948 the 'hg update' command.
949 For 'inrepo' branches, this specifies the named
950 revision to which the tree will update after a
951 clone.
952
953 @param branchType: either 'dirname' or 'inrepo' depending on whether
954 the branch name should be appended to the C{baseURL}
955 or the branch is a mercurial named branch and can be
956 found within the C{repourl}
957
958 @param clobberOnBranchChange: boolean, defaults to True. If set and
959 using inrepos branches, clobber the tree
960 at each branch change. Otherwise, just
961 update to the branch.
962 """
963 self.repourl = repourl
964 self.baseURL = baseURL
965 self.branch = defaultBranch
966 self.branchType = branchType
967 self.clobberOnBranchChange = clobberOnBranchChange
968 Source.__init__(self, **kwargs)
969 self.addFactoryArguments(repourl=repourl,
970 baseURL=baseURL,
971 defaultBranch=defaultBranch,
972 branchType=branchType,
973 clobberOnBranchChange=clobberOnBranchChange,
974 )
975 if repourl and baseURL:
976 raise ValueError("you must provide exactly one of repourl and"
977 " baseURL")
978
979 - def startVC(self, branch, revision, patch):
1006
1008 if not changes:
1009 return None
1010
1011
1012
1013
1014 if len(changes) > 1:
1015 log.msg("Mercurial.computeSourceRevision: warning: "
1016 "there are %d changes here, assuming the last one is "
1017 "the most recent" % len(changes))
1018 return changes[-1].revision
1019
1020
1022 """ P4 is a class for accessing perforce revision control"""
1023 name = "p4"
1024
1025 - def __init__(self, p4base=None, defaultBranch=None, p4port=None, p4user=None,
1026 p4passwd=None, p4extra_views=[], p4line_end='local',
1027 p4client='buildbot_%(slave)s_%(builder)s', **kwargs):
1028 """
1029 @type p4base: string
1030 @param p4base: A view into a perforce depot, typically
1031 "//depot/proj/"
1032
1033 @type defaultBranch: string
1034 @param defaultBranch: Identify a branch to build by default. Perforce
1035 is a view based branching system. So, the branch
1036 is normally the name after the base. For example,
1037 branch=1.0 is view=//depot/proj/1.0/...
1038 branch=1.1 is view=//depot/proj/1.1/...
1039
1040 @type p4port: string
1041 @param p4port: Specify the perforce server to connection in the format
1042 <host>:<port>. Example "perforce.example.com:1666"
1043
1044 @type p4user: string
1045 @param p4user: The perforce user to run the command as.
1046
1047 @type p4passwd: string
1048 @param p4passwd: The password for the perforce user.
1049
1050 @type p4extra_views: list of tuples
1051 @param p4extra_views: Extra views to be added to
1052 the client that is being used.
1053
1054 @type p4line_end: string
1055 @param p4line_end: value of the LineEnd client specification property
1056
1057 @type p4client: string
1058 @param p4client: The perforce client to use for this buildslave.
1059 """
1060
1061 self.p4base = p4base
1062 self.branch = defaultBranch
1063 Source.__init__(self, **kwargs)
1064 self.addFactoryArguments(p4base=p4base,
1065 defaultBranch=defaultBranch,
1066 p4port=p4port,
1067 p4user=p4user,
1068 p4passwd=p4passwd,
1069 p4extra_views=p4extra_views,
1070 p4line_end=p4line_end,
1071 p4client=p4client,
1072 )
1073 self.args['p4port'] = p4port
1074 self.args['p4user'] = p4user
1075 self.args['p4passwd'] = p4passwd
1076 self.args['p4extra_views'] = p4extra_views
1077 self.args['p4line_end'] = p4line_end
1078 self.p4client = p4client
1079
1087
1089 if not changes:
1090 return None
1091 lastChange = max([int(c.revision) for c in changes])
1092 return lastChange
1093
1094 - def startVC(self, branch, revision, patch):
1103
1105 """This is a partial solution for using a P4 source repository. You are
1106 required to manually set up each build slave with a useful P4
1107 environment, which means setting various per-slave environment variables,
1108 and creating a P4 client specification which maps the right files into
1109 the slave's working directory. Once you have done that, this step merely
1110 performs a 'p4 sync' to update that workspace with the newest files.
1111
1112 Each slave needs the following environment:
1113
1114 - PATH: the 'p4' binary must be on the slave's PATH
1115 - P4USER: each slave needs a distinct user account
1116 - P4CLIENT: each slave needs a distinct client specification
1117
1118 You should use 'p4 client' (?) to set up a client view spec which maps
1119 the desired files into $SLAVEBASE/$BUILDERBASE/source .
1120 """
1121
1122 name = "p4sync"
1123
1124 - def __init__(self, p4port, p4user, p4passwd, p4client, **kwargs):
1125 assert kwargs['mode'] == "copy", "P4Sync can only be used in mode=copy"
1126 self.branch = None
1127 Source.__init__(self, **kwargs)
1128 self.addFactoryArguments(p4port=p4port,
1129 p4user=p4user,
1130 p4passwd=p4passwd,
1131 p4client=p4client,
1132 )
1133 self.args['p4port'] = p4port
1134 self.args['p4user'] = p4user
1135 self.args['p4passwd'] = p4passwd
1136 self.args['p4client'] = p4client
1137
1139 if not changes:
1140 return None
1141 lastChange = max([int(c.revision) for c in changes])
1142 return lastChange
1143
1144 - def startVC(self, branch, revision, patch):
1149