##// END OF EJS Templates
utils: ported to python3 and new app
super-admin -
r5076:e00a2a48 default
parent child Browse files
Show More
@@ -23,7 +23,6 b' Utilities library for RhodeCode'
23
23
24 import datetime
24 import datetime
25 import decorator
25 import decorator
26 import json
27 import logging
26 import logging
28 import os
27 import os
29 import re
28 import re
@@ -34,20 +33,20 b' import tempfile'
34 import traceback
33 import traceback
35 import tarfile
34 import tarfile
36 import warnings
35 import warnings
37 import hashlib
38 from os.path import join as jn
36 from os.path import join as jn
39
37
40 import paste
38 import paste
41 import pkg_resources
39 import pkg_resources
42 from webhelpers2.text import collapse, remove_formatting
40 from webhelpers2.text import collapse, strip_tags, convert_accented_entities, convert_misc_entities
41
43 from mako import exceptions
42 from mako import exceptions
44 from pyramid.threadlocal import get_current_registry
45
43
44 from rhodecode.lib.hash_utils import sha256_safe, md5, sha1
45 from rhodecode.lib.str_utils import safe_bytes, safe_str
46 from rhodecode.lib.vcs.backends.base import Config
46 from rhodecode.lib.vcs.backends.base import Config
47 from rhodecode.lib.vcs.exceptions import VCSError
47 from rhodecode.lib.vcs.exceptions import VCSError
48 from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend
48 from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend
49 from rhodecode.lib.utils2 import (
49 from rhodecode.lib.ext_json import sjson as json
50 safe_str, safe_unicode, get_current_rhodecode_user, md5, sha1)
51 from rhodecode.model import meta
50 from rhodecode.model import meta
52 from rhodecode.model.db import (
51 from rhodecode.model.db import (
53 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
52 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
@@ -61,16 +60,16 b" REMOVED_REPO_PAT = re.compile(r'rm__\\d{8"
61 # String which contains characters that are not allowed in slug names for
60 # String which contains characters that are not allowed in slug names for
62 # repositories or repository groups. It is properly escaped to use it in
61 # repositories or repository groups. It is properly escaped to use it in
63 # regular expressions.
62 # regular expressions.
64 SLUG_BAD_CHARS = re.escape('`?=[]\;\'"<>,/~!@#$%^&*()+{}|:')
63 SLUG_BAD_CHARS = re.escape(r'`?=[]\;\'"<>,/~!@#$%^&*()+{}|:')
65
64
66 # Regex that matches forbidden characters in repo/group slugs.
65 # Regex that matches forbidden characters in repo/group slugs.
67 SLUG_BAD_CHAR_RE = re.compile('[{}\x00-\x08\x0b-\x0c\x0e-\x1f]'.format(SLUG_BAD_CHARS))
66 SLUG_BAD_CHAR_RE = re.compile(r'[{}\x00-\x08\x0b-\x0c\x0e-\x1f]'.format(SLUG_BAD_CHARS))
68
67
69 # Regex that matches allowed characters in repo/group slugs.
68 # Regex that matches allowed characters in repo/group slugs.
70 SLUG_GOOD_CHAR_RE = re.compile('[^{}]'.format(SLUG_BAD_CHARS))
69 SLUG_GOOD_CHAR_RE = re.compile(r'[^{}]'.format(SLUG_BAD_CHARS))
71
70
72 # Regex that matches whole repo/group slugs.
71 # Regex that matches whole repo/group slugs.
73 SLUG_RE = re.compile('[^{}]+'.format(SLUG_BAD_CHARS))
72 SLUG_RE = re.compile(r'[^{}]+'.format(SLUG_BAD_CHARS))
74
73
75 _license_cache = None
74 _license_cache = None
76
75
@@ -81,12 +80,17 b' def repo_name_slug(value):'
81 This function is called on each creation/modification
80 This function is called on each creation/modification
82 of repository to prevent bad names in repo
81 of repository to prevent bad names in repo
83 """
82 """
83
84 replacement_char = '-'
84 replacement_char = '-'
85
85
86 slug = remove_formatting(value)
86 slug = strip_tags(value)
87 slug = convert_accented_entities(slug)
88 slug = convert_misc_entities(slug)
89
87 slug = SLUG_BAD_CHAR_RE.sub('', slug)
90 slug = SLUG_BAD_CHAR_RE.sub('', slug)
88 slug = re.sub('[\s]+', '-', slug)
91 slug = re.sub(r'[\s]+', '-', slug)
89 slug = collapse(slug, replacement_char)
92 slug = collapse(slug, replacement_char)
93
90 return slug
94 return slug
91
95
92
96
@@ -96,10 +100,10 b' def repo_name_slug(value):'
96 def get_repo_slug(request):
100 def get_repo_slug(request):
97 _repo = ''
101 _repo = ''
98
102
99 if hasattr(request, 'db_repo'):
103 if hasattr(request, 'db_repo_name'):
100 # if our requests has set db reference use it for name, this
104 # if our requests has set db reference use it for name, this
101 # translates the example.com/_<id> into proper repo names
105 # translates the example.com/_<id> into proper repo names
102 _repo = request.db_repo.repo_name
106 _repo = request.db_repo_name
103 elif getattr(request, 'matchdict', None):
107 elif getattr(request, 'matchdict', None):
104 # pyramid
108 # pyramid
105 _repo = request.matchdict.get('repo_name')
109 _repo = request.matchdict.get('repo_name')
@@ -162,7 +166,7 b' def get_filesystem_repos(path, recursive'
162 log.debug('now scanning in %s location recursive:%s...', path, recursive)
166 log.debug('now scanning in %s location recursive:%s...', path, recursive)
163
167
164 def _get_repos(p):
168 def _get_repos(p):
165 dirpaths = _get_dirpaths(p)
169 dirpaths = get_dirpaths(p)
166 if not _is_dir_writable(p):
170 if not _is_dir_writable(p):
167 log.warning('repo path without write access: %s', p)
171 log.warning('repo path without write access: %s', p)
168
172
@@ -194,7 +198,7 b' def get_filesystem_repos(path, recursive'
194 return _get_repos(path)
198 return _get_repos(path)
195
199
196
200
197 def _get_dirpaths(p):
201 def get_dirpaths(p: str) -> list:
198 try:
202 try:
199 # OS-independable way of checking if we have at least read-only
203 # OS-independable way of checking if we have at least read-only
200 # access or not.
204 # access or not.
@@ -214,7 +218,7 b' def _get_dirpaths(p):'
214 def _has_correct_type(item):
218 def _has_correct_type(item):
215 if type(item) is not expected_type:
219 if type(item) is not expected_type:
216 log.error(
220 log.error(
217 "Ignoring path %s since it cannot be decoded into unicode.",
221 "Ignoring path %s since it cannot be decoded into str.",
218 # Using "repr" to make sure that we see the byte value in case
222 # Using "repr" to make sure that we see the byte value in case
219 # of support.
223 # of support.
220 repr(item))
224 repr(item))
@@ -372,7 +376,7 b' def config_data_from_db(clear_session=Tr'
372 log.debug(
376 log.debug(
373 'settings ui from db@repo[%s]: %s',
377 'settings ui from db@repo[%s]: %s',
374 repo,
378 repo,
375 ','.join(map(lambda s: '[{}] {}={}'.format(*s), ui_data)))
379 ','.join(['[{}] {}={}'.format(*s) for s in ui_data]))
376 if clear_session:
380 if clear_session:
377 meta.Session.remove()
381 meta.Session.remove()
378
382
@@ -441,7 +445,7 b' def set_rhodecode_config(config):'
441 from rhodecode.model.settings import SettingsModel
445 from rhodecode.model.settings import SettingsModel
442 app_settings = SettingsModel().get_all_settings()
446 app_settings = SettingsModel().get_all_settings()
443
447
444 for k, v in app_settings.items():
448 for k, v in list(app_settings.items()):
445 config[k] = v
449 config[k] = v
446
450
447
451
@@ -459,9 +463,9 b' def get_rhodecode_base_path():'
459 Returns the base path. The base path is the filesystem path which points
463 Returns the base path. The base path is the filesystem path which points
460 to the repository store.
464 to the repository store.
461 """
465 """
462 from rhodecode.model.settings import SettingsModel
466
463 paths_ui = SettingsModel().get_ui_by_section_and_key('paths', '/')
467 import rhodecode
464 return safe_str(paths_ui.ui_value)
468 return rhodecode.CONFIG['default_base_path']
465
469
466
470
467 def map_groups(path):
471 def map_groups(path):
@@ -531,10 +535,10 b' def repo2db_mapper(initial_repo_list, re'
531 enable_downloads = defs.get('repo_enable_downloads')
535 enable_downloads = defs.get('repo_enable_downloads')
532 private = defs.get('repo_private')
536 private = defs.get('repo_private')
533
537
534 for name, repo in initial_repo_list.items():
538 for name, repo in list(initial_repo_list.items()):
535 group = map_groups(name)
539 group = map_groups(name)
536 unicode_name = safe_unicode(name)
540 str_name = safe_str(name)
537 db_repo = repo_model.get_by_repo_name(unicode_name)
541 db_repo = repo_model.get_by_repo_name(str_name)
538 # found repo that is on filesystem not in RhodeCode database
542 # found repo that is on filesystem not in RhodeCode database
539 if not db_repo:
543 if not db_repo:
540 log.info('repository %s not found, creating now', name)
544 log.info('repository %s not found, creating now', name)
@@ -574,7 +578,7 b' def repo2db_mapper(initial_repo_list, re'
574 if remove_obsolete:
578 if remove_obsolete:
575 # remove from database those repositories that are not in the filesystem
579 # remove from database those repositories that are not in the filesystem
576 for repo in sa.query(Repository).all():
580 for repo in sa.query(Repository).all():
577 if repo.repo_name not in initial_repo_list.keys():
581 if repo.repo_name not in list(initial_repo_list.keys()):
578 log.debug("Removing non-existing repository found in db `%s`",
582 log.debug("Removing non-existing repository found in db `%s`",
579 repo.repo_name)
583 repo.repo_name)
580 try:
584 try:
@@ -594,13 +598,14 b' def repo2db_mapper(initial_repo_list, re'
594 return gr_name
598 return gr_name
595
599
596 initial_repo_group_list = [splitter(x) for x in
600 initial_repo_group_list = [splitter(x) for x in
597 initial_repo_list.keys() if splitter(x)]
601 list(initial_repo_list.keys()) if splitter(x)]
598
602
599 # remove from database those repository groups that are not in the
603 # remove from database those repository groups that are not in the
600 # filesystem due to parent child relationships we need to delete them
604 # filesystem due to parent child relationships we need to delete them
601 # in a specific order of most nested first
605 # in a specific order of most nested first
602 all_groups = [x.group_name for x in sa.query(RepoGroup).all()]
606 all_groups = [x.group_name for x in sa.query(RepoGroup).all()]
603 nested_sort = lambda gr: len(gr.split('/'))
607 def nested_sort(gr):
608 return len(gr.split('/'))
604 for group_name in sorted(all_groups, key=nested_sort, reverse=True):
609 for group_name in sorted(all_groups, key=nested_sort, reverse=True):
605 if group_name not in initial_repo_group_list:
610 if group_name not in initial_repo_group_list:
606 repo_group = RepoGroup.get_by_group_name(group_name)
611 repo_group = RepoGroup.get_by_group_name(group_name)
@@ -638,7 +643,7 b' def load_rcextensions(root_path):'
638 rcextensions = __import__('rcextensions')
643 rcextensions = __import__('rcextensions')
639 except ImportError:
644 except ImportError:
640 if os.path.isdir(os.path.join(path, 'rcextensions')):
645 if os.path.isdir(os.path.join(path, 'rcextensions')):
641 log.warn('Unable to load rcextensions from %s', path)
646 log.warning('Unable to load rcextensions from %s', path)
642 rcextensions = None
647 rcextensions = None
643
648
644 if rcextensions:
649 if rcextensions:
@@ -676,8 +681,11 b' def create_test_index(repo_location, con'
676 """
681 """
677 Makes default test index.
682 Makes default test index.
678 """
683 """
684 try:
679 import rc_testdata
685 import rc_testdata
680
686 except ImportError:
687 raise ImportError('Failed to import rc_testdata, '
688 'please make sure this package is installed from requirements_test.txt')
681 rc_testdata.extract_search_index(
689 rc_testdata.extract_search_index(
682 'vcs_search_index', os.path.dirname(config['search.location']))
690 'vcs_search_index', os.path.dirname(config['search.location']))
683
691
@@ -696,13 +704,16 b' def create_test_database(test_path, conf'
696 Makes a fresh database.
704 Makes a fresh database.
697 """
705 """
698 from rhodecode.lib.db_manage import DbManage
706 from rhodecode.lib.db_manage import DbManage
707 from rhodecode.lib.utils2 import get_encryption_key
699
708
700 # PART ONE create db
709 # PART ONE create db
701 dbconf = config['sqlalchemy.db1.url']
710 dbconf = config['sqlalchemy.db1.url']
711 enc_key = get_encryption_key(config)
712
702 log.debug('making test db %s', dbconf)
713 log.debug('making test db %s', dbconf)
703
714
704 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
715 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
705 tests=True, cli_args={'force_ask': True})
716 tests=True, cli_args={'force_ask': True}, enc_key=enc_key)
706 dbmanage.create_tables(override=True)
717 dbmanage.create_tables(override=True)
707 dbmanage.set_db_version()
718 dbmanage.set_db_version()
708 # for tests dynamically set new root paths based on generated content
719 # for tests dynamically set new root paths based on generated content
@@ -752,7 +763,7 b' def password_changed(auth_user, session)'
752 if auth_user.username == User.DEFAULT_USER or auth_user.user_id is None:
763 if auth_user.username == User.DEFAULT_USER or auth_user.user_id is None:
753 return False
764 return False
754
765
755 password_hash = md5(auth_user.password) if auth_user.password else None
766 password_hash = md5(safe_bytes(auth_user.password)) if auth_user.password else None
756 rhodecode_user = session.get('rhodecode_user', {})
767 rhodecode_user = session.get('rhodecode_user', {})
757 session_password_hash = rhodecode_user.get('password', '')
768 session_password_hash = rhodecode_user.get('password', '')
758 return password_hash != session_password_hash
769 return password_hash != session_password_hash
@@ -777,7 +788,7 b' def generate_platform_uuid():'
777
788
778 try:
789 try:
779 uuid_list = [platform.platform()]
790 uuid_list = [platform.platform()]
780 return hashlib.sha256(':'.join(uuid_list)).hexdigest()
791 return sha256_safe(':'.join(uuid_list))
781 except Exception as e:
792 except Exception as e:
782 log.error('Failed to generate host uuid: %s', e)
793 log.error('Failed to generate host uuid: %s', e)
783 return 'UNDEFINED'
794 return 'UNDEFINED'
@@ -39,27 +39,23 b' import getpass'
39 import socket
39 import socket
40 import errno
40 import errno
41 import random
41 import random
42 from functools import update_wrapper, partial, wraps
42 import functools
43 from contextlib import closing
43 from contextlib import closing
44
44
45 import pygments.lexers
45 import pygments.lexers
46 import sqlalchemy
46 import sqlalchemy
47 import sqlalchemy.event
47 import sqlalchemy.engine.url
48 import sqlalchemy.engine.url
48 import sqlalchemy.exc
49 import sqlalchemy.exc
49 import sqlalchemy.sql
50 import sqlalchemy.sql
50 import webob
51 import webob
51 import pyramid.threadlocal
52 from pyramid.settings import asbool
52 from pyramid.settings import asbool
53
53
54 import rhodecode
54 import rhodecode
55 from rhodecode.translation import _, _pluralize
55 from rhodecode.translation import _, _pluralize
56 from rhodecode.lib.str_utils import safe_str, safe_int, safe_bytes
56 from rhodecode.lib.str_utils import safe_str, safe_int, safe_bytes
57 from rhodecode.lib.hash_utils import md5, md5_safe, sha1, sha1_safe
57 from rhodecode.lib.hash_utils import md5, md5_safe, sha1, sha1_safe
58 from rhodecode.lib.type_utils import aslist, str2bool
58 from rhodecode.lib.type_utils import aslist, str2bool, StrictAttributeDict, AttributeDict
59 from functools import reduce
60
61 #TODO: there's no longer safe_unicode, we mock it now, but should remove it
62 safe_unicode = safe_str
63
59
64
60
65 def __get_lem(extra_mapping=None):
61 def __get_lem(extra_mapping=None):
@@ -85,7 +81,7 b' def __get_lem(extra_mapping=None):'
85 for lx, t in sorted(pygments.lexers.LEXERS.items()):
81 for lx, t in sorted(pygments.lexers.LEXERS.items()):
86 m = list(map(__clean, t[-2]))
82 m = list(map(__clean, t[-2]))
87 if m:
83 if m:
88 m = reduce(lambda x, y: x + y, m)
84 m = functools.reduce(lambda x, y: x + y, m)
89 for ext in m:
85 for ext in m:
90 desc = lx.replace('Lexer', '')
86 desc = lx.replace('Lexer', '')
91 d[ext].append(desc)
87 d[ext].append(desc)
@@ -94,7 +90,7 b' def __get_lem(extra_mapping=None):'
94
90
95 extra_mapping = extra_mapping or {}
91 extra_mapping = extra_mapping or {}
96 if extra_mapping:
92 if extra_mapping:
97 for k, v in extra_mapping.items():
93 for k, v in list(extra_mapping.items()):
98 if k not in data:
94 if k not in data:
99 # register new mapping2lexer
95 # register new mapping2lexer
100 data[k] = [v]
96 data[k] = [v]
@@ -102,7 +98,7 b' def __get_lem(extra_mapping=None):'
102 return data
98 return data
103
99
104
100
105 def convert_line_endings(line, mode):
101 def convert_line_endings(line: str, mode) -> str:
106 """
102 """
107 Converts a given line "line end" accordingly to given mode
103 Converts a given line "line end" accordingly to given mode
108
104
@@ -113,7 +109,6 b' def convert_line_endings(line, mode):'
113
109
114 :param line: given line to convert
110 :param line: given line to convert
115 :param mode: mode to convert to
111 :param mode: mode to convert to
116 :rtype: str
117 :return: converted line according to mode
112 :return: converted line according to mode
118 """
113 """
119 if mode == 0:
114 if mode == 0:
@@ -127,14 +122,13 b' def convert_line_endings(line, mode):'
127 return line
122 return line
128
123
129
124
130 def detect_mode(line, default):
125 def detect_mode(line: str, default) -> int:
131 """
126 """
132 Detects line break for given line, if line break couldn't be found
127 Detects line break for given line, if line break couldn't be found
133 given default value is returned
128 given default value is returned
134
129
135 :param line: str line
130 :param line: str line
136 :param default: default
131 :param default: default
137 :rtype: int
138 :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
132 :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
139 """
133 """
140 if line.endswith('\r\n'):
134 if line.endswith('\r\n'):
@@ -159,14 +153,18 b' def remove_prefix(s, prefix):'
159 return s
153 return s
160
154
161
155
162 def find_calling_context(ignore_modules=None):
156 def find_calling_context(ignore_modules=None, depth=4, output_writer=None, indent=True):
163 """
157 """
164 Look through the calling stack and return the frame which called
158 Look through the calling stack and return the frame which called
165 this function and is part of core module ( ie. rhodecode.* )
159 this function and is part of core module ( ie. rhodecode.* )
166
160
167 :param ignore_modules: list of modules to ignore eg. ['rhodecode.lib']
161 :param ignore_modules: list of modules to ignore eg. ['rhodecode.lib']
162 :param depth:
163 :param output_writer:
164 :param indent:
168
165
169 usage::
166 usage::
167
170 from rhodecode.lib.utils2 import find_calling_context
168 from rhodecode.lib.utils2 import find_calling_context
171
169
172 calling_context = find_calling_context(ignore_modules=[
170 calling_context = find_calling_context(ignore_modules=[
@@ -174,24 +172,36 b' def find_calling_context(ignore_modules='
174 'rhodecode.model.settings',
172 'rhodecode.model.settings',
175 ])
173 ])
176
174
177 if calling_context:
178 cc_str = 'call context %s:%s' % (
179 calling_context.f_code.co_filename,
180 calling_context.f_lineno,
181 )
182 print(cc_str)
183 """
175 """
176 import inspect
177 if not output_writer:
178 try:
179 from rich import print as pprint
180 except ImportError:
181 pprint = print
182 output_writer = pprint
184
183
185 ignore_modules = ignore_modules or []
184 frame = inspect.currentframe()
185 cc = []
186 try:
187 for i in range(depth): # current frame + 3 callers
188 frame = frame.f_back
189 if not frame:
190 break
186
191
187 f = sys._getframe(2)
192 info = inspect.getframeinfo(frame)
188 while f.f_back is not None:
193 name = frame.f_globals.get('__name__')
189 name = f.f_globals.get('__name__')
190 if name and name.startswith(__name__.split('.')[0]):
191 if name not in ignore_modules:
194 if name not in ignore_modules:
192 return f
195 cc.insert(0, f'CALL_CONTEXT:{i}: file {info.filename}:{info.lineno} -> {info.function}')
193 f = f.f_back
196 finally:
194 return None
197 # Avoids a reference cycle
198 del frame
199
200 output_writer('* INFO: This code was called from: *')
201 for cnt, frm_info in enumerate(cc):
202 if not indent:
203 cnt = 1
204 output_writer(' ' * cnt + frm_info)
195
205
196
206
197 def ping_connection(connection, branch):
207 def ping_connection(connection, branch):
@@ -252,15 +262,10 b' def engine_from_config(configuration, pr'
252 parameters, context, executemany):
262 parameters, context, executemany):
253 setattr(conn, 'query_start_time', time.time())
263 setattr(conn, 'query_start_time', time.time())
254 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
264 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
255 calling_context = find_calling_context(ignore_modules=[
265 find_calling_context(ignore_modules=[
256 'rhodecode.lib.caching_query',
266 'rhodecode.lib.caching_query',
257 'rhodecode.model.settings',
267 'rhodecode.model.settings',
258 ])
268 ], output_writer=log.info)
259 if calling_context:
260 log.info(color_sql('call context %s:%s' % (
261 calling_context.f_code.co_filename,
262 calling_context.f_lineno,
263 )))
264
269
265 def after_cursor_execute(conn, cursor, statement,
270 def after_cursor_execute(conn, cursor, statement,
266 parameters, context, executemany):
271 parameters, context, executemany):
@@ -272,10 +277,12 b' def engine_from_config(configuration, pr'
272 return engine
277 return engine
273
278
274
279
275 def get_encryption_key(config):
280 def get_encryption_key(config) -> bytes:
276 secret = config.get('rhodecode.encrypted_values.secret')
281 secret = config.get('rhodecode.encrypted_values.secret')
277 default = config['beaker.session.secret']
282 default = config['beaker.session.secret']
278 return secret or default
283 enc_key = secret or default
284
285 return safe_bytes(enc_key)
279
286
280
287
281 def age(prevdate, now=None, show_short_version=False, show_suffix=True, short_format=False):
288 def age(prevdate, now=None, show_short_version=False, show_suffix=True, short_format=False):
@@ -476,7 +483,7 b' def get_host_info(request):'
476
483
477 qualified_home_url = request.route_url('home')
484 qualified_home_url = request.route_url('home')
478 parsed_url = urlobject.URLObject(qualified_home_url)
485 parsed_url = urlobject.URLObject(qualified_home_url)
479 decoded_path = safe_unicode(urllib.parse.unquote(parsed_url.path.rstrip('/')))
486 decoded_path = safe_str(urllib.parse.unquote(parsed_url.path.rstrip('/')))
480
487
481 return {
488 return {
482 'scheme': parsed_url.scheme,
489 'scheme': parsed_url.scheme,
@@ -488,7 +495,7 b' def get_host_info(request):'
488 def get_clone_url(request, uri_tmpl, repo_name, repo_id, repo_type, **override):
495 def get_clone_url(request, uri_tmpl, repo_name, repo_id, repo_type, **override):
489 qualified_home_url = request.route_url('home')
496 qualified_home_url = request.route_url('home')
490 parsed_url = urlobject.URLObject(qualified_home_url)
497 parsed_url = urlobject.URLObject(qualified_home_url)
491 decoded_path = safe_unicode(urllib.parse.unquote(parsed_url.path.rstrip('/')))
498 decoded_path = safe_str(urllib.parse.unquote(parsed_url.path.rstrip('/')))
492
499
493 args = {
500 args = {
494 'scheme': parsed_url.scheme,
501 'scheme': parsed_url.scheme,
@@ -505,8 +512,9 b' def get_clone_url(request, uri_tmpl, rep'
505 args.update(override)
512 args.update(override)
506 args['user'] = urllib.parse.quote(safe_str(args['user']))
513 args['user'] = urllib.parse.quote(safe_str(args['user']))
507
514
508 for k, v in args.items():
515 for k, v in list(args.items()):
509 uri_tmpl = uri_tmpl.replace('{%s}' % k, v)
516 tmpl_key = '{%s}' % k
517 uri_tmpl = uri_tmpl.replace(tmpl_key, v)
510
518
511 # special case for SVN clone url
519 # special case for SVN clone url
512 if repo_type == 'svn':
520 if repo_type == 'svn':
@@ -516,7 +524,7 b' def get_clone_url(request, uri_tmpl, rep'
516 url_obj = urlobject.URLObject(uri_tmpl)
524 url_obj = urlobject.URLObject(uri_tmpl)
517 url = url_obj.with_netloc(url_obj.netloc.lstrip('@'))
525 url = url_obj.with_netloc(url_obj.netloc.lstrip('@'))
518
526
519 return safe_unicode(url)
527 return safe_str(url)
520
528
521
529
522 def get_commit_safe(repo, commit_id=None, commit_idx=None, pre_load=None,
530 def get_commit_safe(repo, commit_id=None, commit_idx=None, pre_load=None,
@@ -594,36 +602,6 b' def extract_mentioned_users(s):'
594 return sorted(list(usrs), key=lambda k: k.lower())
602 return sorted(list(usrs), key=lambda k: k.lower())
595
603
596
604
597 class AttributeDictBase(dict):
598 def __getstate__(self):
599 odict = self.__dict__ # get attribute dictionary
600 return odict
601
602 def __setstate__(self, dict):
603 self.__dict__ = dict
604
605 __setattr__ = dict.__setitem__
606 __delattr__ = dict.__delitem__
607
608
609 class StrictAttributeDict(AttributeDictBase):
610 """
611 Strict Version of Attribute dict which raises an Attribute error when
612 requested attribute is not set
613 """
614 def __getattr__(self, attr):
615 try:
616 return self[attr]
617 except KeyError:
618 raise AttributeError('%s object has no attribute %s' % (
619 self.__class__, attr))
620
621
622 class AttributeDict(AttributeDictBase):
623 def __getattr__(self, attr):
624 return self.get(attr, None)
625
626
627 def fix_PATH(os_=None):
605 def fix_PATH(os_=None):
628 """
606 """
629 Get current active python path, and append it to PATH variable to fix
607 Get current active python path, and append it to PATH variable to fix
@@ -635,19 +613,18 b' def fix_PATH(os_=None):'
635 os = os_
613 os = os_
636
614
637 cur_path = os.path.split(sys.executable)[0]
615 cur_path = os.path.split(sys.executable)[0]
616 os_path = os.environ['PATH']
638 if not os.environ['PATH'].startswith(cur_path):
617 if not os.environ['PATH'].startswith(cur_path):
639 os.environ['PATH'] = '%s:%s' % (cur_path, os.environ['PATH'])
618 os.environ['PATH'] = f'{cur_path}:{os_path}'
640
619
641
620
642 def obfuscate_url_pw(engine):
621 def obfuscate_url_pw(engine):
643 _url = engine or ''
622 _url = engine or ''
644 try:
623 try:
645 _url = sqlalchemy.engine.url.make_url(engine)
624 _url = sqlalchemy.engine.url.make_url(engine)
646 if _url.password:
647 _url.password = 'XXXXX'
648 except Exception:
625 except Exception:
649 pass
626 pass
650 return str(_url)
627 return repr(_url)
651
628
652
629
653 def get_server_url(environ):
630 def get_server_url(environ):
@@ -695,6 +672,7 b' def get_current_rhodecode_user(request=N'
695 """
672 """
696 Gets rhodecode user from request
673 Gets rhodecode user from request
697 """
674 """
675 import pyramid.threadlocal
698 pyramid_request = request or pyramid.threadlocal.get_current_request()
676 pyramid_request = request or pyramid.threadlocal.get_current_request()
699
677
700 # web case
678 # web case
@@ -837,51 +815,15 b' class Optional(object):'
837
815
838
816
839 def glob2re(pat):
817 def glob2re(pat):
840 """
818 import fnmatch
841 Translate a shell PATTERN to a regular expression.
819 return fnmatch.translate(pat)
842
843 There is no way to quote meta-characters.
844 """
845
846 i, n = 0, len(pat)
847 res = ''
848 while i < n:
849 c = pat[i]
850 i = i+1
851 if c == '*':
852 #res = res + '.*'
853 res = res + '[^/]*'
854 elif c == '?':
855 #res = res + '.'
856 res = res + '[^/]'
857 elif c == '[':
858 j = i
859 if j < n and pat[j] == '!':
860 j = j+1
861 if j < n and pat[j] == ']':
862 j = j+1
863 while j < n and pat[j] != ']':
864 j = j+1
865 if j >= n:
866 res = res + '\\['
867 else:
868 stuff = pat[i:j].replace('\\','\\\\')
869 i = j+1
870 if stuff[0] == '!':
871 stuff = '^' + stuff[1:]
872 elif stuff[0] == '^':
873 stuff = '\\' + stuff
874 res = '%s[%s]' % (res, stuff)
875 else:
876 res = res + re.escape(c)
877 return res + '\Z(?ms)'
878
820
879
821
880 def parse_byte_string(size_str):
822 def parse_byte_string(size_str):
881 match = re.match(r'(\d+)(MB|KB)', size_str, re.IGNORECASE)
823 match = re.match(r'(\d+)(MB|KB)', size_str, re.IGNORECASE)
882 if not match:
824 if not match:
883 raise ValueError('Given size:%s is invalid, please make sure '
825 raise ValueError(f'Given size:{size_str} is invalid, please make sure '
884 'to use format of <num>(MB|KB)' % size_str)
826 f'to use format of <num>(MB|KB)')
885
827
886 _parts = match.groups()
828 _parts = match.groups()
887 num, type_ = _parts
829 num, type_ = _parts
@@ -911,7 +853,7 b' class CachedProperty(object):'
911 if func_name is None:
853 if func_name is None:
912 func_name = func.__name__
854 func_name = func.__name__
913 self.data = (func, func_name)
855 self.data = (func, func_name)
914 update_wrapper(self, func)
856 functools.update_wrapper(self, func)
915
857
916 def __get__(self, inst, class_):
858 def __get__(self, inst, class_):
917 if inst is None:
859 if inst is None:
@@ -921,7 +863,7 b' class CachedProperty(object):'
921 value = func(inst)
863 value = func(inst)
922 inst.__dict__[func_name] = value
864 inst.__dict__[func_name] = value
923 if '_invalidate_prop_cache' not in inst.__dict__:
865 if '_invalidate_prop_cache' not in inst.__dict__:
924 inst.__dict__['_invalidate_prop_cache'] = partial(
866 inst.__dict__['_invalidate_prop_cache'] = functools.partial(
925 self._invalidate_prop_cache, inst)
867 self._invalidate_prop_cache, inst)
926 return value
868 return value
927
869
@@ -967,7 +909,7 b' def retry(func=None, exception=Exception'
967 """
909 """
968
910
969 if func is None:
911 if func is None:
970 return partial(
912 return functools.partial(
971 retry,
913 retry,
972 exception=exception,
914 exception=exception,
973 n_tries=n_tries,
915 n_tries=n_tries,
@@ -976,7 +918,7 b' def retry(func=None, exception=Exception'
976 logger=logger,
918 logger=logger,
977 )
919 )
978
920
979 @wraps(func)
921 @functools.wraps(func)
980 def wrapper(*args, **kwargs):
922 def wrapper(*args, **kwargs):
981 _n_tries, n_delay = n_tries, delay
923 _n_tries, n_delay = n_tries, delay
982 log = logging.getLogger('rhodecode.retry')
924 log = logging.getLogger('rhodecode.retry')
@@ -1016,7 +958,7 b' def user_agent_normalizer(user_agent_raw'
1016 parts = ua.split(' ')
958 parts = ua.split(' ')
1017 if parts:
959 if parts:
1018 ua = parts[0]
960 ua = parts[0]
1019 ua = re.sub('\.windows\.\d', '', ua).strip()
961 ua = re.sub(r'\.windows\.\d', '', ua).strip()
1020
962
1021 return ua
963 return ua
1022 except Exception:
964 except Exception:
General Comments 0
You need to be logged in to leave comments. Login now