Merge branch 'master' of git://github.com/bbangert/buildbot
[buildbot.git] / buildbot / util.py
blob33329276a56ee3d01a06edde373c72f6f5f0af80
1 # -*- test-case-name: buildbot.test.test_util -*-
3 from twisted.internet.defer import Deferred
4 from twisted.spread import pb
5 import time, re
7 def naturalSort(l):
8 """Returns a sorted copy of l, so that numbers in strings are sorted in the
9 proper order.
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 l.sort(key=key_func)
22 return l
24 def now():
25 #return int(time.time())
26 return time.time()
28 def earlier(old, new):
29 # minimum of two things, but "None" counts as +infinity
30 if old:
31 if new < old:
32 return new
33 return old
34 return new
36 def later(old, new):
37 # maximum of two things, but "None" counts as -infinity
38 if old:
39 if new > old:
40 return new
41 return old
42 return new
44 def formatInterval(eta):
45 eta_parts = []
46 if eta > 3600:
47 eta_parts.append("%d hrs" % (eta / 3600))
48 eta %= 3600
49 if eta > 60:
50 eta_parts.append("%d mins" % (eta / 60))
51 eta %= 60
52 eta_parts.append("%d secs" % eta)
53 return ", ".join(eta_parts)
55 class CancelableDeferred(Deferred):
56 """I am a version of Deferred that can be canceled by calling my
57 .cancel() method. After being canceled, no callbacks or errbacks will be
58 executed.
59 """
60 def __init__(self):
61 Deferred.__init__(self)
62 self.canceled = 0
63 def cancel(self):
64 self.canceled = 1
65 def _runCallbacks(self):
66 if self.canceled:
67 self.callbacks = []
68 return
69 Deferred._runCallbacks(self)
71 def ignoreStaleRefs(failure):
72 """d.addErrback(util.ignoreStaleRefs)"""
73 r = failure.trap(pb.DeadReferenceError, pb.PBConnectionLost)
74 return None
76 class _None:
77 pass
79 class ComparableMixin:
80 """Specify a list of attributes that are 'important'. These will be used
81 for all comparison operations."""
83 compare_attrs = []
85 def __hash__(self):
86 alist = [self.__class__] + \
87 [getattr(self, name, _None) for name in self.compare_attrs]
88 return hash(tuple(alist))
90 def __cmp__(self, them):
91 result = cmp(type(self), type(them))
92 if result:
93 return result
95 result = cmp(self.__class__, them.__class__)
96 if result:
97 return result
99 assert self.compare_attrs == them.compare_attrs
100 self_list= [getattr(self, name, _None) for name in self.compare_attrs]
101 them_list= [getattr(them, name, _None) for name in self.compare_attrs]
102 return cmp(self_list, them_list)
104 def to_text(s):
105 if isinstance(s, (str, unicode)):
106 return s
107 else:
108 return str(s)