##// END OF EJS Templates
Created install_git_hook more verbose version of previos code....
marcink -
r2618:e1370dcb beta
parent child Browse files
Show More
@@ -1,539 +1,526 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 import pkg_resources
31 from os.path import dirname as dn, join as jn
32 30 from datetime import datetime
33 31
34 32 from rhodecode.lib.vcs.backends import get_backend
35 33 from rhodecode.lib.compat import json
36 34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
37 35 from rhodecode.lib.caching_query import FromCache
38 36 from rhodecode.lib.hooks import log_create_repository
39 37
40 38 from rhodecode.model import BaseModel
41 39 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
42 40 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
43 41 from rhodecode.lib import helpers as h
44 42
45 43
46 44 log = logging.getLogger(__name__)
47 45
48 46
49 47 class RepoModel(BaseModel):
50 48
51 49 cls = Repository
52 50 URL_SEPARATOR = Repository.url_sep()
53 51
54 52 def __get_users_group(self, users_group):
55 53 return self._get_instance(UsersGroup, users_group,
56 54 callback=UsersGroup.get_by_group_name)
57 55
58 56 def __get_repos_group(self, repos_group):
59 57 return self._get_instance(RepoGroup, repos_group,
60 58 callback=RepoGroup.get_by_group_name)
61 59
62 60 @LazyProperty
63 61 def repos_path(self):
64 62 """
65 63 Get's the repositories root path from database
66 64 """
67 65
68 66 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
69 67 return q.ui_value
70 68
71 69 def get(self, repo_id, cache=False):
72 70 repo = self.sa.query(Repository)\
73 71 .filter(Repository.repo_id == repo_id)
74 72
75 73 if cache:
76 74 repo = repo.options(FromCache("sql_cache_short",
77 75 "get_repo_%s" % repo_id))
78 76 return repo.scalar()
79 77
80 78 def get_repo(self, repository):
81 79 return self._get_repo(repository)
82 80
83 81 def get_by_repo_name(self, repo_name, cache=False):
84 82 repo = self.sa.query(Repository)\
85 83 .filter(Repository.repo_name == repo_name)
86 84
87 85 if cache:
88 86 repo = repo.options(FromCache("sql_cache_short",
89 87 "get_repo_%s" % repo_name))
90 88 return repo.scalar()
91 89
92 90 def get_users_js(self):
93 91 users = self.sa.query(User).filter(User.active == True).all()
94 92 return json.dumps([
95 93 {
96 94 'id': u.user_id,
97 95 'fname': u.name,
98 96 'lname': u.lastname,
99 97 'nname': u.username,
100 98 'gravatar_lnk': h.gravatar_url(u.email, 14)
101 99 } for u in users]
102 100 )
103 101
104 102 def get_users_groups_js(self):
105 103 users_groups = self.sa.query(UsersGroup)\
106 104 .filter(UsersGroup.users_group_active == True).all()
107 105
108 106 return json.dumps([
109 107 {
110 108 'id': gr.users_group_id,
111 109 'grname': gr.users_group_name,
112 110 'grmembers': len(gr.members),
113 111 } for gr in users_groups]
114 112 )
115 113
116 114 def _get_defaults(self, repo_name):
117 115 """
118 116 Get's information about repository, and returns a dict for
119 117 usage in forms
120 118
121 119 :param repo_name:
122 120 """
123 121
124 122 repo_info = Repository.get_by_repo_name(repo_name)
125 123
126 124 if repo_info is None:
127 125 return None
128 126
129 127 defaults = repo_info.get_dict()
130 128 group, repo_name = repo_info.groups_and_repo
131 129 defaults['repo_name'] = repo_name
132 130 defaults['repo_group'] = getattr(group[-1] if group else None,
133 131 'group_id', None)
134 132
135 133 # fill owner
136 134 if repo_info.user:
137 135 defaults.update({'user': repo_info.user.username})
138 136 else:
139 137 replacement_user = User.query().filter(User.admin ==
140 138 True).first().username
141 139 defaults.update({'user': replacement_user})
142 140
143 141 # fill repository users
144 142 for p in repo_info.repo_to_perm:
145 143 defaults.update({'u_perm_%s' % p.user.username:
146 144 p.permission.permission_name})
147 145
148 146 # fill repository groups
149 147 for p in repo_info.users_group_to_perm:
150 148 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
151 149 p.permission.permission_name})
152 150
153 151 return defaults
154 152
155 153 def update(self, repo_name, form_data):
156 154 try:
157 155 cur_repo = self.get_by_repo_name(repo_name, cache=False)
158 156
159 157 # update permissions
160 158 for member, perm, member_type in form_data['perms_updates']:
161 159 if member_type == 'user':
162 160 # this updates existing one
163 161 RepoModel().grant_user_permission(
164 162 repo=cur_repo, user=member, perm=perm
165 163 )
166 164 else:
167 165 RepoModel().grant_users_group_permission(
168 166 repo=cur_repo, group_name=member, perm=perm
169 167 )
170 168 # set new permissions
171 169 for member, perm, member_type in form_data['perms_new']:
172 170 if member_type == 'user':
173 171 RepoModel().grant_user_permission(
174 172 repo=cur_repo, user=member, perm=perm
175 173 )
176 174 else:
177 175 RepoModel().grant_users_group_permission(
178 176 repo=cur_repo, group_name=member, perm=perm
179 177 )
180 178
181 179 # update current repo
182 180 for k, v in form_data.items():
183 181 if k == 'user':
184 182 cur_repo.user = User.get_by_username(v)
185 183 elif k == 'repo_name':
186 184 pass
187 185 elif k == 'repo_group':
188 186 cur_repo.group = RepoGroup.get(v)
189 187
190 188 else:
191 189 setattr(cur_repo, k, v)
192 190
193 191 new_name = cur_repo.get_new_name(form_data['repo_name'])
194 192 cur_repo.repo_name = new_name
195 193
196 194 self.sa.add(cur_repo)
197 195
198 196 if repo_name != new_name:
199 197 # rename repository
200 198 self.__rename_repo(old=repo_name, new=new_name)
201 199
202 200 return cur_repo
203 201 except:
204 202 log.error(traceback.format_exc())
205 203 raise
206 204
207 205 def create_repo(self, repo_name, repo_type, description, owner,
208 206 private=False, clone_uri=None, repos_group=None,
209 207 landing_rev='tip', just_db=False, fork_of=None,
210 208 copy_fork_permissions=False):
211 209 from rhodecode.model.scm import ScmModel
212 210
213 211 owner = self._get_user(owner)
214 212 fork_of = self._get_repo(fork_of)
215 213 repos_group = self.__get_repos_group(repos_group)
216 214 try:
217 215
218 216 # repo name is just a name of repository
219 217 # while repo_name_full is a full qualified name that is combined
220 218 # with name and path of group
221 219 repo_name_full = repo_name
222 220 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
223 221
224 222 new_repo = Repository()
225 223 new_repo.enable_statistics = False
226 224 new_repo.repo_name = repo_name_full
227 225 new_repo.repo_type = repo_type
228 226 new_repo.user = owner
229 227 new_repo.group = repos_group
230 228 new_repo.description = description or repo_name
231 229 new_repo.private = private
232 230 new_repo.clone_uri = clone_uri
233 231 new_repo.landing_rev = landing_rev
234 232
235 233 if fork_of:
236 234 parent_repo = fork_of
237 235 new_repo.fork = parent_repo
238 236
239 237 self.sa.add(new_repo)
240 238
241 239 def _create_default_perms():
242 240 # create default permission
243 241 repo_to_perm = UserRepoToPerm()
244 242 default = 'repository.read'
245 243 for p in User.get_by_username('default').user_perms:
246 244 if p.permission.permission_name.startswith('repository.'):
247 245 default = p.permission.permission_name
248 246 break
249 247
250 248 default_perm = 'repository.none' if private else default
251 249
252 250 repo_to_perm.permission_id = self.sa.query(Permission)\
253 251 .filter(Permission.permission_name == default_perm)\
254 252 .one().permission_id
255 253
256 254 repo_to_perm.repository = new_repo
257 255 repo_to_perm.user_id = User.get_by_username('default').user_id
258 256
259 257 self.sa.add(repo_to_perm)
260 258
261 259 if fork_of:
262 260 if copy_fork_permissions:
263 261 repo = fork_of
264 262 user_perms = UserRepoToPerm.query()\
265 263 .filter(UserRepoToPerm.repository == repo).all()
266 264 group_perms = UsersGroupRepoToPerm.query()\
267 265 .filter(UsersGroupRepoToPerm.repository == repo).all()
268 266
269 267 for perm in user_perms:
270 268 UserRepoToPerm.create(perm.user, new_repo,
271 269 perm.permission)
272 270
273 271 for perm in group_perms:
274 272 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
275 273 perm.permission)
276 274 else:
277 275 _create_default_perms()
278 276 else:
279 277 _create_default_perms()
280 278
281 279 if not just_db:
282 280 self.__create_repo(repo_name, repo_type,
283 281 repos_group,
284 282 clone_uri)
285 283 log_create_repository(new_repo.get_dict(),
286 284 created_by=owner.username)
287
285 else:
286 # install the githook if it's a git repo
287 if repo_type == 'git':
288 ScmModel().install_git_hook(repo=new_repo.scm_instance)
288 289 # now automatically start following this repository as owner
289 290 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
290 291 owner.user_id)
291 292 return new_repo
292 293 except:
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 from rhodecode.model.scm import ScmModel
451 452
452 453 if parent:
453 454 new_parent_path = os.sep.join(parent.full_path_splitted)
454 455 else:
455 456 new_parent_path = ''
456 457
457 458 # we need to make it str for mercurial
458 459 repo_path = os.path.join(*map(lambda x: safe_str(x),
459 460 [self.repos_path, new_parent_path, repo_name]))
460 461
461 462 # check if this path is not a repository
462 463 if is_valid_repo(repo_path, self.repos_path):
463 464 raise Exception('This path %s is a valid repository' % repo_path)
464 465
465 466 # check if this path is a group
466 467 if is_valid_repos_group(repo_path, self.repos_path):
467 468 raise Exception('This path %s is a valid group' % repo_path)
468 469
469 470 log.info('creating repo %s in %s @ %s' % (
470 471 repo_name, safe_unicode(repo_path), clone_uri
471 472 )
472 473 )
473 474 backend = get_backend(alias)
474 475 if alias == 'hg':
475 476 backend(repo_path, create=True, src_url=clone_uri)
476 477 elif alias == 'git':
477 478 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
478 479 # add rhodecode hook into this repo
479
480 loc = jn(r.path, 'hooks')
481 if not r.bare:
482 loc = jn(r.path, '.git', 'hooks')
483 if not os.path.isdir(loc):
484 os.makedirs(loc)
485
486 tmpl = pkg_resources.resource_string(
487 'rhodecode', jn('config', 'post_receive_tmpl.py')
488 )
489 _hook_file = jn(loc, 'post-receive')
490 with open(_hook_file, 'wb') as f:
491 f.write(tmpl)
492 os.chmod(_hook_file, 0755)
493
480 ScmModel().install_git_hook(repo=r)
494 481 else:
495 482 raise Exception('Undefined alias %s' % alias)
496 483
497 484 def __rename_repo(self, old, new):
498 485 """
499 486 renames repository on filesystem
500 487
501 488 :param old: old name
502 489 :param new: new name
503 490 """
504 491 log.info('renaming repo from %s to %s' % (old, new))
505 492
506 493 old_path = os.path.join(self.repos_path, old)
507 494 new_path = os.path.join(self.repos_path, new)
508 495 if os.path.isdir(new_path):
509 496 raise Exception(
510 497 'Was trying to rename to already existing dir %s' % new_path
511 498 )
512 499 shutil.move(old_path, new_path)
513 500
514 501 def __delete_repo(self, repo):
515 502 """
516 503 removes repo from filesystem, the removal is acctually made by
517 504 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
518 505 repository is no longer valid for rhodecode, can be undeleted later on
519 506 by reverting the renames on this repository
520 507
521 508 :param repo: repo object
522 509 """
523 510 rm_path = os.path.join(self.repos_path, repo.repo_name)
524 511 log.info("Removing %s" % (rm_path))
525 512 # disable hg/git internal that it doesn't get detected as repo
526 513 alias = repo.repo_type
527 514
528 515 bare = getattr(repo.scm_instance, 'bare', False)
529 516
530 517 if not bare:
531 518 # skip this for bare git repos
532 519 shutil.move(os.path.join(rm_path, '.%s' % alias),
533 520 os.path.join(rm_path, 'rm__.%s' % alias))
534 521 # disable repo
535 522 _now = datetime.now()
536 523 _ms = str(_now.microsecond).rjust(6, '0')
537 524 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
538 525 repo.repo_name)
539 526 shutil.move(rm_path, os.path.join(self.repos_path, _d))
@@ -1,547 +1,597 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.scm
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Scm model for RhodeCode
7 7
8 8 :created_on: Apr 9, 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 import os
26 import re
26 27 import time
27 28 import traceback
28 29 import logging
29 30 import cStringIO
31 import pkg_resources
32 from os.path import dirname as dn, join as jn
30 33
31 34 from sqlalchemy import func
32 35 from pylons.i18n.translation import _
33 36
37 import rhodecode
34 38 from rhodecode.lib.vcs import get_backend
35 39 from rhodecode.lib.vcs.exceptions import RepositoryError
36 40 from rhodecode.lib.vcs.utils.lazy import LazyProperty
37 41 from rhodecode.lib.vcs.nodes import FileNode
38 42
39 43 from rhodecode import BACKENDS
40 44 from rhodecode.lib import helpers as h
41 45 from rhodecode.lib.utils2 import safe_str, safe_unicode
42 46 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
43 47 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
44 48 action_logger, EmptyChangeset, REMOVED_REPO_PAT
45 49 from rhodecode.model import BaseModel
46 50 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
47 51 UserFollowing, UserLog, User, RepoGroup, PullRequest
48 52
49 53 log = logging.getLogger(__name__)
50 54
51 55
52 56 class UserTemp(object):
53 57 def __init__(self, user_id):
54 58 self.user_id = user_id
55 59
56 60 def __repr__(self):
57 61 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
58 62
59 63
60 64 class RepoTemp(object):
61 65 def __init__(self, repo_id):
62 66 self.repo_id = repo_id
63 67
64 68 def __repr__(self):
65 69 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
66 70
67 71
68 72 class CachedRepoList(object):
69 73 """
70 74 Cached repo list, uses in-memory cache after initialization, that is
71 75 super fast
72 76 """
73 77
74 78 def __init__(self, db_repo_list, repos_path, order_by=None):
75 79 self.db_repo_list = db_repo_list
76 80 self.repos_path = repos_path
77 81 self.order_by = order_by
78 82 self.reversed = (order_by or '').startswith('-')
79 83
80 84 def __len__(self):
81 85 return len(self.db_repo_list)
82 86
83 87 def __repr__(self):
84 88 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
85 89
86 90 def __iter__(self):
87 91 # pre-propagated cache_map to save executing select statements
88 92 # for each repo
89 93 cache_map = CacheInvalidation.get_cache_map()
90 94
91 95 for dbr in self.db_repo_list:
92 96 scmr = dbr.scm_instance_cached(cache_map)
93 97 # check permission at this level
94 98 if not HasRepoPermissionAny(
95 99 'repository.read', 'repository.write', 'repository.admin'
96 100 )(dbr.repo_name, 'get repo check'):
97 101 continue
98 102
99 103 if scmr is None:
100 104 log.error(
101 105 '%s this repository is present in database but it '
102 106 'cannot be created as an scm instance' % dbr.repo_name
103 107 )
104 108 continue
105 109
106 110 last_change = scmr.last_change
107 111 tip = h.get_changeset_safe(scmr, 'tip')
108 112
109 113 tmp_d = {}
110 114 tmp_d['name'] = dbr.repo_name
111 115 tmp_d['name_sort'] = tmp_d['name'].lower()
112 116 tmp_d['description'] = dbr.description
113 117 tmp_d['description_sort'] = tmp_d['description'].lower()
114 118 tmp_d['last_change'] = last_change
115 119 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
116 120 tmp_d['tip'] = tip.raw_id
117 121 tmp_d['tip_sort'] = tip.revision
118 122 tmp_d['rev'] = tip.revision
119 123 tmp_d['contact'] = dbr.user.full_contact
120 124 tmp_d['contact_sort'] = tmp_d['contact']
121 125 tmp_d['owner_sort'] = tmp_d['contact']
122 126 tmp_d['repo_archives'] = list(scmr._get_archives())
123 127 tmp_d['last_msg'] = tip.message
124 128 tmp_d['author'] = tip.author
125 129 tmp_d['dbrepo'] = dbr.get_dict()
126 130 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
127 131 yield tmp_d
128 132
129 133
130 134 class SimpleCachedRepoList(CachedRepoList):
131 135 """
132 136 Lighter version of CachedRepoList without the scm initialisation
133 137 """
134 138
135 139 def __iter__(self):
136 140 for dbr in self.db_repo_list:
137 141 # check permission at this level
138 142 if not HasRepoPermissionAny(
139 143 'repository.read', 'repository.write', 'repository.admin'
140 144 )(dbr.repo_name, 'get repo check'):
141 145 continue
142 146
143 147 tmp_d = {}
144 148 tmp_d['name'] = dbr.repo_name
145 149 tmp_d['name_sort'] = tmp_d['name'].lower()
146 150 tmp_d['description'] = dbr.description
147 151 tmp_d['description_sort'] = tmp_d['description'].lower()
148 152 tmp_d['dbrepo'] = dbr.get_dict()
149 153 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
150 154 yield tmp_d
151 155
152 156
153 157 class GroupList(object):
154 158
155 159 def __init__(self, db_repo_group_list):
156 160 self.db_repo_group_list = db_repo_group_list
157 161
158 162 def __len__(self):
159 163 return len(self.db_repo_group_list)
160 164
161 165 def __repr__(self):
162 166 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
163 167
164 168 def __iter__(self):
165 169 for dbgr in self.db_repo_group_list:
166 170 # check permission at this level
167 171 if not HasReposGroupPermissionAny(
168 172 'group.read', 'group.write', 'group.admin'
169 173 )(dbgr.group_name, 'get group repo check'):
170 174 continue
171 175
172 176 yield dbgr
173 177
174 178
175 179 class ScmModel(BaseModel):
176 180 """
177 181 Generic Scm Model
178 182 """
179 183
180 184 def __get_repo(self, instance):
181 185 cls = Repository
182 186 if isinstance(instance, cls):
183 187 return instance
184 188 elif isinstance(instance, int) or str(instance).isdigit():
185 189 return cls.get(instance)
186 190 elif isinstance(instance, basestring):
187 191 return cls.get_by_repo_name(instance)
188 192 elif instance:
189 193 raise Exception('given object must be int, basestr or Instance'
190 194 ' of %s got %s' % (type(cls), type(instance)))
191 195
192 196 @LazyProperty
193 197 def repos_path(self):
194 198 """
195 199 Get's the repositories root path from database
196 200 """
197 201
198 202 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
199 203
200 204 return q.ui_value
201 205
202 206 def repo_scan(self, repos_path=None):
203 207 """
204 208 Listing of repositories in given path. This path should not be a
205 209 repository itself. Return a dictionary of repository objects
206 210
207 211 :param repos_path: path to directory containing repositories
208 212 """
209 213
210 214 if repos_path is None:
211 215 repos_path = self.repos_path
212 216
213 217 log.info('scanning for repositories in %s' % repos_path)
214 218
215 219 baseui = make_ui('db')
216 220 repos = {}
217 221
218 222 for name, path in get_filesystem_repos(repos_path, recursive=True):
219 223 # skip removed repos
220 224 if REMOVED_REPO_PAT.match(name):
221 225 continue
222 226
223 227 # name need to be decomposed and put back together using the /
224 228 # since this is internal storage separator for rhodecode
225 229 name = Repository.url_sep().join(name.split(os.sep))
226 230
227 231 try:
228 232 if name in repos:
229 233 raise RepositoryError('Duplicate repository name %s '
230 234 'found in %s' % (name, path))
231 235 else:
232 236
233 237 klass = get_backend(path[0])
234 238
235 239 if path[0] == 'hg' and path[0] in BACKENDS.keys():
236 240 repos[name] = klass(safe_str(path[1]), baseui=baseui)
237 241
238 242 if path[0] == 'git' and path[0] in BACKENDS.keys():
239 243 repos[name] = klass(path[1])
240 244 except OSError:
241 245 continue
242 246
243 247 return repos
244 248
245 249 def get_repos(self, all_repos=None, sort_key=None, simple=False):
246 250 """
247 251 Get all repos from db and for each repo create it's
248 252 backend instance and fill that backed with information from database
249 253
250 254 :param all_repos: list of repository names as strings
251 255 give specific repositories list, good for filtering
252 256
253 257 :param sort_key: initial sorting of repos
254 258 :param simple: use SimpleCachedList - one without the SCM info
255 259 """
256 260 if all_repos is None:
257 261 all_repos = self.sa.query(Repository)\
258 262 .filter(Repository.group_id == None)\
259 263 .order_by(func.lower(Repository.repo_name)).all()
260 264 if simple:
261 265 repo_iter = SimpleCachedRepoList(all_repos,
262 266 repos_path=self.repos_path,
263 267 order_by=sort_key)
264 268 else:
265 269 repo_iter = CachedRepoList(all_repos,
266 270 repos_path=self.repos_path,
267 271 order_by=sort_key)
268 272
269 273 return repo_iter
270 274
271 275 def get_repos_groups(self, all_groups=None):
272 276 if all_groups is None:
273 277 all_groups = RepoGroup.query()\
274 278 .filter(RepoGroup.group_parent_id == None).all()
275 279 group_iter = GroupList(all_groups)
276 280
277 281 return group_iter
278 282
279 283 def mark_for_invalidation(self, repo_name):
280 284 """
281 285 Puts cache invalidation task into db for
282 286 further global cache invalidation
283 287
284 288 :param repo_name: this repo that should invalidation take place
285 289 """
286 290 CacheInvalidation.set_invalidate(repo_name)
287 291
288 292 def toggle_following_repo(self, follow_repo_id, user_id):
289 293
290 294 f = self.sa.query(UserFollowing)\
291 295 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
292 296 .filter(UserFollowing.user_id == user_id).scalar()
293 297
294 298 if f is not None:
295 299 try:
296 300 self.sa.delete(f)
297 301 action_logger(UserTemp(user_id),
298 302 'stopped_following_repo',
299 303 RepoTemp(follow_repo_id))
300 304 return
301 305 except:
302 306 log.error(traceback.format_exc())
303 307 raise
304 308
305 309 try:
306 310 f = UserFollowing()
307 311 f.user_id = user_id
308 312 f.follows_repo_id = follow_repo_id
309 313 self.sa.add(f)
310 314
311 315 action_logger(UserTemp(user_id),
312 316 'started_following_repo',
313 317 RepoTemp(follow_repo_id))
314 318 except:
315 319 log.error(traceback.format_exc())
316 320 raise
317 321
318 322 def toggle_following_user(self, follow_user_id, user_id):
319 323 f = self.sa.query(UserFollowing)\
320 324 .filter(UserFollowing.follows_user_id == follow_user_id)\
321 325 .filter(UserFollowing.user_id == user_id).scalar()
322 326
323 327 if f is not None:
324 328 try:
325 329 self.sa.delete(f)
326 330 return
327 331 except:
328 332 log.error(traceback.format_exc())
329 333 raise
330 334
331 335 try:
332 336 f = UserFollowing()
333 337 f.user_id = user_id
334 338 f.follows_user_id = follow_user_id
335 339 self.sa.add(f)
336 340 except:
337 341 log.error(traceback.format_exc())
338 342 raise
339 343
340 344 def is_following_repo(self, repo_name, user_id, cache=False):
341 345 r = self.sa.query(Repository)\
342 346 .filter(Repository.repo_name == repo_name).scalar()
343 347
344 348 f = self.sa.query(UserFollowing)\
345 349 .filter(UserFollowing.follows_repository == r)\
346 350 .filter(UserFollowing.user_id == user_id).scalar()
347 351
348 352 return f is not None
349 353
350 354 def is_following_user(self, username, user_id, cache=False):
351 355 u = User.get_by_username(username)
352 356
353 357 f = self.sa.query(UserFollowing)\
354 358 .filter(UserFollowing.follows_user == u)\
355 359 .filter(UserFollowing.user_id == user_id).scalar()
356 360
357 361 return f is not None
358 362
359 363 def get_followers(self, repo):
360 364 repo = self._get_repo(repo)
361 365
362 366 return self.sa.query(UserFollowing)\
363 367 .filter(UserFollowing.follows_repository == repo).count()
364 368
365 369 def get_forks(self, repo):
366 370 repo = self._get_repo(repo)
367 371 return self.sa.query(Repository)\
368 372 .filter(Repository.fork == repo).count()
369 373
370 374 def get_pull_requests(self, repo):
371 375 repo = self._get_repo(repo)
372 376 return self.sa.query(PullRequest)\
373 377 .filter(PullRequest.other_repo == repo).count()
374 378
375 379 def mark_as_fork(self, repo, fork, user):
376 380 repo = self.__get_repo(repo)
377 381 fork = self.__get_repo(fork)
378 382 repo.fork = fork
379 383 self.sa.add(repo)
380 384 return repo
381 385
382 386 def pull_changes(self, repo, username):
383 387 dbrepo = self.__get_repo(repo)
384 388 clone_uri = dbrepo.clone_uri
385 389 if not clone_uri:
386 390 raise Exception("This repository doesn't have a clone uri")
387 391
388 392 repo = dbrepo.scm_instance
389 393 try:
390 394 extras = {
391 395 'ip': '',
392 396 'username': username,
393 397 'action': 'push_remote',
394 398 'repository': dbrepo.repo_name,
395 399 'scm': repo.alias,
396 400 }
397 401 Repository.inject_ui(repo, extras=extras)
398 402
399 403 if repo.alias == 'git':
400 404 repo.fetch(clone_uri)
401 405 else:
402 406 repo.pull(clone_uri)
403 407 self.mark_for_invalidation(dbrepo.repo_name)
404 408 except:
405 409 log.error(traceback.format_exc())
406 410 raise
407 411
408 412 def commit_change(self, repo, repo_name, cs, user, author, message,
409 413 content, f_path):
410 414
411 415 if repo.alias == 'hg':
412 416 from rhodecode.lib.vcs.backends.hg import \
413 417 MercurialInMemoryChangeset as IMC
414 418 elif repo.alias == 'git':
415 419 from rhodecode.lib.vcs.backends.git import \
416 420 GitInMemoryChangeset as IMC
417 421
418 422 # decoding here will force that we have proper encoded values
419 423 # in any other case this will throw exceptions and deny commit
420 424 content = safe_str(content)
421 425 path = safe_str(f_path)
422 426 # message and author needs to be unicode
423 427 # proper backend should then translate that into required type
424 428 message = safe_unicode(message)
425 429 author = safe_unicode(author)
426 430 m = IMC(repo)
427 431 m.change(FileNode(path, content))
428 432 tip = m.commit(message=message,
429 433 author=author,
430 434 parents=[cs], branch=cs.branch)
431 435
432 436 new_cs = tip.short_id
433 437 action = 'push_local:%s' % new_cs
434 438
435 439 action_logger(user, action, repo_name)
436 440
437 441 self.mark_for_invalidation(repo_name)
438 442
439 443 def create_node(self, repo, repo_name, cs, user, author, message, content,
440 444 f_path):
441 445 if repo.alias == 'hg':
442 446 from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset as IMC
443 447 elif repo.alias == 'git':
444 448 from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset as IMC
445 449 # decoding here will force that we have proper encoded values
446 450 # in any other case this will throw exceptions and deny commit
447 451
448 452 if isinstance(content, (basestring,)):
449 453 content = safe_str(content)
450 454 elif isinstance(content, (file, cStringIO.OutputType,)):
451 455 content = content.read()
452 456 else:
453 457 raise Exception('Content is of unrecognized type %s' % (
454 458 type(content)
455 459 ))
456 460
457 461 message = safe_unicode(message)
458 462 author = safe_unicode(author)
459 463 path = safe_str(f_path)
460 464 m = IMC(repo)
461 465
462 466 if isinstance(cs, EmptyChangeset):
463 467 # EmptyChangeset means we we're editing empty repository
464 468 parents = None
465 469 else:
466 470 parents = [cs]
467 471
468 472 m.add(FileNode(path, content=content))
469 473 tip = m.commit(message=message,
470 474 author=author,
471 475 parents=parents, branch=cs.branch)
472 476 new_cs = tip.short_id
473 477 action = 'push_local:%s' % new_cs
474 478
475 479 action_logger(user, action, repo_name)
476 480
477 481 self.mark_for_invalidation(repo_name)
478 482
479 483 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
480 484 """
481 485 recursive walk in root dir and return a set of all path in that dir
482 486 based on repository walk function
483 487
484 488 :param repo_name: name of repository
485 489 :param revision: revision for which to list nodes
486 490 :param root_path: root path to list
487 491 :param flat: return as a list, if False returns a dict with decription
488 492
489 493 """
490 494 _files = list()
491 495 _dirs = list()
492 496 try:
493 497 _repo = self.__get_repo(repo_name)
494 498 changeset = _repo.scm_instance.get_changeset(revision)
495 499 root_path = root_path.lstrip('/')
496 500 for topnode, dirs, files in changeset.walk(root_path):
497 501 for f in files:
498 502 _files.append(f.path if flat else {"name": f.path,
499 503 "type": "file"})
500 504 for d in dirs:
501 505 _dirs.append(d.path if flat else {"name": d.path,
502 506 "type": "dir"})
503 507 except RepositoryError:
504 508 log.debug(traceback.format_exc())
505 509 raise
506 510
507 511 return _dirs, _files
508 512
509 513 def get_unread_journal(self):
510 514 return self.sa.query(UserLog).count()
511 515
512 516 def get_repo_landing_revs(self, repo=None):
513 517 """
514 518 Generates select option with tags branches and bookmarks (for hg only)
515 519 grouped by type
516 520
517 521 :param repo:
518 522 :type repo:
519 523 """
520 524
521 525 hist_l = []
522 526 choices = []
523 527 repo = self.__get_repo(repo)
524 528 hist_l.append(['tip', _('latest tip')])
525 529 choices.append('tip')
526 530 if not repo:
527 531 return choices, hist_l
528 532
529 533 repo = repo.scm_instance
530 534
531 535 branches_group = ([(k, k) for k, v in
532 536 repo.branches.iteritems()], _("Branches"))
533 537 hist_l.append(branches_group)
534 538 choices.extend([x[0] for x in branches_group[0]])
535 539
536 540 if repo.alias == 'hg':
537 541 bookmarks_group = ([(k, k) for k, v in
538 542 repo.bookmarks.iteritems()], _("Bookmarks"))
539 543 hist_l.append(bookmarks_group)
540 544 choices.extend([x[0] for x in bookmarks_group[0]])
541 545
542 546 tags_group = ([(k, k) for k, v in
543 547 repo.tags.iteritems()], _("Tags"))
544 548 hist_l.append(tags_group)
545 549 choices.extend([x[0] for x in tags_group[0]])
546 550
547 551 return choices, hist_l
552
553 def install_git_hook(self, repo, force_create=False):
554 """
555 Creates a rhodecode hook inside a git repository
556
557 :param repo: Instance of VCS repo
558 :param force_create: Create even if same name hook exists
559 """
560
561 loc = jn(repo.path, 'hooks')
562 if not repo.bare:
563 loc = jn(repo.path, '.git', 'hooks')
564 if not os.path.isdir(loc):
565 os.makedirs(loc)
566
567 tmpl = pkg_resources.resource_string(
568 'rhodecode', jn('config', 'post_receive_tmpl.py')
569 )
570
571 _hook_file = jn(loc, 'post-receive')
572 _rhodecode_hook = False
573 log.debug('Installing git hook in repo %s' % repo)
574 if os.path.exists(_hook_file):
575 # let's take a look at this hook, maybe it's rhodecode ?
576 log.debug('hook exists, checking if it is from rhodecode')
577 _HOOK_VER_PAT = re.compile(r'^RC_HOOK_VER')
578 with open(_hook_file, 'rb') as f:
579 data = f.read()
580 matches = re.compile(r'(?:%s)\s*=\s*(.*)'
581 % 'RC_HOOK_VER').search(data)
582 if matches:
583 try:
584 ver = matches.groups()[0]
585 log.debug('got %s it is rhodecode' % (ver))
586 _rhodecode_hook = True
587 except:
588 log.error(traceback.format_exc())
589
590 if _rhodecode_hook or force_create:
591 log.debug('writing hook file !')
592 with open(_hook_file, 'wb') as f:
593 tmpl = tmpl.replace('_TMPL_', rhodecode.__version__)
594 f.write(tmpl)
595 os.chmod(_hook_file, 0755)
596 else:
597 log.debug('skipping writing hook file') No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now