##// END OF EJS Templates
project refactoring, cleaned up lib.utils from rarly used functions, and place them...
marcink -
r756:01be209b beta
parent child Browse files
Show More
@@ -1,314 +1,335 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # settings controller for pylons
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on July 14, 2010
22 22 settings controller for pylons
23 23 @author: marcink
24 24 """
25 25 from formencode import htmlfill
26 26 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
27 27 config
28 28 from pylons.controllers.util import abort, redirect
29 29 from pylons.i18n.translation import _
30 30 from rhodecode.lib import helpers as h
31 31 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
32 32 HasPermissionAnyDecorator
33 33 from rhodecode.lib.base import BaseController, render
34 34 from rhodecode.lib.celerylib import tasks, run_task
35 35 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
36 set_rhodecode_config, get_hg_settings, get_hg_ui_settings
36 set_rhodecode_config
37 37 from rhodecode.model.db import RhodeCodeUi, Repository
38 38 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
39 39 ApplicationUiSettingsForm
40 40 from rhodecode.model.scm import ScmModel
41 41 from rhodecode.model.settings import SettingsModel
42 42 from rhodecode.model.user import UserModel
43 43 from sqlalchemy import func
44 44 import formencode
45 45 import logging
46 46 import traceback
47 47
48 48 log = logging.getLogger(__name__)
49 49
50 50
51 51 class SettingsController(BaseController):
52 52 """REST Controller styled on the Atom Publishing Protocol"""
53 53 # To properly map this controller, ensure your config/routing.py
54 54 # file has a resource setup:
55 55 # map.resource('setting', 'settings', controller='admin/settings',
56 56 # path_prefix='/admin', name_prefix='admin_')
57 57
58 58
59 59 @LoginRequired()
60 60 def __before__(self):
61 61 c.admin_user = session.get('admin_user')
62 62 c.admin_username = session.get('admin_username')
63 63 super(SettingsController, self).__before__()
64 64
65 65
66 66 @HasPermissionAllDecorator('hg.admin')
67 67 def index(self, format='html'):
68 68 """GET /admin/settings: All items in the collection"""
69 69 # url('admin_settings')
70 70
71 defaults = get_hg_settings()
72 defaults.update(get_hg_ui_settings())
71 defaults = SettingsModel().get_app_settings()
72 defaults.update(self.get_hg_ui_settings())
73 73 return htmlfill.render(
74 74 render('admin/settings/settings.html'),
75 75 defaults=defaults,
76 76 encoding="UTF-8",
77 77 force_defaults=False
78 78 )
79 79
80 80 @HasPermissionAllDecorator('hg.admin')
81 81 def create(self):
82 82 """POST /admin/settings: Create a new item"""
83 83 # url('admin_settings')
84 84
85 85 @HasPermissionAllDecorator('hg.admin')
86 86 def new(self, format='html'):
87 87 """GET /admin/settings/new: Form to create a new item"""
88 88 # url('admin_new_setting')
89 89
90 90 @HasPermissionAllDecorator('hg.admin')
91 91 def update(self, setting_id):
92 92 """PUT /admin/settings/setting_id: Update an existing item"""
93 93 # Forms posted to this method should contain a hidden field:
94 94 # <input type="hidden" name="_method" value="PUT" />
95 95 # Or using helpers:
96 96 # h.form(url('admin_setting', setting_id=ID),
97 97 # method='put')
98 98 # url('admin_setting', setting_id=ID)
99 99 if setting_id == 'mapping':
100 100 rm_obsolete = request.POST.get('destroy', False)
101 101 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
102 102
103 103 initial = ScmModel().repo_scan(g.paths[0][1], g.baseui)
104 104 for repo_name in initial.keys():
105 105 invalidate_cache('get_repo_cached_%s' % repo_name)
106 106
107 107 repo2db_mapper(initial, rm_obsolete)
108 108
109 109 h.flash(_('Repositories successfully rescanned'), category='success')
110 110
111 111 if setting_id == 'whoosh':
112 repo_location = get_hg_ui_settings()['paths_root_path']
112 repo_location = self.get_hg_ui_settings()['paths_root_path']
113 113 full_index = request.POST.get('full_index', False)
114 114 task = run_task(tasks.whoosh_index, repo_location, full_index)
115 115
116 116 h.flash(_('Whoosh reindex task scheduled'), category='success')
117 117 if setting_id == 'global':
118 118
119 119 application_form = ApplicationSettingsForm()()
120 120 try:
121 121 form_result = application_form.to_python(dict(request.POST))
122 122 settings_model = SettingsModel()
123 123 try:
124 124 hgsettings1 = settings_model.get('title')
125 125 hgsettings1.app_settings_value = form_result['rhodecode_title']
126 126
127 127 hgsettings2 = settings_model.get('realm')
128 128 hgsettings2.app_settings_value = form_result['rhodecode_realm']
129 129
130 130
131 131 self.sa.add(hgsettings1)
132 132 self.sa.add(hgsettings2)
133 133 self.sa.commit()
134 134 set_rhodecode_config(config)
135 135 h.flash(_('Updated application settings'),
136 136 category='success')
137 137
138 138 except:
139 139 log.error(traceback.format_exc())
140 140 h.flash(_('error occurred during updating application settings'),
141 141 category='error')
142 142
143 143 self.sa.rollback()
144 144
145 145
146 146 except formencode.Invalid, errors:
147 147 return htmlfill.render(
148 148 render('admin/settings/settings.html'),
149 149 defaults=errors.value,
150 150 errors=errors.error_dict or {},
151 151 prefix_error=False,
152 152 encoding="UTF-8")
153 153
154 154 if setting_id == 'mercurial':
155 155 application_form = ApplicationUiSettingsForm()()
156 156 try:
157 157 form_result = application_form.to_python(dict(request.POST))
158 158
159 159 try:
160 160
161 161 hgsettings1 = self.sa.query(RhodeCodeUi)\
162 162 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
163 163 hgsettings1.ui_value = form_result['web_push_ssl']
164 164
165 165 hgsettings2 = self.sa.query(RhodeCodeUi)\
166 166 .filter(RhodeCodeUi.ui_key == '/').one()
167 167 hgsettings2.ui_value = form_result['paths_root_path']
168 168
169 169
170 170 #HOOKS
171 171 hgsettings3 = self.sa.query(RhodeCodeUi)\
172 172 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
173 173 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
174 174
175 175 hgsettings4 = self.sa.query(RhodeCodeUi)\
176 176 .filter(RhodeCodeUi.ui_key == 'changegroup.repo_size').one()
177 177 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
178 178
179 179 hgsettings5 = self.sa.query(RhodeCodeUi)\
180 180 .filter(RhodeCodeUi.ui_key == 'pretxnchangegroup.push_logger').one()
181 181 hgsettings5.ui_active = bool(form_result['hooks_pretxnchangegroup_push_logger'])
182 182
183 183 hgsettings6 = self.sa.query(RhodeCodeUi)\
184 184 .filter(RhodeCodeUi.ui_key == 'preoutgoing.pull_logger').one()
185 185 hgsettings6.ui_active = bool(form_result['hooks_preoutgoing_pull_logger'])
186 186
187 187
188 188 self.sa.add(hgsettings1)
189 189 self.sa.add(hgsettings2)
190 190 self.sa.add(hgsettings3)
191 191 self.sa.add(hgsettings4)
192 192 self.sa.add(hgsettings5)
193 193 self.sa.add(hgsettings6)
194 194 self.sa.commit()
195 195
196 196 h.flash(_('Updated mercurial settings'),
197 197 category='success')
198 198
199 199 except:
200 200 log.error(traceback.format_exc())
201 201 h.flash(_('error occurred during updating application settings'),
202 202 category='error')
203 203
204 204 self.sa.rollback()
205 205
206 206
207 207 except formencode.Invalid, errors:
208 208 return htmlfill.render(
209 209 render('admin/settings/settings.html'),
210 210 defaults=errors.value,
211 211 errors=errors.error_dict or {},
212 212 prefix_error=False,
213 213 encoding="UTF-8")
214 214
215 215
216 216
217 217 return redirect(url('admin_settings'))
218 218
219 219 @HasPermissionAllDecorator('hg.admin')
220 220 def delete(self, setting_id):
221 221 """DELETE /admin/settings/setting_id: Delete an existing item"""
222 222 # Forms posted to this method should contain a hidden field:
223 223 # <input type="hidden" name="_method" value="DELETE" />
224 224 # Or using helpers:
225 225 # h.form(url('admin_setting', setting_id=ID),
226 226 # method='delete')
227 227 # url('admin_setting', setting_id=ID)
228 228
229 229 @HasPermissionAllDecorator('hg.admin')
230 230 def show(self, setting_id, format='html'):
231 231 """GET /admin/settings/setting_id: Show a specific item"""
232 232 # url('admin_setting', setting_id=ID)
233 233
234 234 @HasPermissionAllDecorator('hg.admin')
235 235 def edit(self, setting_id, format='html'):
236 236 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
237 237 # url('admin_edit_setting', setting_id=ID)
238 238
239 239
240 240 def my_account(self):
241 241 """
242 242 GET /_admin/my_account Displays info about my account
243 243 """
244 244
245 245 # url('admin_settings_my_account')
246 246 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
247 247 all_repos = self.sa.query(Repository)\
248 248 .filter(Repository.user_id == c.user.user_id)\
249 249 .order_by(func.lower(Repository.repo_name))\
250 250 .all()
251 251 c.user_repos = ScmModel().get_repos(all_repos)
252 252
253 253 if c.user.username == 'default':
254 254 h.flash(_("You can't edit this user since it's"
255 255 " crucial for entire application"), category='warning')
256 256 return redirect(url('users'))
257 257
258 258 defaults = c.user.__dict__
259 259 return htmlfill.render(
260 260 render('admin/users/user_edit_my_account.html'),
261 261 defaults=defaults,
262 262 encoding="UTF-8",
263 263 force_defaults=False
264 264 )
265 265
266 266 def my_account_update(self):
267 267 """PUT /_admin/my_account_update: Update an existing item"""
268 268 # Forms posted to this method should contain a hidden field:
269 269 # <input type="hidden" name="_method" value="PUT" />
270 270 # Or using helpers:
271 271 # h.form(url('admin_settings_my_account_update'),
272 272 # method='put')
273 273 # url('admin_settings_my_account_update', id=ID)
274 274 user_model = UserModel()
275 275 uid = c.rhodecode_user.user_id
276 276 _form = UserForm(edit=True, old_data={'user_id':uid,
277 277 'email':c.rhodecode_user.email})()
278 278 form_result = {}
279 279 try:
280 280 form_result = _form.to_python(dict(request.POST))
281 281 user_model.update_my_account(uid, form_result)
282 282 h.flash(_('Your account was updated succesfully'),
283 283 category='success')
284 284
285 285 except formencode.Invalid, errors:
286 286 c.user = user_model.get(c.rhodecode_user.user_id, cache=False)
287 287 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
288 288 all_repos = self.sa.query(Repository)\
289 289 .filter(Repository.user_id == c.user.user_id)\
290 290 .order_by(func.lower(Repository.repo_name))\
291 291 .all()
292 292 c.user_repos = ScmModel().get_repos(all_repos)
293 293
294 294 return htmlfill.render(
295 295 render('admin/users/user_edit_my_account.html'),
296 296 defaults=errors.value,
297 297 errors=errors.error_dict or {},
298 298 prefix_error=False,
299 299 encoding="UTF-8")
300 300 except Exception:
301 301 log.error(traceback.format_exc())
302 302 h.flash(_('error occured during update of user %s') \
303 303 % form_result.get('username'), category='error')
304 304
305 305 return redirect(url('my_account'))
306 306
307 307 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
308 308 def create_repository(self):
309 309 """GET /_admin/create_repository: Form to create a new item"""
310 310 new_repo = request.GET.get('repo', '')
311 311 c.new_repo = h.repo_name_slug(new_repo)
312 312
313 313 return render('admin/repos/repo_add_create_repository.html')
314 314
315 def get_hg_ui_settings(self):
316 ret = self.sa.query(RhodeCodeUi).all()
317
318 if not ret:
319 raise Exception('Could not get application ui settings !')
320 settings = {}
321 for each in ret:
322 k = each.ui_key
323 v = each.ui_value
324 if k == '/':
325 k = 'root_path'
326
327 if k.find('.') != -1:
328 k = k.replace('.', '_')
329
330 if each.ui_section == 'hooks':
331 v = each.ui_active
332
333 settings[each.ui_section + '_' + k] = v
334
335 return settings
@@ -1,209 +1,221 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # middleware to handle git api calls
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on 2010-04-28
22 22
23 23 @author: marcink
24 24 SimpleGit middleware for handling git protocol request (push/clone etc.)
25 25 It's implemented with basic auth function
26 26 """
27 27
28 28 from dulwich import server as dulserver
29 29
30 30 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
31 31
32 32 def handle(self):
33 33 write = lambda x: self.proto.write_sideband(1, x)
34 34
35 35 graph_walker = dulserver.ProtocolGraphWalker(self, self.repo.object_store,
36 36 self.repo.get_peeled)
37 37 objects_iter = self.repo.fetch_objects(
38 38 graph_walker.determine_wants, graph_walker, self.progress,
39 39 get_tagged=self.get_tagged)
40 40
41 41 # Do they want any objects?
42 42 if len(objects_iter) == 0:
43 43 return
44 44
45 45 self.progress("counting objects: %d, done.\n" % len(objects_iter))
46 46 dulserver.write_pack_data(dulserver.ProtocolFile(None, write), objects_iter,
47 47 len(objects_iter))
48 48 messages = []
49 49 messages.append('thank you for using rhodecode')
50 50
51 51 for msg in messages:
52 52 self.progress(msg + "\n")
53 53 # we are done
54 54 self.proto.write("0000")
55 55
56 56 dulserver.DEFAULT_HANDLERS = {
57 57 'git-upload-pack': SimpleGitUploadPackHandler,
58 58 'git-receive-pack': dulserver.ReceivePackHandler,
59 59 }
60 60
61 61 from dulwich.repo import Repo
62 62 from dulwich.web import HTTPGitApplication
63 63 from paste.auth.basic import AuthBasicAuthenticator
64 64 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
65 65 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
66 from rhodecode.lib.utils import is_git, invalidate_cache, check_repo_fast
66 from rhodecode.lib.utils import invalidate_cache, check_repo_fast
67 67 from rhodecode.model.user import UserModel
68 68 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
69 69 import logging
70 70 import os
71 71 import traceback
72 72
73 73 log = logging.getLogger(__name__)
74 74
75 def is_git(environ):
76 """
77 Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
78 then have git client version given.
79
80 :param environ:
81 """
82 http_user_agent = environ.get('HTTP_USER_AGENT')
83 if http_user_agent and http_user_agent.startswith('git'):
84 return True
85 return False
86
75 87 class SimpleGit(object):
76 88
77 89 def __init__(self, application, config):
78 90 self.application = application
79 91 self.config = config
80 92 #authenticate this git request using
81 93 self.authenticate = AuthBasicAuthenticator('', authfunc)
82 94 self.ipaddr = '0.0.0.0'
83 95 self.repository = None
84 96 self.username = None
85 97 self.action = None
86 98
87 99 def __call__(self, environ, start_response):
88 100 if not is_git(environ):
89 101 return self.application(environ, start_response)
90 102
91 103 proxy_key = 'HTTP_X_REAL_IP'
92 104 def_key = 'REMOTE_ADDR'
93 105 self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
94 106
95 107 #===================================================================
96 108 # AUTHENTICATE THIS GIT REQUEST
97 109 #===================================================================
98 110 username = REMOTE_USER(environ)
99 111 if not username:
100 112 self.authenticate.realm = self.config['rhodecode_realm']
101 113 result = self.authenticate(environ)
102 114 if isinstance(result, str):
103 115 AUTH_TYPE.update(environ, 'basic')
104 116 REMOTE_USER.update(environ, result)
105 117 else:
106 118 return result.wsgi_application(environ, start_response)
107 119
108 120 #=======================================================================
109 121 # GET REPOSITORY
110 122 #=======================================================================
111 123 try:
112 124 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
113 125 if repo_name.endswith('/'):
114 126 repo_name = repo_name.rstrip('/')
115 127 self.repository = repo_name
116 128 except:
117 129 log.error(traceback.format_exc())
118 130 return HTTPInternalServerError()(environ, start_response)
119 131
120 132 #===================================================================
121 133 # CHECK PERMISSIONS FOR THIS REQUEST
122 134 #===================================================================
123 135 self.action = self.__get_action(environ)
124 136 if self.action:
125 137 username = self.__get_environ_user(environ)
126 138 try:
127 139 user = self.__get_user(username)
128 140 self.username = user.username
129 141 except:
130 142 log.error(traceback.format_exc())
131 143 return HTTPInternalServerError()(environ, start_response)
132 144
133 145 #check permissions for this repository
134 146 if self.action == 'push':
135 147 if not HasPermissionAnyMiddleware('repository.write',
136 148 'repository.admin')\
137 149 (user, repo_name):
138 150 return HTTPForbidden()(environ, start_response)
139 151
140 152 else:
141 153 #any other action need at least read permission
142 154 if not HasPermissionAnyMiddleware('repository.read',
143 155 'repository.write',
144 156 'repository.admin')\
145 157 (user, repo_name):
146 158 return HTTPForbidden()(environ, start_response)
147 159
148 160 self.extras = {'ip':self.ipaddr,
149 161 'username':self.username,
150 162 'action':self.action,
151 163 'repository':self.repository}
152 164
153 165 #===================================================================
154 166 # GIT REQUEST HANDLING
155 167 #===================================================================
156 168 self.basepath = self.config['base_path']
157 169 self.repo_path = os.path.join(self.basepath, self.repo_name)
158 170 #quick check if that dir exists...
159 171 if check_repo_fast(self.repo_name, self.basepath):
160 172 return HTTPNotFound()(environ, start_response)
161 173 try:
162 174 app = self.__make_app()
163 175 except:
164 176 log.error(traceback.format_exc())
165 177 return HTTPInternalServerError()(environ, start_response)
166 178
167 179 #invalidate cache on push
168 180 if self.action == 'push':
169 181 self.__invalidate_cache(self.repo_name)
170 182 messages = []
171 183 messages.append('thank you for using rhodecode')
172 184 return app(environ, start_response)
173 185 else:
174 186 return app(environ, start_response)
175 187
176 188
177 189 def __make_app(self):
178 190 backend = dulserver.DictBackend({'/' + self.repo_name: Repo(self.repo_path)})
179 191 gitserve = HTTPGitApplication(backend)
180 192
181 193 return gitserve
182 194
183 195 def __get_environ_user(self, environ):
184 196 return environ.get('REMOTE_USER')
185 197
186 198 def __get_user(self, username):
187 199 return UserModel().get_by_username(username, cache=True)
188 200
189 201 def __get_action(self, environ):
190 202 """
191 203 Maps git request commands into a pull or push command.
192 204 :param environ:
193 205 """
194 206 service = environ['QUERY_STRING'].split('=')
195 207 if len(service) > 1:
196 208 service_cmd = service[1]
197 209 mapping = {'git-receive-pack': 'push',
198 210 'git-upload-pack': 'pull',
199 211 }
200 212
201 213 return mapping.get(service_cmd, service_cmd if service_cmd else 'other')
202 214 else:
203 215 return 'other'
204 216
205 217 def __invalidate_cache(self, repo_name):
206 218 """we know that some change was made to repositories and we should
207 219 invalidate the cache to see the changes right away but only for
208 220 push requests"""
209 221 invalidate_cache('get_repo_cached_%s' % repo_name)
@@ -1,220 +1,229 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # middleware to handle mercurial api calls
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on 2010-04-28
22 22
23 23 @author: marcink
24 24 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
25 25 It's implemented with basic auth function
26 26 """
27 from itertools import chain
28 27 from mercurial.error import RepoError
29 28 from mercurial.hgweb import hgweb
30 29 from mercurial.hgweb.request import wsgiapplication
31 30 from paste.auth.basic import AuthBasicAuthenticator
32 31 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
33 32 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
34 from rhodecode.lib.utils import is_mercurial, make_ui, invalidate_cache, \
33 from rhodecode.lib.utils import make_ui, invalidate_cache, \
35 34 check_repo_fast, ui_sections
36 35 from rhodecode.model.user import UserModel
37 36 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
38 37 import logging
39 38 import os
40 39 import traceback
41 40
42 41 log = logging.getLogger(__name__)
43 42
43 def is_mercurial(environ):
44 """
45 Returns True if request's target is mercurial server - header
46 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
47 """
48 http_accept = environ.get('HTTP_ACCEPT')
49 if http_accept and http_accept.startswith('application/mercurial'):
50 return True
51 return False
52
44 53 class SimpleHg(object):
45 54
46 55 def __init__(self, application, config):
47 56 self.application = application
48 57 self.config = config
49 58 #authenticate this mercurial request using authfunc
50 59 self.authenticate = AuthBasicAuthenticator('', authfunc)
51 60 self.ipaddr = '0.0.0.0'
52 61 self.repository = None
53 62 self.username = None
54 63 self.action = None
55 64
56 65 def __call__(self, environ, start_response):
57 66 if not is_mercurial(environ):
58 67 return self.application(environ, start_response)
59 68
60 69 proxy_key = 'HTTP_X_REAL_IP'
61 70 def_key = 'REMOTE_ADDR'
62 71 self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
63 72
64 73 #===================================================================
65 74 # AUTHENTICATE THIS MERCURIAL REQUEST
66 75 #===================================================================
67 76 username = REMOTE_USER(environ)
68 77
69 78 if not username:
70 79 self.authenticate.realm = self.config['rhodecode_realm']
71 80 result = self.authenticate(environ)
72 81 if isinstance(result, str):
73 82 AUTH_TYPE.update(environ, 'basic')
74 83 REMOTE_USER.update(environ, result)
75 84 else:
76 85 return result.wsgi_application(environ, start_response)
77 86
78 87 #=======================================================================
79 88 # GET REPOSITORY
80 89 #=======================================================================
81 90 try:
82 91 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
83 92 if repo_name.endswith('/'):
84 93 repo_name = repo_name.rstrip('/')
85 94 self.repository = repo_name
86 95 except:
87 96 log.error(traceback.format_exc())
88 97 return HTTPInternalServerError()(environ, start_response)
89 98
90 99 #===================================================================
91 100 # CHECK PERMISSIONS FOR THIS REQUEST
92 101 #===================================================================
93 102 self.action = self.__get_action(environ)
94 103 if self.action:
95 104 username = self.__get_environ_user(environ)
96 105 try:
97 106 user = self.__get_user(username)
98 107 self.username = user.username
99 108 except:
100 109 log.error(traceback.format_exc())
101 110 return HTTPInternalServerError()(environ, start_response)
102 111
103 112 #check permissions for this repository
104 113 if self.action == 'push':
105 114 if not HasPermissionAnyMiddleware('repository.write',
106 115 'repository.admin')\
107 116 (user, repo_name):
108 117 return HTTPForbidden()(environ, start_response)
109 118
110 119 else:
111 120 #any other action need at least read permission
112 121 if not HasPermissionAnyMiddleware('repository.read',
113 122 'repository.write',
114 123 'repository.admin')\
115 124 (user, repo_name):
116 125 return HTTPForbidden()(environ, start_response)
117 126
118 127 self.extras = {'ip':self.ipaddr,
119 128 'username':self.username,
120 129 'action':self.action,
121 130 'repository':self.repository}
122 131
123 132 #===================================================================
124 133 # MERCURIAL REQUEST HANDLING
125 134 #===================================================================
126 135 environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path
127 136 self.baseui = make_ui('db')
128 137 self.basepath = self.config['base_path']
129 138 self.repo_path = os.path.join(self.basepath, repo_name)
130 139
131 140 #quick check if that dir exists...
132 141 if check_repo_fast(repo_name, self.basepath):
133 142 return HTTPNotFound()(environ, start_response)
134 143 try:
135 144 app = wsgiapplication(self.__make_app)
136 145 except RepoError, e:
137 146 if str(e).find('not found') != -1:
138 147 return HTTPNotFound()(environ, start_response)
139 148 except Exception:
140 149 log.error(traceback.format_exc())
141 150 return HTTPInternalServerError()(environ, start_response)
142 151
143 152 #invalidate cache on push
144 153 if self.action == 'push':
145 154 self.__invalidate_cache(repo_name)
146
155
147 156 return app(environ, start_response)
148 157
149 158
150 159 def __make_app(self):
151 160 hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
152 161 return self.__load_web_settings(hgserve, self.extras)
153 162
154 163 def __get_environ_user(self, environ):
155 164 return environ.get('REMOTE_USER')
156 165
157 166 def __get_user(self, username):
158 167 return UserModel().get_by_username(username, cache=True)
159 168
160 169 def __get_action(self, environ):
161 170 """
162 171 Maps mercurial request commands into a clone,pull or push command.
163 172 This should always return a valid command string
164 173 :param environ:
165 174 """
166 175 mapping = {'changegroup': 'pull',
167 176 'changegroupsubset': 'pull',
168 177 'stream_out': 'pull',
169 178 'listkeys': 'pull',
170 179 'unbundle': 'push',
171 180 'pushkey': 'push', }
172 181 for qry in environ['QUERY_STRING'].split('&'):
173 182 if qry.startswith('cmd'):
174 183 cmd = qry.split('=')[-1]
175 184 if mapping.has_key(cmd):
176 185 return mapping[cmd]
177 186 else:
178 187 return cmd
179 188
180 189 def __invalidate_cache(self, repo_name):
181 190 """we know that some change was made to repositories and we should
182 191 invalidate the cache to see the changes right away but only for
183 192 push requests"""
184 193 invalidate_cache('get_repo_cached_%s' % repo_name)
185 194
186 195
187 196 def __load_web_settings(self, hgserve, extras={}):
188 197 #set the global ui for hgserve instance passed
189 198 hgserve.repo.ui = self.baseui
190 199
191 200 hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
192 201
193 202 #inject some additional parameters that will be available in ui
194 203 #for hooks
195 204 for k, v in extras.items():
196 205 hgserve.repo.ui.setconfig('rhodecode_extras', k, v)
197 206
198 207 repoui = make_ui('file', hgrc, False)
199 208
200 209 if repoui:
201 210 #overwrite our ui instance with the section from hgrc file
202 211 for section in ui_sections:
203 212 for k, v in repoui.configitems(section):
204 213 hgserve.repo.ui.setconfig(section, k, v)
205 214
206 215 return hgserve
207 216
208 217
209 218
210 219
211 220
212 221
213 222
214 223
215 224
216 225
217 226
218 227
219 228
220 229
@@ -1,585 +1,508 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # Utilities for RhodeCode
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 # This program is free software; you can redistribute it and/or
6 6 # modify it under the terms of the GNU General Public License
7 7 # as published by the Free Software Foundation; version 2
8 8 # of the License or (at your opinion) any later version of the license.
9 9 #
10 10 # This program is distributed in the hope that it will be useful,
11 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 # GNU General Public License for more details.
14 14 #
15 15 # You should have received a copy of the GNU General Public License
16 16 # along with this program; if not, write to the Free Software
17 17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 18 # MA 02110-1301, USA.
19 19 """
20 20 Created on April 18, 2010
21 21 Utilities for RhodeCode
22 22 @author: marcink
23 23 """
24 24
25 25 from UserDict import DictMixin
26 26 from mercurial import ui, config, hg
27 27 from mercurial.error import RepoError
28 28 from rhodecode.model import meta
29 29 from rhodecode.model.caching_query import FromCache
30 from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, \
31 UserLog
30 from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog
32 31 from rhodecode.model.repo import RepoModel
33 32 from rhodecode.model.user import UserModel
33
34 34 from vcs.backends.base import BaseChangeset
35 35 from paste.script import command
36 36 import ConfigParser
37 37 from vcs.utils.lazy import LazyProperty
38 38 import traceback
39 39 import datetime
40 40 import logging
41 41 import os
42 42
43 43 log = logging.getLogger(__name__)
44 44
45 45
46 46 def get_repo_slug(request):
47 47 return request.environ['pylons.routes_dict'].get('repo_name')
48 48
49 def is_mercurial(environ):
50 """
51 Returns True if request's target is mercurial server - header
52 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
53 """
54 http_accept = environ.get('HTTP_ACCEPT')
55 if http_accept and http_accept.startswith('application/mercurial'):
56 return True
57 return False
58
59 def is_git(environ):
60 """
61 Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
62 then have git client version given.
63
64 :param environ:
65 """
66 http_user_agent = environ.get('HTTP_USER_AGENT')
67 if http_user_agent and http_user_agent.startswith('git'):
68 return True
69 return False
70
71 49 def action_logger(user, action, repo, ipaddr='', sa=None):
72 50 """
73 51 Action logger for various actions made by users
74 52
75 53 :param user: user that made this action, can be a unique username string or
76 54 object containing user_id attribute
77 55 :param action: action to log, should be on of predefined unique actions for
78 56 easy translations
79 57 :param repo: string name of repository or object containing repo_id,
80 58 that action was made on
81 59 :param ipaddr: optional ip address from what the action was made
82 60 :param sa: optional sqlalchemy session
83 61
84 62 """
85 63
86 64 if not sa:
87 65 sa = meta.Session()
88 66
89 67 try:
90 68 um = UserModel()
91 69 if hasattr(user, 'user_id'):
92 70 user_obj = user
93 71 elif isinstance(user, basestring):
94 72 user_obj = um.get_by_username(user, cache=False)
95 73 else:
96 74 raise Exception('You have to provide user object or username')
97 75
98 76
99 77 rm = RepoModel()
100 78 if hasattr(repo, 'repo_id'):
101 79 repo_obj = rm.get(repo.repo_id, cache=False)
102 80 repo_name = repo_obj.repo_name
103 81 elif isinstance(repo, basestring):
104 82 repo_name = repo.lstrip('/')
105 83 repo_obj = rm.get_by_repo_name(repo_name, cache=False)
106 84 else:
107 85 raise Exception('You have to provide repository to action logger')
108 86
109 87
110 88 user_log = UserLog()
111 89 user_log.user_id = user_obj.user_id
112 90 user_log.action = action
113
91
114 92 user_log.repository_id = repo_obj.repo_id
115 93 user_log.repository_name = repo_name
116
94
117 95 user_log.action_date = datetime.datetime.now()
118 96 user_log.user_ip = ipaddr
119 97 sa.add(user_log)
120 98 sa.commit()
121 99
122 log.info('Adding user %s, action %s on %s',
123 user_obj.username, action, repo)
100 log.info('Adding user %s, action %s on %s', user_obj, action, repo)
124 101 except:
125 102 log.error(traceback.format_exc())
126 103 sa.rollback()
127 104
128 105 def get_repos(path, recursive=False, initial=False):
129 106 """
130 107 Scans given path for repos and return (name,(type,path)) tuple
131 108 :param prefix:
132 109 :param path:
133 110 :param recursive:
134 111 :param initial:
135 112 """
136 113 from vcs.utils.helpers import get_scm
137 114 from vcs.exceptions import VCSError
138 115
139 116 try:
140 117 scm = get_scm(path)
141 118 except:
142 119 pass
143 120 else:
144 121 raise Exception('The given path %s should not be a repository got %s',
145 122 path, scm)
146 123
147 124 for dirpath in os.listdir(path):
148 125 try:
149 126 yield dirpath, get_scm(os.path.join(path, dirpath))
150 127 except VCSError:
151 128 pass
152 129
153 if __name__ == '__main__':
154 get_repos('', '/home/marcink/workspace-python')
155
156
157 130 def check_repo_fast(repo_name, base_path):
158 131 if os.path.isdir(os.path.join(base_path, repo_name)):return False
159 132 return True
160 133
161 134 def check_repo(repo_name, base_path, verify=True):
162 135
163 136 repo_path = os.path.join(base_path, repo_name)
164 137
165 138 try:
166 139 if not check_repo_fast(repo_name, base_path):
167 140 return False
168 141 r = hg.repository(ui.ui(), repo_path)
169 142 if verify:
170 143 hg.verify(r)
171 144 #here we hnow that repo exists it was verified
172 145 log.info('%s repo is already created', repo_name)
173 146 return False
174 147 except RepoError:
175 148 #it means that there is no valid repo there...
176 149 log.info('%s repo is free for creation', repo_name)
177 150 return True
178 151
179 152 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
180 153 while True:
181 154 ok = raw_input(prompt)
182 155 if ok in ('y', 'ye', 'yes'): return True
183 156 if ok in ('n', 'no', 'nop', 'nope'): return False
184 157 retries = retries - 1
185 158 if retries < 0: raise IOError
186 159 print complaint
187 160
188 def get_hg_ui_cached():
189 try:
190 sa = meta.Session
191 ret = sa.query(RhodeCodeUi)\
192 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
193 .all()
194 except:
195 pass
196 finally:
197 meta.Session.remove()
198 return ret
199
200
201 def get_hg_settings():
202 try:
203 sa = meta.Session()
204 ret = sa.query(RhodeCodeSettings)\
205 .options(FromCache("sql_cache_short", "get_hg_settings"))\
206 .all()
207 except:
208 pass
209 finally:
210 meta.Session.remove()
211
212 if not ret:
213 raise Exception('Could not get application settings !')
214 settings = {}
215 for each in ret:
216 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
217
218 return settings
219
220 def get_hg_ui_settings():
221 try:
222 sa = meta.Session()
223 ret = sa.query(RhodeCodeUi).all()
224 except:
225 pass
226 finally:
227 meta.Session.remove()
228
229 if not ret:
230 raise Exception('Could not get application ui settings !')
231 settings = {}
232 for each in ret:
233 k = each.ui_key
234 v = each.ui_value
235 if k == '/':
236 k = 'root_path'
237
238 if k.find('.') != -1:
239 k = k.replace('.', '_')
240
241 if each.ui_section == 'hooks':
242 v = each.ui_active
243
244 settings[each.ui_section + '_' + k] = v
245
246 return settings
247
248 161 #propagated from mercurial documentation
249 162 ui_sections = ['alias', 'auth',
250 163 'decode/encode', 'defaults',
251 164 'diff', 'email',
252 165 'extensions', 'format',
253 166 'merge-patterns', 'merge-tools',
254 167 'hooks', 'http_proxy',
255 168 'smtp', 'patch',
256 169 'paths', 'profiling',
257 170 'server', 'trusted',
258 171 'ui', 'web', ]
259 172
260 173 def make_ui(read_from='file', path=None, checkpaths=True):
261 174 """
262 175 A function that will read python rc files or database
263 176 and make an mercurial ui object from read options
264 177
265 178 :param path: path to mercurial config file
266 179 :param checkpaths: check the path
267 180 :param read_from: read from 'file' or 'db'
268 181 """
269 182
270 183 baseui = ui.ui()
271 184
272 185 #clean the baseui object
273 186 baseui._ocfg = config.config()
274 187 baseui._ucfg = config.config()
275 188 baseui._tcfg = config.config()
276 189
277 190 if read_from == 'file':
278 191 if not os.path.isfile(path):
279 192 log.warning('Unable to read config file %s' % path)
280 193 return False
281 194 log.debug('reading hgrc from %s', path)
282 195 cfg = config.config()
283 196 cfg.read(path)
284 197 for section in ui_sections:
285 198 for k, v in cfg.items(section):
286 199 log.debug('settings ui from file[%s]%s:%s', section, k, v)
287 200 baseui.setconfig(section, k, v)
288 201
289 202
290 203 elif read_from == 'db':
291 hg_ui = get_hg_ui_cached()
204 sa = meta.Session()
205 ret = sa.query(RhodeCodeUi)\
206 .options(FromCache("sql_cache_short",
207 "get_hg_ui_settings")).all()
208 meta.Session.remove()
209 hg_ui = ret
292 210 for ui_ in hg_ui:
293 211 if ui_.ui_active:
294 212 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
295 213 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
296 214 return baseui
297 215
298 216
299 217 def set_rhodecode_config(config):
300 hgsettings = get_hg_settings()
218 """
219 Updates pylons config with new settings from database
220 :param config:
221 """
222 from rhodecode.model.settings import SettingsModel
223 hgsettings = SettingsModel().get_app_settings()
301 224
302 225 for k, v in hgsettings.items():
303 226 config[k] = v
304 227
305 228 def invalidate_cache(cache_key, *args):
306 229 """
307 230 Puts cache invalidation task into db for
308 231 further global cache invalidation
309 232 """
310 233 from rhodecode.model.scm import ScmModel
311 234
312 235 if cache_key.startswith('get_repo_cached_'):
313 236 name = cache_key.split('get_repo_cached_')[-1]
314 237 ScmModel().mark_for_invalidation(name)
315 238
316 239 class EmptyChangeset(BaseChangeset):
317 240 """
318 241 An dummy empty changeset. It's possible to pass hash when creating
319 242 an EmptyChangeset
320 243 """
321 244
322 245 def __init__(self, cs='0' * 40):
323 246 self._empty_cs = cs
324 247 self.revision = -1
325 248 self.message = ''
326 249 self.author = ''
327 250 self.date = ''
328 251
329 252 @LazyProperty
330 253 def raw_id(self):
331 254 """
332 255 Returns raw string identifying this changeset, useful for web
333 256 representation.
334 257 """
335 258 return self._empty_cs
336 259
337 260 @LazyProperty
338 261 def short_id(self):
339 262 return self.raw_id[:12]
340 263
341 264 def get_file_changeset(self, path):
342 265 return self
343 266
344 267 def get_file_content(self, path):
345 268 return u''
346 269
347 270 def get_file_size(self, path):
348 271 return 0
349 272
350 273 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
351 274 """
352 275 maps all found repositories into db
353 276 """
354 277
355 278 sa = meta.Session()
356 279 rm = RepoModel()
357 280 user = sa.query(User).filter(User.admin == True).first()
358 281
359 282 for name, repo in initial_repo_list.items():
360 283 if not rm.get_by_repo_name(name, cache=False):
361 284 log.info('repository %s not found creating default', name)
362 285
363 286 form_data = {
364 287 'repo_name':name,
365 288 'repo_type':repo.alias,
366 289 'description':repo.description \
367 290 if repo.description != 'unknown' else \
368 291 '%s repository' % name,
369 292 'private':False
370 293 }
371 294 rm.create(form_data, user, just_db=True)
372 295
373 296 if remove_obsolete:
374 297 #remove from database those repositories that are not in the filesystem
375 298 for repo in sa.query(Repository).all():
376 299 if repo.repo_name not in initial_repo_list.keys():
377 300 sa.delete(repo)
378 301 sa.commit()
379 302
380 303 class OrderedDict(dict, DictMixin):
381 304
382 305 def __init__(self, *args, **kwds):
383 306 if len(args) > 1:
384 307 raise TypeError('expected at most 1 arguments, got %d' % len(args))
385 308 try:
386 309 self.__end
387 310 except AttributeError:
388 311 self.clear()
389 312 self.update(*args, **kwds)
390 313
391 314 def clear(self):
392 315 self.__end = end = []
393 316 end += [None, end, end] # sentinel node for doubly linked list
394 317 self.__map = {} # key --> [key, prev, next]
395 318 dict.clear(self)
396 319
397 320 def __setitem__(self, key, value):
398 321 if key not in self:
399 322 end = self.__end
400 323 curr = end[1]
401 324 curr[2] = end[1] = self.__map[key] = [key, curr, end]
402 325 dict.__setitem__(self, key, value)
403 326
404 327 def __delitem__(self, key):
405 328 dict.__delitem__(self, key)
406 329 key, prev, next = self.__map.pop(key)
407 330 prev[2] = next
408 331 next[1] = prev
409 332
410 333 def __iter__(self):
411 334 end = self.__end
412 335 curr = end[2]
413 336 while curr is not end:
414 337 yield curr[0]
415 338 curr = curr[2]
416 339
417 340 def __reversed__(self):
418 341 end = self.__end
419 342 curr = end[1]
420 343 while curr is not end:
421 344 yield curr[0]
422 345 curr = curr[1]
423 346
424 347 def popitem(self, last=True):
425 348 if not self:
426 349 raise KeyError('dictionary is empty')
427 350 if last:
428 351 key = reversed(self).next()
429 352 else:
430 353 key = iter(self).next()
431 354 value = self.pop(key)
432 355 return key, value
433 356
434 357 def __reduce__(self):
435 358 items = [[k, self[k]] for k in self]
436 359 tmp = self.__map, self.__end
437 360 del self.__map, self.__end
438 361 inst_dict = vars(self).copy()
439 362 self.__map, self.__end = tmp
440 363 if inst_dict:
441 364 return (self.__class__, (items,), inst_dict)
442 365 return self.__class__, (items,)
443 366
444 367 def keys(self):
445 368 return list(self)
446 369
447 370 setdefault = DictMixin.setdefault
448 371 update = DictMixin.update
449 372 pop = DictMixin.pop
450 373 values = DictMixin.values
451 374 items = DictMixin.items
452 375 iterkeys = DictMixin.iterkeys
453 376 itervalues = DictMixin.itervalues
454 377 iteritems = DictMixin.iteritems
455 378
456 379 def __repr__(self):
457 380 if not self:
458 381 return '%s()' % (self.__class__.__name__,)
459 382 return '%s(%r)' % (self.__class__.__name__, self.items())
460 383
461 384 def copy(self):
462 385 return self.__class__(self)
463 386
464 387 @classmethod
465 388 def fromkeys(cls, iterable, value=None):
466 389 d = cls()
467 390 for key in iterable:
468 391 d[key] = value
469 392 return d
470 393
471 394 def __eq__(self, other):
472 395 if isinstance(other, OrderedDict):
473 396 return len(self) == len(other) and self.items() == other.items()
474 397 return dict.__eq__(self, other)
475 398
476 399 def __ne__(self, other):
477 400 return not self == other
478 401
479 402
480 403 #===============================================================================
481 404 # TEST FUNCTIONS AND CREATORS
482 405 #===============================================================================
483 406 def create_test_index(repo_location, full_index):
484 407 """Makes default test index
485 408 :param repo_location:
486 409 :param full_index:
487 410 """
488 411 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
489 412 from rhodecode.lib.pidlock import DaemonLock, LockHeld
490 413 import shutil
491 414
492 415 index_location = os.path.join(repo_location, 'index')
493 416 if os.path.exists(index_location):
494 417 shutil.rmtree(index_location)
495 418
496 419 try:
497 420 l = DaemonLock()
498 421 WhooshIndexingDaemon(index_location=index_location,
499 422 repo_location=repo_location)\
500 423 .run(full_index=full_index)
501 424 l.release()
502 425 except LockHeld:
503 426 pass
504 427
505 428 def create_test_env(repos_test_path, config):
506 429 """Makes a fresh database and
507 430 install test repository into tmp dir
508 431 """
509 432 from rhodecode.lib.db_manage import DbManage
510 433 from rhodecode.tests import HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, \
511 434 HG_FORK, GIT_FORK, TESTS_TMP_PATH
512 435 import tarfile
513 436 import shutil
514 437 from os.path import dirname as dn, join as jn, abspath
515 438
516 439 log = logging.getLogger('TestEnvCreator')
517 440 # create logger
518 441 log.setLevel(logging.DEBUG)
519 442 log.propagate = True
520 443 # create console handler and set level to debug
521 444 ch = logging.StreamHandler()
522 445 ch.setLevel(logging.DEBUG)
523 446
524 447 # create formatter
525 448 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
526 449
527 450 # add formatter to ch
528 451 ch.setFormatter(formatter)
529 452
530 453 # add ch to logger
531 454 log.addHandler(ch)
532 455
533 456 #PART ONE create db
534 457 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
535 458 log.debug('making test db %s', dbname)
536 459
537 460 dbmanage = DbManage(log_sql=True, dbname=dbname, root=config['here'],
538 461 tests=True)
539 462 dbmanage.create_tables(override=True)
540 463 dbmanage.config_prompt(repos_test_path)
541 464 dbmanage.create_default_user()
542 465 dbmanage.admin_prompt()
543 466 dbmanage.create_permissions()
544 467 dbmanage.populate_default_permissions()
545 468
546 469 #PART TWO make test repo
547 470 log.debug('making test vcs repositories')
548 471
549 472 #remove old one from previos tests
550 473 for r in [HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, HG_FORK, GIT_FORK]:
551 474
552 475 if os.path.isdir(jn(TESTS_TMP_PATH, r)):
553 476 log.debug('removing %s', r)
554 477 shutil.rmtree(jn(TESTS_TMP_PATH, r))
555 478
556 479 #CREATE DEFAULT HG REPOSITORY
557 480 cur_dir = dn(dn(abspath(__file__)))
558 481 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
559 482 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
560 483 tar.close()
561 484
562 485 class UpgradeDb(command.Command):
563 486 """Command used for paster to upgrade our database to newer version
564 487 """
565 488
566 489 max_args = 1
567 490 min_args = 1
568 491
569 492 usage = "CONFIG_FILE"
570 493 summary = "Upgrades current db to newer version given configuration file"
571 494 group_name = "RhodeCode"
572 495
573 496 parser = command.Command.standard_parser(verbose=True)
574 497
575 498 parser.add_option('--sql',
576 499 action='store_true',
577 500 dest='just_sql',
578 501 help="Prints upgrade sql for further investigation",
579 502 default=False)
580 503 def command(self):
581 504 config_name = self.args[0]
582 505 p = config_name.split('/')
583 506 root = '.' if len(p) == 1 else '/'.join(p[:-1])
584 507 config = ConfigParser.ConfigParser({'here':root})
585 508 config.read(config_name)
@@ -1,76 +1,87 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # Model for RhodeCode settings
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on Nov 17, 2010
22 22 Model for RhodeCode
23 23 :author: marcink
24 24 """
25 25
26 26 from rhodecode.lib import helpers as h
27 27 from rhodecode.model import BaseModel
28 28 from rhodecode.model.caching_query import FromCache
29 29 from rhodecode.model.db import RhodeCodeSettings
30 30 from sqlalchemy.orm import joinedload
31 from sqlalchemy.orm.session import make_transient
32 31 import logging
33 32
34 33 log = logging.getLogger(__name__)
35 34
36 35 class SettingsModel(BaseModel):
37 36 """
38 37 Settings model
39 38 """
40 39
41 40 def get(self, settings_key, cache=False):
42 41 r = self.sa.query(RhodeCodeSettings)\
43 42 .filter(RhodeCodeSettings.app_settings_name == settings_key).scalar()
44 43 if cache:
45 44 r = r.options(FromCache("sql_cache_short",
46 45 "get_setting_%s" % settings_key))
47 46 return r
48 47
48 def get_app_settings(self):
49 ret = self.sa.query(RhodeCodeSettings)\
50 .options(FromCache("sql_cache_short",
51 "get_hg_settings")).all()
52
53 if not ret:
54 raise Exception('Could not get application settings !')
55 settings = {}
56 for each in ret:
57 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
58
59 return settings
49 60
50 61 def get_ldap_settings(self):
51 62 """
52 63 Returns ldap settings from database
53 64 :returns:
54 65 ldap_active
55 66 ldap_host
56 67 ldap_port
57 68 ldap_ldaps
58 69 ldap_dn_user
59 70 ldap_dn_pass
60 71 ldap_base_dn
61 72 """
62 73
63 74 r = self.sa.query(RhodeCodeSettings)\
64 75 .filter(RhodeCodeSettings.app_settings_name\
65 76 .startswith('ldap_'))\
66 77 .all()
67 78
68 79 fd = {}
69 80
70 81 for row in r:
71 82 v = row.app_settings_value
72 83 if v in ['0', '1']:
73 84 v = v == '1'
74 85 fd.update({row.app_settings_name:v})
75 86
76 87 return fd
General Comments 0
You need to be logged in to leave comments. Login now