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