~jelmer/loggerhead/breezy-compat

« back to all changes in this revision

Viewing changes to loggerhead/util.py

  • Committer: Colin Watson
  • Date: 2019-09-19 08:10:36 UTC
  • mfrom: (491.2.62 breezy)
  • Revision ID: cjwatson@canonical.com-20190919081036-q1symc2h2iedtlh3
[r=cjwatson] Switch loggerhead over to using the Breezy rather than Bazaar APIs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
# Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335  USA
20
20
#
21
21
 
 
22
from __future__ import print_function
 
23
 
22
24
import base64
23
25
import datetime
24
26
import logging
30
32
import os
31
33
import subprocess
32
34
 
 
35
from breezy.sixish import (
 
36
    text_type,
 
37
    viewitems,
 
38
    )
 
39
 
33
40
try:
34
41
    from xml.etree import ElementTree as ET
35
42
except ImportError:
36
43
    from elementtree import ElementTree as ET
37
44
 
38
 
from bzrlib import urlutils
 
45
from breezy import urlutils
39
46
 
40
 
from simpletal.simpleTALUtils import HTMLStructureCleaner
 
47
import bleach
41
48
 
42
49
log = logging.getLogger("loggerhead.controllers")
43
50
 
73
80
 
74
81
 
75
82
def _approximatedate(date):
76
 
    delta = datetime.datetime.now() - date
77
 
    if abs(delta) > datetime.timedelta(1, 0, 0):
78
 
        # far in the past or future, display the date
79
 
        return date_day(date)
 
83
    if date is None:
 
84
        return 'Never'
 
85
    delta = datetime.datetime.utcnow() - date
80
86
    future = delta < datetime.timedelta(0, 0, 0)
81
87
    delta = abs(delta)
 
88
    years = delta.days // 365
 
89
    months = delta.days // 30 # This is approximate.
82
90
    days = delta.days
83
 
    hours = delta.seconds / 3600
 
91
    hours = delta.seconds // 3600
84
92
    minutes = (delta.seconds - (3600*hours)) / 60
85
93
    seconds = delta.seconds % 60
86
94
    result = ''
87
95
    if future:
88
96
        result += 'in '
89
 
    if days != 0:
 
97
    if years != 0:
 
98
        amount = years
 
99
        unit = 'year'
 
100
    elif months != 0:
 
101
        amount = months
 
102
        unit = 'month'
 
103
    elif days != 0:
90
104
        amount = days
91
105
        unit = 'day'
92
106
    elif hours != 0:
100
114
        unit = 'second'
101
115
    if amount != 1:
102
116
        unit += 's'
103
 
    result += '%s %s' % (amount, unit)
 
117
    result += '%s %s' % (int(amount), unit)
104
118
    if not future:
105
119
        result += ' ago'
106
 
        return result
 
120
    return result
107
121
 
108
122
 
109
123
def _wrap_with_date_time_title(date, formatted_date):
126
140
    def __init__(self, _dict=None, **kw):
127
141
        self._properties = {}
128
142
        if _dict is not None:
129
 
            for key, value in _dict.iteritems():
 
143
            for key, value in viewitems(_dict):
130
144
                setattr(self, key, value)
131
 
        for key, value in kw.iteritems():
 
145
        for key, value in viewitems(kw):
132
146
            setattr(self, key, value)
133
147
 
134
148
    def __repr__(self):
135
149
        out = '{ '
136
 
        for key, value in self.__dict__.iteritems():
 
150
        for key, value in viewitems(self.__dict__):
137
151
            if key.startswith('_') or (getattr(self.__dict__[key],
138
152
                                       '__call__', None) is not None):
139
153
                continue
262
276
        return s
263
277
    elif not s.strip():
264
278
        return '&nbsp;'
265
 
    else:
 
279
    elif isinstance(s, bytes):
266
280
        try:
267
281
            s = s.decode('utf-8')
268
282
        except UnicodeDecodeError:
269
283
            s = s.decode('iso-8859-15')
270
284
        return s
 
285
    elif isinstance(s, text_type):
 
286
        return s
 
287
    else:
 
288
        return repr(s)
271
289
 
272
 
HSC = HTMLStructureCleaner()
273
290
 
274
291
def fixed_width(s):
275
292
    """
276
293
    expand tabs and turn spaces into "non-breaking spaces", so browsers won't
277
294
    chop up the string.
278
295
    """
279
 
    if not isinstance(s, unicode):
 
296
    if not isinstance(s, text_type):
280
297
        # this kinda sucks.  file contents are just binary data, and no
281
298
        # encoding metadata is stored, so we need to guess.  this is probably
282
299
        # okay for most code, but for people using things like KOI-8, this
289
306
 
290
307
    s = html_escape(s).expandtabs().replace(' ', NONBREAKING_SPACE)
291
308
 
292
 
    return HSC.clean(s).replace('\n', '<br/>')
 
309
    return bleach.clean(s).replace('\n', '<br/>')
293
310
 
294
311
 
295
312
def fake_permissions(kind, executable):
456
473
    return breadcrumbs
457
474
 
458
475
 
459
 
def branch_breadcrumbs(path, inv, view):
 
476
def branch_breadcrumbs(path, tree, view):
460
477
    """
461
478
    Generate breadcrumb information from the branch path given
462
479
 
464
481
 
465
482
    Arguments:
466
483
    path -- The path to convert into breadcrumbs
467
 
    inv -- Inventory to get file information from
 
484
    tree -- Tree to get file information from
468
485
    view -- The type of view we are showing (files, changes etc)
469
486
    """
470
487
    dir_parts = path.strip('/').split('/')
497
514
def lsprof(f):
498
515
 
499
516
    def _f(*a, **kw):
500
 
        from loggerhead.lsprof import profile
 
517
        from .loggerhead.lsprof import profile
501
518
        import cPickle
502
519
        z = time.time()
503
520
        ret, stats = profile(f, *a, **kw)
548
565
 
549
566
 
550
567
def set_context(map):
551
 
    t_context.map = dict((k, v) for (k, v) in map.iteritems() if k in _valid)
 
568
    t_context.map = dict((k, v) for (k, v) in viewitems(map) if k in _valid)
552
569
 
553
570
 
554
571
def get_context(**overrides):
567
584
        map['remember'] = t_context.map.get('remember', None)
568
585
    else:
569
586
        map.update(t_context.map)
570
 
    overrides = dict((k, v) for (k, v) in overrides.iteritems() if k in _valid)
 
587
    overrides = dict((k, v) for (k, v) in viewitems(overrides) if k in _valid)
571
588
    map.update(overrides)
572
589
    return map
573
590
 
605
622
    @classmethod
606
623
    def restart_with_reloader(cls):
607
624
        """Based on restart_with_monitor from paste.script.serve."""
608
 
        print 'Starting subprocess with file monitor'
 
625
        print('Starting subprocess with file monitor')
609
626
        while True:
610
627
            args = [sys.executable] + sys.argv
611
628
            new_environ = os.environ.copy()
618
635
                    exit_code = proc.wait()
619
636
                    proc = None
620
637
                except KeyboardInterrupt:
621
 
                    print '^C caught in monitor process'
 
638
                    print('^C caught in monitor process')
622
639
                    return 1
623
640
            finally:
624
641
                if (proc is not None
633
650
            # a monitor, any exit code will restart
634
651
            if exit_code != 3:
635
652
                return exit_code
636
 
            print '-'*20, 'Restarting', '-'*20
 
653
            print('-'*20, 'Restarting', '-'*20)
637
654
 
638
655
 
639
656
def convert_file_errors(application):
641
658
    def new_application(environ, start_response):
642
659
        try:
643
660
            return application(environ, start_response)
644
 
        except (IOError, OSError), e:
 
661
        except (IOError, OSError) as e:
645
662
            import errno
646
663
            from paste import httpexceptions
647
664
            if e.errno == errno.ENOENT: