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