##// END OF EJS Templates
more user friendly message for repo path on setup
marcink -
r1896:12135cff beta
parent child Browse files
Show More
@@ -1,492 +1,494 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.db_manage
4 4 ~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Database creation, and setup module for RhodeCode. Used for creation
7 7 of database as well as for migration operations
8 8
9 9 :created_on: Apr 10, 2010
10 10 :author: marcink
11 11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26
27 27 import os
28 28 import sys
29 29 import uuid
30 30 import logging
31 31 from os.path import dirname as dn, join as jn
32 32
33 33 from rhodecode import __dbversion__
34 34 from rhodecode.model import meta
35 35
36 36 from rhodecode.model.user import UserModel
37 37 from rhodecode.lib.utils import ask_ok
38 38 from rhodecode.model import init_model
39 39 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
40 40 RhodeCodeSetting, UserToPerm, DbMigrateVersion
41 41
42 42 from sqlalchemy.engine import create_engine
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46
47 47 class DbManage(object):
48 48 def __init__(self, log_sql, dbconf, root, tests=False):
49 49 self.dbname = dbconf.split('/')[-1]
50 50 self.tests = tests
51 51 self.root = root
52 52 self.dburi = dbconf
53 53 self.log_sql = log_sql
54 54 self.db_exists = False
55 55 self.init_db()
56 56
57 57 def init_db(self):
58 58 engine = create_engine(self.dburi, echo=self.log_sql)
59 59 init_model(engine)
60 60 self.sa = meta.Session
61 61
62 62 def create_tables(self, override=False):
63 63 """
64 64 Create a auth database
65 65 """
66 66
67 67 log.info("Any existing database is going to be destroyed")
68 68 if self.tests:
69 69 destroy = True
70 70 else:
71 71 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
72 72 if not destroy:
73 73 sys.exit()
74 74 if destroy:
75 75 meta.Base.metadata.drop_all()
76 76
77 77 checkfirst = not override
78 78 meta.Base.metadata.create_all(checkfirst=checkfirst)
79 79 log.info('Created tables for %s', self.dbname)
80 80
81 81 def set_db_version(self):
82 82 ver = DbMigrateVersion()
83 83 ver.version = __dbversion__
84 84 ver.repository_id = 'rhodecode_db_migrations'
85 85 ver.repository_path = 'versions'
86 86 self.sa.add(ver)
87 87 log.info('db version set to: %s', __dbversion__)
88 88
89 89 def upgrade(self):
90 90 """
91 91 Upgrades given database schema to given revision following
92 92 all needed steps, to perform the upgrade
93 93
94 94 """
95 95
96 96 from rhodecode.lib.dbmigrate.migrate.versioning import api
97 97 from rhodecode.lib.dbmigrate.migrate.exceptions import \
98 98 DatabaseNotControlledError
99 99
100 100 if 'sqlite' in self.dburi:
101 101 print (
102 102 '********************** WARNING **********************\n'
103 103 'Make sure your version of sqlite is at least 3.7.X. \n'
104 104 'Earlier versions are known to fail on some migrations\n'
105 105 '*****************************************************\n'
106 106 )
107 107 upgrade = ask_ok('You are about to perform database upgrade, make '
108 108 'sure You backed up your database before. '
109 109 'Continue ? [y/n]')
110 110 if not upgrade:
111 111 sys.exit('Nothing done')
112 112
113 113 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
114 114 'rhodecode/lib/dbmigrate')
115 115 db_uri = self.dburi
116 116
117 117 try:
118 118 curr_version = api.db_version(db_uri, repository_path)
119 119 msg = ('Found current database under version'
120 120 ' control with version %s' % curr_version)
121 121
122 122 except (RuntimeError, DatabaseNotControlledError):
123 123 curr_version = 1
124 124 msg = ('Current database is not under version control. Setting'
125 125 ' as version %s' % curr_version)
126 126 api.version_control(db_uri, repository_path, curr_version)
127 127
128 128 print (msg)
129 129
130 130 if curr_version == __dbversion__:
131 131 sys.exit('This database is already at the newest version')
132 132
133 133 #======================================================================
134 134 # UPGRADE STEPS
135 135 #======================================================================
136 136 class UpgradeSteps(object):
137 137 """
138 138 Those steps follow schema versions so for example schema
139 139 for example schema with seq 002 == step_2 and so on.
140 140 """
141 141
142 142 def __init__(self, klass):
143 143 self.klass = klass
144 144
145 145 def step_0(self):
146 146 # step 0 is the schema upgrade, and than follow proper upgrades
147 147 print ('attempting to do database upgrade to version %s' \
148 148 % __dbversion__)
149 149 api.upgrade(db_uri, repository_path, __dbversion__)
150 150 print ('Schema upgrade completed')
151 151
152 152 def step_1(self):
153 153 pass
154 154
155 155 def step_2(self):
156 156 print ('Patching repo paths for newer version of RhodeCode')
157 157 self.klass.fix_repo_paths()
158 158
159 159 print ('Patching default user of RhodeCode')
160 160 self.klass.fix_default_user()
161 161
162 162 log.info('Changing ui settings')
163 163 self.klass.create_ui_settings()
164 164
165 165 def step_3(self):
166 166 print ('Adding additional settings into RhodeCode db')
167 167 self.klass.fix_settings()
168 168 print ('Adding ldap defaults')
169 169 self.klass.create_ldap_options(skip_existing=True)
170 170
171 171 def step_4(self):
172 172 print ('TODO:')
173 173
174 174 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
175 175
176 176 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
177 177 for step in upgrade_steps:
178 178 print ('performing upgrade step %s' % step)
179 179 getattr(UpgradeSteps(self), 'step_%s' % step)()
180 180
181 181 def fix_repo_paths(self):
182 182 """
183 183 Fixes a old rhodecode version path into new one without a '*'
184 184 """
185 185
186 186 paths = self.sa.query(RhodeCodeUi)\
187 187 .filter(RhodeCodeUi.ui_key == '/')\
188 188 .scalar()
189 189
190 190 paths.ui_value = paths.ui_value.replace('*', '')
191 191
192 192 try:
193 193 self.sa.add(paths)
194 194 self.sa.commit()
195 195 except:
196 196 self.sa.rollback()
197 197 raise
198 198
199 199 def fix_default_user(self):
200 200 """
201 201 Fixes a old default user with some 'nicer' default values,
202 202 used mostly for anonymous access
203 203 """
204 204 def_user = self.sa.query(User)\
205 205 .filter(User.username == 'default')\
206 206 .one()
207 207
208 208 def_user.name = 'Anonymous'
209 209 def_user.lastname = 'User'
210 210 def_user.email = 'anonymous@rhodecode.org'
211 211
212 212 try:
213 213 self.sa.add(def_user)
214 214 self.sa.commit()
215 215 except:
216 216 self.sa.rollback()
217 217 raise
218 218
219 219 def fix_settings(self):
220 220 """
221 221 Fixes rhodecode settings adds ga_code key for google analytics
222 222 """
223 223
224 224 hgsettings3 = RhodeCodeSetting('ga_code', '')
225 225
226 226 try:
227 227 self.sa.add(hgsettings3)
228 228 self.sa.commit()
229 229 except:
230 230 self.sa.rollback()
231 231 raise
232 232
233 233 def admin_prompt(self, second=False):
234 234 if not self.tests:
235 235 import getpass
236 236
237 237 def get_password():
238 238 password = getpass.getpass('Specify admin password '
239 239 '(min 6 chars):')
240 240 confirm = getpass.getpass('Confirm password:')
241 241
242 242 if password != confirm:
243 243 log.error('passwords mismatch')
244 244 return False
245 245 if len(password) < 6:
246 246 log.error('password is to short use at least 6 characters')
247 247 return False
248 248
249 249 return password
250 250
251 251 username = raw_input('Specify admin username:')
252 252
253 253 password = get_password()
254 254 if not password:
255 255 #second try
256 256 password = get_password()
257 257 if not password:
258 258 sys.exit()
259 259
260 260 email = raw_input('Specify admin email:')
261 261 self.create_user(username, password, email, True)
262 262 else:
263 263 log.info('creating admin and regular test users')
264 264 from rhodecode.tests import TEST_USER_ADMIN_LOGIN,\
265 265 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL,\
266 266 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,\
267 267 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
268 268 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
269 269
270 270 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
271 271 TEST_USER_ADMIN_EMAIL, True)
272 272
273 273 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
274 274 TEST_USER_REGULAR_EMAIL, False)
275 275
276 276 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
277 277 TEST_USER_REGULAR2_EMAIL, False)
278 278
279 279 def create_ui_settings(self):
280 280 """
281 281 Creates ui settings, fills out hooks
282 282 and disables dotencode
283 283 """
284 284
285 285 #HOOKS
286 286 hooks1_key = RhodeCodeUi.HOOK_UPDATE
287 287 hooks1_ = self.sa.query(RhodeCodeUi)\
288 288 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
289 289
290 290 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
291 291 hooks1.ui_section = 'hooks'
292 292 hooks1.ui_key = hooks1_key
293 293 hooks1.ui_value = 'hg update >&2'
294 294 hooks1.ui_active = False
295 295
296 296 hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
297 297 hooks2_ = self.sa.query(RhodeCodeUi)\
298 298 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
299 299
300 300 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
301 301 hooks2.ui_section = 'hooks'
302 302 hooks2.ui_key = hooks2_key
303 303 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
304 304
305 305 hooks3 = RhodeCodeUi()
306 306 hooks3.ui_section = 'hooks'
307 307 hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
308 308 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
309 309
310 310 hooks4 = RhodeCodeUi()
311 311 hooks4.ui_section = 'hooks'
312 312 hooks4.ui_key = RhodeCodeUi.HOOK_PULL
313 313 hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
314 314
315 315 # For mercurial 1.7 set backward comapatibility with format
316 316 dotencode_disable = RhodeCodeUi()
317 317 dotencode_disable.ui_section = 'format'
318 318 dotencode_disable.ui_key = 'dotencode'
319 319 dotencode_disable.ui_value = 'false'
320 320
321 321 # enable largefiles
322 322 largefiles = RhodeCodeUi()
323 323 largefiles.ui_section = 'extensions'
324 324 largefiles.ui_key = 'largefiles'
325 325 largefiles.ui_value = ''
326 326
327 327 self.sa.add(hooks1)
328 328 self.sa.add(hooks2)
329 329 self.sa.add(hooks3)
330 330 self.sa.add(hooks4)
331 331 self.sa.add(largefiles)
332 332
333 333 def create_ldap_options(self, skip_existing=False):
334 334 """Creates ldap settings"""
335 335
336 336 for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
337 337 ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
338 338 ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
339 339 ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
340 340 ('ldap_filter', ''), ('ldap_search_scope', ''),
341 341 ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
342 342 ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
343 343
344 344 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
345 345 log.debug('Skipping option %s' % k)
346 346 continue
347 347 setting = RhodeCodeSetting(k, v)
348 348 self.sa.add(setting)
349 349
350 350 def config_prompt(self, test_repo_path='', retries=3):
351 351 if retries == 3:
352 352 log.info('Setting up repositories config')
353 353
354 354 if not self.tests and not test_repo_path:
355 path = raw_input('Specify valid full path to your repositories'
356 ' you can change this later in application settings:')
355 path = raw_input(
356 'Enter a valid path to store repositories. '
357 'All repositories in that path will be added automatically:'
358 )
357 359 else:
358 360 path = test_repo_path
359 361 path_ok = True
360 362
361 363 # check proper dir
362 364 if not os.path.isdir(path):
363 365 path_ok = False
364 366 log.error('Given path %s is not a valid directory', path)
365 367
366 368 # check write access
367 369 if not os.access(path, os.W_OK) and path_ok:
368 370 path_ok = False
369 371 log.error('No write permission to given path %s', path)
370 372
371 373 if retries == 0:
372 374 sys.exit('max retries reached')
373 375 if path_ok is False:
374 376 retries -= 1
375 377 return self.config_prompt(test_repo_path, retries)
376 378
377 379 return path
378 380
379 381 def create_settings(self, path):
380 382
381 383 self.create_ui_settings()
382 384
383 385 #HG UI OPTIONS
384 386 web1 = RhodeCodeUi()
385 387 web1.ui_section = 'web'
386 388 web1.ui_key = 'push_ssl'
387 389 web1.ui_value = 'false'
388 390
389 391 web2 = RhodeCodeUi()
390 392 web2.ui_section = 'web'
391 393 web2.ui_key = 'allow_archive'
392 394 web2.ui_value = 'gz zip bz2'
393 395
394 396 web3 = RhodeCodeUi()
395 397 web3.ui_section = 'web'
396 398 web3.ui_key = 'allow_push'
397 399 web3.ui_value = '*'
398 400
399 401 web4 = RhodeCodeUi()
400 402 web4.ui_section = 'web'
401 403 web4.ui_key = 'baseurl'
402 404 web4.ui_value = '/'
403 405
404 406 paths = RhodeCodeUi()
405 407 paths.ui_section = 'paths'
406 408 paths.ui_key = '/'
407 409 paths.ui_value = path
408 410
409 411 hgsettings1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
410 412 hgsettings2 = RhodeCodeSetting('title', 'RhodeCode')
411 413 hgsettings3 = RhodeCodeSetting('ga_code', '')
412 414
413 415 self.sa.add(web1)
414 416 self.sa.add(web2)
415 417 self.sa.add(web3)
416 418 self.sa.add(web4)
417 419 self.sa.add(paths)
418 420 self.sa.add(hgsettings1)
419 421 self.sa.add(hgsettings2)
420 422 self.sa.add(hgsettings3)
421 423
422 424 self.create_ldap_options()
423 425
424 426 log.info('created ui config')
425 427
426 428 def create_user(self, username, password, email='', admin=False):
427 429 log.info('creating user %s', username)
428 430 UserModel().create_or_update(username, password, email,
429 431 name='RhodeCode', lastname='Admin',
430 432 active=True, admin=admin)
431 433
432 434 def create_default_user(self):
433 435 log.info('creating default user')
434 436 # create default user for handling default permissions.
435 437 UserModel().create_or_update(username='default',
436 438 password=str(uuid.uuid1())[:8],
437 439 email='anonymous@rhodecode.org',
438 440 name='Anonymous', lastname='User')
439 441
440 442 def create_permissions(self):
441 443 # module.(access|create|change|delete)_[name]
442 444 # module.(read|write|owner)
443 445 perms = [('repository.none', 'Repository no access'),
444 446 ('repository.read', 'Repository read access'),
445 447 ('repository.write', 'Repository write access'),
446 448 ('repository.admin', 'Repository admin access'),
447 449 ('hg.admin', 'Hg Administrator'),
448 450 ('hg.create.repository', 'Repository create'),
449 451 ('hg.create.none', 'Repository creation disabled'),
450 452 ('hg.register.none', 'Register disabled'),
451 453 ('hg.register.manual_activate', 'Register new user with '
452 454 'RhodeCode without manual'
453 455 'activation'),
454 456
455 457 ('hg.register.auto_activate', 'Register new user with '
456 458 'RhodeCode without auto '
457 459 'activation'),
458 460 ]
459 461
460 462 for p in perms:
461 463 new_perm = Permission()
462 464 new_perm.permission_name = p[0]
463 465 new_perm.permission_longname = p[1]
464 466 self.sa.add(new_perm)
465 467
466 468 def populate_default_permissions(self):
467 469 log.info('creating default user permissions')
468 470
469 471 default_user = self.sa.query(User)\
470 472 .filter(User.username == 'default').scalar()
471 473
472 474 reg_perm = UserToPerm()
473 475 reg_perm.user = default_user
474 476 reg_perm.permission = self.sa.query(Permission)\
475 477 .filter(Permission.permission_name == 'hg.register.manual_activate')\
476 478 .scalar()
477 479
478 480 create_repo_perm = UserToPerm()
479 481 create_repo_perm.user = default_user
480 482 create_repo_perm.permission = self.sa.query(Permission)\
481 483 .filter(Permission.permission_name == 'hg.create.repository')\
482 484 .scalar()
483 485
484 486 default_repo_perm = UserToPerm()
485 487 default_repo_perm.user = default_user
486 488 default_repo_perm.permission = self.sa.query(Permission)\
487 489 .filter(Permission.permission_name == 'repository.read')\
488 490 .scalar()
489 491
490 492 self.sa.add(reg_perm)
491 493 self.sa.add(create_repo_perm)
492 494 self.sa.add(default_repo_perm)
General Comments 0
You need to be logged in to leave comments. Login now