~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/util.py

  • Committer: Robey Pointer
  • Date: 2006-12-11 06:44:19 UTC
  • Revision ID: robey@lag.net-20061211064419-8ssa7mlsiflpmy0c
initial checkin

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#
2
2
# Copyright (C) 2006  Robey Pointer <robey@lag.net>
3
 
# Copyright (C) 2006  Goffredo Baroncelli <kreijack@inwind.it>
4
3
#
5
4
# This program is free software; you can redistribute it and/or modify
6
5
# it under the terms of the GNU General Public License as published by
17
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
17
#
19
18
 
20
 
import cgi
21
 
import datetime
22
 
import logging
23
19
import re
24
20
import sha
25
 
import sys
26
 
import threading
27
 
import traceback
28
 
 
29
 
import turbogears
30
 
 
31
 
 
32
 
log = logging.getLogger("loggerhead.controllers")
33
21
 
34
22
 
35
23
def timespan(delta):
36
 
    if delta.days > 730:
37
 
        # good grief!
38
 
        return '%d years' % (int(delta.days // 365.25),)
39
24
    if delta.days >= 3:
40
25
        return '%d days' % delta.days
41
26
    seg = []
62
47
    return ', '.join(seg)
63
48
 
64
49
 
65
 
def ago(timestamp):
66
 
    now = datetime.datetime.now()
67
 
    return timespan(now - timestamp) + ' ago'
68
 
 
69
 
 
70
 
def fix_year(year):
71
 
    if year < 70:
72
 
        year += 2000
73
 
    if year < 100:
74
 
        year += 1900
75
 
    return year
76
 
 
77
 
 
78
50
class Container (object):
79
51
    """
80
52
    Convert a dict into an object with attributes.
85
57
                setattr(self, key, value)
86
58
        for key, value in kw.iteritems():
87
59
            setattr(self, key, value)
88
 
    
89
 
    def __repr__(self):
90
 
        out = '{ '
91
 
        for key, value in self.__dict__.iteritems():
92
 
            if key.startswith('_') or (getattr(self.__dict__[key], '__call__', None) is not None):
93
 
                continue
94
 
            out += '%r => %r, ' % (key, value)
95
 
        out += '}'
96
 
        return out
97
60
 
98
61
 
99
62
def clean_revid(revid):
106
69
    return ''.join([ '&#%d;' % ord(c) for c in text ])
107
70
 
108
71
 
109
 
def trunc(text, limit=10):
110
 
    if len(text) <= limit:
111
 
        return text
112
 
    return text[:limit] + '...'
113
 
 
114
 
 
115
 
def to_utf8(s):
116
 
    if isinstance(s, unicode):
117
 
        return s.encode('utf-8')
118
 
    return s
119
 
 
120
 
 
121
72
STANDARD_PATTERN = re.compile(r'^(.*?)\s*<(.*?)>\s*$')
122
73
EMAIL_PATTERN = re.compile(r'[-\w\d\+_!%\.]+@[-\w\d\+_!%\.]+')
123
74
 
141
92
    return '%s at %s' % (username, domains[0])
142
93
 
143
94
    
144
 
def triple_factors(min_value=1):
 
95
def triple_factors():
145
96
    factors = (1, 3)
146
97
    index = 0
147
98
    n = 1
148
99
    while True:
149
 
        if n >= min_value:
150
 
            yield n * factors[index]
 
100
        yield n * factors[index]
151
101
        index += 1
152
102
        if index >= len(factors):
153
103
            index = 0
154
104
            n *= 10
155
105
 
156
106
 
157
 
def scan_range(pos, max, pagesize=1):
 
107
def scan_range(pos, max):
158
108
    """
159
109
    given a position in a maximum range, return a list of negative and positive
160
110
    jump factors for an hgweb-style triple-factor geometric scan.
166
116
    invent it. :)
167
117
    """
168
118
    out = []
169
 
    for n in triple_factors(pagesize + 1):
 
119
    for n in triple_factors():
170
120
        if n > max:
171
121
            return out
172
122
        if pos + n < max:
174
124
        if pos - n >= 0:
175
125
            out.insert(0, -n)
176
126
 
177
 
 
178
 
# only do this if unicode turns out to be a problem
179
 
#_BADCHARS_RE = re.compile(ur'[\u007f-\uffff]')
180
 
 
181
 
def html_clean(s):
182
 
    """
183
 
    clean up a string for html display.  expand any tabs, encode any html
184
 
    entities, and replace spaces with '&nbsp;'.  this is primarily for use
185
 
    in displaying monospace text.
186
 
    """
187
 
    s = cgi.escape(s.expandtabs())
188
 
#    s = _BADCHARS_RE.sub(lambda x: '&#%d;' % (ord(x.group(0)),), s)
189
 
    s = s.replace(' ', '&nbsp;')
190
 
    return s
191
 
 
192
 
 
193
 
def fake_permissions(kind, executable):
194
 
    # fake up unix-style permissions given only a "kind" and executable bit
195
 
    if kind == 'directory':
196
 
        return 'drwxr-xr-x'
197
 
    if executable:
198
 
        return '-rwxr-xr-x'
199
 
    return '-rw-r--r--'
200
 
 
201
 
 
202
 
def if_present(format, value):
203
 
    """
204
 
    format a value using a format string, if the value exists and is not None.
205
 
    """
206
 
    if value is None:
207
 
        return ''
208
 
    return format % value
209
 
 
210
 
 
211
 
KILO = 1024
212
 
MEG = 1024 * KILO
213
 
GIG = 1024 * MEG
214
 
P95_MEG = int(0.9 * MEG)
215
 
P95_GIG = int(0.9 * GIG)
216
 
 
217
 
def human_size(size, min_divisor=0):
218
 
    size = int(size)
219
 
    if (size == 0) and (min_divisor == 0):
220
 
        return '0'
221
 
    if (size < 512) and (min_divisor == 0):
222
 
        return str(size)
223
 
 
224
 
    if (size >= P95_GIG) or (min_divisor >= GIG):
225
 
        divisor = GIG
226
 
    elif (size >= P95_MEG) or (min_divisor >= MEG):
227
 
        divisor = MEG
228
 
    else:
229
 
        divisor = KILO
230
 
    
231
 
    dot = size % divisor
232
 
    base = size - dot
233
 
    dot = dot * 10 // divisor
234
 
    base //= divisor
235
 
    if dot >= 10:
236
 
        base += 1
237
 
        dot -= 10
238
 
    
239
 
    out = str(base)
240
 
    if (base < 100) and (dot != 0):
241
 
        out += '.%d' % (dot,)
242
 
    if divisor == KILO:
243
 
        out += 'K'
244
 
    elif divisor == MEG:
245
 
        out += 'M'
246
 
    elif divisor == GIG:
247
 
        out += 'G'
248
 
    return out
249
 
    
250
 
 
251
 
def fill_in_navigation(history, navigation):
252
 
    """
253
 
    given a navigation block (used by the template for the page header), fill
254
 
    in useful calculated values.
255
 
    """
256
 
    navigation.position = history.get_revid_sequence(navigation.revid_list, navigation.revid)
257
 
    if navigation.position is None:
258
 
        navigation.position = 0
259
 
    navigation.count = len(navigation.revid_list)
260
 
    navigation.page_position = navigation.position // navigation.pagesize + 1
261
 
    navigation.page_count = (len(navigation.revid_list) + (navigation.pagesize - 1)) // navigation.pagesize
262
 
    
263
 
    def get_offset(offset):
264
 
        if (navigation.position + offset < 0) or (navigation.position + offset > navigation.count - 1):
265
 
            return None
266
 
        return navigation.revid_list[navigation.position + offset]
267
 
    
268
 
    navigation.prev_page_revid = get_offset(-1 * navigation.pagesize)
269
 
    navigation.next_page_revid = get_offset(1 * navigation.pagesize)
270
 
    
271
 
    params = { 'file_id': navigation.file_id }
272
 
    if getattr(navigation, 'query', None) is not None:
273
 
        params['q'] = navigation.query
274
 
    else:
275
 
        params['start_revid'] = navigation.start_revid
276
 
        
277
 
    if navigation.prev_page_revid:
278
 
        navigation.prev_page_url = turbogears.url([ navigation.scan_url, navigation.prev_page_revid ], **params)
279
 
    if navigation.next_page_revid:
280
 
        navigation.next_page_url = turbogears.url([ navigation.scan_url, navigation.next_page_revid ], **params)
281
 
 
282
 
 
283
 
def log_exception(log):
284
 
    for line in ''.join(traceback.format_exception(*sys.exc_info())).split('\n'):
285
 
        log.debug(line)
286
 
 
287
 
 
288
 
def decorator(unbound):
289
 
    def new_decorator(f):
290
 
        g = unbound(f)
291
 
        g.__name__ = f.__name__
292
 
        g.__doc__ = f.__doc__
293
 
        g.__dict__.update(f.__dict__)
294
 
        return g
295
 
    new_decorator.__name__ = unbound.__name__
296
 
    new_decorator.__doc__ = unbound.__doc__
297
 
    new_decorator.__dict__.update(unbound.__dict__)
298
 
    return new_decorator
299
 
 
300
 
 
301
 
# common threading-lock decorator
302
 
def with_lock(lockname, debug_name=None):
303
 
    if debug_name is None:
304
 
        debug_name = lockname
305
 
    @decorator
306
 
    def _decorator(unbound):
307
 
        def locked(self, *args, **kw):
308
 
            #self.log.debug('-> %r lock %r', id(threading.currentThread()), debug_name)
309
 
            getattr(self, lockname).acquire()
310
 
            try:
311
 
                return unbound(self, *args, **kw)
312
 
            finally:
313
 
                getattr(self, lockname).release()
314
 
                #self.log.debug('<- %r unlock %r', id(threading.currentThread()), debug_name)
315
 
        return locked
316
 
    return _decorator
317