OLD | NEW |
| (Empty) |
1 # coding=utf8 | |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 """Postpone commits until the tree is open.""" | |
6 | |
7 import calendar | |
8 import json | |
9 import logging | |
10 import re | |
11 import ssl | |
12 import time | |
13 import urllib2 | |
14 | |
15 from verification import base | |
16 | |
17 | |
18 class TreeStatus(base.IVerifierStatus): | |
19 tree_status_url = unicode | |
20 issue = int | |
21 last_tree_status = unicode | |
22 | |
23 def get_state(self): | |
24 return base.SUCCEEDED | |
25 | |
26 def postpone(self): | |
27 self.last_tree_status = u'' | |
28 try: | |
29 logging.debug('Fetching tree status for %s' % self.tree_status_url) | |
30 now = time.time() | |
31 cutoff = now - 5 * 60 | |
32 url = self.tree_status_url + '/allstatus?format=json&endTime=%d' % cutoff | |
33 data = json.load(urllib2.urlopen(url)) | |
34 | |
35 # Convert datetime string to epoch. | |
36 for item in data: | |
37 # The time is returned in UTC. | |
38 x = time.strptime(item['date'].split('.', 1)[0], '%Y-%m-%d %H:%M:%S') | |
39 item['date'] = calendar.timegm(x) | |
40 | |
41 for item in sorted(data, key=lambda x: x['date'], reverse=True): | |
42 if item['general_state'] != 'open': | |
43 logging.warn( | |
44 'Not committing CL %d because the tree was closed %ds ago', | |
45 self.issue, int(now - item['date'])) | |
46 self.last_tree_status = unicode(item['message']) | |
47 return True | |
48 if item['date'] < cutoff: | |
49 break | |
50 return False | |
51 except (ssl.SSLError, urllib2.URLError, IOError, ValueError): | |
52 logging.error('Failed to request tree status! %s' % url) | |
53 return True | |
54 | |
55 def why_not(self): | |
56 if self.last_tree_status: | |
57 return u'Tree is currently not open: %s' % self.last_tree_status | |
58 | |
59 | |
60 class AlwaysOpenTreeStatus(TreeStatus): | |
61 """Used when tree status does not need to be checked.""" | |
62 def postpone(self): | |
63 return False | |
64 | |
65 | |
66 class TreeStatusVerifier(base.Verifier): | |
67 """Checks the tree status before allowing a commit.""" | |
68 name = 'tree status' | |
69 | |
70 def __init__(self, tree_status_url): | |
71 super(TreeStatusVerifier, self).__init__() | |
72 self.tree_status_url = tree_status_url | |
73 | |
74 def verify(self, pending): | |
75 if re.search(r'(?im)^NOTREECHECKS=TRUE$', pending.description): | |
76 # Use a TreeStatus instance that always returns False for postpone(). | |
77 tree_status = AlwaysOpenTreeStatus() | |
78 else: | |
79 tree_status = TreeStatus( | |
80 tree_status_url=self.tree_status_url, issue=pending.issue) | |
81 | |
82 pending.verifications[self.name] = tree_status | |
83 | |
84 def update_status(self, queue): | |
85 pass | |
86 | |
OLD | NEW |