##// END OF EJS Templates
fixed default sorting on main page with sorting using wrapped lower() call on database level
marcink -
r2354:f3417f0d beta
parent child Browse files
Show More
@@ -1,470 +1,472 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 import os
25 import os
26 import time
26 import time
27 import traceback
27 import traceback
28 import logging
28 import logging
29 import cStringIO
29 import cStringIO
30
30
31 from sqlalchemy import func
32
31 from rhodecode.lib.vcs import get_backend
33 from rhodecode.lib.vcs import get_backend
32 from rhodecode.lib.vcs.exceptions import RepositoryError
34 from rhodecode.lib.vcs.exceptions import RepositoryError
33 from rhodecode.lib.vcs.utils.lazy import LazyProperty
35 from rhodecode.lib.vcs.utils.lazy import LazyProperty
34 from rhodecode.lib.vcs.nodes import FileNode
36 from rhodecode.lib.vcs.nodes import FileNode
35
37
36 from rhodecode import BACKENDS
38 from rhodecode import BACKENDS
37 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
38 from rhodecode.lib.utils2 import safe_str, safe_unicode
40 from rhodecode.lib.utils2 import safe_str, safe_unicode
39 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
41 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
40 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
42 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
41 action_logger, EmptyChangeset, REMOVED_REPO_PAT
43 action_logger, EmptyChangeset, REMOVED_REPO_PAT
42 from rhodecode.model import BaseModel
44 from rhodecode.model import BaseModel
43 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
45 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
44 UserFollowing, UserLog, User, RepoGroup
46 UserFollowing, UserLog, User, RepoGroup
45
47
46 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
47
49
48
50
49 class UserTemp(object):
51 class UserTemp(object):
50 def __init__(self, user_id):
52 def __init__(self, user_id):
51 self.user_id = user_id
53 self.user_id = user_id
52
54
53 def __repr__(self):
55 def __repr__(self):
54 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
56 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
55
57
56
58
57 class RepoTemp(object):
59 class RepoTemp(object):
58 def __init__(self, repo_id):
60 def __init__(self, repo_id):
59 self.repo_id = repo_id
61 self.repo_id = repo_id
60
62
61 def __repr__(self):
63 def __repr__(self):
62 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
64 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
63
65
64
66
65 class CachedRepoList(object):
67 class CachedRepoList(object):
66
68
67 def __init__(self, db_repo_list, repos_path, order_by=None):
69 def __init__(self, db_repo_list, repos_path, order_by=None):
68 self.db_repo_list = db_repo_list
70 self.db_repo_list = db_repo_list
69 self.repos_path = repos_path
71 self.repos_path = repos_path
70 self.order_by = order_by
72 self.order_by = order_by
71 self.reversed = (order_by or '').startswith('-')
73 self.reversed = (order_by or '').startswith('-')
72
74
73 def __len__(self):
75 def __len__(self):
74 return len(self.db_repo_list)
76 return len(self.db_repo_list)
75
77
76 def __repr__(self):
78 def __repr__(self):
77 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
79 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
78
80
79 def __iter__(self):
81 def __iter__(self):
80 # pre-propagated cache_map to save executing select statements
82 # pre-propagated cache_map to save executing select statements
81 # for each repo
83 # for each repo
82 cache_map = CacheInvalidation.get_cache_map()
84 cache_map = CacheInvalidation.get_cache_map()
83
85
84 for dbr in self.db_repo_list:
86 for dbr in self.db_repo_list:
85 scmr = dbr.scm_instance_cached(cache_map)
87 scmr = dbr.scm_instance_cached(cache_map)
86 # check permission at this level
88 # check permission at this level
87 if not HasRepoPermissionAny(
89 if not HasRepoPermissionAny(
88 'repository.read', 'repository.write', 'repository.admin'
90 'repository.read', 'repository.write', 'repository.admin'
89 )(dbr.repo_name, 'get repo check'):
91 )(dbr.repo_name, 'get repo check'):
90 continue
92 continue
91
93
92 if scmr is None:
94 if scmr is None:
93 log.error(
95 log.error(
94 '%s this repository is present in database but it '
96 '%s this repository is present in database but it '
95 'cannot be created as an scm instance' % dbr.repo_name
97 'cannot be created as an scm instance' % dbr.repo_name
96 )
98 )
97 continue
99 continue
98
100
99 last_change = scmr.last_change
101 last_change = scmr.last_change
100 tip = h.get_changeset_safe(scmr, 'tip')
102 tip = h.get_changeset_safe(scmr, 'tip')
101
103
102 tmp_d = {}
104 tmp_d = {}
103 tmp_d['name'] = dbr.repo_name
105 tmp_d['name'] = dbr.repo_name
104 tmp_d['name_sort'] = tmp_d['name'].lower()
106 tmp_d['name_sort'] = tmp_d['name'].lower()
105 tmp_d['description'] = dbr.description
107 tmp_d['description'] = dbr.description
106 tmp_d['description_sort'] = tmp_d['description']
108 tmp_d['description_sort'] = tmp_d['description']
107 tmp_d['last_change'] = last_change
109 tmp_d['last_change'] = last_change
108 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
110 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
109 tmp_d['tip'] = tip.raw_id
111 tmp_d['tip'] = tip.raw_id
110 tmp_d['tip_sort'] = tip.revision
112 tmp_d['tip_sort'] = tip.revision
111 tmp_d['rev'] = tip.revision
113 tmp_d['rev'] = tip.revision
112 tmp_d['contact'] = dbr.user.full_contact
114 tmp_d['contact'] = dbr.user.full_contact
113 tmp_d['contact_sort'] = tmp_d['contact']
115 tmp_d['contact_sort'] = tmp_d['contact']
114 tmp_d['owner_sort'] = tmp_d['contact']
116 tmp_d['owner_sort'] = tmp_d['contact']
115 tmp_d['repo_archives'] = list(scmr._get_archives())
117 tmp_d['repo_archives'] = list(scmr._get_archives())
116 tmp_d['last_msg'] = tip.message
118 tmp_d['last_msg'] = tip.message
117 tmp_d['author'] = tip.author
119 tmp_d['author'] = tip.author
118 tmp_d['dbrepo'] = dbr.get_dict()
120 tmp_d['dbrepo'] = dbr.get_dict()
119 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
121 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
120 yield tmp_d
122 yield tmp_d
121
123
122
124
123 class GroupList(object):
125 class GroupList(object):
124
126
125 def __init__(self, db_repo_group_list):
127 def __init__(self, db_repo_group_list):
126 self.db_repo_group_list = db_repo_group_list
128 self.db_repo_group_list = db_repo_group_list
127
129
128 def __len__(self):
130 def __len__(self):
129 return len(self.db_repo_group_list)
131 return len(self.db_repo_group_list)
130
132
131 def __repr__(self):
133 def __repr__(self):
132 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
134 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
133
135
134 def __iter__(self):
136 def __iter__(self):
135 for dbgr in self.db_repo_group_list:
137 for dbgr in self.db_repo_group_list:
136 # check permission at this level
138 # check permission at this level
137 if not HasReposGroupPermissionAny(
139 if not HasReposGroupPermissionAny(
138 'group.read', 'group.write', 'group.admin'
140 'group.read', 'group.write', 'group.admin'
139 )(dbgr.group_name, 'get group repo check'):
141 )(dbgr.group_name, 'get group repo check'):
140 continue
142 continue
141
143
142 yield dbgr
144 yield dbgr
143
145
144
146
145 class ScmModel(BaseModel):
147 class ScmModel(BaseModel):
146 """
148 """
147 Generic Scm Model
149 Generic Scm Model
148 """
150 """
149
151
150 def __get_repo(self, instance):
152 def __get_repo(self, instance):
151 cls = Repository
153 cls = Repository
152 if isinstance(instance, cls):
154 if isinstance(instance, cls):
153 return instance
155 return instance
154 elif isinstance(instance, int) or str(instance).isdigit():
156 elif isinstance(instance, int) or str(instance).isdigit():
155 return cls.get(instance)
157 return cls.get(instance)
156 elif isinstance(instance, basestring):
158 elif isinstance(instance, basestring):
157 return cls.get_by_repo_name(instance)
159 return cls.get_by_repo_name(instance)
158 elif instance:
160 elif instance:
159 raise Exception('given object must be int, basestr or Instance'
161 raise Exception('given object must be int, basestr or Instance'
160 ' of %s got %s' % (type(cls), type(instance)))
162 ' of %s got %s' % (type(cls), type(instance)))
161
163
162 @LazyProperty
164 @LazyProperty
163 def repos_path(self):
165 def repos_path(self):
164 """
166 """
165 Get's the repositories root path from database
167 Get's the repositories root path from database
166 """
168 """
167
169
168 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
170 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
169
171
170 return q.ui_value
172 return q.ui_value
171
173
172 def repo_scan(self, repos_path=None):
174 def repo_scan(self, repos_path=None):
173 """
175 """
174 Listing of repositories in given path. This path should not be a
176 Listing of repositories in given path. This path should not be a
175 repository itself. Return a dictionary of repository objects
177 repository itself. Return a dictionary of repository objects
176
178
177 :param repos_path: path to directory containing repositories
179 :param repos_path: path to directory containing repositories
178 """
180 """
179
181
180 if repos_path is None:
182 if repos_path is None:
181 repos_path = self.repos_path
183 repos_path = self.repos_path
182
184
183 log.info('scanning for repositories in %s' % repos_path)
185 log.info('scanning for repositories in %s' % repos_path)
184
186
185 baseui = make_ui('db')
187 baseui = make_ui('db')
186 repos = {}
188 repos = {}
187
189
188 for name, path in get_filesystem_repos(repos_path, recursive=True):
190 for name, path in get_filesystem_repos(repos_path, recursive=True):
189 # skip removed repos
191 # skip removed repos
190 if REMOVED_REPO_PAT.match(name):
192 if REMOVED_REPO_PAT.match(name):
191 continue
193 continue
192
194
193 # name need to be decomposed and put back together using the /
195 # name need to be decomposed and put back together using the /
194 # since this is internal storage separator for rhodecode
196 # since this is internal storage separator for rhodecode
195 name = Repository.url_sep().join(name.split(os.sep))
197 name = Repository.url_sep().join(name.split(os.sep))
196
198
197 try:
199 try:
198 if name in repos:
200 if name in repos:
199 raise RepositoryError('Duplicate repository name %s '
201 raise RepositoryError('Duplicate repository name %s '
200 'found in %s' % (name, path))
202 'found in %s' % (name, path))
201 else:
203 else:
202
204
203 klass = get_backend(path[0])
205 klass = get_backend(path[0])
204
206
205 if path[0] == 'hg' and path[0] in BACKENDS.keys():
207 if path[0] == 'hg' and path[0] in BACKENDS.keys():
206 repos[name] = klass(safe_str(path[1]), baseui=baseui)
208 repos[name] = klass(safe_str(path[1]), baseui=baseui)
207
209
208 if path[0] == 'git' and path[0] in BACKENDS.keys():
210 if path[0] == 'git' and path[0] in BACKENDS.keys():
209 repos[name] = klass(path[1])
211 repos[name] = klass(path[1])
210 except OSError:
212 except OSError:
211 continue
213 continue
212
214
213 return repos
215 return repos
214
216
215 def get_repos(self, all_repos=None, sort_key=None):
217 def get_repos(self, all_repos=None, sort_key=None):
216 """
218 """
217 Get all repos from db and for each repo create it's
219 Get all repos from db and for each repo create it's
218 backend instance and fill that backed with information from database
220 backend instance and fill that backed with information from database
219
221
220 :param all_repos: list of repository names as strings
222 :param all_repos: list of repository names as strings
221 give specific repositories list, good for filtering
223 give specific repositories list, good for filtering
222 """
224 """
223 if all_repos is None:
225 if all_repos is None:
224 all_repos = self.sa.query(Repository)\
226 all_repos = self.sa.query(Repository)\
225 .filter(Repository.group_id == None)\
227 .filter(Repository.group_id == None)\
226 .order_by(Repository.repo_name).all()
228 .order_by(func.lower(Repository.repo_name)).all()
227
229
228 repo_iter = CachedRepoList(all_repos, repos_path=self.repos_path,
230 repo_iter = CachedRepoList(all_repos, repos_path=self.repos_path,
229 order_by=sort_key)
231 order_by=sort_key)
230
232
231 return repo_iter
233 return repo_iter
232
234
233 def get_repos_groups(self, all_groups=None):
235 def get_repos_groups(self, all_groups=None):
234 if all_groups is None:
236 if all_groups is None:
235 all_groups = RepoGroup.query()\
237 all_groups = RepoGroup.query()\
236 .filter(RepoGroup.group_parent_id == None).all()
238 .filter(RepoGroup.group_parent_id == None).all()
237 group_iter = GroupList(all_groups)
239 group_iter = GroupList(all_groups)
238
240
239 return group_iter
241 return group_iter
240
242
241 def mark_for_invalidation(self, repo_name):
243 def mark_for_invalidation(self, repo_name):
242 """
244 """
243 Puts cache invalidation task into db for
245 Puts cache invalidation task into db for
244 further global cache invalidation
246 further global cache invalidation
245
247
246 :param repo_name: this repo that should invalidation take place
248 :param repo_name: this repo that should invalidation take place
247 """
249 """
248 CacheInvalidation.set_invalidate(repo_name)
250 CacheInvalidation.set_invalidate(repo_name)
249
251
250 def toggle_following_repo(self, follow_repo_id, user_id):
252 def toggle_following_repo(self, follow_repo_id, user_id):
251
253
252 f = self.sa.query(UserFollowing)\
254 f = self.sa.query(UserFollowing)\
253 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
255 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
254 .filter(UserFollowing.user_id == user_id).scalar()
256 .filter(UserFollowing.user_id == user_id).scalar()
255
257
256 if f is not None:
258 if f is not None:
257 try:
259 try:
258 self.sa.delete(f)
260 self.sa.delete(f)
259 action_logger(UserTemp(user_id),
261 action_logger(UserTemp(user_id),
260 'stopped_following_repo',
262 'stopped_following_repo',
261 RepoTemp(follow_repo_id))
263 RepoTemp(follow_repo_id))
262 return
264 return
263 except:
265 except:
264 log.error(traceback.format_exc())
266 log.error(traceback.format_exc())
265 raise
267 raise
266
268
267 try:
269 try:
268 f = UserFollowing()
270 f = UserFollowing()
269 f.user_id = user_id
271 f.user_id = user_id
270 f.follows_repo_id = follow_repo_id
272 f.follows_repo_id = follow_repo_id
271 self.sa.add(f)
273 self.sa.add(f)
272
274
273 action_logger(UserTemp(user_id),
275 action_logger(UserTemp(user_id),
274 'started_following_repo',
276 'started_following_repo',
275 RepoTemp(follow_repo_id))
277 RepoTemp(follow_repo_id))
276 except:
278 except:
277 log.error(traceback.format_exc())
279 log.error(traceback.format_exc())
278 raise
280 raise
279
281
280 def toggle_following_user(self, follow_user_id, user_id):
282 def toggle_following_user(self, follow_user_id, user_id):
281 f = self.sa.query(UserFollowing)\
283 f = self.sa.query(UserFollowing)\
282 .filter(UserFollowing.follows_user_id == follow_user_id)\
284 .filter(UserFollowing.follows_user_id == follow_user_id)\
283 .filter(UserFollowing.user_id == user_id).scalar()
285 .filter(UserFollowing.user_id == user_id).scalar()
284
286
285 if f is not None:
287 if f is not None:
286 try:
288 try:
287 self.sa.delete(f)
289 self.sa.delete(f)
288 return
290 return
289 except:
291 except:
290 log.error(traceback.format_exc())
292 log.error(traceback.format_exc())
291 raise
293 raise
292
294
293 try:
295 try:
294 f = UserFollowing()
296 f = UserFollowing()
295 f.user_id = user_id
297 f.user_id = user_id
296 f.follows_user_id = follow_user_id
298 f.follows_user_id = follow_user_id
297 self.sa.add(f)
299 self.sa.add(f)
298 except:
300 except:
299 log.error(traceback.format_exc())
301 log.error(traceback.format_exc())
300 raise
302 raise
301
303
302 def is_following_repo(self, repo_name, user_id, cache=False):
304 def is_following_repo(self, repo_name, user_id, cache=False):
303 r = self.sa.query(Repository)\
305 r = self.sa.query(Repository)\
304 .filter(Repository.repo_name == repo_name).scalar()
306 .filter(Repository.repo_name == repo_name).scalar()
305
307
306 f = self.sa.query(UserFollowing)\
308 f = self.sa.query(UserFollowing)\
307 .filter(UserFollowing.follows_repository == r)\
309 .filter(UserFollowing.follows_repository == r)\
308 .filter(UserFollowing.user_id == user_id).scalar()
310 .filter(UserFollowing.user_id == user_id).scalar()
309
311
310 return f is not None
312 return f is not None
311
313
312 def is_following_user(self, username, user_id, cache=False):
314 def is_following_user(self, username, user_id, cache=False):
313 u = User.get_by_username(username)
315 u = User.get_by_username(username)
314
316
315 f = self.sa.query(UserFollowing)\
317 f = self.sa.query(UserFollowing)\
316 .filter(UserFollowing.follows_user == u)\
318 .filter(UserFollowing.follows_user == u)\
317 .filter(UserFollowing.user_id == user_id).scalar()
319 .filter(UserFollowing.user_id == user_id).scalar()
318
320
319 return f is not None
321 return f is not None
320
322
321 def get_followers(self, repo_id):
323 def get_followers(self, repo_id):
322 if not isinstance(repo_id, int):
324 if not isinstance(repo_id, int):
323 repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
325 repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
324
326
325 return self.sa.query(UserFollowing)\
327 return self.sa.query(UserFollowing)\
326 .filter(UserFollowing.follows_repo_id == repo_id).count()
328 .filter(UserFollowing.follows_repo_id == repo_id).count()
327
329
328 def get_forks(self, repo_id):
330 def get_forks(self, repo_id):
329 if not isinstance(repo_id, int):
331 if not isinstance(repo_id, int):
330 repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
332 repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
331
333
332 return self.sa.query(Repository)\
334 return self.sa.query(Repository)\
333 .filter(Repository.fork_id == repo_id).count()
335 .filter(Repository.fork_id == repo_id).count()
334
336
335 def mark_as_fork(self, repo, fork, user):
337 def mark_as_fork(self, repo, fork, user):
336 repo = self.__get_repo(repo)
338 repo = self.__get_repo(repo)
337 fork = self.__get_repo(fork)
339 fork = self.__get_repo(fork)
338 repo.fork = fork
340 repo.fork = fork
339 self.sa.add(repo)
341 self.sa.add(repo)
340 return repo
342 return repo
341
343
342 def pull_changes(self, repo_name, username):
344 def pull_changes(self, repo_name, username):
343 dbrepo = Repository.get_by_repo_name(repo_name)
345 dbrepo = Repository.get_by_repo_name(repo_name)
344 clone_uri = dbrepo.clone_uri
346 clone_uri = dbrepo.clone_uri
345 if not clone_uri:
347 if not clone_uri:
346 raise Exception("This repository doesn't have a clone uri")
348 raise Exception("This repository doesn't have a clone uri")
347
349
348 repo = dbrepo.scm_instance
350 repo = dbrepo.scm_instance
349 try:
351 try:
350 extras = {
352 extras = {
351 'ip': '',
353 'ip': '',
352 'username': username,
354 'username': username,
353 'action': 'push_remote',
355 'action': 'push_remote',
354 'repository': repo_name,
356 'repository': repo_name,
355 'scm': repo.alias,
357 'scm': repo.alias,
356 }
358 }
357
359
358 # inject ui extra param to log this action via push logger
360 # inject ui extra param to log this action via push logger
359 for k, v in extras.items():
361 for k, v in extras.items():
360 repo._repo.ui.setconfig('rhodecode_extras', k, v)
362 repo._repo.ui.setconfig('rhodecode_extras', k, v)
361
363
362 repo.pull(clone_uri)
364 repo.pull(clone_uri)
363 self.mark_for_invalidation(repo_name)
365 self.mark_for_invalidation(repo_name)
364 except:
366 except:
365 log.error(traceback.format_exc())
367 log.error(traceback.format_exc())
366 raise
368 raise
367
369
368 def commit_change(self, repo, repo_name, cs, user, author, message,
370 def commit_change(self, repo, repo_name, cs, user, author, message,
369 content, f_path):
371 content, f_path):
370
372
371 if repo.alias == 'hg':
373 if repo.alias == 'hg':
372 from rhodecode.lib.vcs.backends.hg import \
374 from rhodecode.lib.vcs.backends.hg import \
373 MercurialInMemoryChangeset as IMC
375 MercurialInMemoryChangeset as IMC
374 elif repo.alias == 'git':
376 elif repo.alias == 'git':
375 from rhodecode.lib.vcs.backends.git import \
377 from rhodecode.lib.vcs.backends.git import \
376 GitInMemoryChangeset as IMC
378 GitInMemoryChangeset as IMC
377
379
378 # decoding here will force that we have proper encoded values
380 # decoding here will force that we have proper encoded values
379 # in any other case this will throw exceptions and deny commit
381 # in any other case this will throw exceptions and deny commit
380 content = safe_str(content)
382 content = safe_str(content)
381 path = safe_str(f_path)
383 path = safe_str(f_path)
382 # message and author needs to be unicode
384 # message and author needs to be unicode
383 # proper backend should then translate that into required type
385 # proper backend should then translate that into required type
384 message = safe_unicode(message)
386 message = safe_unicode(message)
385 author = safe_unicode(author)
387 author = safe_unicode(author)
386 m = IMC(repo)
388 m = IMC(repo)
387 m.change(FileNode(path, content))
389 m.change(FileNode(path, content))
388 tip = m.commit(message=message,
390 tip = m.commit(message=message,
389 author=author,
391 author=author,
390 parents=[cs], branch=cs.branch)
392 parents=[cs], branch=cs.branch)
391
393
392 new_cs = tip.short_id
394 new_cs = tip.short_id
393 action = 'push_local:%s' % new_cs
395 action = 'push_local:%s' % new_cs
394
396
395 action_logger(user, action, repo_name)
397 action_logger(user, action, repo_name)
396
398
397 self.mark_for_invalidation(repo_name)
399 self.mark_for_invalidation(repo_name)
398
400
399 def create_node(self, repo, repo_name, cs, user, author, message, content,
401 def create_node(self, repo, repo_name, cs, user, author, message, content,
400 f_path):
402 f_path):
401 if repo.alias == 'hg':
403 if repo.alias == 'hg':
402 from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset as IMC
404 from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset as IMC
403 elif repo.alias == 'git':
405 elif repo.alias == 'git':
404 from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset as IMC
406 from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset as IMC
405 # decoding here will force that we have proper encoded values
407 # decoding here will force that we have proper encoded values
406 # in any other case this will throw exceptions and deny commit
408 # in any other case this will throw exceptions and deny commit
407
409
408 if isinstance(content, (basestring,)):
410 if isinstance(content, (basestring,)):
409 content = safe_str(content)
411 content = safe_str(content)
410 elif isinstance(content, (file, cStringIO.OutputType,)):
412 elif isinstance(content, (file, cStringIO.OutputType,)):
411 content = content.read()
413 content = content.read()
412 else:
414 else:
413 raise Exception('Content is of unrecognized type %s' % (
415 raise Exception('Content is of unrecognized type %s' % (
414 type(content)
416 type(content)
415 ))
417 ))
416
418
417 message = safe_unicode(message)
419 message = safe_unicode(message)
418 author = safe_unicode(author)
420 author = safe_unicode(author)
419 path = safe_str(f_path)
421 path = safe_str(f_path)
420 m = IMC(repo)
422 m = IMC(repo)
421
423
422 if isinstance(cs, EmptyChangeset):
424 if isinstance(cs, EmptyChangeset):
423 # EmptyChangeset means we we're editing empty repository
425 # EmptyChangeset means we we're editing empty repository
424 parents = None
426 parents = None
425 else:
427 else:
426 parents = [cs]
428 parents = [cs]
427
429
428 m.add(FileNode(path, content=content))
430 m.add(FileNode(path, content=content))
429 tip = m.commit(message=message,
431 tip = m.commit(message=message,
430 author=author,
432 author=author,
431 parents=parents, branch=cs.branch)
433 parents=parents, branch=cs.branch)
432 new_cs = tip.short_id
434 new_cs = tip.short_id
433 action = 'push_local:%s' % new_cs
435 action = 'push_local:%s' % new_cs
434
436
435 action_logger(user, action, repo_name)
437 action_logger(user, action, repo_name)
436
438
437 self.mark_for_invalidation(repo_name)
439 self.mark_for_invalidation(repo_name)
438
440
439 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
441 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
440 """
442 """
441 recursive walk in root dir and return a set of all path in that dir
443 recursive walk in root dir and return a set of all path in that dir
442 based on repository walk function
444 based on repository walk function
443
445
444 :param repo_name: name of repository
446 :param repo_name: name of repository
445 :param revision: revision for which to list nodes
447 :param revision: revision for which to list nodes
446 :param root_path: root path to list
448 :param root_path: root path to list
447 :param flat: return as a list, if False returns a dict with decription
449 :param flat: return as a list, if False returns a dict with decription
448
450
449 """
451 """
450 _files = list()
452 _files = list()
451 _dirs = list()
453 _dirs = list()
452 try:
454 try:
453 _repo = self.__get_repo(repo_name)
455 _repo = self.__get_repo(repo_name)
454 changeset = _repo.scm_instance.get_changeset(revision)
456 changeset = _repo.scm_instance.get_changeset(revision)
455 root_path = root_path.lstrip('/')
457 root_path = root_path.lstrip('/')
456 for topnode, dirs, files in changeset.walk(root_path):
458 for topnode, dirs, files in changeset.walk(root_path):
457 for f in files:
459 for f in files:
458 _files.append(f.path if flat else {"name": f.path,
460 _files.append(f.path if flat else {"name": f.path,
459 "type": "file"})
461 "type": "file"})
460 for d in dirs:
462 for d in dirs:
461 _dirs.append(d.path if flat else {"name": d.path,
463 _dirs.append(d.path if flat else {"name": d.path,
462 "type": "dir"})
464 "type": "dir"})
463 except RepositoryError:
465 except RepositoryError:
464 log.debug(traceback.format_exc())
466 log.debug(traceback.format_exc())
465 raise
467 raise
466
468
467 return _dirs, _files
469 return _dirs, _files
468
470
469 def get_unread_journal(self):
471 def get_unread_journal(self):
470 return self.sa.query(UserLog).count()
472 return self.sa.query(UserLog).count()
General Comments 0
You need to be logged in to leave comments. Login now