1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import time
17
18 from buildbot import interfaces, util
19 from buildbot.util import collections, NotABranch
20 from buildbot.sourcestamp import SourceStamp
21 from buildbot.status.builder import SUCCESS, WARNINGS
22 from buildbot.schedulers import base
23
24 -class Scheduler(base.BaseScheduler, base.ClassifierMixin):
25 fileIsImportant = None
26 compare_attrs = ('name', 'treeStableTimer', 'builderNames',
27 'fileIsImportant', 'properties', 'change_filter')
28
29 - def __init__(self, name, shouldntBeSet=NotABranch, treeStableTimer=None,
30 builderNames=None, branch=NotABranch, fileIsImportant=None,
31 properties={}, categories=None, change_filter=None):
32 """
33 @param name: the name of this Scheduler
34 @param treeStableTimer: the duration, in seconds, for which the tree
35 must remain unchanged before a build is
36 triggered. This is intended to avoid builds
37 of partially-committed fixes. If None, then
38 a separate build will be made for each
39 Change, regardless of when they arrive.
40 @param builderNames: a list of Builder names. When this Scheduler
41 decides to start a set of builds, they will be
42 run on the Builders named by this list.
43
44 @param fileIsImportant: A callable which takes one argument (a Change
45 instance) and returns True if the change is
46 worth building, and False if it is not.
47 Unimportant Changes are accumulated until the
48 build is triggered by an important change.
49 The default value of None means that all
50 Changes are important.
51
52 @param properties: properties to apply to all builds started from
53 this scheduler
54
55 @param change_filter: a buildbot.schedulers.filter.ChangeFilter instance
56 used to filter changes for this scheduler
57
58 @param branch: The branch name that the Scheduler should pay
59 attention to. Any Change that is not in this branch
60 will be ignored. It can be set to None to only pay
61 attention to the default branch.
62 @param categories: A list of categories of changes to accept
63 """
64 assert shouldntBeSet is NotABranch, \
65 "pass arguments to Scheduler using keyword arguments"
66
67 base.BaseScheduler.__init__(self, name, builderNames, properties)
68 self.make_filter(change_filter=change_filter, branch=branch, categories=categories)
69 self.treeStableTimer = treeStableTimer
70 self.stableAt = None
71 self.branch = branch
72 if fileIsImportant:
73 assert callable(fileIsImportant)
74 self.fileIsImportant = fileIsImportant
75
77 return {"last_processed": max_changeid}
78
84
90
92 """Look at the changes that need to be processed and decide whether
93 to queue a BuildRequest or sleep until something changes.
94
95 If I decide that a build should be performed, I will add the
96 appropriate BuildRequest to the database queue, and remove the
97 (retired) changes that went into it from the scheduler_changes table.
98
99 Returns wakeup_delay: either None, or a float indicating when this
100 scheduler wants to be woken up next. The Scheduler is responsible for
101 padding its desired wakeup time by about a second to avoid frenetic
102 must-wake-up-at-exactly-8AM behavior. The Loop may silently impose a
103 minimum delay request of a couple seconds to prevent this sort of
104 thing, but Schedulers must still add their own padding to avoid at
105 least a double wakeup.
106 """
107
108 if not important:
109 return None
110 all_changes = important + unimportant
111 most_recent = max([c.when for c in all_changes])
112 if self.treeStableTimer is not None:
113 now = time.time()
114 self.stableAt = most_recent + self.treeStableTimer
115 if self.stableAt > now:
116
117
118 return self.stableAt + 1.0
119
120
121 self.stableAt = None
122 self._add_build_and_remove_changes(t, important, unimportant)
123 return None
124
126
127
128
129
130 all_changes = sorted(important + unimportant, key=lambda c : c.number)
131
132 db = self.parent.db
133 if self.treeStableTimer is None:
134
135
136 for c in sorted(important, key=lambda c : c.number):
137 ss = SourceStamp(changes=[c])
138 ssid = db.get_sourcestampid(ss, t)
139 self.create_buildset(ssid, "scheduler", t)
140 else:
141
142
143
144 ss = SourceStamp(changes=all_changes)
145 ssid = db.get_sourcestampid(ss, t)
146 self.create_buildset(ssid, "scheduler", t)
147
148
149
150 changeids = [c.number for c in all_changes]
151 db.scheduler_retire_changes(self.schedulerid, changeids, t)
152
153
155 if self.stableAt and self.stableAt > util.now():
156 return [ self.stableAt ]
157 return []
158
160 compare_attrs = ('name', 'treeStableTimer', 'builderNames',
161 'fileIsImportant', 'properties', 'change_filter')
162 - def __init__(self, name, treeStableTimer, builderNames,
163 fileIsImportant=None, properties={}, categories=None,
164 branches=NotABranch, change_filter=None):
165 """
166 Same parameters as the scheduler, but without 'branch', and adding:
167
168 @param branches: (deprecated)
169 """
170
171 Scheduler.__init__(self, name, builderNames=builderNames, properties=properties,
172 categories=categories, treeStableTimer=treeStableTimer,
173 fileIsImportant=fileIsImportant, change_filter=change_filter,
174
175 branch=branches)
176
178 db = self.parent.db
179 res = db.scheduler_get_classified_changes(self.schedulerid, t)
180 (important, unimportant) = res
181 def _twolists(): return [], []
182 branch_changes = collections.defaultdict(_twolists)
183 for c in important:
184 branch_changes[c.branch][0].append(c)
185 for c in unimportant:
186 branch_changes[c.branch][1].append(c)
187 delays = []
188 for branch in branch_changes:
189 (b_important, b_unimportant) = branch_changes[branch]
190 delay = self.decide_and_remove_changes(t, b_important,
191 b_unimportant)
192 if delay is not None:
193 delays.append(delay)
194 if delays:
195 return min(delays)
196 return None
197
199
200
201 compare_attrs = ('name', 'upstream_name', 'builderNames', 'properties')
202
203 - def __init__(self, name, upstream, builderNames, properties={}):
210
214
230
231
232
233
234
235
236
237
238
239
240
241
242
243