~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/controllers/revision_ui.py

  • Committer: Michael Hudson
  • Date: 2008-06-22 23:47:59 UTC
  • mto: This revision was merged to the branch mainline in revision 171.
  • Revision ID: michael.hudson@canonical.com-20080622234759-cs2t7yxjp82698mx
some NEWS

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
#
19
19
 
20
 
from StringIO import StringIO
21
 
 
22
 
import bzrlib.diff
23
 
from bzrlib import errors
24
 
 
25
20
from paste.httpexceptions import HTTPServerError
26
21
 
27
22
from loggerhead import util
28
23
from loggerhead.controllers import TemplatedBranchView
29
 
from loggerhead.history import rich_filename
30
24
 
31
25
 
32
26
DEFAULT_LINE_COUNT_LIMIT = 3000
36
30
 
37
31
    template_path = 'loggerhead.templates.revision'
38
32
 
39
 
    def _process_diff(self, diff):
40
 
        # doesn't really need to be a method; could be static.
41
 
        chunks = []
42
 
        chunk = None
43
 
        for line in diff.splitlines():
44
 
            if len(line) == 0:
45
 
                continue
46
 
            if line.startswith('+++ ') or line.startswith('--- '):
47
 
                continue
48
 
            if line.startswith('@@ '):
49
 
                # new chunk
50
 
                if chunk is not None:
51
 
                    chunks.append(chunk)
52
 
                chunk = util.Container()
53
 
                chunk.diff = []
54
 
                split_lines = line.split(' ')[1:3]
55
 
                lines = [int(x.split(',')[0][1:]) for x in split_lines]
56
 
                old_lineno = lines[0]
57
 
                new_lineno = lines[1]
58
 
            elif line.startswith(' '):
59
 
                chunk.diff.append(util.Container(old_lineno=old_lineno,
60
 
                                                 new_lineno=new_lineno,
61
 
                                                 type='context',
62
 
                                                 line=line[1:]))
63
 
                old_lineno += 1
64
 
                new_lineno += 1
65
 
            elif line.startswith('+'):
66
 
                chunk.diff.append(util.Container(old_lineno=None,
67
 
                                                 new_lineno=new_lineno,
68
 
                                                 type='insert', line=line[1:]))
69
 
                new_lineno += 1
70
 
            elif line.startswith('-'):
71
 
                chunk.diff.append(util.Container(old_lineno=old_lineno,
72
 
                                                 new_lineno=None,
73
 
                                                 type='delete', line=line[1:]))
74
 
                old_lineno += 1
75
 
            else:
76
 
                chunk.diff.append(util.Container(old_lineno=None,
77
 
                                                 new_lineno=None,
78
 
                                                 type='unknown',
79
 
                                                 line=repr(line)))
80
 
        if chunk is not None:
81
 
            chunks.append(chunk)
82
 
        return chunks
83
 
 
84
 
    def _parse_diffs(self, old_tree, new_tree, delta, specific_path):
85
 
        """
86
 
        Return a list of processed diffs, in the format::
87
 
 
88
 
            list(
89
 
                filename: str,
90
 
                file_id: str,
91
 
                chunks: list(
92
 
                    diff: list(
93
 
                        old_lineno: int,
94
 
                        new_lineno: int,
95
 
                        type: str('context', 'delete', or 'insert'),
96
 
                        line: str,
97
 
                    ),
98
 
                ),
99
 
            )
100
 
        """
101
 
        process = []
102
 
        out = []
103
 
 
104
 
        def include_specific_path(path):
105
 
            return specific_path == path
106
 
        def include_all_paths(path):
107
 
            return True
108
 
        if specific_path:
109
 
            include_path = include_specific_path
 
33
    def get_values(self, h, args, kw, response):
 
34
 
 
35
        if len(args) > 0:
 
36
            revid = h.fix_revid(args[0])
110
37
        else:
111
 
            include_path = include_all_paths
112
 
 
113
 
        for old_path, new_path, fid, \
114
 
            kind, text_modified, meta_modified in delta.renamed:
115
 
            if text_modified and include_path(new_path):
116
 
                process.append((old_path, new_path, fid, kind))
117
 
        for path, fid, kind, text_modified, meta_modified in delta.modified:
118
 
            if include_path(path):
119
 
                process.append((path, path, fid, kind))
120
 
        for path, fid, kind in delta.added:
121
 
            if file == 'kind' and include_path(path):
122
 
                process.append((path, path, fid, kind))
123
 
        for path, fid, kind in delta.removed:
124
 
            if file == 'kind' and include_path(path):
125
 
                process.append((path, path, fid, kind))
126
 
 
127
 
        process.sort(key=lambda x:x[1])
128
 
 
129
 
        for old_path, new_path, fid, kind in process:
130
 
            try:
131
 
                old_lines = old_tree.get_file_lines(fid)
132
 
            except errors.NoSuchId:
133
 
                old_lines = []
134
 
            try:
135
 
                new_lines = new_tree.get_file_lines(fid)
136
 
            except errors.NoSuchId:
137
 
                new_lines = []
138
 
            buffer = StringIO()
139
 
            if old_lines != new_lines:
140
 
                try:
141
 
                    bzrlib.diff.internal_diff(old_path, old_lines,
142
 
                                              new_path, new_lines, buffer)
143
 
                except bzrlib.errors.BinaryFile:
144
 
                    diff = ''
145
 
                else:
146
 
                    diff = buffer.getvalue()
147
 
            else:
148
 
                diff = ''
149
 
            out.append(util.Container(
150
 
                filename=rich_filename(new_path, kind), file_id=fid,
151
 
                chunks=self._process_diff(diff)))
152
 
 
153
 
        return out
154
 
 
155
 
    def get_changes_with_diff(self, change, compare_revid, specific_path):
156
 
        h = self._history
157
 
        if compare_revid is None:
158
 
            if change.parents:
159
 
                compare_revid = change.parents[0].revid
160
 
            else:
161
 
                compare_revid = 'null:'
162
 
 
163
 
        rev_tree1 = h._branch.repository.revision_tree(compare_revid)
164
 
        rev_tree2 = h._branch.repository.revision_tree(change.revid)
165
 
        delta = rev_tree2.changes_from(rev_tree1)
166
 
 
167
 
        changes = h.parse_delta(delta)
168
 
 
169
 
        return changes, self._parse_diffs(
170
 
            rev_tree1, rev_tree2, delta, specific_path)
171
 
 
172
 
    def get_values(self, path, kwargs, headers):
173
 
        h = self._history
174
 
        revid = self.get_revid()
175
 
 
176
 
        filter_file_id = kwargs.get('filter_file_id', None)
177
 
        start_revid = h.fix_revid(kwargs.get('start_revid', None))
178
 
        query = kwargs.get('q', None)
179
 
        remember = h.fix_revid(kwargs.get('remember', None))
180
 
        compare_revid = h.fix_revid(kwargs.get('compare_revid', None))
 
38
            revid = None
 
39
 
 
40
        filter_file_id = kw.get('filter_file_id', None)
 
41
        start_revid = h.fix_revid(kw.get('start_revid', None))
 
42
        query = kw.get('q', None)
 
43
        remember = h.fix_revid(kw.get('remember', None))
 
44
        compare_revid = h.fix_revid(kw.get('compare_revid', None))
181
45
 
182
46
        try:
183
 
            revid, start_revid, revid_list = h.get_view(revid,
184
 
                                                        start_revid,
185
 
                                                        filter_file_id,
186
 
                                                        query)
 
47
            revid, start_revid, revid_list = h.get_view(revid, start_revid, filter_file_id, query)
187
48
        except:
188
49
            self.log.exception('Exception fetching changes')
189
50
            raise HTTPServerError('Could not fetch changes')
191
52
        navigation = util.Container(
192
53
            revid_list=revid_list, revid=revid, start_revid=start_revid,
193
54
            filter_file_id=filter_file_id, pagesize=1,
194
 
            scan_url='/revision', branch=self._branch, feed=True, history=h)
 
55
            scan_url='/revision', branch=self._branch, feed=True)
195
56
        if query is not None:
196
57
            navigation.query = query
197
58
        util.fill_in_navigation(navigation)
198
59
 
199
 
        change = h.get_changes([revid])[0]
200
 
        if path in ('', '/'):
201
 
            path = None
202
 
        change.changes, diffs = self.get_changes_with_diff(change, compare_revid, path)
 
60
        change = h.get_change_with_diff(revid, compare_revid)
203
61
        # add parent & merge-point branch-nick info, in case it's useful
204
 
        h.get_branch_nicks([change])
205
 
 
206
 
        # Directory Breadcrumbs
207
 
        directory_breadcrumbs = (
208
 
            util.directory_breadcrumbs(
209
 
                self._branch.friendly_name,
210
 
                self._branch.is_root,
211
 
                'changes'))
 
62
        h.get_branch_nicks([ change ])
 
63
 
 
64
        line_count_limit = DEFAULT_LINE_COUNT_LIMIT
 
65
        line_count = 0
 
66
        for file in change.changes.modified:
 
67
            for chunk in file.chunks:
 
68
                line_count += len(chunk.diff)
 
69
 
 
70
        # let's make side-by-side diff be the default
 
71
        side_by_side = not kw.get('unified', False)
 
72
        if side_by_side:
 
73
            h.add_side_by_side([ change ])
212
74
 
213
75
        return {
214
76
            'branch': self._branch,
215
77
            'revid': revid,
216
78
            'change': change,
217
 
            'diffs': diffs,
218
 
            'specific_path': path,
219
79
            'start_revid': start_revid,
220
80
            'filter_file_id': filter_file_id,
221
81
            'util': util,
224
84
            'query': query,
225
85
            'remember': remember,
226
86
            'compare_revid': compare_revid,
 
87
            'side_by_side': side_by_side,
227
88
            'url': self._branch.context_url,
228
 
            'directory_breadcrumbs': directory_breadcrumbs,
 
89
            'line_count': line_count,
 
90
            'line_count_limit': line_count_limit,
 
91
            'show_plain_diffs': line_count > line_count_limit,
229
92
        }