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