##// END OF EJS Templates
Fake post-push actions when doing git fetch. It's still want show...
marcink -
r3880:a228a33d beta
parent child Browse files
Show More
@@ -1,742 +1,750 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 from __future__ import with_statement
26 26 import os
27 27 import re
28 28 import time
29 29 import traceback
30 30 import logging
31 31 import cStringIO
32 32 import pkg_resources
33 33 from os.path import dirname as dn, join as jn
34 34
35 35 from sqlalchemy import func
36 36 from pylons.i18n.translation import _
37 37
38 38 import rhodecode
39 39 from rhodecode.lib.vcs import get_backend
40 40 from rhodecode.lib.vcs.exceptions import RepositoryError
41 41 from rhodecode.lib.vcs.utils.lazy import LazyProperty
42 42 from rhodecode.lib.vcs.nodes import FileNode
43 43 from rhodecode.lib.vcs.backends.base import EmptyChangeset
44 44
45 45 from rhodecode import BACKENDS
46 46 from rhodecode.lib import helpers as h
47 47 from rhodecode.lib.utils2 import safe_str, safe_unicode, get_server_url,\
48 48 _set_extras
49 49 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny,\
50 50 HasUserGroupPermissionAnyDecorator, HasUserGroupPermissionAny
51 51 from rhodecode.lib.utils import get_filesystem_repos, make_ui, \
52 52 action_logger, REMOVED_REPO_PAT
53 53 from rhodecode.model import BaseModel
54 54 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
55 55 UserFollowing, UserLog, User, RepoGroup, PullRequest
56 56 from rhodecode.lib.hooks import log_push_action
57 57 from rhodecode.lib.exceptions import NonRelativePathError
58 58
59 59 log = logging.getLogger(__name__)
60 60
61 61
62 62 class UserTemp(object):
63 63 def __init__(self, user_id):
64 64 self.user_id = user_id
65 65
66 66 def __repr__(self):
67 67 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
68 68
69 69
70 70 class RepoTemp(object):
71 71 def __init__(self, repo_id):
72 72 self.repo_id = repo_id
73 73
74 74 def __repr__(self):
75 75 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
76 76
77 77
78 78 class CachedRepoList(object):
79 79 """
80 80 Cached repo list, uses in-memory cache after initialization, that is
81 81 super fast
82 82 """
83 83
84 84 def __init__(self, db_repo_list, repos_path, order_by=None, perm_set=None):
85 85 self.db_repo_list = db_repo_list
86 86 self.repos_path = repos_path
87 87 self.order_by = order_by
88 88 self.reversed = (order_by or '').startswith('-')
89 89 if not perm_set:
90 90 perm_set = ['repository.read', 'repository.write',
91 91 'repository.admin']
92 92 self.perm_set = perm_set
93 93
94 94 def __len__(self):
95 95 return len(self.db_repo_list)
96 96
97 97 def __repr__(self):
98 98 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
99 99
100 100 def __iter__(self):
101 101 # pre-propagated valid_cache_keys to save executing select statements
102 102 # for each repo
103 103 valid_cache_keys = CacheInvalidation.get_valid_cache_keys()
104 104
105 105 for dbr in self.db_repo_list:
106 106 scmr = dbr.scm_instance_cached(valid_cache_keys)
107 107 # check permission at this level
108 108 if not HasRepoPermissionAny(
109 109 *self.perm_set)(dbr.repo_name, 'get repo check'):
110 110 continue
111 111
112 112 try:
113 113 last_change = scmr.last_change
114 114 tip = h.get_changeset_safe(scmr, 'tip')
115 115 except Exception:
116 116 log.error(
117 117 '%s this repository is present in database but it '
118 118 'cannot be created as an scm instance, org_exc:%s'
119 119 % (dbr.repo_name, traceback.format_exc())
120 120 )
121 121 continue
122 122
123 123 tmp_d = {}
124 124 tmp_d['name'] = dbr.repo_name
125 125 tmp_d['name_sort'] = tmp_d['name'].lower()
126 126 tmp_d['raw_name'] = tmp_d['name'].lower()
127 127 tmp_d['description'] = dbr.description
128 128 tmp_d['description_sort'] = tmp_d['description'].lower()
129 129 tmp_d['last_change'] = last_change
130 130 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
131 131 tmp_d['tip'] = tip.raw_id
132 132 tmp_d['tip_sort'] = tip.revision
133 133 tmp_d['rev'] = tip.revision
134 134 tmp_d['contact'] = dbr.user.full_contact
135 135 tmp_d['contact_sort'] = tmp_d['contact']
136 136 tmp_d['owner_sort'] = tmp_d['contact']
137 137 tmp_d['repo_archives'] = list(scmr._get_archives())
138 138 tmp_d['last_msg'] = tip.message
139 139 tmp_d['author'] = tip.author
140 140 tmp_d['dbrepo'] = dbr.get_dict()
141 141 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
142 142 yield tmp_d
143 143
144 144
145 145 class SimpleCachedRepoList(CachedRepoList):
146 146 """
147 147 Lighter version of CachedRepoList without the scm initialisation
148 148 """
149 149
150 150 def __iter__(self):
151 151 for dbr in self.db_repo_list:
152 152 # check permission at this level
153 153 if not HasRepoPermissionAny(
154 154 *self.perm_set)(dbr.repo_name, 'get repo check'):
155 155 continue
156 156
157 157 tmp_d = {}
158 158 tmp_d['name'] = dbr.repo_name
159 159 tmp_d['name_sort'] = tmp_d['name'].lower()
160 160 tmp_d['raw_name'] = tmp_d['name'].lower()
161 161 tmp_d['description'] = dbr.description
162 162 tmp_d['description_sort'] = tmp_d['description'].lower()
163 163 tmp_d['dbrepo'] = dbr.get_dict()
164 164 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
165 165 yield tmp_d
166 166
167 167
168 168 class _PermCheckIterator(object):
169 169 def __init__(self, obj_list, obj_attr, perm_set, perm_checker):
170 170 """
171 171 Creates iterator from given list of objects, additionally
172 172 checking permission for them from perm_set var
173 173
174 174 :param obj_list: list of db objects
175 175 :param obj_attr: attribute of object to pass into perm_checker
176 176 :param perm_set: list of permissions to check
177 177 :param perm_checker: callable to check permissions against
178 178 """
179 179 self.obj_list = obj_list
180 180 self.obj_attr = obj_attr
181 181 self.perm_set = perm_set
182 182 self.perm_checker = perm_checker
183 183
184 184 def __len__(self):
185 185 return len(self.obj_list)
186 186
187 187 def __repr__(self):
188 188 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
189 189
190 190 def __iter__(self):
191 191 for db_obj in self.obj_list:
192 192 # check permission at this level
193 193 name = getattr(db_obj, self.obj_attr, None)
194 194 if not self.perm_checker(*self.perm_set)(name, self.__class__.__name__):
195 195 continue
196 196
197 197 yield db_obj
198 198
199 199
200 200 class RepoList(_PermCheckIterator):
201 201
202 202 def __init__(self, db_repo_list, perm_set=None):
203 203 if not perm_set:
204 204 perm_set = ['repository.read', 'repository.write', 'repository.admin']
205 205
206 206 super(RepoList, self).__init__(obj_list=db_repo_list,
207 207 obj_attr='repo_name', perm_set=perm_set,
208 208 perm_checker=HasRepoPermissionAny)
209 209
210 210
211 211 class RepoGroupList(_PermCheckIterator):
212 212
213 213 def __init__(self, db_repo_group_list, perm_set=None):
214 214 if not perm_set:
215 215 perm_set = ['group.read', 'group.write', 'group.admin']
216 216
217 217 super(RepoGroupList, self).__init__(obj_list=db_repo_group_list,
218 218 obj_attr='group_name', perm_set=perm_set,
219 219 perm_checker=HasReposGroupPermissionAny)
220 220
221 221
222 222 class UserGroupList(_PermCheckIterator):
223 223
224 224 def __init__(self, db_user_group_list, perm_set=None):
225 225 if not perm_set:
226 226 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
227 227
228 228 super(UserGroupList, self).__init__(obj_list=db_user_group_list,
229 229 obj_attr='users_group_name', perm_set=perm_set,
230 230 perm_checker=HasUserGroupPermissionAny)
231 231
232 232
233 233 class ScmModel(BaseModel):
234 234 """
235 235 Generic Scm Model
236 236 """
237 237
238 238 def __get_repo(self, instance):
239 239 cls = Repository
240 240 if isinstance(instance, cls):
241 241 return instance
242 242 elif isinstance(instance, int) or safe_str(instance).isdigit():
243 243 return cls.get(instance)
244 244 elif isinstance(instance, basestring):
245 245 return cls.get_by_repo_name(instance)
246 246 elif instance:
247 247 raise Exception('given object must be int, basestr or Instance'
248 248 ' of %s got %s' % (type(cls), type(instance)))
249 249
250 250 @LazyProperty
251 251 def repos_path(self):
252 252 """
253 253 Get's the repositories root path from database
254 254 """
255 255
256 256 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
257 257
258 258 return q.ui_value
259 259
260 260 def repo_scan(self, repos_path=None):
261 261 """
262 262 Listing of repositories in given path. This path should not be a
263 263 repository itself. Return a dictionary of repository objects
264 264
265 265 :param repos_path: path to directory containing repositories
266 266 """
267 267
268 268 if repos_path is None:
269 269 repos_path = self.repos_path
270 270
271 271 log.info('scanning for repositories in %s' % repos_path)
272 272
273 273 baseui = make_ui('db')
274 274 repos = {}
275 275
276 276 for name, path in get_filesystem_repos(repos_path, recursive=True):
277 277 # name need to be decomposed and put back together using the /
278 278 # since this is internal storage separator for rhodecode
279 279 name = Repository.normalize_repo_name(name)
280 280
281 281 try:
282 282 if name in repos:
283 283 raise RepositoryError('Duplicate repository name %s '
284 284 'found in %s' % (name, path))
285 285 else:
286 286
287 287 klass = get_backend(path[0])
288 288
289 289 if path[0] == 'hg' and path[0] in BACKENDS.keys():
290 290 repos[name] = klass(safe_str(path[1]), baseui=baseui)
291 291
292 292 if path[0] == 'git' and path[0] in BACKENDS.keys():
293 293 repos[name] = klass(path[1])
294 294 except OSError:
295 295 continue
296 296 log.debug('found %s paths with repositories' % (len(repos)))
297 297 return repos
298 298
299 299 def get_repos(self, all_repos=None, sort_key=None, simple=False):
300 300 """
301 301 Get all repos from db and for each repo create it's
302 302 backend instance and fill that backed with information from database
303 303
304 304 :param all_repos: list of repository names as strings
305 305 give specific repositories list, good for filtering
306 306
307 307 :param sort_key: initial sorting of repos
308 308 :param simple: use SimpleCachedList - one without the SCM info
309 309 """
310 310 if all_repos is None:
311 311 all_repos = self.sa.query(Repository)\
312 312 .filter(Repository.group_id == None)\
313 313 .order_by(func.lower(Repository.repo_name)).all()
314 314 if simple:
315 315 repo_iter = SimpleCachedRepoList(all_repos,
316 316 repos_path=self.repos_path,
317 317 order_by=sort_key)
318 318 else:
319 319 repo_iter = CachedRepoList(all_repos,
320 320 repos_path=self.repos_path,
321 321 order_by=sort_key)
322 322
323 323 return repo_iter
324 324
325 325 def get_repos_groups(self, all_groups=None):
326 326 if all_groups is None:
327 327 all_groups = RepoGroup.query()\
328 328 .filter(RepoGroup.group_parent_id == None).all()
329 329 return [x for x in RepoGroupList(all_groups)]
330 330
331 331 def mark_for_invalidation(self, repo_name):
332 332 """
333 333 Mark caches of this repo invalid in the database.
334 334
335 335 :param repo_name: the repo for which caches should be marked invalid
336 336 """
337 337 CacheInvalidation.set_invalidate(repo_name)
338 338 repo = Repository.get_by_repo_name(repo_name)
339 339 if repo:
340 340 repo.update_changeset_cache()
341 341
342 342 def toggle_following_repo(self, follow_repo_id, user_id):
343 343
344 344 f = self.sa.query(UserFollowing)\
345 345 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
346 346 .filter(UserFollowing.user_id == user_id).scalar()
347 347
348 348 if f is not None:
349 349 try:
350 350 self.sa.delete(f)
351 351 action_logger(UserTemp(user_id),
352 352 'stopped_following_repo',
353 353 RepoTemp(follow_repo_id))
354 354 return
355 355 except Exception:
356 356 log.error(traceback.format_exc())
357 357 raise
358 358
359 359 try:
360 360 f = UserFollowing()
361 361 f.user_id = user_id
362 362 f.follows_repo_id = follow_repo_id
363 363 self.sa.add(f)
364 364
365 365 action_logger(UserTemp(user_id),
366 366 'started_following_repo',
367 367 RepoTemp(follow_repo_id))
368 368 except Exception:
369 369 log.error(traceback.format_exc())
370 370 raise
371 371
372 372 def toggle_following_user(self, follow_user_id, user_id):
373 373 f = self.sa.query(UserFollowing)\
374 374 .filter(UserFollowing.follows_user_id == follow_user_id)\
375 375 .filter(UserFollowing.user_id == user_id).scalar()
376 376
377 377 if f is not None:
378 378 try:
379 379 self.sa.delete(f)
380 380 return
381 381 except Exception:
382 382 log.error(traceback.format_exc())
383 383 raise
384 384
385 385 try:
386 386 f = UserFollowing()
387 387 f.user_id = user_id
388 388 f.follows_user_id = follow_user_id
389 389 self.sa.add(f)
390 390 except Exception:
391 391 log.error(traceback.format_exc())
392 392 raise
393 393
394 394 def is_following_repo(self, repo_name, user_id, cache=False):
395 395 r = self.sa.query(Repository)\
396 396 .filter(Repository.repo_name == repo_name).scalar()
397 397
398 398 f = self.sa.query(UserFollowing)\
399 399 .filter(UserFollowing.follows_repository == r)\
400 400 .filter(UserFollowing.user_id == user_id).scalar()
401 401
402 402 return f is not None
403 403
404 404 def is_following_user(self, username, user_id, cache=False):
405 405 u = User.get_by_username(username)
406 406
407 407 f = self.sa.query(UserFollowing)\
408 408 .filter(UserFollowing.follows_user == u)\
409 409 .filter(UserFollowing.user_id == user_id).scalar()
410 410
411 411 return f is not None
412 412
413 413 def get_followers(self, repo):
414 414 repo = self._get_repo(repo)
415 415
416 416 return self.sa.query(UserFollowing)\
417 417 .filter(UserFollowing.follows_repository == repo).count()
418 418
419 419 def get_forks(self, repo):
420 420 repo = self._get_repo(repo)
421 421 return self.sa.query(Repository)\
422 422 .filter(Repository.fork == repo).count()
423 423
424 424 def get_pull_requests(self, repo):
425 425 repo = self._get_repo(repo)
426 426 return self.sa.query(PullRequest)\
427 427 .filter(PullRequest.other_repo == repo)\
428 428 .filter(PullRequest.status != PullRequest.STATUS_CLOSED).count()
429 429
430 430 def mark_as_fork(self, repo, fork, user):
431 431 repo = self.__get_repo(repo)
432 432 fork = self.__get_repo(fork)
433 433 if fork and repo.repo_id == fork.repo_id:
434 434 raise Exception("Cannot set repository as fork of itself")
435 435 repo.fork = fork
436 436 self.sa.add(repo)
437 437 return repo
438 438
439 439 def _handle_rc_scm_extras(self, username, repo_name, repo_alias,
440 440 action=None):
441 441 from rhodecode import CONFIG
442 442 from rhodecode.lib.base import _get_ip_addr
443 443 try:
444 444 from pylons import request
445 445 environ = request.environ
446 446 except TypeError:
447 447 # we might use this outside of request context, let's fake the
448 448 # environ data
449 449 from webob import Request
450 450 environ = Request.blank('').environ
451 451 extras = {
452 452 'ip': _get_ip_addr(environ),
453 453 'username': username,
454 454 'action': action or 'push_local',
455 455 'repository': repo_name,
456 456 'scm': repo_alias,
457 457 'config': CONFIG['__file__'],
458 458 'server_url': get_server_url(environ),
459 459 'make_lock': None,
460 460 'locked_by': [None, None]
461 461 }
462 462 _set_extras(extras)
463 463
464 464 def _handle_push(self, repo, username, action, repo_name, revisions):
465 465 """
466 466 Triggers push action hooks
467 467
468 468 :param repo: SCM repo
469 469 :param username: username who pushes
470 470 :param action: push/push_loca/push_remote
471 471 :param repo_name: name of repo
472 472 :param revisions: list of revisions that we pushed
473 473 """
474 474 self._handle_rc_scm_extras(username, repo_name, repo_alias=repo.alias)
475 475 _scm_repo = repo._repo
476 476 # trigger push hook
477 477 if repo.alias == 'hg':
478 478 log_push_action(_scm_repo.ui, _scm_repo, node=revisions[0])
479 479 elif repo.alias == 'git':
480 480 log_push_action(None, _scm_repo, _git_revs=revisions)
481 481
482 482 def _get_IMC_module(self, scm_type):
483 483 """
484 484 Returns InMemoryCommit class based on scm_type
485 485
486 486 :param scm_type:
487 487 """
488 488 if scm_type == 'hg':
489 489 from rhodecode.lib.vcs.backends.hg import \
490 490 MercurialInMemoryChangeset as IMC
491 491 elif scm_type == 'git':
492 492 from rhodecode.lib.vcs.backends.git import \
493 493 GitInMemoryChangeset as IMC
494 494 return IMC
495 495
496 496 def pull_changes(self, repo, username):
497 497 dbrepo = self.__get_repo(repo)
498 498 clone_uri = dbrepo.clone_uri
499 499 if not clone_uri:
500 500 raise Exception("This repository doesn't have a clone uri")
501 501
502 502 repo = dbrepo.scm_instance
503 503 repo_name = dbrepo.repo_name
504 504 try:
505 505 if repo.alias == 'git':
506 506 repo.fetch(clone_uri)
507 # git doesn't really have something like post-fetch action
508 # we fake that now. #TODO: extract fetched revisions somehow
509 # here
510 self._handle_push(repo,
511 username=username,
512 action='push_remote',
513 repo_name=repo_name,
514 revisions=[])
507 515 else:
508 516 self._handle_rc_scm_extras(username, dbrepo.repo_name,
509 517 repo.alias, action='push_remote')
510 518 repo.pull(clone_uri)
511 519
512 520 self.mark_for_invalidation(repo_name)
513 521 except Exception:
514 522 log.error(traceback.format_exc())
515 523 raise
516 524
517 525 def commit_change(self, repo, repo_name, cs, user, author, message,
518 526 content, f_path):
519 527 """
520 528 Commits changes
521 529
522 530 :param repo: SCM instance
523 531
524 532 """
525 533 user = self._get_user(user)
526 534 IMC = self._get_IMC_module(repo.alias)
527 535
528 536 # decoding here will force that we have proper encoded values
529 537 # in any other case this will throw exceptions and deny commit
530 538 content = safe_str(content)
531 539 path = safe_str(f_path)
532 540 # message and author needs to be unicode
533 541 # proper backend should then translate that into required type
534 542 message = safe_unicode(message)
535 543 author = safe_unicode(author)
536 544 imc = IMC(repo)
537 545 imc.change(FileNode(path, content, mode=cs.get_file_mode(f_path)))
538 546 tip = imc.commit(message=message,
539 547 author=author,
540 548 parents=[cs], branch=cs.branch)
541 549
542 550 self.mark_for_invalidation(repo_name)
543 551 self._handle_push(repo,
544 552 username=user.username,
545 553 action='push_local',
546 554 repo_name=repo_name,
547 555 revisions=[tip.raw_id])
548 556 return tip
549 557
550 558 def create_nodes(self, user, repo, message, nodes, parent_cs=None,
551 559 author=None, trigger_push_hook=True):
552 560 """
553 561 Commits given multiple nodes into repo
554 562
555 563 :param user: RhodeCode User object or user_id, the commiter
556 564 :param repo: RhodeCode Repository object
557 565 :param message: commit message
558 566 :param nodes: mapping {filename:{'content':content},...}
559 567 :param parent_cs: parent changeset, can be empty than it's initial commit
560 568 :param author: author of commit, cna be different that commiter only for git
561 569 :param trigger_push_hook: trigger push hooks
562 570
563 571 :returns: new commited changeset
564 572 """
565 573
566 574 user = self._get_user(user)
567 575 scm_instance = repo.scm_instance_no_cache()
568 576
569 577 processed_nodes = []
570 578 for f_path in nodes:
571 579 if f_path.startswith('/') or f_path.startswith('.') or '../' in f_path:
572 580 raise NonRelativePathError('%s is not an relative path' % f_path)
573 581 if f_path:
574 582 f_path = os.path.normpath(f_path)
575 583 f_path = safe_str(f_path)
576 584 content = nodes[f_path]['content']
577 585 # decoding here will force that we have proper encoded values
578 586 # in any other case this will throw exceptions and deny commit
579 587 if isinstance(content, (basestring,)):
580 588 content = safe_str(content)
581 589 elif isinstance(content, (file, cStringIO.OutputType,)):
582 590 content = content.read()
583 591 else:
584 592 raise Exception('Content is of unrecognized type %s' % (
585 593 type(content)
586 594 ))
587 595 processed_nodes.append((f_path, content))
588 596
589 597 message = safe_unicode(message)
590 598 commiter = user.full_contact
591 599 author = safe_unicode(author) if author else commiter
592 600
593 601 IMC = self._get_IMC_module(scm_instance.alias)
594 602 imc = IMC(scm_instance)
595 603
596 604 if not parent_cs:
597 605 parent_cs = EmptyChangeset(alias=scm_instance.alias)
598 606
599 607 if isinstance(parent_cs, EmptyChangeset):
600 608 # EmptyChangeset means we we're editing empty repository
601 609 parents = None
602 610 else:
603 611 parents = [parent_cs]
604 612 # add multiple nodes
605 613 for path, content in processed_nodes:
606 614 imc.add(FileNode(path, content=content))
607 615
608 616 tip = imc.commit(message=message,
609 617 author=author,
610 618 parents=parents,
611 619 branch=parent_cs.branch)
612 620
613 621 self.mark_for_invalidation(repo.repo_name)
614 622 if trigger_push_hook:
615 623 self._handle_push(scm_instance,
616 624 username=user.username,
617 625 action='push_local',
618 626 repo_name=repo.repo_name,
619 627 revisions=[tip.raw_id])
620 628 return tip
621 629
622 630 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
623 631 """
624 632 recursive walk in root dir and return a set of all path in that dir
625 633 based on repository walk function
626 634
627 635 :param repo_name: name of repository
628 636 :param revision: revision for which to list nodes
629 637 :param root_path: root path to list
630 638 :param flat: return as a list, if False returns a dict with decription
631 639
632 640 """
633 641 _files = list()
634 642 _dirs = list()
635 643 try:
636 644 _repo = self.__get_repo(repo_name)
637 645 changeset = _repo.scm_instance.get_changeset(revision)
638 646 root_path = root_path.lstrip('/')
639 647 for topnode, dirs, files in changeset.walk(root_path):
640 648 for f in files:
641 649 _files.append(f.path if flat else {"name": f.path,
642 650 "type": "file"})
643 651 for d in dirs:
644 652 _dirs.append(d.path if flat else {"name": d.path,
645 653 "type": "dir"})
646 654 except RepositoryError:
647 655 log.debug(traceback.format_exc())
648 656 raise
649 657
650 658 return _dirs, _files
651 659
652 660 def get_unread_journal(self):
653 661 return self.sa.query(UserLog).count()
654 662
655 663 def get_repo_landing_revs(self, repo=None):
656 664 """
657 665 Generates select option with tags branches and bookmarks (for hg only)
658 666 grouped by type
659 667
660 668 :param repo:
661 669 """
662 670
663 671 hist_l = []
664 672 choices = []
665 673 repo = self.__get_repo(repo)
666 674 hist_l.append(['tip', _('latest tip')])
667 675 choices.append('tip')
668 676 if not repo:
669 677 return choices, hist_l
670 678
671 679 repo = repo.scm_instance
672 680
673 681 branches_group = ([(k, k) for k, v in
674 682 repo.branches.iteritems()], _("Branches"))
675 683 hist_l.append(branches_group)
676 684 choices.extend([x[0] for x in branches_group[0]])
677 685
678 686 if repo.alias == 'hg':
679 687 bookmarks_group = ([(k, k) for k, v in
680 688 repo.bookmarks.iteritems()], _("Bookmarks"))
681 689 hist_l.append(bookmarks_group)
682 690 choices.extend([x[0] for x in bookmarks_group[0]])
683 691
684 692 tags_group = ([(k, k) for k, v in
685 693 repo.tags.iteritems()], _("Tags"))
686 694 hist_l.append(tags_group)
687 695 choices.extend([x[0] for x in tags_group[0]])
688 696
689 697 return choices, hist_l
690 698
691 699 def install_git_hook(self, repo, force_create=False):
692 700 """
693 701 Creates a rhodecode hook inside a git repository
694 702
695 703 :param repo: Instance of VCS repo
696 704 :param force_create: Create even if same name hook exists
697 705 """
698 706
699 707 loc = jn(repo.path, 'hooks')
700 708 if not repo.bare:
701 709 loc = jn(repo.path, '.git', 'hooks')
702 710 if not os.path.isdir(loc):
703 711 os.makedirs(loc)
704 712
705 713 tmpl_post = pkg_resources.resource_string(
706 714 'rhodecode', jn('config', 'post_receive_tmpl.py')
707 715 )
708 716 tmpl_pre = pkg_resources.resource_string(
709 717 'rhodecode', jn('config', 'pre_receive_tmpl.py')
710 718 )
711 719
712 720 for h_type, tmpl in [('pre', tmpl_pre), ('post', tmpl_post)]:
713 721 _hook_file = jn(loc, '%s-receive' % h_type)
714 722 _rhodecode_hook = False
715 723 log.debug('Installing git hook in repo %s' % repo)
716 724 if os.path.exists(_hook_file):
717 725 # let's take a look at this hook, maybe it's rhodecode ?
718 726 log.debug('hook exists, checking if it is from rhodecode')
719 727 _HOOK_VER_PAT = re.compile(r'^RC_HOOK_VER')
720 728 with open(_hook_file, 'rb') as f:
721 729 data = f.read()
722 730 matches = re.compile(r'(?:%s)\s*=\s*(.*)'
723 731 % 'RC_HOOK_VER').search(data)
724 732 if matches:
725 733 try:
726 734 ver = matches.groups()[0]
727 735 log.debug('got %s it is rhodecode' % (ver))
728 736 _rhodecode_hook = True
729 737 except Exception:
730 738 log.error(traceback.format_exc())
731 739 else:
732 740 # there is no hook in this dir, so we want to create one
733 741 _rhodecode_hook = True
734 742
735 743 if _rhodecode_hook or force_create:
736 744 log.debug('writing %s hook file !' % h_type)
737 745 with open(_hook_file, 'wb') as f:
738 746 tmpl = tmpl.replace('_TMPL_', rhodecode.__version__)
739 747 f.write(tmpl)
740 748 os.chmod(_hook_file, 0755)
741 749 else:
742 750 log.debug('skipping writing hook file')
General Comments 0
You need to be logged in to leave comments. Login now