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