##// END OF EJS Templates
utils: make sure we don't import any models inside utils
marcink -
r262:09af6d74 default
parent child Browse files
Show More
@@ -1,971 +1,977 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Utilities library for RhodeCode
22 Utilities library for RhodeCode
23 """
23 """
24
24
25 import datetime
25 import datetime
26 import decorator
26 import decorator
27 import json
27 import json
28 import logging
28 import logging
29 import os
29 import os
30 import re
30 import re
31 import shutil
31 import shutil
32 import tempfile
32 import tempfile
33 import traceback
33 import traceback
34 import tarfile
34 import tarfile
35 import warnings
35 import warnings
36 from os.path import abspath
36 from os.path import abspath
37 from os.path import dirname as dn, join as jn
37 from os.path import dirname as dn, join as jn
38
38
39 import paste
39 import paste
40 import pkg_resources
40 import pkg_resources
41 from paste.script.command import Command, BadCommand
41 from paste.script.command import Command, BadCommand
42 from webhelpers.text import collapse, remove_formatting, strip_tags
42 from webhelpers.text import collapse, remove_formatting, strip_tags
43 from mako import exceptions
43 from mako import exceptions
44
44
45 from rhodecode.lib.fakemod import create_module
45 from rhodecode.lib.fakemod import create_module
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.utils2 import (
50 safe_str, safe_unicode, get_current_rhodecode_user, md5)
50 safe_str, safe_unicode, get_current_rhodecode_user, md5)
51 from rhodecode.model import meta
51 from rhodecode.model import meta
52 from rhodecode.model.db import (
52 from rhodecode.model.db import (
53 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
53 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
54 from rhodecode.model.meta import Session
54 from rhodecode.model.meta import Session
55 from rhodecode.model.repo_group import RepoGroupModel
55
56 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
57
56
58 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
59
58
60 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
59 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
61
60
62 _license_cache = None
61 _license_cache = None
63
62
64
63
65 def recursive_replace(str_, replace=' '):
64 def recursive_replace(str_, replace=' '):
66 """
65 """
67 Recursive replace of given sign to just one instance
66 Recursive replace of given sign to just one instance
68
67
69 :param str_: given string
68 :param str_: given string
70 :param replace: char to find and replace multiple instances
69 :param replace: char to find and replace multiple instances
71
70
72 Examples::
71 Examples::
73 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
72 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
74 'Mighty-Mighty-Bo-sstones'
73 'Mighty-Mighty-Bo-sstones'
75 """
74 """
76
75
77 if str_.find(replace * 2) == -1:
76 if str_.find(replace * 2) == -1:
78 return str_
77 return str_
79 else:
78 else:
80 str_ = str_.replace(replace * 2, replace)
79 str_ = str_.replace(replace * 2, replace)
81 return recursive_replace(str_, replace)
80 return recursive_replace(str_, replace)
82
81
83
82
84 def repo_name_slug(value):
83 def repo_name_slug(value):
85 """
84 """
86 Return slug of name of repository
85 Return slug of name of repository
87 This function is called on each creation/modification
86 This function is called on each creation/modification
88 of repository to prevent bad names in repo
87 of repository to prevent bad names in repo
89 """
88 """
90
89
91 slug = remove_formatting(value)
90 slug = remove_formatting(value)
92 slug = strip_tags(slug)
91 slug = strip_tags(slug)
93
92
94 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
93 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
95 slug = slug.replace(c, '-')
94 slug = slug.replace(c, '-')
96 slug = recursive_replace(slug, '-')
95 slug = recursive_replace(slug, '-')
97 slug = collapse(slug, '-')
96 slug = collapse(slug, '-')
98 return slug
97 return slug
99
98
100
99
101 #==============================================================================
100 #==============================================================================
102 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
101 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
103 #==============================================================================
102 #==============================================================================
104 def get_repo_slug(request):
103 def get_repo_slug(request):
105 _repo = request.environ['pylons.routes_dict'].get('repo_name')
104 _repo = request.environ['pylons.routes_dict'].get('repo_name')
106 if _repo:
105 if _repo:
107 _repo = _repo.rstrip('/')
106 _repo = _repo.rstrip('/')
108 return _repo
107 return _repo
109
108
110
109
111 def get_repo_group_slug(request):
110 def get_repo_group_slug(request):
112 _group = request.environ['pylons.routes_dict'].get('group_name')
111 _group = request.environ['pylons.routes_dict'].get('group_name')
113 if _group:
112 if _group:
114 _group = _group.rstrip('/')
113 _group = _group.rstrip('/')
115 return _group
114 return _group
116
115
117
116
118 def get_user_group_slug(request):
117 def get_user_group_slug(request):
119 _group = request.environ['pylons.routes_dict'].get('user_group_id')
118 _group = request.environ['pylons.routes_dict'].get('user_group_id')
120 try:
119 try:
121 _group = UserGroup.get(_group)
120 _group = UserGroup.get(_group)
122 if _group:
121 if _group:
123 _group = _group.users_group_name
122 _group = _group.users_group_name
124 except Exception:
123 except Exception:
125 log.debug(traceback.format_exc())
124 log.debug(traceback.format_exc())
126 #catch all failures here
125 #catch all failures here
127 pass
126 pass
128
127
129 return _group
128 return _group
130
129
131
130
132 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
131 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
133 """
132 """
134 Action logger for various actions made by users
133 Action logger for various actions made by users
135
134
136 :param user: user that made this action, can be a unique username string or
135 :param user: user that made this action, can be a unique username string or
137 object containing user_id attribute
136 object containing user_id attribute
138 :param action: action to log, should be on of predefined unique actions for
137 :param action: action to log, should be on of predefined unique actions for
139 easy translations
138 easy translations
140 :param repo: string name of repository or object containing repo_id,
139 :param repo: string name of repository or object containing repo_id,
141 that action was made on
140 that action was made on
142 :param ipaddr: optional ip address from what the action was made
141 :param ipaddr: optional ip address from what the action was made
143 :param sa: optional sqlalchemy session
142 :param sa: optional sqlalchemy session
144
143
145 """
144 """
146
145
147 if not sa:
146 if not sa:
148 sa = meta.Session()
147 sa = meta.Session()
149 # if we don't get explicit IP address try to get one from registered user
148 # if we don't get explicit IP address try to get one from registered user
150 # in tmpl context var
149 # in tmpl context var
151 if not ipaddr:
150 if not ipaddr:
152 ipaddr = getattr(get_current_rhodecode_user(), 'ip_addr', '')
151 ipaddr = getattr(get_current_rhodecode_user(), 'ip_addr', '')
153
152
154 try:
153 try:
155 if getattr(user, 'user_id', None):
154 if getattr(user, 'user_id', None):
156 user_obj = User.get(user.user_id)
155 user_obj = User.get(user.user_id)
157 elif isinstance(user, basestring):
156 elif isinstance(user, basestring):
158 user_obj = User.get_by_username(user)
157 user_obj = User.get_by_username(user)
159 else:
158 else:
160 raise Exception('You have to provide a user object or a username')
159 raise Exception('You have to provide a user object or a username')
161
160
162 if getattr(repo, 'repo_id', None):
161 if getattr(repo, 'repo_id', None):
163 repo_obj = Repository.get(repo.repo_id)
162 repo_obj = Repository.get(repo.repo_id)
164 repo_name = repo_obj.repo_name
163 repo_name = repo_obj.repo_name
165 elif isinstance(repo, basestring):
164 elif isinstance(repo, basestring):
166 repo_name = repo.lstrip('/')
165 repo_name = repo.lstrip('/')
167 repo_obj = Repository.get_by_repo_name(repo_name)
166 repo_obj = Repository.get_by_repo_name(repo_name)
168 else:
167 else:
169 repo_obj = None
168 repo_obj = None
170 repo_name = ''
169 repo_name = ''
171
170
172 user_log = UserLog()
171 user_log = UserLog()
173 user_log.user_id = user_obj.user_id
172 user_log.user_id = user_obj.user_id
174 user_log.username = user_obj.username
173 user_log.username = user_obj.username
175 action = safe_unicode(action)
174 action = safe_unicode(action)
176 user_log.action = action[:1200000]
175 user_log.action = action[:1200000]
177
176
178 user_log.repository = repo_obj
177 user_log.repository = repo_obj
179 user_log.repository_name = repo_name
178 user_log.repository_name = repo_name
180
179
181 user_log.action_date = datetime.datetime.now()
180 user_log.action_date = datetime.datetime.now()
182 user_log.user_ip = ipaddr
181 user_log.user_ip = ipaddr
183 sa.add(user_log)
182 sa.add(user_log)
184
183
185 log.info('Logging action:`%s` on repo:`%s` by user:%s ip:%s',
184 log.info('Logging action:`%s` on repo:`%s` by user:%s ip:%s',
186 action, safe_unicode(repo), user_obj, ipaddr)
185 action, safe_unicode(repo), user_obj, ipaddr)
187 if commit:
186 if commit:
188 sa.commit()
187 sa.commit()
189 except Exception:
188 except Exception:
190 log.error(traceback.format_exc())
189 log.error(traceback.format_exc())
191 raise
190 raise
192
191
193
192
194 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
193 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
195 """
194 """
196 Scans given path for repos and return (name,(type,path)) tuple
195 Scans given path for repos and return (name,(type,path)) tuple
197
196
198 :param path: path to scan for repositories
197 :param path: path to scan for repositories
199 :param recursive: recursive search and return names with subdirs in front
198 :param recursive: recursive search and return names with subdirs in front
200 """
199 """
201
200
202 # remove ending slash for better results
201 # remove ending slash for better results
203 path = path.rstrip(os.sep)
202 path = path.rstrip(os.sep)
204 log.debug('now scanning in %s location recursive:%s...', path, recursive)
203 log.debug('now scanning in %s location recursive:%s...', path, recursive)
205
204
206 def _get_repos(p):
205 def _get_repos(p):
207 dirpaths = _get_dirpaths(p)
206 dirpaths = _get_dirpaths(p)
208 if not _is_dir_writable(p):
207 if not _is_dir_writable(p):
209 log.warning('repo path without write access: %s', p)
208 log.warning('repo path without write access: %s', p)
210
209
211 for dirpath in dirpaths:
210 for dirpath in dirpaths:
212 if os.path.isfile(os.path.join(p, dirpath)):
211 if os.path.isfile(os.path.join(p, dirpath)):
213 continue
212 continue
214 cur_path = os.path.join(p, dirpath)
213 cur_path = os.path.join(p, dirpath)
215
214
216 # skip removed repos
215 # skip removed repos
217 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
216 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
218 continue
217 continue
219
218
220 #skip .<somethin> dirs
219 #skip .<somethin> dirs
221 if dirpath.startswith('.'):
220 if dirpath.startswith('.'):
222 continue
221 continue
223
222
224 try:
223 try:
225 scm_info = get_scm(cur_path)
224 scm_info = get_scm(cur_path)
226 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
225 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
227 except VCSError:
226 except VCSError:
228 if not recursive:
227 if not recursive:
229 continue
228 continue
230 #check if this dir containts other repos for recursive scan
229 #check if this dir containts other repos for recursive scan
231 rec_path = os.path.join(p, dirpath)
230 rec_path = os.path.join(p, dirpath)
232 if os.path.isdir(rec_path):
231 if os.path.isdir(rec_path):
233 for inner_scm in _get_repos(rec_path):
232 for inner_scm in _get_repos(rec_path):
234 yield inner_scm
233 yield inner_scm
235
234
236 return _get_repos(path)
235 return _get_repos(path)
237
236
238
237
239 def _get_dirpaths(p):
238 def _get_dirpaths(p):
240 try:
239 try:
241 # OS-independable way of checking if we have at least read-only
240 # OS-independable way of checking if we have at least read-only
242 # access or not.
241 # access or not.
243 dirpaths = os.listdir(p)
242 dirpaths = os.listdir(p)
244 except OSError:
243 except OSError:
245 log.warning('ignoring repo path without read access: %s', p)
244 log.warning('ignoring repo path without read access: %s', p)
246 return []
245 return []
247
246
248 # os.listpath has a tweak: If a unicode is passed into it, then it tries to
247 # os.listpath has a tweak: If a unicode is passed into it, then it tries to
249 # decode paths and suddenly returns unicode objects itself. The items it
248 # decode paths and suddenly returns unicode objects itself. The items it
250 # cannot decode are returned as strings and cause issues.
249 # cannot decode are returned as strings and cause issues.
251 #
250 #
252 # Those paths are ignored here until a solid solution for path handling has
251 # Those paths are ignored here until a solid solution for path handling has
253 # been built.
252 # been built.
254 expected_type = type(p)
253 expected_type = type(p)
255
254
256 def _has_correct_type(item):
255 def _has_correct_type(item):
257 if type(item) is not expected_type:
256 if type(item) is not expected_type:
258 log.error(
257 log.error(
259 u"Ignoring path %s since it cannot be decoded into unicode.",
258 u"Ignoring path %s since it cannot be decoded into unicode.",
260 # Using "repr" to make sure that we see the byte value in case
259 # Using "repr" to make sure that we see the byte value in case
261 # of support.
260 # of support.
262 repr(item))
261 repr(item))
263 return False
262 return False
264 return True
263 return True
265
264
266 dirpaths = [item for item in dirpaths if _has_correct_type(item)]
265 dirpaths = [item for item in dirpaths if _has_correct_type(item)]
267
266
268 return dirpaths
267 return dirpaths
269
268
270
269
271 def _is_dir_writable(path):
270 def _is_dir_writable(path):
272 """
271 """
273 Probe if `path` is writable.
272 Probe if `path` is writable.
274
273
275 Due to trouble on Cygwin / Windows, this is actually probing if it is
274 Due to trouble on Cygwin / Windows, this is actually probing if it is
276 possible to create a file inside of `path`, stat does not produce reliable
275 possible to create a file inside of `path`, stat does not produce reliable
277 results in this case.
276 results in this case.
278 """
277 """
279 try:
278 try:
280 with tempfile.TemporaryFile(dir=path):
279 with tempfile.TemporaryFile(dir=path):
281 pass
280 pass
282 except OSError:
281 except OSError:
283 return False
282 return False
284 return True
283 return True
285
284
286
285
287 def is_valid_repo(repo_name, base_path, expect_scm=None, explicit_scm=None):
286 def is_valid_repo(repo_name, base_path, expect_scm=None, explicit_scm=None):
288 """
287 """
289 Returns True if given path is a valid repository False otherwise.
288 Returns True if given path is a valid repository False otherwise.
290 If expect_scm param is given also, compare if given scm is the same
289 If expect_scm param is given also, compare if given scm is the same
291 as expected from scm parameter. If explicit_scm is given don't try to
290 as expected from scm parameter. If explicit_scm is given don't try to
292 detect the scm, just use the given one to check if repo is valid
291 detect the scm, just use the given one to check if repo is valid
293
292
294 :param repo_name:
293 :param repo_name:
295 :param base_path:
294 :param base_path:
296 :param expect_scm:
295 :param expect_scm:
297 :param explicit_scm:
296 :param explicit_scm:
298
297
299 :return True: if given path is a valid repository
298 :return True: if given path is a valid repository
300 """
299 """
301 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
300 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
302 log.debug('Checking if `%s` is a valid path for repository', repo_name)
301 log.debug('Checking if `%s` is a valid path for repository', repo_name)
303
302
304 try:
303 try:
305 if explicit_scm:
304 if explicit_scm:
306 detected_scms = [get_scm_backend(explicit_scm)]
305 detected_scms = [get_scm_backend(explicit_scm)]
307 else:
306 else:
308 detected_scms = get_scm(full_path)
307 detected_scms = get_scm(full_path)
309
308
310 if expect_scm:
309 if expect_scm:
311 return detected_scms[0] == expect_scm
310 return detected_scms[0] == expect_scm
312 log.debug('path: %s is an vcs object:%s', full_path, detected_scms)
311 log.debug('path: %s is an vcs object:%s', full_path, detected_scms)
313 return True
312 return True
314 except VCSError:
313 except VCSError:
315 log.debug('path: %s is not a valid repo !', full_path)
314 log.debug('path: %s is not a valid repo !', full_path)
316 return False
315 return False
317
316
318
317
319 def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False):
318 def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False):
320 """
319 """
321 Returns True if given path is a repository group, False otherwise
320 Returns True if given path is a repository group, False otherwise
322
321
323 :param repo_name:
322 :param repo_name:
324 :param base_path:
323 :param base_path:
325 """
324 """
326 full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name))
325 full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name))
327 log.debug('Checking if `%s` is a valid path for repository group',
326 log.debug('Checking if `%s` is a valid path for repository group',
328 repo_group_name)
327 repo_group_name)
329
328
330 # check if it's not a repo
329 # check if it's not a repo
331 if is_valid_repo(repo_group_name, base_path):
330 if is_valid_repo(repo_group_name, base_path):
332 log.debug('Repo called %s exist, it is not a valid '
331 log.debug('Repo called %s exist, it is not a valid '
333 'repo group' % repo_group_name)
332 'repo group' % repo_group_name)
334 return False
333 return False
335
334
336 try:
335 try:
337 # we need to check bare git repos at higher level
336 # we need to check bare git repos at higher level
338 # since we might match branches/hooks/info/objects or possible
337 # since we might match branches/hooks/info/objects or possible
339 # other things inside bare git repo
338 # other things inside bare git repo
340 scm_ = get_scm(os.path.dirname(full_path))
339 scm_ = get_scm(os.path.dirname(full_path))
341 log.debug('path: %s is a vcs object:%s, not valid '
340 log.debug('path: %s is a vcs object:%s, not valid '
342 'repo group' % (full_path, scm_))
341 'repo group' % (full_path, scm_))
343 return False
342 return False
344 except VCSError:
343 except VCSError:
345 pass
344 pass
346
345
347 # check if it's a valid path
346 # check if it's a valid path
348 if skip_path_check or os.path.isdir(full_path):
347 if skip_path_check or os.path.isdir(full_path):
349 log.debug('path: %s is a valid repo group !', full_path)
348 log.debug('path: %s is a valid repo group !', full_path)
350 return True
349 return True
351
350
352 log.debug('path: %s is not a valid repo group !', full_path)
351 log.debug('path: %s is not a valid repo group !', full_path)
353 return False
352 return False
354
353
355
354
356 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
355 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
357 while True:
356 while True:
358 ok = raw_input(prompt)
357 ok = raw_input(prompt)
359 if ok in ('y', 'ye', 'yes'):
358 if ok in ('y', 'ye', 'yes'):
360 return True
359 return True
361 if ok in ('n', 'no', 'nop', 'nope'):
360 if ok in ('n', 'no', 'nop', 'nope'):
362 return False
361 return False
363 retries = retries - 1
362 retries = retries - 1
364 if retries < 0:
363 if retries < 0:
365 raise IOError
364 raise IOError
366 print complaint
365 print complaint
367
366
368 # propagated from mercurial documentation
367 # propagated from mercurial documentation
369 ui_sections = [
368 ui_sections = [
370 'alias', 'auth',
369 'alias', 'auth',
371 'decode/encode', 'defaults',
370 'decode/encode', 'defaults',
372 'diff', 'email',
371 'diff', 'email',
373 'extensions', 'format',
372 'extensions', 'format',
374 'merge-patterns', 'merge-tools',
373 'merge-patterns', 'merge-tools',
375 'hooks', 'http_proxy',
374 'hooks', 'http_proxy',
376 'smtp', 'patch',
375 'smtp', 'patch',
377 'paths', 'profiling',
376 'paths', 'profiling',
378 'server', 'trusted',
377 'server', 'trusted',
379 'ui', 'web', ]
378 'ui', 'web', ]
380
379
381
380
382 def config_data_from_db(clear_session=True, repo=None):
381 def config_data_from_db(clear_session=True, repo=None):
383 """
382 """
384 Read the configuration data from the database and return configuration
383 Read the configuration data from the database and return configuration
385 tuples.
384 tuples.
386 """
385 """
386 from rhodecode.model.settings import VcsSettingsModel
387
387 config = []
388 config = []
388
389
389 sa = meta.Session()
390 sa = meta.Session()
390 settings_model = VcsSettingsModel(repo=repo, sa=sa)
391 settings_model = VcsSettingsModel(repo=repo, sa=sa)
391
392
392 ui_settings = settings_model.get_ui_settings()
393 ui_settings = settings_model.get_ui_settings()
393
394
394 for setting in ui_settings:
395 for setting in ui_settings:
395 if setting.active:
396 if setting.active:
396 log.debug(
397 log.debug(
397 'settings ui from db: [%s] %s=%s',
398 'settings ui from db: [%s] %s=%s',
398 setting.section, setting.key, setting.value)
399 setting.section, setting.key, setting.value)
399 config.append((
400 config.append((
400 safe_str(setting.section), safe_str(setting.key),
401 safe_str(setting.section), safe_str(setting.key),
401 safe_str(setting.value)))
402 safe_str(setting.value)))
402 if setting.key == 'push_ssl':
403 if setting.key == 'push_ssl':
403 # force set push_ssl requirement to False, rhodecode
404 # force set push_ssl requirement to False, rhodecode
404 # handles that
405 # handles that
405 config.append((
406 config.append((
406 safe_str(setting.section), safe_str(setting.key), False))
407 safe_str(setting.section), safe_str(setting.key), False))
407 if clear_session:
408 if clear_session:
408 meta.Session.remove()
409 meta.Session.remove()
409
410
410 # TODO: mikhail: probably it makes no sense to re-read hooks information.
411 # TODO: mikhail: probably it makes no sense to re-read hooks information.
411 # It's already there and activated/deactivated
412 # It's already there and activated/deactivated
412 skip_entries = []
413 skip_entries = []
413 enabled_hook_classes = get_enabled_hook_classes(ui_settings)
414 enabled_hook_classes = get_enabled_hook_classes(ui_settings)
414 if 'pull' not in enabled_hook_classes:
415 if 'pull' not in enabled_hook_classes:
415 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PULL))
416 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PULL))
416 if 'push' not in enabled_hook_classes:
417 if 'push' not in enabled_hook_classes:
417 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PUSH))
418 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PUSH))
418
419
419 config = [entry for entry in config if entry[:2] not in skip_entries]
420 config = [entry for entry in config if entry[:2] not in skip_entries]
420
421
421 return config
422 return config
422
423
423
424
424 def make_db_config(clear_session=True, repo=None):
425 def make_db_config(clear_session=True, repo=None):
425 """
426 """
426 Create a :class:`Config` instance based on the values in the database.
427 Create a :class:`Config` instance based on the values in the database.
427 """
428 """
428 config = Config()
429 config = Config()
429 config_data = config_data_from_db(clear_session=clear_session, repo=repo)
430 config_data = config_data_from_db(clear_session=clear_session, repo=repo)
430 for section, option, value in config_data:
431 for section, option, value in config_data:
431 config.set(section, option, value)
432 config.set(section, option, value)
432 return config
433 return config
433
434
434
435
435 def get_enabled_hook_classes(ui_settings):
436 def get_enabled_hook_classes(ui_settings):
436 """
437 """
437 Return the enabled hook classes.
438 Return the enabled hook classes.
438
439
439 :param ui_settings: List of ui_settings as returned
440 :param ui_settings: List of ui_settings as returned
440 by :meth:`VcsSettingsModel.get_ui_settings`
441 by :meth:`VcsSettingsModel.get_ui_settings`
441
442
442 :return: a list with the enabled hook classes. The order is not guaranteed.
443 :return: a list with the enabled hook classes. The order is not guaranteed.
443 :rtype: list
444 :rtype: list
444 """
445 """
445 enabled_hooks = []
446 enabled_hooks = []
446 active_hook_keys = [
447 active_hook_keys = [
447 key for section, key, value, active in ui_settings
448 key for section, key, value, active in ui_settings
448 if section == 'hooks' and active]
449 if section == 'hooks' and active]
449
450
450 hook_names = {
451 hook_names = {
451 RhodeCodeUi.HOOK_PUSH: 'push',
452 RhodeCodeUi.HOOK_PUSH: 'push',
452 RhodeCodeUi.HOOK_PULL: 'pull',
453 RhodeCodeUi.HOOK_PULL: 'pull',
453 RhodeCodeUi.HOOK_REPO_SIZE: 'repo_size'
454 RhodeCodeUi.HOOK_REPO_SIZE: 'repo_size'
454 }
455 }
455
456
456 for key in active_hook_keys:
457 for key in active_hook_keys:
457 hook = hook_names.get(key)
458 hook = hook_names.get(key)
458 if hook:
459 if hook:
459 enabled_hooks.append(hook)
460 enabled_hooks.append(hook)
460
461
461 return enabled_hooks
462 return enabled_hooks
462
463
463
464
464 def set_rhodecode_config(config):
465 def set_rhodecode_config(config):
465 """
466 """
466 Updates pylons config with new settings from database
467 Updates pylons config with new settings from database
467
468
468 :param config:
469 :param config:
469 """
470 """
471 from rhodecode.model.settings import SettingsModel
470 app_settings = SettingsModel().get_all_settings()
472 app_settings = SettingsModel().get_all_settings()
471
473
472 for k, v in app_settings.items():
474 for k, v in app_settings.items():
473 config[k] = v
475 config[k] = v
474
476
475
477
476 def map_groups(path):
478 def map_groups(path):
477 """
479 """
478 Given a full path to a repository, create all nested groups that this
480 Given a full path to a repository, create all nested groups that this
479 repo is inside. This function creates parent-child relationships between
481 repo is inside. This function creates parent-child relationships between
480 groups and creates default perms for all new groups.
482 groups and creates default perms for all new groups.
481
483
482 :param paths: full path to repository
484 :param paths: full path to repository
483 """
485 """
486 from rhodecode.model.repo_group import RepoGroupModel
484 sa = meta.Session()
487 sa = meta.Session()
485 groups = path.split(Repository.NAME_SEP)
488 groups = path.split(Repository.NAME_SEP)
486 parent = None
489 parent = None
487 group = None
490 group = None
488
491
489 # last element is repo in nested groups structure
492 # last element is repo in nested groups structure
490 groups = groups[:-1]
493 groups = groups[:-1]
491 rgm = RepoGroupModel(sa)
494 rgm = RepoGroupModel(sa)
492 owner = User.get_first_admin()
495 owner = User.get_first_admin()
493 for lvl, group_name in enumerate(groups):
496 for lvl, group_name in enumerate(groups):
494 group_name = '/'.join(groups[:lvl] + [group_name])
497 group_name = '/'.join(groups[:lvl] + [group_name])
495 group = RepoGroup.get_by_group_name(group_name)
498 group = RepoGroup.get_by_group_name(group_name)
496 desc = '%s group' % group_name
499 desc = '%s group' % group_name
497
500
498 # skip folders that are now removed repos
501 # skip folders that are now removed repos
499 if REMOVED_REPO_PAT.match(group_name):
502 if REMOVED_REPO_PAT.match(group_name):
500 break
503 break
501
504
502 if group is None:
505 if group is None:
503 log.debug('creating group level: %s group_name: %s',
506 log.debug('creating group level: %s group_name: %s',
504 lvl, group_name)
507 lvl, group_name)
505 group = RepoGroup(group_name, parent)
508 group = RepoGroup(group_name, parent)
506 group.group_description = desc
509 group.group_description = desc
507 group.user = owner
510 group.user = owner
508 sa.add(group)
511 sa.add(group)
509 perm_obj = rgm._create_default_perms(group)
512 perm_obj = rgm._create_default_perms(group)
510 sa.add(perm_obj)
513 sa.add(perm_obj)
511 sa.flush()
514 sa.flush()
512
515
513 parent = group
516 parent = group
514 return group
517 return group
515
518
516
519
517 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
520 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
518 """
521 """
519 maps all repos given in initial_repo_list, non existing repositories
522 maps all repos given in initial_repo_list, non existing repositories
520 are created, if remove_obsolete is True it also checks for db entries
523 are created, if remove_obsolete is True it also checks for db entries
521 that are not in initial_repo_list and removes them.
524 that are not in initial_repo_list and removes them.
522
525
523 :param initial_repo_list: list of repositories found by scanning methods
526 :param initial_repo_list: list of repositories found by scanning methods
524 :param remove_obsolete: check for obsolete entries in database
527 :param remove_obsolete: check for obsolete entries in database
525 """
528 """
526 from rhodecode.model.repo import RepoModel
529 from rhodecode.model.repo import RepoModel
527 from rhodecode.model.scm import ScmModel
530 from rhodecode.model.scm import ScmModel
531 from rhodecode.model.repo_group import RepoGroupModel
532 from rhodecode.model.settings import SettingsModel
533
528 sa = meta.Session()
534 sa = meta.Session()
529 repo_model = RepoModel()
535 repo_model = RepoModel()
530 user = User.get_first_admin()
536 user = User.get_first_admin()
531 added = []
537 added = []
532
538
533 # creation defaults
539 # creation defaults
534 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
540 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
535 enable_statistics = defs.get('repo_enable_statistics')
541 enable_statistics = defs.get('repo_enable_statistics')
536 enable_locking = defs.get('repo_enable_locking')
542 enable_locking = defs.get('repo_enable_locking')
537 enable_downloads = defs.get('repo_enable_downloads')
543 enable_downloads = defs.get('repo_enable_downloads')
538 private = defs.get('repo_private')
544 private = defs.get('repo_private')
539
545
540 for name, repo in initial_repo_list.items():
546 for name, repo in initial_repo_list.items():
541 group = map_groups(name)
547 group = map_groups(name)
542 unicode_name = safe_unicode(name)
548 unicode_name = safe_unicode(name)
543 db_repo = repo_model.get_by_repo_name(unicode_name)
549 db_repo = repo_model.get_by_repo_name(unicode_name)
544 # found repo that is on filesystem not in RhodeCode database
550 # found repo that is on filesystem not in RhodeCode database
545 if not db_repo:
551 if not db_repo:
546 log.info('repository %s not found, creating now', name)
552 log.info('repository %s not found, creating now', name)
547 added.append(name)
553 added.append(name)
548 desc = (repo.description
554 desc = (repo.description
549 if repo.description != 'unknown'
555 if repo.description != 'unknown'
550 else '%s repository' % name)
556 else '%s repository' % name)
551
557
552 db_repo = repo_model._create_repo(
558 db_repo = repo_model._create_repo(
553 repo_name=name,
559 repo_name=name,
554 repo_type=repo.alias,
560 repo_type=repo.alias,
555 description=desc,
561 description=desc,
556 repo_group=getattr(group, 'group_id', None),
562 repo_group=getattr(group, 'group_id', None),
557 owner=user,
563 owner=user,
558 enable_locking=enable_locking,
564 enable_locking=enable_locking,
559 enable_downloads=enable_downloads,
565 enable_downloads=enable_downloads,
560 enable_statistics=enable_statistics,
566 enable_statistics=enable_statistics,
561 private=private,
567 private=private,
562 state=Repository.STATE_CREATED
568 state=Repository.STATE_CREATED
563 )
569 )
564 sa.commit()
570 sa.commit()
565 # we added that repo just now, and make sure we updated server info
571 # we added that repo just now, and make sure we updated server info
566 if db_repo.repo_type == 'git':
572 if db_repo.repo_type == 'git':
567 git_repo = db_repo.scm_instance()
573 git_repo = db_repo.scm_instance()
568 # update repository server-info
574 # update repository server-info
569 log.debug('Running update server info')
575 log.debug('Running update server info')
570 git_repo._update_server_info()
576 git_repo._update_server_info()
571
577
572 db_repo.update_commit_cache()
578 db_repo.update_commit_cache()
573
579
574 config = db_repo._config
580 config = db_repo._config
575 config.set('extensions', 'largefiles', '')
581 config.set('extensions', 'largefiles', '')
576 ScmModel().install_hooks(
582 ScmModel().install_hooks(
577 db_repo.scm_instance(config=config),
583 db_repo.scm_instance(config=config),
578 repo_type=db_repo.repo_type)
584 repo_type=db_repo.repo_type)
579
585
580 removed = []
586 removed = []
581 if remove_obsolete:
587 if remove_obsolete:
582 # remove from database those repositories that are not in the filesystem
588 # remove from database those repositories that are not in the filesystem
583 for repo in sa.query(Repository).all():
589 for repo in sa.query(Repository).all():
584 if repo.repo_name not in initial_repo_list.keys():
590 if repo.repo_name not in initial_repo_list.keys():
585 log.debug("Removing non-existing repository found in db `%s`",
591 log.debug("Removing non-existing repository found in db `%s`",
586 repo.repo_name)
592 repo.repo_name)
587 try:
593 try:
588 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
594 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
589 sa.commit()
595 sa.commit()
590 removed.append(repo.repo_name)
596 removed.append(repo.repo_name)
591 except Exception:
597 except Exception:
592 # don't hold further removals on error
598 # don't hold further removals on error
593 log.error(traceback.format_exc())
599 log.error(traceback.format_exc())
594 sa.rollback()
600 sa.rollback()
595
601
596 def splitter(full_repo_name):
602 def splitter(full_repo_name):
597 _parts = full_repo_name.rsplit(RepoGroup.url_sep(), 1)
603 _parts = full_repo_name.rsplit(RepoGroup.url_sep(), 1)
598 gr_name = None
604 gr_name = None
599 if len(_parts) == 2:
605 if len(_parts) == 2:
600 gr_name = _parts[0]
606 gr_name = _parts[0]
601 return gr_name
607 return gr_name
602
608
603 initial_repo_group_list = [splitter(x) for x in
609 initial_repo_group_list = [splitter(x) for x in
604 initial_repo_list.keys() if splitter(x)]
610 initial_repo_list.keys() if splitter(x)]
605
611
606 # remove from database those repository groups that are not in the
612 # remove from database those repository groups that are not in the
607 # filesystem due to parent child relationships we need to delete them
613 # filesystem due to parent child relationships we need to delete them
608 # in a specific order of most nested first
614 # in a specific order of most nested first
609 all_groups = [x.group_name for x in sa.query(RepoGroup).all()]
615 all_groups = [x.group_name for x in sa.query(RepoGroup).all()]
610 nested_sort = lambda gr: len(gr.split('/'))
616 nested_sort = lambda gr: len(gr.split('/'))
611 for group_name in sorted(all_groups, key=nested_sort, reverse=True):
617 for group_name in sorted(all_groups, key=nested_sort, reverse=True):
612 if group_name not in initial_repo_group_list:
618 if group_name not in initial_repo_group_list:
613 repo_group = RepoGroup.get_by_group_name(group_name)
619 repo_group = RepoGroup.get_by_group_name(group_name)
614 if (repo_group.children.all() or
620 if (repo_group.children.all() or
615 not RepoGroupModel().check_exist_filesystem(
621 not RepoGroupModel().check_exist_filesystem(
616 group_name=group_name, exc_on_failure=False)):
622 group_name=group_name, exc_on_failure=False)):
617 continue
623 continue
618
624
619 log.info(
625 log.info(
620 'Removing non-existing repository group found in db `%s`',
626 'Removing non-existing repository group found in db `%s`',
621 group_name)
627 group_name)
622 try:
628 try:
623 RepoGroupModel(sa).delete(group_name, fs_remove=False)
629 RepoGroupModel(sa).delete(group_name, fs_remove=False)
624 sa.commit()
630 sa.commit()
625 removed.append(group_name)
631 removed.append(group_name)
626 except Exception:
632 except Exception:
627 # don't hold further removals on error
633 # don't hold further removals on error
628 log.exception(
634 log.exception(
629 'Unable to remove repository group `%s`',
635 'Unable to remove repository group `%s`',
630 group_name)
636 group_name)
631 sa.rollback()
637 sa.rollback()
632 raise
638 raise
633
639
634 return added, removed
640 return added, removed
635
641
636
642
637 def get_default_cache_settings(settings):
643 def get_default_cache_settings(settings):
638 cache_settings = {}
644 cache_settings = {}
639 for key in settings.keys():
645 for key in settings.keys():
640 for prefix in ['beaker.cache.', 'cache.']:
646 for prefix in ['beaker.cache.', 'cache.']:
641 if key.startswith(prefix):
647 if key.startswith(prefix):
642 name = key.split(prefix)[1].strip()
648 name = key.split(prefix)[1].strip()
643 cache_settings[name] = settings[key].strip()
649 cache_settings[name] = settings[key].strip()
644 return cache_settings
650 return cache_settings
645
651
646
652
647 # set cache regions for beaker so celery can utilise it
653 # set cache regions for beaker so celery can utilise it
648 def add_cache(settings):
654 def add_cache(settings):
649 from rhodecode.lib import caches
655 from rhodecode.lib import caches
650 cache_settings = {'regions': None}
656 cache_settings = {'regions': None}
651 # main cache settings used as default ...
657 # main cache settings used as default ...
652 cache_settings.update(get_default_cache_settings(settings))
658 cache_settings.update(get_default_cache_settings(settings))
653
659
654 if cache_settings['regions']:
660 if cache_settings['regions']:
655 for region in cache_settings['regions'].split(','):
661 for region in cache_settings['regions'].split(','):
656 region = region.strip()
662 region = region.strip()
657 region_settings = {}
663 region_settings = {}
658 for key, value in cache_settings.items():
664 for key, value in cache_settings.items():
659 if key.startswith(region):
665 if key.startswith(region):
660 region_settings[key.split('.')[1]] = value
666 region_settings[key.split('.')[1]] = value
661
667
662 caches.configure_cache_region(
668 caches.configure_cache_region(
663 region, region_settings, cache_settings)
669 region, region_settings, cache_settings)
664
670
665
671
666 def load_rcextensions(root_path):
672 def load_rcextensions(root_path):
667 import rhodecode
673 import rhodecode
668 from rhodecode.config import conf
674 from rhodecode.config import conf
669
675
670 path = os.path.join(root_path, 'rcextensions', '__init__.py')
676 path = os.path.join(root_path, 'rcextensions', '__init__.py')
671 if os.path.isfile(path):
677 if os.path.isfile(path):
672 rcext = create_module('rc', path)
678 rcext = create_module('rc', path)
673 EXT = rhodecode.EXTENSIONS = rcext
679 EXT = rhodecode.EXTENSIONS = rcext
674 log.debug('Found rcextensions now loading %s...', rcext)
680 log.debug('Found rcextensions now loading %s...', rcext)
675
681
676 # Additional mappings that are not present in the pygments lexers
682 # Additional mappings that are not present in the pygments lexers
677 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
683 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
678
684
679 # auto check if the module is not missing any data, set to default if is
685 # auto check if the module is not missing any data, set to default if is
680 # this will help autoupdate new feature of rcext module
686 # this will help autoupdate new feature of rcext module
681 #from rhodecode.config import rcextensions
687 #from rhodecode.config import rcextensions
682 #for k in dir(rcextensions):
688 #for k in dir(rcextensions):
683 # if not k.startswith('_') and not hasattr(EXT, k):
689 # if not k.startswith('_') and not hasattr(EXT, k):
684 # setattr(EXT, k, getattr(rcextensions, k))
690 # setattr(EXT, k, getattr(rcextensions, k))
685
691
686
692
687 def get_custom_lexer(extension):
693 def get_custom_lexer(extension):
688 """
694 """
689 returns a custom lexer if it is defined in rcextensions module, or None
695 returns a custom lexer if it is defined in rcextensions module, or None
690 if there's no custom lexer defined
696 if there's no custom lexer defined
691 """
697 """
692 import rhodecode
698 import rhodecode
693 from pygments import lexers
699 from pygments import lexers
694 # check if we didn't define this extension as other lexer
700 # check if we didn't define this extension as other lexer
695 extensions = rhodecode.EXTENSIONS and getattr(rhodecode.EXTENSIONS, 'EXTRA_LEXERS', None)
701 extensions = rhodecode.EXTENSIONS and getattr(rhodecode.EXTENSIONS, 'EXTRA_LEXERS', None)
696 if extensions and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
702 if extensions and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
697 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
703 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
698 return lexers.get_lexer_by_name(_lexer_name)
704 return lexers.get_lexer_by_name(_lexer_name)
699
705
700
706
701 #==============================================================================
707 #==============================================================================
702 # TEST FUNCTIONS AND CREATORS
708 # TEST FUNCTIONS AND CREATORS
703 #==============================================================================
709 #==============================================================================
704 def create_test_index(repo_location, config):
710 def create_test_index(repo_location, config):
705 """
711 """
706 Makes default test index.
712 Makes default test index.
707 """
713 """
708 import rc_testdata
714 import rc_testdata
709
715
710 rc_testdata.extract_search_index(
716 rc_testdata.extract_search_index(
711 'vcs_search_index', os.path.dirname(config['search.location']))
717 'vcs_search_index', os.path.dirname(config['search.location']))
712
718
713
719
714 def create_test_directory(test_path):
720 def create_test_directory(test_path):
715 """
721 """
716 Create test directory if it doesn't exist.
722 Create test directory if it doesn't exist.
717 """
723 """
718 if not os.path.isdir(test_path):
724 if not os.path.isdir(test_path):
719 log.debug('Creating testdir %s', test_path)
725 log.debug('Creating testdir %s', test_path)
720 os.makedirs(test_path)
726 os.makedirs(test_path)
721
727
722
728
723 def create_test_database(test_path, config):
729 def create_test_database(test_path, config):
724 """
730 """
725 Makes a fresh database.
731 Makes a fresh database.
726 """
732 """
727 from rhodecode.lib.db_manage import DbManage
733 from rhodecode.lib.db_manage import DbManage
728
734
729 # PART ONE create db
735 # PART ONE create db
730 dbconf = config['sqlalchemy.db1.url']
736 dbconf = config['sqlalchemy.db1.url']
731 log.debug('making test db %s', dbconf)
737 log.debug('making test db %s', dbconf)
732
738
733 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
739 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
734 tests=True, cli_args={'force_ask': True})
740 tests=True, cli_args={'force_ask': True})
735 dbmanage.create_tables(override=True)
741 dbmanage.create_tables(override=True)
736 dbmanage.set_db_version()
742 dbmanage.set_db_version()
737 # for tests dynamically set new root paths based on generated content
743 # for tests dynamically set new root paths based on generated content
738 dbmanage.create_settings(dbmanage.config_prompt(test_path))
744 dbmanage.create_settings(dbmanage.config_prompt(test_path))
739 dbmanage.create_default_user()
745 dbmanage.create_default_user()
740 dbmanage.create_test_admin_and_users()
746 dbmanage.create_test_admin_and_users()
741 dbmanage.create_permissions()
747 dbmanage.create_permissions()
742 dbmanage.populate_default_permissions()
748 dbmanage.populate_default_permissions()
743 Session().commit()
749 Session().commit()
744
750
745
751
746 def create_test_repositories(test_path, config):
752 def create_test_repositories(test_path, config):
747 """
753 """
748 Creates test repositories in the temporary directory. Repositories are
754 Creates test repositories in the temporary directory. Repositories are
749 extracted from archives within the rc_testdata package.
755 extracted from archives within the rc_testdata package.
750 """
756 """
751 import rc_testdata
757 import rc_testdata
752 from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO
758 from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO
753
759
754 log.debug('making test vcs repositories')
760 log.debug('making test vcs repositories')
755
761
756 idx_path = config['search.location']
762 idx_path = config['search.location']
757 data_path = config['cache_dir']
763 data_path = config['cache_dir']
758
764
759 # clean index and data
765 # clean index and data
760 if idx_path and os.path.exists(idx_path):
766 if idx_path and os.path.exists(idx_path):
761 log.debug('remove %s', idx_path)
767 log.debug('remove %s', idx_path)
762 shutil.rmtree(idx_path)
768 shutil.rmtree(idx_path)
763
769
764 if data_path and os.path.exists(data_path):
770 if data_path and os.path.exists(data_path):
765 log.debug('remove %s', data_path)
771 log.debug('remove %s', data_path)
766 shutil.rmtree(data_path)
772 shutil.rmtree(data_path)
767
773
768 rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO))
774 rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO))
769 rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO))
775 rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO))
770
776
771 # Note: Subversion is in the process of being integrated with the system,
777 # Note: Subversion is in the process of being integrated with the system,
772 # until we have a properly packed version of the test svn repository, this
778 # until we have a properly packed version of the test svn repository, this
773 # tries to copy over the repo from a package "rc_testdata"
779 # tries to copy over the repo from a package "rc_testdata"
774 svn_repo_path = rc_testdata.get_svn_repo_archive()
780 svn_repo_path = rc_testdata.get_svn_repo_archive()
775 with tarfile.open(svn_repo_path) as tar:
781 with tarfile.open(svn_repo_path) as tar:
776 tar.extractall(jn(test_path, SVN_REPO))
782 tar.extractall(jn(test_path, SVN_REPO))
777
783
778
784
779 #==============================================================================
785 #==============================================================================
780 # PASTER COMMANDS
786 # PASTER COMMANDS
781 #==============================================================================
787 #==============================================================================
782 class BasePasterCommand(Command):
788 class BasePasterCommand(Command):
783 """
789 """
784 Abstract Base Class for paster commands.
790 Abstract Base Class for paster commands.
785
791
786 The celery commands are somewhat aggressive about loading
792 The celery commands are somewhat aggressive about loading
787 celery.conf, and since our module sets the `CELERY_LOADER`
793 celery.conf, and since our module sets the `CELERY_LOADER`
788 environment variable to our loader, we have to bootstrap a bit and
794 environment variable to our loader, we have to bootstrap a bit and
789 make sure we've had a chance to load the pylons config off of the
795 make sure we've had a chance to load the pylons config off of the
790 command line, otherwise everything fails.
796 command line, otherwise everything fails.
791 """
797 """
792 min_args = 1
798 min_args = 1
793 min_args_error = "Please provide a paster config file as an argument."
799 min_args_error = "Please provide a paster config file as an argument."
794 takes_config_file = 1
800 takes_config_file = 1
795 requires_config_file = True
801 requires_config_file = True
796
802
797 def notify_msg(self, msg, log=False):
803 def notify_msg(self, msg, log=False):
798 """Make a notification to user, additionally if logger is passed
804 """Make a notification to user, additionally if logger is passed
799 it logs this action using given logger
805 it logs this action using given logger
800
806
801 :param msg: message that will be printed to user
807 :param msg: message that will be printed to user
802 :param log: logging instance, to use to additionally log this message
808 :param log: logging instance, to use to additionally log this message
803
809
804 """
810 """
805 if log and isinstance(log, logging):
811 if log and isinstance(log, logging):
806 log(msg)
812 log(msg)
807
813
808 def run(self, args):
814 def run(self, args):
809 """
815 """
810 Overrides Command.run
816 Overrides Command.run
811
817
812 Checks for a config file argument and loads it.
818 Checks for a config file argument and loads it.
813 """
819 """
814 if len(args) < self.min_args:
820 if len(args) < self.min_args:
815 raise BadCommand(
821 raise BadCommand(
816 self.min_args_error % {'min_args': self.min_args,
822 self.min_args_error % {'min_args': self.min_args,
817 'actual_args': len(args)})
823 'actual_args': len(args)})
818
824
819 # Decrement because we're going to lob off the first argument.
825 # Decrement because we're going to lob off the first argument.
820 # @@ This is hacky
826 # @@ This is hacky
821 self.min_args -= 1
827 self.min_args -= 1
822 self.bootstrap_config(args[0])
828 self.bootstrap_config(args[0])
823 self.update_parser()
829 self.update_parser()
824 return super(BasePasterCommand, self).run(args[1:])
830 return super(BasePasterCommand, self).run(args[1:])
825
831
826 def update_parser(self):
832 def update_parser(self):
827 """
833 """
828 Abstract method. Allows for the class' parser to be updated
834 Abstract method. Allows for the class' parser to be updated
829 before the superclass' `run` method is called. Necessary to
835 before the superclass' `run` method is called. Necessary to
830 allow options/arguments to be passed through to the underlying
836 allow options/arguments to be passed through to the underlying
831 celery command.
837 celery command.
832 """
838 """
833 raise NotImplementedError("Abstract Method.")
839 raise NotImplementedError("Abstract Method.")
834
840
835 def bootstrap_config(self, conf):
841 def bootstrap_config(self, conf):
836 """
842 """
837 Loads the pylons configuration.
843 Loads the pylons configuration.
838 """
844 """
839 from pylons import config as pylonsconfig
845 from pylons import config as pylonsconfig
840
846
841 self.path_to_ini_file = os.path.realpath(conf)
847 self.path_to_ini_file = os.path.realpath(conf)
842 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
848 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
843 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
849 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
844
850
845 def _init_session(self):
851 def _init_session(self):
846 """
852 """
847 Inits SqlAlchemy Session
853 Inits SqlAlchemy Session
848 """
854 """
849 logging.config.fileConfig(self.path_to_ini_file)
855 logging.config.fileConfig(self.path_to_ini_file)
850 from pylons import config
856 from pylons import config
851 from rhodecode.config.utils import initialize_database
857 from rhodecode.config.utils import initialize_database
852
858
853 # get to remove repos !!
859 # get to remove repos !!
854 add_cache(config)
860 add_cache(config)
855 initialize_database(config)
861 initialize_database(config)
856
862
857
863
858 @decorator.decorator
864 @decorator.decorator
859 def jsonify(func, *args, **kwargs):
865 def jsonify(func, *args, **kwargs):
860 """Action decorator that formats output for JSON
866 """Action decorator that formats output for JSON
861
867
862 Given a function that will return content, this decorator will turn
868 Given a function that will return content, this decorator will turn
863 the result into JSON, with a content-type of 'application/json' and
869 the result into JSON, with a content-type of 'application/json' and
864 output it.
870 output it.
865
871
866 """
872 """
867 from pylons.decorators.util import get_pylons
873 from pylons.decorators.util import get_pylons
868 from rhodecode.lib.ext_json import json
874 from rhodecode.lib.ext_json import json
869 pylons = get_pylons(args)
875 pylons = get_pylons(args)
870 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
876 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
871 data = func(*args, **kwargs)
877 data = func(*args, **kwargs)
872 if isinstance(data, (list, tuple)):
878 if isinstance(data, (list, tuple)):
873 msg = "JSON responses with Array envelopes are susceptible to " \
879 msg = "JSON responses with Array envelopes are susceptible to " \
874 "cross-site data leak attacks, see " \
880 "cross-site data leak attacks, see " \
875 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
881 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
876 warnings.warn(msg, Warning, 2)
882 warnings.warn(msg, Warning, 2)
877 log.warning(msg)
883 log.warning(msg)
878 log.debug("Returning JSON wrapped action output")
884 log.debug("Returning JSON wrapped action output")
879 return json.dumps(data, encoding='utf-8')
885 return json.dumps(data, encoding='utf-8')
880
886
881
887
882 class PartialRenderer(object):
888 class PartialRenderer(object):
883 """
889 """
884 Partial renderer used to render chunks of html used in datagrids
890 Partial renderer used to render chunks of html used in datagrids
885 use like::
891 use like::
886
892
887 _render = PartialRenderer('data_table/_dt_elements.html')
893 _render = PartialRenderer('data_table/_dt_elements.html')
888 _render('quick_menu', args, kwargs)
894 _render('quick_menu', args, kwargs)
889 PartialRenderer.h,
895 PartialRenderer.h,
890 c,
896 c,
891 _,
897 _,
892 ungettext
898 ungettext
893 are the template stuff initialized inside and can be re-used later
899 are the template stuff initialized inside and can be re-used later
894
900
895 :param tmpl_name: template path relate to /templates/ dir
901 :param tmpl_name: template path relate to /templates/ dir
896 """
902 """
897
903
898 def __init__(self, tmpl_name):
904 def __init__(self, tmpl_name):
899 import rhodecode
905 import rhodecode
900 from pylons import request, tmpl_context as c
906 from pylons import request, tmpl_context as c
901 from pylons.i18n.translation import _, ungettext
907 from pylons.i18n.translation import _, ungettext
902 from rhodecode.lib import helpers as h
908 from rhodecode.lib import helpers as h
903
909
904 self.tmpl_name = tmpl_name
910 self.tmpl_name = tmpl_name
905 self.rhodecode = rhodecode
911 self.rhodecode = rhodecode
906 self.c = c
912 self.c = c
907 self._ = _
913 self._ = _
908 self.ungettext = ungettext
914 self.ungettext = ungettext
909 self.h = h
915 self.h = h
910 self.request = request
916 self.request = request
911
917
912 def _mako_lookup(self):
918 def _mako_lookup(self):
913 _tmpl_lookup = self.rhodecode.CONFIG['pylons.app_globals'].mako_lookup
919 _tmpl_lookup = self.rhodecode.CONFIG['pylons.app_globals'].mako_lookup
914 return _tmpl_lookup.get_template(self.tmpl_name)
920 return _tmpl_lookup.get_template(self.tmpl_name)
915
921
916 def _update_kwargs_for_render(self, kwargs):
922 def _update_kwargs_for_render(self, kwargs):
917 """
923 """
918 Inject params required for Mako rendering
924 Inject params required for Mako rendering
919 """
925 """
920 _kwargs = {
926 _kwargs = {
921 '_': self._,
927 '_': self._,
922 'h': self.h,
928 'h': self.h,
923 'c': self.c,
929 'c': self.c,
924 'request': self.request,
930 'request': self.request,
925 'ungettext': self.ungettext,
931 'ungettext': self.ungettext,
926 }
932 }
927 _kwargs.update(kwargs)
933 _kwargs.update(kwargs)
928 return _kwargs
934 return _kwargs
929
935
930 def _render_with_exc(self, render_func, args, kwargs):
936 def _render_with_exc(self, render_func, args, kwargs):
931 try:
937 try:
932 return render_func.render(*args, **kwargs)
938 return render_func.render(*args, **kwargs)
933 except:
939 except:
934 log.error(exceptions.text_error_template().render())
940 log.error(exceptions.text_error_template().render())
935 raise
941 raise
936
942
937 def _get_template(self, template_obj, def_name):
943 def _get_template(self, template_obj, def_name):
938 if def_name:
944 if def_name:
939 tmpl = template_obj.get_def(def_name)
945 tmpl = template_obj.get_def(def_name)
940 else:
946 else:
941 tmpl = template_obj
947 tmpl = template_obj
942 return tmpl
948 return tmpl
943
949
944 def render(self, def_name, *args, **kwargs):
950 def render(self, def_name, *args, **kwargs):
945 lookup_obj = self._mako_lookup()
951 lookup_obj = self._mako_lookup()
946 tmpl = self._get_template(lookup_obj, def_name=def_name)
952 tmpl = self._get_template(lookup_obj, def_name=def_name)
947 kwargs = self._update_kwargs_for_render(kwargs)
953 kwargs = self._update_kwargs_for_render(kwargs)
948 return self._render_with_exc(tmpl, args, kwargs)
954 return self._render_with_exc(tmpl, args, kwargs)
949
955
950 def __call__(self, tmpl, *args, **kwargs):
956 def __call__(self, tmpl, *args, **kwargs):
951 return self.render(tmpl, *args, **kwargs)
957 return self.render(tmpl, *args, **kwargs)
952
958
953
959
954 def password_changed(auth_user, session):
960 def password_changed(auth_user, session):
955 if auth_user.username == User.DEFAULT_USER:
961 if auth_user.username == User.DEFAULT_USER:
956 return False
962 return False
957 password_hash = md5(auth_user.password) if auth_user.password else None
963 password_hash = md5(auth_user.password) if auth_user.password else None
958 rhodecode_user = session.get('rhodecode_user', {})
964 rhodecode_user = session.get('rhodecode_user', {})
959 session_password_hash = rhodecode_user.get('password', '')
965 session_password_hash = rhodecode_user.get('password', '')
960 return password_hash != session_password_hash
966 return password_hash != session_password_hash
961
967
962
968
963 def read_opensource_licenses():
969 def read_opensource_licenses():
964 global _license_cache
970 global _license_cache
965
971
966 if not _license_cache:
972 if not _license_cache:
967 licenses = pkg_resources.resource_string(
973 licenses = pkg_resources.resource_string(
968 'rhodecode', 'config/licenses.json')
974 'rhodecode', 'config/licenses.json')
969 _license_cache = json.loads(licenses)
975 _license_cache = json.loads(licenses)
970
976
971 return _license_cache
977 return _license_cache
General Comments 0
You need to be logged in to leave comments. Login now