blob: 2bf3cc0b52f7fcaab16d78b3930f9c4bebb4e345 [file] [log] [blame]
Chris Masone2d61ca22012-04-02 16:52:46 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Chris Masone83af70c2012-04-18 14:33:05 -07005import datetime, logging
Chris Masone2d61ca22012-04-02 16:52:46 -07006import base_event, forgiving_config_parser, task
7
8
9class TimedEvent(base_event.BaseEvent):
Chris Masone5bde7dc2012-04-09 17:08:19 -070010 """Base class for events that trigger based on time/day.
11
Chris Masone93f51d42012-04-18 08:46:52 -070012 @var _deadline: If this time has passed, ShouldHandle() returns True.
Chris Masone5bde7dc2012-04-09 17:08:19 -070013 """
Chris Masone2d61ca22012-04-02 16:52:46 -070014
Chris Masone2d61ca22012-04-02 16:52:46 -070015
Chris Masone93f51d42012-04-18 08:46:52 -070016 def __init__(self, keyword, manifest_versions, always_handle, deadline):
17 """Constructor.
Chris Masone2d61ca22012-04-02 16:52:46 -070018
Chris Masone93f51d42012-04-18 08:46:52 -070019 @param keyword: the keyword/name of this event, e.g. nightly.
20 @param manifest_versions: ManifestVersions instance to use for querying.
21 @param always_handle: If True, make ShouldHandle() always return True.
22 @param deadline: This instance's initial |_deadline|.
23 """
24 super(TimedEvent, self).__init__(keyword, manifest_versions,
25 always_handle)
Chris Masone2d61ca22012-04-02 16:52:46 -070026 self._deadline = deadline
27
28
29 def __ne__(self, other):
Chris Masone96f16632012-04-04 18:36:03 -070030 return self._deadline != other._deadline or self.tasks != other.tasks
Chris Masone2d61ca22012-04-02 16:52:46 -070031
32
33 def __eq__(self, other):
Chris Masone96f16632012-04-04 18:36:03 -070034 return self._deadline == other._deadline and self.tasks == other.tasks
Chris Masone2d61ca22012-04-02 16:52:46 -070035
36
37 @staticmethod
Chris Masone2d61ca22012-04-02 16:52:46 -070038 def _now():
39 return datetime.datetime.now()
40
41
Chris Masone73a78382012-04-20 13:25:51 -070042 def Prepare(self):
43 pass
44
45
Chris Masone2d61ca22012-04-02 16:52:46 -070046 def ShouldHandle(self):
47 """Return True if self._deadline has passed; False if not."""
Chris Masone99d32b82012-07-11 10:29:55 -070048 if super(TimedEvent, self).ShouldHandle():
49 return True
50 else:
Chris Masone075aafa2012-05-09 12:08:59 -070051 logging.info('Checking deadline %s for event %s',
52 self._deadline, self.keyword)
Chris Masone855d86f2012-05-07 13:48:07 -070053 return self._now() >= self._deadline
Chris Masone2d61ca22012-04-02 16:52:46 -070054
55
Chris Masoned17d1852012-04-20 11:52:49 -070056 def _LatestPerBranchBuildsSince(self, board, days_ago):
Chris Masone5bde7dc2012-04-09 17:08:19 -070057 """Get latest per-branch, per-board builds from last |days_ago| days.
58
59 @param board: the board whose builds we want.
60 @param days_ago: how many days back to look for manifests.
Chris Masone05b19442012-04-17 13:37:55 -070061 @return {branch: [build-name]}
Chris Masone5bde7dc2012-04-09 17:08:19 -070062 """
Chris Masoned17d1852012-04-20 11:52:49 -070063 all_branch_manifests = self._mv.ManifestsSinceDays(days_ago, board)
Chris Masone67f06d62012-04-12 15:16:56 -070064 latest_branch_builds = {}
Chris Masone5bde7dc2012-04-09 17:08:19 -070065 for (type, milestone), manifests in all_branch_manifests.iteritems():
Chris Masone9ee3eca2012-04-17 14:53:05 -070066 build = base_event.BuildName(board, type, milestone, manifests[-1])
67 latest_branch_builds[task.PickBranchName(type, milestone)] = [build]
Chris Masone075aafa2012-05-09 12:08:59 -070068 logging.info('%s event found candidate builds: %r',
69 self.keyword, latest_branch_builds)
Chris Masone67f06d62012-04-12 15:16:56 -070070 return latest_branch_builds
Chris Masone5bde7dc2012-04-09 17:08:19 -070071
72
73class Nightly(TimedEvent):
74 """A TimedEvent that happens every night.
75
76 @var KEYWORD: the keyword to use in a run_on option to associate a task
77 with the Nightly event.
78 @var _DEFAULT_HOUR: can be overridden in the "nightly_params" config section
79 """
Chris Masone2d61ca22012-04-02 16:52:46 -070080
81 KEYWORD = 'nightly'
82 _DEFAULT_HOUR = 21
83
84
85 @classmethod
86 def _ParseConfig(cls, config):
Chris Masone83af70c2012-04-18 14:33:05 -070087 """Create args to pass to __init__ by parsing |config|.
88
Chris Masone93f51d42012-04-18 08:46:52 -070089 Calls super class' _ParseConfig() method, then parses these additonal
90 options:
91 hour: Integer hour, on a 24 hour clock.
Chris Masone83af70c2012-04-18 14:33:05 -070092 """
Chris Masone93f51d42012-04-18 08:46:52 -070093 from_base = super(Nightly, cls)._ParseConfig(config)
94
95 section = base_event.SectionName(cls.KEYWORD)
Chris Masone2d61ca22012-04-02 16:52:46 -070096 event_time = config.getint(section, 'hour') or cls._DEFAULT_HOUR
Chris Masone93f51d42012-04-18 08:46:52 -070097
98 from_base.update({'event_time': event_time})
99 return from_base
Chris Masone2d61ca22012-04-02 16:52:46 -0700100
101
Chris Masone93f51d42012-04-18 08:46:52 -0700102 def __init__(self, manifest_versions, always_handle, event_time):
103 """Constructor.
104
105 @param manifest_versions: ManifestVersions instance to use for querying.
106 @param always_handle: If True, make ShouldHandle() always return True.
107 @param event_time: The hour of the day to set |self._deadline| at.
108 """
Chris Masone2d61ca22012-04-02 16:52:46 -0700109 # determine if we're past today's nightly event and set the
110 # next deadline for this suite appropriately.
111 now = self._now()
112 tonight = datetime.datetime.combine(now, datetime.time(event_time))
113 # tonight is now set to today at event_time:00:00
114 if tonight >= now:
115 deadline = tonight
116 else:
117 deadline = tonight + datetime.timedelta(days=1)
Chris Masone93f51d42012-04-18 08:46:52 -0700118 super(Nightly, self).__init__(self.KEYWORD, manifest_versions,
119 always_handle, deadline)
Chris Masone2d61ca22012-04-02 16:52:46 -0700120
121
Chris Masone075aafa2012-05-09 12:08:59 -0700122 def Merge(self, to_merge):
123 """Merge this event with to_merge, changing some mutable properties.
124
125 keyword remains unchanged; the following take on values from to_merge:
126 _deadline iff the time of day in to_merge._deadline is different.
127
128 @param to_merge: A TimedEvent instance to merge into this isntance.
129 """
130 super(TimedEvent, self).Merge(to_merge)
131 if self._deadline.time() != to_merge._deadline.time():
132 self._deadline = to_merge._deadline
133
134
Chris Masoned17d1852012-04-20 11:52:49 -0700135 def GetBranchBuildsForBoard(self, board):
136 return self._LatestPerBranchBuildsSince(board, 1)
Chris Masone2d61ca22012-04-02 16:52:46 -0700137
138
Chris Masonee8bebaf2012-04-24 12:02:59 -0700139 def UpdateCriteria(self):
140 self._deadline = self._deadline + datetime.timedelta(days=1)
141
142
Chris Masone5bde7dc2012-04-09 17:08:19 -0700143class Weekly(TimedEvent):
144 """A TimedEvent that happens every week.
145
146 @var KEYWORD: the keyword to use in a run_on option to associate a task
147 with the Weekly event.
148 @var _DEFAULT_DAY: can be overridden in the "weekly_params" config section.
149 @var _DEFAULT_HOUR: can be overridden in the "weekly_params" config section.
150 """
151
Chris Masone2d61ca22012-04-02 16:52:46 -0700152 KEYWORD = 'weekly'
153 _DEFAULT_DAY = 5 # Saturday
154 _DEFAULT_HOUR = 23
155
156
157 @classmethod
158 def _ParseConfig(cls, config):
Chris Masone83af70c2012-04-18 14:33:05 -0700159 """Create args to pass to __init__ by parsing |config|.
160
Chris Masone93f51d42012-04-18 08:46:52 -0700161 Calls super class' _ParseConfig() method, then parses these additonal
162 options:
163 hour: Integer hour, on a 24 hour clock.
164 day: Integer day, in a 0-indexed 7 day week, e.g. 5 == Saturday.
Chris Masone83af70c2012-04-18 14:33:05 -0700165 """
Chris Masone93f51d42012-04-18 08:46:52 -0700166 from_base = super(Weekly, cls)._ParseConfig(config)
167
168 section = base_event.SectionName(cls.KEYWORD)
Chris Masone2d61ca22012-04-02 16:52:46 -0700169 event_time = config.getint(section, 'hour') or cls._DEFAULT_HOUR
170 event_day = config.getint(section, 'day') or cls._DEFAULT_DAY
Chris Masone93f51d42012-04-18 08:46:52 -0700171
172 from_base.update({'event_time': event_time, 'event_day': event_day})
173 return from_base
Chris Masone2d61ca22012-04-02 16:52:46 -0700174
175
Chris Masone93f51d42012-04-18 08:46:52 -0700176 def __init__(self, manifest_versions, always_handle, event_day, event_time):
177 """Constructor.
178
179 @param manifest_versions: ManifestVersions instance to use for querying.
180 @param always_handle: If True, make ShouldHandle() always return True.
181 @param event_day: The day of the week to set |self._deadline| at.
182 @param event_time: The hour of the day to set |self._deadline| at.
183 """
Chris Masone2d61ca22012-04-02 16:52:46 -0700184 # determine if we're past this week's event and set the
185 # next deadline for this suite appropriately.
186 now = self._now()
187 # Get a datetime representing this week's event_day
188 # If now() is a Sunday, we 'add' 5 - 6 = -1 days to go back a day.
189 # If now() is a Monday, we add 5 - 0 = 5 days to jump forward.
190 this_week = now + datetime.timedelta(event_day-now.weekday())
191 this_week_deadline = datetime.datetime.combine(
192 this_week, datetime.time(event_time))
193 if this_week_deadline >= now:
194 deadline = this_week_deadline
195 else:
196 deadline = this_week_deadline + datetime.timedelta(days=7)
Chris Masone93f51d42012-04-18 08:46:52 -0700197 super(Weekly, self).__init__(self.KEYWORD, manifest_versions,
198 always_handle, deadline)
Chris Masone5bde7dc2012-04-09 17:08:19 -0700199
200
Chris Masone075aafa2012-05-09 12:08:59 -0700201 def Merge(self, to_merge):
202 """Merge this event with to_merge, changing some mutable properties.
203
204 keyword remains unchanged; the following take on values from to_merge:
205 _deadline iff the time of day in to_merge._deadline is different.
206
207 @param to_merge: A TimedEvent instance to merge into this isntance.
208 """
209 super(TimedEvent, self).Merge(to_merge)
210 if (self._deadline.time() != to_merge._deadline.time() or
211 self._deadline.weekday() != to_merge._deadline.weekday()):
212 self._deadline = to_merge._deadline
213
214
Chris Masoned17d1852012-04-20 11:52:49 -0700215 def GetBranchBuildsForBoard(self, board):
216 return self._LatestPerBranchBuildsSince(board, 7)
Chris Masonee8bebaf2012-04-24 12:02:59 -0700217
218
219 def UpdateCriteria(self):
220 self._deadline = self._deadline + datetime.timedelta(days=7)