Mercurial > kallithea
comparison rhodecode/controllers/files.py @ 547:1e757ac98988
renamed project to rhodecode
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Wed, 06 Oct 2010 03:18:16 +0200 |
parents | pylons_app/controllers/files.py@d8778cde98f0 |
children | 7e536d1af60d |
comparison
equal
deleted
inserted
replaced
546:7c2f5e4d7bbf | 547:1e757ac98988 |
---|---|
1 #!/usr/bin/env python | |
2 # encoding: utf-8 | |
3 # files controller for pylons | |
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> | |
5 | |
6 # This program is free software; you can redistribute it and/or | |
7 # modify it under the terms of the GNU General Public License | |
8 # as published by the Free Software Foundation; version 2 | |
9 # of the License or (at your opinion) any later version of the license. | |
10 # | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU General Public License for more details. | |
15 # | |
16 # You should have received a copy of the GNU General Public License | |
17 # along with this program; if not, write to the Free Software | |
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |
19 # MA 02110-1301, USA. | |
20 """ | |
21 Created on April 21, 2010 | |
22 files controller for pylons | |
23 @author: marcink | |
24 """ | |
25 from mercurial import archival | |
26 from pylons import request, response, session, tmpl_context as c, url | |
27 from pylons.i18n.translation import _ | |
28 from pylons.controllers.util import redirect | |
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
30 from rhodecode.lib.base import BaseController, render | |
31 from rhodecode.lib.utils import EmptyChangeset | |
32 from rhodecode.model.hg_model import HgModel | |
33 from vcs.exceptions import RepositoryError, ChangesetError | |
34 from vcs.nodes import FileNode | |
35 from vcs.utils import diffs as differ | |
36 import logging | |
37 import rhodecode.lib.helpers as h | |
38 import tempfile | |
39 | |
40 log = logging.getLogger(__name__) | |
41 | |
42 class FilesController(BaseController): | |
43 | |
44 @LoginRequired() | |
45 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
46 'repository.admin') | |
47 def __before__(self): | |
48 super(FilesController, self).__before__() | |
49 c.file_size_limit = 250 * 1024 #limit of file size to display | |
50 | |
51 def index(self, repo_name, revision, f_path): | |
52 hg_model = HgModel() | |
53 c.repo = repo = hg_model.get_repo(c.repo_name) | |
54 revision = request.POST.get('at_rev', None) or revision | |
55 | |
56 def get_next_rev(cur): | |
57 max_rev = len(c.repo.revisions) - 1 | |
58 r = cur + 1 | |
59 if r > max_rev: | |
60 r = max_rev | |
61 return r | |
62 | |
63 def get_prev_rev(cur): | |
64 r = cur - 1 | |
65 return r | |
66 | |
67 c.f_path = f_path | |
68 | |
69 | |
70 try: | |
71 cur_rev = repo.get_changeset(revision).revision | |
72 prev_rev = repo.get_changeset(get_prev_rev(cur_rev)).short_id | |
73 next_rev = repo.get_changeset(get_next_rev(cur_rev)).short_id | |
74 | |
75 c.url_prev = url('files_home', repo_name=c.repo_name, | |
76 revision=prev_rev, f_path=f_path) | |
77 c.url_next = url('files_home', repo_name=c.repo_name, | |
78 revision=next_rev, f_path=f_path) | |
79 | |
80 c.changeset = repo.get_changeset(revision) | |
81 | |
82 c.cur_rev = c.changeset.short_id | |
83 c.rev_nr = c.changeset.revision | |
84 c.files_list = c.changeset.get_node(f_path) | |
85 c.file_history = self._get_history(repo, c.files_list, f_path) | |
86 | |
87 except (RepositoryError, ChangesetError): | |
88 c.files_list = None | |
89 | |
90 return render('files/files.html') | |
91 | |
92 def rawfile(self, repo_name, revision, f_path): | |
93 hg_model = HgModel() | |
94 c.repo = hg_model.get_repo(c.repo_name) | |
95 file_node = c.repo.get_changeset(revision).get_node(f_path) | |
96 response.content_type = file_node.mimetype | |
97 response.content_disposition = 'attachment; filename=%s' \ | |
98 % f_path.split('/')[-1] | |
99 return file_node.content | |
100 | |
101 def raw(self, repo_name, revision, f_path): | |
102 hg_model = HgModel() | |
103 c.repo = hg_model.get_repo(c.repo_name) | |
104 file_node = c.repo.get_changeset(revision).get_node(f_path) | |
105 response.content_type = 'text/plain' | |
106 | |
107 return file_node.content | |
108 | |
109 def annotate(self, repo_name, revision, f_path): | |
110 hg_model = HgModel() | |
111 c.repo = hg_model.get_repo(c.repo_name) | |
112 cs = c.repo.get_changeset(revision) | |
113 c.file = cs.get_node(f_path) | |
114 c.file_msg = cs.get_file_message(f_path) | |
115 c.cur_rev = cs.short_id | |
116 c.rev_nr = cs.revision | |
117 c.f_path = f_path | |
118 | |
119 return render('files/files_annotate.html') | |
120 | |
121 def archivefile(self, repo_name, revision, fileformat): | |
122 archive_specs = { | |
123 '.tar.bz2': ('application/x-tar', 'tbz2'), | |
124 '.tar.gz': ('application/x-tar', 'tgz'), | |
125 '.zip': ('application/zip', 'zip'), | |
126 } | |
127 if not archive_specs.has_key(fileformat): | |
128 return 'Unknown archive type %s' % fileformat | |
129 | |
130 def read_in_chunks(file_object, chunk_size=1024 * 40): | |
131 """Lazy function (generator) to read a file piece by piece. | |
132 Default chunk size: 40k.""" | |
133 while True: | |
134 data = file_object.read(chunk_size) | |
135 if not data: | |
136 break | |
137 yield data | |
138 | |
139 archive = tempfile.TemporaryFile() | |
140 repo = HgModel().get_repo(repo_name).repo | |
141 fname = '%s-%s%s' % (repo_name, revision, fileformat) | |
142 archival.archive(repo, archive, revision, archive_specs[fileformat][1], | |
143 prefix='%s-%s' % (repo_name, revision)) | |
144 response.content_type = archive_specs[fileformat][0] | |
145 response.content_disposition = 'attachment; filename=%s' % fname | |
146 archive.seek(0) | |
147 return read_in_chunks(archive) | |
148 | |
149 def diff(self, repo_name, f_path): | |
150 hg_model = HgModel() | |
151 diff1 = request.GET.get('diff1') | |
152 diff2 = request.GET.get('diff2') | |
153 c.action = request.GET.get('diff') | |
154 c.no_changes = diff1 == diff2 | |
155 c.f_path = f_path | |
156 c.repo = hg_model.get_repo(c.repo_name) | |
157 | |
158 try: | |
159 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]: | |
160 c.changeset_1 = c.repo.get_changeset(diff1) | |
161 node1 = c.changeset_1.get_node(f_path) | |
162 else: | |
163 c.changeset_1 = EmptyChangeset() | |
164 node1 = FileNode('.', '', changeset=c.changeset_1) | |
165 | |
166 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]: | |
167 c.changeset_2 = c.repo.get_changeset(diff2) | |
168 node2 = c.changeset_2.get_node(f_path) | |
169 else: | |
170 c.changeset_2 = EmptyChangeset() | |
171 node2 = FileNode('.', '', changeset=c.changeset_2) | |
172 except RepositoryError: | |
173 return redirect(url('files_home', | |
174 repo_name=c.repo_name, f_path=f_path)) | |
175 | |
176 c.diff1 = 'r%s:%s' % (c.changeset_1.revision, c.changeset_1.short_id) | |
177 c.diff2 = 'r%s:%s' % (c.changeset_2.revision, c.changeset_2.short_id) | |
178 | |
179 f_udiff = differ.get_udiff(node1, node2) | |
180 diff = differ.DiffProcessor(f_udiff) | |
181 | |
182 if c.action == 'download': | |
183 diff_name = '%s_vs_%s.diff' % (diff1, diff2) | |
184 response.content_type = 'text/plain' | |
185 response.content_disposition = 'attachment; filename=%s' \ | |
186 % diff_name | |
187 return diff.raw_diff() | |
188 | |
189 elif c.action == 'raw': | |
190 c.cur_diff = '<pre class="raw">%s</pre>' % h.escape(diff.raw_diff()) | |
191 elif c.action == 'diff': | |
192 if node1.size > c.file_size_limit or node2.size > c.file_size_limit: | |
193 c.cur_diff = _('Diff is to big to display') | |
194 else: | |
195 c.cur_diff = diff.as_html() | |
196 else: | |
197 #default option | |
198 if node1.size > c.file_size_limit or node2.size > c.file_size_limit: | |
199 c.cur_diff = _('Diff is to big to display') | |
200 else: | |
201 c.cur_diff = diff.as_html() | |
202 | |
203 if not c.cur_diff: c.no_changes = True | |
204 return render('files/file_diff.html') | |
205 | |
206 def _get_history(self, repo, node, f_path): | |
207 from vcs.nodes import NodeKind | |
208 if not node.kind is NodeKind.FILE: | |
209 return [] | |
210 changesets = node.history | |
211 hist_l = [] | |
212 for chs in changesets: | |
213 n_desc = 'r%s:%s' % (chs.revision, chs.short_id) | |
214 hist_l.append((chs.short_id, n_desc,)) | |
215 return hist_l |