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