| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: buildbot.test.test_util -*- | |
| 2 | |
| 3 from twisted.internet.defer import Deferred | |
| 4 from twisted.spread import pb | |
| 5 import time, re, string | |
| 6 | |
| 7 def naturalSort(l): | |
| 8 """Returns a sorted copy of l, so that numbers in strings are sorted in the | |
| 9 proper order. | |
| 10 | |
| 11 e.g. ['foo10', 'foo1', 'foo2'] will be sorted as ['foo1', 'foo2', 'foo10'] | |
| 12 instead of the default ['foo1', 'foo10', 'foo2']""" | |
| 13 l = l[:] | |
| 14 def try_int(s): | |
| 15 try: | |
| 16 return int(s) | |
| 17 except: | |
| 18 return s | |
| 19 def key_func(item): | |
| 20 return [try_int(s) for s in re.split('(\d+)', item)] | |
| 21 # prepend integer keys to each element, sort them, then strip the keys | |
| 22 keyed_l = [ (key_func(i), i) for i in l ] | |
| 23 keyed_l.sort() | |
| 24 l = [ i[1] for i in keyed_l ] | |
| 25 return l | |
| 26 | |
| 27 def now(): | |
| 28 #return int(time.time()) | |
| 29 return time.time() | |
| 30 | |
| 31 def earlier(old, new): | |
| 32 # minimum of two things, but "None" counts as +infinity | |
| 33 if old: | |
| 34 if new < old: | |
| 35 return new | |
| 36 return old | |
| 37 return new | |
| 38 | |
| 39 def later(old, new): | |
| 40 # maximum of two things, but "None" counts as -infinity | |
| 41 if old: | |
| 42 if new > old: | |
| 43 return new | |
| 44 return old | |
| 45 return new | |
| 46 | |
| 47 def formatInterval(eta): | |
| 48 eta_parts = [] | |
| 49 if eta > 3600: | |
| 50 eta_parts.append("%d hrs" % (eta / 3600)) | |
| 51 eta %= 3600 | |
| 52 if eta > 60: | |
| 53 eta_parts.append("%d mins" % (eta / 60)) | |
| 54 eta %= 60 | |
| 55 eta_parts.append("%d secs" % eta) | |
| 56 return ", ".join(eta_parts) | |
| 57 | |
| 58 class CancelableDeferred(Deferred): | |
| 59 """I am a version of Deferred that can be canceled by calling my | |
| 60 .cancel() method. After being canceled, no callbacks or errbacks will be | |
| 61 executed. | |
| 62 """ | |
| 63 def __init__(self): | |
| 64 Deferred.__init__(self) | |
| 65 self.canceled = 0 | |
| 66 def cancel(self): | |
| 67 self.canceled = 1 | |
| 68 def _runCallbacks(self): | |
| 69 if self.canceled: | |
| 70 self.callbacks = [] | |
| 71 return | |
| 72 Deferred._runCallbacks(self) | |
| 73 | |
| 74 def ignoreStaleRefs(failure): | |
| 75 """d.addErrback(util.ignoreStaleRefs)""" | |
| 76 r = failure.trap(pb.DeadReferenceError, pb.PBConnectionLost) | |
| 77 return None | |
| 78 | |
| 79 class _None: | |
| 80 pass | |
| 81 | |
| 82 class ComparableMixin: | |
| 83 """Specify a list of attributes that are 'important'. These will be used | |
| 84 for all comparison operations.""" | |
| 85 | |
| 86 compare_attrs = [] | |
| 87 | |
| 88 def __hash__(self): | |
| 89 alist = [self.__class__] + \ | |
| 90 [getattr(self, name, _None) for name in self.compare_attrs] | |
| 91 return hash(tuple(map(str,alist))) | |
| 92 | |
| 93 def __cmp__(self, them): | |
| 94 result = cmp(type(self), type(them)) | |
| 95 if result: | |
| 96 return result | |
| 97 | |
| 98 result = cmp(self.__class__, them.__class__) | |
| 99 if result: | |
| 100 return result | |
| 101 | |
| 102 assert self.compare_attrs == them.compare_attrs | |
| 103 self_list= [getattr(self, name, _None) for name in self.compare_attrs] | |
| 104 them_list= [getattr(them, name, _None) for name in self.compare_attrs] | |
| 105 return cmp(self_list, them_list) | |
| 106 | |
| 107 def to_text(s): | |
| 108 if isinstance(s, (str, unicode)): | |
| 109 return s | |
| 110 else: | |
| 111 return str(s) | |
| 112 | |
| 113 # Remove potentially harmful characters from builder name if it is to be | |
| 114 # used as the build dir. | |
| 115 badchars_map = string.maketrans("\t !#$%&'()*+,./:;<=>?@[\\]^{|}~", | |
| 116 "______________________________") | |
| 117 def safeTranslate(str): | |
| 118 if isinstance(str, unicode): | |
| 119 str = str.encode('utf8') | |
| 120 return str.translate(badchars_map) | |
| 121 | |
| 122 def remove_userpassword(url): | |
| 123 if '@' not in url: | |
| 124 return url | |
| 125 if '://' not in url: | |
| 126 return url | |
| 127 | |
| 128 # urlparse would've been nice, but doesn't support ssh... sigh | |
| 129 protocol_url = url.split('://') | |
| 130 protocol = protocol_url[0] | |
| 131 repo_url = protocol_url[1].split('@')[-1] | |
| 132 | |
| 133 return protocol + '://' + repo_url | |
| OLD | NEW |