~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/util.py

  • Committer: Robey Pointer
  • Date: 2006-12-19 02:19:42 UTC
  • Revision ID: robey@lag.net-20061219021942-vvymd4ep9yac58mg
tone down the logging a bit

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
#
19
19
 
20
 
import base64
21
20
import cgi
22
21
import datetime
23
22
import logging
24
23
import re
25
24
import sha
26
 
import struct
27
 
import sys
28
25
import threading
29
 
import time
30
 
import traceback
31
26
 
32
27
import turbogears
33
28
 
68
63
def ago(timestamp):
69
64
    now = datetime.datetime.now()
70
65
    return timespan(now - timestamp) + ' ago'
71
 
 
72
 
 
73
 
def fix_year(year):
74
 
    if year < 70:
75
 
        year += 2000
76
 
    if year < 100:
77
 
        year += 1900
78
 
    return year
79
 
 
 
66
    
80
67
 
81
68
class Container (object):
82
69
    """
115
102
    return text[:limit] + '...'
116
103
 
117
104
 
118
 
def to_utf8(s):
119
 
    if isinstance(s, unicode):
120
 
        return s.encode('utf-8')
121
 
    return s
122
 
 
123
 
 
124
105
STANDARD_PATTERN = re.compile(r'^(.*?)\s*<(.*?)>\s*$')
125
106
EMAIL_PATTERN = re.compile(r'[-\w\d\+_!%\.]+@[-\w\d\+_!%\.]+')
126
107
 
211
192
    return format % value
212
193
 
213
194
 
214
 
def b64(s):
215
 
    s = base64.encodestring(s).replace('\n', '')
216
 
    while (len(s) > 0) and (s[-1] == '='):
217
 
        s = s[:-1]
218
 
    return s
219
 
 
220
 
 
221
 
def uniq(uniqs, s):
222
 
    """
223
 
    turn a potentially long string into a unique smaller string.
224
 
    """
225
 
    if s in uniqs:
226
 
        return uniqs[s]
227
 
    uniqs[type(None)] = next = uniqs.get(type(None), 0) + 1
228
 
    x = struct.pack('>I', next)
229
 
    while (len(x) > 1) and (x[0] == '\x00'):
230
 
        x = x[1:]
231
 
    uniqs[s] = b64(x)
232
 
    return uniqs[s]
233
 
 
234
 
 
235
195
KILO = 1024
236
196
MEG = 1024 * KILO
237
197
GIG = 1024 * MEG
277
237
    given a navigation block (used by the template for the page header), fill
278
238
    in useful calculated values.
279
239
    """
280
 
    navigation.position = history.get_revid_sequence(navigation.revid_list, navigation.revid)
281
 
    if navigation.position is None:
282
 
        navigation.position = 0
283
 
    navigation.count = len(navigation.revid_list)
 
240
    navigation.position = history.get_revid_sequence(navigation.revlist, navigation.revid)
 
241
    navigation.count = len(navigation.revlist)
284
242
    navigation.page_position = navigation.position // navigation.pagesize + 1
285
 
    navigation.page_count = (len(navigation.revid_list) + (navigation.pagesize - 1)) // navigation.pagesize
 
243
    navigation.page_count = (len(navigation.revlist) + (navigation.pagesize - 1)) // navigation.pagesize
286
244
    
287
245
    def get_offset(offset):
288
246
        if (navigation.position + offset < 0) or (navigation.position + offset > navigation.count - 1):
289
247
            return None
290
 
        return navigation.revid_list[navigation.position + offset]
 
248
        return navigation.revlist[navigation.position + offset]
291
249
    
292
250
    navigation.prev_page_revid = get_offset(-1 * navigation.pagesize)
293
251
    navigation.next_page_revid = get_offset(1 * navigation.pagesize)
294
 
    
295
 
    params = { 'file_id': navigation.file_id }
296
 
    if getattr(navigation, 'query', None) is not None:
297
 
        params['q'] = navigation.query
298
 
    else:
299
 
        params['start_revid'] = navigation.start_revid
300
 
        
301
252
    if navigation.prev_page_revid:
302
 
        navigation.prev_page_url = navigation.branch.url([ navigation.scan_url, navigation.prev_page_revid ], **get_context(**params))
 
253
        navigation.prev_page_url = turbogears.url([ navigation.scan_url, navigation.prev_page_revid ], file_id=navigation.file_id, start_revid=navigation.start_revid)
303
254
    if navigation.next_page_revid:
304
 
        navigation.next_page_url = navigation.branch.url([ navigation.scan_url, navigation.next_page_revid ], **get_context(**params))
305
 
 
306
 
 
307
 
def log_exception(log):
308
 
    for line in ''.join(traceback.format_exception(*sys.exc_info())).split('\n'):
309
 
        log.debug(line)
310
 
 
311
 
 
312
 
def decorator(unbound):
313
 
    def new_decorator(f):
314
 
        g = unbound(f)
315
 
        g.__name__ = f.__name__
316
 
        g.__doc__ = f.__doc__
317
 
        g.__dict__.update(f.__dict__)
318
 
        return g
319
 
    new_decorator.__name__ = unbound.__name__
320
 
    new_decorator.__doc__ = unbound.__doc__
321
 
    new_decorator.__dict__.update(unbound.__dict__)
322
 
    return new_decorator
323
 
 
324
 
 
325
 
# common threading-lock decorator
326
 
def with_lock(lockname, debug_name=None):
327
 
    if debug_name is None:
328
 
        debug_name = lockname
329
 
    @decorator
330
 
    def _decorator(unbound):
331
 
        def locked(self, *args, **kw):
332
 
            getattr(self, lockname).acquire()
333
 
            try:
334
 
                return unbound(self, *args, **kw)
335
 
            finally:
336
 
                getattr(self, lockname).release()
337
 
        return locked
338
 
    return _decorator
339
 
 
340
 
 
341
 
@decorator
342
 
def strip_whitespace(f):
343
 
    def _f(*a, **kw):
344
 
        out = f(*a, **kw)
345
 
        orig_len = len(out)
346
 
        out = re.sub(r'\n\s+', '\n', out)
347
 
        out = re.sub(r'[ \t]+', ' ', out)
348
 
        out = re.sub(r'\s+\n', '\n', out)
349
 
        new_len = len(out)
350
 
        log.debug('Saved %sB (%d%%) by stripping whitespace.',
351
 
                  human_size(orig_len - new_len),
352
 
                  round(100.0 - float(new_len) * 100.0 / float(orig_len)))
353
 
        return out
354
 
    return _f
355
 
 
356
 
 
357
 
@decorator
358
 
def lsprof(f):
359
 
    def _f(*a, **kw):
360
 
        from loggerhead.lsprof import profile
361
 
        import cPickle
362
 
        z = time.time()
363
 
        ret, stats = profile(f, *a, **kw)
364
 
        log.debug('Finished profiled %s in %d msec.' % (f.__name__, int((time.time() - z) * 1000)))
365
 
        stats.sort()
366
 
        stats.freeze()
367
 
        now = time.time()
368
 
        msec = int(now * 1000) % 1000
369
 
        timestr = time.strftime('%Y%m%d%H%M%S', time.localtime(now)) + ('%03d' % msec)
370
 
        filename = f.__name__ + '-' + timestr + '.lsprof'
371
 
        cPickle.dump(stats, open(filename, 'w'), 2)
372
 
        return ret
373
 
    return _f
374
 
 
375
 
 
376
 
# just thinking out loud here...
377
 
#
378
 
# so, when browsing around, there are 5 pieces of context, most optional:
379
 
#     - current revid
380
 
#         current location along the navigation path (while browsing)
381
 
#     - starting revid (start_revid)
382
 
#         the current beginning of navigation (navigation continues back to
383
 
#         the original revision) -- this may not be along the primary revision
384
 
#         path since the user may have navigated into a branch
385
 
#     - file_id
386
 
#         if navigating the revisions that touched a file
387
 
#     - q (query)
388
 
#         if navigating the revisions that matched a search query
389
 
#     - remember
390
 
#         a previous revision to remember for future comparisons
391
 
#
392
 
# current revid is given on the url path.  the rest are optional components
393
 
# in the url params.
394
 
#
395
 
# other transient things can be set:
396
 
#     - compare_revid
397
 
#         to compare one revision to another, on /revision only
398
 
#     - sort
399
 
#         for re-ordering an existing page by different sort
400
 
 
401
 
t_context = threading.local()
402
 
_valid = ('start_revid', 'file_id', 'q', 'remember', 'compare_revid', 'sort')
403
 
 
404
 
 
405
 
def set_context(map):
406
 
    t_context.map = dict((k, v) for (k, v) in map.iteritems() if k in _valid)
407
 
 
408
 
 
409
 
def get_context(**overrides):
410
 
    """
411
 
    return a context map that may be overriden by specific values passed in,
412
 
    but only contains keys from the list of valid context keys.
413
 
    
414
 
    if 'clear' is set, only the 'remember' context value will be added, and
415
 
    all other context will be omitted.
416
 
    """
417
 
    map = dict()
418
 
    if overrides.get('clear', False):
419
 
        map['remember'] = t_context.map.get('remember', None)
420
 
    else:
421
 
        map.update(t_context.map)
422
 
    overrides = dict((k, v) for (k, v) in overrides.iteritems() if k in _valid)
423
 
    map.update(overrides)
424
 
    return map
 
255
        navigation.next_page_url = turbogears.url([ navigation.scan_url, navigation.next_page_revid ], file_id=navigation.file_id, start_revid=navigation.start_revid)
 
256
 
 
257
 
 
258
# global branch history & cache
 
259
 
 
260
_history = None
 
261
_history_lock = threading.Lock()
 
262
 
 
263
def get_history():
 
264
    global _history
 
265
    from loggerhead.history import History
 
266
    
 
267
    config = get_config()
 
268
    
 
269
    _history_lock.acquire()
 
270
    try:
 
271
        if (_history is None) or _history.out_of_date():
 
272
            log.debug('Reload branch history...')
 
273
            if _history is not None:
 
274
                _history.dont_use_cache()
 
275
            _history = History.from_folder(config.get('folder'))
 
276
            _history.use_cache(config.get('cachepath'))
 
277
        return _history
 
278
    finally:
 
279
        _history_lock.release()
 
280
 
 
281
 
 
282
_config = None
 
283
 
 
284
def set_config(config):
 
285
    global _config
 
286
    _config = config
 
287
 
 
288
def get_config():
 
289
    return _config
 
290