##// END OF EJS Templates
fixed archival in rhodecode to use new functions from vcs
marcink -
r948:85ee0ea1 beta
parent child Browse files
Show More
@@ -1,283 +1,267 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) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27 import tempfile
27 import tempfile
28 import logging
28 import logging
29 import rhodecode.lib.helpers as h
29 import rhodecode.lib.helpers as h
30
30
31 from mercurial import archival
31 from mercurial import archival
32
32
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35 from pylons.controllers.util import redirect
35 from pylons.controllers.util import redirect
36
36
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
38 from rhodecode.lib.base import BaseController, render
38 from rhodecode.lib.base import BaseController, render
39 from rhodecode.lib.utils import EmptyChangeset
39 from rhodecode.lib.utils import EmptyChangeset
40 from rhodecode.model.scm import ScmModel
40 from rhodecode.model.scm import ScmModel
41
41
42 from vcs.backends import ARCHIVE_SPECS
42 from vcs.exceptions import RepositoryError, ChangesetError, \
43 from vcs.exceptions import RepositoryError, ChangesetError, \
43 ChangesetDoesNotExistError, EmptyRepositoryError
44 ChangesetDoesNotExistError, EmptyRepositoryError, InproperArchiveTypeError
44 from vcs.nodes import FileNode
45 from vcs.nodes import FileNode
45 from vcs.utils import diffs as differ
46 from vcs.utils import diffs as differ
46
47
47 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
48
49
49 class FilesController(BaseController):
50 class FilesController(BaseController):
50
51
51 @LoginRequired()
52 @LoginRequired()
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
53 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
53 'repository.admin')
54 'repository.admin')
54 def __before__(self):
55 def __before__(self):
55 super(FilesController, self).__before__()
56 super(FilesController, self).__before__()
56 c.cut_off_limit = self.cut_off_limit
57 c.cut_off_limit = self.cut_off_limit
57
58
58 def index(self, repo_name, revision, f_path):
59 def index(self, repo_name, revision, f_path):
59 hg_model = ScmModel()
60 hg_model = ScmModel()
60 c.repo = hg_model.get_repo(c.repo_name)
61 c.repo = hg_model.get_repo(c.repo_name)
61
62
62 try:
63 try:
63 #reditect to given revision from form
64 #reditect to given revision from form
64 post_revision = request.POST.get('at_rev', None)
65 post_revision = request.POST.get('at_rev', None)
65 if post_revision:
66 if post_revision:
66 post_revision = c.repo.get_changeset(post_revision).raw_id
67 post_revision = c.repo.get_changeset(post_revision).raw_id
67 redirect(url('files_home', repo_name=c.repo_name,
68 redirect(url('files_home', repo_name=c.repo_name,
68 revision=post_revision, f_path=f_path))
69 revision=post_revision, f_path=f_path))
69
70
70 c.branch = request.GET.get('branch', None)
71 c.branch = request.GET.get('branch', None)
71
72
72 c.f_path = f_path
73 c.f_path = f_path
73
74
74 c.changeset = c.repo.get_changeset(revision)
75 c.changeset = c.repo.get_changeset(revision)
75 cur_rev = c.changeset.revision
76 cur_rev = c.changeset.revision
76
77
77 #prev link
78 #prev link
78 try:
79 try:
79 prev_rev = c.repo.get_changeset(cur_rev).prev(c.branch).raw_id
80 prev_rev = c.repo.get_changeset(cur_rev).prev(c.branch).raw_id
80 c.url_prev = url('files_home', repo_name=c.repo_name,
81 c.url_prev = url('files_home', repo_name=c.repo_name,
81 revision=prev_rev, f_path=f_path)
82 revision=prev_rev, f_path=f_path)
82 if c.branch:
83 if c.branch:
83 c.url_prev += '?branch=%s' % c.branch
84 c.url_prev += '?branch=%s' % c.branch
84 except ChangesetDoesNotExistError:
85 except ChangesetDoesNotExistError:
85 c.url_prev = '#'
86 c.url_prev = '#'
86
87
87 #next link
88 #next link
88 try:
89 try:
89 next_rev = c.repo.get_changeset(cur_rev).next(c.branch).raw_id
90 next_rev = c.repo.get_changeset(cur_rev).next(c.branch).raw_id
90 c.url_next = url('files_home', repo_name=c.repo_name,
91 c.url_next = url('files_home', repo_name=c.repo_name,
91 revision=next_rev, f_path=f_path)
92 revision=next_rev, f_path=f_path)
92 if c.branch:
93 if c.branch:
93 c.url_next += '?branch=%s' % c.branch
94 c.url_next += '?branch=%s' % c.branch
94 except ChangesetDoesNotExistError:
95 except ChangesetDoesNotExistError:
95 c.url_next = '#'
96 c.url_next = '#'
96
97
97 #files
98 #files
98 try:
99 try:
99 c.files_list = c.changeset.get_node(f_path)
100 c.files_list = c.changeset.get_node(f_path)
100 c.file_history = self._get_history(c.repo, c.files_list, f_path)
101 c.file_history = self._get_history(c.repo, c.files_list, f_path)
101 except RepositoryError, e:
102 except RepositoryError, e:
102 h.flash(str(e), category='warning')
103 h.flash(str(e), category='warning')
103 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
104 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
104
105
105 except EmptyRepositoryError, e:
106 except EmptyRepositoryError, e:
106 h.flash(_('There are no files yet'), category='warning')
107 h.flash(_('There are no files yet'), category='warning')
107 redirect(h.url('summary_home', repo_name=repo_name))
108 redirect(h.url('summary_home', repo_name=repo_name))
108
109
109 except RepositoryError, e:
110 except RepositoryError, e:
110 h.flash(str(e), category='warning')
111 h.flash(str(e), category='warning')
111 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
112 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
112
113
113
114
114
115
115 return render('files/files.html')
116 return render('files/files.html')
116
117
117 def rawfile(self, repo_name, revision, f_path):
118 def rawfile(self, repo_name, revision, f_path):
118 hg_model = ScmModel()
119 hg_model = ScmModel()
119 c.repo = hg_model.get_repo(c.repo_name)
120 c.repo = hg_model.get_repo(c.repo_name)
120 file_node = c.repo.get_changeset(revision).get_node(f_path)
121 file_node = c.repo.get_changeset(revision).get_node(f_path)
121 response.content_type = file_node.mimetype
122 response.content_type = file_node.mimetype
122 response.content_disposition = 'attachment; filename=%s' \
123 response.content_disposition = 'attachment; filename=%s' \
123 % f_path.split('/')[-1]
124 % f_path.split('/')[-1]
124 return file_node.content
125 return file_node.content
125
126
126 def raw(self, repo_name, revision, f_path):
127 def raw(self, repo_name, revision, f_path):
127 hg_model = ScmModel()
128 hg_model = ScmModel()
128 c.repo = hg_model.get_repo(c.repo_name)
129 c.repo = hg_model.get_repo(c.repo_name)
129 file_node = c.repo.get_changeset(revision).get_node(f_path)
130 file_node = c.repo.get_changeset(revision).get_node(f_path)
130 response.content_type = 'text/plain'
131 response.content_type = 'text/plain'
131
132
132 return file_node.content
133 return file_node.content
133
134
134 def annotate(self, repo_name, revision, f_path):
135 def annotate(self, repo_name, revision, f_path):
135 hg_model = ScmModel()
136 hg_model = ScmModel()
136 c.repo = hg_model.get_repo(c.repo_name)
137 c.repo = hg_model.get_repo(c.repo_name)
137
138
138 try:
139 try:
139 c.cs = c.repo.get_changeset(revision)
140 c.cs = c.repo.get_changeset(revision)
140 c.file = c.cs.get_node(f_path)
141 c.file = c.cs.get_node(f_path)
141 except RepositoryError, e:
142 except RepositoryError, e:
142 h.flash(str(e), category='warning')
143 h.flash(str(e), category='warning')
143 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
144 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
144
145
145 c.file_history = self._get_history(c.repo, c.file, f_path)
146 c.file_history = self._get_history(c.repo, c.file, f_path)
146
147
147 c.f_path = f_path
148 c.f_path = f_path
148
149
149 return render('files/files_annotate.html')
150 return render('files/files_annotate.html')
150
151
151 def archivefile(self, repo_name, fname):
152 def archivefile(self, repo_name, fname):
152 archive_specs = {
153 '.tar.bz2': ('application/x-tar', 'tbz2'),
154 '.tar.gz': ('application/x-tar', 'tgz'),
155 '.zip': ('application/zip', 'zip'),
156 }
157
153
158 fileformat = None
154 fileformat = None
159 revision = None
155 revision = None
156 ext = None
160
157
161 for ext in archive_specs.keys():
158 for a_type, ext_data in ARCHIVE_SPECS.items():
162 archive_spec = fname.split(ext)
159 archive_spec = fname.split(ext_data[1])
163 if len(archive_spec) == 2:
160 if len(archive_spec) == 2 and archive_spec[1] == '':
164 fileformat = archive_spec[1] or ext
161 fileformat = a_type or ext_data[1]
165 revision = archive_spec[0]
162 revision = archive_spec[0]
166
163 ext = ext_data[1]
167 if not archive_specs.has_key(fileformat):
168 return _('Unknown archive type')
169
170 repo = ScmModel().get_repo(repo_name)
171
164
172 try:
165 try:
173 repo.get_changeset(revision)
166 repo = ScmModel().get_repo(repo_name)
167 cs = repo.get_changeset(revision)
174 except ChangesetDoesNotExistError:
168 except ChangesetDoesNotExistError:
175 return _('Unknown revision %s') % revision
169 return _('Unknown revision %s') % revision
176 except EmptyRepositoryError:
170 except EmptyRepositoryError:
177 return _('Empty repository')
171 return _('Empty repository')
172 except InproperArchiveTypeError:
173 return _('Unknown archive type')
178
174
179 archive = tempfile.TemporaryFile()
175 fname = '%s-%s%s' % (repo_name, revision, ext)
180 localrepo = repo.repo
181 fname = '%s-%s%s' % (repo_name, revision, fileformat)
182 archival.archive(localrepo, archive, revision, archive_specs[fileformat][1],
183 prefix='%s-%s' % (repo_name, revision))
184 response.content_type = archive_specs[fileformat][0]
185 response.content_disposition = 'attachment; filename=%s' % fname
186 archive.seek(0)
187
176
188 def read_in_chunks(file_object, chunk_size=1024 * 40):
177 response.content_type = ARCHIVE_SPECS[fileformat][0]
189 """Lazy function (generator) to read a file piece by piece.
178 response.content_disposition = 'attachment; filename=%s' % fname
190 Default chunk size: 40k."""
191 while True:
192 data = file_object.read(chunk_size)
193 if not data:
194 break
195 yield data
196
179
197 return read_in_chunks(archive)
180 return cs.get_chunked_archive(kind=fileformat)
181
198
182
199 def diff(self, repo_name, f_path):
183 def diff(self, repo_name, f_path):
200 hg_model = ScmModel()
184 hg_model = ScmModel()
201 diff1 = request.GET.get('diff1')
185 diff1 = request.GET.get('diff1')
202 diff2 = request.GET.get('diff2')
186 diff2 = request.GET.get('diff2')
203 c.action = request.GET.get('diff')
187 c.action = request.GET.get('diff')
204 c.no_changes = diff1 == diff2
188 c.no_changes = diff1 == diff2
205 c.f_path = f_path
189 c.f_path = f_path
206 c.repo = hg_model.get_repo(c.repo_name)
190 c.repo = hg_model.get_repo(c.repo_name)
207
191
208 try:
192 try:
209 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
193 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
210 c.changeset_1 = c.repo.get_changeset(diff1)
194 c.changeset_1 = c.repo.get_changeset(diff1)
211 node1 = c.changeset_1.get_node(f_path)
195 node1 = c.changeset_1.get_node(f_path)
212 else:
196 else:
213 c.changeset_1 = EmptyChangeset()
197 c.changeset_1 = EmptyChangeset()
214 node1 = FileNode('.', '', changeset=c.changeset_1)
198 node1 = FileNode('.', '', changeset=c.changeset_1)
215
199
216 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
200 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
217 c.changeset_2 = c.repo.get_changeset(diff2)
201 c.changeset_2 = c.repo.get_changeset(diff2)
218 node2 = c.changeset_2.get_node(f_path)
202 node2 = c.changeset_2.get_node(f_path)
219 else:
203 else:
220 c.changeset_2 = EmptyChangeset()
204 c.changeset_2 = EmptyChangeset()
221 node2 = FileNode('.', '', changeset=c.changeset_2)
205 node2 = FileNode('.', '', changeset=c.changeset_2)
222 except RepositoryError:
206 except RepositoryError:
223 return redirect(url('files_home',
207 return redirect(url('files_home',
224 repo_name=c.repo_name, f_path=f_path))
208 repo_name=c.repo_name, f_path=f_path))
225
209
226 f_udiff = differ.get_udiff(node1, node2)
210 f_udiff = differ.get_udiff(node1, node2)
227 diff = differ.DiffProcessor(f_udiff)
211 diff = differ.DiffProcessor(f_udiff)
228
212
229 if c.action == 'download':
213 if c.action == 'download':
230 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
214 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
231 response.content_type = 'text/plain'
215 response.content_type = 'text/plain'
232 response.content_disposition = 'attachment; filename=%s' \
216 response.content_disposition = 'attachment; filename=%s' \
233 % diff_name
217 % diff_name
234 return diff.raw_diff()
218 return diff.raw_diff()
235
219
236 elif c.action == 'raw':
220 elif c.action == 'raw':
237 response.content_type = 'text/plain'
221 response.content_type = 'text/plain'
238 return diff.raw_diff()
222 return diff.raw_diff()
239
223
240 elif c.action == 'diff':
224 elif c.action == 'diff':
241 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
225 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
242 c.cur_diff = _('Diff is to big to display')
226 c.cur_diff = _('Diff is to big to display')
243 else:
227 else:
244 c.cur_diff = diff.as_html()
228 c.cur_diff = diff.as_html()
245 else:
229 else:
246 #default option
230 #default option
247 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
231 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
248 c.cur_diff = _('Diff is to big to display')
232 c.cur_diff = _('Diff is to big to display')
249 else:
233 else:
250 c.cur_diff = diff.as_html()
234 c.cur_diff = diff.as_html()
251
235
252 if not c.cur_diff: c.no_changes = True
236 if not c.cur_diff: c.no_changes = True
253 return render('files/file_diff.html')
237 return render('files/file_diff.html')
254
238
255 def _get_history(self, repo, node, f_path):
239 def _get_history(self, repo, node, f_path):
256 from vcs.nodes import NodeKind
240 from vcs.nodes import NodeKind
257 if not node.kind is NodeKind.FILE:
241 if not node.kind is NodeKind.FILE:
258 return []
242 return []
259 changesets = node.history
243 changesets = node.history
260 hist_l = []
244 hist_l = []
261
245
262 changesets_group = ([], _("Changesets"))
246 changesets_group = ([], _("Changesets"))
263 branches_group = ([], _("Branches"))
247 branches_group = ([], _("Branches"))
264 tags_group = ([], _("Tags"))
248 tags_group = ([], _("Tags"))
265
249
266 for chs in changesets:
250 for chs in changesets:
267 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
251 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
268 changesets_group[0].append((chs.raw_id, n_desc,))
252 changesets_group[0].append((chs.raw_id, n_desc,))
269
253
270 hist_l.append(changesets_group)
254 hist_l.append(changesets_group)
271
255
272 for name, chs in c.repository_branches.items():
256 for name, chs in c.repository_branches.items():
273 #chs = chs.split(':')[-1]
257 #chs = chs.split(':')[-1]
274 branches_group[0].append((chs, name),)
258 branches_group[0].append((chs, name),)
275 hist_l.append(branches_group)
259 hist_l.append(branches_group)
276
260
277 for name, chs in c.repository_tags.items():
261 for name, chs in c.repository_tags.items():
278 #chs = chs.split(':')[-1]
262 #chs = chs.split(':')[-1]
279 tags_group[0].append((chs, name),)
263 tags_group[0].append((chs, name),)
280 hist_l.append(tags_group)
264 hist_l.append(tags_group)
281
265
282 return hist_l
266 return hist_l
283
267
General Comments 0
You need to be logged in to leave comments. Login now