| 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 |