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