##// END OF EJS Templates
fixes issue #455 Creating an archive generates an exception on Windows...
marcink -
r2318:058e2743 beta
parent child Browse files
Show More
@@ -1,490 +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 from paste.fileapp import FileApp, _FileIter
36
36
37 from rhodecode.lib import diffs
37 from rhodecode.lib import diffs
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39
39
40 from rhodecode.lib.compat import OrderedDict
40 from rhodecode.lib.compat import OrderedDict
41 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
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
43 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.base import BaseRepoController, render
44 from rhodecode.lib.utils import EmptyChangeset
44 from rhodecode.lib.utils import EmptyChangeset
45 from rhodecode.lib.vcs.conf import settings
45 from rhodecode.lib.vcs.conf import settings
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
49 from rhodecode.lib.vcs.nodes import FileNode
49 from rhodecode.lib.vcs.nodes import FileNode
50
50
51 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.scm import ScmModel
52 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.db import Repository
53 from rhodecode.model.db import Repository
54
54
55 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
55 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
56 _context_url, get_line_ctx, get_ignore_ws
56 _context_url, get_line_ctx, get_ignore_ws
57
57
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 class FilesController(BaseRepoController):
62 class FilesController(BaseRepoController):
63
63
64 @LoginRequired()
64 @LoginRequired()
65 def __before__(self):
65 def __before__(self):
66 super(FilesController, self).__before__()
66 super(FilesController, self).__before__()
67 c.cut_off_limit = self.cut_off_limit
67 c.cut_off_limit = self.cut_off_limit
68
68
69 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):
70 """
70 """
71 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
72 proper message
72 proper message
73
73
74 :param rev: revision to fetch
74 :param rev: revision to fetch
75 :param repo_name: repo name to redirect after
75 :param repo_name: repo name to redirect after
76 """
76 """
77
77
78 try:
78 try:
79 return c.rhodecode_repo.get_changeset(rev)
79 return c.rhodecode_repo.get_changeset(rev)
80 except EmptyRepositoryError, e:
80 except EmptyRepositoryError, e:
81 if not redirect_after:
81 if not redirect_after:
82 return None
82 return None
83 url_ = url('files_add_home',
83 url_ = url('files_add_home',
84 repo_name=c.repo_name,
84 repo_name=c.repo_name,
85 revision=0, f_path='')
85 revision=0, f_path='')
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
87 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)),
88 category='warning')
88 category='warning')
89 redirect(h.url('summary_home', repo_name=repo_name))
89 redirect(h.url('summary_home', repo_name=repo_name))
90
90
91 except RepositoryError, e:
91 except RepositoryError, e:
92 h.flash(str(e), category='warning')
92 h.flash(str(e), category='warning')
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
94
94
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
96 """
96 """
97 Returns file_node, if error occurs or given path is directory,
97 Returns file_node, if error occurs or given path is directory,
98 it'll redirect to top level path
98 it'll redirect to top level path
99
99
100 :param repo_name: repo_name
100 :param repo_name: repo_name
101 :param cs: given changeset
101 :param cs: given changeset
102 :param path: path to lookup
102 :param path: path to lookup
103 """
103 """
104
104
105 try:
105 try:
106 file_node = cs.get_node(path)
106 file_node = cs.get_node(path)
107 if file_node.is_dir():
107 if file_node.is_dir():
108 raise RepositoryError('given path is a directory')
108 raise RepositoryError('given path is a directory')
109 except RepositoryError, e:
109 except RepositoryError, e:
110 h.flash(str(e), category='warning')
110 h.flash(str(e), category='warning')
111 redirect(h.url('files_home', repo_name=repo_name,
111 redirect(h.url('files_home', repo_name=repo_name,
112 revision=cs.raw_id))
112 revision=cs.raw_id))
113
113
114 return file_node
114 return file_node
115
115
116 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
116 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
117 'repository.admin')
117 'repository.admin')
118 def index(self, repo_name, revision, f_path, annotate=False):
118 def index(self, repo_name, revision, f_path, annotate=False):
119 # redirect to given revision from form if given
119 # redirect to given revision from form if given
120 post_revision = request.POST.get('at_rev', None)
120 post_revision = request.POST.get('at_rev', None)
121 if post_revision:
121 if post_revision:
122 cs = self.__get_cs_or_redirect(post_revision, repo_name)
122 cs = self.__get_cs_or_redirect(post_revision, repo_name)
123 redirect(url('files_home', repo_name=c.repo_name,
123 redirect(url('files_home', repo_name=c.repo_name,
124 revision=cs.raw_id, f_path=f_path))
124 revision=cs.raw_id, f_path=f_path))
125
125
126 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
126 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
127 c.branch = request.GET.get('branch', None)
127 c.branch = request.GET.get('branch', None)
128 c.f_path = f_path
128 c.f_path = f_path
129 c.annotate = annotate
129 c.annotate = annotate
130 cur_rev = c.changeset.revision
130 cur_rev = c.changeset.revision
131
131
132 # prev link
132 # prev link
133 try:
133 try:
134 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)
135 c.url_prev = url('files_home', repo_name=c.repo_name,
135 c.url_prev = url('files_home', repo_name=c.repo_name,
136 revision=prev_rev.raw_id, f_path=f_path)
136 revision=prev_rev.raw_id, f_path=f_path)
137 if c.branch:
137 if c.branch:
138 c.url_prev += '?branch=%s' % c.branch
138 c.url_prev += '?branch=%s' % c.branch
139 except (ChangesetDoesNotExistError, VCSError):
139 except (ChangesetDoesNotExistError, VCSError):
140 c.url_prev = '#'
140 c.url_prev = '#'
141
141
142 # next link
142 # next link
143 try:
143 try:
144 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)
145 c.url_next = url('files_home', repo_name=c.repo_name,
145 c.url_next = url('files_home', repo_name=c.repo_name,
146 revision=next_rev.raw_id, f_path=f_path)
146 revision=next_rev.raw_id, f_path=f_path)
147 if c.branch:
147 if c.branch:
148 c.url_next += '?branch=%s' % c.branch
148 c.url_next += '?branch=%s' % c.branch
149 except (ChangesetDoesNotExistError, VCSError):
149 except (ChangesetDoesNotExistError, VCSError):
150 c.url_next = '#'
150 c.url_next = '#'
151
151
152 # files or dirs
152 # files or dirs
153 try:
153 try:
154 c.file = c.changeset.get_node(f_path)
154 c.file = c.changeset.get_node(f_path)
155
155
156 if c.file.is_file():
156 if c.file.is_file():
157 c.file_history = self._get_node_history(c.changeset, f_path)
157 c.file_history = self._get_node_history(c.changeset, f_path)
158 else:
158 else:
159 c.file_history = []
159 c.file_history = []
160 except RepositoryError, e:
160 except RepositoryError, e:
161 h.flash(str(e), category='warning')
161 h.flash(str(e), category='warning')
162 redirect(h.url('files_home', repo_name=repo_name,
162 redirect(h.url('files_home', repo_name=repo_name,
163 revision=revision))
163 revision=revision))
164
164
165 return render('files/files.html')
165 return render('files/files.html')
166
166
167 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
167 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
168 'repository.admin')
168 'repository.admin')
169 def rawfile(self, repo_name, revision, f_path):
169 def rawfile(self, repo_name, revision, f_path):
170 cs = self.__get_cs_or_redirect(revision, repo_name)
170 cs = self.__get_cs_or_redirect(revision, repo_name)
171 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)
172
172
173 response.content_disposition = 'attachment; filename=%s' % \
173 response.content_disposition = 'attachment; filename=%s' % \
174 safe_str(f_path.split(Repository.url_sep())[-1])
174 safe_str(f_path.split(Repository.url_sep())[-1])
175
175
176 response.content_type = file_node.mimetype
176 response.content_type = file_node.mimetype
177 return file_node.content
177 return file_node.content
178
178
179 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
179 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
180 'repository.admin')
180 'repository.admin')
181 def raw(self, repo_name, revision, f_path):
181 def raw(self, repo_name, revision, f_path):
182 cs = self.__get_cs_or_redirect(revision, repo_name)
182 cs = self.__get_cs_or_redirect(revision, repo_name)
183 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)
184
184
185 raw_mimetype_mapping = {
185 raw_mimetype_mapping = {
186 # map original mimetype to a mimetype used for "show as raw"
186 # map original mimetype to a mimetype used for "show as raw"
187 # you can also provide a content-disposition to override the
187 # you can also provide a content-disposition to override the
188 # default "attachment" disposition.
188 # default "attachment" disposition.
189 # orig_type: (new_type, new_dispo)
189 # orig_type: (new_type, new_dispo)
190
190
191 # show images inline:
191 # show images inline:
192 'image/x-icon': ('image/x-icon', 'inline'),
192 'image/x-icon': ('image/x-icon', 'inline'),
193 'image/png': ('image/png', 'inline'),
193 'image/png': ('image/png', 'inline'),
194 'image/gif': ('image/gif', 'inline'),
194 'image/gif': ('image/gif', 'inline'),
195 'image/jpeg': ('image/jpeg', 'inline'),
195 'image/jpeg': ('image/jpeg', 'inline'),
196 'image/svg+xml': ('image/svg+xml', 'inline'),
196 'image/svg+xml': ('image/svg+xml', 'inline'),
197 }
197 }
198
198
199 mimetype = file_node.mimetype
199 mimetype = file_node.mimetype
200 try:
200 try:
201 mimetype, dispo = raw_mimetype_mapping[mimetype]
201 mimetype, dispo = raw_mimetype_mapping[mimetype]
202 except KeyError:
202 except KeyError:
203 # we don't know anything special about this, handle it safely
203 # we don't know anything special about this, handle it safely
204 if file_node.is_binary:
204 if file_node.is_binary:
205 # do same as download raw for binary files
205 # do same as download raw for binary files
206 mimetype, dispo = 'application/octet-stream', 'attachment'
206 mimetype, dispo = 'application/octet-stream', 'attachment'
207 else:
207 else:
208 # do not just use the original mimetype, but force text/plain,
208 # do not just use the original mimetype, but force text/plain,
209 # otherwise it would serve text/html and that might be unsafe.
209 # otherwise it would serve text/html and that might be unsafe.
210 # Note: underlying vcs library fakes text/plain mimetype if the
210 # Note: underlying vcs library fakes text/plain mimetype if the
211 # mimetype can not be determined and it thinks it is not
211 # mimetype can not be determined and it thinks it is not
212 # binary.This might lead to erroneous text display in some
212 # binary.This might lead to erroneous text display in some
213 # cases, but helps in other cases, like with text files
213 # cases, but helps in other cases, like with text files
214 # without extension.
214 # without extension.
215 mimetype, dispo = 'text/plain', 'inline'
215 mimetype, dispo = 'text/plain', 'inline'
216
216
217 if dispo == 'attachment':
217 if dispo == 'attachment':
218 dispo = 'attachment; filename=%s' % \
218 dispo = 'attachment; filename=%s' % \
219 safe_str(f_path.split(os.sep)[-1])
219 safe_str(f_path.split(os.sep)[-1])
220
220
221 response.content_disposition = dispo
221 response.content_disposition = dispo
222 response.content_type = mimetype
222 response.content_type = mimetype
223 return file_node.content
223 return file_node.content
224
224
225 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
225 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
226 def edit(self, repo_name, revision, f_path):
226 def edit(self, repo_name, revision, f_path):
227 r_post = request.POST
227 r_post = request.POST
228
228
229 c.cs = self.__get_cs_or_redirect(revision, repo_name)
229 c.cs = self.__get_cs_or_redirect(revision, repo_name)
230 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)
231
231
232 if c.file.is_binary:
232 if c.file.is_binary:
233 return redirect(url('files_home', repo_name=c.repo_name,
233 return redirect(url('files_home', repo_name=c.repo_name,
234 revision=c.cs.raw_id, f_path=f_path))
234 revision=c.cs.raw_id, f_path=f_path))
235
235
236 c.f_path = f_path
236 c.f_path = f_path
237
237
238 if r_post:
238 if r_post:
239
239
240 old_content = c.file.content
240 old_content = c.file.content
241 sl = old_content.splitlines(1)
241 sl = old_content.splitlines(1)
242 first_line = sl[0] if sl else ''
242 first_line = sl[0] if sl else ''
243 # modes: 0 - Unix, 1 - Mac, 2 - DOS
243 # modes: 0 - Unix, 1 - Mac, 2 - DOS
244 mode = detect_mode(first_line, 0)
244 mode = detect_mode(first_line, 0)
245 content = convert_line_endings(r_post.get('content'), mode)
245 content = convert_line_endings(r_post.get('content'), mode)
246
246
247 message = r_post.get('message') or (_('Edited %s via RhodeCode')
247 message = r_post.get('message') or (_('Edited %s via RhodeCode')
248 % (f_path))
248 % (f_path))
249 author = self.rhodecode_user.full_contact
249 author = self.rhodecode_user.full_contact
250
250
251 if content == old_content:
251 if content == old_content:
252 h.flash(_('No changes'),
252 h.flash(_('No changes'),
253 category='warning')
253 category='warning')
254 return redirect(url('changeset_home', repo_name=c.repo_name,
254 return redirect(url('changeset_home', repo_name=c.repo_name,
255 revision='tip'))
255 revision='tip'))
256
256
257 try:
257 try:
258 self.scm_model.commit_change(repo=c.rhodecode_repo,
258 self.scm_model.commit_change(repo=c.rhodecode_repo,
259 repo_name=repo_name, cs=c.cs,
259 repo_name=repo_name, cs=c.cs,
260 user=self.rhodecode_user,
260 user=self.rhodecode_user,
261 author=author, message=message,
261 author=author, message=message,
262 content=content, f_path=f_path)
262 content=content, f_path=f_path)
263 h.flash(_('Successfully committed to %s' % f_path),
263 h.flash(_('Successfully committed to %s' % f_path),
264 category='success')
264 category='success')
265
265
266 except Exception:
266 except Exception:
267 log.error(traceback.format_exc())
267 log.error(traceback.format_exc())
268 h.flash(_('Error occurred during commit'), category='error')
268 h.flash(_('Error occurred during commit'), category='error')
269 return redirect(url('changeset_home',
269 return redirect(url('changeset_home',
270 repo_name=c.repo_name, revision='tip'))
270 repo_name=c.repo_name, revision='tip'))
271
271
272 return render('files/files_edit.html')
272 return render('files/files_edit.html')
273
273
274 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
274 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
275 def add(self, repo_name, revision, f_path):
275 def add(self, repo_name, revision, f_path):
276 r_post = request.POST
276 r_post = request.POST
277 c.cs = self.__get_cs_or_redirect(revision, repo_name,
277 c.cs = self.__get_cs_or_redirect(revision, repo_name,
278 redirect_after=False)
278 redirect_after=False)
279 if c.cs is None:
279 if c.cs is None:
280 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
280 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
281
281
282 c.f_path = f_path
282 c.f_path = f_path
283
283
284 if r_post:
284 if r_post:
285 unix_mode = 0
285 unix_mode = 0
286 content = convert_line_endings(r_post.get('content'), unix_mode)
286 content = convert_line_endings(r_post.get('content'), unix_mode)
287
287
288 message = r_post.get('message') or (_('Added %s via RhodeCode')
288 message = r_post.get('message') or (_('Added %s via RhodeCode')
289 % (f_path))
289 % (f_path))
290 location = r_post.get('location')
290 location = r_post.get('location')
291 filename = r_post.get('filename')
291 filename = r_post.get('filename')
292 file_obj = r_post.get('upload_file', None)
292 file_obj = r_post.get('upload_file', None)
293
293
294 if file_obj is not None and hasattr(file_obj, 'filename'):
294 if file_obj is not None and hasattr(file_obj, 'filename'):
295 filename = file_obj.filename
295 filename = file_obj.filename
296 content = file_obj.file
296 content = file_obj.file
297
297
298 node_path = os.path.join(location, filename)
298 node_path = os.path.join(location, filename)
299 author = self.rhodecode_user.full_contact
299 author = self.rhodecode_user.full_contact
300
300
301 if not content:
301 if not content:
302 h.flash(_('No content'), category='warning')
302 h.flash(_('No content'), category='warning')
303 return redirect(url('changeset_home', repo_name=c.repo_name,
303 return redirect(url('changeset_home', repo_name=c.repo_name,
304 revision='tip'))
304 revision='tip'))
305 if not filename:
305 if not filename:
306 h.flash(_('No filename'), category='warning')
306 h.flash(_('No filename'), category='warning')
307 return redirect(url('changeset_home', repo_name=c.repo_name,
307 return redirect(url('changeset_home', repo_name=c.repo_name,
308 revision='tip'))
308 revision='tip'))
309
309
310 try:
310 try:
311 self.scm_model.create_node(repo=c.rhodecode_repo,
311 self.scm_model.create_node(repo=c.rhodecode_repo,
312 repo_name=repo_name, cs=c.cs,
312 repo_name=repo_name, cs=c.cs,
313 user=self.rhodecode_user,
313 user=self.rhodecode_user,
314 author=author, message=message,
314 author=author, message=message,
315 content=content, f_path=node_path)
315 content=content, f_path=node_path)
316 h.flash(_('Successfully committed to %s' % node_path),
316 h.flash(_('Successfully committed to %s' % node_path),
317 category='success')
317 category='success')
318 except NodeAlreadyExistsError, e:
318 except NodeAlreadyExistsError, e:
319 h.flash(_(e), category='error')
319 h.flash(_(e), category='error')
320 except Exception:
320 except Exception:
321 log.error(traceback.format_exc())
321 log.error(traceback.format_exc())
322 h.flash(_('Error occurred during commit'), category='error')
322 h.flash(_('Error occurred during commit'), category='error')
323 return redirect(url('changeset_home',
323 return redirect(url('changeset_home',
324 repo_name=c.repo_name, revision='tip'))
324 repo_name=c.repo_name, revision='tip'))
325
325
326 return render('files/files_add.html')
326 return render('files/files_add.html')
327
327
328 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
328 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
329 'repository.admin')
329 'repository.admin')
330 def archivefile(self, repo_name, fname):
330 def archivefile(self, repo_name, fname):
331
331
332 fileformat = None
332 fileformat = None
333 revision = None
333 revision = None
334 ext = None
334 ext = None
335 subrepos = request.GET.get('subrepos') == 'true'
335 subrepos = request.GET.get('subrepos') == 'true'
336
336
337 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
337 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
338 archive_spec = fname.split(ext_data[1])
338 archive_spec = fname.split(ext_data[1])
339 if len(archive_spec) == 2 and archive_spec[1] == '':
339 if len(archive_spec) == 2 and archive_spec[1] == '':
340 fileformat = a_type or ext_data[1]
340 fileformat = a_type or ext_data[1]
341 revision = archive_spec[0]
341 revision = archive_spec[0]
342 ext = ext_data[1]
342 ext = ext_data[1]
343
343
344 try:
344 try:
345 dbrepo = RepoModel().get_by_repo_name(repo_name)
345 dbrepo = RepoModel().get_by_repo_name(repo_name)
346 if dbrepo.enable_downloads is False:
346 if dbrepo.enable_downloads is False:
347 return _('downloads disabled')
347 return _('downloads disabled')
348
348
349 if c.rhodecode_repo.alias == 'hg':
349 if c.rhodecode_repo.alias == 'hg':
350 # 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
351 # hooks on fetching archives with subrepos
351 # hooks on fetching archives with subrepos
352 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
352 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
353 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
353 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
354
354
355 cs = c.rhodecode_repo.get_changeset(revision)
355 cs = c.rhodecode_repo.get_changeset(revision)
356 content_type = settings.ARCHIVE_SPECS[fileformat][0]
356 content_type = settings.ARCHIVE_SPECS[fileformat][0]
357 except ChangesetDoesNotExistError:
357 except ChangesetDoesNotExistError:
358 return _('Unknown revision %s') % revision
358 return _('Unknown revision %s') % revision
359 except EmptyRepositoryError:
359 except EmptyRepositoryError:
360 return _('Empty repository')
360 return _('Empty repository')
361 except (ImproperArchiveTypeError, KeyError):
361 except (ImproperArchiveTypeError, KeyError):
362 return _('Unknown archive type')
362 return _('Unknown archive type')
363
363
364 fd, _archive_name = tempfile.mkstemp(suffix='rcarchive')
364 fd, archive = tempfile.mkstemp()
365 with open(_archive_name, 'wb') as f:
365 t = open(archive, 'wb')
366 cs.fill_archive(stream=f, kind=fileformat, subrepos=subrepos)
366 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
367
367 t.close()
368 content_disposition = 'attachment; filename=%s-%s%s' \
369 % (repo_name, revision[:12], ext)
370 content_length = os.path.getsize(_archive_name)
371
368
372 headers = [('Content-Disposition', str(content_disposition)),
369 def get_chunked_archive(archive):
373 ('Content-Type', str(content_type)),
370 stream = open(archive, 'rb')
374 ('Content-Length', str(content_length))]
371 while True:
372 data = stream.read(16 * 1024)
373 if not data:
374 stream.close()
375 os.close(fd)
376 os.remove(archive)
377 break
378 yield data
375
379
376 class _DestroyingFileWrapper(_FileIter):
380 response.content_disposition = str('attachment; filename=%s-%s%s' \
377 def close(self):
381 % (repo_name, revision[:12], ext))
378 self.file.close
382 response.content_type = str(content_type)
379 os.remove(self.file.name)
383 return get_chunked_archive(archive)
380
381 request.environ['wsgi.file_wrapper'] = _DestroyingFileWrapper
382 fapp = FileApp(_archive_name, headers=headers)
383 return fapp(request.environ, self.start_response)
384
384
385 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
385 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
386 'repository.admin')
386 'repository.admin')
387 def diff(self, repo_name, f_path):
387 def diff(self, repo_name, f_path):
388 ignore_whitespace = request.GET.get('ignorews') == '1'
388 ignore_whitespace = request.GET.get('ignorews') == '1'
389 line_context = request.GET.get('context', 3)
389 line_context = request.GET.get('context', 3)
390 diff1 = request.GET.get('diff1', '')
390 diff1 = request.GET.get('diff1', '')
391 diff2 = request.GET.get('diff2', '')
391 diff2 = request.GET.get('diff2', '')
392 c.action = request.GET.get('diff')
392 c.action = request.GET.get('diff')
393 c.no_changes = diff1 == diff2
393 c.no_changes = diff1 == diff2
394 c.f_path = f_path
394 c.f_path = f_path
395 c.big_diff = False
395 c.big_diff = False
396 c.anchor_url = anchor_url
396 c.anchor_url = anchor_url
397 c.ignorews_url = _ignorews_url
397 c.ignorews_url = _ignorews_url
398 c.context_url = _context_url
398 c.context_url = _context_url
399 c.changes = OrderedDict()
399 c.changes = OrderedDict()
400 c.changes[diff2] = []
400 c.changes[diff2] = []
401 try:
401 try:
402 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
402 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
403 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
403 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
404 node1 = c.changeset_1.get_node(f_path)
404 node1 = c.changeset_1.get_node(f_path)
405 else:
405 else:
406 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
406 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
407 node1 = FileNode('.', '', changeset=c.changeset_1)
407 node1 = FileNode('.', '', changeset=c.changeset_1)
408
408
409 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
409 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
410 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
410 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
411 node2 = c.changeset_2.get_node(f_path)
411 node2 = c.changeset_2.get_node(f_path)
412 else:
412 else:
413 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
413 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
414 node2 = FileNode('.', '', changeset=c.changeset_2)
414 node2 = FileNode('.', '', changeset=c.changeset_2)
415 except RepositoryError:
415 except RepositoryError:
416 return redirect(url('files_home', repo_name=c.repo_name,
416 return redirect(url('files_home', repo_name=c.repo_name,
417 f_path=f_path))
417 f_path=f_path))
418
418
419 if c.action == 'download':
419 if c.action == 'download':
420 _diff = diffs.get_gitdiff(node1, node2,
420 _diff = diffs.get_gitdiff(node1, node2,
421 ignore_whitespace=ignore_whitespace,
421 ignore_whitespace=ignore_whitespace,
422 context=line_context)
422 context=line_context)
423 diff = diffs.DiffProcessor(_diff, format='gitdiff')
423 diff = diffs.DiffProcessor(_diff, format='gitdiff')
424
424
425 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
425 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
426 response.content_type = 'text/plain'
426 response.content_type = 'text/plain'
427 response.content_disposition = (
427 response.content_disposition = (
428 'attachment; filename=%s' % diff_name
428 'attachment; filename=%s' % diff_name
429 )
429 )
430 return diff.raw_diff()
430 return diff.raw_diff()
431
431
432 elif c.action == 'raw':
432 elif c.action == 'raw':
433 _diff = diffs.get_gitdiff(node1, node2,
433 _diff = diffs.get_gitdiff(node1, node2,
434 ignore_whitespace=ignore_whitespace,
434 ignore_whitespace=ignore_whitespace,
435 context=line_context)
435 context=line_context)
436 diff = diffs.DiffProcessor(_diff, format='gitdiff')
436 diff = diffs.DiffProcessor(_diff, format='gitdiff')
437 response.content_type = 'text/plain'
437 response.content_type = 'text/plain'
438 return diff.raw_diff()
438 return diff.raw_diff()
439
439
440 else:
440 else:
441 fid = h.FID(diff2, node2.path)
441 fid = h.FID(diff2, node2.path)
442 line_context_lcl = get_line_ctx(fid, request.GET)
442 line_context_lcl = get_line_ctx(fid, request.GET)
443 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
443 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
444
444
445 lim = request.GET.get('fulldiff') or self.cut_off_limit
445 lim = request.GET.get('fulldiff') or self.cut_off_limit
446 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
446 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
447 filenode_new=node2,
447 filenode_new=node2,
448 cut_off_limit=lim,
448 cut_off_limit=lim,
449 ignore_whitespace=ign_whitespace_lcl,
449 ignore_whitespace=ign_whitespace_lcl,
450 line_context=line_context_lcl,
450 line_context=line_context_lcl,
451 enable_comments=False)
451 enable_comments=False)
452
452
453 c.changes = [('', node2, diff, cs1, cs2, st,)]
453 c.changes = [('', node2, diff, cs1, cs2, st,)]
454
454
455 return render('files/file_diff.html')
455 return render('files/file_diff.html')
456
456
457 def _get_node_history(self, cs, f_path):
457 def _get_node_history(self, cs, f_path):
458 changesets = cs.get_file_history(f_path)
458 changesets = cs.get_file_history(f_path)
459 hist_l = []
459 hist_l = []
460
460
461 changesets_group = ([], _("Changesets"))
461 changesets_group = ([], _("Changesets"))
462 branches_group = ([], _("Branches"))
462 branches_group = ([], _("Branches"))
463 tags_group = ([], _("Tags"))
463 tags_group = ([], _("Tags"))
464 _hg = cs.repository.alias == 'hg'
464 _hg = cs.repository.alias == 'hg'
465 for chs in changesets:
465 for chs in changesets:
466 _branch = '(%s)' % chs.branch if _hg else ''
466 _branch = '(%s)' % chs.branch if _hg else ''
467 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)
468 changesets_group[0].append((chs.raw_id, n_desc,))
468 changesets_group[0].append((chs.raw_id, n_desc,))
469
469
470 hist_l.append(changesets_group)
470 hist_l.append(changesets_group)
471
471
472 for name, chs in c.rhodecode_repo.branches.items():
472 for name, chs in c.rhodecode_repo.branches.items():
473 branches_group[0].append((chs, name),)
473 branches_group[0].append((chs, name),)
474 hist_l.append(branches_group)
474 hist_l.append(branches_group)
475
475
476 for name, chs in c.rhodecode_repo.tags.items():
476 for name, chs in c.rhodecode_repo.tags.items():
477 tags_group[0].append((chs, name),)
477 tags_group[0].append((chs, name),)
478 hist_l.append(tags_group)
478 hist_l.append(tags_group)
479
479
480 return hist_l
480 return hist_l
481
481
482 @jsonify
482 @jsonify
483 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
483 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
484 'repository.admin')
484 'repository.admin')
485 def nodelist(self, repo_name, revision, f_path):
485 def nodelist(self, repo_name, revision, f_path):
486 if request.environ.get('HTTP_X_PARTIAL_XHR'):
486 if request.environ.get('HTTP_X_PARTIAL_XHR'):
487 cs = self.__get_cs_or_redirect(revision, repo_name)
487 cs = self.__get_cs_or_redirect(revision, repo_name)
488 _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,
489 flat=False)
489 flat=False)
490 return _d + _f
490 return _d + _f
@@ -1,317 +1,320 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 heads = [
202 heads = [
203 ('Content-Type', 'text/html; charset=utf-8'),
203 ('Pragma', 'no-cache'),
204 ('Content-Length', '0'), ('Pragma', 'no-cache'),
204 ('Cache-Control', 'no-cache'),
205 ('Cache-Control', 'no-cache')
205 ('Content-Disposition', 'attachment; filename=%s' % filename),
206 ('Content-Type', '%s; charset=utf-8' % info[0]),
206 ]
207 ]
207 self.assertEqual(response.response._headers.items(), heads)
208 self.assertEqual(response.response._headers.items(), heads)
208
209
209 def test_archival_wrong_ext(self):
210 def test_archival_wrong_ext(self):
210 self.log_user()
211 self.log_user()
211
212
212 for arch_ext in ['tar', 'rar', 'x', '..ax', '.zipz']:
213 for arch_ext in ['tar', 'rar', 'x', '..ax', '.zipz']:
213 fname = '27cd5cce30c96924232dffcd24178a07ffeb5dfc%s' % arch_ext
214 fname = '27cd5cce30c96924232dffcd24178a07ffeb5dfc%s' % arch_ext
214
215
215 response = self.app.get(url(controller='files', action='archivefile',
216 response = self.app.get(url(controller='files',
217 action='archivefile',
216 repo_name=HG_REPO,
218 repo_name=HG_REPO,
217 fname=fname))
219 fname=fname))
218 response.mustcontain('Unknown archive type')
220 response.mustcontain('Unknown archive type')
219
221
220 def test_archival_wrong_revision(self):
222 def test_archival_wrong_revision(self):
221 self.log_user()
223 self.log_user()
222
224
223 for rev in ['00x000000', 'tar', 'wrong', '@##$@$424213232', '232dffcd']:
225 for rev in ['00x000000', 'tar', 'wrong', '@##$@$42413232', '232dffcd']:
224 fname = '%s.zip' % rev
226 fname = '%s.zip' % rev
225
227
226 response = self.app.get(url(controller='files', action='archivefile',
228 response = self.app.get(url(controller='files',
229 action='archivefile',
227 repo_name=HG_REPO,
230 repo_name=HG_REPO,
228 fname=fname))
231 fname=fname))
229 response.mustcontain('Unknown revision')
232 response.mustcontain('Unknown revision')
230
233
231 #==========================================================================
234 #==========================================================================
232 # RAW FILE
235 # RAW FILE
233 #==========================================================================
236 #==========================================================================
234 def test_raw_file_ok(self):
237 def test_raw_file_ok(self):
235 self.log_user()
238 self.log_user()
236 response = self.app.get(url(controller='files', action='rawfile',
239 response = self.app.get(url(controller='files', action='rawfile',
237 repo_name=HG_REPO,
240 repo_name=HG_REPO,
238 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
241 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
239 f_path='vcs/nodes.py'))
242 f_path='vcs/nodes.py'))
240
243
241 self.assertEqual(response.content_disposition, "attachment; filename=nodes.py")
244 self.assertEqual(response.content_disposition, "attachment; filename=nodes.py")
242 self.assertEqual(response.content_type, "text/x-python")
245 self.assertEqual(response.content_type, "text/x-python")
243
246
244 def test_raw_file_wrong_cs(self):
247 def test_raw_file_wrong_cs(self):
245 self.log_user()
248 self.log_user()
246 rev = u'ERRORce30c96924232dffcd24178a07ffeb5dfc'
249 rev = u'ERRORce30c96924232dffcd24178a07ffeb5dfc'
247 f_path = 'vcs/nodes.py'
250 f_path = 'vcs/nodes.py'
248
251
249 response = self.app.get(url(controller='files', action='rawfile',
252 response = self.app.get(url(controller='files', action='rawfile',
250 repo_name=HG_REPO,
253 repo_name=HG_REPO,
251 revision=rev,
254 revision=rev,
252 f_path=f_path))
255 f_path=f_path))
253
256
254 msg = """Revision %r does not exist for this repository""" % (rev)
257 msg = """Revision %r does not exist for this repository""" % (rev)
255 self.checkSessionFlash(response, msg)
258 self.checkSessionFlash(response, msg)
256
259
257 msg = """%s""" % (HG_REPO)
260 msg = """%s""" % (HG_REPO)
258 self.checkSessionFlash(response, msg)
261 self.checkSessionFlash(response, msg)
259
262
260 def test_raw_file_wrong_f_path(self):
263 def test_raw_file_wrong_f_path(self):
261 self.log_user()
264 self.log_user()
262 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
265 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
263 f_path = 'vcs/ERRORnodes.py'
266 f_path = 'vcs/ERRORnodes.py'
264 response = self.app.get(url(controller='files', action='rawfile',
267 response = self.app.get(url(controller='files', action='rawfile',
265 repo_name=HG_REPO,
268 repo_name=HG_REPO,
266 revision=rev,
269 revision=rev,
267 f_path=f_path))
270 f_path=f_path))
268
271
269 msg = "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12])
272 msg = "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12])
270 self.checkSessionFlash(response, msg)
273 self.checkSessionFlash(response, msg)
271
274
272 #==========================================================================
275 #==========================================================================
273 # RAW RESPONSE - PLAIN
276 # RAW RESPONSE - PLAIN
274 #==========================================================================
277 #==========================================================================
275 def test_raw_ok(self):
278 def test_raw_ok(self):
276 self.log_user()
279 self.log_user()
277 response = self.app.get(url(controller='files', action='raw',
280 response = self.app.get(url(controller='files', action='raw',
278 repo_name=HG_REPO,
281 repo_name=HG_REPO,
279 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
282 revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
280 f_path='vcs/nodes.py'))
283 f_path='vcs/nodes.py'))
281
284
282 self.assertEqual(response.content_type, "text/plain")
285 self.assertEqual(response.content_type, "text/plain")
283
286
284 def test_raw_wrong_cs(self):
287 def test_raw_wrong_cs(self):
285 self.log_user()
288 self.log_user()
286 rev = u'ERRORcce30c96924232dffcd24178a07ffeb5dfc'
289 rev = u'ERRORcce30c96924232dffcd24178a07ffeb5dfc'
287 f_path = 'vcs/nodes.py'
290 f_path = 'vcs/nodes.py'
288
291
289 response = self.app.get(url(controller='files', action='raw',
292 response = self.app.get(url(controller='files', action='raw',
290 repo_name=HG_REPO,
293 repo_name=HG_REPO,
291 revision=rev,
294 revision=rev,
292 f_path=f_path))
295 f_path=f_path))
293 msg = """Revision %r does not exist for this repository""" % (rev)
296 msg = """Revision %r does not exist for this repository""" % (rev)
294 self.checkSessionFlash(response, msg)
297 self.checkSessionFlash(response, msg)
295
298
296 msg = """%s""" % (HG_REPO)
299 msg = """%s""" % (HG_REPO)
297 self.checkSessionFlash(response, msg)
300 self.checkSessionFlash(response, msg)
298
301
299 def test_raw_wrong_f_path(self):
302 def test_raw_wrong_f_path(self):
300 self.log_user()
303 self.log_user()
301 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
304 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
302 f_path = 'vcs/ERRORnodes.py'
305 f_path = 'vcs/ERRORnodes.py'
303 response = self.app.get(url(controller='files', action='raw',
306 response = self.app.get(url(controller='files', action='raw',
304 repo_name=HG_REPO,
307 repo_name=HG_REPO,
305 revision=rev,
308 revision=rev,
306 f_path=f_path))
309 f_path=f_path))
307 msg = "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12])
310 msg = "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12])
308 self.checkSessionFlash(response, msg)
311 self.checkSessionFlash(response, msg)
309
312
310 def test_ajaxed_files_list(self):
313 def test_ajaxed_files_list(self):
311 self.log_user()
314 self.log_user()
312 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
315 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
313 response = self.app.get(
316 response = self.app.get(
314 url('files_nodelist_home', repo_name=HG_REPO,f_path='/',revision=rev),
317 url('files_nodelist_home', repo_name=HG_REPO,f_path='/',revision=rev),
315 extra_environ={'HTTP_X_PARTIAL_XHR': '1'},
318 extra_environ={'HTTP_X_PARTIAL_XHR': '1'},
316 )
319 )
317 response.mustcontain("vcs/web/simplevcs/views/repository.py")
320 response.mustcontain("vcs/web/simplevcs/views/repository.py")
General Comments 0
You need to be logged in to leave comments. Login now