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