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