/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Robert Collins
  • Date: 2005-10-15 11:38:29 UTC
  • mfrom: (1185.16.40)
  • Revision ID: robertc@lifelesslap.robertcollins.net-20051015113829-40226233fb246920
mergeĀ fromĀ martin

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006 Canonical Ltd.
 
1
# -*- coding: UTF-8 -*-
2
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
from bzrlib.trace import mutter
 
18
from bzrlib.errors import BzrError
17
19
from bzrlib.delta import compare_trees
18
 
from bzrlib.errors import BzrError
19
 
import bzrlib.errors as errors
20
 
from bzrlib.symbol_versioning import *
21
 
from bzrlib.trace import mutter
22
20
 
23
21
# TODO: Rather than building a changeset object, we should probably
24
22
# invoke callbacks on an object.  That object can either accumulate a
25
23
# list, write them out directly, etc etc.
26
24
 
27
 
def internal_diff(old_filename, oldlines, new_filename, newlines, to_file):
 
25
def internal_diff(old_label, oldlines, new_label, newlines, to_file):
28
26
    import difflib
29
27
    
30
28
    # FIXME: difflib is wrong if there is no trailing newline.
44
42
        return
45
43
 
46
44
    ud = difflib.unified_diff(oldlines, newlines,
47
 
                              fromfile=old_filename+'\t', 
48
 
                              tofile=new_filename+'\t')
 
45
                              fromfile=old_label, tofile=new_label)
49
46
 
50
47
    ud = list(ud)
51
48
    # work-around for difflib being too smart for its own good
65
62
    print >>to_file
66
63
 
67
64
 
68
 
def external_diff(old_filename, oldlines, new_filename, newlines, to_file,
 
65
def external_diff(old_label, oldlines, new_label, newlines, to_file,
69
66
                  diff_opts):
70
67
    """Display a diff by calling out to the external diff program."""
71
68
    import sys
100
97
        if not diff_opts:
101
98
            diff_opts = []
102
99
        diffcmd = ['diff',
103
 
                   '--label', old_filename+'\t',
 
100
                   '--label', old_label,
104
101
                   oldtmpf.name,
105
 
                   '--label', new_filename+'\t',
 
102
                   '--label', new_label,
106
103
                   newtmpf.name]
107
104
 
108
105
        # diff only allows one style to be specified; they don't override.
143
140
        oldtmpf.close()                 # and delete
144
141
        newtmpf.close()
145
142
 
146
 
 
147
 
@deprecated_function(zero_eight)
148
143
def show_diff(b, from_spec, specific_files, external_diff_options=None,
149
 
              revision2=None, output=None, b2=None):
 
144
              revision2=None, output=None):
150
145
    """Shortcut for showing the diff to the working tree.
151
146
 
152
 
    Please use show_diff_trees instead.
153
 
 
154
147
    b
155
148
        Branch.
156
149
 
165
158
        output = sys.stdout
166
159
 
167
160
    if from_spec is None:
168
 
        old_tree = b.bzrdir.open_workingtree()
169
 
        if b2 is None:
170
 
            old_tree = old_tree = old_tree.basis_tree()
 
161
        old_tree = b.basis_tree()
171
162
    else:
172
 
        old_tree = b.repository.revision_tree(from_spec.in_history(b).rev_id)
 
163
        old_tree = b.revision_tree(from_spec.in_history(b).rev_id)
173
164
 
174
165
    if revision2 is None:
175
 
        if b2 is None:
176
 
            new_tree = b.bzrdir.open_workingtree()
177
 
        else:
178
 
            new_tree = b2.bzrdir.open_workingtree()
179
 
    else:
180
 
        new_tree = b.repository.revision_tree(revision2.in_history(b).rev_id)
181
 
 
182
 
    return show_diff_trees(old_tree, new_tree, output, specific_files,
183
 
                           external_diff_options)
184
 
 
185
 
 
186
 
def diff_cmd_helper(tree, specific_files, external_diff_options, 
187
 
                    old_revision_spec=None, new_revision_spec=None):
188
 
    """Helper for cmd_diff.
189
 
 
190
 
   tree 
191
 
        A WorkingTree
192
 
 
193
 
    specific_files
194
 
        The specific files to compare, or None
195
 
 
196
 
    external_diff_options
197
 
        If non-None, run an external diff, and pass it these options
198
 
 
199
 
    old_revision_spec
200
 
        If None, use basis tree as old revision, otherwise use the tree for
201
 
        the specified revision. 
202
 
 
203
 
    new_revision_spec
204
 
        If None, use working tree as new revision, otherwise use the tree for
205
 
        the specified revision.
206
 
    
207
 
    The more general form is show_diff_trees(), where the caller
208
 
    supplies any two trees.
209
 
    """
210
 
    import sys
211
 
    output = sys.stdout
212
 
    def spec_tree(spec):
213
 
        revision_id = spec.in_store(tree.branch).rev_id
214
 
        return tree.branch.repository.revision_tree(revision_id)
215
 
    if old_revision_spec is None:
216
 
        old_tree = tree.basis_tree()
217
 
    else:
218
 
        old_tree = spec_tree(old_revision_spec)
219
 
 
220
 
    if new_revision_spec is None:
221
 
        new_tree = tree
222
 
    else:
223
 
        new_tree = spec_tree(new_revision_spec)
224
 
 
225
 
    return show_diff_trees(old_tree, new_tree, sys.stdout, specific_files,
226
 
                           external_diff_options)
 
166
        new_tree = b.working_tree()
 
167
    else:
 
168
        new_tree = b.revision_tree(revision2.in_history(b).rev_id)
 
169
 
 
170
    show_diff_trees(old_tree, new_tree, output, specific_files,
 
171
                    external_diff_options)
 
172
 
227
173
 
228
174
 
229
175
def show_diff_trees(old_tree, new_tree, to_file, specific_files=None,
236
182
    external_diff_options
237
183
        If set, use an external GNU diff and pass these options.
238
184
    """
239
 
    old_tree.lock_read()
240
 
    try:
241
 
        new_tree.lock_read()
242
 
        try:
243
 
            return _show_diff_trees(old_tree, new_tree, to_file,
244
 
                                    specific_files, external_diff_options)
245
 
        finally:
246
 
            new_tree.unlock()
247
 
    finally:
248
 
        old_tree.unlock()
249
 
 
250
 
 
251
 
def _show_diff_trees(old_tree, new_tree, to_file,
252
 
                     specific_files, external_diff_options):
253
 
 
254
 
    # TODO: Options to control putting on a prefix or suffix, perhaps
255
 
    # as a format string?
256
 
    old_label = 'a/'
257
 
    new_label = 'b/'
 
185
 
 
186
    # TODO: Options to control putting on a prefix or suffix, perhaps as a format string
 
187
    old_label = ''
 
188
    new_label = ''
258
189
 
259
190
    DEVNULL = '/dev/null'
260
191
    # Windows users, don't panic about this filename -- it is a
264
195
    # TODO: Generation of pseudo-diffs for added/deleted files could
265
196
    # be usefully made into a much faster special case.
266
197
 
267
 
    _raise_if_doubly_unversioned(specific_files, old_tree, new_tree)
268
 
 
269
198
    if external_diff_options:
270
199
        assert isinstance(external_diff_options, basestring)
271
200
        opts = external_diff_options.split()
274
203
    else:
275
204
        diff_file = internal_diff
276
205
    
 
206
 
277
207
    delta = compare_trees(old_tree, new_tree, want_unchanged=False,
278
208
                          specific_files=specific_files)
279
209
 
280
 
    has_changes = 0
281
210
    for path, file_id, kind in delta.removed:
282
 
        has_changes = 1
283
 
        print >>to_file, '=== removed %s %r' % (kind, old_label + path)
 
211
        print >>to_file, '=== removed %s %r' % (kind, path)
284
212
        old_tree.inventory[file_id].diff(diff_file, old_label + path, old_tree,
285
213
                                         DEVNULL, None, None, to_file)
286
214
    for path, file_id, kind in delta.added:
287
 
        has_changes = 1
288
 
        print >>to_file, '=== added %s %r' % (kind, new_label + path)
 
215
        print >>to_file, '=== added %s %r' % (kind, path)
289
216
        new_tree.inventory[file_id].diff(diff_file, new_label + path, new_tree,
290
217
                                         DEVNULL, None, None, to_file, 
291
218
                                         reverse=True)
292
219
    for (old_path, new_path, file_id, kind,
293
220
         text_modified, meta_modified) in delta.renamed:
294
 
        has_changes = 1
295
221
        prop_str = get_prop_change(meta_modified)
296
222
        print >>to_file, '=== renamed %s %r => %r%s' % (
297
 
                    kind, old_label + old_path, new_label + new_path, prop_str)
 
223
                          kind, old_path, new_path, prop_str)
298
224
        _maybe_diff_file_or_symlink(old_label, old_path, old_tree, file_id,
299
225
                                    new_label, new_path, new_tree,
300
226
                                    text_modified, kind, to_file, diff_file)
301
227
    for path, file_id, kind, text_modified, meta_modified in delta.modified:
302
 
        has_changes = 1
303
228
        prop_str = get_prop_change(meta_modified)
304
 
        print >>to_file, '=== modified %s %r%s' % (kind, old_label + path,
305
 
                    prop_str)
 
229
        print >>to_file, '=== modified %s %r%s' % (kind, path, prop_str)
306
230
        if text_modified:
307
231
            _maybe_diff_file_or_symlink(old_label, path, old_tree, file_id,
308
232
                                        new_label, path, new_tree,
309
233
                                        True, kind, to_file, diff_file)
310
 
 
311
 
    return has_changes
312
 
 
313
 
 
314
 
def _raise_if_doubly_unversioned(specific_files, old_tree, new_tree):
315
 
    """Complain if paths are not versioned in either tree."""
316
 
    if not specific_files:
317
 
        return
318
 
    old_unversioned = old_tree.filter_unversioned_files(specific_files)
319
 
    new_unversioned = new_tree.filter_unversioned_files(specific_files)
320
 
    unversioned = old_unversioned.intersection(new_unversioned)
321
 
    if unversioned:
322
 
        raise errors.PathsNotVersionedError(sorted(unversioned))
323
234
    
324
235
 
325
236
def get_prop_change(meta_modified):