~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/controllers/revision_ui.py

  • Committer: Michael Hudson
  • Date: 2009-03-04 21:02:14 UTC
  • Revision ID: michael.hudson@canonical.com-20090304210214-1ekwse6xtm2ydb0w
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
 
20
24
from paste.httpexceptions import HTTPServerError
21
25
 
22
26
from loggerhead import util
23
27
from loggerhead.controllers import TemplatedBranchView
 
28
from loggerhead.history import rich_filename
24
29
 
25
30
 
26
31
DEFAULT_LINE_COUNT_LIMIT = 3000
30
35
 
31
36
    template_path = 'loggerhead.templates.revision'
32
37
 
33
 
    def get_values(self, h, args, kw, headers):
34
 
 
35
 
        if len(args) > 0:
36
 
            revid = h.fix_revid(args[0])
37
 
        else:
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))
 
38
    def _process_diff(self, diff):
 
39
        # doesn't really need to be a method; could be static.
 
40
        chunks = []
 
41
        chunk = None
 
42
        for line in diff.splitlines():
 
43
            if len(line) == 0:
 
44
                continue
 
45
            if line.startswith('+++ ') or line.startswith('--- '):
 
46
                continue
 
47
            if line.startswith('@@ '):
 
48
                # new chunk
 
49
                if chunk is not None:
 
50
                    chunks.append(chunk)
 
51
                chunk = util.Container()
 
52
                chunk.diff = []
 
53
                split_lines = line.split(' ')[1:3]
 
54
                lines = [int(x.split(',')[0][1:]) for x in split_lines]
 
55
                old_lineno = lines[0]
 
56
                new_lineno = lines[1]
 
57
            elif line.startswith(' '):
 
58
                chunk.diff.append(util.Container(old_lineno=old_lineno,
 
59
                                                 new_lineno=new_lineno,
 
60
                                                 type='context',
 
61
                                                 line=line[1:]))
 
62
                old_lineno += 1
 
63
                new_lineno += 1
 
64
            elif line.startswith('+'):
 
65
                chunk.diff.append(util.Container(old_lineno=None,
 
66
                                                 new_lineno=new_lineno,
 
67
                                                 type='insert', line=line[1:]))
 
68
                new_lineno += 1
 
69
            elif line.startswith('-'):
 
70
                chunk.diff.append(util.Container(old_lineno=old_lineno,
 
71
                                                 new_lineno=None,
 
72
                                                 type='delete', line=line[1:]))
 
73
                old_lineno += 1
 
74
            else:
 
75
                chunk.diff.append(util.Container(old_lineno=None,
 
76
                                                 new_lineno=None,
 
77
                                                 type='unknown',
 
78
                                                 line=repr(line)))
 
79
        if chunk is not None:
 
80
            chunks.append(chunk)
 
81
        return chunks
 
82
 
 
83
    def _parse_diffs(self, old_tree, new_tree, delta):
 
84
        """
 
85
        Return a list of processed diffs, in the format::
 
86
 
 
87
            list(
 
88
                filename: str,
 
89
                file_id: str,
 
90
                chunks: list(
 
91
                    diff: list(
 
92
                        old_lineno: int,
 
93
                        new_lineno: int,
 
94
                        type: str('context', 'delete', or 'insert'),
 
95
                        line: str,
 
96
                    ),
 
97
                ),
 
98
            )
 
99
        """
 
100
        process = []
 
101
        out = []
 
102
 
 
103
        for old_path, new_path, fid, \
 
104
            kind, text_modified, meta_modified in delta.renamed:
 
105
            if text_modified:
 
106
                process.append((old_path, new_path, fid, kind))
 
107
        for path, fid, kind, text_modified, meta_modified in delta.modified:
 
108
            process.append((path, path, fid, kind))
 
109
 
 
110
        for old_path, new_path, fid, kind in process:
 
111
            old_lines = old_tree.get_file_lines(fid)
 
112
            new_lines = new_tree.get_file_lines(fid)
 
113
            buffer = StringIO()
 
114
            if old_lines != new_lines:
 
115
                try:
 
116
                    bzrlib.diff.internal_diff(old_path, old_lines,
 
117
                                              new_path, new_lines, buffer)
 
118
                except bzrlib.errors.BinaryFile:
 
119
                    diff = ''
 
120
                else:
 
121
                    diff = buffer.getvalue()
 
122
            else:
 
123
                diff = ''
 
124
            out.append(util.Container(
 
125
                          filename=rich_filename(new_path, kind),
 
126
                          file_id=fid,
 
127
                          chunks=self._process_diff(diff),
 
128
                          raw_diff=diff))
 
129
 
 
130
        return out
 
131
 
 
132
    def get_change_with_diff(self, revid, compare_revid):
 
133
        h = self._history
 
134
        change = h.get_changes([revid])[0]
 
135
 
 
136
        if compare_revid is None:
 
137
            if change.parents:
 
138
                compare_revid = change.parents[0].revid
 
139
            else:
 
140
                compare_revid = 'null:'
 
141
 
 
142
        rev_tree1 = h._branch.repository.revision_tree(compare_revid)
 
143
        rev_tree2 = h._branch.repository.revision_tree(revid)
 
144
        delta = rev_tree2.changes_from(rev_tree1)
 
145
 
 
146
        change.changes = h.parse_delta(delta)
 
147
        change.changes.modified = self._parse_diffs(rev_tree1,
 
148
                                                    rev_tree2,
 
149
                                                    delta)
 
150
 
 
151
        return change
 
152
 
 
153
    def get_values(self, path, kwargs, headers):
 
154
        h = self._history
 
155
        revid = self.get_revid()
 
156
 
 
157
        filter_file_id = kwargs.get('filter_file_id', None)
 
158
        start_revid = h.fix_revid(kwargs.get('start_revid', None))
 
159
        query = kwargs.get('q', None)
 
160
        remember = h.fix_revid(kwargs.get('remember', None))
 
161
        compare_revid = h.fix_revid(kwargs.get('compare_revid', None))
45
162
 
46
163
        try:
47
 
            revid, start_revid, revid_list = h.get_view(revid, start_revid, filter_file_id, query)
 
164
            revid, start_revid, revid_list = h.get_view(revid,
 
165
                                                        start_revid,
 
166
                                                        filter_file_id,
 
167
                                                        query)
48
168
        except:
49
169
            self.log.exception('Exception fetching changes')
50
170
            raise HTTPServerError('Could not fetch changes')
57
177
            navigation.query = query
58
178
        util.fill_in_navigation(navigation)
59
179
 
60
 
        change = h.get_change_with_diff(revid, compare_revid)
 
180
        change = self.get_change_with_diff(revid, compare_revid)
61
181
        # add parent & merge-point branch-nick info, in case it's useful
62
 
        h.get_branch_nicks([ change ])
 
182
        h.get_branch_nicks([change])
63
183
 
64
184
        line_count_limit = DEFAULT_LINE_COUNT_LIMIT
65
185
        line_count = 0
67
187
            for chunk in file.chunks:
68
188
                line_count += len(chunk.diff)
69
189
 
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 ])
 
190
        # Directory Breadcrumbs
 
191
        directory_breadcrumbs = (
 
192
            util.directory_breadcrumbs(
 
193
                self._branch.friendly_name,
 
194
                self._branch.is_root,
 
195
                'changes'))
74
196
 
75
197
        return {
76
198
            'branch': self._branch,
84
206
            'query': query,
85
207
            'remember': remember,
86
208
            'compare_revid': compare_revid,
87
 
            'side_by_side': side_by_side,
88
209
            'url': self._branch.context_url,
89
210
            'line_count': line_count,
90
211
            'line_count_limit': line_count_limit,
91
212
            'show_plain_diffs': line_count > line_count_limit,
 
213
            'directory_breadcrumbs': directory_breadcrumbs,
92
214
        }