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