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