/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: Jan Balster
  • Date: 2006-08-15 12:39:42 UTC
  • mfrom: (1923 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1928.
  • Revision ID: jan@merlinux.de-20060815123942-22c388c6e9a8ac91
merge bzr.dev 1923

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import errno
18
18
import os
 
19
import re
19
20
import subprocess
20
21
import sys
21
22
import tempfile
22
23
import time
23
24
 
 
25
# compatability - plugins import compare_trees from diff!!!
 
26
# deprecated as of 0.10
24
27
from bzrlib.delta import compare_trees
25
28
from bzrlib.errors import BzrError
26
29
import bzrlib.errors as errors
88
91
def external_diff(old_filename, oldlines, new_filename, newlines, to_file,
89
92
                  diff_opts):
90
93
    """Display a diff by calling out to the external diff program."""
91
 
    if hasattr(to_file, 'fileno'):
92
 
        out_file = to_file
93
 
        have_fileno = True
94
 
    else:
95
 
        out_file = subprocess.PIPE
96
 
        have_fileno = False
97
 
    
98
94
    # make sure our own output is properly ordered before the diff
99
95
    to_file.flush()
100
96
 
154
150
        try:
155
151
            pipe = subprocess.Popen(diffcmd,
156
152
                                    stdin=subprocess.PIPE,
157
 
                                    stdout=out_file)
 
153
                                    stdout=subprocess.PIPE)
158
154
        except OSError, e:
159
155
            if e.errno == errno.ENOENT:
160
156
                raise errors.NoDiff(str(e))
161
157
            raise
162
158
        pipe.stdin.close()
163
159
 
164
 
        if not have_fileno:
165
 
            bzrlib.osutils.pumpfile(pipe.stdout, to_file)
 
160
        first_line = pipe.stdout.readline()
 
161
        to_file.write(first_line)
 
162
        bzrlib.osutils.pumpfile(pipe.stdout, to_file)
166
163
        rc = pipe.wait()
167
164
        
168
 
        if rc != 0 and rc != 1:
 
165
        if rc == 2:
 
166
            # 'diff' gives retcode == 2 for all sorts of errors
 
167
            # one of those is 'Binary files differ'.
 
168
            # Bad options could also be the problem.
 
169
            # 'Binary files' is not a real error, so we suppress that error
 
170
            m = re.match('^binary files.*differ$', first_line, re.I)
 
171
            if not m:
 
172
                raise BzrError('external diff failed with exit code 2;'
 
173
                               ' command: %r' % (diffcmd,))
 
174
        elif rc not in (0, 1):
169
175
            # returns 1 if files differ; that's OK
170
176
            if rc < 0:
171
177
                msg = 'signal %d' % (-rc)
172
178
            else:
173
179
                msg = 'exit code %d' % rc
174
180
                
175
 
            raise BzrError('external diff failed with %s; command: %r' % (rc, diffcmd))
 
181
            raise BzrError('external diff failed with %s; command: %r' 
 
182
                           % (rc, diffcmd))
 
183
 
 
184
        # internal_diff() adds a trailing newline, add one here for consistency
 
185
        to_file.write('\n')
 
186
 
176
187
    finally:
177
188
        oldtmpf.close()                 # and delete
178
189
        newtmpf.close()
256
267
    The more general form is show_diff_trees(), where the caller
257
268
    supplies any two trees.
258
269
    """
259
 
    output = sys.stdout
260
270
    def spec_tree(spec):
261
 
        revision_id = spec.in_store(tree.branch).rev_id
262
 
        return tree.branch.repository.revision_tree(revision_id)
 
271
        if tree:
 
272
            revision = spec.in_store(tree.branch)
 
273
        else:
 
274
            revision = spec.in_store(None)
 
275
        revision_id = revision.rev_id
 
276
        branch = revision.branch
 
277
        return branch.repository.revision_tree(revision_id)
263
278
    if old_revision_spec is None:
264
279
        old_tree = tree.basis_tree()
265
280
    else:
269
284
        new_tree = tree
270
285
    else:
271
286
        new_tree = spec_tree(new_revision_spec)
 
287
    if new_tree is not tree:
 
288
        extra_trees = (tree,)
 
289
    else:
 
290
        extra_trees = None
272
291
 
273
292
    return show_diff_trees(old_tree, new_tree, sys.stdout, specific_files,
274
293
                           external_diff_options,
275
 
                           old_label=old_label, new_label=new_label)
 
294
                           old_label=old_label, new_label=new_label,
 
295
                           extra_trees=extra_trees)
276
296
 
277
297
 
278
298
def show_diff_trees(old_tree, new_tree, to_file, specific_files=None,
279
299
                    external_diff_options=None,
280
 
                    old_label='a/', new_label='b/'):
 
300
                    old_label='a/', new_label='b/',
 
301
                    extra_trees=None):
281
302
    """Show in text form the changes from one tree to another.
282
303
 
283
304
    to_files
285
306
 
286
307
    external_diff_options
287
308
        If set, use an external GNU diff and pass these options.
 
309
 
 
310
    extra_trees
 
311
        If set, more Trees to use for looking up file ids
288
312
    """
289
313
    old_tree.lock_read()
290
314
    try:
292
316
        try:
293
317
            return _show_diff_trees(old_tree, new_tree, to_file,
294
318
                                    specific_files, external_diff_options,
295
 
                                    old_label=old_label, new_label=new_label)
 
319
                                    old_label=old_label, new_label=new_label,
 
320
                                    extra_trees=extra_trees)
296
321
        finally:
297
322
            new_tree.unlock()
298
323
    finally:
301
326
 
302
327
def _show_diff_trees(old_tree, new_tree, to_file,
303
328
                     specific_files, external_diff_options, 
304
 
                     old_label='a/', new_label='b/' ):
 
329
                     old_label='a/', new_label='b/', extra_trees=None):
305
330
 
306
331
    # GNU Patch uses the epoch date to detect files that are being added
307
332
    # or removed in a diff.
310
335
    # TODO: Generation of pseudo-diffs for added/deleted files could
311
336
    # be usefully made into a much faster special case.
312
337
 
313
 
    _raise_if_doubly_unversioned(specific_files, old_tree, new_tree)
314
 
 
315
338
    if external_diff_options:
316
339
        assert isinstance(external_diff_options, basestring)
317
340
        opts = external_diff_options.split()
320
343
    else:
321
344
        diff_file = internal_diff
322
345
    
323
 
    delta = compare_trees(old_tree, new_tree, want_unchanged=False,
324
 
                          specific_files=specific_files)
 
346
    delta = new_tree.changes_from(old_tree,
 
347
        specific_files=specific_files,
 
348
        extra_trees=extra_trees, require_versioned=True)
325
349
 
326
350
    has_changes = 0
327
351
    for path, file_id, kind in delta.removed:
379
403
    return time.strftime('%Y-%m-%d %H:%M:%S +0000', tm)
380
404
 
381
405
 
382
 
def _raise_if_doubly_unversioned(specific_files, old_tree, new_tree):
383
 
    """Complain if paths are not versioned in either tree."""
384
 
    if not specific_files:
385
 
        return
386
 
    old_unversioned = old_tree.filter_unversioned_files(specific_files)
387
 
    new_unversioned = new_tree.filter_unversioned_files(specific_files)
388
 
    unversioned = old_unversioned.intersection(new_unversioned)
389
 
    if unversioned:
390
 
        raise errors.PathsNotVersionedError(sorted(unversioned))
391
 
    
392
 
 
393
406
def _raise_if_nonexistent(paths, old_tree, new_tree):
394
407
    """Complain if paths are not in either inventory or tree.
395
408