##// END OF EJS Templates
Use paste fileapp to properly send the archive size
marcink -
r2294:3c1d9917 beta
parent child Browse files
Show More
@@ -1,487 +1,490 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.files
3 rhodecode.controllers.files
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Files controller for RhodeCode
6 Files controller for RhodeCode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import tempfile
29 import tempfile
30
30
31 from pylons import request, response, tmpl_context as c, url
31 from pylons import request, response, tmpl_context as c, url
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.decorators import jsonify
34 from pylons.decorators import jsonify
35 from paste.fileapp import FileApp, _FileIter
35
36
36 from rhodecode.lib import diffs
37 from rhodecode.lib import diffs
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
38
39
39 from rhodecode.lib.compat import OrderedDict
40 from rhodecode.lib.compat import OrderedDict
40 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
41 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.utils import EmptyChangeset
44 from rhodecode.lib.utils import EmptyChangeset
44 from rhodecode.lib.vcs.conf import settings
45 from rhodecode.lib.vcs.conf import settings
45 from rhodecode.lib.vcs.exceptions import RepositoryError, \
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
46 ChangesetDoesNotExistError, EmptyRepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
47 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
48 from rhodecode.lib.vcs.nodes import FileNode
49 from rhodecode.lib.vcs.nodes import FileNode
49
50
50 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.scm import ScmModel
52 from rhodecode.model.scm import ScmModel
52 from rhodecode.model.db import Repository
53 from rhodecode.model.db import Repository
53
54
54 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
55 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
55 _context_url, get_line_ctx, get_ignore_ws
56 _context_url, get_line_ctx, get_ignore_ws
56
57
57
58
58 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
59
60
60
61
61 class FilesController(BaseRepoController):
62 class FilesController(BaseRepoController):
62
63
63 @LoginRequired()
64 @LoginRequired()
64 def __before__(self):
65 def __before__(self):
65 super(FilesController, self).__before__()
66 super(FilesController, self).__before__()
66 c.cut_off_limit = self.cut_off_limit
67 c.cut_off_limit = self.cut_off_limit
67
68
68 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
69 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
69 """
70 """
70 Safe way to get changeset if error occur it redirects to tip with
71 Safe way to get changeset if error occur it redirects to tip with
71 proper message
72 proper message
72
73
73 :param rev: revision to fetch
74 :param rev: revision to fetch
74 :param repo_name: repo name to redirect after
75 :param repo_name: repo name to redirect after
75 """
76 """
76
77
77 try:
78 try:
78 return c.rhodecode_repo.get_changeset(rev)
79 return c.rhodecode_repo.get_changeset(rev)
79 except EmptyRepositoryError, e:
80 except EmptyRepositoryError, e:
80 if not redirect_after:
81 if not redirect_after:
81 return None
82 return None
82 url_ = url('files_add_home',
83 url_ = url('files_add_home',
83 repo_name=c.repo_name,
84 repo_name=c.repo_name,
84 revision=0, f_path='')
85 revision=0, f_path='')
85 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
86 h.flash(h.literal(_('There are no files yet %s' % add_new)),
87 h.flash(h.literal(_('There are no files yet %s' % add_new)),
87 category='warning')
88 category='warning')
88 redirect(h.url('summary_home', repo_name=repo_name))
89 redirect(h.url('summary_home', repo_name=repo_name))
89
90
90 except RepositoryError, e:
91 except RepositoryError, e:
91 h.flash(str(e), category='warning')
92 h.flash(str(e), category='warning')
92 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
93
94
94 def __get_filenode_or_redirect(self, repo_name, cs, path):
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
95 """
96 """
96 Returns file_node, if error occurs or given path is directory,
97 Returns file_node, if error occurs or given path is directory,
97 it'll redirect to top level path
98 it'll redirect to top level path
98
99
99 :param repo_name: repo_name
100 :param repo_name: repo_name
100 :param cs: given changeset
101 :param cs: given changeset
101 :param path: path to lookup
102 :param path: path to lookup
102 """
103 """
103
104
104 try:
105 try:
105 file_node = cs.get_node(path)
106 file_node = cs.get_node(path)
106 if file_node.is_dir():
107 if file_node.is_dir():
107 raise RepositoryError('given path is a directory')
108 raise RepositoryError('given path is a directory')
108 except RepositoryError, e:
109 except RepositoryError, e:
109 h.flash(str(e), category='warning')
110 h.flash(str(e), category='warning')
110 redirect(h.url('files_home', repo_name=repo_name,
111 redirect(h.url('files_home', repo_name=repo_name,
111 revision=cs.raw_id))
112 revision=cs.raw_id))
112
113
113 return file_node
114 return file_node
114
115
115 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
116 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
116 'repository.admin')
117 'repository.admin')
117 def index(self, repo_name, revision, f_path, annotate=False):
118 def index(self, repo_name, revision, f_path, annotate=False):
118 # redirect to given revision from form if given
119 # redirect to given revision from form if given
119 post_revision = request.POST.get('at_rev', None)
120 post_revision = request.POST.get('at_rev', None)
120 if post_revision:
121 if post_revision:
121 cs = self.__get_cs_or_redirect(post_revision, repo_name)
122 cs = self.__get_cs_or_redirect(post_revision, repo_name)
122 redirect(url('files_home', repo_name=c.repo_name,
123 redirect(url('files_home', repo_name=c.repo_name,
123 revision=cs.raw_id, f_path=f_path))
124 revision=cs.raw_id, f_path=f_path))
124
125
125 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
126 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
126 c.branch = request.GET.get('branch', None)
127 c.branch = request.GET.get('branch', None)
127 c.f_path = f_path
128 c.f_path = f_path
128 c.annotate = annotate
129 c.annotate = annotate
129 cur_rev = c.changeset.revision
130 cur_rev = c.changeset.revision
130
131
131 # prev link
132 # prev link
132 try:
133 try:
133 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
134 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
134 c.url_prev = url('files_home', repo_name=c.repo_name,
135 c.url_prev = url('files_home', repo_name=c.repo_name,
135 revision=prev_rev.raw_id, f_path=f_path)
136 revision=prev_rev.raw_id, f_path=f_path)
136 if c.branch:
137 if c.branch:
137 c.url_prev += '?branch=%s' % c.branch
138 c.url_prev += '?branch=%s' % c.branch
138 except (ChangesetDoesNotExistError, VCSError):
139 except (ChangesetDoesNotExistError, VCSError):
139 c.url_prev = '#'
140 c.url_prev = '#'
140
141
141 # next link
142 # next link
142 try:
143 try:
143 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
144 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
144 c.url_next = url('files_home', repo_name=c.repo_name,
145 c.url_next = url('files_home', repo_name=c.repo_name,
145 revision=next_rev.raw_id, f_path=f_path)
146 revision=next_rev.raw_id, f_path=f_path)
146 if c.branch:
147 if c.branch:
147 c.url_next += '?branch=%s' % c.branch
148 c.url_next += '?branch=%s' % c.branch
148 except (ChangesetDoesNotExistError, VCSError):
149 except (ChangesetDoesNotExistError, VCSError):
149 c.url_next = '#'
150 c.url_next = '#'
150
151
151 # files or dirs
152 # files or dirs
152 try:
153 try:
153 c.file = c.changeset.get_node(f_path)
154 c.file = c.changeset.get_node(f_path)
154
155
155 if c.file.is_file():
156 if c.file.is_file():
156 c.file_history = self._get_node_history(c.changeset, f_path)
157 c.file_history = self._get_node_history(c.changeset, f_path)
157 else:
158 else:
158 c.file_history = []
159 c.file_history = []
159 except RepositoryError, e:
160 except RepositoryError, e:
160 h.flash(str(e), category='warning')
161 h.flash(str(e), category='warning')
161 redirect(h.url('files_home', repo_name=repo_name,
162 redirect(h.url('files_home', repo_name=repo_name,
162 revision=revision))
163 revision=revision))
163
164
164 return render('files/files.html')
165 return render('files/files.html')
165
166
166 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
167 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
167 'repository.admin')
168 'repository.admin')
168 def rawfile(self, repo_name, revision, f_path):
169 def rawfile(self, repo_name, revision, f_path):
169 cs = self.__get_cs_or_redirect(revision, repo_name)
170 cs = self.__get_cs_or_redirect(revision, repo_name)
170 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
171 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
171
172
172 response.content_disposition = 'attachment; filename=%s' % \
173 response.content_disposition = 'attachment; filename=%s' % \
173 safe_str(f_path.split(Repository.url_sep())[-1])
174 safe_str(f_path.split(Repository.url_sep())[-1])
174
175
175 response.content_type = file_node.mimetype
176 response.content_type = file_node.mimetype
176 return file_node.content
177 return file_node.content
177
178
178 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
179 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
179 'repository.admin')
180 'repository.admin')
180 def raw(self, repo_name, revision, f_path):
181 def raw(self, repo_name, revision, f_path):
181 cs = self.__get_cs_or_redirect(revision, repo_name)
182 cs = self.__get_cs_or_redirect(revision, repo_name)
182 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
183 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
183
184
184 raw_mimetype_mapping = {
185 raw_mimetype_mapping = {
185 # map original mimetype to a mimetype used for "show as raw"
186 # map original mimetype to a mimetype used for "show as raw"
186 # you can also provide a content-disposition to override the
187 # you can also provide a content-disposition to override the
187 # default "attachment" disposition.
188 # default "attachment" disposition.
188 # orig_type: (new_type, new_dispo)
189 # orig_type: (new_type, new_dispo)
189
190
190 # show images inline:
191 # show images inline:
191 'image/x-icon': ('image/x-icon', 'inline'),
192 'image/x-icon': ('image/x-icon', 'inline'),
192 'image/png': ('image/png', 'inline'),
193 'image/png': ('image/png', 'inline'),
193 'image/gif': ('image/gif', 'inline'),
194 'image/gif': ('image/gif', 'inline'),
194 'image/jpeg': ('image/jpeg', 'inline'),
195 'image/jpeg': ('image/jpeg', 'inline'),
195 'image/svg+xml': ('image/svg+xml', 'inline'),
196 'image/svg+xml': ('image/svg+xml', 'inline'),
196 }
197 }
197
198
198 mimetype = file_node.mimetype
199 mimetype = file_node.mimetype
199 try:
200 try:
200 mimetype, dispo = raw_mimetype_mapping[mimetype]
201 mimetype, dispo = raw_mimetype_mapping[mimetype]
201 except KeyError:
202 except KeyError:
202 # we don't know anything special about this, handle it safely
203 # we don't know anything special about this, handle it safely
203 if file_node.is_binary:
204 if file_node.is_binary:
204 # do same as download raw for binary files
205 # do same as download raw for binary files
205 mimetype, dispo = 'application/octet-stream', 'attachment'
206 mimetype, dispo = 'application/octet-stream', 'attachment'
206 else:
207 else:
207 # do not just use the original mimetype, but force text/plain,
208 # do not just use the original mimetype, but force text/plain,
208 # otherwise it would serve text/html and that might be unsafe.
209 # otherwise it would serve text/html and that might be unsafe.
209 # Note: underlying vcs library fakes text/plain mimetype if the
210 # Note: underlying vcs library fakes text/plain mimetype if the
210 # mimetype can not be determined and it thinks it is not
211 # mimetype can not be determined and it thinks it is not
211 # binary.This might lead to erroneous text display in some
212 # binary.This might lead to erroneous text display in some
212 # cases, but helps in other cases, like with text files
213 # cases, but helps in other cases, like with text files
213 # without extension.
214 # without extension.
214 mimetype, dispo = 'text/plain', 'inline'
215 mimetype, dispo = 'text/plain', 'inline'
215
216
216 if dispo == 'attachment':
217 if dispo == 'attachment':
217 dispo = 'attachment; filename=%s' % \
218 dispo = 'attachment; filename=%s' % \
218 safe_str(f_path.split(os.sep)[-1])
219 safe_str(f_path.split(os.sep)[-1])
219
220
220 response.content_disposition = dispo
221 response.content_disposition = dispo
221 response.content_type = mimetype
222 response.content_type = mimetype
222 return file_node.content
223 return file_node.content
223
224
224 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
225 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
225 def edit(self, repo_name, revision, f_path):
226 def edit(self, repo_name, revision, f_path):
226 r_post = request.POST
227 r_post = request.POST
227
228
228 c.cs = self.__get_cs_or_redirect(revision, repo_name)
229 c.cs = self.__get_cs_or_redirect(revision, repo_name)
229 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
230 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
230
231
231 if c.file.is_binary:
232 if c.file.is_binary:
232 return redirect(url('files_home', repo_name=c.repo_name,
233 return redirect(url('files_home', repo_name=c.repo_name,
233 revision=c.cs.raw_id, f_path=f_path))
234 revision=c.cs.raw_id, f_path=f_path))
234
235
235 c.f_path = f_path
236 c.f_path = f_path
236
237
237 if r_post:
238 if r_post:
238
239
239 old_content = c.file.content
240 old_content = c.file.content
240 sl = old_content.splitlines(1)
241 sl = old_content.splitlines(1)
241 first_line = sl[0] if sl else ''
242 first_line = sl[0] if sl else ''
242 # modes: 0 - Unix, 1 - Mac, 2 - DOS
243 # modes: 0 - Unix, 1 - Mac, 2 - DOS
243 mode = detect_mode(first_line, 0)
244 mode = detect_mode(first_line, 0)
244 content = convert_line_endings(r_post.get('content'), mode)
245 content = convert_line_endings(r_post.get('content'), mode)
245
246
246 message = r_post.get('message') or (_('Edited %s via RhodeCode')
247 message = r_post.get('message') or (_('Edited %s via RhodeCode')
247 % (f_path))
248 % (f_path))
248 author = self.rhodecode_user.full_contact
249 author = self.rhodecode_user.full_contact
249
250
250 if content == old_content:
251 if content == old_content:
251 h.flash(_('No changes'),
252 h.flash(_('No changes'),
252 category='warning')
253 category='warning')
253 return redirect(url('changeset_home', repo_name=c.repo_name,
254 return redirect(url('changeset_home', repo_name=c.repo_name,
254 revision='tip'))
255 revision='tip'))
255
256
256 try:
257 try:
257 self.scm_model.commit_change(repo=c.rhodecode_repo,
258 self.scm_model.commit_change(repo=c.rhodecode_repo,
258 repo_name=repo_name, cs=c.cs,
259 repo_name=repo_name, cs=c.cs,
259 user=self.rhodecode_user,
260 user=self.rhodecode_user,
260 author=author, message=message,
261 author=author, message=message,
261 content=content, f_path=f_path)
262 content=content, f_path=f_path)
262 h.flash(_('Successfully committed to %s' % f_path),
263 h.flash(_('Successfully committed to %s' % f_path),
263 category='success')
264 category='success')
264
265
265 except Exception:
266 except Exception:
266 log.error(traceback.format_exc())
267 log.error(traceback.format_exc())
267 h.flash(_('Error occurred during commit'), category='error')
268 h.flash(_('Error occurred during commit'), category='error')
268 return redirect(url('changeset_home',
269 return redirect(url('changeset_home',
269 repo_name=c.repo_name, revision='tip'))
270 repo_name=c.repo_name, revision='tip'))
270
271
271 return render('files/files_edit.html')
272 return render('files/files_edit.html')
272
273
273 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
274 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
274 def add(self, repo_name, revision, f_path):
275 def add(self, repo_name, revision, f_path):
275 r_post = request.POST
276 r_post = request.POST
276 c.cs = self.__get_cs_or_redirect(revision, repo_name,
277 c.cs = self.__get_cs_or_redirect(revision, repo_name,
277 redirect_after=False)
278 redirect_after=False)
278 if c.cs is None:
279 if c.cs is None:
279 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
280 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
280
281
281 c.f_path = f_path
282 c.f_path = f_path
282
283
283 if r_post:
284 if r_post:
284 unix_mode = 0
285 unix_mode = 0
285 content = convert_line_endings(r_post.get('content'), unix_mode)
286 content = convert_line_endings(r_post.get('content'), unix_mode)
286
287
287 message = r_post.get('message') or (_('Added %s via RhodeCode')
288 message = r_post.get('message') or (_('Added %s via RhodeCode')
288 % (f_path))
289 % (f_path))
289 location = r_post.get('location')
290 location = r_post.get('location')
290 filename = r_post.get('filename')
291 filename = r_post.get('filename')
291 file_obj = r_post.get('upload_file', None)
292 file_obj = r_post.get('upload_file', None)
292
293
293 if file_obj is not None and hasattr(file_obj, 'filename'):
294 if file_obj is not None and hasattr(file_obj, 'filename'):
294 filename = file_obj.filename
295 filename = file_obj.filename
295 content = file_obj.file
296 content = file_obj.file
296
297
297 node_path = os.path.join(location, filename)
298 node_path = os.path.join(location, filename)
298 author = self.rhodecode_user.full_contact
299 author = self.rhodecode_user.full_contact
299
300
300 if not content:
301 if not content:
301 h.flash(_('No content'), category='warning')
302 h.flash(_('No content'), category='warning')
302 return redirect(url('changeset_home', repo_name=c.repo_name,
303 return redirect(url('changeset_home', repo_name=c.repo_name,
303 revision='tip'))
304 revision='tip'))
304 if not filename:
305 if not filename:
305 h.flash(_('No filename'), category='warning')
306 h.flash(_('No filename'), category='warning')
306 return redirect(url('changeset_home', repo_name=c.repo_name,
307 return redirect(url('changeset_home', repo_name=c.repo_name,
307 revision='tip'))
308 revision='tip'))
308
309
309 try:
310 try:
310 self.scm_model.create_node(repo=c.rhodecode_repo,
311 self.scm_model.create_node(repo=c.rhodecode_repo,
311 repo_name=repo_name, cs=c.cs,
312 repo_name=repo_name, cs=c.cs,
312 user=self.rhodecode_user,
313 user=self.rhodecode_user,
313 author=author, message=message,
314 author=author, message=message,
314 content=content, f_path=node_path)
315 content=content, f_path=node_path)
315 h.flash(_('Successfully committed to %s' % node_path),
316 h.flash(_('Successfully committed to %s' % node_path),
316 category='success')
317 category='success')
317 except NodeAlreadyExistsError, e:
318 except NodeAlreadyExistsError, e:
318 h.flash(_(e), category='error')
319 h.flash(_(e), category='error')
319 except Exception:
320 except Exception:
320 log.error(traceback.format_exc())
321 log.error(traceback.format_exc())
321 h.flash(_('Error occurred during commit'), category='error')
322 h.flash(_('Error occurred during commit'), category='error')
322 return redirect(url('changeset_home',
323 return redirect(url('changeset_home',
323 repo_name=c.repo_name, revision='tip'))
324 repo_name=c.repo_name, revision='tip'))
324
325
325 return render('files/files_add.html')
326 return render('files/files_add.html')
326
327
327 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
328 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
328 'repository.admin')
329 'repository.admin')
329 def archivefile(self, repo_name, fname):
330 def archivefile(self, repo_name, fname):
330
331
331 fileformat = None
332 fileformat = None
332 revision = None
333 revision = None
333 ext = None
334 ext = None
334 subrepos = request.GET.get('subrepos') == 'true'
335 subrepos = request.GET.get('subrepos') == 'true'
335
336
336 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
337 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
337 archive_spec = fname.split(ext_data[1])
338 archive_spec = fname.split(ext_data[1])
338 if len(archive_spec) == 2 and archive_spec[1] == '':
339 if len(archive_spec) == 2 and archive_spec[1] == '':
339 fileformat = a_type or ext_data[1]
340 fileformat = a_type or ext_data[1]
340 revision = archive_spec[0]
341 revision = archive_spec[0]
341 ext = ext_data[1]
342 ext = ext_data[1]
342
343
343 try:
344 try:
344 dbrepo = RepoModel().get_by_repo_name(repo_name)
345 dbrepo = RepoModel().get_by_repo_name(repo_name)
345 if dbrepo.enable_downloads is False:
346 if dbrepo.enable_downloads is False:
346 return _('downloads disabled')
347 return _('downloads disabled')
347
348
348 if c.rhodecode_repo.alias == 'hg':
349 if c.rhodecode_repo.alias == 'hg':
349 # patch and reset hooks section of UI config to not run any
350 # patch and reset hooks section of UI config to not run any
350 # hooks on fetching archives with subrepos
351 # hooks on fetching archives with subrepos
351 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
352 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
352 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
353 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
353
354
354 cs = c.rhodecode_repo.get_changeset(revision)
355 cs = c.rhodecode_repo.get_changeset(revision)
355 content_type = settings.ARCHIVE_SPECS[fileformat][0]
356 content_type = settings.ARCHIVE_SPECS[fileformat][0]
356 except ChangesetDoesNotExistError:
357 except ChangesetDoesNotExistError:
357 return _('Unknown revision %s') % revision
358 return _('Unknown revision %s') % revision
358 except EmptyRepositoryError:
359 except EmptyRepositoryError:
359 return _('Empty repository')
360 return _('Empty repository')
360 except (ImproperArchiveTypeError, KeyError):
361 except (ImproperArchiveTypeError, KeyError):
361 return _('Unknown archive type')
362 return _('Unknown archive type')
362
363
363 fd, _archive_name = tempfile.mkstemp(suffix='rcarchive')
364 fd, _archive_name = tempfile.mkstemp(suffix='rcarchive')
364 with open(_archive_name, 'wb') as f:
365 with open(_archive_name, 'wb') as f:
365 cs.fill_archive(stream=f, kind=fileformat, subrepos=subrepos)
366 cs.fill_archive(stream=f, kind=fileformat, subrepos=subrepos)
366
367
367 response.content_type = content_type
368 content_disposition = 'attachment; filename=%s-%s%s' \
368 response.content_disposition = 'attachment; filename=%s-%s%s' \
369 % (repo_name, revision[:12], ext)
369 % (repo_name, revision[:12], ext)
370 response.content_length = str(os.path.getsize(_archive_name))
370 content_length = os.path.getsize(_archive_name)
371
372 headers = [('Content-Disposition', str(content_disposition)),
373 ('Content-Type', str(content_type)),
374 ('Content-Length', str(content_length))]
371
375
372 def get_chunked_archive(tmpfile):
376 class _DestroyingFileWrapper(_FileIter):
373 while True:
377 def close(self):
374 data = tmpfile.read(16 * 1024)
378 self.file.close
375 if not data:
379 os.remove(self.file.name)
376 tmpfile.close()
380
377 os.unlink(tmpfile.name)
381 request.environ['wsgi.file_wrapper'] = _DestroyingFileWrapper
378 break
382 fapp = FileApp(_archive_name, headers=headers)
379 yield data
383 return fapp(request.environ, self.start_response)
380 return get_chunked_archive(tmpfile=open(_archive_name, 'rb'))
381
384
382 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
385 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
383 'repository.admin')
386 'repository.admin')
384 def diff(self, repo_name, f_path):
387 def diff(self, repo_name, f_path):
385 ignore_whitespace = request.GET.get('ignorews') == '1'
388 ignore_whitespace = request.GET.get('ignorews') == '1'
386 line_context = request.GET.get('context', 3)
389 line_context = request.GET.get('context', 3)
387 diff1 = request.GET.get('diff1', '')
390 diff1 = request.GET.get('diff1', '')
388 diff2 = request.GET.get('diff2', '')
391 diff2 = request.GET.get('diff2', '')
389 c.action = request.GET.get('diff')
392 c.action = request.GET.get('diff')
390 c.no_changes = diff1 == diff2
393 c.no_changes = diff1 == diff2
391 c.f_path = f_path
394 c.f_path = f_path
392 c.big_diff = False
395 c.big_diff = False
393 c.anchor_url = anchor_url
396 c.anchor_url = anchor_url
394 c.ignorews_url = _ignorews_url
397 c.ignorews_url = _ignorews_url
395 c.context_url = _context_url
398 c.context_url = _context_url
396 c.changes = OrderedDict()
399 c.changes = OrderedDict()
397 c.changes[diff2] = []
400 c.changes[diff2] = []
398 try:
401 try:
399 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
402 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
400 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
403 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
401 node1 = c.changeset_1.get_node(f_path)
404 node1 = c.changeset_1.get_node(f_path)
402 else:
405 else:
403 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
406 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
404 node1 = FileNode('.', '', changeset=c.changeset_1)
407 node1 = FileNode('.', '', changeset=c.changeset_1)
405
408
406 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
409 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
407 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
410 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
408 node2 = c.changeset_2.get_node(f_path)
411 node2 = c.changeset_2.get_node(f_path)
409 else:
412 else:
410 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
413 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
411 node2 = FileNode('.', '', changeset=c.changeset_2)
414 node2 = FileNode('.', '', changeset=c.changeset_2)
412 except RepositoryError:
415 except RepositoryError:
413 return redirect(url('files_home', repo_name=c.repo_name,
416 return redirect(url('files_home', repo_name=c.repo_name,
414 f_path=f_path))
417 f_path=f_path))
415
418
416 if c.action == 'download':
419 if c.action == 'download':
417 _diff = diffs.get_gitdiff(node1, node2,
420 _diff = diffs.get_gitdiff(node1, node2,
418 ignore_whitespace=ignore_whitespace,
421 ignore_whitespace=ignore_whitespace,
419 context=line_context)
422 context=line_context)
420 diff = diffs.DiffProcessor(_diff, format='gitdiff')
423 diff = diffs.DiffProcessor(_diff, format='gitdiff')
421
424
422 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
425 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
423 response.content_type = 'text/plain'
426 response.content_type = 'text/plain'
424 response.content_disposition = (
427 response.content_disposition = (
425 'attachment; filename=%s' % diff_name
428 'attachment; filename=%s' % diff_name
426 )
429 )
427 return diff.raw_diff()
430 return diff.raw_diff()
428
431
429 elif c.action == 'raw':
432 elif c.action == 'raw':
430 _diff = diffs.get_gitdiff(node1, node2,
433 _diff = diffs.get_gitdiff(node1, node2,
431 ignore_whitespace=ignore_whitespace,
434 ignore_whitespace=ignore_whitespace,
432 context=line_context)
435 context=line_context)
433 diff = diffs.DiffProcessor(_diff, format='gitdiff')
436 diff = diffs.DiffProcessor(_diff, format='gitdiff')
434 response.content_type = 'text/plain'
437 response.content_type = 'text/plain'
435 return diff.raw_diff()
438 return diff.raw_diff()
436
439
437 else:
440 else:
438 fid = h.FID(diff2, node2.path)
441 fid = h.FID(diff2, node2.path)
439 line_context_lcl = get_line_ctx(fid, request.GET)
442 line_context_lcl = get_line_ctx(fid, request.GET)
440 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
443 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
441
444
442 lim = request.GET.get('fulldiff') or self.cut_off_limit
445 lim = request.GET.get('fulldiff') or self.cut_off_limit
443 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
446 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
444 filenode_new=node2,
447 filenode_new=node2,
445 cut_off_limit=lim,
448 cut_off_limit=lim,
446 ignore_whitespace=ign_whitespace_lcl,
449 ignore_whitespace=ign_whitespace_lcl,
447 line_context=line_context_lcl,
450 line_context=line_context_lcl,
448 enable_comments=False)
451 enable_comments=False)
449
452
450 c.changes = [('', node2, diff, cs1, cs2, st,)]
453 c.changes = [('', node2, diff, cs1, cs2, st,)]
451
454
452 return render('files/file_diff.html')
455 return render('files/file_diff.html')
453
456
454 def _get_node_history(self, cs, f_path):
457 def _get_node_history(self, cs, f_path):
455 changesets = cs.get_file_history(f_path)
458 changesets = cs.get_file_history(f_path)
456 hist_l = []
459 hist_l = []
457
460
458 changesets_group = ([], _("Changesets"))
461 changesets_group = ([], _("Changesets"))
459 branches_group = ([], _("Branches"))
462 branches_group = ([], _("Branches"))
460 tags_group = ([], _("Tags"))
463 tags_group = ([], _("Tags"))
461 _hg = cs.repository.alias == 'hg'
464 _hg = cs.repository.alias == 'hg'
462 for chs in changesets:
465 for chs in changesets:
463 _branch = '(%s)' % chs.branch if _hg else ''
466 _branch = '(%s)' % chs.branch if _hg else ''
464 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
467 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
465 changesets_group[0].append((chs.raw_id, n_desc,))
468 changesets_group[0].append((chs.raw_id, n_desc,))
466
469
467 hist_l.append(changesets_group)
470 hist_l.append(changesets_group)
468
471
469 for name, chs in c.rhodecode_repo.branches.items():
472 for name, chs in c.rhodecode_repo.branches.items():
470 branches_group[0].append((chs, name),)
473 branches_group[0].append((chs, name),)
471 hist_l.append(branches_group)
474 hist_l.append(branches_group)
472
475
473 for name, chs in c.rhodecode_repo.tags.items():
476 for name, chs in c.rhodecode_repo.tags.items():
474 tags_group[0].append((chs, name),)
477 tags_group[0].append((chs, name),)
475 hist_l.append(tags_group)
478 hist_l.append(tags_group)
476
479
477 return hist_l
480 return hist_l
478
481
479 @jsonify
482 @jsonify
480 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
483 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
481 'repository.admin')
484 'repository.admin')
482 def nodelist(self, repo_name, revision, f_path):
485 def nodelist(self, repo_name, revision, f_path):
483 if request.environ.get('HTTP_X_PARTIAL_XHR'):
486 if request.environ.get('HTTP_X_PARTIAL_XHR'):
484 cs = self.__get_cs_or_redirect(revision, repo_name)
487 cs = self.__get_cs_or_redirect(revision, repo_name)
485 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
488 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
486 flat=False)
489 flat=False)
487 return _d + _f
490 return _d + _f
@@ -1,318 +1,317 b''
1 from rhodecode.tests import *
1 from rhodecode.tests import *
2
2
3 ARCHIVE_SPECS = {
3 ARCHIVE_SPECS = {
4 '.tar.bz2': ('application/x-bzip2', 'tbz2', ''),
4 '.tar.bz2': ('application/x-bzip2', 'tbz2', ''),
5 '.tar.gz': ('application/x-gzip', 'tgz', ''),
5 '.tar.gz': ('application/x-gzip', 'tgz', ''),
6 '.zip': ('application/zip', 'zip', ''),
6 '.zip': ('application/zip', 'zip', ''),
7 }
7 }
8
8
9
9
10 class TestFilesController(TestController):
10 class TestFilesController(TestController):
11
11
12 def test_index(self):
12 def test_index(self):
13 self.log_user()
13 self.log_user()
14 response = self.app.get(url(controller='files', action='index',
14 response = self.app.get(url(controller='files', action='index',
15 repo_name=HG_REPO,
15 repo_name=HG_REPO,
16 revision='tip',
16 revision='tip',
17 f_path='/'))
17 f_path='/'))
18 # Test response...
18 # Test response...
19 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/docs">docs</a>')
19 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/docs">docs</a>')
20 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/tests">tests</a>')
20 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/tests">tests</a>')
21 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/vcs">vcs</a>')
21 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/vcs">vcs</a>')
22 response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/.hgignore">.hgignore</a>')
22 response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/.hgignore">.hgignore</a>')
23 response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/MANIFEST.in">MANIFEST.in</a>')
23 response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/MANIFEST.in">MANIFEST.in</a>')
24
24
25 def test_index_revision(self):
25 def test_index_revision(self):
26 self.log_user()
26 self.log_user()
27
27
28 response = self.app.get(
28 response = self.app.get(
29 url(controller='files', action='index',
29 url(controller='files', action='index',
30 repo_name=HG_REPO,
30 repo_name=HG_REPO,
31 revision='7ba66bec8d6dbba14a2155be32408c435c5f4492',
31 revision='7ba66bec8d6dbba14a2155be32408c435c5f4492',
32 f_path='/')
32 f_path='/')
33 )
33 )
34
34
35 #Test response...
35 #Test response...
36
36
37 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/docs">docs</a>')
37 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/docs">docs</a>')
38 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/tests">tests</a>')
38 response.mustcontain('<a class="browser-dir ypjax-link" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/tests">tests</a>')
39 response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/README.rst">README.rst</a>')
39 response.mustcontain('<a class="browser-file ypjax-link" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/README.rst">README.rst</a>')
40 response.mustcontain('1.1 KiB')
40 response.mustcontain('1.1 KiB')
41 response.mustcontain('text/x-python')
41 response.mustcontain('text/x-python')
42
42
43 def test_index_different_branch(self):
43 def test_index_different_branch(self):
44 self.log_user()
44 self.log_user()
45
45
46 response = self.app.get(url(controller='files', action='index',
46 response = self.app.get(url(controller='files', action='index',
47 repo_name=HG_REPO,
47 repo_name=HG_REPO,
48 revision='97e8b885c04894463c51898e14387d80c30ed1ee',
48 revision='97e8b885c04894463c51898e14387d80c30ed1ee',
49 f_path='/'))
49 f_path='/'))
50
50
51 response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: git</a></span>""")
51 response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: git</a></span>""")
52
52
53 def test_index_paging(self):
53 def test_index_paging(self):
54 self.log_user()
54 self.log_user()
55
55
56 for r in [(73, 'a066b25d5df7016b45a41b7e2a78c33b57adc235'),
56 for r in [(73, 'a066b25d5df7016b45a41b7e2a78c33b57adc235'),
57 (92, 'cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e'),
57 (92, 'cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e'),
58 (109, '75feb4c33e81186c87eac740cee2447330288412'),
58 (109, '75feb4c33e81186c87eac740cee2447330288412'),
59 (1, '3d8f361e72ab303da48d799ff1ac40d5ac37c67e'),
59 (1, '3d8f361e72ab303da48d799ff1ac40d5ac37c67e'),
60 (0, 'b986218ba1c9b0d6a259fac9b050b1724ed8e545')]:
60 (0, 'b986218ba1c9b0d6a259fac9b050b1724ed8e545')]:
61
61
62 response = self.app.get(url(controller='files', action='index',
62 response = self.app.get(url(controller='files', action='index',
63 repo_name=HG_REPO,
63 repo_name=HG_REPO,
64 revision=r[1],
64 revision=r[1],
65 f_path='/'))
65 f_path='/'))
66
66
67 response.mustcontain("""@ r%s:%s""" % (r[0], r[1][:12]))
67 response.mustcontain("""@ r%s:%s""" % (r[0], r[1][:12]))
68
68
69 def test_file_source(self):
69 def test_file_source(self):
70 self.log_user()
70 self.log_user()
71 response = self.app.get(url(controller='files', action='index',
71 response = self.app.get(url(controller='files', action='index',
72 repo_name=HG_REPO,
72 repo_name=HG_REPO,
73 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
73 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
74 f_path='vcs/nodes.py'))
74 f_path='vcs/nodes.py'))
75
75
76 #test or history
76 #test or history
77 response.mustcontain("""<optgroup label="Changesets">
77 response.mustcontain("""<optgroup label="Changesets">
78 <option value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option>
78 <option value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option>
79 <option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35 (default)</option>
79 <option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35 (default)</option>
80 <option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c (default)</option>
80 <option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c (default)</option>
81 <option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329 (default)</option>
81 <option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329 (default)</option>
82 <option value="6249fd0fb2cfb1411e764129f598e2cf0de79a6f">r113:6249fd0fb2cf (git)</option>
82 <option value="6249fd0fb2cfb1411e764129f598e2cf0de79a6f">r113:6249fd0fb2cf (git)</option>
83 <option value="75feb4c33e81186c87eac740cee2447330288412">r109:75feb4c33e81 (default)</option>
83 <option value="75feb4c33e81186c87eac740cee2447330288412">r109:75feb4c33e81 (default)</option>
84 <option value="9a4dc232ecdc763ef2e98ae2238cfcbba4f6ad8d">r108:9a4dc232ecdc (default)</option>
84 <option value="9a4dc232ecdc763ef2e98ae2238cfcbba4f6ad8d">r108:9a4dc232ecdc (default)</option>
85 <option value="595cce4efa21fda2f2e4eeb4fe5f2a6befe6fa2d">r107:595cce4efa21 (default)</option>
85 <option value="595cce4efa21fda2f2e4eeb4fe5f2a6befe6fa2d">r107:595cce4efa21 (default)</option>
86 <option value="4a8bd421fbc2dfbfb70d85a3fe064075ab2c49da">r104:4a8bd421fbc2 (default)</option>
86 <option value="4a8bd421fbc2dfbfb70d85a3fe064075ab2c49da">r104:4a8bd421fbc2 (default)</option>
87 <option value="57be63fc8f85e65a0106a53187f7316f8c487ffa">r102:57be63fc8f85 (default)</option>
87 <option value="57be63fc8f85e65a0106a53187f7316f8c487ffa">r102:57be63fc8f85 (default)</option>
88 <option value="5530bd87f7e2e124a64d07cb2654c997682128be">r101:5530bd87f7e2 (git)</option>
88 <option value="5530bd87f7e2e124a64d07cb2654c997682128be">r101:5530bd87f7e2 (git)</option>
89 <option value="e516008b1c93f142263dc4b7961787cbad654ce1">r99:e516008b1c93 (default)</option>
89 <option value="e516008b1c93f142263dc4b7961787cbad654ce1">r99:e516008b1c93 (default)</option>
90 <option value="41f43fc74b8b285984554532eb105ac3be5c434f">r93:41f43fc74b8b (default)</option>
90 <option value="41f43fc74b8b285984554532eb105ac3be5c434f">r93:41f43fc74b8b (default)</option>
91 <option value="cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e">r92:cc66b61b8455 (default)</option>
91 <option value="cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e">r92:cc66b61b8455 (default)</option>
92 <option value="73ab5b616b3271b0518682fb4988ce421de8099f">r91:73ab5b616b32 (default)</option>
92 <option value="73ab5b616b3271b0518682fb4988ce421de8099f">r91:73ab5b616b32 (default)</option>
93 <option value="e0da75f308c0f18f98e9ce6257626009fdda2b39">r82:e0da75f308c0 (default)</option>
93 <option value="e0da75f308c0f18f98e9ce6257626009fdda2b39">r82:e0da75f308c0 (default)</option>
94 <option value="fb2e41e0f0810be4d7103bc2a4c7be16ee3ec611">r81:fb2e41e0f081 (default)</option>
94 <option value="fb2e41e0f0810be4d7103bc2a4c7be16ee3ec611">r81:fb2e41e0f081 (default)</option>
95 <option value="602ae2f5e7ade70b3b66a58cdd9e3e613dc8a028">r76:602ae2f5e7ad (default)</option>
95 <option value="602ae2f5e7ade70b3b66a58cdd9e3e613dc8a028">r76:602ae2f5e7ad (default)</option>
96 <option value="a066b25d5df7016b45a41b7e2a78c33b57adc235">r73:a066b25d5df7 (default)</option>
96 <option value="a066b25d5df7016b45a41b7e2a78c33b57adc235">r73:a066b25d5df7 (default)</option>
97 <option value="637a933c905958ce5151f154147c25c1c7b68832">r61:637a933c9059 (web)</option>
97 <option value="637a933c905958ce5151f154147c25c1c7b68832">r61:637a933c9059 (web)</option>
98 <option value="0c21004effeb8ce2d2d5b4a8baf6afa8394b6fbc">r60:0c21004effeb (web)</option>
98 <option value="0c21004effeb8ce2d2d5b4a8baf6afa8394b6fbc">r60:0c21004effeb (web)</option>
99 <option value="a1f39c56d3f1d52d5fb5920370a2a2716cd9a444">r59:a1f39c56d3f1 (web)</option>
99 <option value="a1f39c56d3f1d52d5fb5920370a2a2716cd9a444">r59:a1f39c56d3f1 (web)</option>
100 <option value="97d32df05c715a3bbf936bf3cc4e32fb77fe1a7f">r58:97d32df05c71 (web)</option>
100 <option value="97d32df05c715a3bbf936bf3cc4e32fb77fe1a7f">r58:97d32df05c71 (web)</option>
101 <option value="08eaf14517718dccea4b67755a93368341aca919">r57:08eaf1451771 (web)</option>
101 <option value="08eaf14517718dccea4b67755a93368341aca919">r57:08eaf1451771 (web)</option>
102 <option value="22f71ad265265a53238359c883aa976e725aa07d">r56:22f71ad26526 (web)</option>
102 <option value="22f71ad265265a53238359c883aa976e725aa07d">r56:22f71ad26526 (web)</option>
103 <option value="97501f02b7b4330924b647755663a2d90a5e638d">r49:97501f02b7b4 (web)</option>
103 <option value="97501f02b7b4330924b647755663a2d90a5e638d">r49:97501f02b7b4 (web)</option>
104 <option value="86ede6754f2b27309452bb11f997386ae01d0e5a">r47:86ede6754f2b (web)</option>
104 <option value="86ede6754f2b27309452bb11f997386ae01d0e5a">r47:86ede6754f2b (web)</option>
105 <option value="014c40c0203c423dc19ecf94644f7cac9d4cdce0">r45:014c40c0203c (web)</option>
105 <option value="014c40c0203c423dc19ecf94644f7cac9d4cdce0">r45:014c40c0203c (web)</option>
106 <option value="ee87846a61c12153b51543bf860e1026c6d3dcba">r30:ee87846a61c1 (default)</option>
106 <option value="ee87846a61c12153b51543bf860e1026c6d3dcba">r30:ee87846a61c1 (default)</option>
107 <option value="9bb326a04ae5d98d437dece54be04f830cf1edd9">r26:9bb326a04ae5 (default)</option>
107 <option value="9bb326a04ae5d98d437dece54be04f830cf1edd9">r26:9bb326a04ae5 (default)</option>
108 <option value="536c1a19428381cfea92ac44985304f6a8049569">r24:536c1a194283 (default)</option>
108 <option value="536c1a19428381cfea92ac44985304f6a8049569">r24:536c1a194283 (default)</option>
109 <option value="dc5d2c0661b61928834a785d3e64a3f80d3aad9c">r8:dc5d2c0661b6 (default)</option>
109 <option value="dc5d2c0661b61928834a785d3e64a3f80d3aad9c">r8:dc5d2c0661b6 (default)</option>
110 <option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3 (default)</option>
110 <option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3 (default)</option>
111 </optgroup>
111 </optgroup>
112 <optgroup label="Branches">
112 <optgroup label="Branches">
113 <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option>
113 <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option>
114 <option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option>
114 <option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option>
115 <option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option>
115 <option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option>
116 </optgroup>
116 </optgroup>
117 <optgroup label="Tags">
117 <optgroup label="Tags">
118 <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option>
118 <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option>
119 <option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option>
119 <option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option>
120 <option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option>
120 <option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option>
121 <option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option>
121 <option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option>
122 <option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option>
122 <option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option>
123 </optgroup>
123 </optgroup>
124 """)
124 """)
125
125
126 response.mustcontain("""<div class="commit">merge</div>""")
126 response.mustcontain("""<div class="commit">merge</div>""")
127
127
128 response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""")
128 response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""")
129
129
130 def test_file_annotation(self):
130 def test_file_annotation(self):
131 self.log_user()
131 self.log_user()
132 response = self.app.get(url(controller='files', action='index',
132 response = self.app.get(url(controller='files', action='index',
133 repo_name=HG_REPO,
133 repo_name=HG_REPO,
134 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
134 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
135 f_path='vcs/nodes.py',
135 f_path='vcs/nodes.py',
136 annotate=True))
136 annotate=True))
137
137
138
138
139 response.mustcontain("""<optgroup label="Changesets">
139 response.mustcontain("""<optgroup label="Changesets">
140 <option value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option>
140 <option value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option>
141 <option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35 (default)</option>
141 <option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35 (default)</option>
142 <option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c (default)</option>
142 <option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c (default)</option>
143 <option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329 (default)</option>
143 <option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329 (default)</option>
144 <option value="6249fd0fb2cfb1411e764129f598e2cf0de79a6f">r113:6249fd0fb2cf (git)</option>
144 <option value="6249fd0fb2cfb1411e764129f598e2cf0de79a6f">r113:6249fd0fb2cf (git)</option>
145 <option value="75feb4c33e81186c87eac740cee2447330288412">r109:75feb4c33e81 (default)</option>
145 <option value="75feb4c33e81186c87eac740cee2447330288412">r109:75feb4c33e81 (default)</option>
146 <option value="9a4dc232ecdc763ef2e98ae2238cfcbba4f6ad8d">r108:9a4dc232ecdc (default)</option>
146 <option value="9a4dc232ecdc763ef2e98ae2238cfcbba4f6ad8d">r108:9a4dc232ecdc (default)</option>
147 <option value="595cce4efa21fda2f2e4eeb4fe5f2a6befe6fa2d">r107:595cce4efa21 (default)</option>
147 <option value="595cce4efa21fda2f2e4eeb4fe5f2a6befe6fa2d">r107:595cce4efa21 (default)</option>
148 <option value="4a8bd421fbc2dfbfb70d85a3fe064075ab2c49da">r104:4a8bd421fbc2 (default)</option>
148 <option value="4a8bd421fbc2dfbfb70d85a3fe064075ab2c49da">r104:4a8bd421fbc2 (default)</option>
149 <option value="57be63fc8f85e65a0106a53187f7316f8c487ffa">r102:57be63fc8f85 (default)</option>
149 <option value="57be63fc8f85e65a0106a53187f7316f8c487ffa">r102:57be63fc8f85 (default)</option>
150 <option value="5530bd87f7e2e124a64d07cb2654c997682128be">r101:5530bd87f7e2 (git)</option>
150 <option value="5530bd87f7e2e124a64d07cb2654c997682128be">r101:5530bd87f7e2 (git)</option>
151 <option value="e516008b1c93f142263dc4b7961787cbad654ce1">r99:e516008b1c93 (default)</option>
151 <option value="e516008b1c93f142263dc4b7961787cbad654ce1">r99:e516008b1c93 (default)</option>
152 <option value="41f43fc74b8b285984554532eb105ac3be5c434f">r93:41f43fc74b8b (default)</option>
152 <option value="41f43fc74b8b285984554532eb105ac3be5c434f">r93:41f43fc74b8b (default)</option>
153 <option value="cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e">r92:cc66b61b8455 (default)</option>
153 <option value="cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e">r92:cc66b61b8455 (default)</option>
154 <option value="73ab5b616b3271b0518682fb4988ce421de8099f">r91:73ab5b616b32 (default)</option>
154 <option value="73ab5b616b3271b0518682fb4988ce421de8099f">r91:73ab5b616b32 (default)</option>
155 <option value="e0da75f308c0f18f98e9ce6257626009fdda2b39">r82:e0da75f308c0 (default)</option>
155 <option value="e0da75f308c0f18f98e9ce6257626009fdda2b39">r82:e0da75f308c0 (default)</option>
156 <option value="fb2e41e0f0810be4d7103bc2a4c7be16ee3ec611">r81:fb2e41e0f081 (default)</option>
156 <option value="fb2e41e0f0810be4d7103bc2a4c7be16ee3ec611">r81:fb2e41e0f081 (default)</option>
157 <option value="602ae2f5e7ade70b3b66a58cdd9e3e613dc8a028">r76:602ae2f5e7ad (default)</option>
157 <option value="602ae2f5e7ade70b3b66a58cdd9e3e613dc8a028">r76:602ae2f5e7ad (default)</option>
158 <option value="a066b25d5df7016b45a41b7e2a78c33b57adc235">r73:a066b25d5df7 (default)</option>
158 <option value="a066b25d5df7016b45a41b7e2a78c33b57adc235">r73:a066b25d5df7 (default)</option>
159 <option value="637a933c905958ce5151f154147c25c1c7b68832">r61:637a933c9059 (web)</option>
159 <option value="637a933c905958ce5151f154147c25c1c7b68832">r61:637a933c9059 (web)</option>
160 <option value="0c21004effeb8ce2d2d5b4a8baf6afa8394b6fbc">r60:0c21004effeb (web)</option>
160 <option value="0c21004effeb8ce2d2d5b4a8baf6afa8394b6fbc">r60:0c21004effeb (web)</option>
161 <option value="a1f39c56d3f1d52d5fb5920370a2a2716cd9a444">r59:a1f39c56d3f1 (web)</option>
161 <option value="a1f39c56d3f1d52d5fb5920370a2a2716cd9a444">r59:a1f39c56d3f1 (web)</option>
162 <option value="97d32df05c715a3bbf936bf3cc4e32fb77fe1a7f">r58:97d32df05c71 (web)</option>
162 <option value="97d32df05c715a3bbf936bf3cc4e32fb77fe1a7f">r58:97d32df05c71 (web)</option>
163 <option value="08eaf14517718dccea4b67755a93368341aca919">r57:08eaf1451771 (web)</option>
163 <option value="08eaf14517718dccea4b67755a93368341aca919">r57:08eaf1451771 (web)</option>
164 <option value="22f71ad265265a53238359c883aa976e725aa07d">r56:22f71ad26526 (web)</option>
164 <option value="22f71ad265265a53238359c883aa976e725aa07d">r56:22f71ad26526 (web)</option>
165 <option value="97501f02b7b4330924b647755663a2d90a5e638d">r49:97501f02b7b4 (web)</option>
165 <option value="97501f02b7b4330924b647755663a2d90a5e638d">r49:97501f02b7b4 (web)</option>
166 <option value="86ede6754f2b27309452bb11f997386ae01d0e5a">r47:86ede6754f2b (web)</option>
166 <option value="86ede6754f2b27309452bb11f997386ae01d0e5a">r47:86ede6754f2b (web)</option>
167 <option value="014c40c0203c423dc19ecf94644f7cac9d4cdce0">r45:014c40c0203c (web)</option>
167 <option value="014c40c0203c423dc19ecf94644f7cac9d4cdce0">r45:014c40c0203c (web)</option>
168 <option value="ee87846a61c12153b51543bf860e1026c6d3dcba">r30:ee87846a61c1 (default)</option>
168 <option value="ee87846a61c12153b51543bf860e1026c6d3dcba">r30:ee87846a61c1 (default)</option>
169 <option value="9bb326a04ae5d98d437dece54be04f830cf1edd9">r26:9bb326a04ae5 (default)</option>
169 <option value="9bb326a04ae5d98d437dece54be04f830cf1edd9">r26:9bb326a04ae5 (default)</option>
170 <option value="536c1a19428381cfea92ac44985304f6a8049569">r24:536c1a194283 (default)</option>
170 <option value="536c1a19428381cfea92ac44985304f6a8049569">r24:536c1a194283 (default)</option>
171 <option value="dc5d2c0661b61928834a785d3e64a3f80d3aad9c">r8:dc5d2c0661b6 (default)</option>
171 <option value="dc5d2c0661b61928834a785d3e64a3f80d3aad9c">r8:dc5d2c0661b6 (default)</option>
172 <option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3 (default)</option>
172 <option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3 (default)</option>
173 </optgroup>
173 </optgroup>
174 <optgroup label="Branches">
174 <optgroup label="Branches">
175 <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option>
175 <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option>
176 <option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option>
176 <option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option>
177 <option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option>
177 <option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option>
178 </optgroup>
178 </optgroup>
179 <optgroup label="Tags">
179 <optgroup label="Tags">
180 <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option>
180 <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option>
181 <option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option>
181 <option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option>
182 <option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option>
182 <option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option>
183 <option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option>
183 <option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option>
184 <option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option>
184 <option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option>
185 </optgroup>""")
185 </optgroup>""")
186
186
187 response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""")
187 response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""")
188
188
189 def test_archival(self):
189 def test_archival(self):
190 self.log_user()
190 self.log_user()
191
191
192 for arch_ext, info in ARCHIVE_SPECS.items():
192 for arch_ext, info in ARCHIVE_SPECS.items():
193 short = '27cd5cce30c9%s' % arch_ext
193 short = '27cd5cce30c9%s' % arch_ext
194 fname = '27cd5cce30c96924232dffcd24178a07ffeb5dfc%s' % arch_ext
194 fname = '27cd5cce30c96924232dffcd24178a07ffeb5dfc%s' % arch_ext
195 filename = '%s-%s' % (HG_REPO, short)
195 filename = '%s-%s' % (HG_REPO, short)
196 response = self.app.get(url(controller='files',
196 response = self.app.get(url(controller='files',
197 action='archivefile',
197 action='archivefile',
198 repo_name=HG_REPO,
198 repo_name=HG_REPO,
199 fname=fname))
199 fname=fname))
200
200
201 self.assertEqual(response.status, '200 OK')
201 self.assertEqual(response.status, '200 OK')
202 self.assertEqual(response.response._headers.items(),
202 heads = [
203 [('Pragma', 'no-cache'),
203 ('Content-Type', 'text/html; charset=utf-8'),
204 ('Cache-Control', 'no-cache'),
204 ('Content-Length', '0'), ('Pragma', 'no-cache'),
205 ('Content-Type', '%s; charset=utf-8' % info[0]),
205 ('Cache-Control', 'no-cache')
206 ('Content-Disposition', 'attachment; filename=%s' % filename),
206 ]
207 ]
207 self.assertEqual(response.response._headers.items(), heads)
208 )
209
208
210 def test_archival_wrong_ext(self):
209 def test_archival_wrong_ext(self):
211 self.log_user()
210 self.log_user()
212
211
213 for arch_ext in ['tar', 'rar', 'x', '..ax', '.zipz']:
212 for arch_ext in ['tar', 'rar', 'x', '..ax', '.zipz']:
214 fname = '27cd5cce30c96924232dffcd24178a07ffeb5dfc%s' % arch_ext
213 fname = '27cd5cce30c96924232dffcd24178a07ffeb5dfc%s' % arch_ext
215
214
216 response = self.app.get(url(controller='files', action='archivefile',
215 response = self.app.get(url(controller='files', action='archivefile',
217 repo_name=HG_REPO,
216 repo_name=HG_REPO,
218 fname=fname))
217 fname=fname))
219 response.mustcontain('Unknown archive type')
218 response.mustcontain('Unknown archive type')
220
219
221 def test_archival_wrong_revision(self):
220 def test_archival_wrong_revision(self):
222 self.log_user()
221 self.log_user()
223
222
224 for rev in ['00x000000', 'tar', 'wrong', '@##$@$424213232', '232dffcd']:
223 for rev in ['00x000000', 'tar', 'wrong', '@##$@$424213232', '232dffcd']:
225 fname = '%s.zip' % rev
224 fname = '%s.zip' % rev
226
225
227 response = self.app.get(url(controller='files', action='archivefile',
226 response = self.app.get(url(controller='files', action='archivefile',
228 repo_name=HG_REPO,
227 repo_name=HG_REPO,
229 fname=fname))
228 fname=fname))
230 response.mustcontain('Unknown revision')
229 response.mustcontain('Unknown revision')
231
230
232 #==========================================================================
231 #==========================================================================
233 # RAW FILE
232 # RAW FILE
234 #==========================================================================
233 #==========================================================================
235 def test_raw_file_ok(self):
234 def test_raw_file_ok(self):
236 self.log_user()
235 self.log_user()
237 response = self.app.get(url(controller='files', action='rawfile',
236 response = self.app.get(url(controller='files', action='rawfile',
238 repo_name=HG_REPO,
237 repo_name=HG_REPO,
239 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
238 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
240 f_path='vcs/nodes.py'))
239 f_path='vcs/nodes.py'))
241
240
242 self.assertEqual(response.content_disposition, "attachment; filename=nodes.py")
241 self.assertEqual(response.content_disposition, "attachment; filename=nodes.py")
243 self.assertEqual(response.content_type, "text/x-python")
242 self.assertEqual(response.content_type, "text/x-python")
244
243
245 def test_raw_file_wrong_cs(self):
244 def test_raw_file_wrong_cs(self):
246 self.log_user()
245 self.log_user()
247 rev = u'ERRORce30c96924232dffcd24178a07ffeb5dfc'
246 rev = u'ERRORce30c96924232dffcd24178a07ffeb5dfc'
248 f_path = 'vcs/nodes.py'
247 f_path = 'vcs/nodes.py'
249
248
250 response = self.app.get(url(controller='files', action='rawfile',
249 response = self.app.get(url(controller='files', action='rawfile',
251 repo_name=HG_REPO,
250 repo_name=HG_REPO,
252 revision=rev,
251 revision=rev,
253 f_path=f_path))
252 f_path=f_path))
254
253
255 msg = """Revision %r does not exist for this repository""" % (rev)
254 msg = """Revision %r does not exist for this repository""" % (rev)
256 self.checkSessionFlash(response, msg)
255 self.checkSessionFlash(response, msg)
257
256
258 msg = """%s""" % (HG_REPO)
257 msg = """%s""" % (HG_REPO)
259 self.checkSessionFlash(response, msg)
258 self.checkSessionFlash(response, msg)
260
259
261 def test_raw_file_wrong_f_path(self):
260 def test_raw_file_wrong_f_path(self):
262 self.log_user()
261 self.log_user()
263 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
262 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
264 f_path = 'vcs/ERRORnodes.py'
263 f_path = 'vcs/ERRORnodes.py'
265 response = self.app.get(url(controller='files', action='rawfile',
264 response = self.app.get(url(controller='files', action='rawfile',
266 repo_name=HG_REPO,
265 repo_name=HG_REPO,
267 revision=rev,
266 revision=rev,
268 f_path=f_path))
267 f_path=f_path))
269
268
270 msg = "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12])
269 msg = "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12])
271 self.checkSessionFlash(response, msg)
270 self.checkSessionFlash(response, msg)
272
271
273 #==========================================================================
272 #==========================================================================
274 # RAW RESPONSE - PLAIN
273 # RAW RESPONSE - PLAIN
275 #==========================================================================
274 #==========================================================================
276 def test_raw_ok(self):
275 def test_raw_ok(self):
277 self.log_user()
276 self.log_user()
278 response = self.app.get(url(controller='files', action='raw',
277 response = self.app.get(url(controller='files', action='raw',
279 repo_name=HG_REPO,
278 repo_name=HG_REPO,
280 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
279 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
281 f_path='vcs/nodes.py'))
280 f_path='vcs/nodes.py'))
282
281
283 self.assertEqual(response.content_type, "text/plain")
282 self.assertEqual(response.content_type, "text/plain")
284
283
285 def test_raw_wrong_cs(self):
284 def test_raw_wrong_cs(self):
286 self.log_user()
285 self.log_user()
287 rev = u'ERRORcce30c96924232dffcd24178a07ffeb5dfc'
286 rev = u'ERRORcce30c96924232dffcd24178a07ffeb5dfc'
288 f_path = 'vcs/nodes.py'
287 f_path = 'vcs/nodes.py'
289
288
290 response = self.app.get(url(controller='files', action='raw',
289 response = self.app.get(url(controller='files', action='raw',
291 repo_name=HG_REPO,
290 repo_name=HG_REPO,
292 revision=rev,
291 revision=rev,
293 f_path=f_path))
292 f_path=f_path))
294 msg = """Revision %r does not exist for this repository""" % (rev)
293 msg = """Revision %r does not exist for this repository""" % (rev)
295 self.checkSessionFlash(response, msg)
294 self.checkSessionFlash(response, msg)
296
295
297 msg = """%s""" % (HG_REPO)
296 msg = """%s""" % (HG_REPO)
298 self.checkSessionFlash(response, msg)
297 self.checkSessionFlash(response, msg)
299
298
300 def test_raw_wrong_f_path(self):
299 def test_raw_wrong_f_path(self):
301 self.log_user()
300 self.log_user()
302 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
301 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
303 f_path = 'vcs/ERRORnodes.py'
302 f_path = 'vcs/ERRORnodes.py'
304 response = self.app.get(url(controller='files', action='raw',
303 response = self.app.get(url(controller='files', action='raw',
305 repo_name=HG_REPO,
304 repo_name=HG_REPO,
306 revision=rev,
305 revision=rev,
307 f_path=f_path))
306 f_path=f_path))
308 msg = "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12])
307 msg = "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12])
309 self.checkSessionFlash(response, msg)
308 self.checkSessionFlash(response, msg)
310
309
311 def test_ajaxed_files_list(self):
310 def test_ajaxed_files_list(self):
312 self.log_user()
311 self.log_user()
313 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
312 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
314 response = self.app.get(
313 response = self.app.get(
315 url('files_nodelist_home', repo_name=HG_REPO,f_path='/',revision=rev),
314 url('files_nodelist_home', repo_name=HG_REPO,f_path='/',revision=rev),
316 extra_environ={'HTTP_X_PARTIAL_XHR': '1'},
315 extra_environ={'HTTP_X_PARTIAL_XHR': '1'},
317 )
316 )
318 response.mustcontain("vcs/web/simplevcs/views/repository.py")
317 response.mustcontain("vcs/web/simplevcs/views/repository.py")
General Comments 0
You need to be logged in to leave comments. Login now