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