##// END OF EJS Templates
fixed wrong migration schema...
marcink -
r837:60cbde08 beta
parent child Browse files
Show More
@@ -1,332 +1,382 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.db_manage
3 rhodecode.lib.db_manage
4 ~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Database creation, and setup module for RhodeCode
6 Database creation, and setup module for RhodeCode
7
7
8 :created_on: Apr 10, 2010
8 :created_on: Apr 10, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2010 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import os
28 import os
29 import sys
29 import sys
30 import uuid
30 import uuid
31 import logging
31 import logging
32 from os.path import dirname as dn, join as jn
32 from os.path import dirname as dn, join as jn
33
33
34 from rhodecode import __dbversion__
34 from rhodecode import __dbversion__
35 from rhodecode.model.db import
36 from rhodecode.model import meta
35 from rhodecode.model import meta
37
36
38 from rhodecode.lib.auth import get_crypt_password
37 from rhodecode.lib.auth import get_crypt_password
39 from rhodecode.lib.utils import ask_ok
38 from rhodecode.lib.utils import ask_ok
40 from rhodecode.model import init_model
39 from rhodecode.model import init_model
41 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
40 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
42 UserToPerm, DbMigrateVersion
41 UserToPerm, DbMigrateVersion
43
42
44 from sqlalchemy.engine import create_engine
43 from sqlalchemy.engine import create_engine
45
44
46
45
47 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
48
47
49 class DbManage(object):
48 class DbManage(object):
50 def __init__(self, log_sql, dbconf, root, tests=False):
49 def __init__(self, log_sql, dbconf, root, tests=False):
51 self.dbname = dbconf.split('/')[-1]
50 self.dbname = dbconf.split('/')[-1]
52 self.tests = tests
51 self.tests = tests
53 self.root = root
52 self.root = root
54 self.dburi = dbconf
53 self.dburi = dbconf
55 engine = create_engine(self.dburi, echo=log_sql)
54 engine = create_engine(self.dburi, echo=log_sql)
56 init_model(engine)
55 init_model(engine)
57 self.sa = meta.Session()
56 self.sa = meta.Session()
58 self.db_exists = False
57 self.db_exists = False
59
58
60 def check_for_db(self, override):
59 def check_for_db(self, override):
61 db_path = jn(self.root, self.dbname)
60 db_path = jn(self.root, self.dbname)
62 if self.dburi.startswith('sqlite'):
61 if self.dburi.startswith('sqlite'):
63 log.info('checking for existing db in %s', db_path)
62 log.info('checking for existing db in %s', db_path)
64 if os.path.isfile(db_path):
63 if os.path.isfile(db_path):
65
64
66 self.db_exists = True
65 self.db_exists = True
67 if not override:
66 if not override:
68 raise Exception('database already exists')
67 raise Exception('database already exists')
69
68
70 def create_tables(self, override=False):
69 def create_tables(self, override=False):
70 """Create a auth database
71 """
71 """
72 Create a auth database
72
73 """
74 self.check_for_db(override)
73 self.check_for_db(override)
75 if self.db_exists:
74 if self.db_exists:
76 log.info("database exist and it's going to be destroyed")
75 log.info("database exist and it's going to be destroyed")
77 if self.tests:
76 if self.tests:
78 destroy = True
77 destroy = True
79 else:
78 else:
80 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
79 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
81 if not destroy:
80 if not destroy:
82 sys.exit()
81 sys.exit()
83 if self.db_exists and destroy:
82 if self.db_exists and destroy:
84 os.remove(jn(self.root, self.dbname))
83 os.remove(jn(self.root, self.dbname))
85 checkfirst = not override
84 checkfirst = not override
86 meta.Base.metadata.create_all(checkfirst=checkfirst)
85 meta.Base.metadata.create_all(checkfirst=checkfirst)
87 log.info('Created tables for %s', self.dbname)
86 log.info('Created tables for %s', self.dbname)
88
87
89
88
90
89
91 def set_db_version(self):
90 def set_db_version(self):
92 try:
91 try:
93 ver = DbMigrateVersion()
92 ver = DbMigrateVersion()
94 ver.version = __dbversion__
93 ver.version = __dbversion__
95 ver.repository_id = 'rhodecode_db_migrations'
94 ver.repository_id = 'rhodecode_db_migrations'
96 ver.repository_path = 'versions'
95 ver.repository_path = 'versions'
97 self.sa.add(ver)
96 self.sa.add(ver)
98 self.sa.commit()
97 self.sa.commit()
99 except:
98 except:
100 self.sa.rollback()
99 self.sa.rollback()
101 raise
100 raise
102 log.info('db version set to: %s', __dbversion__)
101 log.info('db version set to: %s', __dbversion__)
103
102
103 def fix_repo_paths(self):
104 """Fixes a old rhodecode version path into new one without a '*'
105 """
106
107 paths = self.sa.query(RhodeCodeUi)\
108 .filter(RhodeCodeUi.ui_key == '/')\
109 .scalar()
110
111 paths.ui_value = paths.ui_value.replace('*', '')
112
113 try:
114 self.sa.add(paths)
115 self.sa.commit()
116 except:
117 self.sa.rollback()
118 raise
119
120
121
104 def admin_prompt(self, second=False):
122 def admin_prompt(self, second=False):
105 if not self.tests:
123 if not self.tests:
106 import getpass
124 import getpass
107
125
108
126
109 def get_password():
127 def get_password():
110 password = getpass.getpass('Specify admin password (min 6 chars):')
128 password = getpass.getpass('Specify admin password (min 6 chars):')
111 confirm = getpass.getpass('Confirm password:')
129 confirm = getpass.getpass('Confirm password:')
112
130
113 if password != confirm:
131 if password != confirm:
114 log.error('passwords mismatch')
132 log.error('passwords mismatch')
115 return False
133 return False
116 if len(password) < 6:
134 if len(password) < 6:
117 log.error('password is to short use at least 6 characters')
135 log.error('password is to short use at least 6 characters')
118 return False
136 return False
119
137
120 return password
138 return password
121
139
122 username = raw_input('Specify admin username:')
140 username = raw_input('Specify admin username:')
123
141
124 password = get_password()
142 password = get_password()
125 if not password:
143 if not password:
126 #second try
144 #second try
127 password = get_password()
145 password = get_password()
128 if not password:
146 if not password:
129 sys.exit()
147 sys.exit()
130
148
131 email = raw_input('Specify admin email:')
149 email = raw_input('Specify admin email:')
132 self.create_user(username, password, email, True)
150 self.create_user(username, password, email, True)
133 else:
151 else:
134 log.info('creating admin and regular test users')
152 log.info('creating admin and regular test users')
135 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
153 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
136 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
154 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
137 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
155 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
138
156
157 def create_ui_settings(self):
158 """Creates ui settings, fills out hooks
159 and disables dotencode
160
161 """
162 #HOOKS
163 hooks1_key = 'changegroup.update'
164 hooks1_ = self.sa.query(RhodeCodeUi)\
165 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
139
166
167 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
168 hooks1.ui_section = 'hooks'
169 hooks1.ui_key = hooks1_key
170 hooks1.ui_value = 'hg update >&2'
171 hooks1.ui_active = False
172
173 hooks2_key = 'changegroup.repo_size'
174 hooks2_ = self.sa.query(RhodeCodeUi)\
175 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
176
177 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
178 hooks2.ui_section = 'hooks'
179 hooks2.ui_key = hooks2_key
180 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
181
182 hooks3 = RhodeCodeUi()
183 hooks3.ui_section = 'hooks'
184 hooks3.ui_key = 'pretxnchangegroup.push_logger'
185 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
186
187 hooks4 = RhodeCodeUi()
188 hooks4.ui_section = 'hooks'
189 hooks4.ui_key = 'preoutgoing.pull_logger'
190 hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
191
192 #For mercurial 1.7 set backward comapatibility with format
193 dotencode_disable = RhodeCodeUi()
194 dotencode_disable.ui_section = 'format'
195 dotencode_disable.ui_key = 'dotencode'
196 dotencode_disable.ui_value = 'false'
197
198 try:
199 self.sa.add(hooks1)
200 self.sa.add(hooks2)
201 self.sa.add(hooks3)
202 self.sa.add(hooks4)
203 self.sa.add(dotencode_disable)
204 self.sa.commit()
205 except:
206 self.sa.rollback()
207 raise
208
209
210 def create_ldap_options(self):
211 """Creates ldap settings"""
212
213 try:
214 for k in ['ldap_active', 'ldap_host', 'ldap_port', 'ldap_ldaps',
215 'ldap_dn_user', 'ldap_dn_pass', 'ldap_base_dn']:
216
217 setting = RhodeCodeSettings(k, '')
218 self.sa.add(setting)
219 self.sa.commit()
220 except:
221 self.sa.rollback()
222 raise
140
223
141 def config_prompt(self, test_repo_path=''):
224 def config_prompt(self, test_repo_path=''):
142 log.info('Setting up repositories config')
225 log.info('Setting up repositories config')
143
226
144 if not self.tests and not test_repo_path:
227 if not self.tests and not test_repo_path:
145 path = raw_input('Specify valid full path to your repositories'
228 path = raw_input('Specify valid full path to your repositories'
146 ' you can change this later in application settings:')
229 ' you can change this later in application settings:')
147 else:
230 else:
148 path = test_repo_path
231 path = test_repo_path
149
232
150 if not os.path.isdir(path):
233 if not os.path.isdir(path):
151 log.error('You entered wrong path: %s', path)
234 log.error('You entered wrong path: %s', path)
152 sys.exit()
235 sys.exit()
153
236
154 hooks1 = RhodeCodeUi()
237 self.create_ui_settings()
155 hooks1.ui_section = 'hooks'
156 hooks1.ui_key = 'changegroup.update'
157 hooks1.ui_value = 'hg update >&2'
158 hooks1.ui_active = False
159
160 hooks2 = RhodeCodeUi()
161 hooks2.ui_section = 'hooks'
162 hooks2.ui_key = 'changegroup.repo_size'
163 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
164
238
165 hooks3 = RhodeCodeUi()
239 #HG UI OPTIONS
166 hooks3.ui_section = 'hooks'
167 hooks3.ui_key = 'pretxnchangegroup.push_logger'
168 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
169
170 hooks4 = RhodeCodeUi()
171 hooks4.ui_section = 'hooks'
172 hooks4.ui_key = 'preoutgoing.pull_logger'
173 hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
174
175 #for mercurial 1.7 set backward comapatibility with format
176
177 dotencode_disable = RhodeCodeUi()
178 dotencode_disable.ui_section = 'format'
179 dotencode_disable.ui_key = 'dotencode'
180 dotencode_disable.ui_section = 'false'
181
182
183 web1 = RhodeCodeUi()
240 web1 = RhodeCodeUi()
184 web1.ui_section = 'web'
241 web1.ui_section = 'web'
185 web1.ui_key = 'push_ssl'
242 web1.ui_key = 'push_ssl'
186 web1.ui_value = 'false'
243 web1.ui_value = 'false'
187
244
188 web2 = RhodeCodeUi()
245 web2 = RhodeCodeUi()
189 web2.ui_section = 'web'
246 web2.ui_section = 'web'
190 web2.ui_key = 'allow_archive'
247 web2.ui_key = 'allow_archive'
191 web2.ui_value = 'gz zip bz2'
248 web2.ui_value = 'gz zip bz2'
192
249
193 web3 = RhodeCodeUi()
250 web3 = RhodeCodeUi()
194 web3.ui_section = 'web'
251 web3.ui_section = 'web'
195 web3.ui_key = 'allow_push'
252 web3.ui_key = 'allow_push'
196 web3.ui_value = '*'
253 web3.ui_value = '*'
197
254
198 web4 = RhodeCodeUi()
255 web4 = RhodeCodeUi()
199 web4.ui_section = 'web'
256 web4.ui_section = 'web'
200 web4.ui_key = 'baseurl'
257 web4.ui_key = 'baseurl'
201 web4.ui_value = '/'
258 web4.ui_value = '/'
202
259
203 paths = RhodeCodeUi()
260 paths = RhodeCodeUi()
204 paths.ui_section = 'paths'
261 paths.ui_section = 'paths'
205 paths.ui_key = '/'
262 paths.ui_key = '/'
206 paths.ui_value = path
263 paths.ui_value = path
207
264
208
265
209 hgsettings1 = RhodeCodeSettings('realm', 'RhodeCode authentication')
266 hgsettings1 = RhodeCodeSettings('realm', 'RhodeCode authentication')
210 hgsettings2 = RhodeCodeSettings('title', 'RhodeCode')
267 hgsettings2 = RhodeCodeSettings('title', 'RhodeCode')
211
268
212
269
213 try:
270 try:
214 self.sa.add(hooks1)
215 self.sa.add(hooks2)
216 self.sa.add(hooks3)
217 self.sa.add(hooks4)
218 self.sa.add(web1)
271 self.sa.add(web1)
219 self.sa.add(web2)
272 self.sa.add(web2)
220 self.sa.add(web3)
273 self.sa.add(web3)
221 self.sa.add(web4)
274 self.sa.add(web4)
222 self.sa.add(paths)
275 self.sa.add(paths)
223 self.sa.add(hgsettings1)
276 self.sa.add(hgsettings1)
224 self.sa.add(hgsettings2)
277 self.sa.add(hgsettings2)
225 self.sa.add(dotencode_disable)
226 for k in ['ldap_active', 'ldap_host', 'ldap_port', 'ldap_ldaps',
227 'ldap_dn_user', 'ldap_dn_pass', 'ldap_base_dn']:
228
229 setting = RhodeCodeSettings(k, '')
230 self.sa.add(setting)
231
278
232 self.sa.commit()
279 self.sa.commit()
233 except:
280 except:
234 self.sa.rollback()
281 self.sa.rollback()
235 raise
282 raise
283
284 self.create_ldap_options()
285
236 log.info('created ui config')
286 log.info('created ui config')
237
287
238 def create_user(self, username, password, email='', admin=False):
288 def create_user(self, username, password, email='', admin=False):
239 log.info('creating administrator user %s', username)
289 log.info('creating administrator user %s', username)
240 new_user = User()
290 new_user = User()
241 new_user.username = username
291 new_user.username = username
242 new_user.password = get_crypt_password(password)
292 new_user.password = get_crypt_password(password)
243 new_user.name = 'RhodeCode'
293 new_user.name = 'RhodeCode'
244 new_user.lastname = 'Admin'
294 new_user.lastname = 'Admin'
245 new_user.email = email
295 new_user.email = email
246 new_user.admin = admin
296 new_user.admin = admin
247 new_user.active = True
297 new_user.active = True
248
298
249 try:
299 try:
250 self.sa.add(new_user)
300 self.sa.add(new_user)
251 self.sa.commit()
301 self.sa.commit()
252 except:
302 except:
253 self.sa.rollback()
303 self.sa.rollback()
254 raise
304 raise
255
305
256 def create_default_user(self):
306 def create_default_user(self):
257 log.info('creating default user')
307 log.info('creating default user')
258 #create default user for handling default permissions.
308 #create default user for handling default permissions.
259 def_user = User()
309 def_user = User()
260 def_user.username = 'default'
310 def_user.username = 'default'
261 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
311 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
262 def_user.name = 'Anonymous'
312 def_user.name = 'Anonymous'
263 def_user.lastname = 'User'
313 def_user.lastname = 'User'
264 def_user.email = 'anonymous@rhodecode.org'
314 def_user.email = 'anonymous@rhodecode.org'
265 def_user.admin = False
315 def_user.admin = False
266 def_user.active = False
316 def_user.active = False
267 try:
317 try:
268 self.sa.add(def_user)
318 self.sa.add(def_user)
269 self.sa.commit()
319 self.sa.commit()
270 except:
320 except:
271 self.sa.rollback()
321 self.sa.rollback()
272 raise
322 raise
273
323
274 def create_permissions(self):
324 def create_permissions(self):
275 #module.(access|create|change|delete)_[name]
325 #module.(access|create|change|delete)_[name]
276 #module.(read|write|owner)
326 #module.(read|write|owner)
277 perms = [('repository.none', 'Repository no access'),
327 perms = [('repository.none', 'Repository no access'),
278 ('repository.read', 'Repository read access'),
328 ('repository.read', 'Repository read access'),
279 ('repository.write', 'Repository write access'),
329 ('repository.write', 'Repository write access'),
280 ('repository.admin', 'Repository admin access'),
330 ('repository.admin', 'Repository admin access'),
281 ('hg.admin', 'Hg Administrator'),
331 ('hg.admin', 'Hg Administrator'),
282 ('hg.create.repository', 'Repository create'),
332 ('hg.create.repository', 'Repository create'),
283 ('hg.create.none', 'Repository creation disabled'),
333 ('hg.create.none', 'Repository creation disabled'),
284 ('hg.register.none', 'Register disabled'),
334 ('hg.register.none', 'Register disabled'),
285 ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
335 ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
286 ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
336 ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
287 ]
337 ]
288
338
289 for p in perms:
339 for p in perms:
290 new_perm = Permission()
340 new_perm = Permission()
291 new_perm.permission_name = p[0]
341 new_perm.permission_name = p[0]
292 new_perm.permission_longname = p[1]
342 new_perm.permission_longname = p[1]
293 try:
343 try:
294 self.sa.add(new_perm)
344 self.sa.add(new_perm)
295 self.sa.commit()
345 self.sa.commit()
296 except:
346 except:
297 self.sa.rollback()
347 self.sa.rollback()
298 raise
348 raise
299
349
300 def populate_default_permissions(self):
350 def populate_default_permissions(self):
301 log.info('creating default user permissions')
351 log.info('creating default user permissions')
302
352
303 default_user = self.sa.query(User)\
353 default_user = self.sa.query(User)\
304 .filter(User.username == 'default').scalar()
354 .filter(User.username == 'default').scalar()
305
355
306 reg_perm = UserToPerm()
356 reg_perm = UserToPerm()
307 reg_perm.user = default_user
357 reg_perm.user = default_user
308 reg_perm.permission = self.sa.query(Permission)\
358 reg_perm.permission = self.sa.query(Permission)\
309 .filter(Permission.permission_name == 'hg.register.manual_activate')\
359 .filter(Permission.permission_name == 'hg.register.manual_activate')\
310 .scalar()
360 .scalar()
311
361
312 create_repo_perm = UserToPerm()
362 create_repo_perm = UserToPerm()
313 create_repo_perm.user = default_user
363 create_repo_perm.user = default_user
314 create_repo_perm.permission = self.sa.query(Permission)\
364 create_repo_perm.permission = self.sa.query(Permission)\
315 .filter(Permission.permission_name == 'hg.create.repository')\
365 .filter(Permission.permission_name == 'hg.create.repository')\
316 .scalar()
366 .scalar()
317
367
318 default_repo_perm = UserToPerm()
368 default_repo_perm = UserToPerm()
319 default_repo_perm.user = default_user
369 default_repo_perm.user = default_user
320 default_repo_perm.permission = self.sa.query(Permission)\
370 default_repo_perm.permission = self.sa.query(Permission)\
321 .filter(Permission.permission_name == 'repository.read')\
371 .filter(Permission.permission_name == 'repository.read')\
322 .scalar()
372 .scalar()
323
373
324 try:
374 try:
325 self.sa.add(reg_perm)
375 self.sa.add(reg_perm)
326 self.sa.add(create_repo_perm)
376 self.sa.add(create_repo_perm)
327 self.sa.add(default_repo_perm)
377 self.sa.add(default_repo_perm)
328 self.sa.commit()
378 self.sa.commit()
329 except:
379 except:
330 self.sa.rollback()
380 self.sa.rollback()
331 raise
381 raise
332
382
@@ -1,86 +1,101 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.dbmigrate.__init__
3 rhodecode.lib.dbmigrate.__init__
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Database migration modules
6 Database migration modules
7
7
8 :created_on: Dec 11, 2010
8 :created_on: Dec 11, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2010 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import logging
28 import logging
29 from sqlalchemy import engine_from_config
29 from sqlalchemy import engine_from_config
30
30
31 from rhodecode import __dbversion__
31 from rhodecode import __dbversion__
32 from rhodecode.lib.dbmigrate.migrate.versioning import api
32 from rhodecode.lib.dbmigrate.migrate.versioning import api
33 from rhodecode.lib.dbmigrate.migrate.exceptions import \
33 from rhodecode.lib.dbmigrate.migrate.exceptions import \
34 DatabaseNotControlledError
34 DatabaseNotControlledError
35 from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
35 from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
36 from rhodecode.lib.db_manage import DbManage
36
37
37 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
38
39
39 class UpgradeDb(BasePasterCommand):
40 class UpgradeDb(BasePasterCommand):
40 """Command used for paster to upgrade our database to newer version
41 """Command used for paster to upgrade our database to newer version
41 """
42 """
42
43
43 max_args = 1
44 max_args = 1
44 min_args = 1
45 min_args = 1
45
46
46 usage = "CONFIG_FILE"
47 usage = "CONFIG_FILE"
47 summary = "Upgrades current db to newer version given configuration file"
48 summary = "Upgrades current db to newer version given configuration file"
48 group_name = "RhodeCode"
49 group_name = "RhodeCode"
49
50
50 parser = Command.standard_parser(verbose=True)
51 parser = Command.standard_parser(verbose=True)
51
52
52 def command(self):
53 def command(self):
53 from pylons import config
54 from pylons import config
54
55
55 add_cache(config)
56 add_cache(config)
56
57
57 #engine = engine_from_config(config, 'sqlalchemy.db1.')
58
58
59
59 repository_path = 'rhodecode/lib/dbmigrate'
60 repository_path = 'rhodecode/lib/dbmigrate'
60 db_uri = config['sqlalchemy.db1.url']
61 db_uri = config['sqlalchemy.db1.url']
61
62
62 try:
63 try:
63 curr_version = api.db_version(db_uri, repository_path)
64 curr_version = api.db_version(db_uri, repository_path)
64 msg = ('Found current database under version'
65 msg = ('Found current database under version'
65 ' control with version %s' % curr_version)
66 ' control with version %s' % curr_version)
66
67
67 except (RuntimeError, DatabaseNotControlledError), e:
68 except (RuntimeError, DatabaseNotControlledError), e:
68 curr_version = 1
69 curr_version = 1
69 msg = ('Current database is not under version control setting'
70 msg = ('Current database is not under version control setting'
70 ' as version %s' % curr_version)
71 ' as version %s' % curr_version)
71 api.version_control(db_uri, repository_path, curr_version)
72 api.version_control(db_uri, repository_path, curr_version)
72
73
74 self.notify_msg(msg)
73
75
74 print msg
75 #now we have our dbversion we can do upgrade
76 #now we have our dbversion we can do upgrade
77 self.notify_msg('attempting to do database upgrade to version %s' \
78 % __dbversion__)
79
80 api.upgrade(db_uri, repository_path, __dbversion__)
81 self.notify_msg('Schema upgrade completed')
76
82
77 msg = 'attempting to do database upgrade to version %s' % __dbversion__
83 #we need to make now some extra operations into database
78 print msg
84 self.notify_msg('Prociding with database updates')
79 api.upgrade(db_uri, repository_path, __dbversion__)
85
86 dbmanage = DbManage(log_sql=True, dbconf=db_uri,
87 root=config['here'], tests=False)
88
89 self.notify_msg('Patching repo paths for newer version of rhodecode')
90 dbmanage.fix_repo_paths()
91
92 self.notify_msg('Changing ui settings')
93 dbmanage.create_ui_settings()
94
80
95
81 def update_parser(self):
96 def update_parser(self):
82 self.parser.add_option('--sql',
97 self.parser.add_option('--sql',
83 action='store_true',
98 action='store_true',
84 dest='just_sql',
99 dest='just_sql',
85 help="Prints upgrade sql for further investigation",
100 help="Prints upgrade sql for further investigation",
86 default=False)
101 default=False)
@@ -1,129 +1,127 b''
1 import logging
1 import logging
2 import datetime
2 import datetime
3
3
4 from sqlalchemy import *
4 from sqlalchemy import *
5 from sqlalchemy.exc import DatabaseError
5 from sqlalchemy.exc import DatabaseError
6 from sqlalchemy.orm import relation, backref, class_mapper
6 from sqlalchemy.orm import relation, backref, class_mapper
7 from sqlalchemy.orm.session import Session
7 from sqlalchemy.orm.session import Session
8 from rhodecode.model.meta import Base
8 from rhodecode.model.meta import Base
9 from rhodecode.model.db import BaseModel
9 from rhodecode.model.db import BaseModel
10
10
11 from rhodecode.lib.dbmigrate.migrate import *
11 from rhodecode.lib.dbmigrate.migrate import *
12
12
13 log = logging.getLogger(__name__)
13 log = logging.getLogger(__name__)
14
14
15 def upgrade(migrate_engine):
15 def upgrade(migrate_engine):
16 """ Upgrade operations go here.
16 """ Upgrade operations go here.
17 Don't create your own engine; bind migrate_engine to your metadata
17 Don't create your own engine; bind migrate_engine to your metadata
18 """
18 """
19
19
20 #==========================================================================
20 #==========================================================================
21 # Upgrade of `users` table
21 # Upgrade of `users` table
22 #==========================================================================
22 #==========================================================================
23 tblname = 'users'
23 tblname = 'users'
24 tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
24 tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
25 autoload_with=migrate_engine)
25 autoload_with=migrate_engine)
26
26
27 #ADD is_ldap column
27 #ADD is_ldap column
28 is_ldap = Column("is_ldap", Boolean(), nullable=True,
28 is_ldap = Column("is_ldap", Boolean(), nullable=True,
29 unique=None, default=False)
29 unique=None, default=False)
30 is_ldap.create(tbl, populate_default=True)
30 is_ldap.create(tbl, populate_default=True)
31 is_ldap.alter(nullable=False)
31 is_ldap.alter(nullable=False)
32
32
33 #==========================================================================
33 #==========================================================================
34 # Upgrade of `user_logs` table
34 # Upgrade of `user_logs` table
35 #==========================================================================
35 #==========================================================================
36
36
37 tblname = 'users'
37 tblname = 'users'
38 tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
38 tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
39 autoload_with=migrate_engine)
39 autoload_with=migrate_engine)
40
40
41 #ADD revision column
41 #ADD revision column
42 revision = Column('revision', TEXT(length=None, convert_unicode=False,
42 revision = Column('revision', TEXT(length=None, convert_unicode=False,
43 assert_unicode=None),
43 assert_unicode=None),
44 nullable=True, unique=None, default=None)
44 nullable=True, unique=None, default=None)
45 revision.create(tbl)
45 revision.create(tbl)
46
46
47
47
48
48
49 #==========================================================================
49 #==========================================================================
50 # Upgrade of `repositories` table
50 # Upgrade of `repositories` table
51 #==========================================================================
51 #==========================================================================
52 tblname = 'users'
52 tblname = 'repositories'
53 tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
53 tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
54 autoload_with=migrate_engine)
54 autoload_with=migrate_engine)
55
55
56 #ADD repo_type column
56 #ADD repo_type column#
57 repo_type = Column("repo_type", String(length=None, convert_unicode=False,
57 repo_type = Column("repo_type", String(length=None, convert_unicode=False,
58 assert_unicode=None),
58 assert_unicode=None),
59 nullable=True, unique=False, default='hg')
59 nullable=True, unique=False, default='hg')
60
60
61 repo_type.create(tbl, populate_default=True)
61 repo_type.create(tbl, populate_default=True)
62 repo_type.alter(nullable=False)
62 #repo_type.alter(nullable=False)
63
63
64 #ADD statistics column
64 #ADD statistics column#
65 enable_statistics = Column("statistics", Boolean(), nullable=True,
65 enable_statistics = Column("statistics", Boolean(), nullable=True,
66 unique=None, default=True)
66 unique=None, default=True)
67 enable_statistics.create(tbl)
67 enable_statistics.create(tbl)
68
68
69
70
71 #==========================================================================
69 #==========================================================================
72 # Add table `user_followings`
70 # Add table `user_followings`
73 #==========================================================================
71 #==========================================================================
74 tblname = 'user_followings'
72 tblname = 'user_followings'
75
73
76 class UserFollowing(Base, BaseModel):
74 class UserFollowing(Base, BaseModel):
77 __tablename__ = 'user_followings'
75 __tablename__ = 'user_followings'
78 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
76 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
79 UniqueConstraint('user_id', 'follows_user_id')
77 UniqueConstraint('user_id', 'follows_user_id')
80 , {'useexisting':True})
78 , {'useexisting':True})
81
79
82 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
80 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
83 user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
81 user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
84 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None)
82 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None)
85 follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
83 follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
86
84
87 user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
85 user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
88
86
89 follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
87 follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
90 follows_repository = relation('Repository')
88 follows_repository = relation('Repository')
91
89
92 Base.metadata.tables[tblname].create(migrate_engine)
90 Base.metadata.tables[tblname].create(migrate_engine)
93
91
94 #==========================================================================
92 #==========================================================================
95 # Add table `cache_invalidation`
93 # Add table `cache_invalidation`
96 #==========================================================================
94 #==========================================================================
97 tblname = 'cache_invalidation'
95 tblname = 'cache_invalidation'
98
96
99 class CacheInvalidation(Base, BaseModel):
97 class CacheInvalidation(Base, BaseModel):
100 __tablename__ = 'cache_invalidation'
98 __tablename__ = 'cache_invalidation'
101 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
99 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
102 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
100 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
103 cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
104 cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
102 cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
105 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
103 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
106
104
107
105
108 def __init__(self, cache_key, cache_args=''):
106 def __init__(self, cache_key, cache_args=''):
109 self.cache_key = cache_key
107 self.cache_key = cache_key
110 self.cache_args = cache_args
108 self.cache_args = cache_args
111 self.cache_active = False
109 self.cache_active = False
112
110
113 def __repr__(self):
111 def __repr__(self):
114 return "<CacheInvalidation('%s:%s')>" % (self.cache_id, self.cache_key)
112 return "<CacheInvalidation('%s:%s')>" % (self.cache_id, self.cache_key)
115
113
116 Base.metadata.tables[tblname].create(migrate_engine)
114 Base.metadata.tables[tblname].create(migrate_engine)
117
115
118 return
116 return
119
117
120
118
121
119
122
120
123
121
124
122
125 def downgrade(migrate_engine):
123 def downgrade(migrate_engine):
126 meta = MetaData()
124 meta = MetaData()
127 meta.bind = migrate_engine
125 meta.bind = migrate_engine
128
126
129
127
@@ -1,601 +1,614 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Utilities library for RhodeCode
6 Utilities library for RhodeCode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2010 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import os
28 import os
29 import logging
29 import logging
30 import datetime
30 import datetime
31 import traceback
31 import traceback
32
32
33 from UserDict import DictMixin
33 from UserDict import DictMixin
34
34
35 from mercurial import ui, config, hg
35 from mercurial import ui, config, hg
36 from mercurial.error import RepoError
36 from mercurial.error import RepoError
37
37
38 import paste
38 import paste
39 import beaker
39 import beaker
40 from paste.script.command import Command, BadCommand
40 from paste.script.command import Command, BadCommand
41
41
42 from vcs.backends.base import BaseChangeset
42 from vcs.backends.base import BaseChangeset
43 from vcs.utils.lazy import LazyProperty
43 from vcs.utils.lazy import LazyProperty
44
44
45 from rhodecode.model import meta
45 from rhodecode.model import meta
46 from rhodecode.model.caching_query import FromCache
46 from rhodecode.model.caching_query import FromCache
47 from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog
47 from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog
48 from rhodecode.model.repo import RepoModel
48 from rhodecode.model.repo import RepoModel
49 from rhodecode.model.user import UserModel
49 from rhodecode.model.user import UserModel
50
50
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53
53
54 def get_repo_slug(request):
54 def get_repo_slug(request):
55 return request.environ['pylons.routes_dict'].get('repo_name')
55 return request.environ['pylons.routes_dict'].get('repo_name')
56
56
57 def action_logger(user, action, repo, ipaddr='', sa=None):
57 def action_logger(user, action, repo, ipaddr='', sa=None):
58 """
58 """
59 Action logger for various actions made by users
59 Action logger for various actions made by users
60
60
61 :param user: user that made this action, can be a unique username string or
61 :param user: user that made this action, can be a unique username string or
62 object containing user_id attribute
62 object containing user_id attribute
63 :param action: action to log, should be on of predefined unique actions for
63 :param action: action to log, should be on of predefined unique actions for
64 easy translations
64 easy translations
65 :param repo: string name of repository or object containing repo_id,
65 :param repo: string name of repository or object containing repo_id,
66 that action was made on
66 that action was made on
67 :param ipaddr: optional ip address from what the action was made
67 :param ipaddr: optional ip address from what the action was made
68 :param sa: optional sqlalchemy session
68 :param sa: optional sqlalchemy session
69
69
70 """
70 """
71
71
72 if not sa:
72 if not sa:
73 sa = meta.Session()
73 sa = meta.Session()
74
74
75 try:
75 try:
76 um = UserModel()
76 um = UserModel()
77 if hasattr(user, 'user_id'):
77 if hasattr(user, 'user_id'):
78 user_obj = user
78 user_obj = user
79 elif isinstance(user, basestring):
79 elif isinstance(user, basestring):
80 user_obj = um.get_by_username(user, cache=False)
80 user_obj = um.get_by_username(user, cache=False)
81 else:
81 else:
82 raise Exception('You have to provide user object or username')
82 raise Exception('You have to provide user object or username')
83
83
84
84
85 rm = RepoModel()
85 rm = RepoModel()
86 if hasattr(repo, 'repo_id'):
86 if hasattr(repo, 'repo_id'):
87 repo_obj = rm.get(repo.repo_id, cache=False)
87 repo_obj = rm.get(repo.repo_id, cache=False)
88 repo_name = repo_obj.repo_name
88 repo_name = repo_obj.repo_name
89 elif isinstance(repo, basestring):
89 elif isinstance(repo, basestring):
90 repo_name = repo.lstrip('/')
90 repo_name = repo.lstrip('/')
91 repo_obj = rm.get_by_repo_name(repo_name, cache=False)
91 repo_obj = rm.get_by_repo_name(repo_name, cache=False)
92 else:
92 else:
93 raise Exception('You have to provide repository to action logger')
93 raise Exception('You have to provide repository to action logger')
94
94
95
95
96 user_log = UserLog()
96 user_log = UserLog()
97 user_log.user_id = user_obj.user_id
97 user_log.user_id = user_obj.user_id
98 user_log.action = action
98 user_log.action = action
99
99
100 user_log.repository_id = repo_obj.repo_id
100 user_log.repository_id = repo_obj.repo_id
101 user_log.repository_name = repo_name
101 user_log.repository_name = repo_name
102
102
103 user_log.action_date = datetime.datetime.now()
103 user_log.action_date = datetime.datetime.now()
104 user_log.user_ip = ipaddr
104 user_log.user_ip = ipaddr
105 sa.add(user_log)
105 sa.add(user_log)
106 sa.commit()
106 sa.commit()
107
107
108 log.info('Adding user %s, action %s on %s', user_obj, action, repo)
108 log.info('Adding user %s, action %s on %s', user_obj, action, repo)
109 except:
109 except:
110 log.error(traceback.format_exc())
110 log.error(traceback.format_exc())
111 sa.rollback()
111 sa.rollback()
112
112
113 def get_repos(path, recursive=False, initial=False):
113 def get_repos(path, recursive=False, initial=False):
114 """
114 """
115 Scans given path for repos and return (name,(type,path)) tuple
115 Scans given path for repos and return (name,(type,path)) tuple
116 :param prefix:
116 :param prefix:
117 :param path:
117 :param path:
118 :param recursive:
118 :param recursive:
119 :param initial:
119 :param initial:
120 """
120 """
121 from vcs.utils.helpers import get_scm
121 from vcs.utils.helpers import get_scm
122 from vcs.exceptions import VCSError
122 from vcs.exceptions import VCSError
123
123
124 try:
124 try:
125 scm = get_scm(path)
125 scm = get_scm(path)
126 except:
126 except:
127 pass
127 pass
128 else:
128 else:
129 raise Exception('The given path %s should not be a repository got %s',
129 raise Exception('The given path %s should not be a repository got %s',
130 path, scm)
130 path, scm)
131
131
132 for dirpath in os.listdir(path):
132 for dirpath in os.listdir(path):
133 try:
133 try:
134 yield dirpath, get_scm(os.path.join(path, dirpath))
134 yield dirpath, get_scm(os.path.join(path, dirpath))
135 except VCSError:
135 except VCSError:
136 pass
136 pass
137
137
138 def check_repo_fast(repo_name, base_path):
138 def check_repo_fast(repo_name, base_path):
139 """
139 """
140 Check given path for existance of directory
140 Check given path for existance of directory
141 :param repo_name:
141 :param repo_name:
142 :param base_path:
142 :param base_path:
143
143
144 :return False: if this directory is present
144 :return False: if this directory is present
145 """
145 """
146 if os.path.isdir(os.path.join(base_path, repo_name)):return False
146 if os.path.isdir(os.path.join(base_path, repo_name)):return False
147 return True
147 return True
148
148
149 def check_repo(repo_name, base_path, verify=True):
149 def check_repo(repo_name, base_path, verify=True):
150
150
151 repo_path = os.path.join(base_path, repo_name)
151 repo_path = os.path.join(base_path, repo_name)
152
152
153 try:
153 try:
154 if not check_repo_fast(repo_name, base_path):
154 if not check_repo_fast(repo_name, base_path):
155 return False
155 return False
156 r = hg.repository(ui.ui(), repo_path)
156 r = hg.repository(ui.ui(), repo_path)
157 if verify:
157 if verify:
158 hg.verify(r)
158 hg.verify(r)
159 #here we hnow that repo exists it was verified
159 #here we hnow that repo exists it was verified
160 log.info('%s repo is already created', repo_name)
160 log.info('%s repo is already created', repo_name)
161 return False
161 return False
162 except RepoError:
162 except RepoError:
163 #it means that there is no valid repo there...
163 #it means that there is no valid repo there...
164 log.info('%s repo is free for creation', repo_name)
164 log.info('%s repo is free for creation', repo_name)
165 return True
165 return True
166
166
167 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
167 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
168 while True:
168 while True:
169 ok = raw_input(prompt)
169 ok = raw_input(prompt)
170 if ok in ('y', 'ye', 'yes'): return True
170 if ok in ('y', 'ye', 'yes'): return True
171 if ok in ('n', 'no', 'nop', 'nope'): return False
171 if ok in ('n', 'no', 'nop', 'nope'): return False
172 retries = retries - 1
172 retries = retries - 1
173 if retries < 0: raise IOError
173 if retries < 0: raise IOError
174 print complaint
174 print complaint
175
175
176 #propagated from mercurial documentation
176 #propagated from mercurial documentation
177 ui_sections = ['alias', 'auth',
177 ui_sections = ['alias', 'auth',
178 'decode/encode', 'defaults',
178 'decode/encode', 'defaults',
179 'diff', 'email',
179 'diff', 'email',
180 'extensions', 'format',
180 'extensions', 'format',
181 'merge-patterns', 'merge-tools',
181 'merge-patterns', 'merge-tools',
182 'hooks', 'http_proxy',
182 'hooks', 'http_proxy',
183 'smtp', 'patch',
183 'smtp', 'patch',
184 'paths', 'profiling',
184 'paths', 'profiling',
185 'server', 'trusted',
185 'server', 'trusted',
186 'ui', 'web', ]
186 'ui', 'web', ]
187
187
188 def make_ui(read_from='file', path=None, checkpaths=True):
188 def make_ui(read_from='file', path=None, checkpaths=True):
189 """
189 """
190 A function that will read python rc files or database
190 A function that will read python rc files or database
191 and make an mercurial ui object from read options
191 and make an mercurial ui object from read options
192
192
193 :param path: path to mercurial config file
193 :param path: path to mercurial config file
194 :param checkpaths: check the path
194 :param checkpaths: check the path
195 :param read_from: read from 'file' or 'db'
195 :param read_from: read from 'file' or 'db'
196 """
196 """
197
197
198 baseui = ui.ui()
198 baseui = ui.ui()
199
199
200 #clean the baseui object
200 #clean the baseui object
201 baseui._ocfg = config.config()
201 baseui._ocfg = config.config()
202 baseui._ucfg = config.config()
202 baseui._ucfg = config.config()
203 baseui._tcfg = config.config()
203 baseui._tcfg = config.config()
204
204
205 if read_from == 'file':
205 if read_from == 'file':
206 if not os.path.isfile(path):
206 if not os.path.isfile(path):
207 log.warning('Unable to read config file %s' % path)
207 log.warning('Unable to read config file %s' % path)
208 return False
208 return False
209 log.debug('reading hgrc from %s', path)
209 log.debug('reading hgrc from %s', path)
210 cfg = config.config()
210 cfg = config.config()
211 cfg.read(path)
211 cfg.read(path)
212 for section in ui_sections:
212 for section in ui_sections:
213 for k, v in cfg.items(section):
213 for k, v in cfg.items(section):
214 log.debug('settings ui from file[%s]%s:%s', section, k, v)
214 log.debug('settings ui from file[%s]%s:%s', section, k, v)
215 baseui.setconfig(section, k, v)
215 baseui.setconfig(section, k, v)
216
216
217
217
218 elif read_from == 'db':
218 elif read_from == 'db':
219 sa = meta.Session()
219 sa = meta.Session()
220 ret = sa.query(RhodeCodeUi)\
220 ret = sa.query(RhodeCodeUi)\
221 .options(FromCache("sql_cache_short",
221 .options(FromCache("sql_cache_short",
222 "get_hg_ui_settings")).all()
222 "get_hg_ui_settings")).all()
223
223
224 hg_ui = ret
224 hg_ui = ret
225 for ui_ in hg_ui:
225 for ui_ in hg_ui:
226 if ui_.ui_active:
226 if ui_.ui_active:
227 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
227 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
228 ui_.ui_key, ui_.ui_value)
228 ui_.ui_key, ui_.ui_value)
229 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
229 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
230
230
231 meta.Session.remove()
231 meta.Session.remove()
232 return baseui
232 return baseui
233
233
234
234
235 def set_rhodecode_config(config):
235 def set_rhodecode_config(config):
236 """
236 """
237 Updates pylons config with new settings from database
237 Updates pylons config with new settings from database
238 :param config:
238 :param config:
239 """
239 """
240 from rhodecode.model.settings import SettingsModel
240 from rhodecode.model.settings import SettingsModel
241 hgsettings = SettingsModel().get_app_settings()
241 hgsettings = SettingsModel().get_app_settings()
242
242
243 for k, v in hgsettings.items():
243 for k, v in hgsettings.items():
244 config[k] = v
244 config[k] = v
245
245
246 def invalidate_cache(cache_key, *args):
246 def invalidate_cache(cache_key, *args):
247 """
247 """
248 Puts cache invalidation task into db for
248 Puts cache invalidation task into db for
249 further global cache invalidation
249 further global cache invalidation
250 """
250 """
251 from rhodecode.model.scm import ScmModel
251 from rhodecode.model.scm import ScmModel
252
252
253 if cache_key.startswith('get_repo_cached_'):
253 if cache_key.startswith('get_repo_cached_'):
254 name = cache_key.split('get_repo_cached_')[-1]
254 name = cache_key.split('get_repo_cached_')[-1]
255 ScmModel().mark_for_invalidation(name)
255 ScmModel().mark_for_invalidation(name)
256
256
257 class EmptyChangeset(BaseChangeset):
257 class EmptyChangeset(BaseChangeset):
258 """
258 """
259 An dummy empty changeset. It's possible to pass hash when creating
259 An dummy empty changeset. It's possible to pass hash when creating
260 an EmptyChangeset
260 an EmptyChangeset
261 """
261 """
262
262
263 def __init__(self, cs='0' * 40):
263 def __init__(self, cs='0' * 40):
264 self._empty_cs = cs
264 self._empty_cs = cs
265 self.revision = -1
265 self.revision = -1
266 self.message = ''
266 self.message = ''
267 self.author = ''
267 self.author = ''
268 self.date = ''
268 self.date = ''
269
269
270 @LazyProperty
270 @LazyProperty
271 def raw_id(self):
271 def raw_id(self):
272 """
272 """
273 Returns raw string identifying this changeset, useful for web
273 Returns raw string identifying this changeset, useful for web
274 representation.
274 representation.
275 """
275 """
276 return self._empty_cs
276 return self._empty_cs
277
277
278 @LazyProperty
278 @LazyProperty
279 def short_id(self):
279 def short_id(self):
280 return self.raw_id[:12]
280 return self.raw_id[:12]
281
281
282 def get_file_changeset(self, path):
282 def get_file_changeset(self, path):
283 return self
283 return self
284
284
285 def get_file_content(self, path):
285 def get_file_content(self, path):
286 return u''
286 return u''
287
287
288 def get_file_size(self, path):
288 def get_file_size(self, path):
289 return 0
289 return 0
290
290
291 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
291 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
292 """
292 """
293 maps all found repositories into db
293 maps all found repositories into db
294 """
294 """
295
295
296 sa = meta.Session()
296 sa = meta.Session()
297 rm = RepoModel()
297 rm = RepoModel()
298 user = sa.query(User).filter(User.admin == True).first()
298 user = sa.query(User).filter(User.admin == True).first()
299
299
300 for name, repo in initial_repo_list.items():
300 for name, repo in initial_repo_list.items():
301 if not rm.get_by_repo_name(name, cache=False):
301 if not rm.get_by_repo_name(name, cache=False):
302 log.info('repository %s not found creating default', name)
302 log.info('repository %s not found creating default', name)
303
303
304 form_data = {
304 form_data = {
305 'repo_name':name,
305 'repo_name':name,
306 'repo_type':repo.alias,
306 'repo_type':repo.alias,
307 'description':repo.description \
307 'description':repo.description \
308 if repo.description != 'unknown' else \
308 if repo.description != 'unknown' else \
309 '%s repository' % name,
309 '%s repository' % name,
310 'private':False
310 'private':False
311 }
311 }
312 rm.create(form_data, user, just_db=True)
312 rm.create(form_data, user, just_db=True)
313
313
314 if remove_obsolete:
314 if remove_obsolete:
315 #remove from database those repositories that are not in the filesystem
315 #remove from database those repositories that are not in the filesystem
316 for repo in sa.query(Repository).all():
316 for repo in sa.query(Repository).all():
317 if repo.repo_name not in initial_repo_list.keys():
317 if repo.repo_name not in initial_repo_list.keys():
318 sa.delete(repo)
318 sa.delete(repo)
319 sa.commit()
319 sa.commit()
320
320
321 class OrderedDict(dict, DictMixin):
321 class OrderedDict(dict, DictMixin):
322
322
323 def __init__(self, *args, **kwds):
323 def __init__(self, *args, **kwds):
324 if len(args) > 1:
324 if len(args) > 1:
325 raise TypeError('expected at most 1 arguments, got %d' % len(args))
325 raise TypeError('expected at most 1 arguments, got %d' % len(args))
326 try:
326 try:
327 self.__end
327 self.__end
328 except AttributeError:
328 except AttributeError:
329 self.clear()
329 self.clear()
330 self.update(*args, **kwds)
330 self.update(*args, **kwds)
331
331
332 def clear(self):
332 def clear(self):
333 self.__end = end = []
333 self.__end = end = []
334 end += [None, end, end] # sentinel node for doubly linked list
334 end += [None, end, end] # sentinel node for doubly linked list
335 self.__map = {} # key --> [key, prev, next]
335 self.__map = {} # key --> [key, prev, next]
336 dict.clear(self)
336 dict.clear(self)
337
337
338 def __setitem__(self, key, value):
338 def __setitem__(self, key, value):
339 if key not in self:
339 if key not in self:
340 end = self.__end
340 end = self.__end
341 curr = end[1]
341 curr = end[1]
342 curr[2] = end[1] = self.__map[key] = [key, curr, end]
342 curr[2] = end[1] = self.__map[key] = [key, curr, end]
343 dict.__setitem__(self, key, value)
343 dict.__setitem__(self, key, value)
344
344
345 def __delitem__(self, key):
345 def __delitem__(self, key):
346 dict.__delitem__(self, key)
346 dict.__delitem__(self, key)
347 key, prev, next = self.__map.pop(key)
347 key, prev, next = self.__map.pop(key)
348 prev[2] = next
348 prev[2] = next
349 next[1] = prev
349 next[1] = prev
350
350
351 def __iter__(self):
351 def __iter__(self):
352 end = self.__end
352 end = self.__end
353 curr = end[2]
353 curr = end[2]
354 while curr is not end:
354 while curr is not end:
355 yield curr[0]
355 yield curr[0]
356 curr = curr[2]
356 curr = curr[2]
357
357
358 def __reversed__(self):
358 def __reversed__(self):
359 end = self.__end
359 end = self.__end
360 curr = end[1]
360 curr = end[1]
361 while curr is not end:
361 while curr is not end:
362 yield curr[0]
362 yield curr[0]
363 curr = curr[1]
363 curr = curr[1]
364
364
365 def popitem(self, last=True):
365 def popitem(self, last=True):
366 if not self:
366 if not self:
367 raise KeyError('dictionary is empty')
367 raise KeyError('dictionary is empty')
368 if last:
368 if last:
369 key = reversed(self).next()
369 key = reversed(self).next()
370 else:
370 else:
371 key = iter(self).next()
371 key = iter(self).next()
372 value = self.pop(key)
372 value = self.pop(key)
373 return key, value
373 return key, value
374
374
375 def __reduce__(self):
375 def __reduce__(self):
376 items = [[k, self[k]] for k in self]
376 items = [[k, self[k]] for k in self]
377 tmp = self.__map, self.__end
377 tmp = self.__map, self.__end
378 del self.__map, self.__end
378 del self.__map, self.__end
379 inst_dict = vars(self).copy()
379 inst_dict = vars(self).copy()
380 self.__map, self.__end = tmp
380 self.__map, self.__end = tmp
381 if inst_dict:
381 if inst_dict:
382 return (self.__class__, (items,), inst_dict)
382 return (self.__class__, (items,), inst_dict)
383 return self.__class__, (items,)
383 return self.__class__, (items,)
384
384
385 def keys(self):
385 def keys(self):
386 return list(self)
386 return list(self)
387
387
388 setdefault = DictMixin.setdefault
388 setdefault = DictMixin.setdefault
389 update = DictMixin.update
389 update = DictMixin.update
390 pop = DictMixin.pop
390 pop = DictMixin.pop
391 values = DictMixin.values
391 values = DictMixin.values
392 items = DictMixin.items
392 items = DictMixin.items
393 iterkeys = DictMixin.iterkeys
393 iterkeys = DictMixin.iterkeys
394 itervalues = DictMixin.itervalues
394 itervalues = DictMixin.itervalues
395 iteritems = DictMixin.iteritems
395 iteritems = DictMixin.iteritems
396
396
397 def __repr__(self):
397 def __repr__(self):
398 if not self:
398 if not self:
399 return '%s()' % (self.__class__.__name__,)
399 return '%s()' % (self.__class__.__name__,)
400 return '%s(%r)' % (self.__class__.__name__, self.items())
400 return '%s(%r)' % (self.__class__.__name__, self.items())
401
401
402 def copy(self):
402 def copy(self):
403 return self.__class__(self)
403 return self.__class__(self)
404
404
405 @classmethod
405 @classmethod
406 def fromkeys(cls, iterable, value=None):
406 def fromkeys(cls, iterable, value=None):
407 d = cls()
407 d = cls()
408 for key in iterable:
408 for key in iterable:
409 d[key] = value
409 d[key] = value
410 return d
410 return d
411
411
412 def __eq__(self, other):
412 def __eq__(self, other):
413 if isinstance(other, OrderedDict):
413 if isinstance(other, OrderedDict):
414 return len(self) == len(other) and self.items() == other.items()
414 return len(self) == len(other) and self.items() == other.items()
415 return dict.__eq__(self, other)
415 return dict.__eq__(self, other)
416
416
417 def __ne__(self, other):
417 def __ne__(self, other):
418 return not self == other
418 return not self == other
419
419
420
420
421 #set cache regions for beaker so celery can utilise it
421 #set cache regions for beaker so celery can utilise it
422 def add_cache(settings):
422 def add_cache(settings):
423 cache_settings = {'regions':None}
423 cache_settings = {'regions':None}
424 for key in settings.keys():
424 for key in settings.keys():
425 for prefix in ['beaker.cache.', 'cache.']:
425 for prefix in ['beaker.cache.', 'cache.']:
426 if key.startswith(prefix):
426 if key.startswith(prefix):
427 name = key.split(prefix)[1].strip()
427 name = key.split(prefix)[1].strip()
428 cache_settings[name] = settings[key].strip()
428 cache_settings[name] = settings[key].strip()
429 if cache_settings['regions']:
429 if cache_settings['regions']:
430 for region in cache_settings['regions'].split(','):
430 for region in cache_settings['regions'].split(','):
431 region = region.strip()
431 region = region.strip()
432 region_settings = {}
432 region_settings = {}
433 for key, value in cache_settings.items():
433 for key, value in cache_settings.items():
434 if key.startswith(region):
434 if key.startswith(region):
435 region_settings[key.split('.')[1]] = value
435 region_settings[key.split('.')[1]] = value
436 region_settings['expire'] = int(region_settings.get('expire',
436 region_settings['expire'] = int(region_settings.get('expire',
437 60))
437 60))
438 region_settings.setdefault('lock_dir',
438 region_settings.setdefault('lock_dir',
439 cache_settings.get('lock_dir'))
439 cache_settings.get('lock_dir'))
440 if 'type' not in region_settings:
440 if 'type' not in region_settings:
441 region_settings['type'] = cache_settings.get('type',
441 region_settings['type'] = cache_settings.get('type',
442 'memory')
442 'memory')
443 beaker.cache.cache_regions[region] = region_settings
443 beaker.cache.cache_regions[region] = region_settings
444
444
445 def get_current_revision():
445 def get_current_revision():
446 """
446 """
447 Returns tuple of (number, id) from repository containing this package
447 Returns tuple of (number, id) from repository containing this package
448 or None if repository could not be found.
448 or None if repository could not be found.
449 """
449 """
450 try:
450 try:
451 from vcs import get_repo
451 from vcs import get_repo
452 from vcs.utils.helpers import get_scm
452 from vcs.utils.helpers import get_scm
453 from vcs.exceptions import RepositoryError, VCSError
453 from vcs.exceptions import RepositoryError, VCSError
454 repopath = os.path.join(os.path.dirname(__file__), '..', '..')
454 repopath = os.path.join(os.path.dirname(__file__), '..', '..')
455 scm = get_scm(repopath)[0]
455 scm = get_scm(repopath)[0]
456 repo = get_repo(path=repopath, alias=scm)
456 repo = get_repo(path=repopath, alias=scm)
457 tip = repo.get_changeset()
457 tip = repo.get_changeset()
458 return (tip.revision, tip.short_id)
458 return (tip.revision, tip.short_id)
459 except (ImportError, RepositoryError, VCSError), err:
459 except (ImportError, RepositoryError, VCSError), err:
460 logging.debug("Cannot retrieve rhodecode's revision. Original error "
460 logging.debug("Cannot retrieve rhodecode's revision. Original error "
461 "was: %s" % err)
461 "was: %s" % err)
462 return None
462 return None
463
463
464 #===============================================================================
464 #===============================================================================
465 # TEST FUNCTIONS AND CREATORS
465 # TEST FUNCTIONS AND CREATORS
466 #===============================================================================
466 #===============================================================================
467 def create_test_index(repo_location, full_index):
467 def create_test_index(repo_location, full_index):
468 """Makes default test index
468 """Makes default test index
469 :param repo_location:
469 :param repo_location:
470 :param full_index:
470 :param full_index:
471 """
471 """
472 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
472 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
473 from rhodecode.lib.pidlock import DaemonLock, LockHeld
473 from rhodecode.lib.pidlock import DaemonLock, LockHeld
474 import shutil
474 import shutil
475
475
476 index_location = os.path.join(repo_location, 'index')
476 index_location = os.path.join(repo_location, 'index')
477 if os.path.exists(index_location):
477 if os.path.exists(index_location):
478 shutil.rmtree(index_location)
478 shutil.rmtree(index_location)
479
479
480 try:
480 try:
481 l = DaemonLock()
481 l = DaemonLock()
482 WhooshIndexingDaemon(index_location=index_location,
482 WhooshIndexingDaemon(index_location=index_location,
483 repo_location=repo_location)\
483 repo_location=repo_location)\
484 .run(full_index=full_index)
484 .run(full_index=full_index)
485 l.release()
485 l.release()
486 except LockHeld:
486 except LockHeld:
487 pass
487 pass
488
488
489 def create_test_env(repos_test_path, config):
489 def create_test_env(repos_test_path, config):
490 """Makes a fresh database and
490 """Makes a fresh database and
491 install test repository into tmp dir
491 install test repository into tmp dir
492 """
492 """
493 from rhodecode.lib.db_manage import DbManage
493 from rhodecode.lib.db_manage import DbManage
494 from rhodecode.tests import HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, \
494 from rhodecode.tests import HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, \
495 HG_FORK, GIT_FORK, TESTS_TMP_PATH
495 HG_FORK, GIT_FORK, TESTS_TMP_PATH
496 import tarfile
496 import tarfile
497 import shutil
497 import shutil
498 from os.path import dirname as dn, join as jn, abspath
498 from os.path import dirname as dn, join as jn, abspath
499
499
500 log = logging.getLogger('TestEnvCreator')
500 log = logging.getLogger('TestEnvCreator')
501 # create logger
501 # create logger
502 log.setLevel(logging.DEBUG)
502 log.setLevel(logging.DEBUG)
503 log.propagate = True
503 log.propagate = True
504 # create console handler and set level to debug
504 # create console handler and set level to debug
505 ch = logging.StreamHandler()
505 ch = logging.StreamHandler()
506 ch.setLevel(logging.DEBUG)
506 ch.setLevel(logging.DEBUG)
507
507
508 # create formatter
508 # create formatter
509 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
509 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
510
510
511 # add formatter to ch
511 # add formatter to ch
512 ch.setFormatter(formatter)
512 ch.setFormatter(formatter)
513
513
514 # add ch to logger
514 # add ch to logger
515 log.addHandler(ch)
515 log.addHandler(ch)
516
516
517 #PART ONE create db
517 #PART ONE create db
518 dbconf = config['sqlalchemy.db1.url']
518 dbconf = config['sqlalchemy.db1.url']
519 log.debug('making test db %s', dbconf)
519 log.debug('making test db %s', dbconf)
520
520
521 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
521 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
522 tests=True)
522 tests=True)
523 dbmanage.create_tables(override=True)
523 dbmanage.create_tables(override=True)
524 dbmanage.config_prompt(repos_test_path)
524 dbmanage.config_prompt(repos_test_path)
525 dbmanage.create_default_user()
525 dbmanage.create_default_user()
526 dbmanage.admin_prompt()
526 dbmanage.admin_prompt()
527 dbmanage.create_permissions()
527 dbmanage.create_permissions()
528 dbmanage.populate_default_permissions()
528 dbmanage.populate_default_permissions()
529
529
530 #PART TWO make test repo
530 #PART TWO make test repo
531 log.debug('making test vcs repositories')
531 log.debug('making test vcs repositories')
532
532
533 #remove old one from previos tests
533 #remove old one from previos tests
534 for r in [HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, HG_FORK, GIT_FORK]:
534 for r in [HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, HG_FORK, GIT_FORK]:
535
535
536 if os.path.isdir(jn(TESTS_TMP_PATH, r)):
536 if os.path.isdir(jn(TESTS_TMP_PATH, r)):
537 log.debug('removing %s', r)
537 log.debug('removing %s', r)
538 shutil.rmtree(jn(TESTS_TMP_PATH, r))
538 shutil.rmtree(jn(TESTS_TMP_PATH, r))
539
539
540 #CREATE DEFAULT HG REPOSITORY
540 #CREATE DEFAULT HG REPOSITORY
541 cur_dir = dn(dn(abspath(__file__)))
541 cur_dir = dn(dn(abspath(__file__)))
542 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
542 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
543 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
543 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
544 tar.close()
544 tar.close()
545
545
546
546
547 #==============================================================================
547 #==============================================================================
548 # PASTER COMMANDS
548 # PASTER COMMANDS
549 #==============================================================================
549 #==============================================================================
550
550
551 class BasePasterCommand(Command):
551 class BasePasterCommand(Command):
552 """
552 """
553 Abstract Base Class for paster commands.
553 Abstract Base Class for paster commands.
554
554
555 The celery commands are somewhat aggressive about loading
555 The celery commands are somewhat aggressive about loading
556 celery.conf, and since our module sets the `CELERY_LOADER`
556 celery.conf, and since our module sets the `CELERY_LOADER`
557 environment variable to our loader, we have to bootstrap a bit and
557 environment variable to our loader, we have to bootstrap a bit and
558 make sure we've had a chance to load the pylons config off of the
558 make sure we've had a chance to load the pylons config off of the
559 command line, otherwise everything fails.
559 command line, otherwise everything fails.
560 """
560 """
561 min_args = 1
561 min_args = 1
562 min_args_error = "Please provide a paster config file as an argument."
562 min_args_error = "Please provide a paster config file as an argument."
563 takes_config_file = 1
563 takes_config_file = 1
564 requires_config_file = True
564 requires_config_file = True
565
565
566 def notify_msg(self, msg, log=False):
567 """Make a notification to user, additionally if logger is passed
568 it logs this action using given logger
569
570 :param msg: message that will be printed to user
571 :param log: logging instance, to use to additionally log this message
572
573 """
574 print msg
575 if log and isinstance(log, logging):
576 log(msg)
577
578
566 def run(self, args):
579 def run(self, args):
567 """
580 """
568 Overrides Command.run
581 Overrides Command.run
569
582
570 Checks for a config file argument and loads it.
583 Checks for a config file argument and loads it.
571 """
584 """
572 if len(args) < self.min_args:
585 if len(args) < self.min_args:
573 raise BadCommand(
586 raise BadCommand(
574 self.min_args_error % {'min_args': self.min_args,
587 self.min_args_error % {'min_args': self.min_args,
575 'actual_args': len(args)})
588 'actual_args': len(args)})
576
589
577 # Decrement because we're going to lob off the first argument.
590 # Decrement because we're going to lob off the first argument.
578 # @@ This is hacky
591 # @@ This is hacky
579 self.min_args -= 1
592 self.min_args -= 1
580 self.bootstrap_config(args[0])
593 self.bootstrap_config(args[0])
581 self.update_parser()
594 self.update_parser()
582 return super(BasePasterCommand, self).run(args[1:])
595 return super(BasePasterCommand, self).run(args[1:])
583
596
584 def update_parser(self):
597 def update_parser(self):
585 """
598 """
586 Abstract method. Allows for the class's parser to be updated
599 Abstract method. Allows for the class's parser to be updated
587 before the superclass's `run` method is called. Necessary to
600 before the superclass's `run` method is called. Necessary to
588 allow options/arguments to be passed through to the underlying
601 allow options/arguments to be passed through to the underlying
589 celery command.
602 celery command.
590 """
603 """
591 raise NotImplementedError("Abstract Method.")
604 raise NotImplementedError("Abstract Method.")
592
605
593 def bootstrap_config(self, conf):
606 def bootstrap_config(self, conf):
594 """
607 """
595 Loads the pylons configuration.
608 Loads the pylons configuration.
596 """
609 """
597 from pylons import config as pylonsconfig
610 from pylons import config as pylonsconfig
598
611
599 path_to_ini_file = os.path.realpath(conf)
612 path_to_ini_file = os.path.realpath(conf)
600 conf = paste.deploy.appconfig('config:' + path_to_ini_file)
613 conf = paste.deploy.appconfig('config:' + path_to_ini_file)
601 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
614 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
General Comments 0
You need to be logged in to leave comments. Login now