1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
from zope.interface import implements
from buildbot import util, interfaces
class SourceStamp(util.ComparableMixin):
"""This is a tuple of (branch, revision, patchspec, changes).
C{branch} is always valid, although it may be None to let the Source
step use its default branch. There are three possibilities for the
remaining elements:
- (revision=REV, patchspec=None, changes=None): build REV. If REV is
None, build the HEAD revision from the given branch.
- (revision=REV, patchspec=(LEVEL, DIFF), changes=None): checkout REV,
then apply a patch to the source, with C{patch -pPATCHLEVEL <DIFF}.
If REV is None, checkout HEAD and patch it.
- (revision=None, patchspec=None, changes=[CHANGES]): let the Source
step check out the latest revision indicated by the given Changes.
CHANGES is a tuple of L{buildbot.changes.changes.Change} instances,
and all must be on the same branch.
"""
# all four of these are publically visible attributes
branch = None
revision = None
patch = None
changes = ()
compare_attrs = ('branch', 'revision', 'patch', 'changes')
implements(interfaces.ISourceStamp)
def __init__(self, branch=None, revision=None, patch=None,
changes=None):
self.branch = branch
self.revision = revision
self.patch = patch
if changes:
self.changes = tuple(changes)
self.branch = changes[0].branch
def canBeMergedWith(self, other):
if other.branch != self.branch:
return False # the builds are completely unrelated
if self.changes and other.changes:
# TODO: consider not merging these. It's a tradeoff between
# minimizing the number of builds and obtaining finer-grained
# results.
return True
elif self.changes and not other.changes:
return False # we're using changes, they aren't
elif not self.changes and other.changes:
return False # they're using changes, we aren't
if self.patch or other.patch:
return False # you can't merge patched builds with anything
if self.revision == other.revision:
# both builds are using the same specific revision, so they can
# be merged. It might be the case that revision==None, so they're
# both building HEAD.
return True
return False
def mergeWith(self, others):
"""Generate a SourceStamp for the merger of me and all the other
BuildRequests. This is called by a Build when it starts, to figure
out what its sourceStamp should be."""
# either we're all building the same thing (changes==None), or we're
# all building changes (which can be merged)
changes = []
changes.extend(self.changes)
for req in others:
assert self.canBeMergedWith(req) # should have been checked already
changes.extend(req.changes)
newsource = SourceStamp(branch=self.branch,
revision=self.revision,
patch=self.patch,
changes=changes)
return newsource
def getAbsoluteSourceStamp(self, got_revision):
return SourceStamp(branch=self.branch, revision=got_revision, patch=self.patch)
def getText(self):
# TODO: this won't work for VC's with huge 'revision' strings
if self.revision is None:
return [ "latest" ]
text = [ str(self.revision) ]
if self.branch:
text.append("in '%s'" % self.branch)
if self.patch:
text.append("[patch]")
return text
|