##// END OF EJS Templates
Fixed issue with rm__ system that put removed repos in root location, it can lead to making a heavy copy, and remove operation.
marcink -
r2949:d37b79ad beta
parent child Browse files
Show More
@@ -1,548 +1,551 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 from rhodecode.lib.caching_query import FromCache
36 36 from rhodecode.lib.hooks import log_create_repository, log_delete_repository
37 37
38 38 from rhodecode.model import BaseModel
39 39 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
40 40 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
41 41 from rhodecode.lib import helpers as h
42 42
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46
47 47 class RepoModel(BaseModel):
48 48
49 49 cls = Repository
50 50 URL_SEPARATOR = Repository.url_sep()
51 51
52 52 def __get_users_group(self, users_group):
53 53 return self._get_instance(UsersGroup, users_group,
54 54 callback=UsersGroup.get_by_group_name)
55 55
56 56 def _get_repos_group(self, repos_group):
57 57 return self._get_instance(RepoGroup, repos_group,
58 58 callback=RepoGroup.get_by_group_name)
59 59
60 60 @LazyProperty
61 61 def repos_path(self):
62 62 """
63 63 Get's the repositories root path from database
64 64 """
65 65
66 66 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
67 67 return q.ui_value
68 68
69 69 def get(self, repo_id, cache=False):
70 70 repo = self.sa.query(Repository)\
71 71 .filter(Repository.repo_id == repo_id)
72 72
73 73 if cache:
74 74 repo = repo.options(FromCache("sql_cache_short",
75 75 "get_repo_%s" % repo_id))
76 76 return repo.scalar()
77 77
78 78 def get_repo(self, repository):
79 79 return self._get_repo(repository)
80 80
81 81 def get_by_repo_name(self, repo_name, cache=False):
82 82 repo = self.sa.query(Repository)\
83 83 .filter(Repository.repo_name == repo_name)
84 84
85 85 if cache:
86 86 repo = repo.options(FromCache("sql_cache_short",
87 87 "get_repo_%s" % repo_name))
88 88 return repo.scalar()
89 89
90 90 def get_users_js(self):
91 91 users = self.sa.query(User).filter(User.active == True).all()
92 92 return json.dumps([
93 93 {
94 94 'id': u.user_id,
95 95 'fname': u.name,
96 96 'lname': u.lastname,
97 97 'nname': u.username,
98 98 'gravatar_lnk': h.gravatar_url(u.email, 14)
99 99 } for u in users]
100 100 )
101 101
102 102 def get_users_groups_js(self):
103 103 users_groups = self.sa.query(UsersGroup)\
104 104 .filter(UsersGroup.users_group_active == True).all()
105 105
106 106 return json.dumps([
107 107 {
108 108 'id': gr.users_group_id,
109 109 'grname': gr.users_group_name,
110 110 'grmembers': len(gr.members),
111 111 } for gr in users_groups]
112 112 )
113 113
114 114 def _get_defaults(self, repo_name):
115 115 """
116 116 Get's information about repository, and returns a dict for
117 117 usage in forms
118 118
119 119 :param repo_name:
120 120 """
121 121
122 122 repo_info = Repository.get_by_repo_name(repo_name)
123 123
124 124 if repo_info is None:
125 125 return None
126 126
127 127 defaults = repo_info.get_dict()
128 128 group, repo_name = repo_info.groups_and_repo
129 129 defaults['repo_name'] = repo_name
130 130 defaults['repo_group'] = getattr(group[-1] if group else None,
131 131 'group_id', None)
132 132
133 133 # fill owner
134 134 if repo_info.user:
135 135 defaults.update({'user': repo_info.user.username})
136 136 else:
137 137 replacement_user = User.query().filter(User.admin ==
138 138 True).first().username
139 139 defaults.update({'user': replacement_user})
140 140
141 141 # fill repository users
142 142 for p in repo_info.repo_to_perm:
143 143 defaults.update({'u_perm_%s' % p.user.username:
144 144 p.permission.permission_name})
145 145
146 146 # fill repository groups
147 147 for p in repo_info.users_group_to_perm:
148 148 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
149 149 p.permission.permission_name})
150 150
151 151 return defaults
152 152
153 153 def update(self, repo_name, form_data):
154 154 try:
155 155 cur_repo = self.get_by_repo_name(repo_name, cache=False)
156 156
157 157 # update permissions
158 158 for member, perm, member_type in form_data['perms_updates']:
159 159 if member_type == 'user':
160 160 # this updates existing one
161 161 RepoModel().grant_user_permission(
162 162 repo=cur_repo, user=member, perm=perm
163 163 )
164 164 else:
165 165 RepoModel().grant_users_group_permission(
166 166 repo=cur_repo, group_name=member, perm=perm
167 167 )
168 168 # set new permissions
169 169 for member, perm, member_type in form_data['perms_new']:
170 170 if member_type == 'user':
171 171 RepoModel().grant_user_permission(
172 172 repo=cur_repo, user=member, perm=perm
173 173 )
174 174 else:
175 175 RepoModel().grant_users_group_permission(
176 176 repo=cur_repo, group_name=member, perm=perm
177 177 )
178 178
179 179 # update current repo
180 180 for k, v in form_data.items():
181 181 if k == 'user':
182 182 cur_repo.user = User.get_by_username(v)
183 183 elif k == 'repo_name':
184 184 pass
185 185 elif k == 'repo_group':
186 186 cur_repo.group = RepoGroup.get(v)
187 187
188 188 else:
189 189 setattr(cur_repo, k, v)
190 190
191 191 new_name = cur_repo.get_new_name(form_data['repo_name'])
192 192 cur_repo.repo_name = new_name
193 193
194 194 self.sa.add(cur_repo)
195 195
196 196 if repo_name != new_name:
197 197 # rename repository
198 198 self.__rename_repo(old=repo_name, new=new_name)
199 199
200 200 return cur_repo
201 201 except:
202 202 log.error(traceback.format_exc())
203 203 raise
204 204
205 205 def create_repo(self, repo_name, repo_type, description, owner,
206 206 private=False, clone_uri=None, repos_group=None,
207 207 landing_rev='tip', just_db=False, fork_of=None,
208 208 copy_fork_permissions=False):
209 209 """
210 210 Create repository
211 211
212 212 """
213 213 from rhodecode.model.scm import ScmModel
214 214
215 215 owner = self._get_user(owner)
216 216 fork_of = self._get_repo(fork_of)
217 217 repos_group = self._get_repos_group(repos_group)
218 218 try:
219 219
220 220 # repo name is just a name of repository
221 221 # while repo_name_full is a full qualified name that is combined
222 222 # with name and path of group
223 223 repo_name_full = repo_name
224 224 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
225 225
226 226 new_repo = Repository()
227 227 new_repo.enable_statistics = False
228 228 new_repo.repo_name = repo_name_full
229 229 new_repo.repo_type = repo_type
230 230 new_repo.user = owner
231 231 new_repo.group = repos_group
232 232 new_repo.description = description or repo_name
233 233 new_repo.private = private
234 234 new_repo.clone_uri = clone_uri
235 235 new_repo.landing_rev = landing_rev
236 236
237 237 if repos_group:
238 238 new_repo.enable_locking = repos_group.enable_locking
239 239
240 240 if fork_of:
241 241 parent_repo = fork_of
242 242 new_repo.fork = parent_repo
243 243
244 244 self.sa.add(new_repo)
245 245
246 246 def _create_default_perms():
247 247 # create default permission
248 248 repo_to_perm = UserRepoToPerm()
249 249 default = 'repository.read'
250 250 for p in User.get_by_username('default').user_perms:
251 251 if p.permission.permission_name.startswith('repository.'):
252 252 default = p.permission.permission_name
253 253 break
254 254
255 255 default_perm = 'repository.none' if private else default
256 256
257 257 repo_to_perm.permission_id = self.sa.query(Permission)\
258 258 .filter(Permission.permission_name == default_perm)\
259 259 .one().permission_id
260 260
261 261 repo_to_perm.repository = new_repo
262 262 repo_to_perm.user_id = User.get_by_username('default').user_id
263 263
264 264 self.sa.add(repo_to_perm)
265 265
266 266 if fork_of:
267 267 if copy_fork_permissions:
268 268 repo = fork_of
269 269 user_perms = UserRepoToPerm.query()\
270 270 .filter(UserRepoToPerm.repository == repo).all()
271 271 group_perms = UsersGroupRepoToPerm.query()\
272 272 .filter(UsersGroupRepoToPerm.repository == repo).all()
273 273
274 274 for perm in user_perms:
275 275 UserRepoToPerm.create(perm.user, new_repo,
276 276 perm.permission)
277 277
278 278 for perm in group_perms:
279 279 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
280 280 perm.permission)
281 281 else:
282 282 _create_default_perms()
283 283 else:
284 284 _create_default_perms()
285 285
286 286 if not just_db:
287 287 self.__create_repo(repo_name, repo_type,
288 288 repos_group,
289 289 clone_uri)
290 290 log_create_repository(new_repo.get_dict(),
291 291 created_by=owner.username)
292 292
293 293 # now automatically start following this repository as owner
294 294 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
295 295 owner.user_id)
296 296 return new_repo
297 297 except:
298 298 log.error(traceback.format_exc())
299 299 raise
300 300
301 301 def create(self, form_data, cur_user, just_db=False, fork=None):
302 302 """
303 303 Backward compatibility function, just a wrapper on top of create_repo
304 304
305 305 :param form_data:
306 306 :param cur_user:
307 307 :param just_db:
308 308 :param fork:
309 309 """
310 310
311 311 repo_name = form_data['repo_name_full']
312 312 repo_type = form_data['repo_type']
313 313 description = form_data['description']
314 314 owner = cur_user
315 315 private = form_data['private']
316 316 clone_uri = form_data.get('clone_uri')
317 317 repos_group = form_data['repo_group']
318 318 landing_rev = form_data['landing_rev']
319 319 copy_fork_permissions = form_data.get('copy_permissions')
320 320 fork_of = form_data.get('fork_parent_id')
321 321 return self.create_repo(
322 322 repo_name, repo_type, description, owner, private, clone_uri,
323 323 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions
324 324 )
325 325
326 326 def create_fork(self, form_data, cur_user):
327 327 """
328 328 Simple wrapper into executing celery task for fork creation
329 329
330 330 :param form_data:
331 331 :param cur_user:
332 332 """
333 333 from rhodecode.lib.celerylib import tasks, run_task
334 334 run_task(tasks.create_repo_fork, form_data, cur_user)
335 335
336 336 def delete(self, repo):
337 337 repo = self._get_repo(repo)
338 338 if repo:
339 339 old_repo_dict = repo.get_dict()
340 340 owner = repo.user
341 341 try:
342 342 self.sa.delete(repo)
343 343 self.__delete_repo(repo)
344 344 log_delete_repository(old_repo_dict,
345 345 deleted_by=owner.username)
346 346 except:
347 347 log.error(traceback.format_exc())
348 348 raise
349 349
350 350 def grant_user_permission(self, repo, user, perm):
351 351 """
352 352 Grant permission for user on given repository, or update existing one
353 353 if found
354 354
355 355 :param repo: Instance of Repository, repository_id, or repository name
356 356 :param user: Instance of User, user_id or username
357 357 :param perm: Instance of Permission, or permission_name
358 358 """
359 359 user = self._get_user(user)
360 360 repo = self._get_repo(repo)
361 361 permission = self._get_perm(perm)
362 362
363 363 # check if we have that permission already
364 364 obj = self.sa.query(UserRepoToPerm)\
365 365 .filter(UserRepoToPerm.user == user)\
366 366 .filter(UserRepoToPerm.repository == repo)\
367 367 .scalar()
368 368 if obj is None:
369 369 # create new !
370 370 obj = UserRepoToPerm()
371 371 obj.repository = repo
372 372 obj.user = user
373 373 obj.permission = permission
374 374 self.sa.add(obj)
375 375 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
376 376
377 377 def revoke_user_permission(self, repo, user):
378 378 """
379 379 Revoke permission for user on given repository
380 380
381 381 :param repo: Instance of Repository, repository_id, or repository name
382 382 :param user: Instance of User, user_id or username
383 383 """
384 384
385 385 user = self._get_user(user)
386 386 repo = self._get_repo(repo)
387 387
388 388 obj = self.sa.query(UserRepoToPerm)\
389 389 .filter(UserRepoToPerm.repository == repo)\
390 390 .filter(UserRepoToPerm.user == user)\
391 391 .scalar()
392 392 if obj:
393 393 self.sa.delete(obj)
394 394 log.debug('Revoked perm on %s on %s' % (repo, user))
395 395
396 396 def grant_users_group_permission(self, repo, group_name, perm):
397 397 """
398 398 Grant permission for users group on given repository, or update
399 399 existing one if found
400 400
401 401 :param repo: Instance of Repository, repository_id, or repository name
402 402 :param group_name: Instance of UserGroup, users_group_id,
403 403 or users group name
404 404 :param perm: Instance of Permission, or permission_name
405 405 """
406 406 repo = self._get_repo(repo)
407 407 group_name = self.__get_users_group(group_name)
408 408 permission = self._get_perm(perm)
409 409
410 410 # check if we have that permission already
411 411 obj = self.sa.query(UsersGroupRepoToPerm)\
412 412 .filter(UsersGroupRepoToPerm.users_group == group_name)\
413 413 .filter(UsersGroupRepoToPerm.repository == repo)\
414 414 .scalar()
415 415
416 416 if obj is None:
417 417 # create new
418 418 obj = UsersGroupRepoToPerm()
419 419
420 420 obj.repository = repo
421 421 obj.users_group = group_name
422 422 obj.permission = permission
423 423 self.sa.add(obj)
424 424 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
425 425
426 426 def revoke_users_group_permission(self, repo, group_name):
427 427 """
428 428 Revoke permission for users group on given repository
429 429
430 430 :param repo: Instance of Repository, repository_id, or repository name
431 431 :param group_name: Instance of UserGroup, users_group_id,
432 432 or users group name
433 433 """
434 434 repo = self._get_repo(repo)
435 435 group_name = self.__get_users_group(group_name)
436 436
437 437 obj = self.sa.query(UsersGroupRepoToPerm)\
438 438 .filter(UsersGroupRepoToPerm.repository == repo)\
439 439 .filter(UsersGroupRepoToPerm.users_group == group_name)\
440 440 .scalar()
441 441 if obj:
442 442 self.sa.delete(obj)
443 443 log.debug('Revoked perm to %s on %s' % (repo, group_name))
444 444
445 445 def delete_stats(self, repo_name):
446 446 """
447 447 removes stats for given repo
448 448
449 449 :param repo_name:
450 450 """
451 451 try:
452 452 obj = self.sa.query(Statistics)\
453 453 .filter(Statistics.repository ==
454 454 self.get_by_repo_name(repo_name))\
455 455 .one()
456 456 self.sa.delete(obj)
457 457 except:
458 458 log.error(traceback.format_exc())
459 459 raise
460 460
461 461 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
462 462 """
463 463 makes repository on filesystem. It's group aware means it'll create
464 464 a repository within a group, and alter the paths accordingly of
465 465 group location
466 466
467 467 :param repo_name:
468 468 :param alias:
469 469 :param parent_id:
470 470 :param clone_uri:
471 471 """
472 472 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
473 473 from rhodecode.model.scm import ScmModel
474 474
475 475 if parent:
476 476 new_parent_path = os.sep.join(parent.full_path_splitted)
477 477 else:
478 478 new_parent_path = ''
479 479
480 480 # we need to make it str for mercurial
481 481 repo_path = os.path.join(*map(lambda x: safe_str(x),
482 482 [self.repos_path, new_parent_path, repo_name]))
483 483
484 484 # check if this path is not a repository
485 485 if is_valid_repo(repo_path, self.repos_path):
486 486 raise Exception('This path %s is a valid repository' % repo_path)
487 487
488 488 # check if this path is a group
489 489 if is_valid_repos_group(repo_path, self.repos_path):
490 490 raise Exception('This path %s is a valid group' % repo_path)
491 491
492 492 log.info('creating repo %s in %s @ %s' % (
493 493 repo_name, safe_unicode(repo_path), clone_uri
494 494 )
495 495 )
496 496 backend = get_backend(alias)
497 497 if alias == 'hg':
498 498 backend(repo_path, create=True, src_url=clone_uri)
499 499 elif alias == 'git':
500 500 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
501 501 # add rhodecode hook into this repo
502 502 ScmModel().install_git_hook(repo=r)
503 503 else:
504 504 raise Exception('Undefined alias %s' % alias)
505 505
506 506 def __rename_repo(self, old, new):
507 507 """
508 508 renames repository on filesystem
509 509
510 510 :param old: old name
511 511 :param new: new name
512 512 """
513 513 log.info('renaming repo from %s to %s' % (old, new))
514 514
515 515 old_path = os.path.join(self.repos_path, old)
516 516 new_path = os.path.join(self.repos_path, new)
517 517 if os.path.isdir(new_path):
518 518 raise Exception(
519 519 'Was trying to rename to already existing dir %s' % new_path
520 520 )
521 521 shutil.move(old_path, new_path)
522 522
523 523 def __delete_repo(self, repo):
524 524 """
525 525 removes repo from filesystem, the removal is acctually made by
526 526 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
527 527 repository is no longer valid for rhodecode, can be undeleted later on
528 528 by reverting the renames on this repository
529 529
530 530 :param repo: repo object
531 531 """
532 532 rm_path = os.path.join(self.repos_path, repo.repo_name)
533 533 log.info("Removing %s" % (rm_path))
534 534 # disable hg/git internal that it doesn't get detected as repo
535 535 alias = repo.repo_type
536 536
537 537 bare = getattr(repo.scm_instance, 'bare', False)
538 538
539 539 if not bare:
540 540 # skip this for bare git repos
541 541 shutil.move(os.path.join(rm_path, '.%s' % alias),
542 542 os.path.join(rm_path, 'rm__.%s' % alias))
543 543 # disable repo
544 544 _now = datetime.now()
545 545 _ms = str(_now.microsecond).rjust(6, '0')
546 546 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
547 repo.repo_name)
547 repo.just_name)
548 if repo.group:
549 args = repo.group.full_path_splitted + [_d]
550 _d = os.path.join(*args)
548 551 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