##// END OF EJS Templates
fixed raw_changeset for git, accidentally it was generated with hg patch headers...
marcink -
r2083:60115135 beta
parent child Browse files
Show More
@@ -1,367 +1,373 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.changeset
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 changeset controller for pylons showoing changes beetween
7 7 revisions
8 8
9 9 :created_on: Apr 25, 2010
10 10 :author: marcink
11 11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26 import logging
27 27 import traceback
28 28 from collections import defaultdict
29 29 from webob.exc import HTTPForbidden
30 30
31 31 from pylons import tmpl_context as c, url, request, response
32 32 from pylons.i18n.translation import _
33 33 from pylons.controllers.util import redirect
34 34 from pylons.decorators import jsonify
35 35
36 36 from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetError, \
37 37 ChangesetDoesNotExistError
38 38 from rhodecode.lib.vcs.nodes import FileNode
39 39
40 40 import rhodecode.lib.helpers as h
41 41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 42 from rhodecode.lib.base import BaseRepoController, render
43 43 from rhodecode.lib.utils import EmptyChangeset
44 44 from rhodecode.lib.compat import OrderedDict
45 45 from rhodecode.lib import diffs
46 46 from rhodecode.model.db import ChangesetComment
47 47 from rhodecode.model.comment import ChangesetCommentsModel
48 48 from rhodecode.model.meta import Session
49 49 from rhodecode.lib.diffs import wrapped_diff
50 50
51 51 log = logging.getLogger(__name__)
52 52
53 53
54 54 def anchor_url(revision, path):
55 55 fid = h.FID(revision, path)
56 56 return h.url.current(anchor=fid, **dict(request.GET))
57 57
58 58
59 59 def get_ignore_ws(fid, GET):
60 60 ig_ws_global = request.GET.get('ignorews')
61 61 ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
62 62 if ig_ws:
63 63 try:
64 64 return int(ig_ws[0].split(':')[-1])
65 65 except:
66 66 pass
67 67 return ig_ws_global
68 68
69 69
70 70 def _ignorews_url(fileid=None):
71 71
72 72 params = defaultdict(list)
73 73 lbl = _('show white space')
74 74 ig_ws = get_ignore_ws(fileid, request.GET)
75 75 ln_ctx = get_line_ctx(fileid, request.GET)
76 76 # global option
77 77 if fileid is None:
78 78 if ig_ws is None:
79 79 params['ignorews'] += [1]
80 80 lbl = _('ignore white space')
81 81 ctx_key = 'context'
82 82 ctx_val = ln_ctx
83 83 # per file options
84 84 else:
85 85 if ig_ws is None:
86 86 params[fileid] += ['WS:1']
87 87 lbl = _('ignore white space')
88 88
89 89 ctx_key = fileid
90 90 ctx_val = 'C:%s' % ln_ctx
91 91 # if we have passed in ln_ctx pass it along to our params
92 92 if ln_ctx:
93 93 params[ctx_key] += [ctx_val]
94 94
95 95 params['anchor'] = fileid
96 96 img = h.image(h.url('/images/icons/text_strikethrough.png'), lbl, class_='icon')
97 97 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
98 98
99 99
100 100 def get_line_ctx(fid, GET):
101 101 ln_ctx_global = request.GET.get('context')
102 102 ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
103 103
104 104 if ln_ctx:
105 105 retval = ln_ctx[0].split(':')[-1]
106 106 else:
107 107 retval = ln_ctx_global
108 108
109 109 try:
110 110 return int(retval)
111 111 except:
112 112 return
113 113
114 114
115 115 def _context_url(fileid=None):
116 116 """
117 117 Generates url for context lines
118 118
119 119 :param fileid:
120 120 """
121 121 ig_ws = get_ignore_ws(fileid, request.GET)
122 122 ln_ctx = (get_line_ctx(fileid, request.GET) or 3) * 2
123 123
124 124 params = defaultdict(list)
125 125
126 126 # global option
127 127 if fileid is None:
128 128 if ln_ctx > 0:
129 129 params['context'] += [ln_ctx]
130 130
131 131 if ig_ws:
132 132 ig_ws_key = 'ignorews'
133 133 ig_ws_val = 1
134 134
135 135 # per file option
136 136 else:
137 137 params[fileid] += ['C:%s' % ln_ctx]
138 138 ig_ws_key = fileid
139 139 ig_ws_val = 'WS:%s' % 1
140 140
141 141 if ig_ws:
142 142 params[ig_ws_key] += [ig_ws_val]
143 143
144 144 lbl = _('%s line context') % ln_ctx
145 145
146 146 params['anchor'] = fileid
147 147 img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
148 148 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
149 149
150 150
151 151 class ChangesetController(BaseRepoController):
152 152
153 153 @LoginRequired()
154 154 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
155 155 'repository.admin')
156 156 def __before__(self):
157 157 super(ChangesetController, self).__before__()
158 158 c.affected_files_cut_off = 60
159 159
160 160 def index(self, revision):
161 161
162 162 c.anchor_url = anchor_url
163 163 c.ignorews_url = _ignorews_url
164 164 c.context_url = _context_url
165 165
166 166 #get ranges of revisions if preset
167 167 rev_range = revision.split('...')[:2]
168 168 enable_comments = True
169 169 try:
170 170 if len(rev_range) == 2:
171 171 enable_comments = False
172 172 rev_start = rev_range[0]
173 173 rev_end = rev_range[1]
174 174 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
175 175 end=rev_end)
176 176 else:
177 177 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
178 178
179 179 c.cs_ranges = list(rev_ranges)
180 180 if not c.cs_ranges:
181 181 raise RepositoryError('Changeset range returned empty result')
182 182
183 183 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
184 184 log.error(traceback.format_exc())
185 185 h.flash(str(e), category='warning')
186 186 return redirect(url('home'))
187 187
188 188 c.changes = OrderedDict()
189 189
190 190 c.lines_added = 0 # count of lines added
191 191 c.lines_deleted = 0 # count of lines removes
192 192
193 193 cumulative_diff = 0
194 194 c.cut_off = False # defines if cut off limit is reached
195 195
196 196 c.comments = []
197 197 c.inline_comments = []
198 198 c.inline_cnt = 0
199 199 # Iterate over ranges (default changeset view is always one changeset)
200 200 for changeset in c.cs_ranges:
201 201 c.comments.extend(ChangesetCommentsModel()\
202 202 .get_comments(c.rhodecode_db_repo.repo_id,
203 203 changeset.raw_id))
204 204 inlines = ChangesetCommentsModel()\
205 205 .get_inline_comments(c.rhodecode_db_repo.repo_id,
206 206 changeset.raw_id)
207 207 c.inline_comments.extend(inlines)
208 208 c.changes[changeset.raw_id] = []
209 209 try:
210 210 changeset_parent = changeset.parents[0]
211 211 except IndexError:
212 212 changeset_parent = None
213 213
214 214 #==================================================================
215 215 # ADDED FILES
216 216 #==================================================================
217 217 for node in changeset.added:
218 218 fid = h.FID(revision, node.path)
219 219 line_context_lcl = get_line_ctx(fid, request.GET)
220 220 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
221 221 lim = self.cut_off_limit
222 222 if cumulative_diff > self.cut_off_limit:
223 223 lim = -1
224 size, cs1, cs2, diff, st = wrapped_diff(filenode_old=None,
225 filenode_new=node,
226 cut_off_limit=lim,
227 ignore_whitespace=ign_whitespace_lcl,
228 line_context=line_context_lcl,
229 enable_comments=enable_comments)
224 size, cs1, cs2, diff, st = wrapped_diff(
225 filenode_old=None,
226 filenode_new=node,
227 cut_off_limit=lim,
228 ignore_whitespace=ign_whitespace_lcl,
229 line_context=line_context_lcl,
230 enable_comments=enable_comments
231 )
230 232 cumulative_diff += size
231 233 c.lines_added += st[0]
232 234 c.lines_deleted += st[1]
233 c.changes[changeset.raw_id].append(('added', node, diff,
234 cs1, cs2, st))
235 c.changes[changeset.raw_id].append(
236 ('added', node, diff, cs1, cs2, st)
237 )
235 238
236 239 #==================================================================
237 240 # CHANGED FILES
238 241 #==================================================================
239 242 for node in changeset.changed:
240 243 try:
241 244 filenode_old = changeset_parent.get_node(node.path)
242 245 except ChangesetError:
243 246 log.warning('Unable to fetch parent node for diff')
244 247 filenode_old = FileNode(node.path, '', EmptyChangeset())
245 248
246 249 fid = h.FID(revision, node.path)
247 250 line_context_lcl = get_line_ctx(fid, request.GET)
248 251 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
249 252 lim = self.cut_off_limit
250 253 if cumulative_diff > self.cut_off_limit:
251 254 lim = -1
252 size, cs1, cs2, diff, st = wrapped_diff(filenode_old=filenode_old,
253 filenode_new=node,
254 cut_off_limit=lim,
255 ignore_whitespace=ign_whitespace_lcl,
256 line_context=line_context_lcl,
257 enable_comments=enable_comments)
255 size, cs1, cs2, diff, st = wrapped_diff(
256 filenode_old=filenode_old,
257 filenode_new=node,
258 cut_off_limit=lim,
259 ignore_whitespace=ign_whitespace_lcl,
260 line_context=line_context_lcl,
261 enable_comments=enable_comments
262 )
258 263 cumulative_diff += size
259 264 c.lines_added += st[0]
260 265 c.lines_deleted += st[1]
261 c.changes[changeset.raw_id].append(('changed', node, diff,
262 cs1, cs2, st))
263
266 c.changes[changeset.raw_id].append(
267 ('changed', node, diff, cs1, cs2, st)
268 )
264 269 #==================================================================
265 270 # REMOVED FILES
266 271 #==================================================================
267 272 for node in changeset.removed:
268 c.changes[changeset.raw_id].append(('removed', node, None,
269 None, None, (0, 0)))
273 c.changes[changeset.raw_id].append(
274 ('removed', node, None, None, None, (0, 0))
275 )
270 276
271 277 # count inline comments
272 278 for path, lines in c.inline_comments:
273 279 for comments in lines.values():
274 280 c.inline_cnt += len(comments)
275 281
276 282 if len(c.cs_ranges) == 1:
277 283 c.changeset = c.cs_ranges[0]
278 284 c.changes = c.changes[c.changeset.raw_id]
279 285
280 286 return render('changeset/changeset.html')
281 287 else:
282 288 return render('changeset/changeset_range.html')
283 289
284 290 def raw_changeset(self, revision):
285 291
286 292 method = request.GET.get('diff', 'show')
287 293 ignore_whitespace = request.GET.get('ignorews') == '1'
288 294 line_context = request.GET.get('context', 3)
289 295 try:
290 296 c.scm_type = c.rhodecode_repo.alias
291 297 c.changeset = c.rhodecode_repo.get_changeset(revision)
292 298 except RepositoryError:
293 299 log.error(traceback.format_exc())
294 300 return redirect(url('home'))
295 301 else:
296 302 try:
297 303 c.changeset_parent = c.changeset.parents[0]
298 304 except IndexError:
299 305 c.changeset_parent = None
300 306 c.changes = []
301 307
302 308 for node in c.changeset.added:
303 309 filenode_old = FileNode(node.path, '')
304 310 if filenode_old.is_binary or node.is_binary:
305 311 diff = _('binary file') + '\n'
306 312 else:
307 313 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
308 314 ignore_whitespace=ignore_whitespace,
309 315 context=line_context)
310 316 diff = diffs.DiffProcessor(f_gitdiff,
311 317 format='gitdiff').raw_diff()
312 318
313 319 cs1 = None
314 320 cs2 = node.last_changeset.raw_id
315 321 c.changes.append(('added', node, diff, cs1, cs2))
316 322
317 323 for node in c.changeset.changed:
318 324 filenode_old = c.changeset_parent.get_node(node.path)
319 325 if filenode_old.is_binary or node.is_binary:
320 326 diff = _('binary file')
321 327 else:
322 328 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
323 329 ignore_whitespace=ignore_whitespace,
324 330 context=line_context)
325 331 diff = diffs.DiffProcessor(f_gitdiff,
326 332 format='gitdiff').raw_diff()
327 333
328 334 cs1 = filenode_old.last_changeset.raw_id
329 335 cs2 = node.last_changeset.raw_id
330 336 c.changes.append(('changed', node, diff, cs1, cs2))
331 337
332 338 response.content_type = 'text/plain'
333 339
334 340 if method == 'download':
335 341 response.content_disposition = 'attachment; filename=%s.patch' \
336 342 % revision
337 343
338 c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id for x in
339 c.changeset.parents])
344 c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id
345 for x in c.changeset.parents])
340 346
341 347 c.diffs = ''
342 348 for x in c.changes:
343 349 c.diffs += x[2]
344 350
345 351 return render('changeset/raw_changeset.html')
346 352
347 353 def comment(self, repo_name, revision):
348 354 ChangesetCommentsModel().create(text=request.POST.get('text'),
349 355 repo_id=c.rhodecode_db_repo.repo_id,
350 356 user_id=c.rhodecode_user.user_id,
351 357 revision=revision,
352 358 f_path=request.POST.get('f_path'),
353 359 line_no=request.POST.get('line'))
354 360 Session.commit()
355 361 return redirect(h.url('changeset_home', repo_name=repo_name,
356 362 revision=revision))
357 363
358 364 @jsonify
359 365 def delete_comment(self, repo_name, comment_id):
360 366 co = ChangesetComment.get(comment_id)
361 367 owner = lambda: co.author.user_id == c.rhodecode_user.user_id
362 368 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
363 369 ChangesetCommentsModel().delete(comment=co)
364 370 Session.commit()
365 371 return True
366 372 else:
367 373 raise HTTPForbidden()
@@ -1,493 +1,494 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.files
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Files controller for RhodeCode
7 7
8 8 :created_on: Apr 21, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import traceback
29 29
30 30 from pylons import request, response, tmpl_context as c, url
31 31 from pylons.i18n.translation import _
32 32 from pylons.controllers.util import redirect
33 33 from pylons.decorators import jsonify
34 34
35 35 from rhodecode.lib.vcs.conf import settings
36 36 from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
37 37 EmptyRepositoryError, ImproperArchiveTypeError, VCSError, \
38 38 NodeAlreadyExistsError
39 39 from rhodecode.lib.vcs.nodes import FileNode
40 40
41 41 from rhodecode.lib.compat import OrderedDict
42 42 from rhodecode.lib import convert_line_endings, detect_mode, safe_str
43 43 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
44 44 from rhodecode.lib.base import BaseRepoController, render
45 45 from rhodecode.lib.utils import EmptyChangeset
46 46 from rhodecode.lib import diffs
47 47 import rhodecode.lib.helpers as h
48 48 from rhodecode.model.repo import RepoModel
49 49 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
50 50 _context_url, get_line_ctx, get_ignore_ws
51 51 from rhodecode.lib.diffs import wrapped_diff
52 52 from rhodecode.model.scm import ScmModel
53 53
54 54 log = logging.getLogger(__name__)
55 55
56 56
57 57 class FilesController(BaseRepoController):
58 58
59 59 @LoginRequired()
60 60 def __before__(self):
61 61 super(FilesController, self).__before__()
62 62 c.cut_off_limit = self.cut_off_limit
63 63
64 64 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
65 65 """
66 66 Safe way to get changeset if error occur it redirects to tip with
67 67 proper message
68 68
69 69 :param rev: revision to fetch
70 70 :param repo_name: repo name to redirect after
71 71 """
72 72
73 73 try:
74 74 return c.rhodecode_repo.get_changeset(rev)
75 75 except EmptyRepositoryError, e:
76 76 if not redirect_after:
77 77 return None
78 78 url_ = url('files_add_home',
79 79 repo_name=c.repo_name,
80 80 revision=0, f_path='')
81 81 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
82 82 h.flash(h.literal(_('There are no files yet %s' % add_new)),
83 83 category='warning')
84 84 redirect(h.url('summary_home', repo_name=repo_name))
85 85
86 86 except RepositoryError, e:
87 87 h.flash(str(e), category='warning')
88 88 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
89 89
90 90 def __get_filenode_or_redirect(self, repo_name, cs, path):
91 91 """
92 92 Returns file_node, if error occurs or given path is directory,
93 93 it'll redirect to top level path
94 94
95 95 :param repo_name: repo_name
96 96 :param cs: given changeset
97 97 :param path: path to lookup
98 98 """
99 99
100 100 try:
101 101 file_node = cs.get_node(path)
102 102 if file_node.is_dir():
103 103 raise RepositoryError('given path is a directory')
104 104 except RepositoryError, e:
105 105 h.flash(str(e), category='warning')
106 106 redirect(h.url('files_home', repo_name=repo_name,
107 107 revision=cs.raw_id))
108 108
109 109 return file_node
110 110
111 111 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
112 112 'repository.admin')
113 113 def index(self, repo_name, revision, f_path):
114 114 # redirect to given revision from form if given
115 115 post_revision = request.POST.get('at_rev', None)
116 116 if post_revision:
117 117 cs = self.__get_cs_or_redirect(post_revision, repo_name)
118 118 redirect(url('files_home', repo_name=c.repo_name,
119 119 revision=cs.raw_id, f_path=f_path))
120 120
121 121 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
122 122 c.branch = request.GET.get('branch', None)
123 123 c.f_path = f_path
124 124
125 125 cur_rev = c.changeset.revision
126 126
127 127 # prev link
128 128 try:
129 129 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
130 130 c.url_prev = url('files_home', repo_name=c.repo_name,
131 131 revision=prev_rev.raw_id, f_path=f_path)
132 132 if c.branch:
133 133 c.url_prev += '?branch=%s' % c.branch
134 134 except (ChangesetDoesNotExistError, VCSError):
135 135 c.url_prev = '#'
136 136
137 137 # next link
138 138 try:
139 139 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
140 140 c.url_next = url('files_home', repo_name=c.repo_name,
141 141 revision=next_rev.raw_id, f_path=f_path)
142 142 if c.branch:
143 143 c.url_next += '?branch=%s' % c.branch
144 144 except (ChangesetDoesNotExistError, VCSError):
145 145 c.url_next = '#'
146 146
147 147 # files or dirs
148 148 try:
149 149 c.file = c.changeset.get_node(f_path)
150 150
151 151 if c.file.is_file():
152 152 c.file_history = self._get_node_history(c.changeset, f_path)
153 153 else:
154 154 c.file_history = []
155 155 except RepositoryError, e:
156 156 h.flash(str(e), category='warning')
157 157 redirect(h.url('files_home', repo_name=repo_name,
158 158 revision=revision))
159 159
160 160 return render('files/files.html')
161 161
162 162 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
163 163 'repository.admin')
164 164 def rawfile(self, repo_name, revision, f_path):
165 165 cs = self.__get_cs_or_redirect(revision, repo_name)
166 166 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
167 167
168 168 response.content_disposition = 'attachment; filename=%s' % \
169 169 safe_str(f_path.split(os.sep)[-1])
170 170
171 171 response.content_type = file_node.mimetype
172 172 return file_node.content
173 173
174 174 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
175 175 'repository.admin')
176 176 def raw(self, repo_name, revision, f_path):
177 177 cs = self.__get_cs_or_redirect(revision, repo_name)
178 178 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
179 179
180 180 raw_mimetype_mapping = {
181 181 # map original mimetype to a mimetype used for "show as raw"
182 182 # you can also provide a content-disposition to override the
183 183 # default "attachment" disposition.
184 184 # orig_type: (new_type, new_dispo)
185 185
186 186 # show images inline:
187 187 'image/x-icon': ('image/x-icon', 'inline'),
188 188 'image/png': ('image/png', 'inline'),
189 189 'image/gif': ('image/gif', 'inline'),
190 190 'image/jpeg': ('image/jpeg', 'inline'),
191 191 'image/svg+xml': ('image/svg+xml', 'inline'),
192 192 }
193 193
194 194 mimetype = file_node.mimetype
195 195 try:
196 196 mimetype, dispo = raw_mimetype_mapping[mimetype]
197 197 except KeyError:
198 198 # we don't know anything special about this, handle it safely
199 199 if file_node.is_binary:
200 200 # do same as download raw for binary files
201 201 mimetype, dispo = 'application/octet-stream', 'attachment'
202 202 else:
203 203 # do not just use the original mimetype, but force text/plain,
204 204 # otherwise it would serve text/html and that might be unsafe.
205 205 # Note: underlying vcs library fakes text/plain mimetype if the
206 206 # mimetype can not be determined and it thinks it is not
207 207 # binary.This might lead to erroneous text display in some
208 208 # cases, but helps in other cases, like with text files
209 209 # without extension.
210 210 mimetype, dispo = 'text/plain', 'inline'
211 211
212 212 if dispo == 'attachment':
213 213 dispo = 'attachment; filename=%s' % \
214 214 safe_str(f_path.split(os.sep)[-1])
215 215
216 216 response.content_disposition = dispo
217 217 response.content_type = mimetype
218 218 return file_node.content
219 219
220 220 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
221 221 'repository.admin')
222 222 def annotate(self, repo_name, revision, f_path):
223 223 c.cs = self.__get_cs_or_redirect(revision, repo_name)
224 224 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
225 225
226 226 c.file_history = self._get_node_history(c.cs, f_path)
227 227 c.f_path = f_path
228 228 return render('files/files_annotate.html')
229 229
230 230 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
231 231 def edit(self, repo_name, revision, f_path):
232 232 r_post = request.POST
233 233
234 234 c.cs = self.__get_cs_or_redirect(revision, repo_name)
235 235 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
236 236
237 237 if c.file.is_binary:
238 238 return redirect(url('files_home', repo_name=c.repo_name,
239 239 revision=c.cs.raw_id, f_path=f_path))
240 240
241 241 c.f_path = f_path
242 242
243 243 if r_post:
244 244
245 245 old_content = c.file.content
246 246 sl = old_content.splitlines(1)
247 247 first_line = sl[0] if sl else ''
248 248 # modes: 0 - Unix, 1 - Mac, 2 - DOS
249 249 mode = detect_mode(first_line, 0)
250 250 content = convert_line_endings(r_post.get('content'), mode)
251 251
252 252 message = r_post.get('message') or (_('Edited %s via RhodeCode')
253 253 % (f_path))
254 254 author = self.rhodecode_user.full_contact
255 255
256 256 if content == old_content:
257 257 h.flash(_('No changes'),
258 258 category='warning')
259 259 return redirect(url('changeset_home', repo_name=c.repo_name,
260 260 revision='tip'))
261 261
262 262 try:
263 263 self.scm_model.commit_change(repo=c.rhodecode_repo,
264 264 repo_name=repo_name, cs=c.cs,
265 265 user=self.rhodecode_user,
266 266 author=author, message=message,
267 267 content=content, f_path=f_path)
268 268 h.flash(_('Successfully committed to %s' % f_path),
269 269 category='success')
270 270
271 271 except Exception:
272 272 log.error(traceback.format_exc())
273 273 h.flash(_('Error occurred during commit'), category='error')
274 274 return redirect(url('changeset_home',
275 275 repo_name=c.repo_name, revision='tip'))
276 276
277 277 return render('files/files_edit.html')
278 278
279 279 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
280 280 def add(self, repo_name, revision, f_path):
281 281 r_post = request.POST
282 282 c.cs = self.__get_cs_or_redirect(revision, repo_name,
283 283 redirect_after=False)
284 284 if c.cs is None:
285 285 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
286 286
287 287 c.f_path = f_path
288 288
289 289 if r_post:
290 290 unix_mode = 0
291 291 content = convert_line_endings(r_post.get('content'), unix_mode)
292 292
293 293 message = r_post.get('message') or (_('Added %s via RhodeCode')
294 294 % (f_path))
295 295 location = r_post.get('location')
296 296 filename = r_post.get('filename')
297 297 file_obj = r_post.get('upload_file', None)
298 298
299 299 if file_obj is not None and hasattr(file_obj, 'filename'):
300 300 filename = file_obj.filename
301 301 content = file_obj.file
302 302
303 303 node_path = os.path.join(location, filename)
304 304 author = self.rhodecode_user.full_contact
305 305
306 306 if not content:
307 307 h.flash(_('No content'), category='warning')
308 308 return redirect(url('changeset_home', repo_name=c.repo_name,
309 309 revision='tip'))
310 310 if not filename:
311 311 h.flash(_('No filename'), category='warning')
312 312 return redirect(url('changeset_home', repo_name=c.repo_name,
313 313 revision='tip'))
314 314
315 315 try:
316 316 self.scm_model.create_node(repo=c.rhodecode_repo,
317 317 repo_name=repo_name, cs=c.cs,
318 318 user=self.rhodecode_user,
319 319 author=author, message=message,
320 320 content=content, f_path=node_path)
321 321 h.flash(_('Successfully committed to %s' % node_path),
322 322 category='success')
323 323 except NodeAlreadyExistsError, e:
324 324 h.flash(_(e), category='error')
325 325 except Exception:
326 326 log.error(traceback.format_exc())
327 327 h.flash(_('Error occurred during commit'), category='error')
328 328 return redirect(url('changeset_home',
329 329 repo_name=c.repo_name, revision='tip'))
330 330
331 331 return render('files/files_add.html')
332 332
333 333 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
334 334 'repository.admin')
335 335 def archivefile(self, repo_name, fname):
336 336
337 337 fileformat = None
338 338 revision = None
339 339 ext = None
340 340 subrepos = request.GET.get('subrepos') == 'true'
341 341
342 342 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
343 343 archive_spec = fname.split(ext_data[1])
344 344 if len(archive_spec) == 2 and archive_spec[1] == '':
345 345 fileformat = a_type or ext_data[1]
346 346 revision = archive_spec[0]
347 347 ext = ext_data[1]
348 348
349 349 try:
350 350 dbrepo = RepoModel().get_by_repo_name(repo_name)
351 351 if dbrepo.enable_downloads is False:
352 352 return _('downloads disabled')
353 353
354 354 if c.rhodecode_repo.alias == 'hg':
355 355 # patch and reset hooks section of UI config to not run any
356 356 # hooks on fetching archives with subrepos
357 357 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
358 358 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
359 359
360 360 cs = c.rhodecode_repo.get_changeset(revision)
361 361 content_type = settings.ARCHIVE_SPECS[fileformat][0]
362 362 except ChangesetDoesNotExistError:
363 363 return _('Unknown revision %s') % revision
364 364 except EmptyRepositoryError:
365 365 return _('Empty repository')
366 366 except (ImproperArchiveTypeError, KeyError):
367 367 return _('Unknown archive type')
368 368
369 369 response.content_type = content_type
370 370 response.content_disposition = 'attachment; filename=%s-%s%s' \
371 371 % (repo_name, revision, ext)
372 372
373 373 import tempfile
374 374 archive = tempfile.mkstemp()[1]
375 375 t = open(archive, 'wb')
376 376 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
377 377
378 378 def get_chunked_archive(archive):
379 379 stream = open(archive, 'rb')
380 380 while True:
381 381 data = stream.read(4096)
382 382 if not data:
383 383 os.remove(archive)
384 384 break
385 385 yield data
386 386
387 387 return get_chunked_archive(archive)
388 388
389 389 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
390 390 'repository.admin')
391 391 def diff(self, repo_name, f_path):
392 392 ignore_whitespace = request.GET.get('ignorews') == '1'
393 393 line_context = request.GET.get('context', 3)
394 394 diff1 = request.GET.get('diff1', '')
395 395 diff2 = request.GET.get('diff2', '')
396 396 c.action = request.GET.get('diff')
397 397 c.no_changes = diff1 == diff2
398 398 c.f_path = f_path
399 399 c.big_diff = False
400 400 c.anchor_url = anchor_url
401 401 c.ignorews_url = _ignorews_url
402 402 c.context_url = _context_url
403 403 c.changes = OrderedDict()
404 404 c.changes[diff2] = []
405 405 try:
406 406 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
407 407 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
408 408 node1 = c.changeset_1.get_node(f_path)
409 409 else:
410 410 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
411 411 node1 = FileNode('.', '', changeset=c.changeset_1)
412 412
413 413 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
414 414 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
415 415 node2 = c.changeset_2.get_node(f_path)
416 416 else:
417 417 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
418 418 node2 = FileNode('.', '', changeset=c.changeset_2)
419 419 except RepositoryError:
420 420 return redirect(url('files_home', repo_name=c.repo_name,
421 421 f_path=f_path))
422 422
423 423 if c.action == 'download':
424 424 _diff = diffs.get_gitdiff(node1, node2,
425 425 ignore_whitespace=ignore_whitespace,
426 426 context=line_context)
427 427 diff = diffs.DiffProcessor(_diff, format='gitdiff')
428 428
429 429 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
430 430 response.content_type = 'text/plain'
431 response.content_disposition = 'attachment; filename=%s' \
432 % diff_name
431 response.content_disposition = (
432 'attachment; filename=%s' % diff_name
433 )
433 434 return diff.raw_diff()
434 435
435 436 elif c.action == 'raw':
436 437 _diff = diffs.get_gitdiff(node1, node2,
437 438 ignore_whitespace=ignore_whitespace,
438 439 context=line_context)
439 440 diff = diffs.DiffProcessor(_diff, format='gitdiff')
440 441 response.content_type = 'text/plain'
441 442 return diff.raw_diff()
442 443
443 444 else:
444 445 fid = h.FID(diff2, node2.path)
445 446 line_context_lcl = get_line_ctx(fid, request.GET)
446 447 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
447 448
448 449 lim = request.GET.get('fulldiff') or self.cut_off_limit
449 450 _, cs1, cs2, diff, st = wrapped_diff(filenode_old=node1,
450 451 filenode_new=node2,
451 452 cut_off_limit=lim,
452 453 ignore_whitespace=ign_whitespace_lcl,
453 454 line_context=line_context_lcl,
454 455 enable_comments=False)
455 456
456 457 c.changes = [('', node2, diff, cs1, cs2, st,)]
457 458
458 459 return render('files/file_diff.html')
459 460
460 461 def _get_node_history(self, cs, f_path):
461 462 changesets = cs.get_file_history(f_path)
462 463 hist_l = []
463 464
464 465 changesets_group = ([], _("Changesets"))
465 466 branches_group = ([], _("Branches"))
466 467 tags_group = ([], _("Tags"))
467 468 _hg = cs.repository.alias == 'hg'
468 469 for chs in changesets:
469 470 _branch = '(%s)' % chs.branch if _hg else ''
470 471 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
471 472 changesets_group[0].append((chs.raw_id, n_desc,))
472 473
473 474 hist_l.append(changesets_group)
474 475
475 476 for name, chs in c.rhodecode_repo.branches.items():
476 477 branches_group[0].append((chs, name),)
477 478 hist_l.append(branches_group)
478 479
479 480 for name, chs in c.rhodecode_repo.tags.items():
480 481 tags_group[0].append((chs, name),)
481 482 hist_l.append(tags_group)
482 483
483 484 return hist_l
484 485
485 486 @jsonify
486 487 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
487 488 'repository.admin')
488 489 def nodelist(self, repo_name, revision, f_path):
489 490 if request.environ.get('HTTP_X_PARTIAL_XHR'):
490 491 cs = self.__get_cs_or_redirect(revision, repo_name)
491 492 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
492 493 flat=False)
493 494 return _d + _f
@@ -1,8 +1,9 b''
1 %if h.is_hg(c.scm_type):
1 2 # ${c.scm_type.upper()} changeset patch
2 3 # User ${c.changeset.author|n}
3 4 # Date ${c.changeset.date}
4 5 # Node ID ${c.changeset.raw_id}
5 6 ${c.parent_tmpl}
6 7 ${c.changeset.message}
7
8 %endif
8 9 ${c.diffs|n}
General Comments 0
You need to be logged in to leave comments. Login now