~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-02 05:09:06 UTC
  • Revision ID: michael.hudson@canonical.com-20090302050906-n7fderzauzhsj7yw
comment out more forcefully

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
 
import time
21
 
 
22
 
import turbogears
23
 
from cherrypy import InternalError
 
20
from StringIO import StringIO
 
21
 
 
22
import bzrlib.diff
 
23
 
 
24
from paste.httpexceptions import HTTPServerError
24
25
 
25
26
from loggerhead import util
26
 
 
27
 
 
28
 
class RevisionUI (object):
29
 
 
30
 
    def __init__(self, branch):
31
 
        # BranchView object
32
 
        self._branch = branch
33
 
        self.log = branch.log
34
 
    
35
 
#    @util.lsprof
36
 
    @util.strip_whitespace
37
 
    @turbogears.expose(html='loggerhead.templates.revision')
38
 
    def default(self, *args, **kw):
39
 
        z = time.time()
40
 
        h = self._branch.get_history()
41
 
        util.set_context(kw)
42
 
        
43
 
        h._branch.lock_read()
 
27
from loggerhead.controllers import TemplatedBranchView
 
28
from loggerhead.history import rich_filename
 
29
 
 
30
 
 
31
DEFAULT_LINE_COUNT_LIMIT = 3000
 
32
 
 
33
 
 
34
class RevisionUI(TemplatedBranchView):
 
35
 
 
36
    template_path = 'loggerhead.templates.revision'
 
37
 
 
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))
 
162
 
44
163
        try:
45
 
            if len(args) > 0:
46
 
                revid = h.fix_revid(args[0])
47
 
            else:
48
 
                revid = None
49
 
 
50
 
            filter_file_id = kw.get('filter_file_id', None)
51
 
            start_revid = h.fix_revid(kw.get('start_revid', None))
52
 
            query = kw.get('q', None)
53
 
            remember = kw.get('remember', None)
54
 
            compare_revid = kw.get('compare_revid', None)
55
 
 
56
 
            try:
57
 
                revid, start_revid, revid_list = h.get_view(revid, start_revid, filter_file_id, query)
58
 
            except:
59
 
                self.log.exception('Exception fetching changes')
60
 
                raise InternalError('Could not fetch changes')
61
 
 
62
 
            navigation = util.Container(
63
 
                revid_list=revid_list, revid=revid, start_revid=start_revid,
64
 
                filter_file_id=filter_file_id, pagesize=1,
65
 
                scan_url='/revision', branch=self._branch, feed=True)
66
 
            if query is not None:
67
 
                navigation.query = query
68
 
            util.fill_in_navigation(navigation)
69
 
 
70
 
            change = h.get_change_with_diff(revid, compare_revid)
71
 
            # add parent & merge-point branch-nick info, in case it's useful
72
 
            h.get_branch_nicks([ change ])
73
 
 
74
 
            # let's make side-by-side diff be the default
75
 
            side_by_side = not kw.get('unified', False)
76
 
            if side_by_side:
77
 
                h.add_side_by_side([ change ])
78
 
 
79
 
            vals = {
80
 
                'branch': self._branch,
81
 
                'revid': revid,
82
 
                'change': change,
83
 
                'start_revid': start_revid,
84
 
                'filter_file_id': filter_file_id,
85
 
                'util': util,
86
 
                'history': h,
87
 
                'navigation': navigation,
88
 
                'query': query,
89
 
                'remember': remember,
90
 
                'compare_revid': compare_revid,
91
 
                'side_by_side': side_by_side,
92
 
            }
93
 
            h.flush_cache()
94
 
            self.log.info('/revision: %r seconds' % (time.time() - z,))
95
 
            return vals
96
 
        finally:
97
 
            h._branch.unlock()
 
164
            revid, start_revid, revid_list = h.get_view(revid,
 
165
                                                        start_revid,
 
166
                                                        filter_file_id,
 
167
                                                        query)
 
168
        except:
 
169
            self.log.exception('Exception fetching changes')
 
170
            raise HTTPServerError('Could not fetch changes')
 
171
 
 
172
        navigation = util.Container(
 
173
            revid_list=revid_list, revid=revid, start_revid=start_revid,
 
174
            filter_file_id=filter_file_id, pagesize=1,
 
175
            scan_url='/revision', branch=self._branch, feed=True, history=h)
 
176
        if query is not None:
 
177
            navigation.query = query
 
178
        util.fill_in_navigation(navigation)
 
179
 
 
180
        change = self.get_change_with_diff(revid, compare_revid)
 
181
        # add parent & merge-point branch-nick info, in case it's useful
 
182
        h.get_branch_nicks([change])
 
183
 
 
184
        line_count_limit = DEFAULT_LINE_COUNT_LIMIT
 
185
        line_count = 0
 
186
        for file in change.changes.modified:
 
187
            for chunk in file.chunks:
 
188
                line_count += len(chunk.diff)
 
189
 
 
190
        # Directory Breadcrumbs
 
191
        directory_breadcrumbs = (
 
192
            util.directory_breadcrumbs(
 
193
                self._branch.friendly_name,
 
194
                self._branch.is_root,
 
195
                'changes'))
 
196
 
 
197
        return {
 
198
            'branch': self._branch,
 
199
            'revid': revid,
 
200
            'change': change,
 
201
            'start_revid': start_revid,
 
202
            'filter_file_id': filter_file_id,
 
203
            'util': util,
 
204
            'history': h,
 
205
            'navigation': navigation,
 
206
            'query': query,
 
207
            'remember': remember,
 
208
            'compare_revid': compare_revid,
 
209
            'url': self._branch.context_url,
 
210
            'line_count': line_count,
 
211
            'line_count_limit': line_count_limit,
 
212
            'show_plain_diffs': line_count > line_count_limit,
 
213
            'directory_breadcrumbs': directory_breadcrumbs,
 
214
        }