Switch to unified view

a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
...
...
20
import sys
20
import sys
21
import os
21
import os
22
import os.path
22
import os.path
23
import difflib
23
import difflib
24
import urllib
24
import urllib
25
import urllib2
25
import re
26
import re
26
import json
27
import json
27
import logging
28
import logging
28
import cPickle as pickle
29
import cPickle as pickle
29
from hashlib import sha1
30
from hashlib import sha1
30
from datetime import datetime, timedelta
31
from datetime import datetime, timedelta
31
from collections import defaultdict
32
from collections import defaultdict
32
import shlex
33
import shlex
34
import socket
33
35
34
import tg
36
import tg
35
import genshi.template
37
import genshi.template
36
import chardet
38
import chardet
37
import pkg_resources
39
import pkg_resources
...
...
51
53
52
from webhelpers import date, feedgenerator, html, number, misc, text
54
from webhelpers import date, feedgenerator, html, number, misc, text
53
55
54
from allura.lib import exceptions as exc
56
from allura.lib import exceptions as exc
55
# Reimport to make available to templates
57
# Reimport to make available to templates
56
from allura.lib.decorators import exceptionless
57
from allura.lib import AsciiDammit
58
from allura.lib import AsciiDammit
58
from .security import has_access
59
from .security import has_access
59
60
61
log = logging.getLogger(__name__)
60
62
61
# validates project, subproject, and user names
63
# validates project, subproject, and user names
62
re_project_name = re.compile(r'^[a-z][-a-z0-9]{2,14}$')
64
re_project_name = re.compile(r'^[a-z][-a-z0-9]{2,14}$')
63
65
64
# validates tool mount point names
66
# validates tool mount point names
...
...
855
        # which would break html when rendered inside tag's value attr.
857
        # which would break html when rendered inside tag's value attr.
856
        # Escaping doesn't help here, 'cause it breaks EasyWidgets' validation,
858
        # Escaping doesn't help here, 'cause it breaks EasyWidgets' validation,
857
        # so we're getting rid of those.
859
        # so we're getting rid of those.
858
        field_options = [o.replace('"', '') for o in field_options]
860
        field_options = [o.replace('"', '') for o in field_options]
859
    return field_options
861
    return field_options
862
863
864
@contextmanager
865
def notifications_disabled(project):
866
    """Temporarily disable email notifications on a project.
867
868
    """
869
    orig = project.notifications_disabled
870
    try:
871
        project.notifications_disabled = True
872
        yield
873
    finally:
874
        project.notifications_disabled = orig
875
876
877
@contextmanager
878
def null_contextmanager(*args, **kw):
879
    """A no-op contextmanager.
880
881
    """
882
    yield
883
884
885
class exceptionless(object):
886
    '''Decorator making the decorated function return 'error_result' on any
887
    exceptions rather than propagating exceptions up the stack
888
    '''
889
890
    def __init__(self, error_result, log=None):
891
        self.error_result = error_result
892
        self.log = log
893
894
    def __call__(self, fun):
895
        fname = 'exceptionless(%s)' % fun.__name__
896
        def inner(*args, **kwargs):
897
            try:
898
                return fun(*args, **kwargs)
899
            except Exception as e:
900
                if self.log:
901
                    self.log.exception('Error calling %s(args=%s, kwargs=%s): %s',
902
                            fname, args, kwargs, str(e))
903
                return self.error_result
904
        inner.__name__ = fname
905
        return inner
906
907
908
def urlopen(url, retries=3, codes=(408,)):
909
    """Open url, optionally retrying if an error is encountered.
910
911
    Socket timeouts will always be retried if retries > 0.
912
    HTTP errors are retried if the error code is passed in ``codes``.
913
914
    :param retries: Number of time to retry.
915
    :param codes: HTTP error codes that should be retried.
916
917
    """
918
    while True:
919
        try:
920
            return urllib2.urlopen(url)
921
        except (urllib2.HTTPError, socket.timeout) as e:
922
            if retries and (isinstance(e, socket.timeout) or
923
                    e.code in codes):
924
                retries -= 1
925
                continue
926
            else:
927
                log.exception('Failed after %s retries: %s', retries, e)
928
                raise