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 |