##// END OF EJS Templates
fixed UnicodeWarning on pushing from sqlalchemy
marcink -
r2249:a3eb31cc beta
parent child Browse files
Show More
@@ -1,666 +1,666 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Utilities library for RhodeCode
6 Utilities library for RhodeCode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import re
27 import re
28 import logging
28 import logging
29 import datetime
29 import datetime
30 import traceback
30 import traceback
31 import paste
31 import paste
32 import beaker
32 import beaker
33 import tarfile
33 import tarfile
34 import shutil
34 import shutil
35 from os.path import abspath
35 from os.path import abspath
36 from os.path import dirname as dn, join as jn
36 from os.path import dirname as dn, join as jn
37
37
38 from paste.script.command import Command, BadCommand
38 from paste.script.command import Command, BadCommand
39
39
40 from mercurial import ui, config
40 from mercurial import ui, config
41
41
42 from webhelpers.text import collapse, remove_formatting, strip_tags
42 from webhelpers.text import collapse, remove_formatting, strip_tags
43
43
44 from rhodecode.lib.vcs import get_backend
44 from rhodecode.lib.vcs import get_backend
45 from rhodecode.lib.vcs.backends.base import BaseChangeset
45 from rhodecode.lib.vcs.backends.base import BaseChangeset
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 from rhodecode.lib.vcs.utils.helpers import get_scm
47 from rhodecode.lib.vcs.utils.helpers import get_scm
48 from rhodecode.lib.vcs.exceptions import VCSError
48 from rhodecode.lib.vcs.exceptions import VCSError
49
49
50 from rhodecode.lib.caching_query import FromCache
50 from rhodecode.lib.caching_query import FromCache
51
51
52 from rhodecode.model import meta
52 from rhodecode.model import meta
53 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
53 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
54 UserLog, RepoGroup, RhodeCodeSetting, UserRepoGroupToPerm,\
54 UserLog, RepoGroup, RhodeCodeSetting, UserRepoGroupToPerm,\
55 CacheInvalidation
55 CacheInvalidation
56 from rhodecode.model.meta import Session
56 from rhodecode.model.meta import Session
57 from rhodecode.model.repos_group import ReposGroupModel
57 from rhodecode.model.repos_group import ReposGroupModel
58 from rhodecode.lib.utils2 import safe_str, safe_unicode
58 from rhodecode.lib.utils2 import safe_str, safe_unicode
59 from rhodecode.lib.vcs.utils.fakemod import create_module
59 from rhodecode.lib.vcs.utils.fakemod import create_module
60
60
61 log = logging.getLogger(__name__)
61 log = logging.getLogger(__name__)
62
62
63 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
63 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
64
64
65
65
66 def recursive_replace(str_, replace=' '):
66 def recursive_replace(str_, replace=' '):
67 """
67 """
68 Recursive replace of given sign to just one instance
68 Recursive replace of given sign to just one instance
69
69
70 :param str_: given string
70 :param str_: given string
71 :param replace: char to find and replace multiple instances
71 :param replace: char to find and replace multiple instances
72
72
73 Examples::
73 Examples::
74 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
74 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
75 'Mighty-Mighty-Bo-sstones'
75 'Mighty-Mighty-Bo-sstones'
76 """
76 """
77
77
78 if str_.find(replace * 2) == -1:
78 if str_.find(replace * 2) == -1:
79 return str_
79 return str_
80 else:
80 else:
81 str_ = str_.replace(replace * 2, replace)
81 str_ = str_.replace(replace * 2, replace)
82 return recursive_replace(str_, replace)
82 return recursive_replace(str_, replace)
83
83
84
84
85 def repo_name_slug(value):
85 def repo_name_slug(value):
86 """
86 """
87 Return slug of name of repository
87 Return slug of name of repository
88 This function is called on each creation/modification
88 This function is called on each creation/modification
89 of repository to prevent bad names in repo
89 of repository to prevent bad names in repo
90 """
90 """
91
91
92 slug = remove_formatting(value)
92 slug = remove_formatting(value)
93 slug = strip_tags(slug)
93 slug = strip_tags(slug)
94
94
95 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
95 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
96 slug = slug.replace(c, '-')
96 slug = slug.replace(c, '-')
97 slug = recursive_replace(slug, '-')
97 slug = recursive_replace(slug, '-')
98 slug = collapse(slug, '-')
98 slug = collapse(slug, '-')
99 return slug
99 return slug
100
100
101
101
102 def get_repo_slug(request):
102 def get_repo_slug(request):
103 _repo = request.environ['pylons.routes_dict'].get('repo_name')
103 _repo = request.environ['pylons.routes_dict'].get('repo_name')
104 if _repo:
104 if _repo:
105 _repo = _repo.rstrip('/')
105 _repo = _repo.rstrip('/')
106 return _repo
106 return _repo
107
107
108
108
109 def get_repos_group_slug(request):
109 def get_repos_group_slug(request):
110 _group = request.environ['pylons.routes_dict'].get('group_name')
110 _group = request.environ['pylons.routes_dict'].get('group_name')
111 if _group:
111 if _group:
112 _group = _group.rstrip('/')
112 _group = _group.rstrip('/')
113 return _group
113 return _group
114
114
115
115
116 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
116 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
117 """
117 """
118 Action logger for various actions made by users
118 Action logger for various actions made by users
119
119
120 :param user: user that made this action, can be a unique username string or
120 :param user: user that made this action, can be a unique username string or
121 object containing user_id attribute
121 object containing user_id attribute
122 :param action: action to log, should be on of predefined unique actions for
122 :param action: action to log, should be on of predefined unique actions for
123 easy translations
123 easy translations
124 :param repo: string name of repository or object containing repo_id,
124 :param repo: string name of repository or object containing repo_id,
125 that action was made on
125 that action was made on
126 :param ipaddr: optional ip address from what the action was made
126 :param ipaddr: optional ip address from what the action was made
127 :param sa: optional sqlalchemy session
127 :param sa: optional sqlalchemy session
128
128
129 """
129 """
130
130
131 if not sa:
131 if not sa:
132 sa = meta.Session
132 sa = meta.Session
133
133
134 try:
134 try:
135 if hasattr(user, 'user_id'):
135 if hasattr(user, 'user_id'):
136 user_obj = user
136 user_obj = user
137 elif isinstance(user, basestring):
137 elif isinstance(user, basestring):
138 user_obj = User.get_by_username(user)
138 user_obj = User.get_by_username(user)
139 else:
139 else:
140 raise Exception('You have to provide user object or username')
140 raise Exception('You have to provide user object or username')
141
141
142 if hasattr(repo, 'repo_id'):
142 if hasattr(repo, 'repo_id'):
143 repo_obj = Repository.get(repo.repo_id)
143 repo_obj = Repository.get(repo.repo_id)
144 repo_name = repo_obj.repo_name
144 repo_name = repo_obj.repo_name
145 elif isinstance(repo, basestring):
145 elif isinstance(repo, basestring):
146 repo_name = repo.lstrip('/')
146 repo_name = repo.lstrip('/')
147 repo_obj = Repository.get_by_repo_name(repo_name)
147 repo_obj = Repository.get_by_repo_name(repo_name)
148 else:
148 else:
149 raise Exception('You have to provide repository to action logger')
149 raise Exception('You have to provide repository to action logger')
150
150
151 user_log = UserLog()
151 user_log = UserLog()
152 user_log.user_id = user_obj.user_id
152 user_log.user_id = user_obj.user_id
153 user_log.action = action
153 user_log.action = safe_unicode(action)
154
154
155 user_log.repository_id = repo_obj.repo_id
155 user_log.repository_id = repo_obj.repo_id
156 user_log.repository_name = repo_name
156 user_log.repository_name = repo_name
157
157
158 user_log.action_date = datetime.datetime.now()
158 user_log.action_date = datetime.datetime.now()
159 user_log.user_ip = ipaddr
159 user_log.user_ip = ipaddr
160 sa.add(user_log)
160 sa.add(user_log)
161
161
162 log.info(
162 log.info(
163 'Adding user %s, action %s on %s' % (user_obj, action,
163 'Adding user %s, action %s on %s' % (user_obj, action,
164 safe_unicode(repo))
164 safe_unicode(repo))
165 )
165 )
166 if commit:
166 if commit:
167 sa.commit()
167 sa.commit()
168 except:
168 except:
169 log.error(traceback.format_exc())
169 log.error(traceback.format_exc())
170 raise
170 raise
171
171
172
172
173 def get_repos(path, recursive=False):
173 def get_repos(path, recursive=False):
174 """
174 """
175 Scans given path for repos and return (name,(type,path)) tuple
175 Scans given path for repos and return (name,(type,path)) tuple
176
176
177 :param path: path to scan for repositories
177 :param path: path to scan for repositories
178 :param recursive: recursive search and return names with subdirs in front
178 :param recursive: recursive search and return names with subdirs in front
179 """
179 """
180
180
181 # remove ending slash for better results
181 # remove ending slash for better results
182 path = path.rstrip(os.sep)
182 path = path.rstrip(os.sep)
183
183
184 def _get_repos(p):
184 def _get_repos(p):
185 if not os.access(p, os.W_OK):
185 if not os.access(p, os.W_OK):
186 return
186 return
187 for dirpath in os.listdir(p):
187 for dirpath in os.listdir(p):
188 if os.path.isfile(os.path.join(p, dirpath)):
188 if os.path.isfile(os.path.join(p, dirpath)):
189 continue
189 continue
190 cur_path = os.path.join(p, dirpath)
190 cur_path = os.path.join(p, dirpath)
191 try:
191 try:
192 scm_info = get_scm(cur_path)
192 scm_info = get_scm(cur_path)
193 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
193 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
194 except VCSError:
194 except VCSError:
195 if not recursive:
195 if not recursive:
196 continue
196 continue
197 #check if this dir containts other repos for recursive scan
197 #check if this dir containts other repos for recursive scan
198 rec_path = os.path.join(p, dirpath)
198 rec_path = os.path.join(p, dirpath)
199 if os.path.isdir(rec_path):
199 if os.path.isdir(rec_path):
200 for inner_scm in _get_repos(rec_path):
200 for inner_scm in _get_repos(rec_path):
201 yield inner_scm
201 yield inner_scm
202
202
203 return _get_repos(path)
203 return _get_repos(path)
204
204
205
205
206 def is_valid_repo(repo_name, base_path):
206 def is_valid_repo(repo_name, base_path):
207 """
207 """
208 Returns True if given path is a valid repository False otherwise
208 Returns True if given path is a valid repository False otherwise
209
209
210 :param repo_name:
210 :param repo_name:
211 :param base_path:
211 :param base_path:
212
212
213 :return True: if given path is a valid repository
213 :return True: if given path is a valid repository
214 """
214 """
215 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
215 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
216
216
217 try:
217 try:
218 get_scm(full_path)
218 get_scm(full_path)
219 return True
219 return True
220 except VCSError:
220 except VCSError:
221 return False
221 return False
222
222
223
223
224 def is_valid_repos_group(repos_group_name, base_path):
224 def is_valid_repos_group(repos_group_name, base_path):
225 """
225 """
226 Returns True if given path is a repos group False otherwise
226 Returns True if given path is a repos group False otherwise
227
227
228 :param repo_name:
228 :param repo_name:
229 :param base_path:
229 :param base_path:
230 """
230 """
231 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
231 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
232
232
233 # check if it's not a repo
233 # check if it's not a repo
234 if is_valid_repo(repos_group_name, base_path):
234 if is_valid_repo(repos_group_name, base_path):
235 return False
235 return False
236
236
237 # check if it's a valid path
237 # check if it's a valid path
238 if os.path.isdir(full_path):
238 if os.path.isdir(full_path):
239 return True
239 return True
240
240
241 return False
241 return False
242
242
243
243
244 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
244 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
245 while True:
245 while True:
246 ok = raw_input(prompt)
246 ok = raw_input(prompt)
247 if ok in ('y', 'ye', 'yes'):
247 if ok in ('y', 'ye', 'yes'):
248 return True
248 return True
249 if ok in ('n', 'no', 'nop', 'nope'):
249 if ok in ('n', 'no', 'nop', 'nope'):
250 return False
250 return False
251 retries = retries - 1
251 retries = retries - 1
252 if retries < 0:
252 if retries < 0:
253 raise IOError
253 raise IOError
254 print complaint
254 print complaint
255
255
256 #propagated from mercurial documentation
256 #propagated from mercurial documentation
257 ui_sections = ['alias', 'auth',
257 ui_sections = ['alias', 'auth',
258 'decode/encode', 'defaults',
258 'decode/encode', 'defaults',
259 'diff', 'email',
259 'diff', 'email',
260 'extensions', 'format',
260 'extensions', 'format',
261 'merge-patterns', 'merge-tools',
261 'merge-patterns', 'merge-tools',
262 'hooks', 'http_proxy',
262 'hooks', 'http_proxy',
263 'smtp', 'patch',
263 'smtp', 'patch',
264 'paths', 'profiling',
264 'paths', 'profiling',
265 'server', 'trusted',
265 'server', 'trusted',
266 'ui', 'web', ]
266 'ui', 'web', ]
267
267
268
268
269 def make_ui(read_from='file', path=None, checkpaths=True):
269 def make_ui(read_from='file', path=None, checkpaths=True):
270 """
270 """
271 A function that will read python rc files or database
271 A function that will read python rc files or database
272 and make an mercurial ui object from read options
272 and make an mercurial ui object from read options
273
273
274 :param path: path to mercurial config file
274 :param path: path to mercurial config file
275 :param checkpaths: check the path
275 :param checkpaths: check the path
276 :param read_from: read from 'file' or 'db'
276 :param read_from: read from 'file' or 'db'
277 """
277 """
278
278
279 baseui = ui.ui()
279 baseui = ui.ui()
280
280
281 # clean the baseui object
281 # clean the baseui object
282 baseui._ocfg = config.config()
282 baseui._ocfg = config.config()
283 baseui._ucfg = config.config()
283 baseui._ucfg = config.config()
284 baseui._tcfg = config.config()
284 baseui._tcfg = config.config()
285
285
286 if read_from == 'file':
286 if read_from == 'file':
287 if not os.path.isfile(path):
287 if not os.path.isfile(path):
288 log.debug('hgrc file is not present at %s skipping...' % path)
288 log.debug('hgrc file is not present at %s skipping...' % path)
289 return False
289 return False
290 log.debug('reading hgrc from %s' % path)
290 log.debug('reading hgrc from %s' % path)
291 cfg = config.config()
291 cfg = config.config()
292 cfg.read(path)
292 cfg.read(path)
293 for section in ui_sections:
293 for section in ui_sections:
294 for k, v in cfg.items(section):
294 for k, v in cfg.items(section):
295 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
295 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
296 baseui.setconfig(section, k, v)
296 baseui.setconfig(section, k, v)
297
297
298 elif read_from == 'db':
298 elif read_from == 'db':
299 sa = meta.Session
299 sa = meta.Session
300 ret = sa.query(RhodeCodeUi)\
300 ret = sa.query(RhodeCodeUi)\
301 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
301 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
302 .all()
302 .all()
303
303
304 hg_ui = ret
304 hg_ui = ret
305 for ui_ in hg_ui:
305 for ui_ in hg_ui:
306 if ui_.ui_active:
306 if ui_.ui_active:
307 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
307 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
308 ui_.ui_key, ui_.ui_value)
308 ui_.ui_key, ui_.ui_value)
309 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
309 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
310
310
311 meta.Session.remove()
311 meta.Session.remove()
312 return baseui
312 return baseui
313
313
314
314
315 def set_rhodecode_config(config):
315 def set_rhodecode_config(config):
316 """
316 """
317 Updates pylons config with new settings from database
317 Updates pylons config with new settings from database
318
318
319 :param config:
319 :param config:
320 """
320 """
321 hgsettings = RhodeCodeSetting.get_app_settings()
321 hgsettings = RhodeCodeSetting.get_app_settings()
322
322
323 for k, v in hgsettings.items():
323 for k, v in hgsettings.items():
324 config[k] = v
324 config[k] = v
325
325
326
326
327 def invalidate_cache(cache_key, *args):
327 def invalidate_cache(cache_key, *args):
328 """
328 """
329 Puts cache invalidation task into db for
329 Puts cache invalidation task into db for
330 further global cache invalidation
330 further global cache invalidation
331 """
331 """
332
332
333 from rhodecode.model.scm import ScmModel
333 from rhodecode.model.scm import ScmModel
334
334
335 if cache_key.startswith('get_repo_cached_'):
335 if cache_key.startswith('get_repo_cached_'):
336 name = cache_key.split('get_repo_cached_')[-1]
336 name = cache_key.split('get_repo_cached_')[-1]
337 ScmModel().mark_for_invalidation(name)
337 ScmModel().mark_for_invalidation(name)
338
338
339
339
340 class EmptyChangeset(BaseChangeset):
340 class EmptyChangeset(BaseChangeset):
341 """
341 """
342 An dummy empty changeset. It's possible to pass hash when creating
342 An dummy empty changeset. It's possible to pass hash when creating
343 an EmptyChangeset
343 an EmptyChangeset
344 """
344 """
345
345
346 def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
346 def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
347 alias=None):
347 alias=None):
348 self._empty_cs = cs
348 self._empty_cs = cs
349 self.revision = -1
349 self.revision = -1
350 self.message = ''
350 self.message = ''
351 self.author = ''
351 self.author = ''
352 self.date = ''
352 self.date = ''
353 self.repository = repo
353 self.repository = repo
354 self.requested_revision = requested_revision
354 self.requested_revision = requested_revision
355 self.alias = alias
355 self.alias = alias
356
356
357 @LazyProperty
357 @LazyProperty
358 def raw_id(self):
358 def raw_id(self):
359 """
359 """
360 Returns raw string identifying this changeset, useful for web
360 Returns raw string identifying this changeset, useful for web
361 representation.
361 representation.
362 """
362 """
363
363
364 return self._empty_cs
364 return self._empty_cs
365
365
366 @LazyProperty
366 @LazyProperty
367 def branch(self):
367 def branch(self):
368 return get_backend(self.alias).DEFAULT_BRANCH_NAME
368 return get_backend(self.alias).DEFAULT_BRANCH_NAME
369
369
370 @LazyProperty
370 @LazyProperty
371 def short_id(self):
371 def short_id(self):
372 return self.raw_id[:12]
372 return self.raw_id[:12]
373
373
374 def get_file_changeset(self, path):
374 def get_file_changeset(self, path):
375 return self
375 return self
376
376
377 def get_file_content(self, path):
377 def get_file_content(self, path):
378 return u''
378 return u''
379
379
380 def get_file_size(self, path):
380 def get_file_size(self, path):
381 return 0
381 return 0
382
382
383
383
384 def map_groups(path):
384 def map_groups(path):
385 """
385 """
386 Given a full path to a repository, create all nested groups that this
386 Given a full path to a repository, create all nested groups that this
387 repo is inside. This function creates parent-child relationships between
387 repo is inside. This function creates parent-child relationships between
388 groups and creates default perms for all new groups.
388 groups and creates default perms for all new groups.
389
389
390 :param paths: full path to repository
390 :param paths: full path to repository
391 """
391 """
392 sa = meta.Session
392 sa = meta.Session
393 groups = path.split(Repository.url_sep())
393 groups = path.split(Repository.url_sep())
394 parent = None
394 parent = None
395 group = None
395 group = None
396
396
397 # last element is repo in nested groups structure
397 # last element is repo in nested groups structure
398 groups = groups[:-1]
398 groups = groups[:-1]
399 rgm = ReposGroupModel(sa)
399 rgm = ReposGroupModel(sa)
400 for lvl, group_name in enumerate(groups):
400 for lvl, group_name in enumerate(groups):
401 group_name = '/'.join(groups[:lvl] + [group_name])
401 group_name = '/'.join(groups[:lvl] + [group_name])
402 group = RepoGroup.get_by_group_name(group_name)
402 group = RepoGroup.get_by_group_name(group_name)
403 desc = '%s group' % group_name
403 desc = '%s group' % group_name
404
404
405 # skip folders that are now removed repos
405 # skip folders that are now removed repos
406 if REMOVED_REPO_PAT.match(group_name):
406 if REMOVED_REPO_PAT.match(group_name):
407 break
407 break
408
408
409 if group is None:
409 if group is None:
410 log.debug('creating group level: %s group_name: %s' % (lvl,
410 log.debug('creating group level: %s group_name: %s' % (lvl,
411 group_name))
411 group_name))
412 group = RepoGroup(group_name, parent)
412 group = RepoGroup(group_name, parent)
413 group.group_description = desc
413 group.group_description = desc
414 sa.add(group)
414 sa.add(group)
415 rgm._create_default_perms(group)
415 rgm._create_default_perms(group)
416 sa.flush()
416 sa.flush()
417 parent = group
417 parent = group
418 return group
418 return group
419
419
420
420
421 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
421 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
422 """
422 """
423 maps all repos given in initial_repo_list, non existing repositories
423 maps all repos given in initial_repo_list, non existing repositories
424 are created, if remove_obsolete is True it also check for db entries
424 are created, if remove_obsolete is True it also check for db entries
425 that are not in initial_repo_list and removes them.
425 that are not in initial_repo_list and removes them.
426
426
427 :param initial_repo_list: list of repositories found by scanning methods
427 :param initial_repo_list: list of repositories found by scanning methods
428 :param remove_obsolete: check for obsolete entries in database
428 :param remove_obsolete: check for obsolete entries in database
429 """
429 """
430 from rhodecode.model.repo import RepoModel
430 from rhodecode.model.repo import RepoModel
431 sa = meta.Session
431 sa = meta.Session
432 rm = RepoModel()
432 rm = RepoModel()
433 user = sa.query(User).filter(User.admin == True).first()
433 user = sa.query(User).filter(User.admin == True).first()
434 if user is None:
434 if user is None:
435 raise Exception('Missing administrative account !')
435 raise Exception('Missing administrative account !')
436 added = []
436 added = []
437
437
438 for name, repo in initial_repo_list.items():
438 for name, repo in initial_repo_list.items():
439 group = map_groups(name)
439 group = map_groups(name)
440 if not rm.get_by_repo_name(name, cache=False):
440 if not rm.get_by_repo_name(name, cache=False):
441 log.info('repository %s not found creating default' % name)
441 log.info('repository %s not found creating default' % name)
442 added.append(name)
442 added.append(name)
443 form_data = {
443 form_data = {
444 'repo_name': name,
444 'repo_name': name,
445 'repo_name_full': name,
445 'repo_name_full': name,
446 'repo_type': repo.alias,
446 'repo_type': repo.alias,
447 'description': repo.description \
447 'description': repo.description \
448 if repo.description != 'unknown' else '%s repository' % name,
448 if repo.description != 'unknown' else '%s repository' % name,
449 'private': False,
449 'private': False,
450 'group_id': getattr(group, 'group_id', None)
450 'group_id': getattr(group, 'group_id', None)
451 }
451 }
452 rm.create(form_data, user, just_db=True)
452 rm.create(form_data, user, just_db=True)
453 sa.commit()
453 sa.commit()
454 removed = []
454 removed = []
455 if remove_obsolete:
455 if remove_obsolete:
456 # remove from database those repositories that are not in the filesystem
456 # remove from database those repositories that are not in the filesystem
457 for repo in sa.query(Repository).all():
457 for repo in sa.query(Repository).all():
458 if repo.repo_name not in initial_repo_list.keys():
458 if repo.repo_name not in initial_repo_list.keys():
459 log.debug("Removing non existing repository found in db %s" %
459 log.debug("Removing non existing repository found in db %s" %
460 repo.repo_name)
460 repo.repo_name)
461 removed.append(repo.repo_name)
461 removed.append(repo.repo_name)
462 sa.delete(repo)
462 sa.delete(repo)
463 sa.commit()
463 sa.commit()
464
464
465 # clear cache keys
465 # clear cache keys
466 log.debug("Clearing cache keys now...")
466 log.debug("Clearing cache keys now...")
467 CacheInvalidation.clear_cache()
467 CacheInvalidation.clear_cache()
468 sa.commit()
468 sa.commit()
469 return added, removed
469 return added, removed
470
470
471
471
472 # set cache regions for beaker so celery can utilise it
472 # set cache regions for beaker so celery can utilise it
473 def add_cache(settings):
473 def add_cache(settings):
474 cache_settings = {'regions': None}
474 cache_settings = {'regions': None}
475 for key in settings.keys():
475 for key in settings.keys():
476 for prefix in ['beaker.cache.', 'cache.']:
476 for prefix in ['beaker.cache.', 'cache.']:
477 if key.startswith(prefix):
477 if key.startswith(prefix):
478 name = key.split(prefix)[1].strip()
478 name = key.split(prefix)[1].strip()
479 cache_settings[name] = settings[key].strip()
479 cache_settings[name] = settings[key].strip()
480 if cache_settings['regions']:
480 if cache_settings['regions']:
481 for region in cache_settings['regions'].split(','):
481 for region in cache_settings['regions'].split(','):
482 region = region.strip()
482 region = region.strip()
483 region_settings = {}
483 region_settings = {}
484 for key, value in cache_settings.items():
484 for key, value in cache_settings.items():
485 if key.startswith(region):
485 if key.startswith(region):
486 region_settings[key.split('.')[1]] = value
486 region_settings[key.split('.')[1]] = value
487 region_settings['expire'] = int(region_settings.get('expire',
487 region_settings['expire'] = int(region_settings.get('expire',
488 60))
488 60))
489 region_settings.setdefault('lock_dir',
489 region_settings.setdefault('lock_dir',
490 cache_settings.get('lock_dir'))
490 cache_settings.get('lock_dir'))
491 region_settings.setdefault('data_dir',
491 region_settings.setdefault('data_dir',
492 cache_settings.get('data_dir'))
492 cache_settings.get('data_dir'))
493
493
494 if 'type' not in region_settings:
494 if 'type' not in region_settings:
495 region_settings['type'] = cache_settings.get('type',
495 region_settings['type'] = cache_settings.get('type',
496 'memory')
496 'memory')
497 beaker.cache.cache_regions[region] = region_settings
497 beaker.cache.cache_regions[region] = region_settings
498
498
499
499
500 def load_rcextensions(root_path):
500 def load_rcextensions(root_path):
501 import rhodecode
501 import rhodecode
502 from rhodecode.config import conf
502 from rhodecode.config import conf
503
503
504 path = os.path.join(root_path, 'rcextensions', '__init__.py')
504 path = os.path.join(root_path, 'rcextensions', '__init__.py')
505 if os.path.isfile(path):
505 if os.path.isfile(path):
506 rcext = create_module('rc', path)
506 rcext = create_module('rc', path)
507 EXT = rhodecode.EXTENSIONS = rcext
507 EXT = rhodecode.EXTENSIONS = rcext
508 log.debug('Found rcextensions now loading %s...' % rcext)
508 log.debug('Found rcextensions now loading %s...' % rcext)
509
509
510 # Additional mappings that are not present in the pygments lexers
510 # Additional mappings that are not present in the pygments lexers
511 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
511 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
512
512
513 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
513 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
514
514
515 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
515 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
516 log.debug('settings custom INDEX_EXTENSIONS')
516 log.debug('settings custom INDEX_EXTENSIONS')
517 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
517 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
518
518
519 #ADDITIONAL MAPPINGS
519 #ADDITIONAL MAPPINGS
520 log.debug('adding extra into INDEX_EXTENSIONS')
520 log.debug('adding extra into INDEX_EXTENSIONS')
521 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
521 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
522
522
523
523
524 #==============================================================================
524 #==============================================================================
525 # TEST FUNCTIONS AND CREATORS
525 # TEST FUNCTIONS AND CREATORS
526 #==============================================================================
526 #==============================================================================
527 def create_test_index(repo_location, config, full_index):
527 def create_test_index(repo_location, config, full_index):
528 """
528 """
529 Makes default test index
529 Makes default test index
530
530
531 :param config: test config
531 :param config: test config
532 :param full_index:
532 :param full_index:
533 """
533 """
534
534
535 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
535 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
536 from rhodecode.lib.pidlock import DaemonLock, LockHeld
536 from rhodecode.lib.pidlock import DaemonLock, LockHeld
537
537
538 repo_location = repo_location
538 repo_location = repo_location
539
539
540 index_location = os.path.join(config['app_conf']['index_dir'])
540 index_location = os.path.join(config['app_conf']['index_dir'])
541 if not os.path.exists(index_location):
541 if not os.path.exists(index_location):
542 os.makedirs(index_location)
542 os.makedirs(index_location)
543
543
544 try:
544 try:
545 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
545 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
546 WhooshIndexingDaemon(index_location=index_location,
546 WhooshIndexingDaemon(index_location=index_location,
547 repo_location=repo_location)\
547 repo_location=repo_location)\
548 .run(full_index=full_index)
548 .run(full_index=full_index)
549 l.release()
549 l.release()
550 except LockHeld:
550 except LockHeld:
551 pass
551 pass
552
552
553
553
554 def create_test_env(repos_test_path, config):
554 def create_test_env(repos_test_path, config):
555 """
555 """
556 Makes a fresh database and
556 Makes a fresh database and
557 install test repository into tmp dir
557 install test repository into tmp dir
558 """
558 """
559 from rhodecode.lib.db_manage import DbManage
559 from rhodecode.lib.db_manage import DbManage
560 from rhodecode.tests import HG_REPO, TESTS_TMP_PATH
560 from rhodecode.tests import HG_REPO, TESTS_TMP_PATH
561
561
562 # PART ONE create db
562 # PART ONE create db
563 dbconf = config['sqlalchemy.db1.url']
563 dbconf = config['sqlalchemy.db1.url']
564 log.debug('making test db %s' % dbconf)
564 log.debug('making test db %s' % dbconf)
565
565
566 # create test dir if it doesn't exist
566 # create test dir if it doesn't exist
567 if not os.path.isdir(repos_test_path):
567 if not os.path.isdir(repos_test_path):
568 log.debug('Creating testdir %s' % repos_test_path)
568 log.debug('Creating testdir %s' % repos_test_path)
569 os.makedirs(repos_test_path)
569 os.makedirs(repos_test_path)
570
570
571 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
571 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
572 tests=True)
572 tests=True)
573 dbmanage.create_tables(override=True)
573 dbmanage.create_tables(override=True)
574 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
574 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
575 dbmanage.create_default_user()
575 dbmanage.create_default_user()
576 dbmanage.admin_prompt()
576 dbmanage.admin_prompt()
577 dbmanage.create_permissions()
577 dbmanage.create_permissions()
578 dbmanage.populate_default_permissions()
578 dbmanage.populate_default_permissions()
579 Session.commit()
579 Session.commit()
580 # PART TWO make test repo
580 # PART TWO make test repo
581 log.debug('making test vcs repositories')
581 log.debug('making test vcs repositories')
582
582
583 idx_path = config['app_conf']['index_dir']
583 idx_path = config['app_conf']['index_dir']
584 data_path = config['app_conf']['cache_dir']
584 data_path = config['app_conf']['cache_dir']
585
585
586 #clean index and data
586 #clean index and data
587 if idx_path and os.path.exists(idx_path):
587 if idx_path and os.path.exists(idx_path):
588 log.debug('remove %s' % idx_path)
588 log.debug('remove %s' % idx_path)
589 shutil.rmtree(idx_path)
589 shutil.rmtree(idx_path)
590
590
591 if data_path and os.path.exists(data_path):
591 if data_path and os.path.exists(data_path):
592 log.debug('remove %s' % data_path)
592 log.debug('remove %s' % data_path)
593 shutil.rmtree(data_path)
593 shutil.rmtree(data_path)
594
594
595 #CREATE DEFAULT HG REPOSITORY
595 #CREATE DEFAULT HG REPOSITORY
596 cur_dir = dn(dn(abspath(__file__)))
596 cur_dir = dn(dn(abspath(__file__)))
597 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
597 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
598 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
598 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
599 tar.close()
599 tar.close()
600
600
601
601
602 #==============================================================================
602 #==============================================================================
603 # PASTER COMMANDS
603 # PASTER COMMANDS
604 #==============================================================================
604 #==============================================================================
605 class BasePasterCommand(Command):
605 class BasePasterCommand(Command):
606 """
606 """
607 Abstract Base Class for paster commands.
607 Abstract Base Class for paster commands.
608
608
609 The celery commands are somewhat aggressive about loading
609 The celery commands are somewhat aggressive about loading
610 celery.conf, and since our module sets the `CELERY_LOADER`
610 celery.conf, and since our module sets the `CELERY_LOADER`
611 environment variable to our loader, we have to bootstrap a bit and
611 environment variable to our loader, we have to bootstrap a bit and
612 make sure we've had a chance to load the pylons config off of the
612 make sure we've had a chance to load the pylons config off of the
613 command line, otherwise everything fails.
613 command line, otherwise everything fails.
614 """
614 """
615 min_args = 1
615 min_args = 1
616 min_args_error = "Please provide a paster config file as an argument."
616 min_args_error = "Please provide a paster config file as an argument."
617 takes_config_file = 1
617 takes_config_file = 1
618 requires_config_file = True
618 requires_config_file = True
619
619
620 def notify_msg(self, msg, log=False):
620 def notify_msg(self, msg, log=False):
621 """Make a notification to user, additionally if logger is passed
621 """Make a notification to user, additionally if logger is passed
622 it logs this action using given logger
622 it logs this action using given logger
623
623
624 :param msg: message that will be printed to user
624 :param msg: message that will be printed to user
625 :param log: logging instance, to use to additionally log this message
625 :param log: logging instance, to use to additionally log this message
626
626
627 """
627 """
628 if log and isinstance(log, logging):
628 if log and isinstance(log, logging):
629 log(msg)
629 log(msg)
630
630
631 def run(self, args):
631 def run(self, args):
632 """
632 """
633 Overrides Command.run
633 Overrides Command.run
634
634
635 Checks for a config file argument and loads it.
635 Checks for a config file argument and loads it.
636 """
636 """
637 if len(args) < self.min_args:
637 if len(args) < self.min_args:
638 raise BadCommand(
638 raise BadCommand(
639 self.min_args_error % {'min_args': self.min_args,
639 self.min_args_error % {'min_args': self.min_args,
640 'actual_args': len(args)})
640 'actual_args': len(args)})
641
641
642 # Decrement because we're going to lob off the first argument.
642 # Decrement because we're going to lob off the first argument.
643 # @@ This is hacky
643 # @@ This is hacky
644 self.min_args -= 1
644 self.min_args -= 1
645 self.bootstrap_config(args[0])
645 self.bootstrap_config(args[0])
646 self.update_parser()
646 self.update_parser()
647 return super(BasePasterCommand, self).run(args[1:])
647 return super(BasePasterCommand, self).run(args[1:])
648
648
649 def update_parser(self):
649 def update_parser(self):
650 """
650 """
651 Abstract method. Allows for the class's parser to be updated
651 Abstract method. Allows for the class's parser to be updated
652 before the superclass's `run` method is called. Necessary to
652 before the superclass's `run` method is called. Necessary to
653 allow options/arguments to be passed through to the underlying
653 allow options/arguments to be passed through to the underlying
654 celery command.
654 celery command.
655 """
655 """
656 raise NotImplementedError("Abstract Method.")
656 raise NotImplementedError("Abstract Method.")
657
657
658 def bootstrap_config(self, conf):
658 def bootstrap_config(self, conf):
659 """
659 """
660 Loads the pylons configuration.
660 Loads the pylons configuration.
661 """
661 """
662 from pylons import config as pylonsconfig
662 from pylons import config as pylonsconfig
663
663
664 self.path_to_ini_file = os.path.realpath(conf)
664 self.path_to_ini_file = os.path.realpath(conf)
665 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
665 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
666 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
666 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
General Comments 0
You need to be logged in to leave comments. Login now