##// END OF EJS Templates
Add git version detection to warn users that Git used in system is to old. ref #588...
marcink -
r2890:84414d73 beta
parent child Browse files
Show More
@@ -1,106 +1,109
1 """Pylons environment configuration"""
1 """Pylons environment configuration"""
2
2
3 import os
3 import os
4 import logging
4 import logging
5 import rhodecode
5 import rhodecode
6
6
7 from mako.lookup import TemplateLookup
7 from mako.lookup import TemplateLookup
8 from pylons.configuration import PylonsConfig
8 from pylons.configuration import PylonsConfig
9 from pylons.error import handle_mako_error
9 from pylons.error import handle_mako_error
10
10
11 # don't remove this import it does magic for celery
11 # don't remove this import it does magic for celery
12 from rhodecode.lib import celerypylons
12 from rhodecode.lib import celerypylons
13
13
14 import rhodecode.lib.app_globals as app_globals
14 import rhodecode.lib.app_globals as app_globals
15
15
16 from rhodecode.config.routing import make_map
16 from rhodecode.config.routing import make_map
17
17
18 from rhodecode.lib import helpers
18 from rhodecode.lib import helpers
19 from rhodecode.lib.auth import set_available_permissions
19 from rhodecode.lib.auth import set_available_permissions
20 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config,\
20 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config,\
21 load_rcextensions
21 load_rcextensions, check_git_version
22 from rhodecode.lib.utils2 import engine_from_config, str2bool
22 from rhodecode.lib.utils2 import engine_from_config, str2bool
23 from rhodecode.model import init_model
23 from rhodecode.model import init_model
24 from rhodecode.model.scm import ScmModel
24 from rhodecode.model.scm import ScmModel
25
25
26 log = logging.getLogger(__name__)
26 log = logging.getLogger(__name__)
27
27
28
28
29 def load_environment(global_conf, app_conf, initial=False):
29 def load_environment(global_conf, app_conf, initial=False):
30 """
30 """
31 Configure the Pylons environment via the ``pylons.config``
31 Configure the Pylons environment via the ``pylons.config``
32 object
32 object
33 """
33 """
34 config = PylonsConfig()
34 config = PylonsConfig()
35
35
36 # Pylons paths
36 # Pylons paths
37 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
37 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
38 paths = dict(
38 paths = dict(
39 root=root,
39 root=root,
40 controllers=os.path.join(root, 'controllers'),
40 controllers=os.path.join(root, 'controllers'),
41 static_files=os.path.join(root, 'public'),
41 static_files=os.path.join(root, 'public'),
42 templates=[os.path.join(root, 'templates')]
42 templates=[os.path.join(root, 'templates')]
43 )
43 )
44
44
45 # Initialize config with the basic options
45 # Initialize config with the basic options
46 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
46 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
47
47
48 # store some globals into rhodecode
48 # store some globals into rhodecode
49 rhodecode.CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
49 rhodecode.CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
50 rhodecode.CELERY_EAGER = str2bool(config['app_conf'].get('celery.always.eager'))
50 rhodecode.CELERY_EAGER = str2bool(config['app_conf'].get('celery.always.eager'))
51
51
52 config['routes.map'] = make_map(config)
52 config['routes.map'] = make_map(config)
53 config['pylons.app_globals'] = app_globals.Globals(config)
53 config['pylons.app_globals'] = app_globals.Globals(config)
54 config['pylons.h'] = helpers
54 config['pylons.h'] = helpers
55 rhodecode.CONFIG = config
55 rhodecode.CONFIG = config
56
56
57 load_rcextensions(root_path=config['here'])
57 load_rcextensions(root_path=config['here'])
58
58
59 # Setup cache object as early as possible
59 # Setup cache object as early as possible
60 import pylons
60 import pylons
61 pylons.cache._push_object(config['pylons.app_globals'].cache)
61 pylons.cache._push_object(config['pylons.app_globals'].cache)
62
62
63 # Create the Mako TemplateLookup, with the default auto-escaping
63 # Create the Mako TemplateLookup, with the default auto-escaping
64 config['pylons.app_globals'].mako_lookup = TemplateLookup(
64 config['pylons.app_globals'].mako_lookup = TemplateLookup(
65 directories=paths['templates'],
65 directories=paths['templates'],
66 error_handler=handle_mako_error,
66 error_handler=handle_mako_error,
67 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
67 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
68 input_encoding='utf-8', default_filters=['escape'],
68 input_encoding='utf-8', default_filters=['escape'],
69 imports=['from webhelpers.html import escape'])
69 imports=['from webhelpers.html import escape'])
70
70
71 # sets the c attribute access when don't existing attribute are accessed
71 # sets the c attribute access when don't existing attribute are accessed
72 config['pylons.strict_tmpl_context'] = True
72 config['pylons.strict_tmpl_context'] = True
73 test = os.path.split(config['__file__'])[-1] == 'test.ini'
73 test = os.path.split(config['__file__'])[-1] == 'test.ini'
74 if test:
74 if test:
75 if os.environ.get('TEST_DB'):
75 if os.environ.get('TEST_DB'):
76 # swap config if we pass enviroment variable
76 # swap config if we pass enviroment variable
77 config['sqlalchemy.db1.url'] = os.environ.get('TEST_DB')
77 config['sqlalchemy.db1.url'] = os.environ.get('TEST_DB')
78
78
79 from rhodecode.lib.utils import create_test_env, create_test_index
79 from rhodecode.lib.utils import create_test_env, create_test_index
80 from rhodecode.tests import TESTS_TMP_PATH
80 from rhodecode.tests import TESTS_TMP_PATH
81 # set RC_NO_TMP_PATH=1 to disable re-creating the database and
81 # set RC_NO_TMP_PATH=1 to disable re-creating the database and
82 # test repos
82 # test repos
83 if not int(os.environ.get('RC_NO_TMP_PATH', 0)):
83 if not int(os.environ.get('RC_NO_TMP_PATH', 0)):
84 create_test_env(TESTS_TMP_PATH, config)
84 create_test_env(TESTS_TMP_PATH, config)
85 # set RC_WHOOSH_TEST_DISABLE=1 to disable whoosh index during tests
85 # set RC_WHOOSH_TEST_DISABLE=1 to disable whoosh index during tests
86 if not int(os.environ.get('RC_WHOOSH_TEST_DISABLE', 0)):
86 if not int(os.environ.get('RC_WHOOSH_TEST_DISABLE', 0)):
87 create_test_index(TESTS_TMP_PATH, config, True)
87 create_test_index(TESTS_TMP_PATH, config, True)
88
88
89 #check git version
90 check_git_version()
91
89 # MULTIPLE DB configs
92 # MULTIPLE DB configs
90 # Setup the SQLAlchemy database engine
93 # Setup the SQLAlchemy database engine
91 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.')
94 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.')
92 init_model(sa_engine_db1)
95 init_model(sa_engine_db1)
93
96
94 repos_path = make_ui('db').configitems('paths')[0][1]
97 repos_path = make_ui('db').configitems('paths')[0][1]
95 repo2db_mapper(ScmModel().repo_scan(repos_path),
98 repo2db_mapper(ScmModel().repo_scan(repos_path),
96 remove_obsolete=False, install_git_hook=False)
99 remove_obsolete=False, install_git_hook=False)
97 set_available_permissions(config)
100 set_available_permissions(config)
98 config['base_path'] = repos_path
101 config['base_path'] = repos_path
99 set_rhodecode_config(config)
102 set_rhodecode_config(config)
100 # CONFIGURATION OPTIONS HERE (note: all config options will override
103 # CONFIGURATION OPTIONS HERE (note: all config options will override
101 # any Pylons config options)
104 # any Pylons config options)
102
105
103 # store config reference into our module to skip import magic of
106 # store config reference into our module to skip import magic of
104 # pylons
107 # pylons
105 rhodecode.CONFIG.update(config)
108 rhodecode.CONFIG.update(config)
106 return config
109 return config
@@ -1,502 +1,503
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.settings
3 rhodecode.controllers.admin.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 settings controller for rhodecode admin
6 settings controller for rhodecode admin
7
7
8 :created_on: Jul 14, 2010
8 :created_on: Jul 14, 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 logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29 import pkg_resources
29 import pkg_resources
30 import platform
30 import platform
31
31
32 from sqlalchemy import func
32 from sqlalchemy import func
33 from formencode import htmlfill
33 from formencode import htmlfill
34 from pylons import request, session, tmpl_context as c, url, config
34 from pylons import request, session, tmpl_context as c, url, config
35 from pylons.controllers.util import abort, redirect
35 from pylons.controllers.util import abort, redirect
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 HasPermissionAnyDecorator, NotAnonymous
40 HasPermissionAnyDecorator, NotAnonymous
41 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.celerylib import tasks, run_task
42 from rhodecode.lib.celerylib import tasks, run_task
43 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
43 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
44 set_rhodecode_config, repo_name_slug
44 set_rhodecode_config, repo_name_slug, check_git_version
45 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
45 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
46 RhodeCodeSetting, PullRequest, PullRequestReviewers
46 RhodeCodeSetting, PullRequest, PullRequestReviewers
47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
48 ApplicationUiSettingsForm, ApplicationVisualisationForm
48 ApplicationUiSettingsForm, ApplicationVisualisationForm
49 from rhodecode.model.scm import ScmModel
49 from rhodecode.model.scm import ScmModel
50 from rhodecode.model.user import UserModel
50 from rhodecode.model.user import UserModel
51 from rhodecode.model.db import User
51 from rhodecode.model.db import User
52 from rhodecode.model.notification import EmailNotificationModel
52 from rhodecode.model.notification import EmailNotificationModel
53 from rhodecode.model.meta import Session
53 from rhodecode.model.meta import Session
54 from rhodecode.lib.utils2 import str2bool
54 from rhodecode.lib.utils2 import str2bool
55
55
56 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
57
57
58
58
59 class SettingsController(BaseController):
59 class SettingsController(BaseController):
60 """REST Controller styled on the Atom Publishing Protocol"""
60 """REST Controller styled on the Atom Publishing Protocol"""
61 # To properly map this controller, ensure your config/routing.py
61 # To properly map this controller, ensure your config/routing.py
62 # file has a resource setup:
62 # file has a resource setup:
63 # map.resource('setting', 'settings', controller='admin/settings',
63 # map.resource('setting', 'settings', controller='admin/settings',
64 # path_prefix='/admin', name_prefix='admin_')
64 # path_prefix='/admin', name_prefix='admin_')
65
65
66 @LoginRequired()
66 @LoginRequired()
67 def __before__(self):
67 def __before__(self):
68 c.admin_user = session.get('admin_user')
68 c.admin_user = session.get('admin_user')
69 c.admin_username = session.get('admin_username')
69 c.admin_username = session.get('admin_username')
70 c.modules = sorted([(p.project_name, p.version)
70 c.modules = sorted([(p.project_name, p.version)
71 for p in pkg_resources.working_set],
71 for p in pkg_resources.working_set]
72 + [('git', check_git_version())],
72 key=lambda k: k[0].lower())
73 key=lambda k: k[0].lower())
73 c.py_version = platform.python_version()
74 c.py_version = platform.python_version()
74 c.platform = platform.platform()
75 c.platform = platform.platform()
75 super(SettingsController, self).__before__()
76 super(SettingsController, self).__before__()
76
77
77 @HasPermissionAllDecorator('hg.admin')
78 @HasPermissionAllDecorator('hg.admin')
78 def index(self, format='html'):
79 def index(self, format='html'):
79 """GET /admin/settings: All items in the collection"""
80 """GET /admin/settings: All items in the collection"""
80 # url('admin_settings')
81 # url('admin_settings')
81
82
82 defaults = RhodeCodeSetting.get_app_settings()
83 defaults = RhodeCodeSetting.get_app_settings()
83 defaults.update(self._get_hg_ui_settings())
84 defaults.update(self._get_hg_ui_settings())
84
85
85 return htmlfill.render(
86 return htmlfill.render(
86 render('admin/settings/settings.html'),
87 render('admin/settings/settings.html'),
87 defaults=defaults,
88 defaults=defaults,
88 encoding="UTF-8",
89 encoding="UTF-8",
89 force_defaults=False
90 force_defaults=False
90 )
91 )
91
92
92 @HasPermissionAllDecorator('hg.admin')
93 @HasPermissionAllDecorator('hg.admin')
93 def create(self):
94 def create(self):
94 """POST /admin/settings: Create a new item"""
95 """POST /admin/settings: Create a new item"""
95 # url('admin_settings')
96 # url('admin_settings')
96
97
97 @HasPermissionAllDecorator('hg.admin')
98 @HasPermissionAllDecorator('hg.admin')
98 def new(self, format='html'):
99 def new(self, format='html'):
99 """GET /admin/settings/new: Form to create a new item"""
100 """GET /admin/settings/new: Form to create a new item"""
100 # url('admin_new_setting')
101 # url('admin_new_setting')
101
102
102 @HasPermissionAllDecorator('hg.admin')
103 @HasPermissionAllDecorator('hg.admin')
103 def update(self, setting_id):
104 def update(self, setting_id):
104 """PUT /admin/settings/setting_id: Update an existing item"""
105 """PUT /admin/settings/setting_id: Update an existing item"""
105 # Forms posted to this method should contain a hidden field:
106 # Forms posted to this method should contain a hidden field:
106 # <input type="hidden" name="_method" value="PUT" />
107 # <input type="hidden" name="_method" value="PUT" />
107 # Or using helpers:
108 # Or using helpers:
108 # h.form(url('admin_setting', setting_id=ID),
109 # h.form(url('admin_setting', setting_id=ID),
109 # method='put')
110 # method='put')
110 # url('admin_setting', setting_id=ID)
111 # url('admin_setting', setting_id=ID)
111
112
112 if setting_id == 'mapping':
113 if setting_id == 'mapping':
113 rm_obsolete = request.POST.get('destroy', False)
114 rm_obsolete = request.POST.get('destroy', False)
114 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
115 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
115 initial = ScmModel().repo_scan()
116 initial = ScmModel().repo_scan()
116 log.debug('invalidating all repositories')
117 log.debug('invalidating all repositories')
117 for repo_name in initial.keys():
118 for repo_name in initial.keys():
118 invalidate_cache('get_repo_cached_%s' % repo_name)
119 invalidate_cache('get_repo_cached_%s' % repo_name)
119
120
120 added, removed = repo2db_mapper(initial, rm_obsolete)
121 added, removed = repo2db_mapper(initial, rm_obsolete)
121
122
122 h.flash(_('Repositories successfully'
123 h.flash(_('Repositories successfully'
123 ' rescanned added: %s,removed: %s') % (added, removed),
124 ' rescanned added: %s,removed: %s') % (added, removed),
124 category='success')
125 category='success')
125
126
126 if setting_id == 'whoosh':
127 if setting_id == 'whoosh':
127 repo_location = self._get_hg_ui_settings()['paths_root_path']
128 repo_location = self._get_hg_ui_settings()['paths_root_path']
128 full_index = request.POST.get('full_index', False)
129 full_index = request.POST.get('full_index', False)
129 run_task(tasks.whoosh_index, repo_location, full_index)
130 run_task(tasks.whoosh_index, repo_location, full_index)
130 h.flash(_('Whoosh reindex task scheduled'), category='success')
131 h.flash(_('Whoosh reindex task scheduled'), category='success')
131
132
132 if setting_id == 'global':
133 if setting_id == 'global':
133
134
134 application_form = ApplicationSettingsForm()()
135 application_form = ApplicationSettingsForm()()
135 try:
136 try:
136 form_result = application_form.to_python(dict(request.POST))
137 form_result = application_form.to_python(dict(request.POST))
137 except formencode.Invalid, errors:
138 except formencode.Invalid, errors:
138 return htmlfill.render(
139 return htmlfill.render(
139 render('admin/settings/settings.html'),
140 render('admin/settings/settings.html'),
140 defaults=errors.value,
141 defaults=errors.value,
141 errors=errors.error_dict or {},
142 errors=errors.error_dict or {},
142 prefix_error=False,
143 prefix_error=False,
143 encoding="UTF-8"
144 encoding="UTF-8"
144 )
145 )
145
146
146 try:
147 try:
147 sett1 = RhodeCodeSetting.get_by_name_or_create('title')
148 sett1 = RhodeCodeSetting.get_by_name_or_create('title')
148 sett1.app_settings_value = form_result['rhodecode_title']
149 sett1.app_settings_value = form_result['rhodecode_title']
149 Session().add(sett1)
150 Session().add(sett1)
150
151
151 sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
152 sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
152 sett2.app_settings_value = form_result['rhodecode_realm']
153 sett2.app_settings_value = form_result['rhodecode_realm']
153 Session().add(sett2)
154 Session().add(sett2)
154
155
155 sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
156 sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
156 sett3.app_settings_value = form_result['rhodecode_ga_code']
157 sett3.app_settings_value = form_result['rhodecode_ga_code']
157 Session().add(sett3)
158 Session().add(sett3)
158
159
159 Session().commit()
160 Session().commit()
160 set_rhodecode_config(config)
161 set_rhodecode_config(config)
161 h.flash(_('Updated application settings'), category='success')
162 h.flash(_('Updated application settings'), category='success')
162
163
163 except Exception:
164 except Exception:
164 log.error(traceback.format_exc())
165 log.error(traceback.format_exc())
165 h.flash(_('error occurred during updating '
166 h.flash(_('error occurred during updating '
166 'application settings'),
167 'application settings'),
167 category='error')
168 category='error')
168
169
169 if setting_id == 'visual':
170 if setting_id == 'visual':
170
171
171 application_form = ApplicationVisualisationForm()()
172 application_form = ApplicationVisualisationForm()()
172 try:
173 try:
173 form_result = application_form.to_python(dict(request.POST))
174 form_result = application_form.to_python(dict(request.POST))
174 except formencode.Invalid, errors:
175 except formencode.Invalid, errors:
175 return htmlfill.render(
176 return htmlfill.render(
176 render('admin/settings/settings.html'),
177 render('admin/settings/settings.html'),
177 defaults=errors.value,
178 defaults=errors.value,
178 errors=errors.error_dict or {},
179 errors=errors.error_dict or {},
179 prefix_error=False,
180 prefix_error=False,
180 encoding="UTF-8"
181 encoding="UTF-8"
181 )
182 )
182
183
183 try:
184 try:
184 sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
185 sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
185 sett1.app_settings_value = \
186 sett1.app_settings_value = \
186 form_result['rhodecode_show_public_icon']
187 form_result['rhodecode_show_public_icon']
187
188
188 sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
189 sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
189 sett2.app_settings_value = \
190 sett2.app_settings_value = \
190 form_result['rhodecode_show_private_icon']
191 form_result['rhodecode_show_private_icon']
191
192
192 sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
193 sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
193 sett3.app_settings_value = \
194 sett3.app_settings_value = \
194 form_result['rhodecode_stylify_metatags']
195 form_result['rhodecode_stylify_metatags']
195
196
196 Session().add(sett1)
197 Session().add(sett1)
197 Session().add(sett2)
198 Session().add(sett2)
198 Session().add(sett3)
199 Session().add(sett3)
199 Session().commit()
200 Session().commit()
200 set_rhodecode_config(config)
201 set_rhodecode_config(config)
201 h.flash(_('Updated visualisation settings'),
202 h.flash(_('Updated visualisation settings'),
202 category='success')
203 category='success')
203
204
204 except Exception:
205 except Exception:
205 log.error(traceback.format_exc())
206 log.error(traceback.format_exc())
206 h.flash(_('error occurred during updating '
207 h.flash(_('error occurred during updating '
207 'visualisation settings'),
208 'visualisation settings'),
208 category='error')
209 category='error')
209
210
210 if setting_id == 'vcs':
211 if setting_id == 'vcs':
211 application_form = ApplicationUiSettingsForm()()
212 application_form = ApplicationUiSettingsForm()()
212 try:
213 try:
213 form_result = application_form.to_python(dict(request.POST))
214 form_result = application_form.to_python(dict(request.POST))
214 except formencode.Invalid, errors:
215 except formencode.Invalid, errors:
215 return htmlfill.render(
216 return htmlfill.render(
216 render('admin/settings/settings.html'),
217 render('admin/settings/settings.html'),
217 defaults=errors.value,
218 defaults=errors.value,
218 errors=errors.error_dict or {},
219 errors=errors.error_dict or {},
219 prefix_error=False,
220 prefix_error=False,
220 encoding="UTF-8"
221 encoding="UTF-8"
221 )
222 )
222
223
223 try:
224 try:
224 # fix namespaces for hooks and extensions
225 # fix namespaces for hooks and extensions
225 _f = lambda s: s.replace('.', '_')
226 _f = lambda s: s.replace('.', '_')
226
227
227 sett = RhodeCodeUi.get_by_key('push_ssl')
228 sett = RhodeCodeUi.get_by_key('push_ssl')
228 sett.ui_value = form_result['web_push_ssl']
229 sett.ui_value = form_result['web_push_ssl']
229 Session().add(sett)
230 Session().add(sett)
230
231
231 sett = RhodeCodeUi.get_by_key('/')
232 sett = RhodeCodeUi.get_by_key('/')
232 sett.ui_value = form_result['paths_root_path']
233 sett.ui_value = form_result['paths_root_path']
233 Session().add(sett)
234 Session().add(sett)
234
235
235 #HOOKS
236 #HOOKS
236 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE)
237 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE)
237 sett.ui_active = form_result[_f('hooks_%s' %
238 sett.ui_active = form_result[_f('hooks_%s' %
238 RhodeCodeUi.HOOK_UPDATE)]
239 RhodeCodeUi.HOOK_UPDATE)]
239 Session().add(sett)
240 Session().add(sett)
240
241
241 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE)
242 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE)
242 sett.ui_active = form_result[_f('hooks_%s' %
243 sett.ui_active = form_result[_f('hooks_%s' %
243 RhodeCodeUi.HOOK_REPO_SIZE)]
244 RhodeCodeUi.HOOK_REPO_SIZE)]
244 Session().add(sett)
245 Session().add(sett)
245
246
246 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH)
247 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH)
247 sett.ui_active = form_result[_f('hooks_%s' %
248 sett.ui_active = form_result[_f('hooks_%s' %
248 RhodeCodeUi.HOOK_PUSH)]
249 RhodeCodeUi.HOOK_PUSH)]
249 Session().add(sett)
250 Session().add(sett)
250
251
251 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL)
252 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL)
252 sett.ui_active = form_result[_f('hooks_%s' %
253 sett.ui_active = form_result[_f('hooks_%s' %
253 RhodeCodeUi.HOOK_PULL)]
254 RhodeCodeUi.HOOK_PULL)]
254
255
255 Session().add(sett)
256 Session().add(sett)
256
257
257 ## EXTENSIONS
258 ## EXTENSIONS
258 sett = RhodeCodeUi.get_by_key('largefiles')
259 sett = RhodeCodeUi.get_by_key('largefiles')
259 if not sett:
260 if not sett:
260 #make one if it's not there !
261 #make one if it's not there !
261 sett = RhodeCodeUi()
262 sett = RhodeCodeUi()
262 sett.ui_key = 'largefiles'
263 sett.ui_key = 'largefiles'
263 sett.ui_section = 'extensions'
264 sett.ui_section = 'extensions'
264 sett.ui_active = form_result[_f('extensions_largefiles')]
265 sett.ui_active = form_result[_f('extensions_largefiles')]
265 Session().add(sett)
266 Session().add(sett)
266
267
267 sett = RhodeCodeUi.get_by_key('hgsubversion')
268 sett = RhodeCodeUi.get_by_key('hgsubversion')
268 if not sett:
269 if not sett:
269 #make one if it's not there !
270 #make one if it's not there !
270 sett = RhodeCodeUi()
271 sett = RhodeCodeUi()
271 sett.ui_key = 'hgsubversion'
272 sett.ui_key = 'hgsubversion'
272 sett.ui_section = 'extensions'
273 sett.ui_section = 'extensions'
273
274
274 sett.ui_active = form_result[_f('extensions_hgsubversion')]
275 sett.ui_active = form_result[_f('extensions_hgsubversion')]
275 Session().add(sett)
276 Session().add(sett)
276
277
277 # sett = RhodeCodeUi.get_by_key('hggit')
278 # sett = RhodeCodeUi.get_by_key('hggit')
278 # if not sett:
279 # if not sett:
279 # #make one if it's not there !
280 # #make one if it's not there !
280 # sett = RhodeCodeUi()
281 # sett = RhodeCodeUi()
281 # sett.ui_key = 'hggit'
282 # sett.ui_key = 'hggit'
282 # sett.ui_section = 'extensions'
283 # sett.ui_section = 'extensions'
283 #
284 #
284 # sett.ui_active = form_result[_f('extensions_hggit')]
285 # sett.ui_active = form_result[_f('extensions_hggit')]
285 # Session().add(sett)
286 # Session().add(sett)
286
287
287 Session().commit()
288 Session().commit()
288
289
289 h.flash(_('Updated VCS settings'), category='success')
290 h.flash(_('Updated VCS settings'), category='success')
290
291
291 except Exception:
292 except Exception:
292 log.error(traceback.format_exc())
293 log.error(traceback.format_exc())
293 h.flash(_('error occurred during updating '
294 h.flash(_('error occurred during updating '
294 'application settings'), category='error')
295 'application settings'), category='error')
295
296
296 if setting_id == 'hooks':
297 if setting_id == 'hooks':
297 ui_key = request.POST.get('new_hook_ui_key')
298 ui_key = request.POST.get('new_hook_ui_key')
298 ui_value = request.POST.get('new_hook_ui_value')
299 ui_value = request.POST.get('new_hook_ui_value')
299 try:
300 try:
300
301
301 if ui_value and ui_key:
302 if ui_value and ui_key:
302 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
303 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
303 h.flash(_('Added new hook'),
304 h.flash(_('Added new hook'),
304 category='success')
305 category='success')
305
306
306 # check for edits
307 # check for edits
307 update = False
308 update = False
308 _d = request.POST.dict_of_lists()
309 _d = request.POST.dict_of_lists()
309 for k, v in zip(_d.get('hook_ui_key', []),
310 for k, v in zip(_d.get('hook_ui_key', []),
310 _d.get('hook_ui_value_new', [])):
311 _d.get('hook_ui_value_new', [])):
311 RhodeCodeUi.create_or_update_hook(k, v)
312 RhodeCodeUi.create_or_update_hook(k, v)
312 update = True
313 update = True
313
314
314 if update:
315 if update:
315 h.flash(_('Updated hooks'), category='success')
316 h.flash(_('Updated hooks'), category='success')
316 Session().commit()
317 Session().commit()
317 except Exception:
318 except Exception:
318 log.error(traceback.format_exc())
319 log.error(traceback.format_exc())
319 h.flash(_('error occurred during hook creation'),
320 h.flash(_('error occurred during hook creation'),
320 category='error')
321 category='error')
321
322
322 return redirect(url('admin_edit_setting', setting_id='hooks'))
323 return redirect(url('admin_edit_setting', setting_id='hooks'))
323
324
324 if setting_id == 'email':
325 if setting_id == 'email':
325 test_email = request.POST.get('test_email')
326 test_email = request.POST.get('test_email')
326 test_email_subj = 'RhodeCode TestEmail'
327 test_email_subj = 'RhodeCode TestEmail'
327 test_email_body = 'RhodeCode Email test'
328 test_email_body = 'RhodeCode Email test'
328
329
329 test_email_html_body = EmailNotificationModel()\
330 test_email_html_body = EmailNotificationModel()\
330 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
331 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
331 body=test_email_body)
332 body=test_email_body)
332
333
333 recipients = [test_email] if [test_email] else None
334 recipients = [test_email] if [test_email] else None
334
335
335 run_task(tasks.send_email, recipients, test_email_subj,
336 run_task(tasks.send_email, recipients, test_email_subj,
336 test_email_body, test_email_html_body)
337 test_email_body, test_email_html_body)
337
338
338 h.flash(_('Email task created'), category='success')
339 h.flash(_('Email task created'), category='success')
339 return redirect(url('admin_settings'))
340 return redirect(url('admin_settings'))
340
341
341 @HasPermissionAllDecorator('hg.admin')
342 @HasPermissionAllDecorator('hg.admin')
342 def delete(self, setting_id):
343 def delete(self, setting_id):
343 """DELETE /admin/settings/setting_id: Delete an existing item"""
344 """DELETE /admin/settings/setting_id: Delete an existing item"""
344 # Forms posted to this method should contain a hidden field:
345 # Forms posted to this method should contain a hidden field:
345 # <input type="hidden" name="_method" value="DELETE" />
346 # <input type="hidden" name="_method" value="DELETE" />
346 # Or using helpers:
347 # Or using helpers:
347 # h.form(url('admin_setting', setting_id=ID),
348 # h.form(url('admin_setting', setting_id=ID),
348 # method='delete')
349 # method='delete')
349 # url('admin_setting', setting_id=ID)
350 # url('admin_setting', setting_id=ID)
350 if setting_id == 'hooks':
351 if setting_id == 'hooks':
351 hook_id = request.POST.get('hook_id')
352 hook_id = request.POST.get('hook_id')
352 RhodeCodeUi.delete(hook_id)
353 RhodeCodeUi.delete(hook_id)
353 Session().commit()
354 Session().commit()
354
355
355 @HasPermissionAllDecorator('hg.admin')
356 @HasPermissionAllDecorator('hg.admin')
356 def show(self, setting_id, format='html'):
357 def show(self, setting_id, format='html'):
357 """
358 """
358 GET /admin/settings/setting_id: Show a specific item"""
359 GET /admin/settings/setting_id: Show a specific item"""
359 # url('admin_setting', setting_id=ID)
360 # url('admin_setting', setting_id=ID)
360
361
361 @HasPermissionAllDecorator('hg.admin')
362 @HasPermissionAllDecorator('hg.admin')
362 def edit(self, setting_id, format='html'):
363 def edit(self, setting_id, format='html'):
363 """
364 """
364 GET /admin/settings/setting_id/edit: Form to
365 GET /admin/settings/setting_id/edit: Form to
365 edit an existing item"""
366 edit an existing item"""
366 # url('admin_edit_setting', setting_id=ID)
367 # url('admin_edit_setting', setting_id=ID)
367
368
368 c.hooks = RhodeCodeUi.get_builtin_hooks()
369 c.hooks = RhodeCodeUi.get_builtin_hooks()
369 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
370 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
370
371
371 return htmlfill.render(
372 return htmlfill.render(
372 render('admin/settings/hooks.html'),
373 render('admin/settings/hooks.html'),
373 defaults={},
374 defaults={},
374 encoding="UTF-8",
375 encoding="UTF-8",
375 force_defaults=False
376 force_defaults=False
376 )
377 )
377
378
378 @NotAnonymous()
379 @NotAnonymous()
379 def my_account(self):
380 def my_account(self):
380 """
381 """
381 GET /_admin/my_account Displays info about my account
382 GET /_admin/my_account Displays info about my account
382 """
383 """
383 # url('admin_settings_my_account')
384 # url('admin_settings_my_account')
384
385
385 c.user = User.get(self.rhodecode_user.user_id)
386 c.user = User.get(self.rhodecode_user.user_id)
386 all_repos = Session().query(Repository)\
387 all_repos = Session().query(Repository)\
387 .filter(Repository.user_id == c.user.user_id)\
388 .filter(Repository.user_id == c.user.user_id)\
388 .order_by(func.lower(Repository.repo_name)).all()
389 .order_by(func.lower(Repository.repo_name)).all()
389
390
390 c.user_repos = ScmModel().get_repos(all_repos)
391 c.user_repos = ScmModel().get_repos(all_repos)
391
392
392 if c.user.username == 'default':
393 if c.user.username == 'default':
393 h.flash(_("You can't edit this user since it's"
394 h.flash(_("You can't edit this user since it's"
394 " crucial for entire application"), category='warning')
395 " crucial for entire application"), category='warning')
395 return redirect(url('users'))
396 return redirect(url('users'))
396
397
397 defaults = c.user.get_dict()
398 defaults = c.user.get_dict()
398
399
399 c.form = htmlfill.render(
400 c.form = htmlfill.render(
400 render('admin/users/user_edit_my_account_form.html'),
401 render('admin/users/user_edit_my_account_form.html'),
401 defaults=defaults,
402 defaults=defaults,
402 encoding="UTF-8",
403 encoding="UTF-8",
403 force_defaults=False
404 force_defaults=False
404 )
405 )
405 return render('admin/users/user_edit_my_account.html')
406 return render('admin/users/user_edit_my_account.html')
406
407
407 @NotAnonymous()
408 @NotAnonymous()
408 def my_account_update(self):
409 def my_account_update(self):
409 """PUT /_admin/my_account_update: Update an existing item"""
410 """PUT /_admin/my_account_update: Update an existing item"""
410 # Forms posted to this method should contain a hidden field:
411 # Forms posted to this method should contain a hidden field:
411 # <input type="hidden" name="_method" value="PUT" />
412 # <input type="hidden" name="_method" value="PUT" />
412 # Or using helpers:
413 # Or using helpers:
413 # h.form(url('admin_settings_my_account_update'),
414 # h.form(url('admin_settings_my_account_update'),
414 # method='put')
415 # method='put')
415 # url('admin_settings_my_account_update', id=ID)
416 # url('admin_settings_my_account_update', id=ID)
416 uid = self.rhodecode_user.user_id
417 uid = self.rhodecode_user.user_id
417 email = self.rhodecode_user.email
418 email = self.rhodecode_user.email
418 _form = UserForm(edit=True,
419 _form = UserForm(edit=True,
419 old_data={'user_id': uid, 'email': email})()
420 old_data={'user_id': uid, 'email': email})()
420 form_result = {}
421 form_result = {}
421 try:
422 try:
422 form_result = _form.to_python(dict(request.POST))
423 form_result = _form.to_python(dict(request.POST))
423 UserModel().update_my_account(uid, form_result)
424 UserModel().update_my_account(uid, form_result)
424 h.flash(_('Your account was updated successfully'),
425 h.flash(_('Your account was updated successfully'),
425 category='success')
426 category='success')
426 Session().commit()
427 Session().commit()
427 except formencode.Invalid, errors:
428 except formencode.Invalid, errors:
428 c.user = User.get(self.rhodecode_user.user_id)
429 c.user = User.get(self.rhodecode_user.user_id)
429
430
430 c.form = htmlfill.render(
431 c.form = htmlfill.render(
431 render('admin/users/user_edit_my_account_form.html'),
432 render('admin/users/user_edit_my_account_form.html'),
432 defaults=errors.value,
433 defaults=errors.value,
433 errors=errors.error_dict or {},
434 errors=errors.error_dict or {},
434 prefix_error=False,
435 prefix_error=False,
435 encoding="UTF-8")
436 encoding="UTF-8")
436 return render('admin/users/user_edit_my_account.html')
437 return render('admin/users/user_edit_my_account.html')
437 except Exception:
438 except Exception:
438 log.error(traceback.format_exc())
439 log.error(traceback.format_exc())
439 h.flash(_('error occurred during update of user %s') \
440 h.flash(_('error occurred during update of user %s') \
440 % form_result.get('username'), category='error')
441 % form_result.get('username'), category='error')
441
442
442 return redirect(url('my_account'))
443 return redirect(url('my_account'))
443
444
444 @NotAnonymous()
445 @NotAnonymous()
445 def my_account_my_repos(self):
446 def my_account_my_repos(self):
446 all_repos = Session().query(Repository)\
447 all_repos = Session().query(Repository)\
447 .filter(Repository.user_id == self.rhodecode_user.user_id)\
448 .filter(Repository.user_id == self.rhodecode_user.user_id)\
448 .order_by(func.lower(Repository.repo_name))\
449 .order_by(func.lower(Repository.repo_name))\
449 .all()
450 .all()
450 c.user_repos = ScmModel().get_repos(all_repos)
451 c.user_repos = ScmModel().get_repos(all_repos)
451 return render('admin/users/user_edit_my_account_repos.html')
452 return render('admin/users/user_edit_my_account_repos.html')
452
453
453 @NotAnonymous()
454 @NotAnonymous()
454 def my_account_my_pullrequests(self):
455 def my_account_my_pullrequests(self):
455 c.my_pull_requests = PullRequest.query()\
456 c.my_pull_requests = PullRequest.query()\
456 .filter(PullRequest.user_id==
457 .filter(PullRequest.user_id==
457 self.rhodecode_user.user_id)\
458 self.rhodecode_user.user_id)\
458 .all()
459 .all()
459 c.participate_in_pull_requests = \
460 c.participate_in_pull_requests = \
460 [x.pull_request for x in PullRequestReviewers.query()\
461 [x.pull_request for x in PullRequestReviewers.query()\
461 .filter(PullRequestReviewers.user_id==
462 .filter(PullRequestReviewers.user_id==
462 self.rhodecode_user.user_id)\
463 self.rhodecode_user.user_id)\
463 .all()]
464 .all()]
464 return render('admin/users/user_edit_my_account_pullrequests.html')
465 return render('admin/users/user_edit_my_account_pullrequests.html')
465
466
466 @NotAnonymous()
467 @NotAnonymous()
467 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
468 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
468 def create_repository(self):
469 def create_repository(self):
469 """GET /_admin/create_repository: Form to create a new item"""
470 """GET /_admin/create_repository: Form to create a new item"""
470
471
471 c.repo_groups = RepoGroup.groups_choices(check_perms=True)
472 c.repo_groups = RepoGroup.groups_choices(check_perms=True)
472 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
473 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
473 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
474 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
474
475
475 new_repo = request.GET.get('repo', '')
476 new_repo = request.GET.get('repo', '')
476 c.new_repo = repo_name_slug(new_repo)
477 c.new_repo = repo_name_slug(new_repo)
477
478
478 return render('admin/repos/repo_add_create_repository.html')
479 return render('admin/repos/repo_add_create_repository.html')
479
480
480 def _get_hg_ui_settings(self):
481 def _get_hg_ui_settings(self):
481 ret = RhodeCodeUi.query().all()
482 ret = RhodeCodeUi.query().all()
482
483
483 if not ret:
484 if not ret:
484 raise Exception('Could not get application ui settings !')
485 raise Exception('Could not get application ui settings !')
485 settings = {}
486 settings = {}
486 for each in ret:
487 for each in ret:
487 k = each.ui_key
488 k = each.ui_key
488 v = each.ui_value
489 v = each.ui_value
489 if k == '/':
490 if k == '/':
490 k = 'root_path'
491 k = 'root_path'
491
492
492 if k == 'push_ssl':
493 if k == 'push_ssl':
493 v = str2bool(v)
494 v = str2bool(v)
494
495
495 if k.find('.') != -1:
496 if k.find('.') != -1:
496 k = k.replace('.', '_')
497 k = k.replace('.', '_')
497
498
498 if each.ui_section in ['hooks', 'extensions']:
499 if each.ui_section in ['hooks', 'extensions']:
499 v = each.ui_active
500 v = each.ui_active
500
501
501 settings[each.ui_section + '_' + k] = v
502 settings[each.ui_section + '_' + k] = v
502 return settings
503 return settings
@@ -1,674 +1,709
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Utilities library for RhodeCode
6 Utilities library for RhodeCode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import re
27 import re
28 import logging
28 import logging
29 import datetime
29 import datetime
30 import traceback
30 import traceback
31 import paste
31 import paste
32 import beaker
32 import beaker
33 import tarfile
33 import tarfile
34 import shutil
34 import shutil
35 from os.path import abspath
35 from os.path import abspath
36 from os.path import dirname as dn, join as jn
36 from os.path import dirname as dn, join as jn
37
37
38 from paste.script.command import Command, BadCommand
38 from paste.script.command import Command, BadCommand
39
39
40 from mercurial import ui, config
40 from mercurial import ui, config
41
41
42 from webhelpers.text import collapse, remove_formatting, strip_tags
42 from webhelpers.text import collapse, remove_formatting, strip_tags
43
43
44 from rhodecode.lib.vcs import get_backend
44 from rhodecode.lib.vcs import get_backend
45 from rhodecode.lib.vcs.backends.base import BaseChangeset
45 from rhodecode.lib.vcs.backends.base import BaseChangeset
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 from rhodecode.lib.vcs.utils.helpers import get_scm
47 from rhodecode.lib.vcs.utils.helpers import get_scm
48 from rhodecode.lib.vcs.exceptions import VCSError
48 from rhodecode.lib.vcs.exceptions import VCSError
49
49
50 from rhodecode.lib.caching_query import FromCache
50 from rhodecode.lib.caching_query import FromCache
51
51
52 from rhodecode.model import meta
52 from rhodecode.model import meta
53 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
53 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
54 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
54 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
55 from rhodecode.model.meta import Session
55 from rhodecode.model.meta import Session
56 from rhodecode.model.repos_group import ReposGroupModel
56 from rhodecode.model.repos_group import ReposGroupModel
57 from rhodecode.lib.utils2 import safe_str, safe_unicode
57 from rhodecode.lib.utils2 import safe_str, safe_unicode
58 from rhodecode.lib.vcs.utils.fakemod import create_module
58 from rhodecode.lib.vcs.utils.fakemod import create_module
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
62 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
63
63
64
64
65 def recursive_replace(str_, replace=' '):
65 def recursive_replace(str_, replace=' '):
66 """
66 """
67 Recursive replace of given sign to just one instance
67 Recursive replace of given sign to just one instance
68
68
69 :param str_: given string
69 :param str_: given string
70 :param replace: char to find and replace multiple instances
70 :param replace: char to find and replace multiple instances
71
71
72 Examples::
72 Examples::
73 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
73 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
74 'Mighty-Mighty-Bo-sstones'
74 'Mighty-Mighty-Bo-sstones'
75 """
75 """
76
76
77 if str_.find(replace * 2) == -1:
77 if str_.find(replace * 2) == -1:
78 return str_
78 return str_
79 else:
79 else:
80 str_ = str_.replace(replace * 2, replace)
80 str_ = str_.replace(replace * 2, replace)
81 return recursive_replace(str_, replace)
81 return recursive_replace(str_, replace)
82
82
83
83
84 def repo_name_slug(value):
84 def repo_name_slug(value):
85 """
85 """
86 Return slug of name of repository
86 Return slug of name of repository
87 This function is called on each creation/modification
87 This function is called on each creation/modification
88 of repository to prevent bad names in repo
88 of repository to prevent bad names in repo
89 """
89 """
90
90
91 slug = remove_formatting(value)
91 slug = remove_formatting(value)
92 slug = strip_tags(slug)
92 slug = strip_tags(slug)
93
93
94 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
94 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
95 slug = slug.replace(c, '-')
95 slug = slug.replace(c, '-')
96 slug = recursive_replace(slug, '-')
96 slug = recursive_replace(slug, '-')
97 slug = collapse(slug, '-')
97 slug = collapse(slug, '-')
98 return slug
98 return slug
99
99
100
100
101 def get_repo_slug(request):
101 def get_repo_slug(request):
102 _repo = request.environ['pylons.routes_dict'].get('repo_name')
102 _repo = request.environ['pylons.routes_dict'].get('repo_name')
103 if _repo:
103 if _repo:
104 _repo = _repo.rstrip('/')
104 _repo = _repo.rstrip('/')
105 return _repo
105 return _repo
106
106
107
107
108 def get_repos_group_slug(request):
108 def get_repos_group_slug(request):
109 _group = request.environ['pylons.routes_dict'].get('group_name')
109 _group = request.environ['pylons.routes_dict'].get('group_name')
110 if _group:
110 if _group:
111 _group = _group.rstrip('/')
111 _group = _group.rstrip('/')
112 return _group
112 return _group
113
113
114
114
115 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
115 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
116 """
116 """
117 Action logger for various actions made by users
117 Action logger for various actions made by users
118
118
119 :param user: user that made this action, can be a unique username string or
119 :param user: user that made this action, can be a unique username string or
120 object containing user_id attribute
120 object containing user_id attribute
121 :param action: action to log, should be on of predefined unique actions for
121 :param action: action to log, should be on of predefined unique actions for
122 easy translations
122 easy translations
123 :param repo: string name of repository or object containing repo_id,
123 :param repo: string name of repository or object containing repo_id,
124 that action was made on
124 that action was made on
125 :param ipaddr: optional ip address from what the action was made
125 :param ipaddr: optional ip address from what the action was made
126 :param sa: optional sqlalchemy session
126 :param sa: optional sqlalchemy session
127
127
128 """
128 """
129
129
130 if not sa:
130 if not sa:
131 sa = meta.Session()
131 sa = meta.Session()
132
132
133 try:
133 try:
134 if hasattr(user, 'user_id'):
134 if hasattr(user, 'user_id'):
135 user_obj = user
135 user_obj = user
136 elif isinstance(user, basestring):
136 elif isinstance(user, basestring):
137 user_obj = User.get_by_username(user)
137 user_obj = User.get_by_username(user)
138 else:
138 else:
139 raise Exception('You have to provide user object or username')
139 raise Exception('You have to provide user object or username')
140
140
141 if hasattr(repo, 'repo_id'):
141 if hasattr(repo, 'repo_id'):
142 repo_obj = Repository.get(repo.repo_id)
142 repo_obj = Repository.get(repo.repo_id)
143 repo_name = repo_obj.repo_name
143 repo_name = repo_obj.repo_name
144 elif isinstance(repo, basestring):
144 elif isinstance(repo, basestring):
145 repo_name = repo.lstrip('/')
145 repo_name = repo.lstrip('/')
146 repo_obj = Repository.get_by_repo_name(repo_name)
146 repo_obj = Repository.get_by_repo_name(repo_name)
147 else:
147 else:
148 repo_obj = None
148 repo_obj = None
149 repo_name = ''
149 repo_name = ''
150
150
151 user_log = UserLog()
151 user_log = UserLog()
152 user_log.user_id = user_obj.user_id
152 user_log.user_id = user_obj.user_id
153 user_log.action = safe_unicode(action)
153 user_log.action = safe_unicode(action)
154
154
155 user_log.repository = repo_obj
155 user_log.repository = repo_obj
156 user_log.repository_name = repo_name
156 user_log.repository_name = repo_name
157
157
158 user_log.action_date = datetime.datetime.now()
158 user_log.action_date = datetime.datetime.now()
159 user_log.user_ip = ipaddr
159 user_log.user_ip = ipaddr
160 sa.add(user_log)
160 sa.add(user_log)
161
161
162 log.info(
162 log.info(
163 'Adding user %s, action %s on %s' % (user_obj, action,
163 'Adding user %s, action %s on %s' % (user_obj, action,
164 safe_unicode(repo))
164 safe_unicode(repo))
165 )
165 )
166 if commit:
166 if commit:
167 sa.commit()
167 sa.commit()
168 except:
168 except:
169 log.error(traceback.format_exc())
169 log.error(traceback.format_exc())
170 raise
170 raise
171
171
172
172
173 def get_repos(path, recursive=False):
173 def get_repos(path, recursive=False):
174 """
174 """
175 Scans given path for repos and return (name,(type,path)) tuple
175 Scans given path for repos and return (name,(type,path)) tuple
176
176
177 :param path: path to scan for repositories
177 :param path: path to scan for repositories
178 :param recursive: recursive search and return names with subdirs in front
178 :param recursive: recursive search and return names with subdirs in front
179 """
179 """
180
180
181 # remove ending slash for better results
181 # remove ending slash for better results
182 path = path.rstrip(os.sep)
182 path = path.rstrip(os.sep)
183
183
184 def _get_repos(p):
184 def _get_repos(p):
185 if not os.access(p, os.W_OK):
185 if not os.access(p, os.W_OK):
186 return
186 return
187 for dirpath in os.listdir(p):
187 for dirpath in os.listdir(p):
188 if os.path.isfile(os.path.join(p, dirpath)):
188 if os.path.isfile(os.path.join(p, dirpath)):
189 continue
189 continue
190 cur_path = os.path.join(p, dirpath)
190 cur_path = os.path.join(p, dirpath)
191 try:
191 try:
192 scm_info = get_scm(cur_path)
192 scm_info = get_scm(cur_path)
193 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
193 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
194 except VCSError:
194 except VCSError:
195 if not recursive:
195 if not recursive:
196 continue
196 continue
197 #check if this dir containts other repos for recursive scan
197 #check if this dir containts other repos for recursive scan
198 rec_path = os.path.join(p, dirpath)
198 rec_path = os.path.join(p, dirpath)
199 if os.path.isdir(rec_path):
199 if os.path.isdir(rec_path):
200 for inner_scm in _get_repos(rec_path):
200 for inner_scm in _get_repos(rec_path):
201 yield inner_scm
201 yield inner_scm
202
202
203 return _get_repos(path)
203 return _get_repos(path)
204
204
205
205
206 def is_valid_repo(repo_name, base_path, scm=None):
206 def is_valid_repo(repo_name, base_path, scm=None):
207 """
207 """
208 Returns True if given path is a valid repository False otherwise.
208 Returns True if given path is a valid repository False otherwise.
209 If scm param is given also compare if given scm is the same as expected
209 If scm param is given also compare if given scm is the same as expected
210 from scm parameter
210 from scm parameter
211
211
212 :param repo_name:
212 :param repo_name:
213 :param base_path:
213 :param base_path:
214 :param scm:
214 :param scm:
215
215
216 :return True: if given path is a valid repository
216 :return True: if given path is a valid repository
217 """
217 """
218 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
218 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
219
219
220 try:
220 try:
221 scm_ = get_scm(full_path)
221 scm_ = get_scm(full_path)
222 if scm:
222 if scm:
223 return scm_[0] == scm
223 return scm_[0] == scm
224 return True
224 return True
225 except VCSError:
225 except VCSError:
226 return False
226 return False
227
227
228
228
229 def is_valid_repos_group(repos_group_name, base_path):
229 def is_valid_repos_group(repos_group_name, base_path):
230 """
230 """
231 Returns True if given path is a repos group False otherwise
231 Returns True if given path is a repos group False otherwise
232
232
233 :param repo_name:
233 :param repo_name:
234 :param base_path:
234 :param base_path:
235 """
235 """
236 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
236 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
237
237
238 # check if it's not a repo
238 # check if it's not a repo
239 if is_valid_repo(repos_group_name, base_path):
239 if is_valid_repo(repos_group_name, base_path):
240 return False
240 return False
241
241
242 try:
242 try:
243 # we need to check bare git repos at higher level
243 # we need to check bare git repos at higher level
244 # since we might match branches/hooks/info/objects or possible
244 # since we might match branches/hooks/info/objects or possible
245 # other things inside bare git repo
245 # other things inside bare git repo
246 get_scm(os.path.dirname(full_path))
246 get_scm(os.path.dirname(full_path))
247 return False
247 return False
248 except VCSError:
248 except VCSError:
249 pass
249 pass
250
250
251 # check if it's a valid path
251 # check if it's a valid path
252 if os.path.isdir(full_path):
252 if os.path.isdir(full_path):
253 return True
253 return True
254
254
255 return False
255 return False
256
256
257
257
258 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
258 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
259 while True:
259 while True:
260 ok = raw_input(prompt)
260 ok = raw_input(prompt)
261 if ok in ('y', 'ye', 'yes'):
261 if ok in ('y', 'ye', 'yes'):
262 return True
262 return True
263 if ok in ('n', 'no', 'nop', 'nope'):
263 if ok in ('n', 'no', 'nop', 'nope'):
264 return False
264 return False
265 retries = retries - 1
265 retries = retries - 1
266 if retries < 0:
266 if retries < 0:
267 raise IOError
267 raise IOError
268 print complaint
268 print complaint
269
269
270 #propagated from mercurial documentation
270 #propagated from mercurial documentation
271 ui_sections = ['alias', 'auth',
271 ui_sections = ['alias', 'auth',
272 'decode/encode', 'defaults',
272 'decode/encode', 'defaults',
273 'diff', 'email',
273 'diff', 'email',
274 'extensions', 'format',
274 'extensions', 'format',
275 'merge-patterns', 'merge-tools',
275 'merge-patterns', 'merge-tools',
276 'hooks', 'http_proxy',
276 'hooks', 'http_proxy',
277 'smtp', 'patch',
277 'smtp', 'patch',
278 'paths', 'profiling',
278 'paths', 'profiling',
279 'server', 'trusted',
279 'server', 'trusted',
280 'ui', 'web', ]
280 'ui', 'web', ]
281
281
282
282
283 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
283 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
284 """
284 """
285 A function that will read python rc files or database
285 A function that will read python rc files or database
286 and make an mercurial ui object from read options
286 and make an mercurial ui object from read options
287
287
288 :param path: path to mercurial config file
288 :param path: path to mercurial config file
289 :param checkpaths: check the path
289 :param checkpaths: check the path
290 :param read_from: read from 'file' or 'db'
290 :param read_from: read from 'file' or 'db'
291 """
291 """
292
292
293 baseui = ui.ui()
293 baseui = ui.ui()
294
294
295 # clean the baseui object
295 # clean the baseui object
296 baseui._ocfg = config.config()
296 baseui._ocfg = config.config()
297 baseui._ucfg = config.config()
297 baseui._ucfg = config.config()
298 baseui._tcfg = config.config()
298 baseui._tcfg = config.config()
299
299
300 if read_from == 'file':
300 if read_from == 'file':
301 if not os.path.isfile(path):
301 if not os.path.isfile(path):
302 log.debug('hgrc file is not present at %s skipping...' % path)
302 log.debug('hgrc file is not present at %s skipping...' % path)
303 return False
303 return False
304 log.debug('reading hgrc from %s' % path)
304 log.debug('reading hgrc from %s' % path)
305 cfg = config.config()
305 cfg = config.config()
306 cfg.read(path)
306 cfg.read(path)
307 for section in ui_sections:
307 for section in ui_sections:
308 for k, v in cfg.items(section):
308 for k, v in cfg.items(section):
309 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
309 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
310 baseui.setconfig(section, k, v)
310 baseui.setconfig(section, k, v)
311
311
312 elif read_from == 'db':
312 elif read_from == 'db':
313 sa = meta.Session()
313 sa = meta.Session()
314 ret = sa.query(RhodeCodeUi)\
314 ret = sa.query(RhodeCodeUi)\
315 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
315 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
316 .all()
316 .all()
317
317
318 hg_ui = ret
318 hg_ui = ret
319 for ui_ in hg_ui:
319 for ui_ in hg_ui:
320 if ui_.ui_active:
320 if ui_.ui_active:
321 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
321 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
322 ui_.ui_key, ui_.ui_value)
322 ui_.ui_key, ui_.ui_value)
323 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
323 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
324 if ui_.ui_key == 'push_ssl':
324 if ui_.ui_key == 'push_ssl':
325 # force set push_ssl requirement to False, rhodecode
325 # force set push_ssl requirement to False, rhodecode
326 # handles that
326 # handles that
327 baseui.setconfig(ui_.ui_section, ui_.ui_key, False)
327 baseui.setconfig(ui_.ui_section, ui_.ui_key, False)
328 if clear_session:
328 if clear_session:
329 meta.Session.remove()
329 meta.Session.remove()
330 return baseui
330 return baseui
331
331
332
332
333 def set_rhodecode_config(config):
333 def set_rhodecode_config(config):
334 """
334 """
335 Updates pylons config with new settings from database
335 Updates pylons config with new settings from database
336
336
337 :param config:
337 :param config:
338 """
338 """
339 hgsettings = RhodeCodeSetting.get_app_settings()
339 hgsettings = RhodeCodeSetting.get_app_settings()
340
340
341 for k, v in hgsettings.items():
341 for k, v in hgsettings.items():
342 config[k] = v
342 config[k] = v
343
343
344
344
345 def invalidate_cache(cache_key, *args):
345 def invalidate_cache(cache_key, *args):
346 """
346 """
347 Puts cache invalidation task into db for
347 Puts cache invalidation task into db for
348 further global cache invalidation
348 further global cache invalidation
349 """
349 """
350
350
351 from rhodecode.model.scm import ScmModel
351 from rhodecode.model.scm import ScmModel
352
352
353 if cache_key.startswith('get_repo_cached_'):
353 if cache_key.startswith('get_repo_cached_'):
354 name = cache_key.split('get_repo_cached_')[-1]
354 name = cache_key.split('get_repo_cached_')[-1]
355 ScmModel().mark_for_invalidation(name)
355 ScmModel().mark_for_invalidation(name)
356
356
357
357
358 def map_groups(path):
358 def map_groups(path):
359 """
359 """
360 Given a full path to a repository, create all nested groups that this
360 Given a full path to a repository, create all nested groups that this
361 repo is inside. This function creates parent-child relationships between
361 repo is inside. This function creates parent-child relationships between
362 groups and creates default perms for all new groups.
362 groups and creates default perms for all new groups.
363
363
364 :param paths: full path to repository
364 :param paths: full path to repository
365 """
365 """
366 sa = meta.Session()
366 sa = meta.Session()
367 groups = path.split(Repository.url_sep())
367 groups = path.split(Repository.url_sep())
368 parent = None
368 parent = None
369 group = None
369 group = None
370
370
371 # last element is repo in nested groups structure
371 # last element is repo in nested groups structure
372 groups = groups[:-1]
372 groups = groups[:-1]
373 rgm = ReposGroupModel(sa)
373 rgm = ReposGroupModel(sa)
374 for lvl, group_name in enumerate(groups):
374 for lvl, group_name in enumerate(groups):
375 group_name = '/'.join(groups[:lvl] + [group_name])
375 group_name = '/'.join(groups[:lvl] + [group_name])
376 group = RepoGroup.get_by_group_name(group_name)
376 group = RepoGroup.get_by_group_name(group_name)
377 desc = '%s group' % group_name
377 desc = '%s group' % group_name
378
378
379 # skip folders that are now removed repos
379 # skip folders that are now removed repos
380 if REMOVED_REPO_PAT.match(group_name):
380 if REMOVED_REPO_PAT.match(group_name):
381 break
381 break
382
382
383 if group is None:
383 if group is None:
384 log.debug('creating group level: %s group_name: %s' % (lvl,
384 log.debug('creating group level: %s group_name: %s' % (lvl,
385 group_name))
385 group_name))
386 group = RepoGroup(group_name, parent)
386 group = RepoGroup(group_name, parent)
387 group.group_description = desc
387 group.group_description = desc
388 sa.add(group)
388 sa.add(group)
389 rgm._create_default_perms(group)
389 rgm._create_default_perms(group)
390 sa.flush()
390 sa.flush()
391 parent = group
391 parent = group
392 return group
392 return group
393
393
394
394
395 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
395 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
396 install_git_hook=False):
396 install_git_hook=False):
397 """
397 """
398 maps all repos given in initial_repo_list, non existing repositories
398 maps all repos given in initial_repo_list, non existing repositories
399 are created, if remove_obsolete is True it also check for db entries
399 are created, if remove_obsolete is True it also check for db entries
400 that are not in initial_repo_list and removes them.
400 that are not in initial_repo_list and removes them.
401
401
402 :param initial_repo_list: list of repositories found by scanning methods
402 :param initial_repo_list: list of repositories found by scanning methods
403 :param remove_obsolete: check for obsolete entries in database
403 :param remove_obsolete: check for obsolete entries in database
404 :param install_git_hook: if this is True, also check and install githook
404 :param install_git_hook: if this is True, also check and install githook
405 for a repo if missing
405 for a repo if missing
406 """
406 """
407 from rhodecode.model.repo import RepoModel
407 from rhodecode.model.repo import RepoModel
408 from rhodecode.model.scm import ScmModel
408 from rhodecode.model.scm import ScmModel
409 sa = meta.Session()
409 sa = meta.Session()
410 rm = RepoModel()
410 rm = RepoModel()
411 user = sa.query(User).filter(User.admin == True).first()
411 user = sa.query(User).filter(User.admin == True).first()
412 if user is None:
412 if user is None:
413 raise Exception('Missing administrative account !')
413 raise Exception('Missing administrative account !')
414 added = []
414 added = []
415
415
416 # # clear cache keys
416 # # clear cache keys
417 # log.debug("Clearing cache keys now...")
417 # log.debug("Clearing cache keys now...")
418 # CacheInvalidation.clear_cache()
418 # CacheInvalidation.clear_cache()
419 # sa.commit()
419 # sa.commit()
420
420
421 for name, repo in initial_repo_list.items():
421 for name, repo in initial_repo_list.items():
422 group = map_groups(name)
422 group = map_groups(name)
423 db_repo = rm.get_by_repo_name(name)
423 db_repo = rm.get_by_repo_name(name)
424 # found repo that is on filesystem not in RhodeCode database
424 # found repo that is on filesystem not in RhodeCode database
425 if not db_repo:
425 if not db_repo:
426 log.info('repository %s not found creating now' % name)
426 log.info('repository %s not found creating now' % name)
427 added.append(name)
427 added.append(name)
428 desc = (repo.description
428 desc = (repo.description
429 if repo.description != 'unknown'
429 if repo.description != 'unknown'
430 else '%s repository' % name)
430 else '%s repository' % name)
431 new_repo = rm.create_repo(
431 new_repo = rm.create_repo(
432 repo_name=name,
432 repo_name=name,
433 repo_type=repo.alias,
433 repo_type=repo.alias,
434 description=desc,
434 description=desc,
435 repos_group=getattr(group, 'group_id', None),
435 repos_group=getattr(group, 'group_id', None),
436 owner=user,
436 owner=user,
437 just_db=True
437 just_db=True
438 )
438 )
439 # we added that repo just now, and make sure it has githook
439 # we added that repo just now, and make sure it has githook
440 # installed
440 # installed
441 if new_repo.repo_type == 'git':
441 if new_repo.repo_type == 'git':
442 ScmModel().install_git_hook(new_repo.scm_instance)
442 ScmModel().install_git_hook(new_repo.scm_instance)
443 elif install_git_hook:
443 elif install_git_hook:
444 if db_repo.repo_type == 'git':
444 if db_repo.repo_type == 'git':
445 ScmModel().install_git_hook(db_repo.scm_instance)
445 ScmModel().install_git_hook(db_repo.scm_instance)
446 # during starting install all cache keys for all repositories in the
446 # during starting install all cache keys for all repositories in the
447 # system, this will register all repos and multiple instances
447 # system, this will register all repos and multiple instances
448 key, _prefix, _org_key = CacheInvalidation._get_key(name)
448 key, _prefix, _org_key = CacheInvalidation._get_key(name)
449 log.debug("Creating cache key for %s instance_id:`%s`" % (name, _prefix))
449 log.debug("Creating cache key for %s instance_id:`%s`" % (name, _prefix))
450 CacheInvalidation._get_or_create_key(key, _prefix, _org_key, commit=False)
450 CacheInvalidation._get_or_create_key(key, _prefix, _org_key, commit=False)
451 sa.commit()
451 sa.commit()
452 removed = []
452 removed = []
453 if remove_obsolete:
453 if remove_obsolete:
454 # remove from database those repositories that are not in the filesystem
454 # remove from database those repositories that are not in the filesystem
455 for repo in sa.query(Repository).all():
455 for repo in sa.query(Repository).all():
456 if repo.repo_name not in initial_repo_list.keys():
456 if repo.repo_name not in initial_repo_list.keys():
457 log.debug("Removing non existing repository found in db `%s`" %
457 log.debug("Removing non existing repository found in db `%s`" %
458 repo.repo_name)
458 repo.repo_name)
459 try:
459 try:
460 sa.delete(repo)
460 sa.delete(repo)
461 sa.commit()
461 sa.commit()
462 removed.append(repo.repo_name)
462 removed.append(repo.repo_name)
463 except:
463 except:
464 #don't hold further removals on error
464 #don't hold further removals on error
465 log.error(traceback.format_exc())
465 log.error(traceback.format_exc())
466 sa.rollback()
466 sa.rollback()
467
467
468 return added, removed
468 return added, removed
469
469
470
470
471 # set cache regions for beaker so celery can utilise it
471 # set cache regions for beaker so celery can utilise it
472 def add_cache(settings):
472 def add_cache(settings):
473 cache_settings = {'regions': None}
473 cache_settings = {'regions': None}
474 for key in settings.keys():
474 for key in settings.keys():
475 for prefix in ['beaker.cache.', 'cache.']:
475 for prefix in ['beaker.cache.', 'cache.']:
476 if key.startswith(prefix):
476 if key.startswith(prefix):
477 name = key.split(prefix)[1].strip()
477 name = key.split(prefix)[1].strip()
478 cache_settings[name] = settings[key].strip()
478 cache_settings[name] = settings[key].strip()
479 if cache_settings['regions']:
479 if cache_settings['regions']:
480 for region in cache_settings['regions'].split(','):
480 for region in cache_settings['regions'].split(','):
481 region = region.strip()
481 region = region.strip()
482 region_settings = {}
482 region_settings = {}
483 for key, value in cache_settings.items():
483 for key, value in cache_settings.items():
484 if key.startswith(region):
484 if key.startswith(region):
485 region_settings[key.split('.')[1]] = value
485 region_settings[key.split('.')[1]] = value
486 region_settings['expire'] = int(region_settings.get('expire',
486 region_settings['expire'] = int(region_settings.get('expire',
487 60))
487 60))
488 region_settings.setdefault('lock_dir',
488 region_settings.setdefault('lock_dir',
489 cache_settings.get('lock_dir'))
489 cache_settings.get('lock_dir'))
490 region_settings.setdefault('data_dir',
490 region_settings.setdefault('data_dir',
491 cache_settings.get('data_dir'))
491 cache_settings.get('data_dir'))
492
492
493 if 'type' not in region_settings:
493 if 'type' not in region_settings:
494 region_settings['type'] = cache_settings.get('type',
494 region_settings['type'] = cache_settings.get('type',
495 'memory')
495 'memory')
496 beaker.cache.cache_regions[region] = region_settings
496 beaker.cache.cache_regions[region] = region_settings
497
497
498
498
499 def load_rcextensions(root_path):
499 def load_rcextensions(root_path):
500 import rhodecode
500 import rhodecode
501 from rhodecode.config import conf
501 from rhodecode.config import conf
502
502
503 path = os.path.join(root_path, 'rcextensions', '__init__.py')
503 path = os.path.join(root_path, 'rcextensions', '__init__.py')
504 if os.path.isfile(path):
504 if os.path.isfile(path):
505 rcext = create_module('rc', path)
505 rcext = create_module('rc', path)
506 EXT = rhodecode.EXTENSIONS = rcext
506 EXT = rhodecode.EXTENSIONS = rcext
507 log.debug('Found rcextensions now loading %s...' % rcext)
507 log.debug('Found rcextensions now loading %s...' % rcext)
508
508
509 # Additional mappings that are not present in the pygments lexers
509 # Additional mappings that are not present in the pygments lexers
510 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
510 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
511
511
512 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
512 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
513
513
514 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
514 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
515 log.debug('settings custom INDEX_EXTENSIONS')
515 log.debug('settings custom INDEX_EXTENSIONS')
516 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
516 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
517
517
518 #ADDITIONAL MAPPINGS
518 #ADDITIONAL MAPPINGS
519 log.debug('adding extra into INDEX_EXTENSIONS')
519 log.debug('adding extra into INDEX_EXTENSIONS')
520 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
520 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
521
521
522
522
523 #==============================================================================
523 #==============================================================================
524 # TEST FUNCTIONS AND CREATORS
524 # TEST FUNCTIONS AND CREATORS
525 #==============================================================================
525 #==============================================================================
526 def create_test_index(repo_location, config, full_index):
526 def create_test_index(repo_location, config, full_index):
527 """
527 """
528 Makes default test index
528 Makes default test index
529
529
530 :param config: test config
530 :param config: test config
531 :param full_index:
531 :param full_index:
532 """
532 """
533
533
534 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
534 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
535 from rhodecode.lib.pidlock import DaemonLock, LockHeld
535 from rhodecode.lib.pidlock import DaemonLock, LockHeld
536
536
537 repo_location = repo_location
537 repo_location = repo_location
538
538
539 index_location = os.path.join(config['app_conf']['index_dir'])
539 index_location = os.path.join(config['app_conf']['index_dir'])
540 if not os.path.exists(index_location):
540 if not os.path.exists(index_location):
541 os.makedirs(index_location)
541 os.makedirs(index_location)
542
542
543 try:
543 try:
544 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
544 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
545 WhooshIndexingDaemon(index_location=index_location,
545 WhooshIndexingDaemon(index_location=index_location,
546 repo_location=repo_location)\
546 repo_location=repo_location)\
547 .run(full_index=full_index)
547 .run(full_index=full_index)
548 l.release()
548 l.release()
549 except LockHeld:
549 except LockHeld:
550 pass
550 pass
551
551
552
552
553 def create_test_env(repos_test_path, config):
553 def create_test_env(repos_test_path, config):
554 """
554 """
555 Makes a fresh database and
555 Makes a fresh database and
556 install test repository into tmp dir
556 install test repository into tmp dir
557 """
557 """
558 from rhodecode.lib.db_manage import DbManage
558 from rhodecode.lib.db_manage import DbManage
559 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
559 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
560
560
561 # PART ONE create db
561 # PART ONE create db
562 dbconf = config['sqlalchemy.db1.url']
562 dbconf = config['sqlalchemy.db1.url']
563 log.debug('making test db %s' % dbconf)
563 log.debug('making test db %s' % dbconf)
564
564
565 # create test dir if it doesn't exist
565 # create test dir if it doesn't exist
566 if not os.path.isdir(repos_test_path):
566 if not os.path.isdir(repos_test_path):
567 log.debug('Creating testdir %s' % repos_test_path)
567 log.debug('Creating testdir %s' % repos_test_path)
568 os.makedirs(repos_test_path)
568 os.makedirs(repos_test_path)
569
569
570 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
570 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
571 tests=True)
571 tests=True)
572 dbmanage.create_tables(override=True)
572 dbmanage.create_tables(override=True)
573 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
573 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
574 dbmanage.create_default_user()
574 dbmanage.create_default_user()
575 dbmanage.admin_prompt()
575 dbmanage.admin_prompt()
576 dbmanage.create_permissions()
576 dbmanage.create_permissions()
577 dbmanage.populate_default_permissions()
577 dbmanage.populate_default_permissions()
578 Session().commit()
578 Session().commit()
579 # PART TWO make test repo
579 # PART TWO make test repo
580 log.debug('making test vcs repositories')
580 log.debug('making test vcs repositories')
581
581
582 idx_path = config['app_conf']['index_dir']
582 idx_path = config['app_conf']['index_dir']
583 data_path = config['app_conf']['cache_dir']
583 data_path = config['app_conf']['cache_dir']
584
584
585 #clean index and data
585 #clean index and data
586 if idx_path and os.path.exists(idx_path):
586 if idx_path and os.path.exists(idx_path):
587 log.debug('remove %s' % idx_path)
587 log.debug('remove %s' % idx_path)
588 shutil.rmtree(idx_path)
588 shutil.rmtree(idx_path)
589
589
590 if data_path and os.path.exists(data_path):
590 if data_path and os.path.exists(data_path):
591 log.debug('remove %s' % data_path)
591 log.debug('remove %s' % data_path)
592 shutil.rmtree(data_path)
592 shutil.rmtree(data_path)
593
593
594 #CREATE DEFAULT TEST REPOS
594 #CREATE DEFAULT TEST REPOS
595 cur_dir = dn(dn(abspath(__file__)))
595 cur_dir = dn(dn(abspath(__file__)))
596 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
596 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
597 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
597 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
598 tar.close()
598 tar.close()
599
599
600 cur_dir = dn(dn(abspath(__file__)))
600 cur_dir = dn(dn(abspath(__file__)))
601 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
601 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
602 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
602 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
603 tar.close()
603 tar.close()
604
604
605 #LOAD VCS test stuff
605 #LOAD VCS test stuff
606 from rhodecode.tests.vcs import setup_package
606 from rhodecode.tests.vcs import setup_package
607 setup_package()
607 setup_package()
608
608
609
609
610 #==============================================================================
610 #==============================================================================
611 # PASTER COMMANDS
611 # PASTER COMMANDS
612 #==============================================================================
612 #==============================================================================
613 class BasePasterCommand(Command):
613 class BasePasterCommand(Command):
614 """
614 """
615 Abstract Base Class for paster commands.
615 Abstract Base Class for paster commands.
616
616
617 The celery commands are somewhat aggressive about loading
617 The celery commands are somewhat aggressive about loading
618 celery.conf, and since our module sets the `CELERY_LOADER`
618 celery.conf, and since our module sets the `CELERY_LOADER`
619 environment variable to our loader, we have to bootstrap a bit and
619 environment variable to our loader, we have to bootstrap a bit and
620 make sure we've had a chance to load the pylons config off of the
620 make sure we've had a chance to load the pylons config off of the
621 command line, otherwise everything fails.
621 command line, otherwise everything fails.
622 """
622 """
623 min_args = 1
623 min_args = 1
624 min_args_error = "Please provide a paster config file as an argument."
624 min_args_error = "Please provide a paster config file as an argument."
625 takes_config_file = 1
625 takes_config_file = 1
626 requires_config_file = True
626 requires_config_file = True
627
627
628 def notify_msg(self, msg, log=False):
628 def notify_msg(self, msg, log=False):
629 """Make a notification to user, additionally if logger is passed
629 """Make a notification to user, additionally if logger is passed
630 it logs this action using given logger
630 it logs this action using given logger
631
631
632 :param msg: message that will be printed to user
632 :param msg: message that will be printed to user
633 :param log: logging instance, to use to additionally log this message
633 :param log: logging instance, to use to additionally log this message
634
634
635 """
635 """
636 if log and isinstance(log, logging):
636 if log and isinstance(log, logging):
637 log(msg)
637 log(msg)
638
638
639 def run(self, args):
639 def run(self, args):
640 """
640 """
641 Overrides Command.run
641 Overrides Command.run
642
642
643 Checks for a config file argument and loads it.
643 Checks for a config file argument and loads it.
644 """
644 """
645 if len(args) < self.min_args:
645 if len(args) < self.min_args:
646 raise BadCommand(
646 raise BadCommand(
647 self.min_args_error % {'min_args': self.min_args,
647 self.min_args_error % {'min_args': self.min_args,
648 'actual_args': len(args)})
648 'actual_args': len(args)})
649
649
650 # Decrement because we're going to lob off the first argument.
650 # Decrement because we're going to lob off the first argument.
651 # @@ This is hacky
651 # @@ This is hacky
652 self.min_args -= 1
652 self.min_args -= 1
653 self.bootstrap_config(args[0])
653 self.bootstrap_config(args[0])
654 self.update_parser()
654 self.update_parser()
655 return super(BasePasterCommand, self).run(args[1:])
655 return super(BasePasterCommand, self).run(args[1:])
656
656
657 def update_parser(self):
657 def update_parser(self):
658 """
658 """
659 Abstract method. Allows for the class's parser to be updated
659 Abstract method. Allows for the class's parser to be updated
660 before the superclass's `run` method is called. Necessary to
660 before the superclass's `run` method is called. Necessary to
661 allow options/arguments to be passed through to the underlying
661 allow options/arguments to be passed through to the underlying
662 celery command.
662 celery command.
663 """
663 """
664 raise NotImplementedError("Abstract Method.")
664 raise NotImplementedError("Abstract Method.")
665
665
666 def bootstrap_config(self, conf):
666 def bootstrap_config(self, conf):
667 """
667 """
668 Loads the pylons configuration.
668 Loads the pylons configuration.
669 """
669 """
670 from pylons import config as pylonsconfig
670 from pylons import config as pylonsconfig
671
671
672 self.path_to_ini_file = os.path.realpath(conf)
672 self.path_to_ini_file = os.path.realpath(conf)
673 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
673 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
674 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
674 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
675
676
677 def check_git_version():
678 """
679 Checks what version of git is installed in system, and issues a warning
680 if it's to old for RhodeCode to properly work.
681 """
682 import subprocess
683 from distutils.version import StrictVersion
684 from rhodecode import BACKENDS
685
686 p = subprocess.Popen('git --version', shell=True,
687 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
688 stdout, stderr = p.communicate()
689 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
690 try:
691 _ver = StrictVersion(ver)
692 except:
693 _ver = StrictVersion('0.0.0')
694 stderr = traceback.format_exc()
695
696 req_ver = '1.7.4'
697 to_old_git = False
698 if _ver <= StrictVersion(req_ver):
699 to_old_git = True
700
701 if 'git' in BACKENDS:
702 log.debug('GIT version detected: %s' % stdout)
703 if stderr:
704 log.warning('Unable to detect git version org error was:%r' % stderr)
705 elif to_old_git:
706 log.warning('RhodeCode detected git version %s, which is to old '
707 'for the system to function properly make sure '
708 'it is at least in version %s' % (ver, req_ver))
709 return _ver No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now