35
34
log = logging.getLogger("loggerhead.controllers")
39
# date_day -- just the day
40
# date_time -- full date with time
42
# displaydate -- for use in sentences
43
# approximatedate -- for use in tables
45
# displaydate and approximatedate return an elementtree <span> Element
46
# with the full date in a tooltip.
49
return value.strftime('%Y-%m-%d')
53
return value.strftime('%Y-%m-%d %T')
56
def _displaydate(date):
57
delta = abs(datetime.datetime.now() - date)
58
if delta > datetime.timedelta(1, 0, 0):
59
# far in the past or future, display the date
60
return 'on ' + date_day(date)
61
return _approximatedate(date)
64
def _approximatedate(date):
65
delta = datetime.datetime.now() - date
66
if abs(delta) > datetime.timedelta(1, 0, 0):
67
# far in the past or future, display the date
69
future = delta < datetime.timedelta(0, 0, 0)
72
hours = delta.seconds / 3600
73
minutes = (delta.seconds - (3600*hours)) / 60
74
seconds = delta.seconds % 60
92
result += '%s %s' % (amount, unit)
98
def _wrap_with_date_time_title(date, formatted_date):
99
elem = ET.Element("span")
100
elem.text = formatted_date
101
elem.set("title", date_time(date))
105
def approximatedate(date):
106
return _wrap_with_date_time_title(date, _approximatedate(date))
109
def displaydate(date):
110
return _wrap_with_date_time_title(date, _displaydate(date))
40
return '%d years' % (int(delta.days // 365.25),)
42
return '%d days' % delta.days
48
seg.append('%d days' % delta.days)
49
hrs = delta.seconds // 3600
50
mins = (delta.seconds % 3600) // 60
55
seg.append('%d hours' % hrs)
59
seg.append('1 minute')
61
seg.append('%d minutes' % mins)
63
seg.append('less than a minute')
68
now = datetime.datetime.now()
69
return timespan(now - timestamp) + ' ago'
113
80
class Container (object):
120
87
setattr(self, key, value)
121
88
for key, value in kw.iteritems():
122
89
setattr(self, key, value)
124
91
def __repr__(self):
126
93
for key, value in self.__dict__.iteritems():
194
161
given a position in a maximum range, return a list of negative and positive
195
162
jump factors for an hgweb-style triple-factor geometric scan.
197
164
for example, with pos=20 and max=500, the range would be:
198
165
[ -10, -3, -1, 1, 3, 10, 30, 100, 300 ]
200
167
i admit this is a very strange way of jumping through revisions. i didn't
221
187
in displaying monospace text.
223
189
s = cgi.escape(s.expandtabs())
190
# s = _BADCHARS_RE.sub(lambda x: '&#%d;' % (ord(x.group(0)),), s)
224
191
s = s.replace(' ', ' ')
229
NONBREAKING_SPACE = u'\N{NO-BREAK SPACE}'
233
expand tabs and turn spaces into "non-breaking spaces", so browsers won't
236
if not isinstance(s, unicode):
237
# this kinda sucks. file contents are just binary data, and no
238
# encoding metadata is stored, so we need to guess. this is probably
239
# okay for most code, but for people using things like KOI-8, this
240
# will display gibberish. we have no way of detecting the correct
243
s = s.decode('utf-8')
244
except UnicodeDecodeError:
245
s = s.decode('iso-8859-15')
246
return s.expandtabs().replace(' ', NONBREAKING_SPACE)
249
195
def fake_permissions(kind, executable):
250
196
# fake up unix-style permissions given only a "kind" and executable bit
251
197
if kind == 'directory':
323
269
elif divisor == GIG:
328
def fill_in_navigation(navigation):
274
def fill_in_navigation(history, navigation):
330
276
given a navigation block (used by the template for the page header), fill
331
277
in useful calculated values.
333
if navigation.revid in navigation.revid_list: # XXX is this always true?
334
navigation.position = navigation.revid_list.index(navigation.revid)
279
navigation.position = history.get_revid_sequence(navigation.revid_list, navigation.revid)
280
if navigation.position is None:
336
281
navigation.position = 0
337
282
navigation.count = len(navigation.revid_list)
338
283
navigation.page_position = navigation.position // navigation.pagesize + 1
339
284
navigation.page_count = (len(navigation.revid_list) + (navigation.pagesize - 1)) // navigation.pagesize
341
286
def get_offset(offset):
342
287
if (navigation.position + offset < 0) or (navigation.position + offset > navigation.count - 1):
344
289
return navigation.revid_list[navigation.position + offset]
346
291
navigation.prev_page_revid = get_offset(-1 * navigation.pagesize)
347
292
navigation.next_page_revid = get_offset(1 * navigation.pagesize)
349
params = { 'filter_file_id': navigation.filter_file_id }
294
params = { 'file_id': navigation.file_id }
350
295
if getattr(navigation, 'query', None) is not None:
351
296
params['q'] = navigation.query
353
298
params['start_revid'] = navigation.start_revid
355
300
if navigation.prev_page_revid:
356
301
navigation.prev_page_url = navigation.branch.url([ navigation.scan_url, navigation.prev_page_revid ], **get_context(**params))
357
302
if navigation.next_page_revid:
414
from loggerhead.lsprof import profile
417
ret, stats = profile(f, *a, **kw)
418
log.debug('Finished profiled %s in %d msec.' % (f.__name__, int((time.time() - z) * 1000)))
422
msec = int(now * 1000) % 1000
423
timestr = time.strftime('%Y%m%d%H%M%S', time.localtime(now)) + ('%03d' % msec)
424
filename = f.__name__ + '-' + timestr + '.lsprof'
425
cPickle.dump(stats, open(filename, 'w'), 2)
430
356
# just thinking out loud here...
432
358
# so, when browsing around, there are 5 pieces of context, most optional:
434
360
# current location along the navigation path (while browsing)
435
361
# - starting revid (start_revid)
436
362
# the current beginning of navigation (navigation continues back to
437
# the original revision) -- this defines an 'alternate mainline'
438
# when the user navigates into a branch.
363
# the original revision) -- this may not be along the primary revision
364
# path since the user may have navigated into a branch
440
# the file being looked at
442
366
# if navigating the revisions that touched a file
444
368
# if navigating the revisions that matched a search query
455
379
# for re-ordering an existing page by different sort
457
381
t_context = threading.local()
458
_valid = ('start_revid', 'file_id', 'filter_file_id', 'q', 'remember',
459
'compare_revid', 'sort')
382
_valid = ('start_revid', 'file_id', 'q', 'remember', 'compare_revid', 'sort')
462
385
def set_context(map):