~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/util.py

  • Committer: Ian Clatworthy
  • Date: 2010-04-13 08:46:44 UTC
  • mto: This revision was merged to the branch mainline in revision 405.
  • Revision ID: ian.clatworthy@canonical.com-20100413084644-2xagalmce6bb8w3m
Simplified README and added a NEWS item

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
#
21
21
 
22
22
import base64
 
23
import cgi
23
24
import datetime
24
25
import logging
25
26
import re
35
36
except ImportError:
36
37
    from elementtree import ElementTree as ET
37
38
 
38
 
from bzrlib import urlutils
39
 
 
40
39
from simpletal.simpleTALUtils import HTMLStructureCleaner
41
40
 
42
41
log = logging.getLogger("loggerhead.controllers")
67
66
 
68
67
def date_time(value):
69
68
    if value is not None:
70
 
        return value.strftime('%Y-%m-%d %H:%M:%S')
 
69
        return value.strftime('%Y-%m-%d %T')
71
70
    else:
72
71
        return 'N/A'
73
72
 
136
135
    """
137
136
 
138
137
    def __init__(self, _dict=None, **kw):
139
 
        self._properties = {}
140
138
        if _dict is not None:
141
139
            for key, value in _dict.iteritems():
142
140
                setattr(self, key, value)
153
151
        out += '}'
154
152
        return out
155
153
 
156
 
    def __getattr__(self, attr):
157
 
        """Used for handling things that aren't already available."""
158
 
        if attr.startswith('_') or attr not in self._properties:
159
 
            raise AttributeError('No attribute: %s' % (attr,))
160
 
        val = self._properties[attr](self, attr)
161
 
        setattr(self, attr, val)
162
 
        return val
163
 
 
164
 
    def _set_property(self, attr, prop_func):
165
 
        """Set a function that will be called when an attribute is desired.
166
 
 
167
 
        We will cache the return value, so the function call should be
168
 
        idempotent. We will pass 'self' and the 'attr' name when triggered.
169
 
        """
170
 
        if attr.startswith('_'):
171
 
            raise ValueError("Cannot create properties that start with _")
172
 
        self._properties[attr] = prop_func
173
 
 
174
154
 
175
155
def trunc(text, limit=10):
176
156
    if len(text) <= limit:
213
193
# only do this if unicode turns out to be a problem
214
194
#_BADCHARS_RE = re.compile(ur'[\u007f-\uffff]')
215
195
 
216
 
# Can't be a dict; &amp; needs to be done first.
217
 
html_entity_subs = [
218
 
    ("&", "&amp;"),
219
 
    ('"', "&quot;"),
220
 
    ("'", "&#39;"), # &apos; is defined in XML, but not HTML.
221
 
    (">", "&gt;"),
222
 
    ("<", "&lt;"),
223
 
    ]
224
 
 
225
 
 
226
 
def html_escape(s):
227
 
    """Transform dangerous (X)HTML characters into entities.
228
 
 
229
 
    Like cgi.escape, except also escaping " and '. This makes it safe to use
230
 
    in both attribute and element content.
231
 
 
232
 
    If you want to safely fill a format string with escaped values, use
233
 
    html_format instead
234
 
    """
235
 
    for char, repl in html_entity_subs:
236
 
        s = s.replace(char, repl)
237
 
    return s
238
 
 
239
 
 
240
 
def html_format(template, *args):
241
 
    """Safely format an HTML template string, escaping the arguments.
242
 
 
243
 
    The template string must not be user-controlled; it will not be escaped.
244
 
    """
245
 
    return template % tuple(html_escape(arg) for arg in args)
246
 
 
247
 
 
248
196
# FIXME: get rid of this method; use fixed_width() and avoid XML().
249
197
 
 
198
 
250
199
def html_clean(s):
251
200
    """
252
201
    clean up a string for html display.  expand any tabs, encode any html
253
202
    entities, and replace spaces with '&nbsp;'.  this is primarily for use
254
203
    in displaying monospace text.
255
204
    """
256
 
    s = html_escape(s.expandtabs())
 
205
    s = cgi.escape(s.expandtabs())
257
206
    s = s.replace(' ', '&nbsp;')
258
207
    return s
259
208
 
299
248
        except UnicodeDecodeError:
300
249
            s = s.decode('iso-8859-15')
301
250
 
302
 
    s = html_escape(s).expandtabs().replace(' ', NONBREAKING_SPACE)
 
251
    s = cgi.escape(s).expandtabs().replace(' ', NONBREAKING_SPACE)
303
252
 
304
253
    return HSC.clean(s).replace('\n', '<br/>')
305
254
 
375
324
    return out
376
325
 
377
326
 
378
 
def local_path_from_url(url):
379
 
    """Convert Bazaar URL to local path, ignoring readonly+ prefix"""
380
 
    readonly_prefix = 'readonly+'
381
 
    if url.startswith(readonly_prefix):
382
 
        url = url[len(readonly_prefix):]
383
 
    return urlutils.local_path_from_url(url)
384
 
 
385
 
 
386
327
def fill_in_navigation(navigation):
387
328
    """
388
329
    given a navigation block (used by the template for the page header), fill