##// END OF EJS Templates
Added missing migrations, and move update_repoinfo to RepoModel...
marcink -
r3309:b3cf4539 beta
parent child Browse files
Show More
@@ -0,0 +1,28 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.model.db_1_6_0
4 ~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Database Models for RhodeCode <=1.5.X
7
8 :created_on: Apr 08, 2010
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26 #TODO: replace that will db.py content after next
27
28 from rhodecode.model.db import *
@@ -0,0 +1,36 b''
1 import logging
2 import datetime
3
4 from sqlalchemy import *
5 from sqlalchemy.exc import DatabaseError
6 from sqlalchemy.orm import relation, backref, class_mapper, joinedload
7 from sqlalchemy.orm.session import Session
8 from sqlalchemy.ext.declarative import declarative_base
9
10 from rhodecode.lib.dbmigrate.migrate import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
12
13 from rhodecode.model.meta import Base
14 from rhodecode.model import meta
15 from rhodecode.lib.dbmigrate.versions import _reset_base
16
17 log = logging.getLogger(__name__)
18
19
20 def upgrade(migrate_engine):
21 """
22 Upgrade operations go here.
23 Don't create your own engine; bind migrate_engine to your metadata
24 """
25 _reset_base(migrate_engine)
26 #==========================================================================
27 # USER LOGS
28 #==========================================================================
29 from rhodecode.lib.dbmigrate.schema.db_1_6_0 import RepositoryField
30 tbl = RepositoryField.__table__
31 tbl.create()
32
33
34 def downgrade(migrate_engine):
35 meta = MetaData()
36 meta.bind = migrate_engine
@@ -1,715 +1,722 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__, __py_version__
34 34
35 35 from rhodecode.model.user import UserModel
36 36 from rhodecode.lib.utils import ask_ok
37 37 from rhodecode.model import init_model
38 38 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
39 39 RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup, \
40 40 UserRepoGroupToPerm
41 41
42 42 from sqlalchemy.engine import create_engine
43 43 from rhodecode.model.repos_group import ReposGroupModel
44 44 #from rhodecode.model import meta
45 45 from rhodecode.model.meta import Session, Base
46 from rhodecode.model.repo import RepoModel
46 47
47 48
48 49 log = logging.getLogger(__name__)
49 50
50 51
51 52 def notify(msg):
52 53 """
53 54 Notification for migrations messages
54 55 """
55 56 ml = len(msg) + (4 * 2)
56 57 print >> sys.stdout, ('*** %s ***\n%s' % (msg, '*' * ml)).upper()
57 58
58 59
59 60 class DbManage(object):
60 61 def __init__(self, log_sql, dbconf, root, tests=False, cli_args={}):
61 62 self.dbname = dbconf.split('/')[-1]
62 63 self.tests = tests
63 64 self.root = root
64 65 self.dburi = dbconf
65 66 self.log_sql = log_sql
66 67 self.db_exists = False
67 68 self.cli_args = cli_args
68 69 self.init_db()
69 70 global ask_ok
70 71
71 72 if self.cli_args.get('force_ask') is True:
72 73 ask_ok = lambda *args, **kwargs: True
73 74 elif self.cli_args.get('force_ask') is False:
74 75 ask_ok = lambda *args, **kwargs: False
75 76
76 77 def init_db(self):
77 78 engine = create_engine(self.dburi, echo=self.log_sql)
78 79 init_model(engine)
79 80 self.sa = Session()
80 81
81 82 def create_tables(self, override=False):
82 83 """
83 84 Create a auth database
84 85 """
85 86
86 87 log.info("Any existing database is going to be destroyed")
87 88 if self.tests:
88 89 destroy = True
89 90 else:
90 91 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
91 92 if not destroy:
92 93 sys.exit('Nothing done')
93 94 if destroy:
94 95 Base.metadata.drop_all()
95 96
96 97 checkfirst = not override
97 98 Base.metadata.create_all(checkfirst=checkfirst)
98 99 log.info('Created tables for %s' % self.dbname)
99 100
100 101 def set_db_version(self):
101 102 ver = DbMigrateVersion()
102 103 ver.version = __dbversion__
103 104 ver.repository_id = 'rhodecode_db_migrations'
104 105 ver.repository_path = 'versions'
105 106 self.sa.add(ver)
106 107 log.info('db version set to: %s' % __dbversion__)
107 108
108 109 def upgrade(self):
109 110 """
110 111 Upgrades given database schema to given revision following
111 112 all needed steps, to perform the upgrade
112 113
113 114 """
114 115
115 116 from rhodecode.lib.dbmigrate.migrate.versioning import api
116 117 from rhodecode.lib.dbmigrate.migrate.exceptions import \
117 118 DatabaseNotControlledError
118 119
119 120 if 'sqlite' in self.dburi:
120 121 print (
121 122 '********************** WARNING **********************\n'
122 123 'Make sure your version of sqlite is at least 3.7.X. \n'
123 124 'Earlier versions are known to fail on some migrations\n'
124 125 '*****************************************************\n'
125 126 )
126 127 upgrade = ask_ok('You are about to perform database upgrade, make '
127 128 'sure You backed up your database before. '
128 129 'Continue ? [y/n]')
129 130 if not upgrade:
130 131 sys.exit('Nothing done')
131 132
132 133 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
133 134 'rhodecode/lib/dbmigrate')
134 135 db_uri = self.dburi
135 136
136 137 try:
137 138 curr_version = api.db_version(db_uri, repository_path)
138 139 msg = ('Found current database under version'
139 140 ' control with version %s' % curr_version)
140 141
141 142 except (RuntimeError, DatabaseNotControlledError):
142 143 curr_version = 1
143 144 msg = ('Current database is not under version control. Setting'
144 145 ' as version %s' % curr_version)
145 146 api.version_control(db_uri, repository_path, curr_version)
146 147
147 148 notify(msg)
148 149
149 150 if curr_version == __dbversion__:
150 151 sys.exit('This database is already at the newest version')
151 152
152 153 #======================================================================
153 154 # UPGRADE STEPS
154 155 #======================================================================
155 156
156 157 class UpgradeSteps(object):
157 158 """
158 159 Those steps follow schema versions so for example schema
159 160 for example schema with seq 002 == step_2 and so on.
160 161 """
161 162
162 163 def __init__(self, klass):
163 164 self.klass = klass
164 165
165 166 def step_0(self):
166 167 # step 0 is the schema upgrade, and than follow proper upgrades
167 168 notify('attempting to do database upgrade from '
168 169 'version %s to version %s' %(curr_version, __dbversion__))
169 170 api.upgrade(db_uri, repository_path, __dbversion__)
170 171 notify('Schema upgrade completed')
171 172
172 173 def step_1(self):
173 174 pass
174 175
175 176 def step_2(self):
176 177 notify('Patching repo paths for newer version of RhodeCode')
177 178 self.klass.fix_repo_paths()
178 179
179 180 notify('Patching default user of RhodeCode')
180 181 self.klass.fix_default_user()
181 182
182 183 log.info('Changing ui settings')
183 184 self.klass.create_ui_settings()
184 185
185 186 def step_3(self):
186 187 notify('Adding additional settings into RhodeCode db')
187 188 self.klass.fix_settings()
188 189 notify('Adding ldap defaults')
189 190 self.klass.create_ldap_options(skip_existing=True)
190 191
191 192 def step_4(self):
192 193 notify('create permissions and fix groups')
193 194 self.klass.create_permissions()
194 195 self.klass.fixup_groups()
195 196
196 197 def step_5(self):
197 198 pass
198 199
199 200 def step_6(self):
200 201
201 202 notify('re-checking permissions')
202 203 self.klass.create_permissions()
203 204
204 205 notify('installing new UI options')
205 206 sett4 = RhodeCodeSetting('show_public_icon', True)
206 207 Session().add(sett4)
207 208 sett5 = RhodeCodeSetting('show_private_icon', True)
208 209 Session().add(sett5)
209 210 sett6 = RhodeCodeSetting('stylify_metatags', False)
210 211 Session().add(sett6)
211 212
212 213 notify('fixing old PULL hook')
213 214 _pull = RhodeCodeUi.get_by_key('preoutgoing.pull_logger')
214 215 if _pull:
215 216 _pull.ui_key = RhodeCodeUi.HOOK_PULL
216 217 Session().add(_pull)
217 218
218 219 notify('fixing old PUSH hook')
219 220 _push = RhodeCodeUi.get_by_key('pretxnchangegroup.push_logger')
220 221 if _push:
221 222 _push.ui_key = RhodeCodeUi.HOOK_PUSH
222 223 Session().add(_push)
223 224
224 225 notify('installing new pre-push hook')
225 226 hooks4 = RhodeCodeUi()
226 227 hooks4.ui_section = 'hooks'
227 228 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
228 229 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
229 230 Session().add(hooks4)
230 231
231 232 notify('installing new pre-pull hook')
232 233 hooks6 = RhodeCodeUi()
233 234 hooks6.ui_section = 'hooks'
234 235 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
235 236 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
236 237 Session().add(hooks6)
237 238
238 239 notify('installing hgsubversion option')
239 240 # enable hgsubversion disabled by default
240 241 hgsubversion = RhodeCodeUi()
241 242 hgsubversion.ui_section = 'extensions'
242 243 hgsubversion.ui_key = 'hgsubversion'
243 244 hgsubversion.ui_value = ''
244 245 hgsubversion.ui_active = False
245 246 Session().add(hgsubversion)
246 247
247 248 notify('installing hg git option')
248 249 # enable hggit disabled by default
249 250 hggit = RhodeCodeUi()
250 251 hggit.ui_section = 'extensions'
251 252 hggit.ui_key = 'hggit'
252 253 hggit.ui_value = ''
253 254 hggit.ui_active = False
254 255 Session().add(hggit)
255 256
256 257 notify('re-check default permissions')
257 258 default_user = User.get_by_username(User.DEFAULT_USER)
258 259 perm = Permission.get_by_key('hg.fork.repository')
259 260 reg_perm = UserToPerm()
260 261 reg_perm.user = default_user
261 262 reg_perm.permission = perm
262 263 Session().add(reg_perm)
263 264
264 265 def step_7(self):
265 266 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
266 267 Session().commit()
267 268 if perm_fixes:
268 269 notify('There was an inconsistent state of permissions '
269 270 'detected for default user. Permissions are now '
270 271 'reset to the default value for default user. '
271 272 'Please validate and check default permissions '
272 273 'in admin panel')
273 274
274 275 def step_8(self):
275 276 self.klass.populate_default_permissions()
276 277 self.klass.create_default_options(skip_existing=True)
277 278 Session().commit()
278 279
279 280 def step_9(self):
280 281 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
281 282 Session().commit()
282 283 if perm_fixes:
283 284 notify('There was an inconsistent state of permissions '
284 285 'detected for default user. Permissions are now '
285 286 'reset to the default value for default user. '
286 287 'Please validate and check default permissions '
287 288 'in admin panel')
288 289
289 290 def step_10(self):
290 291 pass
291 292
293 def step_11(self):
294 self.klass.update_repo_info()
295
292 296 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
293 297
294 298 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
295 299 _step = None
296 300 for step in upgrade_steps:
297 301 notify('performing upgrade step %s' % step)
298 302 getattr(UpgradeSteps(self), 'step_%s' % step)()
299 303 self.sa.commit()
300 304 _step = step
301 305
302 306 notify('upgrade to version %s successful' % _step)
303 307
304 308 def fix_repo_paths(self):
305 309 """
306 310 Fixes a old rhodecode version path into new one without a '*'
307 311 """
308 312
309 313 paths = self.sa.query(RhodeCodeUi)\
310 314 .filter(RhodeCodeUi.ui_key == '/')\
311 315 .scalar()
312 316
313 317 paths.ui_value = paths.ui_value.replace('*', '')
314 318
315 319 try:
316 320 self.sa.add(paths)
317 321 self.sa.commit()
318 322 except:
319 323 self.sa.rollback()
320 324 raise
321 325
322 326 def fix_default_user(self):
323 327 """
324 328 Fixes a old default user with some 'nicer' default values,
325 329 used mostly for anonymous access
326 330 """
327 331 def_user = self.sa.query(User)\
328 332 .filter(User.username == 'default')\
329 333 .one()
330 334
331 335 def_user.name = 'Anonymous'
332 336 def_user.lastname = 'User'
333 337 def_user.email = 'anonymous@rhodecode.org'
334 338
335 339 try:
336 340 self.sa.add(def_user)
337 341 self.sa.commit()
338 342 except:
339 343 self.sa.rollback()
340 344 raise
341 345
342 346 def fix_settings(self):
343 347 """
344 348 Fixes rhodecode settings adds ga_code key for google analytics
345 349 """
346 350
347 351 hgsettings3 = RhodeCodeSetting('ga_code', '')
348 352
349 353 try:
350 354 self.sa.add(hgsettings3)
351 355 self.sa.commit()
352 356 except:
353 357 self.sa.rollback()
354 358 raise
355 359
356 360 def admin_prompt(self, second=False):
357 361 if not self.tests:
358 362 import getpass
359 363
360 364 # defaults
361 365 defaults = self.cli_args
362 366 username = defaults.get('username')
363 367 password = defaults.get('password')
364 368 email = defaults.get('email')
365 369
366 370 def get_password():
367 371 password = getpass.getpass('Specify admin password '
368 372 '(min 6 chars):')
369 373 confirm = getpass.getpass('Confirm password:')
370 374
371 375 if password != confirm:
372 376 log.error('passwords mismatch')
373 377 return False
374 378 if len(password) < 6:
375 379 log.error('password is to short use at least 6 characters')
376 380 return False
377 381
378 382 return password
379 383 if username is None:
380 384 username = raw_input('Specify admin username:')
381 385 if password is None:
382 386 password = get_password()
383 387 if not password:
384 388 #second try
385 389 password = get_password()
386 390 if not password:
387 391 sys.exit()
388 392 if email is None:
389 393 email = raw_input('Specify admin email:')
390 394 self.create_user(username, password, email, True)
391 395 else:
392 396 log.info('creating admin and regular test users')
393 397 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
394 398 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
395 399 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
396 400 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
397 401 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
398 402
399 403 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
400 404 TEST_USER_ADMIN_EMAIL, True)
401 405
402 406 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
403 407 TEST_USER_REGULAR_EMAIL, False)
404 408
405 409 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
406 410 TEST_USER_REGULAR2_EMAIL, False)
407 411
408 412 def create_ui_settings(self):
409 413 """
410 414 Creates ui settings, fills out hooks
411 415 and disables dotencode
412 416 """
413 417
414 418 #HOOKS
415 419 hooks1_key = RhodeCodeUi.HOOK_UPDATE
416 420 hooks1_ = self.sa.query(RhodeCodeUi)\
417 421 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
418 422
419 423 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
420 424 hooks1.ui_section = 'hooks'
421 425 hooks1.ui_key = hooks1_key
422 426 hooks1.ui_value = 'hg update >&2'
423 427 hooks1.ui_active = False
424 428 self.sa.add(hooks1)
425 429
426 430 hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
427 431 hooks2_ = self.sa.query(RhodeCodeUi)\
428 432 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
429 433 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
430 434 hooks2.ui_section = 'hooks'
431 435 hooks2.ui_key = hooks2_key
432 436 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
433 437 self.sa.add(hooks2)
434 438
435 439 hooks3 = RhodeCodeUi()
436 440 hooks3.ui_section = 'hooks'
437 441 hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
438 442 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
439 443 self.sa.add(hooks3)
440 444
441 445 hooks4 = RhodeCodeUi()
442 446 hooks4.ui_section = 'hooks'
443 447 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
444 448 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
445 449 self.sa.add(hooks4)
446 450
447 451 hooks5 = RhodeCodeUi()
448 452 hooks5.ui_section = 'hooks'
449 453 hooks5.ui_key = RhodeCodeUi.HOOK_PULL
450 454 hooks5.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
451 455 self.sa.add(hooks5)
452 456
453 457 hooks6 = RhodeCodeUi()
454 458 hooks6.ui_section = 'hooks'
455 459 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
456 460 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
457 461 self.sa.add(hooks6)
458 462
459 463 # enable largefiles
460 464 largefiles = RhodeCodeUi()
461 465 largefiles.ui_section = 'extensions'
462 466 largefiles.ui_key = 'largefiles'
463 467 largefiles.ui_value = ''
464 468 self.sa.add(largefiles)
465 469
466 470 # enable hgsubversion disabled by default
467 471 hgsubversion = RhodeCodeUi()
468 472 hgsubversion.ui_section = 'extensions'
469 473 hgsubversion.ui_key = 'hgsubversion'
470 474 hgsubversion.ui_value = ''
471 475 hgsubversion.ui_active = False
472 476 self.sa.add(hgsubversion)
473 477
474 478 # enable hggit disabled by default
475 479 hggit = RhodeCodeUi()
476 480 hggit.ui_section = 'extensions'
477 481 hggit.ui_key = 'hggit'
478 482 hggit.ui_value = ''
479 483 hggit.ui_active = False
480 484 self.sa.add(hggit)
481 485
482 486 def create_ldap_options(self, skip_existing=False):
483 487 """Creates ldap settings"""
484 488
485 489 for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
486 490 ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
487 491 ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
488 492 ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
489 493 ('ldap_filter', ''), ('ldap_search_scope', ''),
490 494 ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
491 495 ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
492 496
493 497 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
494 498 log.debug('Skipping option %s' % k)
495 499 continue
496 500 setting = RhodeCodeSetting(k, v)
497 501 self.sa.add(setting)
498 502
499 503 def create_default_options(self, skip_existing=False):
500 504 """Creates default settings"""
501 505
502 506 for k, v in [
503 507 ('default_repo_enable_locking', False),
504 508 ('default_repo_enable_downloads', False),
505 509 ('default_repo_enable_statistics', False),
506 510 ('default_repo_private', False),
507 511 ('default_repo_type', 'hg')]:
508 512
509 513 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
510 514 log.debug('Skipping option %s' % k)
511 515 continue
512 516 setting = RhodeCodeSetting(k, v)
513 517 self.sa.add(setting)
514 518
515 519 def fixup_groups(self):
516 520 def_usr = User.get_by_username('default')
517 521 for g in RepoGroup.query().all():
518 522 g.group_name = g.get_new_name(g.name)
519 523 self.sa.add(g)
520 524 # get default perm
521 525 default = UserRepoGroupToPerm.query()\
522 526 .filter(UserRepoGroupToPerm.group == g)\
523 527 .filter(UserRepoGroupToPerm.user == def_usr)\
524 528 .scalar()
525 529
526 530 if default is None:
527 531 log.debug('missing default permission for group %s adding' % g)
528 532 ReposGroupModel()._create_default_perms(g)
529 533
530 534 def reset_permissions(self, username):
531 535 """
532 536 Resets permissions to default state, usefull when old systems had
533 537 bad permissions, we must clean them up
534 538
535 539 :param username:
536 540 :type username:
537 541 """
538 542 default_user = User.get_by_username(username)
539 543 if not default_user:
540 544 return
541 545
542 546 u2p = UserToPerm.query()\
543 547 .filter(UserToPerm.user == default_user).all()
544 548 fixed = False
545 549 if len(u2p) != len(User.DEFAULT_PERMISSIONS):
546 550 for p in u2p:
547 551 Session().delete(p)
548 552 fixed = True
549 553 self.populate_default_permissions()
550 554 return fixed
551 555
556 def update_repo_info(self):
557 RepoModel.update_repoinfo()
558
552 559 def config_prompt(self, test_repo_path='', retries=3):
553 560 defaults = self.cli_args
554 561 _path = defaults.get('repos_location')
555 562 if retries == 3:
556 563 log.info('Setting up repositories config')
557 564
558 565 if _path is not None:
559 566 path = _path
560 567 elif not self.tests and not test_repo_path:
561 568 path = raw_input(
562 569 'Enter a valid absolute path to store repositories. '
563 570 'All repositories in that path will be added automatically:'
564 571 )
565 572 else:
566 573 path = test_repo_path
567 574 path_ok = True
568 575
569 576 # check proper dir
570 577 if not os.path.isdir(path):
571 578 path_ok = False
572 579 log.error('Given path %s is not a valid directory' % path)
573 580
574 581 elif not os.path.isabs(path):
575 582 path_ok = False
576 583 log.error('Given path %s is not an absolute path' % path)
577 584
578 585 # check write access
579 586 elif not os.access(path, os.W_OK) and path_ok:
580 587 path_ok = False
581 588 log.error('No write permission to given path %s' % path)
582 589
583 590 if retries == 0:
584 591 sys.exit('max retries reached')
585 592 if path_ok is False:
586 593 retries -= 1
587 594 return self.config_prompt(test_repo_path, retries)
588 595
589 596 real_path = os.path.normpath(os.path.realpath(path))
590 597
591 598 if real_path != os.path.normpath(path):
592 599 if not ask_ok(('Path looks like a symlink, Rhodecode will store '
593 600 'given path as %s ? [y/n]') % (real_path)):
594 601 log.error('Canceled by user')
595 602 sys.exit(-1)
596 603
597 604 return real_path
598 605
599 606 def create_settings(self, path):
600 607
601 608 self.create_ui_settings()
602 609
603 610 #HG UI OPTIONS
604 611 web1 = RhodeCodeUi()
605 612 web1.ui_section = 'web'
606 613 web1.ui_key = 'push_ssl'
607 614 web1.ui_value = 'false'
608 615
609 616 web2 = RhodeCodeUi()
610 617 web2.ui_section = 'web'
611 618 web2.ui_key = 'allow_archive'
612 619 web2.ui_value = 'gz zip bz2'
613 620
614 621 web3 = RhodeCodeUi()
615 622 web3.ui_section = 'web'
616 623 web3.ui_key = 'allow_push'
617 624 web3.ui_value = '*'
618 625
619 626 web4 = RhodeCodeUi()
620 627 web4.ui_section = 'web'
621 628 web4.ui_key = 'baseurl'
622 629 web4.ui_value = '/'
623 630
624 631 paths = RhodeCodeUi()
625 632 paths.ui_section = 'paths'
626 633 paths.ui_key = '/'
627 634 paths.ui_value = path
628 635
629 636 phases = RhodeCodeUi()
630 637 phases.ui_section = 'phases'
631 638 phases.ui_key = 'publish'
632 639 phases.ui_value = False
633 640
634 641 sett1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
635 642 sett2 = RhodeCodeSetting('title', 'RhodeCode')
636 643 sett3 = RhodeCodeSetting('ga_code', '')
637 644
638 645 sett4 = RhodeCodeSetting('show_public_icon', True)
639 646 sett5 = RhodeCodeSetting('show_private_icon', True)
640 647 sett6 = RhodeCodeSetting('stylify_metatags', False)
641 648
642 649 self.sa.add(web1)
643 650 self.sa.add(web2)
644 651 self.sa.add(web3)
645 652 self.sa.add(web4)
646 653 self.sa.add(paths)
647 654 self.sa.add(sett1)
648 655 self.sa.add(sett2)
649 656 self.sa.add(sett3)
650 657 self.sa.add(sett4)
651 658 self.sa.add(sett5)
652 659 self.sa.add(sett6)
653 660
654 661 self.create_ldap_options()
655 662 self.create_default_options()
656 663
657 664 log.info('created ui config')
658 665
659 666 def create_user(self, username, password, email='', admin=False):
660 667 log.info('creating user %s' % username)
661 668 UserModel().create_or_update(username, password, email,
662 669 firstname='RhodeCode', lastname='Admin',
663 670 active=True, admin=admin)
664 671
665 672 def create_default_user(self):
666 673 log.info('creating default user')
667 674 # create default user for handling default permissions.
668 675 UserModel().create_or_update(username='default',
669 676 password=str(uuid.uuid1())[:8],
670 677 email='anonymous@rhodecode.org',
671 678 firstname='Anonymous', lastname='User')
672 679
673 680 def create_permissions(self):
674 681 # module.(access|create|change|delete)_[name]
675 682 # module.(none|read|write|admin)
676 683
677 684 for p in Permission.PERMS:
678 685 if not Permission.get_by_key(p[0]):
679 686 new_perm = Permission()
680 687 new_perm.permission_name = p[0]
681 688 new_perm.permission_longname = p[0]
682 689 self.sa.add(new_perm)
683 690
684 691 def populate_default_permissions(self):
685 692 log.info('creating default user permissions')
686 693
687 694 default_user = User.get_by_username('default')
688 695
689 696 for def_perm in User.DEFAULT_PERMISSIONS:
690 697
691 698 perm = self.sa.query(Permission)\
692 699 .filter(Permission.permission_name == def_perm)\
693 700 .scalar()
694 701 if not perm:
695 702 raise Exception(
696 703 'CRITICAL: permission %s not found inside database !!'
697 704 % def_perm
698 705 )
699 706 if not UserToPerm.query()\
700 707 .filter(UserToPerm.permission == perm)\
701 708 .filter(UserToPerm.user == default_user).scalar():
702 709 reg_perm = UserToPerm()
703 710 reg_perm.user = default_user
704 711 reg_perm.permission = perm
705 712 self.sa.add(reg_perm)
706 713
707 714 @staticmethod
708 715 def check_waitress():
709 716 """
710 717 Function executed at the end of setup
711 718 """
712 719 if not __py_version__ >= (2, 6):
713 720 notify('Python2.5 detected, please switch '
714 721 'egg:waitress#main -> egg:Paste#http '
715 722 'in your .ini file')
@@ -1,87 +1,87 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 package.rhodecode.lib.cleanup
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 :created_on: Jul 14, 2012
7 7 :author: marcink
8 8 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
9 9 :license: GPLv3, see COPYING for more details.
10 10 """
11 11 # This program is free software: you can redistribute it and/or modify
12 12 # it under the terms of the GNU General Public License as published by
13 13 # the Free Software Foundation, either version 3 of the License, or
14 14 # (at your option) any later version.
15 15 #
16 16 # This program is distributed in the hope that it will be useful,
17 17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 19 # GNU General Public License for more details.
20 20 #
21 21 # You should have received a copy of the GNU General Public License
22 22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 23 from __future__ import with_statement
24 24
25 25 import os
26 26 import sys
27 27 import re
28 28 import shutil
29 29 import logging
30 30 import datetime
31 31 import string
32 32
33 33 from os.path import dirname as dn, join as jn
34 34 from rhodecode.model import init_model
35 from rhodecode.lib.utils2 import engine_from_config, safe_str
36 from rhodecode.model.db import RhodeCodeUi, Repository
37 from rhodecode.lib.vcs.backends.base import EmptyChangeset
35 from rhodecode.lib.utils2 import engine_from_config
36 from rhodecode.model.db import Repository
37 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.meta import Session
38 39
39 40
40 41 #to get the rhodecode import
41 42 sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
42 43
43 44 from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
44 45
45 46 log = logging.getLogger(__name__)
46 47
47 48
48 49 class UpdateCommand(BasePasterCommand):
49 50
50 51 max_args = 1
51 52 min_args = 1
52 53
53 54 usage = "CONFIG_FILE"
54 55 summary = "Cleanup deleted repos"
55 56 group_name = "RhodeCode"
56 57 takes_config_file = -1
57 58 parser = Command.standard_parser(verbose=True)
58 59
59 60 def command(self):
60 61 logging.config.fileConfig(self.path_to_ini_file)
61 62 from pylons import config
62 63
63 64 #get to remove repos !!
64 65 add_cache(config)
65 66 engine = engine_from_config(config, 'sqlalchemy.db1.')
66 67 init_model(engine)
67 68
68 69 repo_update_list = map(string.strip,
69 70 self.options.repo_update_list.split(',')) \
70 71 if self.options.repo_update_list else None
71 72
72 73 if repo_update_list:
73 repo_list = Repository.query().filter(Repository.repo_name.in_(repo_update_list))
74 repo_list = Repository.query()\
75 .filter(Repository.repo_name.in_(repo_update_list))
74 76 else:
75 77 repo_list = Repository.getAll()
76 for repo in repo_list:
77 last_cs = (repo.scm_instance.get_changeset() if repo.scm_instance
78 else EmptyChangeset())
79 repo.update_changeset_cache(last_cs)
78 RepoModel.update_repoinfo(repositories=repo_list)
79 Session().commit()
80 80
81 81 def update_parser(self):
82 82 self.parser.add_option('--update-only',
83 83 action='store',
84 84 dest='repo_update_list',
85 85 help="Specifies a comma separated list of repositores "
86 86 "to update last commit info for. OPTIONAL",
87 87 )
@@ -1,693 +1,705 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.repo
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repository model for rhodecode
7 7
8 8 :created_on: Jun 5, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 from __future__ import with_statement
26 26 import os
27 27 import shutil
28 28 import logging
29 29 import traceback
30 30 from datetime import datetime
31 31
32 32 from rhodecode.lib.vcs.backends import get_backend
33 33 from rhodecode.lib.compat import json
34 34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode,\
35 35 remove_prefix
36 36 from rhodecode.lib.caching_query import FromCache
37 37 from rhodecode.lib.hooks import log_create_repository, log_delete_repository
38 38
39 39 from rhodecode.model import BaseModel
40 40 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
41 41 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
42 42 RhodeCodeSetting, RepositoryField
43 43 from rhodecode.lib import helpers as h
44 44 from rhodecode.lib.auth import HasRepoPermissionAny
45 from rhodecode.lib.vcs.backends.base import EmptyChangeset
45 46
46 47
47 48 log = logging.getLogger(__name__)
48 49
49 50
50 51 class RepoModel(BaseModel):
51 52
52 53 cls = Repository
53 54 URL_SEPARATOR = Repository.url_sep()
54 55
55 56 def __get_users_group(self, users_group):
56 57 return self._get_instance(UsersGroup, users_group,
57 58 callback=UsersGroup.get_by_group_name)
58 59
59 60 def _get_repos_group(self, repos_group):
60 61 return self._get_instance(RepoGroup, repos_group,
61 62 callback=RepoGroup.get_by_group_name)
62 63
63 64 @LazyProperty
64 65 def repos_path(self):
65 66 """
66 67 Get's the repositories root path from database
67 68 """
68 69
69 70 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
70 71 return q.ui_value
71 72
72 73 def get(self, repo_id, cache=False):
73 74 repo = self.sa.query(Repository)\
74 75 .filter(Repository.repo_id == repo_id)
75 76
76 77 if cache:
77 78 repo = repo.options(FromCache("sql_cache_short",
78 79 "get_repo_%s" % repo_id))
79 80 return repo.scalar()
80 81
81 82 def get_repo(self, repository):
82 83 return self._get_repo(repository)
83 84
84 85 def get_by_repo_name(self, repo_name, cache=False):
85 86 repo = self.sa.query(Repository)\
86 87 .filter(Repository.repo_name == repo_name)
87 88
88 89 if cache:
89 90 repo = repo.options(FromCache("sql_cache_short",
90 91 "get_repo_%s" % repo_name))
91 92 return repo.scalar()
92 93
93 94 def get_all_user_repos(self, user):
94 95 """
95 96 Get's all repositories that user have at least read access
96 97
97 98 :param user:
98 99 :type user:
99 100 """
100 101 from rhodecode.lib.auth import AuthUser
101 102 user = self._get_user(user)
102 103 repos = AuthUser(user_id=user.user_id).permissions['repositories']
103 104 access_check = lambda r: r[1] in ['repository.read',
104 105 'repository.write',
105 106 'repository.admin']
106 107 repos = [x[0] for x in filter(access_check, repos.items())]
107 108 return Repository.query().filter(Repository.repo_name.in_(repos))
108 109
109 110 def get_users_js(self):
110 111 users = self.sa.query(User).filter(User.active == True).all()
111 112 return json.dumps([
112 113 {
113 114 'id': u.user_id,
114 115 'fname': u.name,
115 116 'lname': u.lastname,
116 117 'nname': u.username,
117 118 'gravatar_lnk': h.gravatar_url(u.email, 14)
118 119 } for u in users]
119 120 )
120 121
121 122 def get_users_groups_js(self):
122 123 users_groups = self.sa.query(UsersGroup)\
123 124 .filter(UsersGroup.users_group_active == True).all()
124 125
125 126 return json.dumps([
126 127 {
127 128 'id': gr.users_group_id,
128 129 'grname': gr.users_group_name,
129 130 'grmembers': len(gr.members),
130 131 } for gr in users_groups]
131 132 )
132 133
133 134 @classmethod
134 135 def _render_datatable(cls, tmpl, *args, **kwargs):
135 136 import rhodecode
136 137 from pylons import tmpl_context as c
137 138 from pylons.i18n.translation import _
138 139
139 140 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
140 141 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
141 142
142 143 tmpl = template.get_def(tmpl)
143 144 kwargs.update(dict(_=_, h=h, c=c))
144 145 return tmpl.render(*args, **kwargs)
145 146
147 @classmethod
148 def update_repoinfo(cls, repositories=None):
149 if not repositories:
150 repositories = Repository.getAll()
151 for repo in repositories:
152 scm_repo = repo.scm_instance_no_cache
153 last_cs = EmptyChangeset()
154 if scm_repo:
155 last_cs = scm_repo.get_changeset()
156 repo.update_changeset_cache(last_cs)
157
146 158 def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True,
147 159 super_user_actions=False):
148 160 _render = self._render_datatable
149 161
150 162 def quick_menu(repo_name):
151 163 return _render('quick_menu', repo_name)
152 164
153 165 def repo_lnk(name, rtype, private, fork_of):
154 166 return _render('repo_name', name, rtype, private, fork_of,
155 167 short_name=not admin, admin=False)
156 168
157 169 def last_change(last_change):
158 170 return _render("last_change", last_change)
159 171
160 172 def rss_lnk(repo_name):
161 173 return _render("rss", repo_name)
162 174
163 175 def atom_lnk(repo_name):
164 176 return _render("atom", repo_name)
165 177
166 178 def last_rev(repo_name, cs_cache):
167 179 return _render('revision', repo_name, cs_cache.get('revision'),
168 180 cs_cache.get('raw_id'), cs_cache.get('author'),
169 181 cs_cache.get('message'))
170 182
171 183 def desc(desc):
172 184 from pylons import tmpl_context as c
173 185 if c.visual.stylify_metatags:
174 186 return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
175 187 else:
176 188 return h.urlify_text(h.truncate(desc, 60))
177 189
178 190 def repo_actions(repo_name):
179 191 return _render('repo_actions', repo_name, super_user_actions)
180 192
181 193 def owner_actions(user_id, username):
182 194 return _render('user_name', user_id, username)
183 195
184 196 repos_data = []
185 197 for repo in repos_list:
186 198 if perm_check:
187 199 # check permission at this level
188 200 if not HasRepoPermissionAny(
189 201 'repository.read', 'repository.write', 'repository.admin'
190 202 )(repo.repo_name, 'get_repos_as_dict check'):
191 203 continue
192 204 cs_cache = repo.changeset_cache
193 205 row = {
194 206 "menu": quick_menu(repo.repo_name),
195 207 "raw_name": repo.repo_name.lower(),
196 208 "name": repo_lnk(repo.repo_name, repo.repo_type,
197 209 repo.private, repo.fork),
198 210 "last_change": last_change(repo.last_db_change),
199 211 "last_changeset": last_rev(repo.repo_name, cs_cache),
200 212 "raw_tip": cs_cache.get('revision'),
201 213 "desc": desc(repo.description),
202 214 "owner": h.person(repo.user.username),
203 215 "rss": rss_lnk(repo.repo_name),
204 216 "atom": atom_lnk(repo.repo_name),
205 217
206 218 }
207 219 if admin:
208 220 row.update({
209 221 "action": repo_actions(repo.repo_name),
210 222 "owner": owner_actions(repo.user.user_id,
211 223 h.person(repo.user.username))
212 224 })
213 225 repos_data.append(row)
214 226
215 227 return {
216 228 "totalRecords": len(repos_list),
217 229 "startIndex": 0,
218 230 "sort": "name",
219 231 "dir": "asc",
220 232 "records": repos_data
221 233 }
222 234
223 235 def _get_defaults(self, repo_name):
224 236 """
225 237 Get's information about repository, and returns a dict for
226 238 usage in forms
227 239
228 240 :param repo_name:
229 241 """
230 242
231 243 repo_info = Repository.get_by_repo_name(repo_name)
232 244
233 245 if repo_info is None:
234 246 return None
235 247
236 248 defaults = repo_info.get_dict()
237 249 group, repo_name = repo_info.groups_and_repo
238 250 defaults['repo_name'] = repo_name
239 251 defaults['repo_group'] = getattr(group[-1] if group else None,
240 252 'group_id', None)
241 253
242 254 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
243 255 (1, 'repo_description'), (1, 'repo_enable_locking'),
244 256 (1, 'repo_landing_rev'), (0, 'clone_uri'),
245 257 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
246 258 attr = k
247 259 if strip:
248 260 attr = remove_prefix(k, 'repo_')
249 261
250 262 defaults[k] = defaults[attr]
251 263
252 264 # fill owner
253 265 if repo_info.user:
254 266 defaults.update({'user': repo_info.user.username})
255 267 else:
256 268 replacement_user = User.query().filter(User.admin ==
257 269 True).first().username
258 270 defaults.update({'user': replacement_user})
259 271
260 272 # fill repository users
261 273 for p in repo_info.repo_to_perm:
262 274 defaults.update({'u_perm_%s' % p.user.username:
263 275 p.permission.permission_name})
264 276
265 277 # fill repository groups
266 278 for p in repo_info.users_group_to_perm:
267 279 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
268 280 p.permission.permission_name})
269 281
270 282 return defaults
271 283
272 284 def update(self, org_repo_name, **kwargs):
273 285 try:
274 286 cur_repo = self.get_by_repo_name(org_repo_name, cache=False)
275 287
276 288 # update permissions
277 289 for member, perm, member_type in kwargs['perms_updates']:
278 290 if member_type == 'user':
279 291 # this updates existing one
280 292 RepoModel().grant_user_permission(
281 293 repo=cur_repo, user=member, perm=perm
282 294 )
283 295 else:
284 296 RepoModel().grant_users_group_permission(
285 297 repo=cur_repo, group_name=member, perm=perm
286 298 )
287 299 # set new permissions
288 300 for member, perm, member_type in kwargs['perms_new']:
289 301 if member_type == 'user':
290 302 RepoModel().grant_user_permission(
291 303 repo=cur_repo, user=member, perm=perm
292 304 )
293 305 else:
294 306 RepoModel().grant_users_group_permission(
295 307 repo=cur_repo, group_name=member, perm=perm
296 308 )
297 309
298 310 if 'user' in kwargs:
299 311 cur_repo.user = User.get_by_username(kwargs['user'])
300 312
301 313 if 'repo_group' in kwargs:
302 314 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
303 315
304 316 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
305 317 (1, 'repo_description'), (1, 'repo_enable_locking'),
306 318 (1, 'repo_landing_rev'), (0, 'clone_uri'),
307 319 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
308 320 if k in kwargs:
309 321 val = kwargs[k]
310 322 if strip:
311 323 k = remove_prefix(k, 'repo_')
312 324 setattr(cur_repo, k, val)
313 325
314 326 new_name = cur_repo.get_new_name(kwargs['repo_name'])
315 327 cur_repo.repo_name = new_name
316 328
317 329 #handle extra fields
318 330 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
319 331 k = RepositoryField.un_prefix_key(field)
320 332 ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo)
321 333 if ex_field:
322 334 ex_field.field_value = kwargs[field]
323 335 self.sa.add(ex_field)
324 336 self.sa.add(cur_repo)
325 337
326 338 if org_repo_name != new_name:
327 339 # rename repository
328 340 self.__rename_repo(old=org_repo_name, new=new_name)
329 341
330 342 return cur_repo
331 343 except:
332 344 log.error(traceback.format_exc())
333 345 raise
334 346
335 347 def create_repo(self, repo_name, repo_type, description, owner,
336 348 private=False, clone_uri=None, repos_group=None,
337 349 landing_rev='tip', just_db=False, fork_of=None,
338 350 copy_fork_permissions=False, enable_statistics=False,
339 351 enable_locking=False, enable_downloads=False):
340 352 """
341 353 Create repository
342 354
343 355 """
344 356 from rhodecode.model.scm import ScmModel
345 357
346 358 owner = self._get_user(owner)
347 359 fork_of = self._get_repo(fork_of)
348 360 repos_group = self._get_repos_group(repos_group)
349 361 try:
350 362
351 363 # repo name is just a name of repository
352 364 # while repo_name_full is a full qualified name that is combined
353 365 # with name and path of group
354 366 repo_name_full = repo_name
355 367 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
356 368
357 369 new_repo = Repository()
358 370 new_repo.enable_statistics = False
359 371 new_repo.repo_name = repo_name_full
360 372 new_repo.repo_type = repo_type
361 373 new_repo.user = owner
362 374 new_repo.group = repos_group
363 375 new_repo.description = description or repo_name
364 376 new_repo.private = private
365 377 new_repo.clone_uri = clone_uri
366 378 new_repo.landing_rev = landing_rev
367 379
368 380 new_repo.enable_statistics = enable_statistics
369 381 new_repo.enable_locking = enable_locking
370 382 new_repo.enable_downloads = enable_downloads
371 383
372 384 if repos_group:
373 385 new_repo.enable_locking = repos_group.enable_locking
374 386
375 387 if fork_of:
376 388 parent_repo = fork_of
377 389 new_repo.fork = parent_repo
378 390
379 391 self.sa.add(new_repo)
380 392
381 393 def _create_default_perms():
382 394 # create default permission
383 395 repo_to_perm = UserRepoToPerm()
384 396 default = 'repository.read'
385 397 for p in User.get_by_username('default').user_perms:
386 398 if p.permission.permission_name.startswith('repository.'):
387 399 default = p.permission.permission_name
388 400 break
389 401
390 402 default_perm = 'repository.none' if private else default
391 403
392 404 repo_to_perm.permission_id = self.sa.query(Permission)\
393 405 .filter(Permission.permission_name == default_perm)\
394 406 .one().permission_id
395 407
396 408 repo_to_perm.repository = new_repo
397 409 repo_to_perm.user_id = User.get_by_username('default').user_id
398 410
399 411 self.sa.add(repo_to_perm)
400 412
401 413 if fork_of:
402 414 if copy_fork_permissions:
403 415 repo = fork_of
404 416 user_perms = UserRepoToPerm.query()\
405 417 .filter(UserRepoToPerm.repository == repo).all()
406 418 group_perms = UsersGroupRepoToPerm.query()\
407 419 .filter(UsersGroupRepoToPerm.repository == repo).all()
408 420
409 421 for perm in user_perms:
410 422 UserRepoToPerm.create(perm.user, new_repo,
411 423 perm.permission)
412 424
413 425 for perm in group_perms:
414 426 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
415 427 perm.permission)
416 428 else:
417 429 _create_default_perms()
418 430 else:
419 431 _create_default_perms()
420 432
421 433 if not just_db:
422 434 self.__create_repo(repo_name, repo_type,
423 435 repos_group,
424 436 clone_uri)
425 437 log_create_repository(new_repo.get_dict(),
426 438 created_by=owner.username)
427 439
428 440 # now automatically start following this repository as owner
429 441 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
430 442 owner.user_id)
431 443 return new_repo
432 444 except:
433 445 log.error(traceback.format_exc())
434 446 raise
435 447
436 448 def create(self, form_data, cur_user, just_db=False, fork=None):
437 449 """
438 450 Backward compatibility function, just a wrapper on top of create_repo
439 451
440 452 :param form_data:
441 453 :param cur_user:
442 454 :param just_db:
443 455 :param fork:
444 456 """
445 457 owner = cur_user
446 458 repo_name = form_data['repo_name_full']
447 459 repo_type = form_data['repo_type']
448 460 description = form_data['repo_description']
449 461 private = form_data['repo_private']
450 462 clone_uri = form_data.get('clone_uri')
451 463 repos_group = form_data['repo_group']
452 464 landing_rev = form_data['repo_landing_rev']
453 465 copy_fork_permissions = form_data.get('copy_permissions')
454 466 fork_of = form_data.get('fork_parent_id')
455 467
456 468 ## repo creation defaults, private and repo_type are filled in form
457 469 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
458 470 enable_statistics = defs.get('repo_enable_statistics')
459 471 enable_locking = defs.get('repo_enable_locking')
460 472 enable_downloads = defs.get('repo_enable_downloads')
461 473
462 474 return self.create_repo(
463 475 repo_name, repo_type, description, owner, private, clone_uri,
464 476 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions,
465 477 enable_statistics, enable_locking, enable_downloads
466 478 )
467 479
468 480 def create_fork(self, form_data, cur_user):
469 481 """
470 482 Simple wrapper into executing celery task for fork creation
471 483
472 484 :param form_data:
473 485 :param cur_user:
474 486 """
475 487 from rhodecode.lib.celerylib import tasks, run_task
476 488 run_task(tasks.create_repo_fork, form_data, cur_user)
477 489
478 490 def delete(self, repo):
479 491 repo = self._get_repo(repo)
480 492 if repo:
481 493 old_repo_dict = repo.get_dict()
482 494 owner = repo.user
483 495 try:
484 496 self.sa.delete(repo)
485 497 self.__delete_repo(repo)
486 498 log_delete_repository(old_repo_dict,
487 499 deleted_by=owner.username)
488 500 except:
489 501 log.error(traceback.format_exc())
490 502 raise
491 503
492 504 def grant_user_permission(self, repo, user, perm):
493 505 """
494 506 Grant permission for user on given repository, or update existing one
495 507 if found
496 508
497 509 :param repo: Instance of Repository, repository_id, or repository name
498 510 :param user: Instance of User, user_id or username
499 511 :param perm: Instance of Permission, or permission_name
500 512 """
501 513 user = self._get_user(user)
502 514 repo = self._get_repo(repo)
503 515 permission = self._get_perm(perm)
504 516
505 517 # check if we have that permission already
506 518 obj = self.sa.query(UserRepoToPerm)\
507 519 .filter(UserRepoToPerm.user == user)\
508 520 .filter(UserRepoToPerm.repository == repo)\
509 521 .scalar()
510 522 if obj is None:
511 523 # create new !
512 524 obj = UserRepoToPerm()
513 525 obj.repository = repo
514 526 obj.user = user
515 527 obj.permission = permission
516 528 self.sa.add(obj)
517 529 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
518 530
519 531 def revoke_user_permission(self, repo, user):
520 532 """
521 533 Revoke permission for user on given repository
522 534
523 535 :param repo: Instance of Repository, repository_id, or repository name
524 536 :param user: Instance of User, user_id or username
525 537 """
526 538
527 539 user = self._get_user(user)
528 540 repo = self._get_repo(repo)
529 541
530 542 obj = self.sa.query(UserRepoToPerm)\
531 543 .filter(UserRepoToPerm.repository == repo)\
532 544 .filter(UserRepoToPerm.user == user)\
533 545 .scalar()
534 546 if obj:
535 547 self.sa.delete(obj)
536 548 log.debug('Revoked perm on %s on %s' % (repo, user))
537 549
538 550 def grant_users_group_permission(self, repo, group_name, perm):
539 551 """
540 552 Grant permission for users group on given repository, or update
541 553 existing one if found
542 554
543 555 :param repo: Instance of Repository, repository_id, or repository name
544 556 :param group_name: Instance of UserGroup, users_group_id,
545 557 or users group name
546 558 :param perm: Instance of Permission, or permission_name
547 559 """
548 560 repo = self._get_repo(repo)
549 561 group_name = self.__get_users_group(group_name)
550 562 permission = self._get_perm(perm)
551 563
552 564 # check if we have that permission already
553 565 obj = self.sa.query(UsersGroupRepoToPerm)\
554 566 .filter(UsersGroupRepoToPerm.users_group == group_name)\
555 567 .filter(UsersGroupRepoToPerm.repository == repo)\
556 568 .scalar()
557 569
558 570 if obj is None:
559 571 # create new
560 572 obj = UsersGroupRepoToPerm()
561 573
562 574 obj.repository = repo
563 575 obj.users_group = group_name
564 576 obj.permission = permission
565 577 self.sa.add(obj)
566 578 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
567 579
568 580 def revoke_users_group_permission(self, repo, group_name):
569 581 """
570 582 Revoke permission for users group on given repository
571 583
572 584 :param repo: Instance of Repository, repository_id, or repository name
573 585 :param group_name: Instance of UserGroup, users_group_id,
574 586 or users group name
575 587 """
576 588 repo = self._get_repo(repo)
577 589 group_name = self.__get_users_group(group_name)
578 590
579 591 obj = self.sa.query(UsersGroupRepoToPerm)\
580 592 .filter(UsersGroupRepoToPerm.repository == repo)\
581 593 .filter(UsersGroupRepoToPerm.users_group == group_name)\
582 594 .scalar()
583 595 if obj:
584 596 self.sa.delete(obj)
585 597 log.debug('Revoked perm to %s on %s' % (repo, group_name))
586 598
587 599 def delete_stats(self, repo_name):
588 600 """
589 601 removes stats for given repo
590 602
591 603 :param repo_name:
592 604 """
593 605 try:
594 606 obj = self.sa.query(Statistics)\
595 607 .filter(Statistics.repository ==
596 608 self.get_by_repo_name(repo_name))\
597 609 .one()
598 610 self.sa.delete(obj)
599 611 except:
600 612 log.error(traceback.format_exc())
601 613 raise
602 614
603 615 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
604 616 """
605 617 makes repository on filesystem. It's group aware means it'll create
606 618 a repository within a group, and alter the paths accordingly of
607 619 group location
608 620
609 621 :param repo_name:
610 622 :param alias:
611 623 :param parent_id:
612 624 :param clone_uri:
613 625 """
614 626 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
615 627 from rhodecode.model.scm import ScmModel
616 628
617 629 if parent:
618 630 new_parent_path = os.sep.join(parent.full_path_splitted)
619 631 else:
620 632 new_parent_path = ''
621 633
622 634 # we need to make it str for mercurial
623 635 repo_path = os.path.join(*map(lambda x: safe_str(x),
624 636 [self.repos_path, new_parent_path, repo_name]))
625 637
626 638 # check if this path is not a repository
627 639 if is_valid_repo(repo_path, self.repos_path):
628 640 raise Exception('This path %s is a valid repository' % repo_path)
629 641
630 642 # check if this path is a group
631 643 if is_valid_repos_group(repo_path, self.repos_path):
632 644 raise Exception('This path %s is a valid group' % repo_path)
633 645
634 646 log.info('creating repo %s in %s @ %s' % (
635 647 repo_name, safe_unicode(repo_path), clone_uri
636 648 )
637 649 )
638 650 backend = get_backend(alias)
639 651 if alias == 'hg':
640 652 backend(repo_path, create=True, src_url=clone_uri)
641 653 elif alias == 'git':
642 654 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
643 655 # add rhodecode hook into this repo
644 656 ScmModel().install_git_hook(repo=r)
645 657 else:
646 658 raise Exception('Undefined alias %s' % alias)
647 659
648 660 def __rename_repo(self, old, new):
649 661 """
650 662 renames repository on filesystem
651 663
652 664 :param old: old name
653 665 :param new: new name
654 666 """
655 667 log.info('renaming repo from %s to %s' % (old, new))
656 668
657 669 old_path = os.path.join(self.repos_path, old)
658 670 new_path = os.path.join(self.repos_path, new)
659 671 if os.path.isdir(new_path):
660 672 raise Exception(
661 673 'Was trying to rename to already existing dir %s' % new_path
662 674 )
663 675 shutil.move(old_path, new_path)
664 676
665 677 def __delete_repo(self, repo):
666 678 """
667 679 removes repo from filesystem, the removal is acctually made by
668 680 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
669 681 repository is no longer valid for rhodecode, can be undeleted later on
670 682 by reverting the renames on this repository
671 683
672 684 :param repo: repo object
673 685 """
674 686 rm_path = os.path.join(self.repos_path, repo.repo_name)
675 687 log.info("Removing %s" % (rm_path))
676 688 # disable hg/git internal that it doesn't get detected as repo
677 689 alias = repo.repo_type
678 690
679 691 bare = getattr(repo.scm_instance, 'bare', False)
680 692
681 693 if not bare:
682 694 # skip this for bare git repos
683 695 shutil.move(os.path.join(rm_path, '.%s' % alias),
684 696 os.path.join(rm_path, 'rm__.%s' % alias))
685 697 # disable repo
686 698 _now = datetime.now()
687 699 _ms = str(_now.microsecond).rjust(6, '0')
688 700 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
689 701 repo.just_name)
690 702 if repo.group:
691 703 args = repo.group.full_path_splitted + [_d]
692 704 _d = os.path.join(*args)
693 705 shutil.move(rm_path, os.path.join(self.repos_path, _d))
General Comments 0
You need to be logged in to leave comments. Login now